diff --git a/apps/cs/app/api/proxy/[...url]/route.ts b/apps/cs/app/api/proxy/[...url]/route.ts new file mode 100644 index 000000000..53f5a6e41 --- /dev/null +++ b/apps/cs/app/api/proxy/[...url]/route.ts @@ -0,0 +1,81 @@ +import { + ACCESS_TOKEN, + AUTH_USER_ID, + CLAIM_NAME, + REFRESH_TOKEN, + SERVER_API_URL, + SITE_ID, +} from "@/shared/config/env"; +import { cookies } from "next/headers"; +import { NextResponse } from "next/server"; + +export async function POST( + request: Request, + props: { params: Promise<{ url: string[] }> }, +) { + const params = await props.params; + + const headers: Record = { + "Content-Type": "application/json", + "X-Site-Id": SITE_ID ?? "", + }; + + const cookieStore = await cookies(); + + // silent refresh + if (params.url.includes("refresh")) { + const refreshToken = cookieStore.get(REFRESH_TOKEN); + headers[CLAIM_NAME] = refreshToken?.value ?? ""; + + if (!headers[CLAIM_NAME]) { + return NextResponse.json({ message: "Can't refresh" }, { status: 401 }); + } + } + + try { + const body = await request.json(); + const result = await fetch(`${SERVER_API_URL}/${params.url.join("/")}`, { + method: "POST", + headers, + body: JSON.stringify(body), + }); + + if (!result.ok) { + return NextResponse.json( + { message: "Invalid Credentials" }, + { status: 401 }, + ); + } + + const accessToken = result.headers.get(ACCESS_TOKEN); + const refreshToken = result.headers.get(REFRESH_TOKEN); + const userId = result.headers.get(AUTH_USER_ID); + + if (accessToken && userId) { + const response = NextResponse.json({ + [ACCESS_TOKEN]: accessToken, + [AUTH_USER_ID]: userId, + }); + + if (refreshToken) { + cookieStore.set(REFRESH_TOKEN, refreshToken, { + httpOnly: true, + sameSite: "lax", + path: "/", + }); + } + + return response; + } + + return NextResponse.json( + { message: "Invalid Credentials" }, + { status: 401 }, + ); + } catch (error) { + return NextResponse.json( + { message: "Server Error", error }, + { status: 500 }, + ); + } +} diff --git a/apps/cs/env.d.ts b/apps/cs/env.d.ts new file mode 100644 index 000000000..31ff74044 --- /dev/null +++ b/apps/cs/env.d.ts @@ -0,0 +1,16 @@ +/// + +interface ImportMetaEnv { + readonly VITE_PORT: string; + readonly VITE_PROXY_HOST: string; + readonly VITE_SERVER_API_URL: string; + readonly VITE_SITE_ID: string; + readonly VITE_CLAIM_NAME: string; + readonly VITE_ACCESS_TOKEN: string; + readonly VITE_REFRESH_TOKEN: string; + readonly VITE_AUTH_USER_ID: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/apps/cs/next.config.ts b/apps/cs/next.config.ts index 355adfad3..fd2a3a156 100644 --- a/apps/cs/next.config.ts +++ b/apps/cs/next.config.ts @@ -1,33 +1,49 @@ import type { NextConfig } from "next"; import webpack from "webpack"; +const serverApiUrl = + process.env.NEXT_PUBLIC_SERVER_API_URL || "http://localhost:3000"; + const nextConfig: NextConfig = { webpack: (config) => { config.plugins.push( new webpack.DefinePlugin({ + "import.meta.env.VITE_PORT": JSON.stringify( + process.env.NEXT_PUBLIC_PORT, + ), + "import.meta.env.VITE_PROXY_HOST": JSON.stringify( + process.env.NEXT_PUBLIC_PROXY_HOST, + ), "import.meta.env.VITE_SERVER_API_URL": JSON.stringify( - process.env.VITE_SERVER_API_URL, - ), - "import.meta.env.VITE_SITE_ID": JSON.stringify( - process.env.VITE_SITE_ID, + process.env.NEXT_PUBLIC_SERVER_API_URL, ), + "import.meta.env.VITE_SITE_ID": JSON.stringify(process.env.SITE_ID), "import.meta.env.VITE_CLAIM_NAME": JSON.stringify( - process.env.VITE_CLAIM_NAME, + process.env.NEXT_PUBLIC_CLAIM_NAME, ), "import.meta.env.VITE_ACCESS_TOKEN": JSON.stringify( - process.env.VITE_ACCESS_TOKEN, + process.env.NEXT_PUBLIC_ACCESS_TOKEN, ), "import.meta.env.VITE_REFRESH_TOKEN": JSON.stringify( - process.env.VITE_REFRESH_TOKEN, + process.env.NEXT_PUBLIC_REFRESH_TOKEN, ), - "import.meta.env.VITE_TOKEN_ID": JSON.stringify( - process.env.VITE_TOKEN_ID, + "import.meta.env.VITE_AUTH_USER_ID": JSON.stringify( + process.env.NEXT_PUBLIC_AUTH_USER_ID, ), + "process.env.SITE_ID": JSON.stringify(process.env.NEXT_PUBLIC_SITE_ID), }), ); return config; }, + async rewrites() { + return [ + { + source: "/server/:path*", + destination: `${serverApiUrl}/:path*`, + }, + ]; + }, }; export default nextConfig; diff --git a/apps/cs/package.json b/apps/cs/package.json index db07cc588..1797b4828 100644 --- a/apps/cs/package.json +++ b/apps/cs/package.json @@ -11,6 +11,7 @@ "dependencies": { "@common/assets": "workspace:*", "@common/components": "workspace:*", + "@tanstack/react-query": "^5.67.1", "@tanstack/react-table": "^8.21.2", "axios": "^1.8.1", "chart.js": "^4.4.8", diff --git a/apps/cs/src/app/index.tsx b/apps/cs/src/app/index.tsx index 9223b0790..a78e1c124 100644 --- a/apps/cs/src/app/index.tsx +++ b/apps/cs/src/app/index.tsx @@ -1,10 +1,15 @@ import "./styles/base.css"; import "./styles/components.css"; +import { CookieProvider, QueryProvider } from "@/shared/providers"; const App = ({ children }: Readonly<{ children: React.ReactNode }>) => { return ( - {children} + + + {children} + + ); }; diff --git a/apps/cs/src/entities/user/api/user-service.ts b/apps/cs/src/entities/user/api/user-service.ts new file mode 100644 index 000000000..a7209969f --- /dev/null +++ b/apps/cs/src/entities/user/api/user-service.ts @@ -0,0 +1,22 @@ +import { client } from "@/shared/api"; +import { getToken } from "@/shared/lib/cookie"; +import { AUTH_USER_ID, CLAIM_NAME, ENDPOINT } from "@/shared/config"; +import type { IUser, IUserInfo, UserService } from "../model/user"; + +export class UsersApiService implements UserService { + public async userInfo(payload: IUserInfo): Promise { + const response = await client.get( + `${ENDPOINT.USER_SERVICE.USERS}/${payload.userUniqId}`, + { + headers: { + [CLAIM_NAME]: `${getToken(CLAIM_NAME)}`, + [AUTH_USER_ID]: `${getToken(AUTH_USER_ID)}`, + }, + }, + ); + + return response.data; + } +} + +export const UserApi = new UsersApiService(); diff --git a/apps/cs/src/entities/user/index.ts b/apps/cs/src/entities/user/index.ts new file mode 100644 index 000000000..3076aa261 --- /dev/null +++ b/apps/cs/src/entities/user/index.ts @@ -0,0 +1 @@ +export { useUser } from "./lib/use-user"; diff --git a/apps/cs/src/entities/user/lib/use-user.ts b/apps/cs/src/entities/user/lib/use-user.ts new file mode 100644 index 000000000..a48c441c4 --- /dev/null +++ b/apps/cs/src/entities/user/lib/use-user.ts @@ -0,0 +1,19 @@ +import { useQuery } from "@tanstack/react-query"; +import { UserApi } from "../api/user-service"; +import { useCookie } from "@/shared/providers"; +import { AUTH_USER_ID, ENDPOINT } from "@/shared/config"; + +const useUser = () => { + const { getToken } = useCookie(); + const { data } = useQuery({ + queryKey: [ENDPOINT.USER_SERVICE.USERS], + queryFn: () => + UserApi.userInfo({ + userUniqId: getToken(AUTH_USER_ID) ?? "", + }), + }); + + return { userInfo: data }; +}; + +export { useUser }; diff --git a/apps/cs/src/entities/user/model/user.ts b/apps/cs/src/entities/user/model/user.ts new file mode 100644 index 000000000..1af75fbb7 --- /dev/null +++ b/apps/cs/src/entities/user/model/user.ts @@ -0,0 +1,41 @@ +export interface IUserInfo { + userUniqId: string; +} + +export interface IUser { + regDt: string; + mdfcnDt: string; + rgtr: string; + mdfr: string; + userUnqId: string; + userId: string; + userName: string; + email: string; + encryptedPassword: string; + refreshToken: string; + userStateCode: string; + lastLoginDate: string; + loginFailCount: number; + pswdHnt: string; + pswdAns: string; + mphn: string; + telno: string; + zip: string; + addr: string; + daddr: string; + laeSeCd: string; + ogdpSeCd: string; + aprvYn: string; + autzrId: string; + expryYmd: string; + lastPswdChgDt: string; + googleId: string; + kakaoId: string; + naverId: string; + isSocialUser: boolean; + hasPassword: boolean; +} + +export interface UserService { + userInfo: (payload: IUserInfo) => Promise; +} diff --git a/apps/cs/src/pages/auth/login/api/login.ts b/apps/cs/src/pages/auth/login/api/login.ts index da407960c..fc1d94ca1 100644 --- a/apps/cs/src/pages/auth/login/api/login.ts +++ b/apps/cs/src/pages/auth/login/api/login.ts @@ -1,12 +1,10 @@ import { AxiosError } from "axios"; -import { client } from "@/shared/api"; import { ACCESS_TOKEN, + AUTH_USER_ID, CLAIM_NAME, ENDPOINT, JWT_EXPIRATION_TIME, - REFRESH_TOKEN, - TOKEN_ID, } from "@/shared/config"; import { tokenManager } from "../lib/token-manager"; import type { LoginService, ILogin } from "../model/login"; @@ -25,22 +23,24 @@ export class LoginApiService implements LoginService { public async login(payload: ILogin): Promise { try { - const response = await client.post(ENDPOINT.USER_SERVICE.LOGIN, { - userId: payload.userId, - password: payload.password, + const response = await fetch(`/api/proxy${ENDPOINT.USER_SERVICE.LOGIN}`, { + method: "POST", + body: JSON.stringify({ + userId: payload.userId, + password: payload.password, + }), }); - const accessToken = response.headers[ACCESS_TOKEN]; - const refreshToken = response.headers[REFRESH_TOKEN]; - const tokenId = response.headers[TOKEN_ID]; + const data = await response.json(); + const accessToken = data[ACCESS_TOKEN]; + const tokenId = data[AUTH_USER_ID]; - if (!refreshToken || !accessToken || !tokenId) { + if (!accessToken || !tokenId) { throw new Error("Missing required authentication tokens"); } - tokenManager.setToken(ACCESS_TOKEN, accessToken); - tokenManager.setToken(TOKEN_ID, tokenId); - tokenManager.setRefreshToken(refreshToken); + tokenManager.setToken(CLAIM_NAME, accessToken); + tokenManager.setToken(AUTH_USER_ID, tokenId); tokenManager.setupRefreshTimer( () => this.silentRefresh(), JWT_EXPIRATION_TIME, @@ -57,25 +57,23 @@ export class LoginApiService implements LoginService { public async silentRefresh(): Promise { try { - const refreshToken = tokenManager.getRefreshToken(); - if (!refreshToken) { - throw new Error("No refresh token available"); - } + const response = await fetch( + `/api/proxy${ENDPOINT.USER_SERVICE.SILENT_REFRESH}`, + { method: "PUT" }, + ); - tokenManager.setToken(CLAIM_NAME, refreshToken); - - const response = await client.put(ENDPOINT.USER_SERVICE.SILENT_REFRESH); - - const accessToken = response.headers[ACCESS_TOKEN]; - const tokenId = response.headers[TOKEN_ID]; + const data = await response.json(); + const accessToken = data[ACCESS_TOKEN]; + const tokenId = data[AUTH_USER_ID]; if (!accessToken || !tokenId) { throw new Error("Missing required authentication tokens"); } - tokenManager.setToken(ACCESS_TOKEN, accessToken); - tokenManager.setToken(TOKEN_ID, tokenId); + tokenManager.setToken(CLAIM_NAME, accessToken); + tokenManager.setToken(AUTH_USER_ID, tokenId); } catch (error) { + console.warn("Token has expired, logging out."); if (error instanceof AxiosError) { throw new Error( `Silent refresh failed: ${error.response?.data?.message || error.message}`, diff --git a/apps/cs/src/pages/auth/login/lib/token-manager.ts b/apps/cs/src/pages/auth/login/lib/token-manager.ts index 226cfc843..c704bbb5c 100644 --- a/apps/cs/src/pages/auth/login/lib/token-manager.ts +++ b/apps/cs/src/pages/auth/login/lib/token-manager.ts @@ -1,6 +1,5 @@ -import axios from "axios"; -import Cookies from "js-cookie"; -import { CLAIM_NAME, REFRESH_TOKEN, TOKEN_ID } from "@/shared/config"; +import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config"; +import { setToken, removeToken } from "@/shared/lib/cookie"; export class TokenManager { private static instance: TokenManager; @@ -16,21 +15,12 @@ export class TokenManager { } public setToken(key: string, value: string): void { - axios.defaults.headers.common[key] = value; - } - - public setRefreshToken(token: string): void { - Cookies.set(REFRESH_TOKEN, token, { - httpOnly: true, - secure: true, + setToken(key, value, { + secure: window.location.protocol === "https:", sameSite: "lax", }); } - public getRefreshToken(): string | undefined { - return Cookies.get(REFRESH_TOKEN); - } - public setupRefreshTimer( callback: () => Promise, expirationTime: number, @@ -52,9 +42,9 @@ export class TokenManager { clearTimeout(this.refreshTimer); this.refreshTimer = null; } - Cookies.remove(REFRESH_TOKEN); - delete axios.defaults.headers.common[CLAIM_NAME]; - delete axios.defaults.headers.common[TOKEN_ID]; + + removeToken(CLAIM_NAME); + removeToken(AUTH_USER_ID); } } diff --git a/apps/cs/src/pages/site/ui/register-page.tsx b/apps/cs/src/pages/site/ui/register-page.tsx index 40a098da7..3c35ae8e0 100644 --- a/apps/cs/src/pages/site/ui/register-page.tsx +++ b/apps/cs/src/pages/site/ui/register-page.tsx @@ -1,3 +1,5 @@ +"use client"; + import { Button, DropdownMenu, @@ -16,6 +18,7 @@ import { } from "@common/components"; import { SitePageLayout } from "./layout"; import { IPManagementDialog } from "./ip-management-dialog"; + function RegisterPage() { return ( diff --git a/apps/cs/src/shared/api/client.ts b/apps/cs/src/shared/api/client.ts index e63a4813e..231887202 100644 --- a/apps/cs/src/shared/api/client.ts +++ b/apps/cs/src/shared/api/client.ts @@ -1,7 +1,7 @@ import { Client } from "@common/network"; -import { SERVER_API_URL, SITE_ID } from "../config"; +import { BASE_URL, SITE_ID } from "../config"; export const client = Client.getInstance({ - baseURL: SERVER_API_URL as string, - siteId: SITE_ID as string, + baseURL: BASE_URL, + siteId: SITE_ID, }); diff --git a/apps/cs/src/shared/config/api.ts b/apps/cs/src/shared/config/api.ts index 594157d09..b02f439be 100644 --- a/apps/cs/src/shared/config/api.ts +++ b/apps/cs/src/shared/config/api.ts @@ -1,6 +1,11 @@ +import { PROXY_HOST } from "./env"; + +export const BASE_URL = `${PROXY_HOST}/server`; + export const ENDPOINT = { USER_SERVICE: { LOGIN: "/user-service/login", + USERS: "/user-service/api/v1/users", SILENT_REFRESH: "/user-service/api/v1/users/token/refresh", }, }; diff --git a/apps/cs/src/shared/config/env.ts b/apps/cs/src/shared/config/env.ts index 13bf870a3..f0b4c83b1 100644 --- a/apps/cs/src/shared/config/env.ts +++ b/apps/cs/src/shared/config/env.ts @@ -1,7 +1,13 @@ -export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL; -export const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID; +export const PORT = process.env.NEXT_PUBLIC_PORT || "3000"; +export const PROXY_HOST = + process.env.NEXT_PUBLIC_PROXY_HOST || `http://localhost:${PORT}`; -export const CLAIM_NAME = process.env.CLAIM_NAME || "Authorization"; -export const ACCESS_TOKEN = process.env.ACCESS_TOKEN || "access-token"; -export const REFRESH_TOKEN = process.env.REFRESH_TOKEN || "refresh-token"; -export const TOKEN_ID = process.env.TOKEN_ID || "token-id"; +export const SERVER_API_URL = process.env.NEXT_PUBLIC_SERVER_API_URL; +export const SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "CS"; + +export const CLAIM_NAME = process.env.NEXT_PUBLIC_CLAIM_NAME || "Authorization"; +export const ACCESS_TOKEN = + process.env.NEXT_PUBLIC_ACCESS_TOKEN || "access-token"; +export const REFRESH_TOKEN = + process.env.NEXT_PUBLIC_REFRESH_TOKEN || "refresh-token"; +export const AUTH_USER_ID = process.env.NEXT_PUBLIC_AUTH_USER_ID || "token-id"; diff --git a/apps/cs/src/shared/lib/cookie.ts b/apps/cs/src/shared/lib/cookie.ts new file mode 100644 index 000000000..3e9c91d16 --- /dev/null +++ b/apps/cs/src/shared/lib/cookie.ts @@ -0,0 +1,50 @@ +"use client"; + +import Cookies from "js-cookie"; + +export function getCookie(name: string): string | undefined { + if (typeof window === "undefined") { + return undefined; + } + return Cookies.get(name); +} + +export function setCookie( + name: string, + value: string, + options: Cookies.CookieAttributes, +): void { + if (typeof window === "undefined") { + return; + } + Cookies.set(name, value, options); +} + +export function removeCookie( + name: string, + options: Cookies.CookieAttributes, +): void { + if (typeof window === "undefined") { + return; + } + Cookies.remove(name, options); +} + +export function getToken(key: string): string | undefined { + return getCookie(key); +} + +export function setToken( + key: string, + token: string, + options: Cookies.CookieAttributes, +): void { + setCookie(key, token, { + ...options, + path: "/", + }); +} + +export function removeToken(key: string): void { + removeCookie(key, { path: "/" }); +} diff --git a/apps/cs/src/shared/providers/cookie/cookie-provider.tsx b/apps/cs/src/shared/providers/cookie/cookie-provider.tsx new file mode 100644 index 000000000..f92ca8a6f --- /dev/null +++ b/apps/cs/src/shared/providers/cookie/cookie-provider.tsx @@ -0,0 +1,56 @@ +"use client"; + +import { + getCookie, + setCookie, + removeCookie, + getToken, + setToken, + removeToken, +} from "../../lib/cookie"; + +import { createContext, useContext } from "react"; + +export interface CookieContextType { + getToken: (key: string) => string | undefined; + setToken: ( + key: string, + token: string, + options: Cookies.CookieAttributes, + ) => void; + removeToken: (key: string) => void; + getCookie: (name: string) => string | undefined; + setCookie: ( + name: string, + value: string, + options: Cookies.CookieAttributes, + ) => void; + removeCookie: (name: string, options: Cookies.CookieAttributes) => void; +} + +export const CookieContext = createContext(null); + +export function CookieProvider({ children }: { children: React.ReactNode }) { + const cookieContextValue: CookieContextType = { + getToken, + setToken, + removeToken, + getCookie, + setCookie, + removeCookie, + }; + + return ( + + {children} + + ); +} + +export function useCookie(): CookieContextType { + const context = useContext(CookieContext); + if (!context) { + throw new Error("useCookie must be used within a CookieProvider"); + } + return context; +} diff --git a/apps/cs/src/shared/providers/index.ts b/apps/cs/src/shared/providers/index.ts new file mode 100644 index 000000000..d3e4a1ff3 --- /dev/null +++ b/apps/cs/src/shared/providers/index.ts @@ -0,0 +1,6 @@ +export { + CookieContext, + CookieProvider, + useCookie, +} from "./cookie/cookie-provider"; +export { QueryProvider } from "./query/query-client"; diff --git a/apps/cs/src/shared/providers/query/query-client.tsx b/apps/cs/src/shared/providers/query/query-client.tsx new file mode 100644 index 000000000..65a8ca837 --- /dev/null +++ b/apps/cs/src/shared/providers/query/query-client.tsx @@ -0,0 +1,11 @@ +"use client"; + +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; + +const queryClient = new QueryClient(); + +export const QueryProvider = ({ children }: { children: React.ReactNode }) => { + return ( + {children} + ); +}; diff --git a/packages/common/components/package.json b/packages/common/components/package.json index a2f9889ec..b9b9f4f40 100644 --- a/packages/common/components/package.json +++ b/packages/common/components/package.json @@ -40,11 +40,13 @@ "@radix-ui/react-tabs": "^1.1.3", "@tanstack/react-query": "^5.67.1", "@tanstack/react-table": "^8.21.2", + "@types/js-cookie": "^3.0.6", "axios": "^1.8.1", "chart.js": "^4.4.8", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^3.6.0", + "js-cookie": "^3.0.5", "lucide-react": "^0.474.0", "react-chartjs-2": "^5.3.0", "react-day-picker": "^8.10.1", diff --git a/packages/common/components/src/api/client.ts b/packages/common/components/src/api/client.ts index e63a4813e..231887202 100644 --- a/packages/common/components/src/api/client.ts +++ b/packages/common/components/src/api/client.ts @@ -1,7 +1,7 @@ import { Client } from "@common/network"; -import { SERVER_API_URL, SITE_ID } from "../config"; +import { BASE_URL, SITE_ID } from "../config"; export const client = Client.getInstance({ - baseURL: SERVER_API_URL as string, - siteId: SITE_ID as string, + baseURL: BASE_URL, + siteId: SITE_ID, }); diff --git a/packages/common/components/src/api/user.ts b/packages/common/components/src/api/user.ts index 3e2516b15..478143e09 100644 --- a/packages/common/components/src/api/user.ts +++ b/packages/common/components/src/api/user.ts @@ -1,15 +1,45 @@ -import { useMutation } from "@tanstack/react-query"; +import { useQuery } from "@tanstack/react-query"; import { ENDPOINT } from "../config"; import { client } from "./client"; -export interface UserInfo { +export interface IUser { + regDt: string; + mdfcnDt: string; + rgtr: string; + mdfr: string; + userUnqId: string; + userId: string; userName: string; + email: string; + encryptedPassword: string; + refreshToken: string; + userStateCode: string; lastLoginDate: string; + loginFailCount: number; + pswdHnt: string; + pswdAns: string; + mphn: string; + telno: string; + zip: string; + addr: string; + daddr: string; + laeSeCd: string; + ogdpSeCd: string; + aprvYn: string; + autzrId: string; + expryYmd: string; + lastPswdChgDt: string; + googleId: string; + kakaoId: string; + naverId: string; + isSocialUser: boolean; + hasPassword: boolean; } -export const useUsersMutation = () => { - return useMutation({ - mutationFn: ({ userUniqId }: { userUniqId: string }) => - client.put(`${ENDPOINT.USER_SERVICE.USERS}/${userUniqId}`), +export const useUsersQuery = ({ userUniqId }: { userUniqId: string }) => { + return useQuery({ + queryKey: [ENDPOINT.USER_SERVICE.USERS], + queryFn: () => + client.get(`${ENDPOINT.USER_SERVICE.USERS}/${userUniqId}`), }); }; diff --git a/packages/common/components/src/config/api.ts b/packages/common/components/src/config/api.ts index d55c2d1f0..6d1f59655 100644 --- a/packages/common/components/src/config/api.ts +++ b/packages/common/components/src/config/api.ts @@ -1,3 +1,7 @@ +import { PROXY_HOST } from "./env"; + +export const BASE_URL = `${PROXY_HOST}/server`; + export const ENDPOINT = { USER_SERVICE: { USERS: "/user-service/api/v1/users", diff --git a/packages/common/components/src/config/env.ts b/packages/common/components/src/config/env.ts index df02cbb7d..d75d108a3 100644 --- a/packages/common/components/src/config/env.ts +++ b/packages/common/components/src/config/env.ts @@ -1,2 +1,12 @@ -export const SERVER_API_URL = process.env.SERVER_API_URL; -export const SITE_ID = process.env.SITE_ID; +export const PORT = import.meta.env.VITE_PORT || "3000"; +export const PROXY_HOST = + import.meta.env.VITE_PROXY_HOST || `http://localhost:${PORT}`; + +export const SERVER_API_URL = import.meta.env.VITE_SERVER_API_URL; +export const SITE_ID = import.meta.env.VITE_SITE_ID || "CS"; + +export const CLAIM_NAME = import.meta.env.VITE_CLAIM_NAME || "Authorization"; +export const ACCESS_TOKEN = import.meta.env.VITE_ACCESS_TOKEN || "access-token"; +export const REFRESH_TOKEN = + import.meta.env.VITE_REFRESH_TOKEN || "refresh-token"; +export const AUTH_USER_ID = import.meta.env.VITE_AUTH_USER_ID || "token-id"; diff --git a/packages/common/components/src/lib/cookie.ts b/packages/common/components/src/lib/cookie.ts new file mode 100644 index 000000000..a0fcf2bd9 --- /dev/null +++ b/packages/common/components/src/lib/cookie.ts @@ -0,0 +1,48 @@ +import Cookies from "js-cookie"; + +export function getCookie(name: string): string | undefined { + if (typeof window === "undefined") { + return undefined; + } + return Cookies.get(name); +} + +export function setCookie( + name: string, + value: string, + options: Cookies.CookieAttributes, +): void { + if (typeof window === "undefined") { + return; + } + Cookies.set(name, value, options); +} + +export function removeCookie( + name: string, + options: Cookies.CookieAttributes, +): void { + if (typeof window === "undefined") { + return; + } + Cookies.remove(name, options); +} + +export function getToken(key: string): string | undefined { + return getCookie(key); +} + +export function setToken( + key: string, + token: string, + options: Cookies.CookieAttributes, +): void { + setCookie(key, token, { + ...options, + path: "/", + }); +} + +export function removeToken(key: string): void { + removeCookie(key, { path: "/" }); +} diff --git a/packages/common/components/src/lib/index.ts b/packages/common/components/src/lib/index.ts index 178cd64f8..04f69ba83 100644 --- a/packages/common/components/src/lib/index.ts +++ b/packages/common/components/src/lib/index.ts @@ -1 +1,2 @@ export * from "./utils"; +export * from "./cookie"; diff --git a/packages/common/components/src/ui/header/index.tsx b/packages/common/components/src/ui/header/index.tsx index 955ed016f..7f5a213cf 100644 --- a/packages/common/components/src/ui/header/index.tsx +++ b/packages/common/components/src/ui/header/index.tsx @@ -1,8 +1,9 @@ "use client"; -import { useEffect, useState } from "react"; import { images } from "@common/assets"; -import { useUsersMutation, type UserInfo } from "../../api"; +import { useUsersQuery } from "../../api"; +import { AUTH_USER_ID } from "../../config"; +import { getToken } from "../../lib"; import { DropdownMenu, DropdownMenuTrigger, @@ -12,25 +13,10 @@ import { import { Button } from "../button"; export function Header() { - const { mutate } = useUsersMutation(); - const [userInfo, setUserInfo] = useState({ - userName: "", - lastLoginDate: "", + const { data: userInfo } = useUsersQuery({ + userUniqId: getToken(AUTH_USER_ID) ?? "", }); - useEffect(() => { - mutate( - { - userUniqId: "65a00f65-8460-49af-98ec-042977e56f4b", - }, - { - onSuccess: (data) => { - setUserInfo(data.data); - }, - }, - ); - }, []); - return (
@@ -46,7 +32,7 @@ export function Header() { @@ -54,7 +40,7 @@ export function Header() { 프로필 설정

최종접속일

-

{userInfo.lastLoginDate}

+

{userInfo?.data.lastLoginDate}

접속 IP

diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 762d9fae0..bfb638ec5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -42,6 +42,9 @@ importers: '@common/components': specifier: workspace:* version: link:../../packages/common/components + '@tanstack/react-query': + specifier: ^5.67.1 + version: 5.67.1(react@18.3.1) '@tanstack/react-table': specifier: ^8.21.2 version: 8.21.2(react-dom@18.3.1)(react@18.3.1)