SPMS_WEB/react/src/routes/index.tsx
SEAN af6ecab428 feat: 가이드라인 기반 공통 컴포넌트 및 레이아웃 개선
- 공통 컴포넌트 11개 생성 (PageHeader, StatusBadge, CategoryBadge, FilterDropdown, DateRangeInput, SearchInput, FilterResetButton, Pagination, EmptyState, CopyButton, PlatformBadge)
- AppHeader: 다단계 breadcrumb, 알림 드롭다운 구현
- AppLayout: 푸터 개인정보처리방침/이용약관 모달 추가
- AppSidebar: 이메일 폰트 자동 축소 (clamp)
- SignupPage: 모달 닫기 버튼 x 아이콘으로 통일
- Suspense fallback SVG 스피너로 변경

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 09:27:21 +09:00

119 lines
5.0 KiB
TypeScript

import { createBrowserRouter } from "react-router-dom";
import { lazy, Suspense, type ComponentType } from "react";
import { Navigate } from "react-router-dom";
import AppLayout from "@/components/layout/AppLayout";
import AuthLayout from "@/components/layout/AuthLayout";
import ProtectedRoute from "./ProtectedRoute";
import PublicRoute from "./PublicRoute";
import { useAuthStore } from "@/stores/authStore";
/** lazy import 래퍼 */
function lazyPage(importFn: () => Promise<{ default: ComponentType }>) {
const LazyComponent = lazy(importFn);
return (
<Suspense fallback={
<div className="flex h-full flex-col items-center justify-center gap-3">
<svg className="size-9 animate-spin text-primary" viewBox="0 0 24 24" fill="none">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
<span className="text-sm text-gray-400">Loading...</span>
</div>
}>
<LazyComponent />
</Suspense>
);
}
/* Auth 페이지 */
const LoginPage = () => lazyPage(() => import("@/features/auth/pages/LoginPage"));
const SignupPage = () => lazyPage(() => import("@/features/auth/pages/SignupPage"));
const VerifyEmailPage = () => lazyPage(() => import("@/features/auth/pages/VerifyEmailPage"));
/* Dashboard 페이지 */
const HomePage = () => lazyPage(() => import("@/features/dashboard/pages/HomePage"));
const DashboardPage = () => lazyPage(() => import("@/features/dashboard/pages/DashboardPage"));
/* Service 페이지 */
const ServiceListPage = () => lazyPage(() => import("@/features/service/pages/ServiceListPage"));
const ServiceRegisterPage = () => lazyPage(() => import("@/features/service/pages/ServiceRegisterPage"));
const ServiceDetailPage = () => lazyPage(() => import("@/features/service/pages/ServiceDetailPage"));
const ServiceEditPage = () => lazyPage(() => import("@/features/service/pages/ServiceEditPage"));
/* Message 페이지 */
const MessageListPage = () => lazyPage(() => import("@/features/message/pages/MessageListPage"));
const MessageRegisterPage = () => lazyPage(() => import("@/features/message/pages/MessageRegisterPage"));
/* Statistics 페이지 */
const StatisticsPage = () => lazyPage(() => import("@/features/statistics/pages/StatisticsPage"));
const StatisticsHistoryPage = () => lazyPage(() => import("@/features/statistics/pages/StatisticsHistoryPage"));
/* Device 페이지 */
const DeviceListPage = () => lazyPage(() => import("@/features/device/pages/DeviceListPage"));
/* Tag 페이지 */
const TagManagePage = () => lazyPage(() => import("@/features/tag/pages/TagManagePage"));
/* Settings 페이지 */
const MyPage = () => lazyPage(() => import("@/features/settings/pages/MyPage"));
const ProfileEditPage = () => lazyPage(() => import("@/features/settings/pages/ProfileEditPage"));
const NotificationsPage = () => lazyPage(() => import("@/features/settings/pages/NotificationsPage"));
/** 이메일 인증 페이지 가드: 인증 완료 상태면 홈으로 */
function VerifyEmailGuard() {
const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
if (isAuthenticated) {
return <Navigate to="/" replace />;
}
return <VerifyEmailPage />;
}
export const router = createBrowserRouter([
{
/* 공개 라우트 (인증 불필요) */
element: <PublicRoute />,
children: [
{
element: <AuthLayout />,
children: [
{ path: "/login", element: <LoginPage /> },
{ path: "/signup", element: <SignupPage /> },
],
},
],
},
{
/* 이메일 인증 (로그인 후, 인증 전 — 인증 완료 시 홈으로) */
element: <AuthLayout />,
children: [
{ path: "/verify-email", Component: VerifyEmailGuard },
],
},
{
/* 보호된 라우트 (인증 필요) */
element: <ProtectedRoute />,
children: [
{
element: <AppLayout />,
children: [
{ path: "/", element: <HomePage /> },
{ path: "/dashboard", element: <DashboardPage /> },
{ path: "/services", element: <ServiceListPage /> },
{ path: "/services/register", element: <ServiceRegisterPage /> },
{ path: "/services/:id", element: <ServiceDetailPage /> },
{ path: "/services/:id/edit", element: <ServiceEditPage /> },
{ path: "/messages", element: <MessageListPage /> },
{ path: "/messages/register", element: <MessageRegisterPage /> },
{ path: "/statistics", element: <StatisticsPage /> },
{ path: "/statistics/history", element: <StatisticsHistoryPage /> },
{ path: "/devices", element: <DeviceListPage /> },
{ path: "/tags", element: <TagManagePage /> },
{ path: "/settings", element: <MyPage /> },
{ path: "/settings/profile", element: <ProfileEditPage /> },
{ path: "/settings/notifications", element: <NotificationsPage /> },
],
},
],
},
]);