diff --git a/apps/theme-market/src/app/_pages/Main/ThemeDownload/index.tsx b/apps/theme-market/src/app/_pages/Main/ThemeDownload/index.tsx
index e3a353b..2a66344 100644
--- a/apps/theme-market/src/app/_pages/Main/ThemeDownload/index.tsx
+++ b/apps/theme-market/src/app/_pages/Main/ThemeDownload/index.tsx
@@ -1,13 +1,10 @@
-import { cookies } from "next/headers";
-
-import { ACCESS_TOKEN_KEY } from "@/clients/HttpClient";
import { themeService } from "@/services/ThemeService";
import { ThemeList } from "./ThemeList";
+import { cookieService } from "@/services/CookieService";
export const ThemeDownload = async () => {
- const cookieStore = cookies();
- const accessToken = cookieStore.get(ACCESS_TOKEN_KEY)?.value;
+ const accessToken = cookieService.getAccessToken();
const bestThemes = await themeService.getBestThemes(accessToken);
const friendsThemes = await themeService.getFriendsThemes(accessToken);
diff --git a/apps/theme-market/src/app/_providers/ThemeProvider.tsx b/apps/theme-market/src/app/_providers/ThemeProvider.tsx
new file mode 100644
index 0000000..40fcc37
--- /dev/null
+++ b/apps/theme-market/src/app/_providers/ThemeProvider.tsx
@@ -0,0 +1,38 @@
+"use client";
+
+import { createContext, ReactNode, useContext, useRef } from "react";
+import { createThemeStore, ThemeStore } from "../_stores/ThemeStore";
+import { useStore } from "zustand";
+
+export type ThemeStoreApi = ReturnType;
+
+export interface ThemeStoreProviderProps {
+ children: ReactNode;
+}
+
+export const ThemeStoreContext = createContext(
+ undefined
+);
+
+export const ThemeStoreProvider = ({ children }: ThemeStoreProviderProps) => {
+ const ref = useRef();
+ if (!ref.current) {
+ ref.current = createThemeStore();
+ }
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useThemeStore = (selector: (store: ThemeStore) => T): T => {
+ const themeStoreContext = useContext(ThemeStoreContext);
+
+ if (!themeStoreContext) {
+ throw new Error(`useThemeStore must be used within ThemeStoreProvider`);
+ }
+
+ return useStore(themeStoreContext, selector);
+};
diff --git a/apps/theme-market/src/app/_providers/UserProvider.tsx b/apps/theme-market/src/app/_providers/UserProvider.tsx
new file mode 100644
index 0000000..ddf1773
--- /dev/null
+++ b/apps/theme-market/src/app/_providers/UserProvider.tsx
@@ -0,0 +1,43 @@
+"use client";
+
+import { createContext, ReactNode, useContext, useRef } from "react";
+import { createUserStore, UserStore } from "../_stores/UserStore";
+import { useStore } from "zustand";
+import { User } from "@/entities/User";
+
+export type UserStoreApi = ReturnType;
+
+export interface UserStoreProviderProps {
+ children: ReactNode;
+ user: User;
+}
+
+export const UserStoreContext = createContext(
+ undefined
+);
+
+export const UserStoreProvider = ({
+ children,
+ user,
+}: UserStoreProviderProps) => {
+ const ref = useRef();
+ if (!ref.current) {
+ ref.current = createUserStore({ user });
+ }
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useUserStore = (selector: (store: UserStore) => T): T => {
+ const userStoreContext = useContext(UserStoreContext);
+
+ if (!userStoreContext) {
+ throw new Error(`useUserStore must be used within UserStoreProvider`);
+ }
+
+ return useStore(userStoreContext, selector);
+};
diff --git a/apps/theme-market/src/app/_stores/ThemeStore.ts b/apps/theme-market/src/app/_stores/ThemeStore.ts
new file mode 100644
index 0000000..8598506
--- /dev/null
+++ b/apps/theme-market/src/app/_stores/ThemeStore.ts
@@ -0,0 +1,19 @@
+import { Theme } from "@/entities/Theme";
+import { createStore } from "zustand";
+
+export type ThemeStoreState = {
+ theme: Theme | null;
+};
+
+export type ThemeStoreAction = {
+ setTheme: (theme: Theme | null) => void;
+};
+
+export type ThemeStore = ThemeStoreState & ThemeStoreAction;
+
+export const createThemeStore = () => {
+ return createStore((set) => ({
+ theme: null,
+ setTheme: (theme) => set((state) => ({ ...state, theme })),
+ }));
+};
diff --git a/apps/theme-market/src/app/_stores/UserStore.ts b/apps/theme-market/src/app/_stores/UserStore.ts
new file mode 100644
index 0000000..f1fe094
--- /dev/null
+++ b/apps/theme-market/src/app/_stores/UserStore.ts
@@ -0,0 +1,16 @@
+import { User } from "@/entities/User";
+import { createStore } from "zustand";
+
+export type UserStoreState = {
+ user: User;
+};
+
+export type UserStoreAction = {};
+
+export type UserStore = UserStoreState & UserStoreAction;
+
+export const createUserStore = (initalSate: UserStoreState) => {
+ return createStore(() => ({
+ ...initalSate,
+ }));
+};
diff --git a/apps/theme-market/src/entities/User.ts b/apps/theme-market/src/entities/User.ts
new file mode 100644
index 0000000..eedb194
--- /dev/null
+++ b/apps/theme-market/src/entities/User.ts
@@ -0,0 +1,9 @@
+export type User = {
+ id: string;
+ email: string;
+ localId: string;
+ nickname: {
+ nickname: string;
+ tag: string;
+ };
+};
diff --git a/apps/theme-market/src/repositories/AuthRepository.ts b/apps/theme-market/src/repositories/AuthRepository.ts
index 3d2eca3..6c8c35e 100644
--- a/apps/theme-market/src/repositories/AuthRepository.ts
+++ b/apps/theme-market/src/repositories/AuthRepository.ts
@@ -1,13 +1,13 @@
import { httpClient } from "@/clients/HttpClient";
+import { User } from "@/entities/User";
-// 예시용
type AuthRepository = {
- me: () => Promise;
+ me: (accessToken?: string) => Promise;
};
export const authRepositry: AuthRepository = {
- me: async () => {
- const res = await httpClient.get("/v1/users/me");
+ me: async (accessToken?: string) => {
+ const res = await httpClient.get("/v1/users/me", accessToken);
return res;
},
diff --git a/apps/theme-market/src/repositories/CookieRepository.ts b/apps/theme-market/src/repositories/CookieRepository.ts
new file mode 100644
index 0000000..9dae064
--- /dev/null
+++ b/apps/theme-market/src/repositories/CookieRepository.ts
@@ -0,0 +1,11 @@
+import { cookies } from "next/headers";
+
+type CookieRepository = {
+ get: (name: string, defaultValue?: string) => string | undefined;
+};
+
+export const cookieRepository: CookieRepository = {
+ get: (name: string, defaultValue?: string) => {
+ return cookies().get(name)?.value || defaultValue;
+ },
+};
diff --git a/apps/theme-market/src/repositories/ThemeRepository.ts b/apps/theme-market/src/repositories/ThemeRepository.ts
index e1cc6a6..5567cc7 100644
--- a/apps/theme-market/src/repositories/ThemeRepository.ts
+++ b/apps/theme-market/src/repositories/ThemeRepository.ts
@@ -4,6 +4,13 @@ import { PageResponse } from "@/entities/Page";
import { Theme } from "@/entities/Theme";
type ThemeRepository = {
+ getTheme: ({
+ id,
+ accessToken,
+ }: {
+ id: string;
+ accessToken?: string;
+ }) => Promise;
getMyThemes: ({ accessToken }: { accessToken?: string }) => Promise;
getBestThemes: ({
page,
@@ -24,6 +31,11 @@ type ThemeRepository = {
const DEFAULT_PAGE = 1;
export const themeRepositry: ThemeRepository = {
+ getTheme: async ({ id, accessToken }) => {
+ const res = await httpClient.get(`/v1/themes/${id}`, accessToken);
+
+ return res;
+ },
getMyThemes: async ({ accessToken }) => {
const res = await httpClient.get("/v1/themes", accessToken);
return res;
diff --git a/apps/theme-market/src/services/AuthService.ts b/apps/theme-market/src/services/AuthService.ts
index e7b984d..1a3a282 100644
--- a/apps/theme-market/src/services/AuthService.ts
+++ b/apps/theme-market/src/services/AuthService.ts
@@ -1,12 +1,12 @@
+import { User } from "@/entities/User";
import { authRepositry } from "@/repositories/AuthRepository";
-// 예시용
type AuthService = {
- me: () => Promise;
+ me: (accessToken?: string) => Promise;
};
export const authService: AuthService = {
- me: async () => {
- return await authRepositry.me();
+ me: async (accessToken?: string) => {
+ return await authRepositry.me(accessToken);
},
};
diff --git a/apps/theme-market/src/services/CookieService.ts b/apps/theme-market/src/services/CookieService.ts
new file mode 100644
index 0000000..4816635
--- /dev/null
+++ b/apps/theme-market/src/services/CookieService.ts
@@ -0,0 +1,17 @@
+import { ACCESS_TOKEN_KEY } from "@/clients/HttpClient";
+import { cookieRepository } from "@/repositories/CookieRepository";
+import { cookies } from "next/headers";
+
+type CookieService = {
+ get: (name: string, defaultValue: string) => string | undefined;
+ getAccessToken: () => string | undefined;
+};
+
+export const cookieService: CookieService = {
+ get: (name: string, defaultValue?: string) => {
+ return cookieRepository.get(name, defaultValue);
+ },
+ getAccessToken: () => {
+ return cookieRepository.get(ACCESS_TOKEN_KEY);
+ },
+};
diff --git a/apps/theme-market/src/services/ThemeService.ts b/apps/theme-market/src/services/ThemeService.ts
index ebea110..b8faa1a 100644
--- a/apps/theme-market/src/services/ThemeService.ts
+++ b/apps/theme-market/src/services/ThemeService.ts
@@ -3,12 +3,16 @@ import { Theme } from "@/entities/Theme";
import { themeRepositry } from "@/repositories/ThemeRepository";
type ThemeService = {
+ getTheme: (id: string, accessToken?: string) => Promise;
getMyThemes: (accessToken?: string) => Promise;
getBestThemes: (accessToken?: string) => Promise;
getFriendsThemes: (accessToken?: string) => Promise;
};
export const themeService: ThemeService = {
+ getTheme: async (id: string, accessToken?: string) => {
+ return await themeRepositry.getTheme({ id, accessToken });
+ },
getMyThemes: async (accessToken?: string) => {
return (await themeRepositry.getMyThemes({ accessToken })).filter(
(theme) => theme.isCustom
diff --git a/yarn.lock b/yarn.lock
index 14b1798..1d258c8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -11079,3 +11079,8 @@ yocto-queue@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251"
integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==
+
+zustand@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/zustand/-/zustand-5.0.1.tgz#2bdca5e4be172539558ce3974fe783174a48fdcf"
+ integrity sha512-pRET7Lao2z+n5R/HduXMio35TncTlSW68WsYBq2Lg1ASspsNGjpwLAsij3RpouyV6+kHMwwwzP0bZPD70/Jx/w==