@@ -9,8 +12,7 @@ export default function EmailHeroSection() {
본인 인증 메일을 귀하의
- {' '}
- boogririn@gmail.com
+ {' ' + email}
로 보냈습니다.
diff --git a/apps/web/src/pages/SignUp/components/SignUpform.tsx b/apps/web/src/pages/SignUp/components/SignUpform.tsx
index f2836a7..3231928 100644
--- a/apps/web/src/pages/SignUp/components/SignUpform.tsx
+++ b/apps/web/src/pages/SignUp/components/SignUpform.tsx
@@ -11,6 +11,7 @@ import {
useSignupMutation,
} from '../../../api/signup/signup';
import { useState } from 'react';
+import { useEmailStore } from '../../../store/useSignUpStore';
const SignUpForm = () => {
const { mutate: checkDuplicateEmail } = useDuplicatedEmailMutation();
@@ -19,6 +20,7 @@ const SignUpForm = () => {
const [duplicateSuccess, setDuplicateSuccess] = useState(
null,
);
+ const { setEmail } = useEmailStore();
const {
register,
@@ -46,10 +48,12 @@ const SignUpForm = () => {
checkDuplicateEmail(email, {
onSuccess: (data) => {
- if (data?.isDuplicate) {
+ if (data?.data?.isDuplicate) {
+ console.log(data);
setDuplicateSuccess(false);
setDuplicateMessage('이미 가입된 이메일입니다.');
} else {
+ console.log(data);
setDuplicateSuccess(true);
setDuplicateMessage('사용 가능한 이메일입니다');
}
@@ -67,6 +71,9 @@ const SignUpForm = () => {
setDuplicateSuccess(false);
return;
}
+
+ setEmail(data.email);
+
signupMutation.mutate({
email: data.email,
password: data.password,
diff --git a/apps/web/src/pages/SignUp/components/VerifyAction.tsx b/apps/web/src/pages/SignUp/components/VerifyAction.tsx
index 5fc22df..805e18b 100644
--- a/apps/web/src/pages/SignUp/components/VerifyAction.tsx
+++ b/apps/web/src/pages/SignUp/components/VerifyAction.tsx
@@ -1,11 +1,22 @@
import { Button } from '@ui/Button/Button';
import TextField from '@ui/InputField/TextField';
+import { useNavigate } from 'react-router-dom';
+
+export default function VerifyAction({ email }: { email: string }) {
+ const navigate = useNavigate();
-export default function VerifyAction() {
return (
-
-
+
+
);
}
diff --git a/apps/web/src/store/useSignUpStore.ts b/apps/web/src/store/useSignUpStore.ts
new file mode 100644
index 0000000..a61e082
--- /dev/null
+++ b/apps/web/src/store/useSignUpStore.ts
@@ -0,0 +1,20 @@
+import { create } from 'zustand';
+import { createJSONStorage, persist } from 'zustand/middleware';
+
+interface EmailState {
+ email: string;
+ setEmail: (email: string) => void;
+}
+
+export const useEmailStore = create()(
+ persist(
+ (set) => ({
+ email: '',
+ setEmail: (email) => set({ email }),
+ }),
+ {
+ name: 'email',
+ storage: createJSONStorage(() => sessionStorage),
+ },
+ ),
+);
From 195bd8e734628f00e0f3538fab3c00569520f424 Mon Sep 17 00:00:00 2001
From: Lee hwan seuk
Date: Wed, 29 Oct 2025 17:29:07 +0900
Subject: [PATCH 05/14] =?UTF-8?q?feat(signup):=20=EC=9D=B4=EB=A9=94?=
=?UTF-8?q?=EC=9D=BC=20=EC=9D=B8=EC=A6=9D=20=EB=8B=A4=EC=8B=9C=20=EB=B3=B4?=
=?UTF-8?q?=EB=82=B4=EA=B8=B0=20api=20=EA=B5=AC=ED=98=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/web/src/api/signup/verifyEmail.ts | 14 +++++--
.../pages/SignUp/EmailVerificationPage.tsx | 15 +++++++-
.../pages/SignUp/ResendVerificationPage.tsx | 15 ++++++--
.../pages/SignUp/components/ResendSection.tsx | 14 +++----
package-lock.json | 38 +++++++++++++++++--
.../src/components/InputField/TextField.tsx | 3 ++
6 files changed, 77 insertions(+), 22 deletions(-)
diff --git a/apps/web/src/api/signup/verifyEmail.ts b/apps/web/src/api/signup/verifyEmail.ts
index 57467bc..378af61 100644
--- a/apps/web/src/api/signup/verifyEmail.ts
+++ b/apps/web/src/api/signup/verifyEmail.ts
@@ -1,9 +1,10 @@
import { useMutation } from '@tanstack/react-query';
import api from '../api';
+import { useNavigate } from 'react-router-dom';
export interface ResendVerifyEmailRequest {
email: string;
- token: string;
+ callbackUrl: string;
}
const verifyEmail = async (token: string) => {
@@ -18,14 +19,16 @@ const verifyEmail = async (token: string) => {
};
const resendVerifyEmail = async (data: ResendVerifyEmailRequest) => {
- const response = await api.post('/auth/resend-verify-email', {
+ const response = await api.post('/auth/resend-verification-email', {
...data,
callbackUrl: `${window.location.origin}/auth/resend`,
});
+
const result = response.data;
if (!result.success) {
- throw new Error(result || '다시 보내기 실패패');
+ console.log(result);
+ throw new Error(result || '다시 보내기 실패');
}
return response.data;
@@ -45,11 +48,14 @@ export const useVerifyEmailMutation = () => {
};
export const useResendVerifyEmailMuation = () => {
+ const navigate = useNavigate();
+
return useMutation({
mutationFn: resendVerifyEmail,
onSuccess: (data) => {
- console.log('✅ 인증 다시 보내기기 성공:', data);
+ navigate('/auth/resend');
+ console.log('✅ 인증 다시 보내기 성공:', data);
},
onError: (error: unknown) => {
console.error('❌ 인증 다시 실패:', error);
diff --git a/apps/web/src/pages/SignUp/EmailVerificationPage.tsx b/apps/web/src/pages/SignUp/EmailVerificationPage.tsx
index 67725a9..7d6e26e 100644
--- a/apps/web/src/pages/SignUp/EmailVerificationPage.tsx
+++ b/apps/web/src/pages/SignUp/EmailVerificationPage.tsx
@@ -3,11 +3,18 @@ import EmailHeroSection from './components/EmailHeroSection';
import ResendSection from './components/ResendSection';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { useEffect } from 'react';
-import { useVerifyEmailMutation } from '../../api/signup/verifyEmail';
+import {
+ ResendVerifyEmailRequest,
+ useResendVerifyEmailMuation,
+ useVerifyEmailMutation,
+} from '../../api/signup/verifyEmail';
+import { useEmailStore } from '../../store/useSignUpStore';
const EmailVerificationPage = () => {
const [searchParams] = useSearchParams();
const verifyEmailMutation = useVerifyEmailMutation();
+ const resendverifyEmailMutation = useResendVerifyEmailMuation();
+ const email = useEmailStore((state) => state.email);
const navigate = useNavigate();
useEffect(() => {
@@ -17,6 +24,10 @@ const EmailVerificationPage = () => {
}
}, [searchParams]);
+ const onSubmit = () => {
+ resendverifyEmailMutation.mutate({ email: email, callbackUrl: '' });
+ };
+
return (
@@ -27,7 +38,7 @@ const EmailVerificationPage = () => {
text="로그인"
className="text-body-xl-medium h-[49px] w-[440px]"
/>
-
+
diff --git a/apps/web/src/pages/SignUp/ResendVerificationPage.tsx b/apps/web/src/pages/SignUp/ResendVerificationPage.tsx
index 695cfdb..cdddf6b 100644
--- a/apps/web/src/pages/SignUp/ResendVerificationPage.tsx
+++ b/apps/web/src/pages/SignUp/ResendVerificationPage.tsx
@@ -3,28 +3,37 @@ import ResendEmailHerosection from './components/ResendEmailHeroSection';
import ResendSection from './components/ResendSection';
import VerifyAction from './components/VerifyAction';
import { useSearchParams } from 'react-router-dom';
-import { useResendVerifyEmailMuation } from '../../api/signup/verifyEmail';
+import {
+ ResendVerifyEmailRequest,
+ useResendVerifyEmailMuation,
+ useVerifyEmailMutation,
+} from '../../api/signup/verifyEmail';
import { useEmailStore } from '../../store/useSignUpStore';
const ResendVerificationPage = () => {
const [searchParams] = useSearchParams();
+ const verifyEmailMutation = useVerifyEmailMutation();
const resendverifyEmailMutation = useResendVerifyEmailMuation();
const email = useEmailStore((state) => state.email);
useEffect(() => {
const token = searchParams.get('token');
if (token) {
- resendverifyEmailMutation.mutate({ token, email });
+ verifyEmailMutation.mutate(token);
}
}, [searchParams]);
+ const onSubmit = () => {
+ resendverifyEmailMutation.mutate({ email: email, callbackUrl: '' });
+ };
+
return (
diff --git a/apps/web/src/pages/SignUp/components/ResendSection.tsx b/apps/web/src/pages/SignUp/components/ResendSection.tsx
index 9f2580a..e495632 100644
--- a/apps/web/src/pages/SignUp/components/ResendSection.tsx
+++ b/apps/web/src/pages/SignUp/components/ResendSection.tsx
@@ -1,17 +1,13 @@
-import { useNavigate } from 'react-router-dom';
-
-export default function ResendSection() {
- const navigate = useNavigate();
-
- const handleResendClick = () => {
- navigate('/auth/resend');
- };
+interface ResendSectionProps {
+ onClick: () => void;
+}
+export default function ResendSection({ onClick }: ResendSectionProps) {
return (
이메일을 못받으셨나요?
이메일 다시 보내기
diff --git a/package-lock.json b/package-lock.json
index 39bce05..2e8333f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -93,7 +93,8 @@
"axios": "^1.6.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "react-router-dom": "^7.9.4"
+ "react-router-dom": "^7.9.4",
+ "zustand": "^5.0.8"
},
"devDependencies": {
"@types/react": "^18.2.0",
@@ -3221,7 +3222,7 @@
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/@types/q": {
@@ -3234,7 +3235,7 @@
"version": "18.3.26",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.26.tgz",
"integrity": "sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==",
- "dev": true,
+ "devOptional": true,
"license": "MIT",
"dependencies": {
"@types/prop-types": "*",
@@ -5456,7 +5457,7 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true,
+ "devOptional": true,
"license": "MIT"
},
"node_modules/data-view-buffer": {
@@ -14793,6 +14794,35 @@
"zod": "^3.25.0 || ^4.0.0"
}
},
+ "node_modules/zustand": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz",
+ "integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20.0"
+ },
+ "peerDependencies": {
+ "@types/react": ">=18.0.0",
+ "immer": ">=9.0.6",
+ "react": ">=18.0.0",
+ "use-sync-external-store": ">=1.2.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "immer": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "use-sync-external-store": {
+ "optional": true
+ }
+ }
+ },
"packages/api": {
"version": "0.0.0",
"license": "MIT",
diff --git a/packages/ui/src/components/InputField/TextField.tsx b/packages/ui/src/components/InputField/TextField.tsx
index 14a0433..613b213 100644
--- a/packages/ui/src/components/InputField/TextField.tsx
+++ b/packages/ui/src/components/InputField/TextField.tsx
@@ -5,6 +5,7 @@ interface TextFieldProps {
type?: string;
placeholder?: string;
value?: string;
+ disabled?: boolean;
maxLength?: number;
onChange?: (e: React.ChangeEvent) => void;
onFocus?: (e: React.FocusEvent) => void;
@@ -21,6 +22,7 @@ const TextField = forwardRef(
placeholder = '이름을 입력하세요',
value,
maxLength,
+ disabled,
onChange,
onFocus,
onBlur,
@@ -38,6 +40,7 @@ const TextField = forwardRef(
placeholder={placeholder}
value={value}
maxLength={maxLength}
+ disabled={disabled}
onChange={onChange}
onFocus={onFocus}
onBlur={onBlur}
From 4eaf4625f9d93af2b72714d3c4468d9a6519703a Mon Sep 17 00:00:00 2001
From: Lee hwan seuk
Date: Wed, 29 Oct 2025 18:29:24 +0900
Subject: [PATCH 06/14] =?UTF-8?q?fix(signup):=20=ED=9A=8C=EC=9B=90?=
=?UTF-8?q?=EA=B0=80=EC=9E=85=20=EC=99=84=EB=A3=8C=20=EC=8B=9C=20=EC=A0=84?=
=?UTF-8?q?=EC=97=AD=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20=EC=83=81=ED=83=9C=20?=
=?UTF-8?q?=EC=B4=88=EA=B8=B0=ED=99=94?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
apps/web/src/api/signup/signup.ts | 7 +++++--
apps/web/src/api/signup/verifyEmail.ts | 13 +++++++++----
apps/web/src/main.tsx | 8 +++-----
apps/web/src/pages/SignUp/EmailVerificationPage.tsx | 6 ++++--
.../web/src/pages/SignUp/ResendVerificationPage.tsx | 6 ++++--
apps/web/src/pages/SignUp/components/SignUpform.tsx | 4 ++--
apps/web/src/store/useSignUpStore.ts | 2 +-
7 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/apps/web/src/api/signup/signup.ts b/apps/web/src/api/signup/signup.ts
index e2c7b2a..34b43d1 100644
--- a/apps/web/src/api/signup/signup.ts
+++ b/apps/web/src/api/signup/signup.ts
@@ -10,11 +10,13 @@ export interface SignupRequest {
avatar?: string;
}
+/* 이메일 중복 확인 api */
const duplicatedEmail = async (email: string) => {
const response = await api.post('/auth/check-email', { email });
return response.data;
};
+/* 회원가입 api */
const signupUser = async (data: SignupRequest) => {
const response = await api.post(`/auth/sign-up`, {
...data,
@@ -22,6 +24,7 @@ const signupUser = async (data: SignupRequest) => {
});
const result = response.data;
+ /* 회원가입 실패 시 예외 처리 */
if (!result.success) {
throw new Error(result || '회원가입 실패');
}
@@ -43,10 +46,10 @@ export const useSignupMutation = () => {
onSuccess: (data) => {
// 회원가입 성공 시, 인증 안내 페이지로 이동
navigate('/auth/verify');
- console.log('✅ 회원가입 성공:', data);
+ console.log('회원가입 성공:', data);
},
onError: (error: unknown) => {
- console.error('❌ 회원가입 실패:', error);
+ console.error('회원가입 실패:', error);
alert('회원가입에 실패했습니다. 잠시 후 다시 시도해주세요.');
},
});
diff --git a/apps/web/src/api/signup/verifyEmail.ts b/apps/web/src/api/signup/verifyEmail.ts
index 378af61..f988b07 100644
--- a/apps/web/src/api/signup/verifyEmail.ts
+++ b/apps/web/src/api/signup/verifyEmail.ts
@@ -7,6 +7,7 @@ export interface ResendVerifyEmailRequest {
callbackUrl: string;
}
+/*이메일 인증 api*/
const verifyEmail = async (token: string) => {
const response = await api.post('/auth/verify-email', { token });
const result = response.data;
@@ -18,6 +19,7 @@ const verifyEmail = async (token: string) => {
return response.data;
};
+/*이메일 인증 다시 보내기 api*/
const resendVerifyEmail = async (data: ResendVerifyEmailRequest) => {
const response = await api.post('/auth/resend-verification-email', {
...data,
@@ -39,10 +41,13 @@ export const useVerifyEmailMutation = () => {
mutationFn: verifyEmail,
onSuccess: (data) => {
- console.log('✅ 이메일 인증 성공:', data);
+ console.log('이메일 인증 성공:', data);
+ alert('인증 성공!');
+ localStorage.clear();
},
onError: (error: unknown) => {
- console.error('❌ 인증 실패:', error);
+ console.error('인증 실패:', error);
+ alert('인증 실패! 다시 시도해주세요');
},
});
};
@@ -55,10 +60,10 @@ export const useResendVerifyEmailMuation = () => {
onSuccess: (data) => {
navigate('/auth/resend');
- console.log('✅ 인증 다시 보내기 성공:', data);
+ console.log('인증 다시 보내기 성공:', data);
},
onError: (error: unknown) => {
- console.error('❌ 인증 다시 실패:', error);
+ console.error('인증 다시 보내기 실패:', error);
},
});
};
diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx
index e07ee24..d0c514d 100644
--- a/apps/web/src/main.tsx
+++ b/apps/web/src/main.tsx
@@ -16,9 +16,7 @@ const queryClient = new QueryClient({
});
ReactDOM.createRoot(document.getElementById('root')!).render(
-
-
-
-
- ,
+
+
+ ,
);
diff --git a/apps/web/src/pages/SignUp/EmailVerificationPage.tsx b/apps/web/src/pages/SignUp/EmailVerificationPage.tsx
index 7d6e26e..df32e78 100644
--- a/apps/web/src/pages/SignUp/EmailVerificationPage.tsx
+++ b/apps/web/src/pages/SignUp/EmailVerificationPage.tsx
@@ -17,6 +17,7 @@ const EmailVerificationPage = () => {
const email = useEmailStore((state) => state.email);
const navigate = useNavigate();
+ /* 토큰 여부에 따른 이메일 인증 */
useEffect(() => {
const token = searchParams.get('token');
if (token) {
@@ -24,7 +25,8 @@ const EmailVerificationPage = () => {
}
}, [searchParams]);
- const onSubmit = () => {
+ /*이메일 다시 보내기 */
+ const onResendClick = () => {
resendverifyEmailMutation.mutate({ email: email, callbackUrl: '' });
};
@@ -38,7 +40,7 @@ const EmailVerificationPage = () => {
text="로그인"
className="text-body-xl-medium h-[49px] w-[440px]"
/>
-
+