From 45dc4cbaaa16f50168169c0df4b3a788836ed22d Mon Sep 17 00:00:00 2001 From: geonhee-min Date: Mon, 1 Dec 2025 16:22:40 +0900 Subject: [PATCH] =?UTF-8?q?issue=20#33=20-=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EC=9A=94=EC=B2=AD=20=ED=9B=84=20=EC=9D=91=EB=8B=B5=EC=9D=84?= =?UTF-8?q?=20AuthData=20=EB=A1=9C=20=EC=A0=80=EC=9E=A5=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84=20-=20Access/Refresh=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20=EA=B5=AC=ED=98=84=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 4 +- src/const/HttpResponse.ts | 9 +++++ .../RoutingData.ts => const/PageRouting.ts} | 2 +- src/data/AuthData.ts | 1 - src/network/AccountNetwork.ts | 39 ++++++++++++++++--- src/network/BaseNetwork.ts | 20 ++++++---- src/store/authStore.ts | 13 ++++++- src/ui/page/login/LoginPage.tsx | 36 ++++++++++------- .../page/resetPassword/ResetPasswordPage.tsx | 2 +- src/ui/page/signup/SignUpPage.tsx | 2 +- vite.config.ts | 3 ++ 11 files changed, 97 insertions(+), 34 deletions(-) create mode 100644 src/const/HttpResponse.ts rename src/{data/RoutingData.ts => const/PageRouting.ts} (91%) diff --git a/src/App.tsx b/src/App.tsx index f87273a..28de1e2 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,7 +3,7 @@ import SignUpPage from './ui/page/signup/SignUpPage'; import Layout from './layouts/Layout'; import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import { useAuthStore } from './store/authStore'; -import { PageRouting } from './data/RoutingData'; +import { PageRouting } from './const/PageRouting'; import LoginPage from './ui/page/login/LoginPage'; import ResetPasswordPage from './ui/page/resetPassword/ResetPasswordPage'; @@ -17,7 +17,7 @@ function App() { } path={PageRouting["LOGIN"].path} /> } path={PageRouting["SIGN_UP"].path} /> } path={PageRouting["RESET_PASSWORD"].path} /> - {!(authData?.isLogedIn) ? } path="*" /> : null} + {!authData ? } path="*" /> : null} diff --git a/src/const/HttpResponse.ts b/src/const/HttpResponse.ts new file mode 100644 index 0000000..ff6e2e3 --- /dev/null +++ b/src/const/HttpResponse.ts @@ -0,0 +1,9 @@ +export const HttpResponse = { + "ACCESS_TOKEN_EXPIRED": "ACCESS TOKEN EXPIRED", + "REFRESH_TOKEN_EXPIRED": "REFRESH TOKEN EXPIRED", + "UNAUTHORIZED": "UNAUTHORIZED", + "OK": "OK", + "CREATED": "CREATED", + "BAD_REQUEST": "BAD REQUEST", + "INTERNAL_SERVER_ERROR": "INTERNAL SERVER ERROR" +} as const; \ No newline at end of file diff --git a/src/data/RoutingData.ts b/src/const/PageRouting.ts similarity index 91% rename from src/data/RoutingData.ts rename to src/const/PageRouting.ts index 3b978c6..e800042 100644 --- a/src/data/RoutingData.ts +++ b/src/const/PageRouting.ts @@ -16,5 +16,5 @@ export const PageRouting: Record = { USER_FOLLOWING: { path: "/info/following", title: "팔로잉 목록" }, USER_FOLLOWER: { path: "/info/follower", title: "팔로워 목록" }, SETTINGS: { path: "/settings", title: "설정" }, - NOT_FOUD: { path: "/not-found", title: "존재하지 않는 페이지" }, + NOT_FOUND: { path: "/not-found", title: "존재하지 않는 페이지" }, } as const; \ No newline at end of file diff --git a/src/data/AuthData.ts b/src/data/AuthData.ts index 8805e52..6b3e939 100644 --- a/src/data/AuthData.ts +++ b/src/data/AuthData.ts @@ -1,5 +1,4 @@ export type AuthData = { accessToken: string; refreshToken: string; - isLogedIn: boolean; } \ No newline at end of file diff --git a/src/network/AccountNetwork.ts b/src/network/AccountNetwork.ts index 860863d..6fe868e 100644 --- a/src/network/AccountNetwork.ts +++ b/src/network/AccountNetwork.ts @@ -20,22 +20,51 @@ export class AccountNetwork extends BaseNetwork { async checkDuplication(data: CheckDuplicationRequest) { const { type, value } = data; - return await this.instance.get(`${this.baseUrl}/check-duplication?type=${type}&value=${value}`); + return await this.get( + `${this.baseUrl}/check-duplication?type=${type}&value=${value}` + , { + authPass: true + } + ); } async sendVerificationCode(data: SendVerificationCodeRequest) { - return await this.instance.post(this.baseUrl + "/send-verification-code", data); + return await this.post( + this.baseUrl + "/send-verification-code" + , data + , { + authPass: true + } + ); } async verifyCode(data: VerifyCodeRequest) { - return await this.instance.post(this.baseUrl + "/verify-code", data); + return await this.post( + this.baseUrl + "/verify-code" + , data + , { + authPass: true + } + ); } async signup(data: SignupRequest) { - return await this.instance.post(this.baseUrl + "/signup", data); + return await this.post( + this.baseUrl + "/signup" + , data + , { + authPass: true + } + ); } async login(data: LoginRequest) { - return await this.instance.post(this.baseUrl + "/login", data); + return await this.post( + this.baseUrl + "/login" + , data + , { + authPass: true + } + ); } } \ No newline at end of file diff --git a/src/network/BaseNetwork.ts b/src/network/BaseNetwork.ts index 632f92f..bdef8e9 100644 --- a/src/network/BaseNetwork.ts +++ b/src/network/BaseNetwork.ts @@ -4,6 +4,7 @@ import type { AxiosRequestConfig, AxiosError, AxiosResponse, + InternalAxiosRequestConfig, } from "axios"; export class BaseNetwork { @@ -29,12 +30,15 @@ export class BaseNetwork { // ★ 요청 인터셉터 this.instance.interceptors.request.use( (config) => { - // 예: 자동 토큰 추가 - // const token = localStorage.getItem("token"); - // if (token) { - // config.headers.Authorization = `Bearer ${token}`; - // } - + const reqConfig = config as InternalAxiosRequestConfig & { authPass?: boolean }; + if (reqConfig.authPass) { + return config; + } + const accessToken = localStorage.getItem("accessToken"); + if (accessToken) { + config.headers.Authorization = `Bearer ${accessToken}`; + } + return config; }, (error: AxiosError) => Promise.reject(error) @@ -61,11 +65,11 @@ export class BaseNetwork { /** * 기본 CRUD 메서드 */ - protected async get(url: string, config?: AxiosRequestConfig) { + protected async get(url: string, config?: AxiosRequestConfig & { authPass?: boolean }) { return await this.instance.get(url, config); } - protected async post(url: string, data?: any, config?: AxiosRequestConfig) { + protected async post(url: string, data?: any, config?: AxiosRequestConfig & { authPass?: boolean }) { return await this.instance.post(url, data, config); } } \ No newline at end of file diff --git a/src/store/authStore.ts b/src/store/authStore.ts index 7fd58fb..2ba2bba 100644 --- a/src/store/authStore.ts +++ b/src/store/authStore.ts @@ -8,6 +8,15 @@ interface AuthStoreProps { export const useAuthStore = create((set) => ({ authData: undefined, - login: (data: AuthData) => set({ authData: data }), - logout: () => set({ authData: undefined }) + login: (data: AuthData) => { + set({ authData: data }); + Object.entries(data) + .forEach((entry) => { + localStorage.setItem(entry[0], entry[1]); + }) + }, + logout: () => { + set({ authData: undefined }); + localStorage.clear(); + } })); \ No newline at end of file diff --git a/src/ui/page/login/LoginPage.tsx b/src/ui/page/login/LoginPage.tsx index 20511db..9f262b3 100644 --- a/src/ui/page/login/LoginPage.tsx +++ b/src/ui/page/login/LoginPage.tsx @@ -7,17 +7,18 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { useCallback, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; -import { PageRouting } from '@/data/RoutingData'; +import { PageRouting } from '@/const/PageRouting'; import * as z from 'zod'; import { Separator } from '@/components/ui/separator'; import { Validator } from '@/util/Validator'; import { LoginRequest } from '@/data/request/account/LoginRequest'; import { AccountNetwork } from '@/network/AccountNetwork'; import { toast } from 'sonner'; -import { LoginResponse } from '@/data/response'; +import { useAuthStore } from '@/store/authStore'; export default function LoginPage() { const [isLoading, setIsLoading] = useState(false); + const { login } = useAuthStore(); const navigate = useNavigate(); const accountNetwork = new AccountNetwork(); const loginForm = useForm>({ @@ -37,17 +38,19 @@ export default function LoginPage() { navigate(PageRouting["RESET_PASSWORD"].path); }, []); - const moveToMainPage = useCallback(() => { - + const moveToHomePage = useCallback(() => { + navigate(PageRouting["HOME"].path); }, []); // TODO 33 로그인 기능 구현 - const login = async () => { + const reqLogin = async () => { if (isLoading) return; const type = Validator.isEmail(id) ? 'email' : 'accountId'; const data: LoginRequest = new LoginRequest(type, id, password); + setIsLoading(true); + const loginPromise = accountNetwork.login(data); toast.promise<{ message?: string }>( @@ -55,9 +58,9 @@ export default function LoginPage() { try { loginPromise.then((res) => { if (res.data.success) { - resolve({message: ''}) + resolve({message: ''}); } else { - reject(res.data.message) + reject(res.data.message); } }) } catch (err) { @@ -71,11 +74,18 @@ export default function LoginPage() { } ); - // loginPromise.then((res) => { - // if (res.data.success) { - // moveToMainPage(); - // } - // }); + loginPromise + .then((res) => { + if (res.data.success) { + const data = { + accessToken: res.data.accessToken!, + refreshToken: res.data.refreshToken! + } + login({ ...data }); + moveToHomePage(); + } + }) + .finally(() => setIsLoading(false)); } const TextSeparator = ({ text }: { text: string }) => { @@ -148,7 +158,7 @@ export default function LoginPage() { className="w-full bg-indigo-500 hover:bg-indigo-400" type="button" disabled={id.trim().length < 1 || password.trim().length < 1} - onClick={login} + onClick={reqLogin} > 로그인 diff --git a/src/ui/page/resetPassword/ResetPasswordPage.tsx b/src/ui/page/resetPassword/ResetPasswordPage.tsx index bafff7c..a421072 100644 --- a/src/ui/page/resetPassword/ResetPasswordPage.tsx +++ b/src/ui/page/resetPassword/ResetPasswordPage.tsx @@ -7,7 +7,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { useState, useCallback } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { useNavigate } from 'react-router-dom'; -import { PageRouting } from '@/data/RoutingData'; +import { PageRouting } from '@/const/PageRouting'; import * as z from 'zod'; export default function ResetPasswordPage() { diff --git a/src/ui/page/signup/SignUpPage.tsx b/src/ui/page/signup/SignUpPage.tsx index e186306..abe3adc 100644 --- a/src/ui/page/signup/SignUpPage.tsx +++ b/src/ui/page/signup/SignUpPage.tsx @@ -17,7 +17,7 @@ import { CheckDuplicationRequest, SignupRequest } from '@/data/request'; import { AccountNetwork } from '@/network/AccountNetwork'; import { toast } from 'sonner'; import { useNavigate } from 'react-router-dom'; -import { PageRouting } from '@/data/RoutingData'; +import { PageRouting } from '@/const/PageRouting'; export default function SignUpPage() { const [emailVerificationModalOpen, setEmailVerificationModalOpen] = useState(false); diff --git a/vite.config.ts b/vite.config.ts index 9dfd07f..732dddd 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,6 +4,9 @@ import tailwindcss from '@tailwindcss/vite' import path from 'path' // https://vite.dev/config/ export default defineConfig({ + server: { + port: 5185 + }, plugins: [ react(), tailwindcss()