Skip to content

Commit 3ae6213

Browse files
committed
design: 롤링페이퍼 메사지 추가 모달 버픕ㄹ리싱
1 parent bdc90ee commit 3ae6213

File tree

5 files changed

+106
-4
lines changed

5 files changed

+106
-4
lines changed

src/assets/images/modal-pink.png

133 KB
Loading

src/components/MessageModal.tsx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { ChangeEvent } from 'react';
2+
3+
import ModalBg from '@/assets/images/modal-pink.png';
4+
5+
import ModalOverlay from './ModalOverlay';
6+
import TextareaField from './TextareaField';
7+
8+
interface MessageModalProps {
9+
description?: string;
10+
inputValue: string;
11+
placeholder?: string;
12+
cancelText: string;
13+
completeText: string;
14+
children?: React.ReactNode;
15+
onInputChange: (e: ChangeEvent<HTMLTextAreaElement>) => void;
16+
onCancel: () => void;
17+
onComplete: () => void;
18+
}
19+
20+
const MessageModal = ({
21+
description,
22+
inputValue,
23+
placeholder,
24+
cancelText,
25+
completeText,
26+
children,
27+
onInputChange,
28+
onCancel,
29+
onComplete,
30+
}: MessageModalProps) => {
31+
return (
32+
<ModalOverlay>
33+
<p className="body-sb mb-4 text-white">{description}</p>
34+
<section
35+
className="mb-12 w-78 rounded-lg bg-[image:var(--bg-image)] bg-[length:100%_100%] bg-center p-4"
36+
style={{ '--bg-image': `url(${ModalBg})` } as React.CSSProperties}
37+
>
38+
<TextareaField
39+
rows={5}
40+
value={inputValue}
41+
placeholder={placeholder}
42+
onChange={onInputChange}
43+
/>
44+
{children}
45+
</section>
46+
<section className="flex items-center gap-6">
47+
<button
48+
type="button"
49+
className="body-m secondary-btn h-10 flex-1 basis-1/2"
50+
onClick={onCancel}
51+
>
52+
{cancelText}
53+
</button>
54+
<button
55+
type="button"
56+
className="primary-btn body-m h-10 flex-1 basis-1/2"
57+
onClick={onComplete}
58+
>
59+
{completeText}
60+
</button>
61+
</section>
62+
</ModalOverlay>
63+
);
64+
};
65+
66+
export default MessageModal;

src/components/ReportModal.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useState } from 'react';
22
import { twMerge } from 'tailwind-merge';
33

44
import ConfirmModal from './ConfirmModal';
5+
import TextareaField from './TextareaField';
56

67
interface ReportModalProps {
78
onClose: () => void;
@@ -46,10 +47,9 @@ const ReportModal = ({ onClose }: ReportModalProps) => {
4647
</button>
4748
))}
4849
</section>
49-
<textarea
50+
<TextareaField
5051
rows={3}
5152
placeholder="이곳을 눌러 추가 사유를 작성해주세요"
52-
className="body-m placeholder:text-gray-30 text-gray-80 w-full resize-none rounded-sm bg-white px-3 py-1.5"
5353
value={additionalReason}
5454
onChange={(e) => setAdditionalReason(e.target.value)}
5555
/>

src/components/TextareaField.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ComponentPropsWithoutRef } from 'react';
2+
3+
const TextareaField = ({ ...props }: ComponentPropsWithoutRef<'textarea'>) => {
4+
return (
5+
<textarea
6+
className="body-m placeholder:text-gray-30 text-gray-80 w-full resize-none rounded-sm bg-white px-3 py-1.5"
7+
{...props}
8+
/>
9+
);
10+
};
11+
12+
export default TextareaField;

src/pages/RollingPaper/index.tsx

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { MasonryInfiniteGrid } from '@egjs/react-infinitegrid';
2-
import { useState } from 'react';
2+
import { ChangeEvent, useState } from 'react';
33

44
import EnvelopeImg from '@/assets/images/envelope.png';
55
import BgItem from '@/assets/images/field-4.png';
6+
import MessageModal from '@/components/MessageModal';
67
import PageTitle from '@/components/PageTitle';
78
import ReportModal from '@/components/ReportModal';
89
import Header from '@/layouts/Header';
@@ -23,6 +24,8 @@ const DUMMY_MESSAGES = Array.from({ length: 10 }, () => ({ ...DUMMY_MESSAGE }));
2324
const RollingPaperPage = () => {
2425
const [activeMessageIndex, setActiveMessageIndex] = useState<number | null>(null);
2526
const [activeReportModal, setActiveReportModal] = useState(false);
27+
const [activeMessageModal, setActiveMessageModal] = useState(false);
28+
const [newMessage, setNewMessage] = useState('');
2629

2730
const handleReport = () => {
2831
setActiveMessageIndex(null);
@@ -33,6 +36,10 @@ const RollingPaperPage = () => {
3336
setActiveMessageIndex(null);
3437
};
3538

39+
const handleChangeMessage = (e: ChangeEvent<HTMLTextAreaElement>) => {
40+
setNewMessage(e.target.value);
41+
};
42+
3643
return (
3744
<>
3845
{activeMessageIndex !== null && (
@@ -45,6 +52,19 @@ const RollingPaperPage = () => {
4552
/>
4653
)}
4754
{activeReportModal && <ReportModal onClose={() => setActiveReportModal(false)} />}
55+
{activeMessageModal && (
56+
<MessageModal
57+
inputValue={newMessage}
58+
placeholder="이곳을 눌러 메시지를 작성해주세요"
59+
cancelText="취소하기"
60+
completeText="편지 남기기"
61+
onInputChange={handleChangeMessage}
62+
onCancel={() => setActiveMessageModal(false)}
63+
onComplete={() => setActiveMessageModal(false)}
64+
>
65+
<p className="body-r mt-5 text-end text-black">From. {DUMMY_USER_ZIP_CODE}</p>
66+
</MessageModal>
67+
)}
4868
<Header />
4969
<main className="flex grow flex-col items-center px-5 pt-4 pb-12">
5070
<PageTitle className="mb-18 max-w-73 text-center">{DUMMY_TITLE}</PageTitle>
@@ -56,7 +76,11 @@ const RollingPaperPage = () => {
5676
))}
5777
</MasonryInfiniteGrid>
5878
</section>
59-
<button type="button" className="fixed bottom-7.5 left-5 overflow-hidden rounded-sm">
79+
<button
80+
type="button"
81+
className="fixed bottom-7.5 left-5 overflow-hidden rounded-sm"
82+
onClick={() => setActiveMessageModal(true)}
83+
>
6084
<img src={EnvelopeImg} alt="편지지 이미지" className="h-12 w-auto opacity-70" />
6185
<p className="caption-sb absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 whitespace-nowrap text-white">
6286
편지 쓰기

0 commit comments

Comments
 (0)