Merge commit 'ccf20ee7eb279c3ed80ca23de059ad788ec56293' into iipbs/wr/main_merge
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import "./styles/base.css";
|
||||
import "./styles/components.css";
|
||||
import { AppProvider } from "@/shared/provider";
|
||||
import { AppProvider } from "./providers";
|
||||
|
||||
const App = ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import { ConfirmProvider } from "@frontend-opensource/use-react-hooks";
|
||||
import { AuthWrapper } from "@/entities/auth";
|
||||
import { QueryProvider, StoreProvider } from "@/shared/providers";
|
||||
|
||||
const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
||||
return (
|
||||
<StoreProvider>
|
||||
<QueryProvider>
|
||||
<ConfirmProvider>
|
||||
<AuthWrapper>{children}</AuthWrapper>
|
||||
</ConfirmProvider>
|
||||
</QueryProvider>
|
||||
</StoreProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export { AppProvider };
|
||||
@@ -0,0 +1 @@
|
||||
export { AppProvider } from "./app-provider";
|
||||
+7
-2
@@ -1,6 +1,11 @@
|
||||
import { AxiosError } from "axios";
|
||||
import { ENDPOINT, JWT_EXPIRATION_TIME } from "@/shared/config/api";
|
||||
import { ACCESS_TOKEN, AUTH_USER_ID, CLAIM_NAME } from "@/shared/config/env";
|
||||
import {
|
||||
ENDPOINT,
|
||||
JWT_EXPIRATION_TIME,
|
||||
ACCESS_TOKEN,
|
||||
AUTH_USER_ID,
|
||||
CLAIM_NAME,
|
||||
} from "@/shared/config";
|
||||
import type { LoginService, ILogin } from "../model/login-interface";
|
||||
import { tokenManager } from "../lib/token-manager";
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export { LoginApi } from "./api/login-service";
|
||||
export { AuthWrapper } from "./ui/auth-wrapper";
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config/env";
|
||||
import { getCookie, setCookie, removeCookie } from "@/shared/lib/cookie";
|
||||
import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config";
|
||||
import { getCookie, setCookie, removeCookie } from "@/shared/lib";
|
||||
|
||||
export class TokenManager {
|
||||
private static instance: TokenManager;
|
||||
@@ -1 +0,0 @@
|
||||
export { LoginApi } from "./api/login-service";
|
||||
@@ -0,0 +1,46 @@
|
||||
"use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT, AUTH_USER_ID } from "@/shared/config";
|
||||
import { getCookie, useUserStore } from "@/shared/lib";
|
||||
import type { IUserInfo } from "@/shared/store";
|
||||
import { LoginApi } from "../api/login-service";
|
||||
|
||||
const AuthWrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
const router = useRouter();
|
||||
const { setUserInfo } = useUserStore((state) => state);
|
||||
|
||||
useQuery({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS],
|
||||
queryFn: async () => {
|
||||
try {
|
||||
const userId = getCookie(AUTH_USER_ID);
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("Missing required authentication tokens");
|
||||
}
|
||||
|
||||
const response = await client.get<IUserInfo>(
|
||||
`${ENDPOINT.USER_SERVICE.USERS}/${userId}`,
|
||||
);
|
||||
setUserInfo(response.data);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
try {
|
||||
await LoginApi.silentRefresh();
|
||||
} catch (refreshError) {
|
||||
console.error("Token refresh failed:", refreshError);
|
||||
setUserInfo(null);
|
||||
router.push("/auth/login");
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
export { AuthWrapper };
|
||||
@@ -1,5 +1,5 @@
|
||||
import { client } from "@/shared/api/client";
|
||||
import { ENDPOINT } from "@/shared/config/api";
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import type { CodeService, ICode } from "../model/code-interface";
|
||||
|
||||
export class CodeApiService implements CodeService {
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@common/components";
|
||||
import { ENDPOINT } from "@/shared/config/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { CodeApi } from "../api/code-service";
|
||||
|
||||
type CodeSelectProps = {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
export { SiteApi } from "./api/site-service";
|
||||
export * from "./model/site-interface";
|
||||
@@ -1,15 +0,0 @@
|
||||
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: IUser): Promise<IUserInfo> {
|
||||
const response = await client.get<IUserInfo>(
|
||||
`${ENDPOINT.USER_SERVICE.USERS}/${payload.userUniqId}`,
|
||||
);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
}
|
||||
|
||||
export const UserApi = new UsersApiService();
|
||||
@@ -1 +0,0 @@
|
||||
export { useUser } from "./lib/use-user";
|
||||
@@ -1,20 +0,0 @@
|
||||
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";
|
||||
|
||||
const useUser = () => {
|
||||
const { getCookie } = useCookie();
|
||||
const { data } = useQuery({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS],
|
||||
queryFn: () =>
|
||||
UserApi.userInfo({
|
||||
userUniqId: getCookie(AUTH_USER_ID) ?? "",
|
||||
}),
|
||||
});
|
||||
|
||||
return { userInfo: data };
|
||||
};
|
||||
|
||||
export { useUser };
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import Image from "next/image";
|
||||
import { images } from "@common/assets";
|
||||
import { LoginApi } from "@/entities/auth/login";
|
||||
import { LoginApi } from "@/entities/auth";
|
||||
import "./login.css";
|
||||
|
||||
function LoginPage() {
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import { client } from "@/shared/api/client";
|
||||
import { ENDPOINT } from "@/shared/config/api";
|
||||
import { client } from "@/shared/api";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import {
|
||||
siteFormSchema,
|
||||
type ISiteInfo,
|
||||
@@ -1,6 +1,6 @@
|
||||
import dayjs from "dayjs";
|
||||
import { createColumnHelper } from "@tanstack/react-table";
|
||||
import type { ISite } from "@/entities/site/model/site-interface";
|
||||
import type { ISite } from "./site-interface";
|
||||
|
||||
const columnHelper = createColumnHelper<ISite>();
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ import { useRouter } from "next/navigation";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { SiteApi, siteFormSchema, type SiteFormData } from "@/entities/site";
|
||||
import { SiteApi } from "../api/site-service";
|
||||
import { siteFormSchema, type SiteFormData } from "../model/site-interface";
|
||||
import { SitePageLayout } from "./layout";
|
||||
import { SiteForm } from "./site-form";
|
||||
import {
|
||||
|
||||
@@ -5,13 +5,13 @@ import { useRouter } from "next/navigation";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { SiteApi } from "../api/site-service";
|
||||
import {
|
||||
SiteApi,
|
||||
siteFormSchema,
|
||||
type ISiteDetail,
|
||||
type SiteFormData,
|
||||
} from "@/entities/site";
|
||||
import { ENDPOINT } from "@/shared/config/api";
|
||||
} from "../model/site-interface";
|
||||
import { SitePageLayout } from "./layout";
|
||||
import { SiteForm } from "./site-form";
|
||||
import {
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
TableRow,
|
||||
} from "@common/components";
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import { type ISiteDetail, type SiteFormData } from "@/entities/site";
|
||||
import {
|
||||
FormItem,
|
||||
FormControl,
|
||||
@@ -27,6 +26,7 @@ import {
|
||||
Form,
|
||||
FormMessage,
|
||||
} from "@/shared/ui/form";
|
||||
import { type ISiteDetail, type SiteFormData } from "../model/site-interface";
|
||||
import { IPManagementDialog } from "./ip-management-dialog";
|
||||
import {
|
||||
DomainManagementDialog,
|
||||
@@ -37,7 +37,7 @@ type SiteFormProps = {
|
||||
form: UseFormReturn<SiteFormData>;
|
||||
siteId?: string;
|
||||
handleSave: (data: SiteFormData) => void;
|
||||
handleDelete: () => void;
|
||||
handleDelete?: () => void;
|
||||
};
|
||||
|
||||
function SiteForm({ form, siteId, handleSave, handleDelete }: SiteFormProps) {
|
||||
@@ -65,7 +65,7 @@ function SiteForm({ form, siteId, handleSave, handleDelete }: SiteFormProps) {
|
||||
|
||||
const onDelete = async () => {
|
||||
if (await confirm("정말 삭제하시겠습니까?")) {
|
||||
handleDelete();
|
||||
handleDelete?.();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@ import { ENDPOINT } from "@/shared/config/api";
|
||||
import { Button, DataTable, Input } from "@common/components";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { columns } from "../model/table-columns";
|
||||
import { SitePageLayout } from "./layout";
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { client } from "./client";
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./api";
|
||||
export * from "./env";
|
||||
@@ -0,0 +1,2 @@
|
||||
export { getCookie, setCookie, removeCookie } from "./cookie";
|
||||
export { useUserStore } from "./use-user-store";
|
||||
@@ -0,0 +1,14 @@
|
||||
import { useStore } from "zustand";
|
||||
import { useContext } from "react";
|
||||
import { type UserStore } from "@/shared/store/user-store";
|
||||
import { StoreContext } from "../providers/store-provider";
|
||||
|
||||
export const useUserStore = <T>(selector: (store: UserStore) => T): T => {
|
||||
const storeContext = useContext(StoreContext);
|
||||
|
||||
if (!storeContext) {
|
||||
throw new Error("useUserStore must be used within StoreProvider");
|
||||
}
|
||||
|
||||
return useStore(storeContext.userStore, selector);
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { ConfirmProvider } from "@frontend-opensource/use-react-hooks";
|
||||
import { AuthProvider } from "./auth-provider";
|
||||
import { CookieProvider } from "./cookie-provider";
|
||||
import { QueryProvider } from "./query-provider";
|
||||
|
||||
const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
||||
return (
|
||||
<QueryProvider>
|
||||
<CookieProvider>
|
||||
<AuthProvider>
|
||||
<ConfirmProvider>{children}</ConfirmProvider>
|
||||
</AuthProvider>
|
||||
</CookieProvider>
|
||||
</QueryProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export { AppProvider };
|
||||
@@ -1,101 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
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 { 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 router = useRouter();
|
||||
const [userInfo, setUserInfo] = useState<IUserInfo | null>(null);
|
||||
|
||||
useQuery({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS],
|
||||
queryFn: async () => {
|
||||
try {
|
||||
const userId = getCookie(AUTH_USER_ID);
|
||||
|
||||
if (!userId) {
|
||||
throw new Error("Missing required authentication tokens");
|
||||
}
|
||||
|
||||
const response = await client.get<IUserInfo>(
|
||||
`${ENDPOINT.USER_SERVICE.USERS}/${userId}`,
|
||||
);
|
||||
setUserInfo(response.data);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
try {
|
||||
await LoginApi.silentRefresh();
|
||||
} catch (refreshError) {
|
||||
console.error("Token refresh failed:", refreshError);
|
||||
setUserInfo(null);
|
||||
router.push("/auth/login");
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
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,38 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, useContext } from "react";
|
||||
import { getCookie, setCookie, removeCookie } from "../lib/cookie";
|
||||
|
||||
export interface CookieContextType {
|
||||
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<CookieContextType | null>(null);
|
||||
|
||||
export function CookieProvider({ children }: { children: React.ReactNode }) {
|
||||
const cookieContextValue: CookieContextType = {
|
||||
getCookie,
|
||||
setCookie,
|
||||
removeCookie,
|
||||
};
|
||||
|
||||
return (
|
||||
<CookieContext.Provider value={cookieContextValue}>
|
||||
{children}
|
||||
</CookieContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useCookie(): CookieContextType {
|
||||
const context = useContext(CookieContext);
|
||||
if (!context) {
|
||||
throw new Error("useCookie must be used within a CookieProvider");
|
||||
}
|
||||
return context;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
export { AppProvider } from "./app-provider";
|
||||
export { useAuth } from "./auth-provider";
|
||||
export { useCookie } from "./cookie-provider";
|
||||
@@ -0,0 +1,2 @@
|
||||
export { QueryProvider } from "./query-provider";
|
||||
export { StoreProvider } from "./store-provider";
|
||||
@@ -0,0 +1,27 @@
|
||||
"use client";
|
||||
|
||||
import { createContext, useRef } from "react";
|
||||
import { createUserStore } from "@/shared/store/user-store";
|
||||
|
||||
type StoreContextType = {
|
||||
userStore: ReturnType<typeof createUserStore>;
|
||||
};
|
||||
|
||||
export const StoreContext = createContext<StoreContextType | undefined>(
|
||||
undefined,
|
||||
);
|
||||
|
||||
export const StoreProvider = ({ children }: { children: React.ReactNode }) => {
|
||||
const storeRef = useRef<StoreContextType | null>(null);
|
||||
if (storeRef.current === null) {
|
||||
storeRef.current = {
|
||||
userStore: createUserStore(),
|
||||
};
|
||||
}
|
||||
|
||||
return (
|
||||
<StoreContext.Provider value={storeRef.current}>
|
||||
{children}
|
||||
</StoreContext.Provider>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export { createUserStore, type IUserInfo } from "./user-store";
|
||||
+21
-6
@@ -1,6 +1,4 @@
|
||||
export interface IUser {
|
||||
userUniqId: string;
|
||||
}
|
||||
import { createStore } from "zustand/vanilla";
|
||||
|
||||
export interface IUserInfo {
|
||||
regDt: string;
|
||||
@@ -36,6 +34,23 @@ export interface IUserInfo {
|
||||
hasPassword: boolean;
|
||||
}
|
||||
|
||||
export interface UserService {
|
||||
userInfo: (payload: IUser) => Promise<IUserInfo>;
|
||||
}
|
||||
export type UserState = {
|
||||
userInfo: IUserInfo | null;
|
||||
};
|
||||
|
||||
export type UserActions = {
|
||||
setUserInfo: (userInfo: IUserInfo | null) => void;
|
||||
};
|
||||
|
||||
export type UserStore = UserState & UserActions;
|
||||
|
||||
export const defaultInitState: UserState = {
|
||||
userInfo: null,
|
||||
};
|
||||
|
||||
export const createUserStore = (initState: UserState = defaultInitState) => {
|
||||
return createStore<UserStore>()((set) => ({
|
||||
...initState,
|
||||
setUserInfo: (userInfo: IUserInfo | null) => set(() => ({ userInfo })),
|
||||
}));
|
||||
};
|
||||
Reference in New Issue
Block a user