Merge pull request 'iipbs_cs' (#5) from iipbs_cs into main
Reviewed-on: #5
This commit was merged in pull request #5.
This commit is contained in:
@@ -9,21 +9,21 @@ import {
|
||||
import { cookies } from "next/headers";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function POST(
|
||||
async function handler(
|
||||
request: Request,
|
||||
props: { params: Promise<{ url: string[] }> },
|
||||
params: { url: string[] },
|
||||
method: "GET" | "POST" | "PUT" | "DELETE",
|
||||
) {
|
||||
const params = await props.params;
|
||||
|
||||
const cookieStore = await cookies();
|
||||
const headers: Record<string, string> = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Site-Id": SITE_ID ?? "",
|
||||
"X-Site-Id": SITE_ID,
|
||||
};
|
||||
|
||||
const cookieStore = await cookies();
|
||||
let body = {};
|
||||
const isRefreshHandler = params.url.includes("refresh");
|
||||
|
||||
// silent refresh
|
||||
if (params.url.includes("refresh")) {
|
||||
if (isRefreshHandler) {
|
||||
const refreshToken = cookieStore.get(REFRESH_TOKEN);
|
||||
headers[CLAIM_NAME] = refreshToken?.value ?? "";
|
||||
|
||||
@@ -33,9 +33,12 @@ export async function POST(
|
||||
}
|
||||
|
||||
try {
|
||||
const body = await request.json();
|
||||
if (!isRefreshHandler) {
|
||||
body = await request.json();
|
||||
}
|
||||
|
||||
const result = await fetch(`${SERVER_API_URL}/${params.url.join("/")}`, {
|
||||
method: "POST",
|
||||
method,
|
||||
headers,
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
@@ -79,3 +82,19 @@ export async function POST(
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
request: Request,
|
||||
props: { params: Promise<{ url: string[] }> },
|
||||
) {
|
||||
const params = await props.params;
|
||||
return handler(request, params, "POST");
|
||||
}
|
||||
|
||||
export async function PUT(
|
||||
request: Request,
|
||||
props: { params: Promise<{ url: string[] }> },
|
||||
) {
|
||||
const params = await props.params;
|
||||
return handler(request, params, "PUT");
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import "./styles/base.css";
|
||||
import "./styles/components.css";
|
||||
import { CookieProvider, QueryProvider } from "@/shared/providers";
|
||||
import { AuthProvider, CookieProvider, QueryProvider } from "@/shared/provider";
|
||||
|
||||
const App = ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
||||
return (
|
||||
<html lang="ko">
|
||||
<body>
|
||||
<QueryProvider>
|
||||
<CookieProvider>{children}</CookieProvider>
|
||||
<CookieProvider>
|
||||
<AuthProvider>{children}</AuthProvider>
|
||||
</CookieProvider>
|
||||
</QueryProvider>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+8
-10
@@ -1,13 +1,8 @@
|
||||
import { AxiosError } from "axios";
|
||||
import {
|
||||
ACCESS_TOKEN,
|
||||
AUTH_USER_ID,
|
||||
CLAIM_NAME,
|
||||
ENDPOINT,
|
||||
JWT_EXPIRATION_TIME,
|
||||
} from "@/shared/config";
|
||||
import { ENDPOINT, JWT_EXPIRATION_TIME } from "@/shared/config/api";
|
||||
import { ACCESS_TOKEN, AUTH_USER_ID, CLAIM_NAME } from "@/shared/config/env";
|
||||
import type { LoginService, ILogin } from "../model/login-interface";
|
||||
import { tokenManager } from "../lib/token-manager";
|
||||
import type { LoginService, ILogin } from "../model/login";
|
||||
|
||||
export class LoginApiService implements LoginService {
|
||||
private static instance: LoginApiService;
|
||||
@@ -36,7 +31,7 @@ export class LoginApiService implements LoginService {
|
||||
const tokenId = data[AUTH_USER_ID];
|
||||
|
||||
if (!accessToken || !tokenId) {
|
||||
throw new Error("Missing required authentication tokens");
|
||||
throw new Error("[login] Missing required authentication tokens");
|
||||
}
|
||||
|
||||
tokenManager.setToken(CLAIM_NAME, accessToken);
|
||||
@@ -67,13 +62,16 @@ export class LoginApiService implements LoginService {
|
||||
const tokenId = data[AUTH_USER_ID];
|
||||
|
||||
if (!accessToken || !tokenId) {
|
||||
throw new Error("Missing required authentication tokens");
|
||||
throw new Error(
|
||||
"[silentRefresh] Missing required authentication tokens",
|
||||
);
|
||||
}
|
||||
|
||||
tokenManager.setToken(CLAIM_NAME, accessToken);
|
||||
tokenManager.setToken(AUTH_USER_ID, tokenId);
|
||||
} catch (error) {
|
||||
console.warn("Token has expired, logging out.");
|
||||
tokenManager.clearAuthToken();
|
||||
if (error instanceof AxiosError) {
|
||||
throw new Error(
|
||||
`Silent refresh failed: ${error.response?.data?.message || error.message}`,
|
||||
@@ -0,0 +1 @@
|
||||
export { LoginApi } from "./api/login-service";
|
||||
+15
-7
@@ -1,5 +1,5 @@
|
||||
import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config";
|
||||
import { setToken, removeToken } from "@/shared/lib/cookie";
|
||||
import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config/env";
|
||||
import { getCookie, setCookie, removeCookie } from "@/shared/lib/cookie";
|
||||
|
||||
export class TokenManager {
|
||||
private static instance: TokenManager;
|
||||
@@ -14,13 +14,21 @@ export class TokenManager {
|
||||
return TokenManager.instance;
|
||||
}
|
||||
|
||||
public getToken(key: string): string | undefined {
|
||||
return getCookie(key);
|
||||
}
|
||||
|
||||
public setToken(key: string, value: string): void {
|
||||
setToken(key, value, {
|
||||
setCookie(key, value, {
|
||||
secure: window.location.protocol === "https:",
|
||||
sameSite: "lax",
|
||||
});
|
||||
}
|
||||
|
||||
public removeToken(key: string): void {
|
||||
removeCookie(key);
|
||||
}
|
||||
|
||||
public setupRefreshTimer(
|
||||
callback: () => Promise<void>,
|
||||
expirationTime: number,
|
||||
@@ -32,19 +40,19 @@ export class TokenManager {
|
||||
this.refreshTimer = setTimeout(() => {
|
||||
callback().catch((error) => {
|
||||
console.error("Silent refresh failed:", error);
|
||||
this.clearAuth();
|
||||
this.clearAuthToken();
|
||||
});
|
||||
}, expirationTime - 60000);
|
||||
}
|
||||
|
||||
public clearAuth(): void {
|
||||
public clearAuthToken(): void {
|
||||
if (this.refreshTimer) {
|
||||
clearTimeout(this.refreshTimer);
|
||||
this.refreshTimer = null;
|
||||
}
|
||||
|
||||
removeToken(CLAIM_NAME);
|
||||
removeToken(AUTH_USER_ID);
|
||||
this.removeToken(CLAIM_NAME);
|
||||
this.removeToken(AUTH_USER_ID);
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -5,4 +5,5 @@ export interface ILogin {
|
||||
|
||||
export interface LoginService {
|
||||
login(payload: ILogin): Promise<void>;
|
||||
silentRefresh(): Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { client } from "@/shared/api/client";
|
||||
import { ENDPOINT } from "@/shared/config/api";
|
||||
import type {
|
||||
ISiteQuery,
|
||||
ISiteInfo,
|
||||
SiteService,
|
||||
} from "../model/site-interface";
|
||||
|
||||
export class SiteApiService implements SiteService {
|
||||
public async siteInfo(query: ISiteQuery): Promise<ISiteInfo> {
|
||||
const response = await client.get<ISiteInfo>(
|
||||
`${ENDPOINT.CMS_SERVICE.SITES}`,
|
||||
{ params: query },
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const SiteApi = new SiteApiService();
|
||||
@@ -0,0 +1 @@
|
||||
export { SiteApi } from "./api/site-service";
|
||||
@@ -0,0 +1,49 @@
|
||||
export interface ISiteQuery {
|
||||
siteNm: string;
|
||||
siteKndCd: string;
|
||||
useYn: string;
|
||||
page: number;
|
||||
size: number;
|
||||
sort: string[];
|
||||
}
|
||||
|
||||
export interface ISite {
|
||||
siteId: string;
|
||||
siteNm: string;
|
||||
siteKindCode: string;
|
||||
bscSiteYn: string;
|
||||
useYn: string;
|
||||
}
|
||||
|
||||
export interface ISiteInfo {
|
||||
totalPages: number;
|
||||
totalElements: number;
|
||||
number: number;
|
||||
sort: {
|
||||
empty: boolean;
|
||||
sorted: boolean;
|
||||
unsorted: boolean;
|
||||
};
|
||||
size: number;
|
||||
content: ISite[];
|
||||
pageable: {
|
||||
sort: {
|
||||
empty: boolean;
|
||||
sorted: boolean;
|
||||
unsorted: boolean;
|
||||
};
|
||||
offset: number;
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
paged: boolean;
|
||||
unpaged: boolean;
|
||||
};
|
||||
numberOfElements: number;
|
||||
first: boolean;
|
||||
last: boolean;
|
||||
empty: boolean;
|
||||
}
|
||||
|
||||
export interface SiteService {
|
||||
siteInfo(query: ISiteQuery): Promise<ISiteInfo>;
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { client } from "@/shared/api/client";
|
||||
import { ENDPOINT } from "@/shared/config/api";
|
||||
import type { IUser, IUserInfo, UserService } from "../model/user-interface";
|
||||
|
||||
export class UsersApiService implements UserService {
|
||||
public async userInfo(payload: IUserInfo): Promise<IUser> {
|
||||
const response = await client.get<IUser>(
|
||||
public async userInfo(payload: IUser): Promise<IUserInfo> {
|
||||
const response = await client.get<IUserInfo>(
|
||||
`${ENDPOINT.USER_SERVICE.USERS}/${payload.userUniqId}`,
|
||||
);
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { ENDPOINT } from "@/shared/config/api";
|
||||
import { AUTH_USER_ID } from "@/shared/config/env";
|
||||
import { useCookie } from "@/shared/provider";
|
||||
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 { getCookie } = useCookie();
|
||||
const { data } = useQuery({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS],
|
||||
queryFn: () =>
|
||||
UserApi.userInfo({
|
||||
userUniqId: getToken(AUTH_USER_ID) ?? "",
|
||||
userUniqId: getCookie(AUTH_USER_ID) ?? "",
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
export interface IUserInfo {
|
||||
export interface IUser {
|
||||
userUniqId: string;
|
||||
}
|
||||
|
||||
export interface IUser {
|
||||
export interface IUserInfo {
|
||||
regDt: string;
|
||||
mdfcnDt: string;
|
||||
rgtr: string;
|
||||
@@ -37,5 +37,5 @@ export interface IUser {
|
||||
}
|
||||
|
||||
export interface UserService {
|
||||
userInfo: (payload: IUserInfo) => Promise<IUser>;
|
||||
userInfo: (payload: IUser) => Promise<IUserInfo>;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import Image from "next/image";
|
||||
import { images } from "@common/assets";
|
||||
import { LoginApi } from "../api/login";
|
||||
import { LoginApi } from "@/entities/auth/login";
|
||||
import "./login.css";
|
||||
|
||||
function LoginPage() {
|
||||
|
||||
@@ -1,59 +1,43 @@
|
||||
import { createColumnHelper } from "@tanstack/react-table";
|
||||
import { fakerKO as faker } from "@faker-js/faker";
|
||||
import type { ISite } from "@/entities/site/model/site-interface";
|
||||
|
||||
type Site = {
|
||||
id: number;
|
||||
사이트코드: string;
|
||||
사이트명: string;
|
||||
대표_URL: string;
|
||||
기본_사이트_여부: boolean;
|
||||
사용_여부: boolean;
|
||||
등록자: string;
|
||||
등록일: string;
|
||||
};
|
||||
|
||||
faker.seed(123);
|
||||
|
||||
const data: Site[] = Array.from({ length: 100 }, (_, i) => ({
|
||||
id: i + 1,
|
||||
사이트코드: faker.string.alpha(2).toUpperCase(),
|
||||
사이트명: faker.lorem.word(),
|
||||
대표_URL: faker.internet.url(),
|
||||
기본_사이트_여부: faker.datatype.boolean(),
|
||||
사용_여부: faker.datatype.boolean(),
|
||||
등록자: faker.person.fullName(),
|
||||
등록일: faker.date.recent().toISOString().split("T")[0] as string,
|
||||
}));
|
||||
|
||||
const columnHelper = createColumnHelper<Site>();
|
||||
const columnHelper = createColumnHelper<ISite>();
|
||||
|
||||
const columns = [
|
||||
columnHelper.accessor("id", {
|
||||
columnHelper.accessor((_, index) => index + 1, {
|
||||
id: "no",
|
||||
header: "NO",
|
||||
}),
|
||||
columnHelper.accessor("사이트코드", {
|
||||
columnHelper.accessor("siteId", {
|
||||
id: "siteId",
|
||||
header: "사이트코드",
|
||||
}),
|
||||
columnHelper.accessor("사이트명", {
|
||||
columnHelper.accessor("siteNm", {
|
||||
id: "siteNm",
|
||||
header: "사이트명",
|
||||
}),
|
||||
columnHelper.accessor("대표_URL", {
|
||||
columnHelper.accessor("siteKindCode", {
|
||||
id: "unknown1",
|
||||
header: "대표 URL",
|
||||
}),
|
||||
columnHelper.accessor("기본_사이트_여부", {
|
||||
columnHelper.accessor("bscSiteYn", {
|
||||
id: "bscSiteYn",
|
||||
header: "기본 사이트 여부",
|
||||
cell: (info) => (info.getValue() ? "Y" : "N"),
|
||||
}),
|
||||
columnHelper.accessor("사용_여부", {
|
||||
columnHelper.accessor("useYn", {
|
||||
id: "useYn",
|
||||
header: "사용 여부",
|
||||
cell: (info) => (info.getValue() ? "Y" : "N"),
|
||||
}),
|
||||
columnHelper.accessor("등록자", {
|
||||
columnHelper.accessor("siteId", {
|
||||
id: "unknown2",
|
||||
header: "등록자",
|
||||
}),
|
||||
columnHelper.accessor("등록일", {
|
||||
columnHelper.accessor("siteId", {
|
||||
id: "ununknown3",
|
||||
header: "등록일",
|
||||
}),
|
||||
];
|
||||
|
||||
export { data, columns };
|
||||
export { columns };
|
||||
|
||||
@@ -3,30 +3,67 @@
|
||||
import "@common/assets/styles/grid.css";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { Button, Input, DataTable } from "@common/components";
|
||||
import { data, columns } from "../model/__mocks__";
|
||||
import { SiteApi } from "@/entities/site/api/site-service";
|
||||
import { ENDPOINT } from "@/shared/config/api";
|
||||
import { columns } from "../model/__mocks__";
|
||||
import { SitePageLayout } from "./layout";
|
||||
import type { ISiteQuery } from "@/entities/site/model/site-interface";
|
||||
|
||||
function SitePage() {
|
||||
const [siteQuery, setSiteQuery] = useState<ISiteQuery>({
|
||||
siteNm: "",
|
||||
siteKndCd: "",
|
||||
useYn: "",
|
||||
page: 0,
|
||||
size: 0,
|
||||
sort: [],
|
||||
});
|
||||
|
||||
const { data: siteInfo, refetch } = useQuery({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.SITES],
|
||||
queryFn: () => SiteApi.siteInfo(siteQuery),
|
||||
enabled: false,
|
||||
});
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
refetch();
|
||||
};
|
||||
|
||||
const router = useRouter();
|
||||
const table = useReactTable({
|
||||
data,
|
||||
data: siteInfo?.content ?? [],
|
||||
columns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
refetch();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<SitePageLayout>
|
||||
<div className="card card-border !mt-6">
|
||||
<div className="card card-border !border-[#dbe2e6] !bg-[#eef7ff]">
|
||||
<div className="flex items-center gap-2 p-2">
|
||||
<form onSubmit={handleSubmit} className="flex items-center gap-2 p-2">
|
||||
<label htmlFor="" className="mr-2 text-[#657481]">
|
||||
사이트명
|
||||
</label>
|
||||
<Input className="h-[3.2rem] w-[24rem] rounded-sm !text-[1.3rem]" />
|
||||
<Button className="h-[3.2rem]">조회</Button>
|
||||
</div>
|
||||
<Input
|
||||
className="h-[3.2rem] w-[24rem] rounded-sm !text-[1.3rem]"
|
||||
value={siteQuery.siteNm}
|
||||
onChange={(e) =>
|
||||
setSiteQuery({ ...siteQuery, siteNm: e.target.value })
|
||||
}
|
||||
/>
|
||||
<Button className="h-[3.2rem]" type="submit">
|
||||
조회
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
<div className="card card-border">
|
||||
<div className="card-header">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Client } from "@common/network";
|
||||
import { BASE_URL, SITE_ID } from "../config";
|
||||
import { BASE_URL } from "../config/api";
|
||||
import { SITE_ID } from "../config/env";
|
||||
|
||||
export const client = Client.getInstance({
|
||||
baseURL: BASE_URL,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { client } from "./client";
|
||||
@@ -8,6 +8,9 @@ export const ENDPOINT = {
|
||||
USERS: "/user-service/api/v1/users",
|
||||
SILENT_REFRESH: "/user-service/api/v1/users/token/refresh",
|
||||
},
|
||||
CMS_SERVICE: {
|
||||
SITES: "/cms-service/api/v1/sites",
|
||||
},
|
||||
};
|
||||
|
||||
export const JWT_EXPIRATION_TIME = 1800000;
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from "./api";
|
||||
export * from "./env";
|
||||
@@ -12,7 +12,7 @@ export function getCookie(name: string): string | undefined {
|
||||
export function setCookie(
|
||||
name: string,
|
||||
value: string,
|
||||
options: Cookies.CookieAttributes,
|
||||
options?: Cookies.CookieAttributes,
|
||||
): void {
|
||||
if (typeof window === "undefined") {
|
||||
return;
|
||||
@@ -22,29 +22,10 @@ export function setCookie(
|
||||
|
||||
export function removeCookie(
|
||||
name: string,
|
||||
options: Cookies.CookieAttributes,
|
||||
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: "/" });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
"use client";
|
||||
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { createContext, useContext, useState } from "react";
|
||||
import { client } from "../api/client";
|
||||
import { ENDPOINT } from "../config/api";
|
||||
import { AUTH_USER_ID } from "../config/env";
|
||||
import { getCookie } from "../lib/cookie";
|
||||
import { AxiosError } from "axios";
|
||||
import { LoginApi } from "@/entities/auth/login";
|
||||
|
||||
interface IUserInfo {
|
||||
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 AuthContextType {
|
||||
userInfo: IUserInfo | null;
|
||||
}
|
||||
|
||||
export const AuthContext = createContext<AuthContextType | null>(null);
|
||||
|
||||
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const [userInfo, setUserInfo] = useState<IUserInfo | null>(null);
|
||||
|
||||
useQuery({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS],
|
||||
queryFn: async () => {
|
||||
try {
|
||||
const response = await client.get<IUserInfo>(
|
||||
`${ENDPOINT.USER_SERVICE.USERS}/${getCookie(AUTH_USER_ID)}`,
|
||||
);
|
||||
setUserInfo(response.data);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (error instanceof AxiosError) {
|
||||
if (error.response?.status === 401) {
|
||||
try {
|
||||
await LoginApi.silentRefresh();
|
||||
} catch (refreshError) {
|
||||
console.error("Token refresh failed:", refreshError);
|
||||
setUserInfo(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const authContextValue: AuthContextType = {
|
||||
userInfo,
|
||||
};
|
||||
|
||||
return (
|
||||
<AuthContext.Provider value={authContextValue}>
|
||||
{children}
|
||||
</AuthContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useAuth = (): AuthContextType => {
|
||||
const context = useContext(AuthContext);
|
||||
if (!context) {
|
||||
throw new Error("useAuth must be used within an AuthProvider");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
+1
-19
@@ -1,24 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
getCookie,
|
||||
setCookie,
|
||||
removeCookie,
|
||||
getToken,
|
||||
setToken,
|
||||
removeToken,
|
||||
} from "../../lib/cookie";
|
||||
|
||||
import { createContext, useContext } from "react";
|
||||
import { getCookie, setCookie, removeCookie } from "../lib/cookie";
|
||||
|
||||
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,
|
||||
@@ -32,9 +17,6 @@ export const CookieContext = createContext<CookieContextType | null>(null);
|
||||
|
||||
export function CookieProvider({ children }: { children: React.ReactNode }) {
|
||||
const cookieContextValue: CookieContextType = {
|
||||
getToken,
|
||||
setToken,
|
||||
removeToken,
|
||||
getCookie,
|
||||
setCookie,
|
||||
removeCookie,
|
||||
@@ -0,0 +1,3 @@
|
||||
export { AuthProvider, useAuth } from "./auth-provider";
|
||||
export { CookieProvider, useCookie } from "./cookie-provider";
|
||||
export { QueryProvider } from "./query-provider";
|
||||
@@ -1,6 +0,0 @@
|
||||
export {
|
||||
CookieContext,
|
||||
CookieProvider,
|
||||
useCookie,
|
||||
} from "./cookie/cookie-provider";
|
||||
export { QueryProvider } from "./query/query-client";
|
||||
@@ -1,4 +1,4 @@
|
||||
import axios from "axios";
|
||||
import axios, { AxiosError } from "axios";
|
||||
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios";
|
||||
import Cookies from "js-cookie";
|
||||
import { AUTH_USER_ID, CLAIM_NAME } from "./env";
|
||||
@@ -27,7 +27,19 @@ class Client {
|
||||
const userId = Cookies.get(AUTH_USER_ID);
|
||||
|
||||
if (!token || !userId) {
|
||||
throw new Error("Missing required authentication tokens");
|
||||
throw new AxiosError(
|
||||
"[Client] Missing required authentication tokens",
|
||||
"UNAUTHORIZED",
|
||||
config,
|
||||
null,
|
||||
{
|
||||
data: { message: "Missing required authentication tokens" },
|
||||
status: 401,
|
||||
statusText: "Unauthorized",
|
||||
headers: this.axiosInstance.defaults.headers,
|
||||
config: config,
|
||||
} as AxiosResponse
|
||||
);
|
||||
}
|
||||
|
||||
config.headers[CLAIM_NAME] = token;
|
||||
|
||||
Reference in New Issue
Block a user