Skip to content

Commit 0dc6dec

Browse files
committed
✨ feat(#172): 비회원 편지 작성 발신인 이름 작성 추가
1 parent 0f1e6d3 commit 0dc6dec

8 files changed

Lines changed: 233 additions & 12 deletions

File tree

src/api/send/send.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,20 @@ export const postSendLetter = async ({
2525

2626
// 비회원 편지 쓰기
2727
export const postAnonymousSendLetter = async ({
28+
senderName,
2829
receiverName,
2930
content,
3031
images,
3132
templateType
3233
}: {
34+
senderName: string;
3335
receiverName: string;
3436
content: string;
3537
images: string[];
3638
templateType: number;
3739
}) => {
3840
return await client.post(`/api/v1/letters/anonymous/send`, {
41+
senderName,
3942
receiverName,
4043
content,
4144
images,

src/app/login/page.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export default function Login() {
2121
clearAnonymousSendLetterCode();
2222
setSendState({
2323
draftId: null,
24+
senderName: null,
2425
receiverName: '',
2526
content: '',
2627
images: [] as string[],

src/app/send/(process)/content/page.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ const SendContentPage = () => {
267267
previewImages: previewImages
268268
}));
269269

270-
router.push(`/send/template${isGuest ? '?guest=true' : ''}`);
270+
router.push(`${isGuest ? '/send/sender?guest=true' : '/send/template'}`);
271271
};
272272

273273
/* 임시 저장 삭제 핸들러 */
@@ -294,15 +294,16 @@ const SendContentPage = () => {
294294
console.log('임시 저장 조회 성공', response.data);
295295

296296
console.log('상태 변경됨');
297-
setLetterState({
297+
setLetterState((prev) => ({
298+
...prev,
298299
draftId: response.data.draftKey,
299300
receiverName: response.data.receiverName,
300301
content: response.data.content,
301302
images: response.data.images,
302303
previewImages: response.data.images,
303304
templateType: 0,
304305
letterId: null
305-
});
306+
}));
306307

307308
// 각 input 상태 업데이트
308309
setDraftId(response.data.draftKey);

src/app/send/(process)/layout.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import NavigatorBar from '@/components/common/NavigatorBar';
44
import ProgressBar from '@/components/common/ProgressBar';
55
import { theme } from '@/styles/theme';
6-
import { usePathname } from 'next/navigation';
6+
import { usePathname, useSearchParams } from 'next/navigation';
77
import React from 'react';
88
import styled from 'styled-components';
99

@@ -13,12 +13,20 @@ interface SendLayoutProps {
1313

1414
const SendLayout = ({ children }: SendLayoutProps) => {
1515
const pathname = usePathname();
16+
const searchParams = useSearchParams();
17+
const isGuest = searchParams.get('guest') === 'true';
1618

1719
const current =
1820
pathname === '/send/receiver'
1921
? 1
2022
: pathname === '/send/content'
2123
? 2
24+
: isGuest
25+
? pathname === '/send/sender'
26+
? 3
27+
: pathname === '/send/template'
28+
? 4
29+
: null
2230
: pathname === '/send/template'
2331
? 3
2432
: null;
@@ -30,7 +38,7 @@ const SendLayout = ({ children }: SendLayoutProps) => {
3038
</NavigatorBarWrapper>
3139
{current && (
3240
<ProgressBarWrapper>
33-
<ProgressBar current={current} total={3} />
41+
<ProgressBar current={current} total={isGuest ? 4 : 3} />
3442
</ProgressBarWrapper>
3543
)}
3644
{children}

src/app/send/(process)/preview/page.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,15 @@ const SendPreviewPage = () => {
2121
const searchParams = useSearchParams();
2222
const isKakaoLoaded = useKakaoSDK();
2323
const [letterState, setLetterState] = useRecoilState(sendLetterState);
24-
const { draftId, receiverName, content, images, templateType, letterId } =
25-
useRecoilValue(sendLetterState);
24+
const {
25+
draftId,
26+
senderName,
27+
receiverName,
28+
content,
29+
images,
30+
templateType,
31+
letterId
32+
} = useRecoilValue(sendLetterState);
2633
const { name } = useRecoilValue(userState);
2734
const [isImage, setIsImage] = useState<boolean>(false);
2835
const [letterCode, setLetterCode] = useState<string>('');
@@ -86,6 +93,7 @@ const SendPreviewPage = () => {
8693
if (isGuest) {
8794
// 비회원 편지 저장 API 연동
8895
const response = await postAnonymousSendLetter({
96+
senderName,
8997
receiverName,
9098
content,
9199
images,
@@ -120,7 +128,7 @@ const SendPreviewPage = () => {
120128
requestUrl: location.origin + location.pathname,
121129
templateId: 112798,
122130
templateArgs: {
123-
senderName: isGuest ? receiverName + ' 님께' : name + ' 님으로부터',
131+
senderName: `${isGuest ? senderName : name}`,
124132
id: letterCode
125133
},
126134
serverCallbackArgs: {
@@ -204,7 +212,11 @@ const SendPreviewPage = () => {
204212
buttonType="primary"
205213
text="카카오로 편지 보내기"
206214
onClick={handleSendLetterAndShare}
207-
disabled={!receiverName || !content || isLoading}
215+
disabled={
216+
isGuest
217+
? !receiverName || !content || !senderName || isLoading
218+
: !receiverName || !content || isLoading
219+
}
208220
>
209221
<Image
210222
src="/assets/icons/ic_kakao_talk.svg"

src/app/send/(process)/receiver/page.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,15 +212,16 @@ const SendReceiverPage = () => {
212212
console.log('임시 저장 조회 성공', response.data);
213213

214214
console.log('상태 변경됨');
215-
setLetterState({
215+
setLetterState((prev) => ({
216+
...prev,
216217
draftId: response.data.draftKey,
217218
receiverName: response.data.receiverName,
218219
content: response.data.content,
219220
images: response.data.images,
220221
previewImages: response.data.images,
221222
templateType: 0,
222223
letterId: null
223-
});
224+
}));
224225

225226
// 각 input 상태 업데이트
226227
setDraftId(response.data.draftKey);
@@ -250,7 +251,7 @@ const SendReceiverPage = () => {
250251
)}
251252
<Container>
252253
<Column>
253-
<Label>편지를 받는 사람</Label>
254+
<Label>{isGuest && 'To.'} 편지를 받는 사람</Label>
254255
<Input
255256
inputType="boxText"
256257
value={receiver}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
'use client';
2+
3+
import React, { Suspense, useEffect, useState } from 'react';
4+
import styled, { css } from 'styled-components';
5+
import { theme } from '@/styles/theme';
6+
import Input from '@/components/common/Input';
7+
import Button from '@/components/common/Button';
8+
import { useRouter, useSearchParams } from 'next/navigation';
9+
import { sendLetterState } from '@/recoil/letterStore';
10+
import { useRecoilState } from 'recoil';
11+
import { useToast } from '@/hooks/useToast';
12+
import Loader, { LoaderContainer } from '@/components/common/Loader';
13+
14+
const SendSenderPage = () => {
15+
const router = useRouter();
16+
const searchParams = useSearchParams();
17+
const { showToast } = useToast();
18+
const [draftId, setDraftId] = useState<string | null>(null);
19+
const [sender, setSender] = useState<string>('');
20+
const [receiver, setReceiver] = useState<string>('');
21+
const [content, setContent] = useState<string>('');
22+
const [images, setImages] = useState<string[]>([]); // 서버 전송용
23+
const [previewImages, setPreviewImages] = useState<string[]>([]); // 미리보기용
24+
25+
const isGuest = searchParams.get('guest') === 'true';
26+
const [letterState, setLetterState] = useRecoilState(sendLetterState);
27+
28+
useEffect(() => {
29+
if (letterState) {
30+
setDraftId(letterState.draftId);
31+
setSender(letterState.senderName);
32+
setReceiver(letterState.receiverName);
33+
setContent(letterState.content);
34+
setImages(letterState.images);
35+
setPreviewImages(letterState.images);
36+
}
37+
}, [letterState]);
38+
39+
const handleSenderChange = (newValue: string) => {
40+
setSender(newValue);
41+
setLetterState((prevState) => ({
42+
...prevState,
43+
senderName: newValue
44+
}));
45+
};
46+
47+
const handleAddNext = async () => {
48+
/* 다음 페이지 */
49+
setLetterState((prevState) => ({
50+
...prevState,
51+
draftId: draftId,
52+
receiverName: receiver,
53+
content: content,
54+
images: images,
55+
previewImages: previewImages
56+
}));
57+
58+
router.push(`/send/template${isGuest ? '?guest=true' : ''}`);
59+
};
60+
61+
return (
62+
<>
63+
<Container>
64+
<Column>
65+
<Label>From. 편지를 보내는 사람</Label>
66+
<Input
67+
inputType="boxText"
68+
value={sender}
69+
onChange={handleSenderChange}
70+
placeholder="작성자 본인의 '성 + 이름' 의 실명을 입력해주세요"
71+
/>
72+
</Column>
73+
</Container>
74+
<ButtonWrapper>
75+
<Button
76+
buttonType="primary"
77+
size="large"
78+
text={'다음'}
79+
disabled={!sender}
80+
onClick={handleAddNext}
81+
/>
82+
</ButtonWrapper>
83+
</>
84+
);
85+
};
86+
87+
export default function SendSenderPaging() {
88+
return (
89+
<Suspense
90+
fallback={
91+
<LoaderContainer>
92+
<Loader />
93+
</LoaderContainer>
94+
}
95+
>
96+
<SendSenderPage />
97+
</Suspense>
98+
);
99+
}
100+
101+
const Container = styled.div`
102+
width: 100%;
103+
height: 100%;
104+
display: flex;
105+
flex-direction: column;
106+
overflow-y: auto;
107+
108+
&::-webkit-scrollbar {
109+
display: none;
110+
}
111+
112+
@media (max-height: 628px) {
113+
position: relative;
114+
}
115+
`;
116+
117+
const Column = styled.div<{ $position?: boolean }>`
118+
margin-bottom: 40px;
119+
120+
@media (max-height: 710px) {
121+
margin-bottom: 20px;
122+
}
123+
124+
@media (max-height: 628px) {
125+
${({ $position }) =>
126+
$position &&
127+
css`
128+
width: 100%;
129+
position: absolute;
130+
top: 300px;
131+
`}
132+
}
133+
134+
@media (max-height: 580px) {
135+
${({ $position }) =>
136+
$position &&
137+
css`
138+
width: 100%;
139+
position: absolute;
140+
top: 280px;
141+
`}
142+
}
143+
`;
144+
145+
const Label = styled.div<{ $show?: boolean }>`
146+
display: flex;
147+
justify-content: space-between;
148+
align-items: center;
149+
color: ${theme.colors.white};
150+
${(props) => props.theme.fonts.subtitle};
151+
margin-bottom: 12px;
152+
153+
@media (max-height: 628px) {
154+
${theme.fonts.body6}
155+
margin-bottom: 12px;
156+
${({ $show }) =>
157+
$show === false &&
158+
css`
159+
display: none;
160+
margin-bottom: 0px;
161+
`}
162+
}
163+
164+
@media (max-height: 580px) {
165+
${theme.fonts.body10}
166+
margin-bottom: 8px;
167+
}
168+
`;
169+
170+
const ButtonWrapper = styled.div`
171+
width: 100%;
172+
position: absolute;
173+
padding: 0 20px;
174+
bottom: 40px;
175+
left: 0;
176+
`;
177+
178+
const DescriptionText = styled.button`
179+
width: 100%;
180+
display: flex;
181+
justify-content: center;
182+
padding: 23px;
183+
text-decoration: underline;
184+
${theme.fonts.body09};
185+
color: ${(props) => props.theme.colors.gray400};
186+
`;
187+
188+
const BottomWrapper = styled.div`
189+
width: 100%;
190+
max-width: 393px;
191+
position: absolute;
192+
bottom: 0px;
193+
z-index: 1000;
194+
`;

src/recoil/letterStore.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const sendLetterState = atom({
4141
key: 'sendLetterState',
4242
default: {
4343
draftId: null as string | null,
44+
senderName: null as string | null,
4445
receiverName: '',
4546
content: '',
4647
images: [] as string[],

0 commit comments

Comments
 (0)