import { BrowserRouter, Routes, Route } from "react-router-dom"; import { cn, getTodayKST, formatFullDate } from "@/utils"; import { useUIStore } from "@/stores"; import { useIsMobile, useCategories, useScheduleData } from "@/hooks"; import { ErrorBoundary, Loading, ToastContainer, ScheduleCard } from "@/components"; /** * 프로미스나인 팬사이트 메인 앱 * * Phase 6: 공통 컴포넌트 완료 * - ErrorBoundary: 에러 경계 * - Loading, FullPageLoading, InlineLoading: 로딩 스피너 * - Toast, ToastContainer: 토스트 알림 * - Lightbox: 이미지 라이트박스 * - ScheduleCard: 스케줄 카드 (list/card/compact) */ function App() { const today = getTodayKST(); const isMobile = useIsMobile(); const { showSuccess, showError } = useUIStore(); // 커스텀 훅 사용 const { data: categories, isLoading: categoriesLoading } = useCategories(); const currentDate = new Date(); const { data: schedules, isLoading: schedulesLoading } = useScheduleData( currentDate.getFullYear(), currentDate.getMonth() + 1 ); return (

fromis_9 Frontend Refactoring

Phase 6 완료 - 공통 컴포넌트

디바이스: {isMobile ? "모바일" : "PC"}

오늘: {formatFullDate(today)}

카테고리 ({categories?.length || 0}개)

{categoriesLoading ? ( ) : (
{categories?.map((c) => ( {c.name} ))}
)}

토스트 테스트

{/* ScheduleCard 컴포넌트 테스트 */} {schedulesLoading ? (
) : schedules?.length > 0 ? ( <> {/* Public Variant (공개 페이지용) */}

variant="public" (공개 페이지용)

{schedules.slice(0, 2).map((schedule) => ( showSuccess(`${schedule.title} 클릭`)} /> ))}
{/* Admin Variant (관리자 페이지용) */}

variant="admin" (관리자 페이지용)

{schedules.slice(0, 2).map((schedule) => ( showSuccess(`${schedule.title} 클릭`)} onEdit={(s) => showSuccess(`${s.title} 수정`)} onDelete={(s) => showError(`${s.title} 삭제`)} /> ))}
) : (

이번 달 스케줄이 없습니다.

)}
{/* 토스트 컨테이너 */} } />
); } export default App;