diff --git a/src/api/book-club/react-query/customHooks.ts b/src/api/book-club/react-query/customHooks.ts index 0e8cd82f..5276cd55 100644 --- a/src/api/book-club/react-query/customHooks.ts +++ b/src/api/book-club/react-query/customHooks.ts @@ -126,9 +126,8 @@ export function useLikeBookClub(filter: BookClubParams) { //TODO: 로직 확인 후 변경 필요 // onSuccess: () => { // queryClient.invalidateQueries({ - // queryKey: ['bookClubs', 'list', DEFAULT_FILTERS], + // queryKey: bookClubs._def, // }); - // // console.log(bookClubs._def) // }, onError: (_error, id, context) => { diff --git a/src/api/book-club/react-query/likeOptimisticUpdate.ts b/src/api/book-club/react-query/likeOptimisticUpdate.ts index dce81855..5c02550d 100644 --- a/src/api/book-club/react-query/likeOptimisticUpdate.ts +++ b/src/api/book-club/react-query/likeOptimisticUpdate.ts @@ -1,7 +1,7 @@ import { QueryClient } from '@tanstack/react-query'; import { BookClub, BookClubParams } from '@/types/bookclubs'; import { bookClubs } from './queries'; -import { DEFAULT_FILTERS } from '@/lib/constants/filters'; +import { DEFAULT_FILTERS } from '@/constants/filters'; export const likeOnMutate = async ( queryClient: QueryClient, @@ -12,22 +12,17 @@ export const likeOnMutate = async ( const listQueryKey = ['bookClubs', 'list', filter || DEFAULT_FILTERS]; const detailQueryKey = bookClubs.detail(id).queryKey; + // 기존 요청을 취소(데이터 충돌 방지) await queryClient.cancelQueries({ queryKey: listQueryKey }); await queryClient.cancelQueries({ queryKey: detailQueryKey }); - // console.log('🔍 수정된 listQueryKey:', listQueryKey); - // console.log('🔍 현재 활성화된 모든 쿼리키:', queryClient.getQueriesData({})); - + // 기존 캐시 데이터 저장 const previousBookClubs = queryClient.getQueryData<{ bookClubs: BookClub[] }>( listQueryKey, ); const previousDetail = queryClient.getQueryData(detailQueryKey); - // if (!previousBookClubs) { - // console.warn('⚠️ 캐시된 데이터가 없습니다. queryKey 확인 필요:', listQueryKey); - // queryClient.invalidateQueries({ queryKey: listQueryKey }); - // } - + // 캐시 데이터 업데이트 if (previousBookClubs) { queryClient.setQueryData(listQueryKey, (old: any) => old?.map((club: BookClub) => @@ -35,11 +30,11 @@ export const likeOnMutate = async ( ), ); } - if (previousDetail) { queryClient.setQueryData(detailQueryKey, { ...previousDetail, isLiked }); } + // API 요청이 실패 시 이전 상태로 복구할 수 있도록 기존 데이터를 반환 return { previousBookClubs, previousDetail }; }; diff --git a/src/app/bookclub/page.tsx b/src/app/bookclub/page.tsx index 8e0d78c2..ea8484ec 100644 --- a/src/app/bookclub/page.tsx +++ b/src/app/bookclub/page.tsx @@ -1,18 +1,20 @@ import BookClubMainPage from '@/features/bookclub/components/BookClubMainPage'; -import { DEFAULT_FILTERS } from '@/lib/constants/filters'; +import { DEFAULT_FILTERS } from '@/constants/filters'; import { fetchBookClubs } from '@/lib/utils/fetchBookClubs'; import { dehydrate, HydrationBoundary, QueryClient, } from '@tanstack/react-query'; +import { getServerSideToken } from '@/lib/utils/getServerSideToken'; export default async function Home() { const queryClient = new QueryClient(); + const token = await getServerSideToken(); await queryClient.prefetchQuery({ queryKey: ['bookClubs', 'list', DEFAULT_FILTERS], - queryFn: () => fetchBookClubs(DEFAULT_FILTERS), + queryFn: () => fetchBookClubs(DEFAULT_FILTERS, token || undefined), }); return ( diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 48a6dc59..547bf187 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -6,6 +6,7 @@ import { Toast } from '@/components/toast/toast'; import { MSWComponent } from '@/components/MSWComponent'; import '@/styles/globals.css'; +import { LikeProvider } from '@/lib/contexts/LikeContext'; export const metadata: Metadata = { title: 'Bookco', @@ -25,11 +26,13 @@ export default function RootLayout({ strategy="beforeInteractive" /> - -
- - {children} -
+ + +
+ + {children} +
+
diff --git a/src/app/page.tsx b/src/app/page.tsx index 8e0d78c2..ea8484ec 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,18 +1,20 @@ import BookClubMainPage from '@/features/bookclub/components/BookClubMainPage'; -import { DEFAULT_FILTERS } from '@/lib/constants/filters'; +import { DEFAULT_FILTERS } from '@/constants/filters'; import { fetchBookClubs } from '@/lib/utils/fetchBookClubs'; import { dehydrate, HydrationBoundary, QueryClient, } from '@tanstack/react-query'; +import { getServerSideToken } from '@/lib/utils/getServerSideToken'; export default async function Home() { const queryClient = new QueryClient(); + const token = await getServerSideToken(); await queryClient.prefetchQuery({ queryKey: ['bookClubs', 'list', DEFAULT_FILTERS], - queryFn: () => fetchBookClubs(DEFAULT_FILTERS), + queryFn: () => fetchBookClubs(DEFAULT_FILTERS, token || undefined), }); return ( diff --git a/src/components/card/Card.tsx b/src/components/card/Card.tsx index cd5dc547..3e1eb04d 100644 --- a/src/components/card/Card.tsx +++ b/src/components/card/Card.tsx @@ -7,7 +7,7 @@ import Avatar from '../avatar/Avatar'; import { LocationIcon, HostIcon, - HeartIcon, + // HeartIcon, RatingIcon, OnlineIcon, } from '../../../public/icons'; @@ -52,10 +52,11 @@ function CardBox({ children, className = '', ...props }: CardBoxProps) { function CardImage({ url, alt = '모임 이미지', - isLiked, - onLikeClick, + // isLiked, + // onLikeClick, className, isPast, + // isHost, ...props }: CardImageProps) { return ( @@ -73,11 +74,11 @@ function CardImage({ fill className={twMerge('object-cover', isPast && 'grayscale')} /> - {isLiked !== undefined && ( + {/* {isLiked !== undefined && !isHost && (
- )} + )} */} ); } @@ -218,6 +219,7 @@ function Card(props: CardProps) { max, isPast, isCanceled, + isHost, // meetingType, bookClubType, clubStatus, @@ -234,6 +236,7 @@ function Card(props: CardProps) { alt={imageAlt} isLiked={isLiked} isPast={isPast} + isHost={isHost} onLikeClick={onLikeClick} /> diff --git a/src/components/card/types/card.ts b/src/components/card/types/card.ts index 1ed7064b..9587d39c 100644 --- a/src/components/card/types/card.ts +++ b/src/components/card/types/card.ts @@ -34,6 +34,7 @@ interface CardImageProps extends ComponentPropsWithoutRef<'div'> { alt?: string; isLiked?: boolean; isPast?: boolean; + isHost?: boolean; onLikeClick?: () => void; } diff --git a/src/components/card/types/clubCard.ts b/src/components/card/types/clubCard.ts index f20afced..dd42604d 100644 --- a/src/components/card/types/clubCard.ts +++ b/src/components/card/types/clubCard.ts @@ -30,6 +30,9 @@ interface DefaultClubCard extends ClubCard { current: number; max: number; + // 호스트 여부 + isHost?: boolean; + //마이페이지 판별 isMyPage?: boolean; } diff --git a/src/lib/constants/filters.ts b/src/constants/filters.ts similarity index 100% rename from src/lib/constants/filters.ts rename to src/constants/filters.ts diff --git a/src/features/bookclub/components/BookClubMainPage.tsx b/src/features/bookclub/components/BookClubMainPage.tsx index cee9b1f3..824bfc72 100644 --- a/src/features/bookclub/components/BookClubMainPage.tsx +++ b/src/features/bookclub/components/BookClubMainPage.tsx @@ -15,7 +15,9 @@ function BookClubMainPage() { const { data, isLoading, isFetching } = useQuery({ queryKey: ['bookClubs', 'list', filters], queryFn: () => fetchBookClubs(filters), - staleTime: 1000 * 30, + enabled: false, // ✅ 서버에서 이미 가져왔기 때문에 클라이언트에서 다시 요청하지 않음 + refetchOnMount: false, // ✅ 마운트 시 다시 데이터를 불러오지 않음 + staleTime: 1000 * 60, }); const router = useRouter(); diff --git a/src/features/bookclub/components/ClubListSection.tsx b/src/features/bookclub/components/ClubListSection.tsx index 29bcd6ad..856c7699 100644 --- a/src/features/bookclub/components/ClubListSection.tsx +++ b/src/features/bookclub/components/ClubListSection.tsx @@ -3,11 +3,14 @@ import Card from '@/components/card/Card'; import { formatDateForUI, isPastDate } from '@/lib/utils/formatDateForUI'; import { useRouter } from 'next/navigation'; -import { useMemo } from 'react'; +import { useEffect, useMemo } from 'react'; import EmptyState from '@/components/common-layout/EmptyState'; import { clubStatus } from '@/lib/utils/clubUtils'; import { BookClub, BookClubParams } from '@/types/bookclubs'; -import { useLikeClub, useUnLikeClub } from '@/lib/hooks'; +import { useLikeClub, useLikeWithAuthCheck, useUnLikeClub } from '@/lib/hooks'; +import { useAuthStore } from '@/store/authStore'; +import PopUp from '@/components/pop-up/PopUp'; +import { queryClient } from '@/lib/utils/reactQueryProvider'; interface ClubListSectionProps { bookClubs: BookClub[]; @@ -16,15 +19,46 @@ interface ClubListSectionProps { function ClubListSection({ bookClubs = [], filter }: ClubListSectionProps) { const router = useRouter(); + const { + isLikePopUpOpen, + likePopUpLabel, + onShowAuthPopUp, + onCloseCheckAuthPopup, + } = useLikeWithAuthCheck(); const { onConfirmUnLike } = useUnLikeClub(filter); const { onConfirmLike } = useLikeClub(filter); + const { isLoggedIn, checkLoginStatus, user } = useAuthStore(); + + useEffect(() => { + checkLoginStatus(); + console.log('메인 페이지: ', bookClubs); + }, [checkLoginStatus]); const today = useMemo(() => new Date(), []); // console.log('🔍 ClubListSection 데이터:', bookClubs); const handleLikeClub = (isLiked: boolean, id: number) => { - isLiked ? onConfirmUnLike(id) : onConfirmLike(id); + if (!isLoggedIn) { + onShowAuthPopUp(); + return; + } + + if (isLiked) { + onConfirmUnLike(id); + } else { + onConfirmLike(id); + } + + queryClient.setQueryData(['bookClubs', 'list', filter], (oldData: any) => + oldData.map((club: BookClub) => + club.id === id ? { ...club, isLiked: !isLiked } : club, + ), + ); + }; + + const handleLikePopUpConfirm = () => { + router.push('/login'); }; return ( @@ -52,6 +86,7 @@ function ClubListSection({ bookClubs = [], filter }: ClubListSectionProps) { club.endDate, today, )} + isHost={club.hostId === user?.id} onLikeClick={() => handleLikeClub(club.isLiked, club.id)} onClick={() => router.push(`/bookclub/${club.id}`)} /> @@ -62,6 +97,14 @@ function ClubListSection({ bookClubs = [], filter }: ClubListSectionProps) { subtitle="지금 바로 책 모임을 만들어보세요." /> )} + ); } diff --git a/src/features/bookclub/hooks/useFetchBookClubList.test.tsx b/src/features/bookclub/hooks/useFetchBookClubList.test.tsx index 9c7d45bb..20d40477 100644 --- a/src/features/bookclub/hooks/useFetchBookClubList.test.tsx +++ b/src/features/bookclub/hooks/useFetchBookClubList.test.tsx @@ -1,6 +1,6 @@ import { renderHook, act } from '@testing-library/react'; import useBookClubList from '@/features/bookclub/hooks/useFetchBookClubList'; -import { DEFAULT_FILTERS } from '@/lib/constants/filters'; +import { DEFAULT_FILTERS } from '@/constants/filters'; describe('useBookClubList', () => { it('초기 필터 상태는 DEFAULT_FILTERS와 동일해야 한다', () => { diff --git a/src/features/bookclub/hooks/useFetchBookClubList.ts b/src/features/bookclub/hooks/useFetchBookClubList.ts index aa2940da..c0ed9def 100644 --- a/src/features/bookclub/hooks/useFetchBookClubList.ts +++ b/src/features/bookclub/hooks/useFetchBookClubList.ts @@ -1,6 +1,6 @@ import { useState } from 'react'; import { BookClubParams } from '@/types/bookclubs'; -import { DEFAULT_FILTERS } from '@/lib/constants/filters'; +import { DEFAULT_FILTERS } from '@/constants/filters'; const useBookClubList = () => { const [filters, setFilters] = useState(DEFAULT_FILTERS); diff --git a/src/features/club-details/components/HeaderSection.tsx b/src/features/club-details/components/HeaderSection.tsx index c1d43b62..ea49dace 100644 --- a/src/features/club-details/components/HeaderSection.tsx +++ b/src/features/club-details/components/HeaderSection.tsx @@ -8,14 +8,16 @@ import { formatDateForUI, isPastDate } from '@/lib/utils/formatDateForUI'; import { useAuthStore } from '@/store/authStore'; import { BookClub } from '@/types/bookclubs'; import { useRouter } from 'next/navigation'; -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import { useJoinClub } from '../hooks'; import { useCancelClub, useLeaveClub, + useLikeClub, useLikeWithAuthCheck, useUnLikeClub, } from '@/lib/hooks/index'; +import { useLikeContext } from '@/lib/contexts/LikeContext'; interface HeaderSectionProps { clubInfo: BookClub; @@ -23,16 +25,13 @@ interface HeaderSectionProps { } function HeaderSection({ clubInfo, idAsNumber }: HeaderSectionProps) { - const [isOpen, setIsOpen] = useState(false); - const [isMember, setIsMember] = useState<{ - label: string; - isTwoButton: boolean; - handlePopUpConfirm?: () => void; - } | null>(null); - const { handleJoin } = useJoinClub(); - const { popUpState, onCancel, onConfirmCancel, onClosePopUp } = - useCancelClub(); + const { + popUpState: cancelPopUpState, + onCancel, + onConfirmCancel, + onClosePopUp: onCloseCancelPopUp, + } = useCancelClub(); const { leavePopUpState, onCancelParticipation, @@ -42,10 +41,13 @@ function HeaderSection({ clubInfo, idAsNumber }: HeaderSectionProps) { const { isLikePopUpOpen, likePopUpLabel, - onCheckAuthPopUp, + onShowAuthPopUp, onCloseCheckAuthPopup, } = useLikeWithAuthCheck(); + const { onConfirmLike } = useLikeClub(); const { onConfirmUnLike } = useUnLikeClub(); + const { likedClubs, toggleLike } = useLikeContext(); + const isLiked = likedClubs?.has(clubInfo.id) ?? clubInfo.isLiked; const { isLoggedIn, checkLoginStatus, user } = useAuthStore(); @@ -63,23 +65,22 @@ function HeaderSection({ clubInfo, idAsNumber }: HeaderSectionProps) { }, [idAsNumber]); const handleJoinClick = () => { + !isLoggedIn ? router.push('/login') : handleJoin(clubInfo.id); + }; + + const handleLikeClub = () => { if (!isLoggedIn) { - setIsMember({ - label: '로그인 후 이용해주세요!', - isTwoButton: true, - handlePopUpConfirm: () => router.replace('/login'), - }); - setIsOpen(true); + onShowAuthPopUp(); return; } - handleJoin(clubInfo.id); - }; + toggleLike(clubInfo.id, !isLiked); // ✅ 전역 상태 업데이트 - const handleLikeClub = () => { - clubInfo.isLiked - ? onConfirmUnLike(clubInfo.id) - : onCheckAuthPopUp(clubInfo.id); + if (isLiked) { + onConfirmUnLike(clubInfo.id); + } else { + onConfirmLike(clubInfo.id); + } }; const handleLikePopUpConfirm = () => { @@ -125,17 +126,6 @@ function HeaderSection({ clubInfo, idAsNumber }: HeaderSectionProps) { return (
- {isMember && ( - { - setIsOpen(false); - }} - handlePopUpConfirm={isMember.handlePopUpConfirm} - /> - )} {/* 찜하기 */} diff --git a/src/features/club-find/api/index.ts b/src/features/club-find/api/index.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/src/features/club-find/api/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/src/features/club-find/components/index.ts b/src/features/club-find/components/index.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/src/features/club-find/components/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/src/features/club-find/container/index.ts b/src/features/club-find/container/index.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/src/features/club-find/container/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/src/features/club-find/hooks/index.ts b/src/features/club-find/hooks/index.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/src/features/club-find/hooks/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/src/features/club-find/types/index.ts b/src/features/club-find/types/index.ts deleted file mode 100644 index cb0ff5c3..00000000 --- a/src/features/club-find/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {}; diff --git a/src/lib/contexts/LikeContext.tsx b/src/lib/contexts/LikeContext.tsx new file mode 100644 index 00000000..5f49e169 --- /dev/null +++ b/src/lib/contexts/LikeContext.tsx @@ -0,0 +1,99 @@ +'use client'; + +import React, { + createContext, + useState, + useContext, + useCallback, + useEffect, +} from 'react'; +import { useAuthStore } from '@/store/authStore'; + +interface LikeContextType { + likedClubs: Set | undefined; + toggleLike: (clubId: number, isLiked?: boolean) => void; + isLiked: (clubId: number) => boolean; +} + +// 초깃값과 함께 컨텍스트 생성 +const LikeContext = createContext(undefined); + +export const LikeProvider: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + const [likedClubs, setLikedClubs] = useState | undefined>( + undefined, + ); + const { isLoggedIn } = useAuthStore(); + + // // ✅ localStorage에서 찜한 목록 불러오기 (초기 로드) + useEffect(() => { + const storedLikes = localStorage.getItem('likedClubs'); + if (storedLikes) { + setLikedClubs(new Set(JSON.parse(storedLikes))); + } else { + setLikedClubs(new Set()); + } + }, []); + + // ✅ `localStorage`에서 찜 목록 다시 불러오기 (새로고침 시) + useEffect(() => { + if (typeof window !== 'undefined') { + const storedLikes = localStorage.getItem('likedClubs'); + setLikedClubs(storedLikes ? new Set(JSON.parse(storedLikes)) : new Set()); + } + }, []); + + // ✅ likedClubs가 변경될 때마다 `localStorage`에 저장 + useEffect(() => { + if (typeof window !== 'undefined' && likedClubs) { + localStorage.setItem( + 'likedClubs', + JSON.stringify(Array.from(likedClubs)), + ); + } + }, [likedClubs]); + + // ✅ 로그아웃 시 찜한 목록 초기화 + useEffect(() => { + if (!isLoggedIn) { + setLikedClubs(new Set()); // ✅ 찜한 상태 초기화 + localStorage.removeItem('likedClubs'); // ✅ localStorage에서도 삭제 + } + }, [isLoggedIn]); + + const toggleLike = useCallback((clubId: number, isLiked?: boolean) => { + setLikedClubs((prev) => { + if (!prev) return prev; // 로딩 중이면 변경 X + const newSet = new Set(prev); + if (isLiked !== undefined) { + isLiked ? newSet.add(clubId) : newSet.delete(clubId); + } else { + newSet.has(clubId) ? newSet.delete(clubId) : newSet.add(clubId); + } + localStorage.setItem('likedClubs', JSON.stringify(Array.from(newSet))); + return newSet; + }); + }, []); + + const isLiked = useCallback( + (clubId: number) => likedClubs?.has(clubId) ?? false, // `undefined`일 경우 `false` 반환 + [likedClubs], + ); + + // 컨텍스트 생서자로 데이터 제공 + return ( + + {children} + + ); +}; + +export const useLikeContext = () => { + // 컨텍스트 사용으로 데이터 얻기 + const context = useContext(LikeContext); + if (context === undefined) { + throw new Error('useLikeContext must be used within a LikeProvider'); + } + return context; +}; diff --git a/src/lib/hooks/useLikeClub.ts b/src/lib/hooks/useLikeClub.ts index 353278ec..d4003ddb 100644 --- a/src/lib/hooks/useLikeClub.ts +++ b/src/lib/hooks/useLikeClub.ts @@ -2,7 +2,7 @@ import { useLikeBookClub } from '@/api/book-club/react-query'; import { showToast } from '@/components/toast/toast'; import { TOAST_MESSAGES } from '@/constants/messages/toast'; import { BookClubParams } from '@/types/bookclubs'; -import { DEFAULT_FILTERS } from '../constants/filters'; +import { DEFAULT_FILTERS } from '@/constants/filters'; export const useLikeClub = (filter?: BookClubParams) => { const { mutate: likeClub } = useLikeBookClub(filter || DEFAULT_FILTERS); diff --git a/src/lib/hooks/useLikeWithAuthCheck.ts b/src/lib/hooks/useLikeWithAuthCheck.ts index a0c09298..e8eaca08 100644 --- a/src/lib/hooks/useLikeWithAuthCheck.ts +++ b/src/lib/hooks/useLikeWithAuthCheck.ts @@ -1,27 +1,14 @@ -import { useEffect, useState } from 'react'; -import { useLikeClub } from './useLikeClub'; -import { useAuthStore } from '@/store/authStore'; +import { useState } from 'react'; export const useLikeWithAuthCheck = () => { - const { onConfirmLike } = useLikeClub(); const [isPopUpOpen, setIsPopUpOpen] = useState(false); const [popUpLabel, setPopUpLabel] = useState(''); - const { isLoggedIn, checkLoginStatus } = useAuthStore(); - - useEffect(() => { - checkLoginStatus(); - }, [checkLoginStatus]); - - const onCheckAuthPopUp = (clubId: number) => { - if (isLoggedIn) { - onConfirmLike(clubId); - } else { - setPopUpLabel( - `로그인 후 이용할 수 있어요.\n로그인 페이지로 이동하시겠어요?`, - ); - setIsPopUpOpen(true); - } + const onShowAuthPopUp = () => { + setPopUpLabel( + `로그인 후 이용할 수 있어요.\n로그인 페이지로 이동하시겠어요?`, + ); + setIsPopUpOpen(true); }; const onCloseCheckAuthPopup = () => { @@ -32,7 +19,7 @@ export const useLikeWithAuthCheck = () => { return { isLikePopUpOpen: isPopUpOpen, likePopUpLabel: popUpLabel, - onCheckAuthPopUp, + onShowAuthPopUp, onCloseCheckAuthPopup, }; }; diff --git a/src/lib/hooks/useUnLikeClub.ts b/src/lib/hooks/useUnLikeClub.ts index 00bbda19..ea386274 100644 --- a/src/lib/hooks/useUnLikeClub.ts +++ b/src/lib/hooks/useUnLikeClub.ts @@ -2,7 +2,7 @@ import { useUnLikeBookClub } from '@/api/book-club/react-query'; import { showToast } from '@/components/toast/toast'; import { TOAST_MESSAGES } from '@/constants/messages/toast'; import { BookClubParams } from '@/types/bookclubs'; -import { DEFAULT_FILTERS } from '../constants/filters'; +import { DEFAULT_FILTERS } from '@/constants/filters'; export const useUnLikeClub = (filter?: BookClubParams) => { const { mutate: unLikeClub } = useUnLikeBookClub(filter || DEFAULT_FILTERS); diff --git a/src/lib/utils/fetchBookClub.test.ts b/src/lib/utils/fetchBookClub.test.ts index b0f32e0e..1873767e 100644 --- a/src/lib/utils/fetchBookClub.test.ts +++ b/src/lib/utils/fetchBookClub.test.ts @@ -1,6 +1,6 @@ import { mockBookClubs } from '@/mocks/mockDatas'; import { fetchBookClubs } from './fetchBookClubs'; -import { DEFAULT_FILTERS } from '@/lib/constants/filters'; +import { DEFAULT_FILTERS } from '@/constants/filters'; describe('fetchBookClubs', () => { beforeEach(() => { diff --git a/src/lib/utils/fetchBookClubs.ts b/src/lib/utils/fetchBookClubs.ts index e19d6c46..a0dba2e1 100644 --- a/src/lib/utils/fetchBookClubs.ts +++ b/src/lib/utils/fetchBookClubs.ts @@ -1,6 +1,6 @@ import { BookClubParams } from '@/types/bookclubs'; -export async function fetchBookClubs(filters: BookClubParams) { +export async function fetchBookClubs(filters: BookClubParams, token?: string) { try { // filters 객체를 URLSearchParams로 변환 const queryParams = new URLSearchParams( @@ -15,6 +15,7 @@ export async function fetchBookClubs(filters: BookClubParams) { method: 'GET', headers: { 'Content-Type': 'application/json', + ...(token ? { Authorization: `Bearer ${token}` } : {}), }, }, ); diff --git a/src/lib/utils/getServerSideToken.ts b/src/lib/utils/getServerSideToken.ts new file mode 100644 index 00000000..841bb796 --- /dev/null +++ b/src/lib/utils/getServerSideToken.ts @@ -0,0 +1,10 @@ +import { cookies } from 'next/headers'; + +export async function getServerSideToken() { + try { + const cookieStore = cookies(); + return (await cookieStore).get('auth_token')?.value; + } catch { + return null; + } +}