Skip to content

Dashboard

The operational landing screen for authenticated staff — KPIs, financial summary, quick actions, pending approvals, active groups, inventory utilisation, and an inline general-ledger search.

Page

  • src/pages/Dashboard.tsx — mounted at /app.

Route (src/App.tsx:149):

<Route path="/app"
  element={<ProtectedRoute allowedRoles={['admin', 'staff']}>
    <Dashboard />
  </ProtectedRoute>} />

Permission drift

The route uses allowedRoles=['admin','staff'] instead of requiredPermissions={['dashboard.view']}. dashboard.view is seeded (migration 20260416030000) but not yet enforced by the route. Tracked as drift item #2 in docs/PERMISSIONS.md §8.

Widgets (top to bottom)

Primary KPI row

Four KPICard tiles (Dashboard.tsx:339):

Tile Source Drills into
Total Bookings Count of bookings /sales/bookings
Pending Approvals Bookings where opsApprovalStatus === 'pending' /approvals
Active Groups Groups where status in ('open','planning') /groups
Total Revenue Sum of verified/refunded payment amounts + outstanding balance subtitle /finance

Financial summary row (when available)

Four more tiles (Dashboard.tsx:372) pulled from journal lines + accounts:

Tile Source
Monthly Revenue Sum (credit − debit) of this-month INCOME journal lines
Monthly Expenses Sum (debit − credit) of this-month EXPENSE lines
Net Profit Monthly Revenue − Monthly Expenses
Outstanding Receivables Σ balanceAmount across all bookings

Requires GET /finance/journals/lines?limit=5000 and GET /finance/accounts; silently hidden if the requests fail.

FinanceHeadlineRow

src/components/dashboard/FinanceHeadlineRow.tsx — additional finance headlines (today's vs yesterday's cash-in / cash-out etc.). Gracefully hides when the underlying RPC is unavailable.

Quick Actions grid

Nine action tiles (Dashboard.tsx:410). The first four open in-place dialogs; the rest are links:

Tile Target Dialog / Route
Add Account dialog POST /finance/accounts
Add Customer dialog CustomerFormDialog (customers.create)
Record Payment dialog POST /finance/payments (finance.create)
Journal Entry dialog POST /finance/journals — quick 2-line Dr/Cr (finance.create)
Bookings link /sales/bookings
Vouchers link /finance?tab=vouchers
Accounts link /finance?tab=accounts
Groups link /groups
Reports link /finance?tab=reports

A typeahead over GL accounts that opens a full account ledger dialog (date, voucher no., memo, debit, credit, running balance, closing totals). Pulls GET /finance/journals and flattens the line array per account. Display names for AGR- / AGP- / CUS- / SUP- accounts strip the "Receivable — " / "Payable — " prefix (getDisplayName, Dashboard.tsx:256).

Tickets-due-soon banner

Conditional amber banner if any tickets fall within 2 days of their nameUpdateDeadline and aren't yet issued. Links to /tickets.

Pending approvals + recent activity

  • Pending Operations Approval — first 5 rows from bookings.filter(b => b.opsApprovalStatus === 'pending'). Click-through to /approvals.
  • Recent Activity — 5 latest audit log rows rendered as a Timeline.

Active travel groups

Capacity/progress tiles for any group where status !== 'completed'. Shows booked / total capacity and departure date.

Inventory utilisation

Three progress-bar lists from GET /inventory/utilization:

  • Airline Seats
  • Hotel Rooms
  • Food / Meals

Gracefully hides when the endpoint is unavailable.

Quick stats row

Three small cards: Visas in Pipeline, Tickets Due Soon, Departures This Month.

Role-specific variants

There is one dashboard implementation served to all staff roles; differentiation is by permission-filtered nav, not by rendering different tiles.

  • Agent portal dashboard lives at /partner (src/pages/partner/AgentPortal.tsx) and is a separate component.
  • Customer portal dashboard lives at /customer (src/pages/customer/CustomerPortal.tsx).

Data sources

Source Fetcher
Bookings fetchBookings()src/services/bookingService.ts
Payments fetchPayments()
Groups fetchGroups()
Visa cases fetchVisaCases()
Ticket records fetchTicketRecords()
Audit logs fetchAuditLogs()
Inventory utilisation GET /inventory/utilization
Journal lines GET /finance/journals/lines?limit=5000
Accounts GET /finance/accounts
Finance journals (ledger drill-in) GET /finance/journals

Permissions

Action Permission Enforcement
View /app dashboard.view (seeded) / allowedRoles=['admin','staff'] (actual) Route guard — see drift note above
Quick-add account finance.create Server
Quick-add customer customers.create Server
Quick-record payment finance.create Server
Quick journal entry finance.create Server
Open ledger finance.view Server
  • Approvals queue → docs/features/approvals.md.
  • Finance module (all finance tiles link here) → docs/features/finance/index.md.
  • Tickets name-update deadline rule → docs/features/tickets.md.