diff --git a/src/@type/index.d.ts b/src/@type/index.d.ts index 8bf21737..a5cbb70c 100644 --- a/src/@type/index.d.ts +++ b/src/@type/index.d.ts @@ -135,6 +135,11 @@ declare module AuthType { interface resetPasswordState { email?: string; } + + type resetPasswordQuery = { + username: string; + code: string; + }; } declare module HomeType { diff --git a/src/app/store/ducks/auth/authSlice.ts b/src/app/store/ducks/auth/authSlice.ts index 1e209a50..f5b07036 100644 --- a/src/app/store/ducks/auth/authSlice.ts +++ b/src/app/store/ducks/auth/authSlice.ts @@ -1,6 +1,12 @@ import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { FormState } from "./authThunk.type"; -import { getUserInfo, signIn } from "./authThunk"; +import { + getUserInfo, + signIn, + resetPassword, + checkCurrentURL, + signInUseCode, +} from "./authThunk"; import { setAccessTokenInAxiosHeaders } from "customAxios"; export interface AuthStateProps { @@ -90,6 +96,16 @@ const authSlice = createSlice({ state.isLogin = true; setAccessTokenInAxiosHeaders(action.payload); }) + .addCase(resetPassword.fulfilled, (state, action) => { + state.isLoading = false; + state.isLogin = true; + setAccessTokenInAxiosHeaders(action.payload); + }) + .addCase(signInUseCode.fulfilled, (state, action) => { + state.isLoading = false; + state.isLogin = true; + setAccessTokenInAxiosHeaders(action.payload); + }) .addCase(signIn.rejected, (state, action) => { state.isAsyncReject = true; state.isLoading = false; @@ -104,6 +120,12 @@ const authSlice = createSlice({ .addCase(getUserInfo.pending, (state) => {}) .addCase(getUserInfo.fulfilled, (state, action) => { state.userInfo = action.payload; + }) + .addCase(resetPassword.rejected, (state) => { + state.errorMessage = `전에 사용한 적 없는 새로운 비밀번호를 만드세요.`; + }) + .addCase(checkCurrentURL.rejected, (state) => { + // 유효하지 않은 url ** }); }, }); diff --git a/src/app/store/ducks/auth/authThunk.ts b/src/app/store/ducks/auth/authThunk.ts index fa10a166..b4a8e62f 100644 --- a/src/app/store/ducks/auth/authThunk.ts +++ b/src/app/store/ducks/auth/authThunk.ts @@ -58,13 +58,54 @@ export const getUserInfo = createAsyncThunk( }, ); -// export const resetPassword = createAsyncThunk<>( -// "auth/passwordReset", -// async (payload, ThunkOptions) => { -// try { -// // call api -// } catch (error) { -// // error handling -// } -// }, -// ); +export const checkCurrentURL = createAsyncThunk< + void, + { code: string; username: string } +>("auth/checkResetPassword", async (payload, ThunkOptions) => { + try { + const config = { + params: { + code: payload.code, + username: payload.username, + }, + }; + const { data } = await customAxios.get( + `/accounts/password/reset`, + config, + ); + console.log(data); + } catch (error) { + throw ThunkOptions.rejectWithValue(error); + } +}); + +export const resetPassword = createAsyncThunk< + AuthType.Token, + { code: string; username: string; newPassword: string } +>("auth/resetPassword", async (payload, ThunkOptions) => { + try { + const { data } = await customAxios.put(`/accounts/password/reset`, { + code: payload.code, + username: payload.username, + newPassword: payload.newPassword, + }); + return data.data; + } catch (error) { + throw ThunkOptions.rejectWithValue(error); + } +}); + +export const signInUseCode = createAsyncThunk< + AuthType.Token, + { code: string; username: string } +>("auth/signInUseCode", async (payload) => { + try { + const { data } = await customAxios.post(`/accounts/login/recovery`, { + code: payload.code, + username: payload.username, + }); + return data.data; + } catch { + // 에러나는 경우? username, code가 잘못됐을 때? + } +}); diff --git a/src/components/Auth/ResetPassword/ResetPasswordForm.tsx b/src/components/Auth/ResetPassword/ResetPasswordForm.tsx index 9ceaad78..83ac270c 100644 --- a/src/components/Auth/ResetPassword/ResetPasswordForm.tsx +++ b/src/components/Auth/ResetPassword/ResetPasswordForm.tsx @@ -5,6 +5,9 @@ import ContentBox from "components/Common/ContentBox"; import styled from "styled-components"; import SubmitButton from "../SubmitButton"; import useInput from "hooks/useInput"; +import { useEffect, MouseEvent } from "react"; +import { useAppDispatch, useAppSelector } from "app/store/Hooks"; +import { checkCurrentURL, resetPassword } from "app/store/ducks/auth/authThunk"; const Container = styled.section` background-color: #fff; @@ -56,13 +59,25 @@ const Container = styled.section` margin: 20px 52px 60px 52px; height: 44px; } + + .error-message { + color: #ed4956; + font-size: 14px; + line-height: 18px; + text-align: center; + margin: 10px 40px; + } } } `; export default function ResetPasswordForm() { const { search } = useLocation(); - const { username, code } = queryString.parse(search); + const { username, code } = queryString.parse( + search, + ) as AuthType.resetPasswordQuery; + const dispatch = useAppDispatch(); + const { errorMessage } = useAppSelector((state) => state.auth); const [newPasswordInputProps, newPasswordIsValid] = useInput( "", @@ -76,8 +91,22 @@ export default function ResetPasswordForm() { (value) => newPasswordInputProps.value === value, ); - // submit api 연결 - // 들어오자마자, code유효한지 체크 -> 그 전까지, loding (using useEffect) + useEffect(() => { + dispatch(checkCurrentURL({ code, username })); + }, []); + + const resetPasswordClickHandler = ( + event: MouseEvent, + ) => { + event.preventDefault(); + dispatch( + resetPassword({ + code, + username, + newPassword: newPasswordInputProps.value, + }), + ); + }; return ( @@ -123,9 +152,15 @@ export default function ResetPasswordForm() { reEnterPasswordIsValid ) } + onClick={resetPasswordClickHandler} > 비밀번호 재설정 + {errorMessage && ( +
+

{errorMessage}

+
+ )} diff --git a/src/pages/Auth/index.tsx b/src/pages/Auth/index.tsx index f8aadf7e..e44419f9 100644 --- a/src/pages/Auth/index.tsx +++ b/src/pages/Auth/index.tsx @@ -3,7 +3,10 @@ import { useAppDispatch } from "app/store/Hooks"; import Form from "components/Auth/Form"; import { Footer } from "components/Common/Footer/Footer"; import { useEffect } from "react"; +import { useLocation } from "react-router-dom"; import styled from "styled-components"; +import queryString from "query-string"; +import { signInUseCode } from "app/store/ducks/auth/authThunk"; const Section = styled.section` flex-shrink: 0; @@ -19,7 +22,15 @@ const Section = styled.section` export default function AuthPage(props: { router: "signIn" | "signUp" }) { const dispatch = useAppDispatch(); + const { search } = useLocation(); + const { username, code } = queryString.parse( + search, + ) as AuthType.resetPasswordQuery; + useEffect(() => { + if (props.router === "signIn") { + dispatch(signInUseCode({ username, code })); + } dispatch(authAction.changeFormState(props.router)); }, []);