diff --git a/src/app/(private)/(auth)/hub/page.tsx b/src/app/(private)/(auth)/hub/page.tsx index c5cb77af..bffdd033 100644 --- a/src/app/(private)/(auth)/hub/page.tsx +++ b/src/app/(private)/(auth)/hub/page.tsx @@ -1,6 +1,8 @@ import { unstable_rethrow } from 'next/navigation'; import { HubActionCard, HubProfile } from '@/components/auth/hub'; import { apiServer } from '@/lib/apis/server'; +import type { ApiResponse } from '@/types/common'; +import type { ClubDto } from '@/types/mypage'; type CardVariant = 'create' | 'join' | 'go'; @@ -20,6 +22,8 @@ export default async function HubPage({ let cardOrder: CardVariant[]; let goHref: string | undefined; + let goClubId: string | undefined; + let goClubName: string | undefined; const status = await apiServer .get('/clubs/membership-status') @@ -29,7 +33,23 @@ export default async function HubPage({ }); const hasActiveClub = status?.data?.hasActiveClub ?? false; - if (hasActiveClub) goHref = '/club/select'; + + if (hasActiveClub) { + const clubsRes = await apiServer.get>('/clubs').catch((err) => { + unstable_rethrow(err); + return null; + }); + const clubs = clubsRes?.data ?? []; + + if (clubs.length === 1) { + const club = clubs[0]; + goHref = `/${club.id}/home`; + goClubId = club.id; + goClubName = club.name; + } else { + goHref = '/club/select'; + } + } if (intent === 'create') { cardOrder = ['create', 'join', 'go']; @@ -55,6 +75,8 @@ export default async function HubPage({ variant={variant} href={hrefMap[variant]} isPrimary={index === 0} + clubId={variant === 'go' ? goClubId : undefined} + clubName={variant === 'go' ? goClubName : undefined} /> ))} diff --git a/src/hooks/home/useHomeGuard.ts b/src/hooks/home/useHomeGuard.ts index 961f89bd..6c85e151 100644 --- a/src/hooks/home/useHomeGuard.ts +++ b/src/hooks/home/useHomeGuard.ts @@ -1,15 +1,16 @@ 'use client'; import { useEffect, useSyncExternalStore } from 'react'; -import { useRouter } from 'next/navigation'; +import { useParams, useRouter } from 'next/navigation'; import { isAxiosError } from 'axios'; import { useClubActions, useClubId, useClubStore } from '@/stores/useClubStore'; import { useHomeQuery } from './useHomeQuery'; export function useHomeGuard() { const router = useRouter(); + const { clubId: clubIdParam } = useParams<{ clubId: string }>(); const clubId = useClubId(); - const { reset } = useClubActions(); + const { reset, syncClubId } = useClubActions(); const { error } = useHomeQuery(); const hydrated = useSyncExternalStore( @@ -20,11 +21,17 @@ export function useHomeGuard() { useEffect(() => { if (!hydrated) return; - if (!clubId) { + + if (clubIdParam && clubId !== clubIdParam) { + syncClubId(clubIdParam); + return; + } + + if (!clubIdParam && !clubId) { reset(); router.replace('/hub'); } - }, [hydrated, clubId, reset, router]); + }, [hydrated, clubId, clubIdParam, reset, router, syncClubId]); useEffect(() => { if (isAxiosError(error) && error.response?.status === 404) { diff --git a/src/providers/user-hydrator.tsx b/src/providers/user-hydrator.tsx index 5aef3159..50780559 100644 --- a/src/providers/user-hydrator.tsx +++ b/src/providers/user-hydrator.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useLayoutEffect, useRef } from 'react'; +import { useLayoutEffect } from 'react'; import { useClubStore } from '@/stores/useClubStore'; import { useUserStore } from '@/stores/useUserStore'; @@ -14,13 +14,20 @@ interface UserHydratorProps { } function UserHydrator({ userInfo, clubInfo, children }: UserHydratorProps) { - const hydrated = useRef(false); - useLayoutEffect(() => { - if (hydrated.current) return; - useUserStore.setState(userInfo, false, 'setUser'); - useClubStore.setState(clubInfo, false, 'setClub'); - hydrated.current = true; + const currentUser = useUserStore.getState(); + const currentClub = useClubStore.getState(); + + if ( + currentUser.id !== userInfo.id || + currentUser.profileImageUrl !== userInfo.profileImageUrl + ) { + useUserStore.setState(userInfo, false, 'setUser'); + } + + if (currentClub.clubId !== clubInfo.clubId || currentClub.clubName !== clubInfo.clubName) { + useClubStore.setState(clubInfo, false, 'setClub'); + } }, [clubInfo, userInfo]); return children; diff --git a/src/stores/useClubStore.ts b/src/stores/useClubStore.ts index 25213c3c..d1af1de1 100644 --- a/src/stores/useClubStore.ts +++ b/src/stores/useClubStore.ts @@ -16,6 +16,7 @@ export const useClubStore = create( combine(initialState, (set) => ({ setClubId: (clubId: string) => set({ clubId, clubName: null, clubProfileImageUrl: null }, false, 'setClubId'), + syncClubId: (clubId: string) => set({ clubId }, false, 'syncClubId'), setClub: (clubId: string, clubName: string, clubProfileImageUrl?: string | null) => set( { clubId, clubName, clubProfileImageUrl: clubProfileImageUrl ?? null }, @@ -24,7 +25,24 @@ export const useClubStore = create( ), reset: () => set(initialState, false, 'reset'), })), - { name: 'clubId' }, + { + name: 'clubId', + partialize: (state) => ({ + ...(state.clubId ? { clubId: state.clubId } : {}), + ...(state.clubName ? { clubName: state.clubName } : {}), + ...(state.clubProfileImageUrl ? { clubProfileImageUrl: state.clubProfileImageUrl } : {}), + }), + merge: (persistedState, currentState) => { + const persisted = (persistedState ?? {}) as Partial; + + return { + ...currentState, + clubId: persisted.clubId ?? currentState.clubId, + clubName: persisted.clubName ?? currentState.clubName, + clubProfileImageUrl: persisted.clubProfileImageUrl ?? currentState.clubProfileImageUrl, + }; + }, + }, ), { name: 'ClubStore' }, ), @@ -37,6 +55,7 @@ export const useClubActions = () => useClubStore( useShallow((store) => ({ setClubId: store.setClubId, + syncClubId: store.syncClubId, setClub: store.setClub, reset: store.reset, })),