feat: implement Story 2.1 — Owner/Manager Command Center Dashboard

- Rewrite DashboardController with cached role-scoped KPI aggregation
  (Cache::remember, 5-min TTL, Declaration::forUser scope)
- Create StatCard.vue component with CVA status variants and a11y
- Rewrite Dashboard.vue with 4-column KPI grid + urgent declarations table
- Add mise_en_demeure status to DeclarationStatus enum with transitions
- Exclude termine, mise_en_demeure, ferme from dashboard queries
- Set deadline proximity red threshold to ≤5 days
- Add abort(404) for non-member workspace access per architecture
- Fix null-safe client access for soft-deleted clients
- Fix hardcoded routes with Wayfinder type-safe imports
- Fix DashboardProps.stats type to allow null
- Add aria-pressed to StatCard for accessibility
- Install shadcn-vue table component (11 files)
- Add 11 Pest feature tests + 3 mise_en_demeure transition tests
- Fix DeclarationFactory eager workspace creation causing slug collisions
- 196 tests pass, 836 assertions, zero regressions
This commit is contained in:
2026-03-20 12:00:24 +00:00
parent e53b013359
commit a2ab6f365d
23 changed files with 1283 additions and 523 deletions

View File

@@ -0,0 +1,36 @@
export type DashboardStats = {
overdue: number;
dueThisWeek: number;
enAttenteClient: number;
enCours: number;
};
export type DashboardDeclaration = {
id: number;
title: string;
type: string;
typeLabel: string;
clientName: string;
assigneeName: string | null;
status: string;
statusLabel: string;
dueDate: string | null;
showUrl: string;
};
export type StatCardLink = {
label: string;
count: number;
status: 'danger' | 'warning' | 'info' | 'success';
href: string;
};
export type DashboardProps = {
stats: DashboardStats | null;
statCards: StatCardLink[];
declarations: DashboardDeclaration[];
workspaceName: string | null;
roleLabel: string | null;
declarationsUrl: string | null;
clientsUrl: string | null;
};

View File

@@ -1,4 +1,5 @@
export * from './auth';
export * from './dashboard';
export * from './navigation';
export * from './team';
export * from './ui';