92 lines
4.6 KiB
Markdown
92 lines
4.6 KiB
Markdown
# Changelog — 2026-07-04 (Phase 1 frontend)
|
||
|
||
## feat(frontend): HR & Finance Phase 1 surfaces — frontend
|
||
|
||
Branch: `feature/hr-finance-phase-1-frontend` (off `dev`).
|
||
Depends on: `feature/hr-finance-phase-1` backend endpoints (B1–B8).
|
||
|
||
### What ships
|
||
|
||
Six user-facing pages consuming the Phase 1 backend, plus merged stores
|
||
preserving Phase 0 state shape so HRManagement.tsx and FinanceManagement
|
||
consumers keep working.
|
||
|
||
| Path | Roles | Backend endpoint(s) consumed |
|
||
|---|---|---|
|
||
| `/dashboard/hr` | school_admin, systems_admin, principal, hr, bursar, accountant | `GET /api/hr/dashboard/summary` |
|
||
| `/dashboard/finance` | school_admin, systems_admin, principal, bursar, accountant | `GET /api/finance/dashboard/summary` |
|
||
| `/finance/expenses` | school_admin, systems_admin, principal, bursar, accountant | `GET /api/finance/expenses?status=&category=&date_from=&date_to=` |
|
||
| `/finance/expenses/new` | as above | `POST /api/finance/expenses` |
|
||
| `/finance/expenses/:id/edit` | as above | `PATCH /api/finance/expenses/:id` (see deviation #1) |
|
||
| `/hr/payslips/:id` | school_admin, systems_admin, principal, hr, bursar, accountant | `GET /api/hr/payslips/:id` |
|
||
|
||
### Stores
|
||
|
||
- `client/src/store/hr.ts` — extended to also expose `fetchDashboardSummary`,
|
||
`fetchPayslip(id)`, and `resetPayslip`. New `currentPayslip` and
|
||
`dashboardSummary` state slots. Legacy Phase 0 records / leaveRequests /
|
||
payrollRuns / payslips / vacancies / applicants / metadata / staff_records
|
||
management endpoints + their methods are preserved verbatim.
|
||
- `client/src/store/finance.ts` — extended with `fetchDashboardSummary`,
|
||
`fetchCategories`, `fetchExpenses`, `fetchExpense` (see deviation #1),
|
||
`createExpense`, `updateExpense`, `deleteExpense`. Phase 0 payroll proxy
|
||
actions kept intact for the existing Finance payroll UX.
|
||
|
||
### Routing / Nav
|
||
|
||
- New routes wired into App.tsx's role-aware `getRoutes()` switch arms for
|
||
`school_admin`, `systems_admin`, `principal`, `hr`, `bursar`.
|
||
- Nav.tsx `NAV_CONFIG` blocks for those five roles gain dashboard and
|
||
expenses entries using `lucide-react` icons (`LayoutDashboard`, `Receipt`,
|
||
`Plus`).
|
||
- Role gating is in App.tsx via `<ProtectedRoute>` — no in-component
|
||
role checks.
|
||
|
||
### Deviations from the dispatch
|
||
|
||
1. **`PATCH` instead of `PUT` for expense updates.** The Phase 1 backend
|
||
exposes `PATCH /api/finance/expenses/:id`, not `PUT`. Store and form both
|
||
use `api.patch(...)`.
|
||
2. **`GET /api/finance/expenses/:id` does not exist on the backend.**
|
||
The edit page prefills by fetching the list endpoint with `limit=500`
|
||
and matching by id. Caches the row for subsequent visits.
|
||
See `client/src/store/finance.ts` `fetchExpense` for the rationale.
|
||
3. **`FinanceDashboard` uses `/api/finance/dashboard/summary` directly.**
|
||
The dispatch says the backend doesn't expose this endpoint yet and
|
||
suggests falling back to `/api/dashboard/stats`; however the Phase 1
|
||
branch already shipped that endpoint. We consume it directly. A monthly
|
||
time-series endpoint remains a TODO for Phase 2 — the current chart
|
||
synthesises a 2-point series from MTD totals.
|
||
4. **`PayslipDetail` uses `/api/hr/payslips/:id` directly.** Same as above;
|
||
the Phase 1 branch already exposed it.
|
||
|
||
### Files added (8)
|
||
|
||
- `client/src/store/hr.ts` (modified, +139 lines)
|
||
- `client/src/store/finance.ts` (modified, +282 lines)
|
||
- `client/src/App.tsx` (modified, +42 lines)
|
||
- `client/src/components/Nav.tsx` (modified, +13 lines)
|
||
- `client/src/pages/dashboard/HRDashboard.tsx` (new)
|
||
- `client/src/pages/dashboard/FinanceDashboard.tsx` (new)
|
||
- `client/src/pages/finance/Expenses.tsx` (new)
|
||
- `client/src/pages/finance/ExpenseNew.tsx` (new)
|
||
- `client/src/pages/finance/ExpenseEdit.tsx` (new)
|
||
- `client/src/pages/hr/PayslipView.tsx` (new)
|
||
|
||
### Acceptance check
|
||
|
||
- ✅ `npm run build` succeeds — `✓ built in 13.48s`, no TS errors.
|
||
- ✅ Phase 1 backend (`:3001/api/hr/dashboard/summary`) returns the four-tile
|
||
aggregate for admin token.
|
||
- ✅ `/api/finance/dashboard/summary` returns collected_mtd / outstanding_fees /
|
||
payroll_last_run / expenses_mtd / pending_expenses.
|
||
- ✅ `/api/finance/expenses` GET returns `{ expenses, pagination }`.
|
||
- ✅ POST → PATCH → DELETE round-trip on `/api/finance/expenses` works (smoke
|
||
test created expense #7, patched to 99.99, deleted).
|
||
- ✅ RBAC denial — student@school.com token gets `403 HR, Finance, Principal
|
||
or Admin access required` on `/api/hr/dashboard/summary`, and
|
||
`403 Finance, Bursar, Accountant, HR, Principal or Admin access required`
|
||
on `/api/finance/expenses`.
|
||
- ✅ Print stylesheet wired into `PayslipView.tsx` (`@media print` block
|
||
scopes the visible content to `#payslip` only).
|