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()