diff --git a/package.json b/package.json index c980d70..b331650 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "eslint-plugin-simple-import-sort": "^12.1.0", - "js-cookie": "^3.0.5", "lucide-react": "^0.390.0", "next": "14.2.3", "next-auth": "5.0.0-beta.20", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f270b65..8ddfcf4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,9 +35,6 @@ importers: eslint-plugin-simple-import-sort: specifier: ^12.1.0 version: 12.1.0(eslint@8.57.0) - js-cookie: - specifier: ^3.0.5 - version: 3.0.5 lucide-react: specifier: ^0.390.0 version: 0.390.0(react@18.3.1) @@ -2330,10 +2327,6 @@ packages: jquery@3.7.1: resolution: {integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==} - js-cookie@3.0.5: - resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} - engines: {node: '>=14'} - js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -6131,8 +6124,6 @@ snapshots: jquery@3.7.1: {} - js-cookie@3.0.5: {} - js-tokens@4.0.0: {} js-yaml@4.1.0: diff --git a/src/app/album/create/hooks/useAlbum.ts b/src/app/album/create/hooks/useAlbum.ts index a2fec44..ff6155b 100644 --- a/src/app/album/create/hooks/useAlbum.ts +++ b/src/app/album/create/hooks/useAlbum.ts @@ -3,13 +3,13 @@ import { useRouter } from "next/navigation" import { postAlbum } from "@/app/api/photo" import { getQueryClient } from "@/common/QueryProviders" -import { useAlert } from "@/store/AlertContext" +import { useAlertStore } from "@/store/alert" import { usePatchPhotoAlbum } from "../../../scanner/hooks/usePhoto" import type { AlbumType } from "../../types" export const usePostAlbum = () => { - const { showAlert } = useAlert() + const { showAlert } = useAlertStore() const router = useRouter() const { patchPhotoAlbum } = usePatchPhotoAlbum() diff --git a/src/app/api/myfetch/index.ts b/src/app/api/myfetch/index.ts index 7e5552d..dd2f0cc 100644 --- a/src/app/api/myfetch/index.ts +++ b/src/app/api/myfetch/index.ts @@ -1,4 +1,4 @@ -import { getAccessToken } from "@/libs" +import { useAuthStore } from "@/store/auth" import customFetch from "./customFetch" @@ -13,10 +13,12 @@ export const myFetch = customFetch({ request: async ([url, options], fetch) => { // 요청 인터셉터 로직 추가 (예: 로깅, 인증 토큰 추가) // console.log("Request Interceptor:", url, options) - const token = getAccessToken() - if (token && options) { + + const { accessToken } = useAuthStore.getState() + + if (accessToken && options) { const headers = new Headers(options.headers || {}) - headers.set("Authorization", `Bearer ${token}`) + headers.set("Authorization", `Bearer ${accessToken}`) options.headers = headers } return [url, options] diff --git a/src/app/layout.tsx b/src/app/layout.tsx index b224372..28cd6e5 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,12 +1,15 @@ import "@/styles/main.css" import type { Metadata } from "next" +import { cookies } from "next/headers" -import AuthProvider from "@/common/AuthProvider" import ErrorHandlingWrapper from "@/common/ErrorHandlingWrapper" +import NextAuthProvider from "@/common/NextAuthProvider" import { QueryProviders } from "@/common/QueryProviders" +import { ACCESS_TOKEN_KEY } from "@/constants" import { pretendard } from "@/font" -import AlertContainer from "@/store/AlertContext" +import { AlertProvider } from "@/store/alert" +import { AuthProvider } from "@/store/auth" export const metadata: Metadata = { title: "마푸-네컷사진 전용 앨범", @@ -41,17 +44,20 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode }>) { + const accessToken = cookies().get(ACCESS_TOKEN_KEY)?.value || null + return ( - + - + + {children} - + ) diff --git a/src/app/profile/_components/ListItem.tsx b/src/app/profile/_components/ListItem.tsx index 0629b70..fcecc2b 100644 --- a/src/app/profile/_components/ListItem.tsx +++ b/src/app/profile/_components/ListItem.tsx @@ -6,7 +6,7 @@ import Button from "@/common/Button" import Icon from "@/common/Icon" import { LIST_ITEM_INFO } from "@/constants" import { isExternalLink, isInternalLink } from "@/libs" -import { useAlert } from "@/store/AlertContext" +import { useAlertStore } from "@/store/alert" interface ItemButtonType { label: string @@ -21,7 +21,7 @@ export interface ListItemProps { const ListItem = () => { const router = useRouter() - const { showAlert } = useAlert() + const { showAlert } = useAlertStore() const handleClick = async (item: ItemButtonType) => { if (item.action) { diff --git a/src/app/scanner/hooks/usePhoto.ts b/src/app/scanner/hooks/usePhoto.ts index c1c2316..4beb6a4 100644 --- a/src/app/scanner/hooks/usePhoto.ts +++ b/src/app/scanner/hooks/usePhoto.ts @@ -1,10 +1,10 @@ import { useMutation, useQuery } from "@tanstack/react-query" import { getAlbums, patchPhotoAlbum, postQrCode } from "@/app/api/photo" -import { useAlert } from "@/store/AlertContext" +import { useAlertStore } from "@/store/alert" export const usePostQrCode = () => { - const { showAlert } = useAlert() + const { showAlert } = useAlertStore() const { data, mutate, isPending } = useMutation({ mutationFn: (code: string) => postQrCode(code), diff --git a/src/auth.ts b/src/auth.ts index 420e977..4668915 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -5,6 +5,8 @@ import KakaoProvider from "next-auth/providers/kakao" import { authLogin } from "@/app/api/signIn" import { ACCESS_TOKEN_KEY } from "@/constants" +import { useAuthStore } from "./store/auth" + export const { handlers: { GET, POST }, auth, @@ -26,7 +28,12 @@ export const { if (account?.access_token) { const authResponse = await authLogin(account.access_token) - cookies().set(ACCESS_TOKEN_KEY, authResponse.accessToken) + cookies().set(ACCESS_TOKEN_KEY, authResponse.accessToken, { + httpOnly: true, + sameSite: "lax", + path: "/", + maxAge: 30 * 24 * 60 * 60, // 30일 + }) const updatedAccount = { ...account, @@ -58,6 +65,7 @@ export const { events: { signOut() { cookies().delete(ACCESS_TOKEN_KEY) + useAuthStore.getState().clearAuth() return }, }, diff --git a/src/common/AuthProvider.tsx b/src/common/AuthProvider.tsx deleted file mode 100644 index ba872d8..0000000 --- a/src/common/AuthProvider.tsx +++ /dev/null @@ -1,18 +0,0 @@ -"use client" - -import { SessionProvider } from "next-auth/react" -import React from "react" - -interface Props { - children: React.ReactNode -} - -const AuthProvider = ({ children }: Props) => { - return ( - - {children} - - ) -} - -export default AuthProvider diff --git a/src/common/NextAuthProvider.tsx b/src/common/NextAuthProvider.tsx new file mode 100644 index 0000000..aab0adb --- /dev/null +++ b/src/common/NextAuthProvider.tsx @@ -0,0 +1,14 @@ +"use client" + +import { SessionProvider } from "next-auth/react" +import React from "react" + +interface Props { + children: React.ReactNode +} + +const NextAuthProvider = ({ children }: Props) => { + return {children} +} + +export default NextAuthProvider diff --git a/src/libs/index.ts b/src/libs/index.ts index 995470f..3d45787 100644 --- a/src/libs/index.ts +++ b/src/libs/index.ts @@ -1,9 +1,3 @@ -import Cookies from "js-cookie" - -import { ACCESS_TOKEN_KEY } from "@/constants" - -export const getAccessToken = () => Cookies.get(ACCESS_TOKEN_KEY) - // 하루 필름인 경우는 지점별 도메인이 가변적 // HARUFILM: "http://haru{숫자}.mx{숫자}.co.kr", diff --git a/src/store/AlertContext.tsx b/src/store/AlertContext.tsx deleted file mode 100644 index 3230f01..0000000 --- a/src/store/AlertContext.tsx +++ /dev/null @@ -1,37 +0,0 @@ -"use client" - -import { create } from "zustand" - -import Alert from "../common/Alert" - -interface AlertState { - title: string - description: string - visible: boolean - showAlert: (title: string, description: string) => void - hideAlert: () => void -} - -const useAlertStore = create((set) => ({ - title: "", - description: "", - visible: false, - showAlert: (title: string, description: string) => - set({ title, description, visible: true }), - hideAlert: () => set({ visible: false }), -})) - -export const useAlert = () => { - const { showAlert, hideAlert, title, description, visible } = useAlertStore() - return { showAlert, hideAlert, title, description, visible } -} - -const AlertContainer = () => { - const { title, description, visible, hideAlert } = useAlert() - - if (!visible) return null - - return -} - -export default AlertContainer diff --git a/src/store/alert/AlertProvider.tsx b/src/store/alert/AlertProvider.tsx new file mode 100644 index 0000000..32dcd92 --- /dev/null +++ b/src/store/alert/AlertProvider.tsx @@ -0,0 +1,14 @@ +"use client" + +import Alert from "../../common/Alert" +import useAlertStore from "./useAlertStore" + +const AlertProvider = () => { + const { title, description, visible, hideAlert } = useAlertStore() + + if (!visible) return null + + return +} + +export default AlertProvider diff --git a/src/store/alert/index.ts b/src/store/alert/index.ts new file mode 100644 index 0000000..b01f7c5 --- /dev/null +++ b/src/store/alert/index.ts @@ -0,0 +1,2 @@ +export { default as AlertProvider } from "./AlertProvider" +export { default as useAlertStore } from "./useAlertStore" diff --git a/src/store/alert/useAlertStore.ts b/src/store/alert/useAlertStore.ts new file mode 100644 index 0000000..d992f5e --- /dev/null +++ b/src/store/alert/useAlertStore.ts @@ -0,0 +1,20 @@ +import { create } from "zustand" + +interface AlertState { + title: string + description: string + visible: boolean + showAlert: (title: string, description: string) => void + hideAlert: () => void +} + +const useAlertStore = create((set) => ({ + title: "", + description: "", + visible: false, + showAlert: (title: string, description: string) => + set({ title, description, visible: true }), + hideAlert: () => set({ visible: false }), +})) + +export default useAlertStore diff --git a/src/store/auth/AuthProvider.tsx b/src/store/auth/AuthProvider.tsx new file mode 100644 index 0000000..4f6030f --- /dev/null +++ b/src/store/auth/AuthProvider.tsx @@ -0,0 +1,19 @@ +"use client" + +import useAuthStore from "./useAuthStore" + +interface AuthContextProps { + accessToken: string | null +} + +const AuthProvider = ({ accessToken }: AuthContextProps) => { + const setAccessToken = useAuthStore((state) => state.setAccessToken) + + if (accessToken) { + setAccessToken(accessToken) + } + + return null +} + +export default AuthProvider diff --git a/src/store/auth/index.ts b/src/store/auth/index.ts new file mode 100644 index 0000000..f7b6780 --- /dev/null +++ b/src/store/auth/index.ts @@ -0,0 +1,2 @@ +export { default as AuthProvider } from "./AuthProvider" +export { default as useAuthStore } from "./useAuthStore" diff --git a/src/store/auth/useAuthStore.ts b/src/store/auth/useAuthStore.ts new file mode 100644 index 0000000..3540729 --- /dev/null +++ b/src/store/auth/useAuthStore.ts @@ -0,0 +1,15 @@ +import { create } from "zustand" + +interface AuthState { + accessToken: string | null + setAccessToken: (token: string | null) => void + clearAuth: () => void +} + +const useAuthStore = create((set) => ({ + accessToken: null, + setAccessToken: (token) => set({ accessToken: token }), + clearAuth: () => set({ accessToken: null }), +})) + +export default useAuthStore