Files
solution-erp/fe-user/src/App.tsx
pqhuy1987 df12fb19c8
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 2m59s
[CLAUDE] FE-Admin+FE-User: Module Ngân sách (Budget) FE — 3-panel List + Create + Detail tabs + Workflow timeline
Mirror pattern PE 3-panel cho 2 app (admin + user):

- types/budget.ts (BudgetPhase 5-state enum + label/color, BudgetListItem, BudgetDetailRow, BudgetApproval, BudgetWorkflowSummary, BudgetChangelog, BudgetDetailBundle, BudgetDetailBody)
- components/budgets/BudgetDetailTabs.tsx — flat render Section "Thông tin" Header + Section "Hạng mục" table CRUD inline (Add/Edit/Delete dialog với auto-compute ThanhTien = KL × DonGia). Export BudgetApprovalsSection + BudgetHistorySection cho Panel 3 reuse.
- components/budgets/BudgetWorkflowPanel.tsx — Panel 3 timeline activePhases + nextPhases buttons (Approve/Reject color coding) + Dialog xác nhận có comment + sub-section Approvals + Changelog.
- pages/budgets/BudgetsListPage.tsx — 3-panel [340px_1fr_360px] với search + filter Phase + filter NamNganSach. ?phase=Pending alias FE filter 2 phase ChoCCM/ChoCEO. SlaTimer per row + readOnly mode khi pendingMe.
- pages/budgets/BudgetCreatePage.tsx — form Header (TenNganSach/Năm/Dự án/Phòng ban/Mô tả). Edit mode khóa Project+Department.
- App.tsx routes /budgets, /budgets/new, /budgets/:id cả 2 app
- Layout.tsx menu resolver Bg_List → /budgets, Bg_Create → /budgets/new, Bg_Pending → /budgets?phase=Pending. NavLink active dùng queryMatches helper (gotcha #34 — không conflict Bg_List vs Bg_Pending cùng pathname).

TS build: cả fe-admin + fe-user pass clean (1918 + 1901 modules).
BE: dùng 11 endpoint Budgets từ migration 14 (Phase 7 BE đã deploy commit a05c57b).

Tổng FE: +12 file (5 fe-admin + 5 fe-user + 2 mod App/Layout × 2). ~1100 LOC TSX.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:25:22 +07:00

59 lines
2.6 KiB
TypeScript

import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom'
import { Toaster } from 'sonner'
import { AuthProvider } from '@/contexts/AuthContext'
import { ProtectedRoute } from '@/components/ProtectedRoute'
import { Layout } from '@/components/Layout'
import { LoginPage } from '@/pages/LoginPage'
import { UserDashboardPage } from '@/pages/UserDashboardPage'
import { InboxPage } from '@/pages/InboxPage'
import { ContractCreatePage } from '@/pages/contracts/ContractCreatePage'
import { ContractDetailPage } from '@/pages/contracts/ContractDetailPage'
import { MyContractsPage } from '@/pages/contracts/MyContractsPage'
import { PurchaseEvaluationsListPage, PurchaseEvaluationDetailPage } from '@/pages/pe/PurchaseEvaluationsListPage'
import { PurchaseEvaluationCreatePage } from '@/pages/pe/PurchaseEvaluationCreatePage'
import { BudgetsListPage, BudgetDetailPage } from '@/pages/budgets/BudgetsListPage'
import { BudgetCreatePage } from '@/pages/budgets/BudgetCreatePage'
function App() {
return (
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route
element={
<ProtectedRoute>
<Layout />
</ProtectedRoute>
}
>
<Route path="/dashboard" element={<UserDashboardPage />} />
<Route path="/inbox" element={<InboxPage />} />
<Route path="/contracts/new" element={<ContractCreatePage />} />
<Route path="/contracts/:id" element={<ContractDetailPage />} />
<Route path="/my-contracts" element={<MyContractsPage />} />
<Route path="/purchase-evaluations" element={<PurchaseEvaluationsListPage />} />
<Route path="/purchase-evaluations/new" element={<PurchaseEvaluationCreatePage />} />
<Route path="/purchase-evaluations/:id" element={<PurchaseEvaluationDetailPage />} />
<Route path="/budgets" element={<BudgetsListPage />} />
<Route path="/budgets/new" element={<BudgetCreatePage />} />
<Route path="/budgets/:id" element={<BudgetDetailPage />} />
<Route path="/" element={<Navigate to="/dashboard" replace />} />
<Route
path="*"
element={
<div className="p-8 text-slate-500">
Trang này chưa đưc build.
</div>
}
/>
</Route>
</Routes>
<Toaster richColors position="top-right" />
</AuthProvider>
</BrowserRouter>
)
}
export default App