export type DashboardWidgetSize = 'S' | 'M' | 'L'; export type WidgetDataState = 'loading' | 'success' | 'empty' | 'error' | 'unavailable'; export type WidgetDataResult = { state: WidgetDataState; payload?: T; message?: string; }; export type KpiPayload = { value: string; delta: string; note: string; tone: 'up' | 'down'; icon: 'users' | 'building' | 'trend' | 'card'; }; export type LineChartPayload = { labels: string[]; series: number[]; maxY: number; }; export type BarChartPayload = { labels: string[]; series: number[]; maxY: number; }; export type AdminWidgetPayload = | { kind: 'kpi'; data: KpiPayload } | { kind: 'line_chart'; data: LineChartPayload } | { kind: 'bar_chart'; data: BarChartPayload }; export type DashboardWidgetDefinition = { widgetKey: string; title: string; moduleKey: string; defaultSize: DashboardWidgetSize; defaultVisible: boolean; order: number; dataAdapterKey: string; readiness: 'ready' | 'planned'; description?: string; }; const kpiData: Record = { totalUsers: { value: '12,458', delta: '+12.5%', note: '+1,245 this month', tone: 'up', icon: 'users', }, activeCompanies: { value: '1,234', delta: '+8.2%', note: '+94 this month', tone: 'up', icon: 'building', }, openLeads: { value: '847', delta: '-3.1%', note: '27 fewer than last month', tone: 'down', icon: 'trend', }, creditsPurchased: { value: '₹45,890', delta: '+18.7%', note: '₹7,234 more this month', tone: 'up', icon: 'card', }, }; const lineChartData: LineChartPayload = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [62, 70, 81, 75, 88, 102], maxY: 120, }; const barChartData: BarChartPayload = { labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], series: [42000, 48000, 55000, 51000, 62000, 69000], maxY: 80000, }; const adapterMap: Record Promise>> = { kpi_total_users: async () => ({ state: 'success', payload: { kind: 'kpi', data: kpiData.totalUsers } }), kpi_active_companies: async () => ({ state: 'success', payload: { kind: 'kpi', data: kpiData.activeCompanies } }), kpi_open_leads: async () => ({ state: 'success', payload: { kind: 'kpi', data: kpiData.openLeads } }), kpi_credits_purchased: async () => ({ state: 'success', payload: { kind: 'kpi', data: kpiData.creditsPurchased } }), chart_leads_trend: async () => ({ state: 'success', payload: { kind: 'line_chart', data: lineChartData } }), chart_revenue_overview: async () => ({ state: 'success', payload: { kind: 'bar_chart', data: barChartData } }), }; export const ADMIN_DASHBOARD_WIDGETS: DashboardWidgetDefinition[] = [ { widgetKey: 'kpi_total_users', title: 'Total Users', moduleKey: 'USER_MANAGEMENT', defaultSize: 'S', defaultVisible: true, order: 1, dataAdapterKey: 'kpi_total_users', readiness: 'ready', }, { widgetKey: 'kpi_active_companies', title: 'Active Companies', moduleKey: 'COMPANY_MANAGEMENT', defaultSize: 'S', defaultVisible: true, order: 2, dataAdapterKey: 'kpi_active_companies', readiness: 'ready', }, { widgetKey: 'kpi_open_leads', title: 'Open Leads', moduleKey: 'REQUIREMENTS_MANAGEMENT', defaultSize: 'S', defaultVisible: true, order: 3, dataAdapterKey: 'kpi_open_leads', readiness: 'ready', }, { widgetKey: 'kpi_credits_purchased', title: 'Credits Purchased', moduleKey: 'CREDIT_MANAGEMENT', defaultSize: 'S', defaultVisible: true, order: 4, dataAdapterKey: 'kpi_credits_purchased', readiness: 'ready', }, { widgetKey: 'chart_leads_trend', title: 'Leads Trend', moduleKey: 'REPORTS', defaultSize: 'M', defaultVisible: true, order: 5, dataAdapterKey: 'chart_leads_trend', readiness: 'planned', description: 'Monthly leads performance overview', }, { widgetKey: 'chart_revenue_overview', title: 'Revenue Overview', moduleKey: 'REVENUE_LEDGER', defaultSize: 'M', defaultVisible: true, order: 6, dataAdapterKey: 'chart_revenue_overview', readiness: 'planned', description: 'Monthly revenue vs expenses comparison', }, ]; export function loadWidgetData(definition: DashboardWidgetDefinition): Promise> { if (definition.readiness !== 'ready') { return Promise.resolve({ state: 'unavailable', message: 'This widget will switch to module-backed data when that module is completed.', }); } const loader = adapterMap[definition.dataAdapterKey]; if (!loader) { return Promise.resolve({ state: 'error', message: `Missing data adapter: ${definition.dataAdapterKey}`, }); } return loader().catch(() => ({ state: 'error', message: 'Failed to load widget data.', })); }