Skip to content

Commit 07587a7

Browse files
authored
Merge pull request #68 from CodeitFESI4-Team1/Feat/CR-63/ReviewingModal
Feat/CR-63/ReviewingModal
2 parents dccc388 + 0095a26 commit 07587a7

File tree

4 files changed

+182
-0
lines changed

4 files changed

+182
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { useState } from 'react';
2+
import Image from 'next/image';
3+
import activeHeart from '@/public/assets/icons/active-heart.svg';
4+
import defaultHeart from '@/public/assets/icons/default-heart.svg';
5+
6+
interface ButtonHeartsProps {
7+
onChange: (score: number) => void;
8+
}
9+
10+
export default function ButtonHearts({ onChange }: ButtonHeartsProps) {
11+
const [clickedArray, setClickedArray] = useState<boolean[]>(Array(5).fill(false));
12+
13+
const handleClick = (index: number) => {
14+
setClickedArray((prev) => prev.map((_, i) => i <= index));
15+
onChange(index + 1);
16+
};
17+
18+
return (
19+
<div className="flex w-full flex-col items-start justify-between gap-[12px]">
20+
<p className="font-base font-semibold">만족스러운 경험이었나요?</p>
21+
<div>
22+
{Array.from({ length: 5 }).map((_, index) => (
23+
<button type="button" onClick={() => handleClick(index)} key={`btn ${index + 1}`}>
24+
<Image
25+
src={clickedArray[index] ? activeHeart : defaultHeart}
26+
width={24}
27+
height={24}
28+
alt="heartbtn"
29+
/>
30+
</button>
31+
))}
32+
</div>
33+
</div>
34+
);
35+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { useState } from 'react';
2+
import { useForm } from 'react-hook-form';
3+
import { Button } from '@mantine/core';
4+
import Textarea from '@/src/components/common/input/textarea';
5+
import ButtonHearts from './button-hearts';
6+
7+
type FormValues = {
8+
reviewText: string;
9+
score: number;
10+
};
11+
12+
interface ReviewProps {
13+
onCancel: () => void;
14+
}
15+
16+
export default function ReviewForm({ onCancel }: ReviewProps) {
17+
const { register, handleSubmit } = useForm<FormValues>();
18+
const [textReview, setTextReview] = useState<string>('');
19+
const [point, setPoint] = useState<number>(0);
20+
21+
// TODO : 주석 부분(api 연결) 수정
22+
// TODO : form에 넣기: onSubmit={handleSubmit(clickSubmit)}
23+
24+
const handleTextChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
25+
setTextReview(e.target.value);
26+
};
27+
28+
const handleScoreChange = (newScore: number) => {
29+
setPoint(newScore);
30+
};
31+
32+
return (
33+
<form className="flex h-[308px] w-[472px] flex-col justify-between gap-[24px]">
34+
<ButtonHearts onChange={handleScoreChange} />
35+
<Textarea
36+
placeholder="남겨주신 리뷰는 프로그램 운영 및 다른 회원 분들께 큰 도움이 됩니다."
37+
inputClassNames="w-[471px] h-[120px] bg-gray-50 text-gray-400"
38+
value={textReview}
39+
onChange={handleTextChange}
40+
register={register('reviewText')}
41+
label="경험에 대해 남겨주세요"
42+
styles={{
43+
input: {
44+
'::placeholder': {
45+
color: 'gray - 400',
46+
fontWeight: 500,
47+
fontSize: '1rem',
48+
},
49+
},
50+
label: {
51+
fontWeight: 600,
52+
fontSize: '1rem',
53+
},
54+
}}
55+
/>
56+
<input type="hidden" value={point} {...register('score')} />
57+
<div className="font-base flex justify-between gap-[16px] font-semibold">
58+
<Button
59+
onClick={onCancel}
60+
className="h-[44px] w-[228px] border border-blue-500 bg-white text-blue-500"
61+
>
62+
취소
63+
</Button>
64+
<Button type="submit" className="h-[44px] w-[228px] border-none bg-blue-500 text-white">
65+
리뷰 등록
66+
</Button>
67+
</div>
68+
</form>
69+
);
70+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { useEffect, useState } from 'react';
2+
import { Button } from '@mantine/core';
3+
import { action } from '@storybook/addon-actions';
4+
import { Meta, StoryFn } from '@storybook/react';
5+
import ReviewingModal, { ReviewingModalProps } from './reviewing-modal';
6+
7+
const meta: Meta<typeof ReviewingModal> = {
8+
title: 'Modal/ReviewingModal',
9+
component: ReviewingModal,
10+
argTypes: { opened: { control: 'boolean' } },
11+
};
12+
13+
export default meta;
14+
const Template: StoryFn<ReviewingModalProps> = function GatheringDetailModalStory({
15+
opened,
16+
}: ReviewingModalProps) {
17+
const [isOpened, setIsOpened] = useState(opened);
18+
19+
const handleOpen = () => {
20+
action('Modal Opened')();
21+
setIsOpened(true);
22+
};
23+
24+
const handleClose = () => {
25+
action('Modal Closed')();
26+
setIsOpened(false);
27+
};
28+
29+
useEffect(() => {
30+
setIsOpened(opened);
31+
}, [opened]);
32+
33+
return (
34+
<>
35+
<Button onClick={handleOpen}>Open Modal</Button>
36+
<ReviewingModal opened={isOpened} close={handleClose} />
37+
</>
38+
);
39+
};
40+
41+
export const Default = Template.bind({});
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use client';
2+
3+
import React from 'react';
4+
import { Modal } from '@mantine/core';
5+
import ReviewForm from './review-form';
6+
7+
export interface ReviewingModalProps {
8+
opened: boolean;
9+
close: () => void;
10+
}
11+
12+
export default function ReviewingModal({ opened, close }: ReviewingModalProps) {
13+
return (
14+
<Modal
15+
opened={opened}
16+
centered
17+
title="리뷰 쓰기"
18+
onClose={close}
19+
size="auto"
20+
padding={24}
21+
radius={12}
22+
overlayProps={{ backgroundOpacity: 0.5 }}
23+
styles={{
24+
title: {
25+
fontWeight: 600,
26+
fontSize: '1.125rem',
27+
},
28+
body: {
29+
fontFamily: 'var(--font-pretendard)',
30+
},
31+
}}
32+
>
33+
<ReviewForm onCancel={close} />
34+
</Modal>
35+
);
36+
}

0 commit comments

Comments
 (0)