Skip to content

Commit 69eced2

Browse files
authored
Merge pull request #209 from FE13-Part4-Team2/feat/#206/reset-passsword-page
[feat] #206 비밀번호 재설정 페이지 구현 / 요청에 따른 응답 처리 분기 / 코드 리뷰 반영
2 parents b9de4c3 + b052bb6 commit 69eced2

File tree

5 files changed

+57
-18
lines changed

5 files changed

+57
-18
lines changed

src/app/(auth)/login/_components/LoginForm/OpenPasswordResetModal.tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@ import ResetPasswordModal from '@/components/common/Modal/content/ResetPasswordM
44
import { postResetPasswordToEmail } from '@/lib/apis/user';
55
import { ResetPasswordToEmailBody } from '@/lib/apis/user/type';
66
import { useModalStore } from '@/store/useModalStore';
7-
import { useRouter } from 'next/navigation';
87
import { useEffect } from 'react';
98
import { toast } from 'react-toastify';
109

1110
export default function OpenPasswordResetModal({ ...props }) {
1211
const { openModal } = useModalStore();
13-
const router = useRouter();
1412

1513
useEffect(() => {
1614
const unsubscribe = useModalStore.subscribe(
@@ -30,7 +28,7 @@ export default function OpenPasswordResetModal({ ...props }) {
3028
}
3129
);
3230
return () => {
33-
unsubscribe(); // 언마운트, 구독 해제
31+
unsubscribe();
3432
};
3533
}, []);
3634

@@ -49,10 +47,9 @@ export default function OpenPasswordResetModal({ ...props }) {
4947
if (error instanceof Error) {
5048
const errorMessage = error.message;
5149

52-
// 존재하지 않는 유저 : User not found
50+
// User not found
5351
if (errorMessage.includes('User not found')) {
5452
toast.error('존재하지 않는 이메일입니다. 회원가입을 먼저 해주세요.');
55-
router.push('/signup');
5653
} else {
5754
toast.error(`Error : ${error}`);
5855
}
@@ -71,14 +68,13 @@ export default function OpenPasswordResetModal({ ...props }) {
7168
title: '비밀번호 재설정',
7269
description: '비밀번호 재설정 링크를 보내드립니다.',
7370
button: {
74-
formId: 'reset-password-form', // formId 연결
71+
formId: 'reset-password-form', // form 연결
7572
number: 2,
7673
text: '링크 보내기',
7774
// 기존 모달 컴포넌트의 onRequest 호출 방식과의 일관성을 위해 빈 함수 전달
7875
onRequest: () => {},
7976
},
8077
},
81-
8278
(() => <ResetPasswordModal />)()
8379
);
8480
}}

src/app/(auth)/reset-password/ResetPasswordForm.tsx

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
import InputWithLabel from '@/components/auth/InputWithLabel';
44
import Button from '@/components/common/Button';
5+
import { ROUTES } from '@/constants/routes';
6+
import { patchResetPassword } from '@/lib/apis/user';
57
import {
68
validatePassword,
79
validatePasswordConfirm,
810
} from '@/utils/inputValidation';
11+
import { useRouter, useSearchParams } from 'next/navigation';
912
import { useMemo, useState } from 'react';
13+
import { toast } from 'react-toastify';
1014
import { z } from 'zod';
1115

1216
// reset password schema
@@ -20,15 +24,13 @@ const resetPasswordSchema = z
2024
const { password, passwordConfirm } = val;
2125

2226
if (!password) {
23-
// 비밀번호가 비어있음
2427
ctx.addIssue({
2528
path: ['password'],
2629
code: z.ZodIssueCode.custom,
2730
message: '비밀번호는 필수 입력입니다.',
2831
fatal: true, // 조건 실패 시, 유효성 검사 중단
2932
});
3033
} else if (!validatePassword(password)) {
31-
// 비밀번호가 입력은 되었지만, 유효하지 않음
3234
ctx.addIssue({
3335
path: ['password'],
3436
code: z.ZodIssueCode.custom,
@@ -38,15 +40,13 @@ const resetPasswordSchema = z
3840
}
3941

4042
if (!passwordConfirm) {
41-
// 비밀번호 확인이 비어있는 경우
4243
ctx.addIssue({
4344
path: ['passwordConfirm'],
4445
code: z.ZodIssueCode.custom,
4546
message: '비밀번호 확인은 필수 입력입니다.',
4647
fatal: true,
4748
});
4849
} else if (!validatePasswordConfirm({ password, passwordConfirm })) {
49-
// 비밀번호 확인이 입력은 되었지만, 비밀번호와 일치하지 않음
5050
ctx.addIssue({
5151
path: ['passwordConfirm'],
5252
code: z.ZodIssueCode.custom,
@@ -71,6 +71,9 @@ export default function ResetPasswordForm() {
7171
passwordConfirm: [],
7272
});
7373

74+
const router = useRouter();
75+
const searchParams = useSearchParams();
76+
7477
const isFormValid = useMemo(() => {
7578
return (
7679
formValues.password !== '' &&
@@ -96,18 +99,52 @@ export default function ResetPasswordForm() {
9699
} else {
97100
setFormErrors((prev) => ({
98101
...prev,
99-
[key]: '',
102+
[key]: [],
100103
}));
101104
}
102105
setFormValues(newFormValues);
103106
};
104107

105-
const handleFormSubmit = () => {
106-
console.log('form submit');
108+
const handleFormSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
109+
e.preventDefault();
110+
111+
if (!isFormValid) return;
112+
113+
// formErrors 초기화
107114
setFormErrors({
108115
password: [],
109116
passwordConfirm: [],
110117
});
118+
119+
try {
120+
const token = searchParams.get('token');
121+
// early return
122+
if (!token) {
123+
toast.error('유효하지 않은 링크입니다. 다시 시도해주세요.');
124+
return;
125+
}
126+
127+
const res = await patchResetPassword({
128+
body: {
129+
passwordConfirmation: formValues.passwordConfirm,
130+
password: formValues.password,
131+
token,
132+
},
133+
});
134+
console.log('res', res);
135+
toast.success('비밀번호 재설정이 완료되었습니다.');
136+
router.push(ROUTES.LOGIN);
137+
} catch (error) {
138+
if (error instanceof Error) {
139+
const errorMessage = error.message;
140+
if (errorMessage.includes('유효하지 않은 토큰입니다.')) {
141+
toast.error(
142+
'비밀번호 재설정 링크카 만료되었습니다. 다시 요청해주세요.'
143+
);
144+
}
145+
console.error(errorMessage);
146+
}
147+
}
111148
};
112149
return (
113150
<form onSubmit={handleFormSubmit}>

src/app/(auth)/reset-password/page.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
import ResetPasswordForm from '@/app/(auth)/reset-password/ResetPasswordForm';
2+
import { Suspense } from 'react';
23

34
export default function ResetPasswordPage() {
45
return (
56
<div className="flex h-[calc(100vh-60px)] justify-center pt-[140px]">
67
<div className="flex flex-col">
7-
<ResetPasswordForm />
8+
<Suspense
9+
fallback={
10+
<div className="py-10 text-center text-slate-400">로딩 중...</div>
11+
}
12+
>
13+
<ResetPasswordForm />
14+
</Suspense>
815
</div>
916
</div>
1017
);

src/components/common/Modal/index.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ export default function Modal() {
3737
button?.onRequest?.(requestBody);
3838
closeModal();
3939
isSubmittedRef.current = false;
40-
console.log('handleRequest 실행');
4140
return;
4241
}
4342
}

src/lib/apis/user/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ export async function postResetPasswordToEmail({
102102
});
103103
}
104104

105-
// 이메일로 전달받은 링크에서 비밀번호 초기화 (PATCH /user/reset-password)
105+
// 비밀번호 재설정 페이지 : 이메일로 전달받은 링크에서 비밀번호 초기화 (PATCH /user/reset-password)
106106
export async function patchResetPassword({
107107
body,
108108
}: {
@@ -115,7 +115,7 @@ export async function patchResetPassword({
115115
});
116116
}
117117

118-
// 비밀번호 변경 (PATCH /user/password)
118+
// 계정 설정 페이지 : 비밀번호 변경 (PATCH /user/password)
119119
export async function patchPassword({
120120
body,
121121
}: {

0 commit comments

Comments
 (0)