'use client'; import { useState, useCallback, useMemo } from 'react'; import { useRouter, useParams, useSearchParams } from 'next/navigation'; /** * 상세 페이지 모드 타입 * - view: 조회 모드 * - edit: 수정 모드 * - create: 등록 모드 */ export type DetailMode = 'view' | 'edit' | 'create'; export interface UseDetailPageStateOptions { /** 기본 모드 (기본값: 'view') */ defaultMode?: DetailMode; /** 목록 페이지 경로 (뒤로가기용) */ listPath?: string; } export interface UseDetailPageStateReturn { // ===== 라우터 정보 ===== /** 현재 아이템 ID (params.id) */ id: string | null; /** 현재 locale */ locale: string; /** Next.js router */ router: ReturnType; // ===== 모드 관리 ===== /** 현재 모드 */ mode: DetailMode; /** 모드 변경 */ setMode: (mode: DetailMode) => void; /** 조회 모드 여부 */ isViewMode: boolean; /** 수정 모드 여부 */ isEditMode: boolean; /** 등록 모드 여부 */ isCreateMode: boolean; // ===== 데이터 상태 ===== /** 데이터 */ data: T | null; /** 데이터 설정 */ setData: (data: T | null) => void; /** 로딩 상태 */ isLoading: boolean; /** 로딩 상태 설정 */ setIsLoading: (loading: boolean) => void; /** 에러 메시지 */ error: string | null; /** 에러 설정 */ setError: (error: string | null) => void; // ===== 네비게이션 ===== /** 목록으로 이동 */ goToList: () => void; /** 수정 모드로 전환 (URL도 변경) */ goToEdit: () => void; /** 조회 모드로 전환 */ goToView: () => void; } /** * 상세 페이지 공통 상태 관리 훅 * * 등록/수정/상세 페이지에서 반복되는 상태 및 라우터 로직을 통합합니다. * * @example * ```tsx * // 상세/수정 페이지 * const { * id, mode, isViewMode, isEditMode, * data, setData, isLoading, setIsLoading, * goToList, goToEdit * } = useDetailPageState({ listPath: '/settings/accounts' }); * * // 등록 페이지 * const { mode, isCreateMode, goToList } = useDetailPageState({ * defaultMode: 'create', * listPath: '/settings/accounts' * }); * ``` */ export function useDetailPageState( options: UseDetailPageStateOptions = {} ): UseDetailPageStateReturn { const { defaultMode = 'view', listPath } = options; // ===== 라우터 ===== const router = useRouter(); const params = useParams(); const searchParams = useSearchParams(); // ID 추출 (params.id가 string | string[] | undefined일 수 있음) const id = useMemo(() => { const rawId = params?.id; if (Array.isArray(rawId)) return rawId[0] || null; return rawId || null; }, [params?.id]); // locale 추출 const locale = useMemo(() => { const rawLocale = params?.locale; if (Array.isArray(rawLocale)) return rawLocale[0] || 'ko'; return rawLocale || 'ko'; }, [params?.locale]); // ===== 모드 관리 ===== // URL의 ?mode=edit 파라미터 확인 const urlMode = searchParams?.get('mode'); const initialMode = urlMode === 'edit' ? 'edit' : defaultMode; const [mode, setModeState] = useState(initialMode); const setMode = useCallback((newMode: DetailMode) => { setModeState(newMode); }, []); const isViewMode = mode === 'view'; const isEditMode = mode === 'edit'; const isCreateMode = mode === 'create'; // ===== 데이터 상태 ===== const [data, setData] = useState(null); const [isLoading, setIsLoading] = useState(!isCreateMode); // 등록 모드는 로딩 불필요 const [error, setError] = useState(null); // ===== 네비게이션 ===== const goToList = useCallback(() => { if (listPath) { router.push(`/${locale}${listPath}`); } else { router.back(); } }, [router, locale, listPath]); const goToEdit = useCallback(() => { setModeState('edit'); if (id) { // URL에 mode=edit 추가 (현재 경로 유지) const currentPath = window.location.pathname; router.push(`${currentPath}?mode=edit`); } }, [router, id]); const goToView = useCallback(() => { setModeState('view'); if (id) { // URL에서 mode 파라미터 제거 const currentPath = window.location.pathname; router.push(currentPath); } }, [router, id]); return { // 라우터 정보 id, locale, router, // 모드 관리 mode, setMode, isViewMode, isEditMode, isCreateMode, // 데이터 상태 data, setData, isLoading, setIsLoading, error, setError, // 네비게이션 goToList, goToEdit, goToView, }; }