spin-frontend/src/App.tsx
theorose49 65bcb69374
All checks were successful
build-and-push / build (push) Successful in 31s
feat: 메일함·프로필 사진·근무상태 드롭다운·접이식 사이드바 + #03143F 팔레트 + 인센티브 게이지
- 브랜드 포인트컬러 #03143F로 팔레트 전면 재설정, 회사 로고 흰 wrap 제거+크롭, 로고 블렌딩
- 사이드바 접기/펼치기(localStorage), 로고 아래 근무상태 드롭다운(출근/퇴근/휴식/미팅/이동)
- 대시보드 역할 무관 동일(회계/전사 위젯 제거)
- 유저 근무화면 단순화(남은연차 소수점·기록·휴가/공가만), 관리자 근무관리(/admin/attendance)
- 프로젝트: 관리자 전용 관리창(/admin/projects), 나의 업무는 본인 참여분 read-only
- 메일함(/inbox)+탑바 벨(미확인), 프로필(부서·연락처·사진 업로드)
- 인센티브 유저: BE/non-BE·환율 숨김, 할당량 세그먼트 게이지(지급완료→반영완료→반영중→예정, 할당량 화살표)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 09:38:51 +09:00

65 lines
2.8 KiB
TypeScript

import { Routes, Route, Navigate } from "react-router-dom";
import { AuthProvider, useAuth } from "@/context/Auth";
import { AppShell } from "@/components/AppShell";
import { LoadingState } from "@/components/ui";
import { DashboardPage } from "@/pages/Dashboard";
import { AttendancePage } from "@/pages/Attendance";
import { ProjectsPage } from "@/pages/Projects";
import { ProjectDetailPage } from "@/pages/ProjectDetail";
import { IncentivePage } from "@/pages/Incentive";
import { ProfilePage } from "@/pages/Profile";
import { InboxPage } from "@/pages/Inbox";
import { ApprovalsPage } from "@/pages/admin/Approvals";
import { AttendanceAdminPage } from "@/pages/admin/AttendanceAdmin";
import { ProjectsAdminPage } from "@/pages/admin/ProjectsAdmin";
import { IncentiveAdminPage } from "@/pages/admin/IncentiveAdmin";
import { AccountingPage } from "@/pages/admin/Accounting";
import { MembersPage } from "@/pages/admin/Members";
import { SettingsPage } from "@/pages/admin/Settings";
function RequireAdmin({ children }: { children: JSX.Element }) {
const { isAdmin, loading } = useAuth();
if (loading) return <LoadingState />;
return isAdmin ? children : <Navigate to="/" replace />;
}
function Shell() {
const { loading } = useAuth();
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-canvas">
<LoadingState label="spin 로딩 중…" />
</div>
);
}
return (
<Routes>
<Route element={<AppShell />}>
<Route path="/" element={<DashboardPage />} />
<Route path="/attendance" element={<AttendancePage />} />
<Route path="/projects" element={<ProjectsPage />} />
<Route path="/projects/:id" element={<ProjectDetailPage />} />
<Route path="/incentive" element={<IncentivePage />} />
<Route path="/profile" element={<ProfilePage />} />
<Route path="/inbox" element={<InboxPage />} />
<Route path="/admin/approvals" element={<RequireAdmin><ApprovalsPage /></RequireAdmin>} />
<Route path="/admin/attendance" element={<RequireAdmin><AttendanceAdminPage /></RequireAdmin>} />
<Route path="/admin/projects" element={<RequireAdmin><ProjectsAdminPage /></RequireAdmin>} />
<Route path="/admin/incentive" element={<RequireAdmin><IncentiveAdminPage /></RequireAdmin>} />
<Route path="/admin/accounting" element={<RequireAdmin><AccountingPage /></RequireAdmin>} />
<Route path="/admin/members" element={<RequireAdmin><MembersPage /></RequireAdmin>} />
<Route path="/admin/settings" element={<RequireAdmin><SettingsPage /></RequireAdmin>} />
<Route path="*" element={<Navigate to="/" replace />} />
</Route>
</Routes>
);
}
export default function App() {
return (
<AuthProvider>
<Shell />
</AuthProvider>
);
}