185 lines
4.8 KiB
TypeScript
185 lines
4.8 KiB
TypeScript
export type DashboardWidgetSize = 'S' | 'M' | 'L';
|
|
|
|
export type WidgetDataState = 'loading' | 'success' | 'empty' | 'error' | 'unavailable';
|
|
|
|
export type WidgetDataResult<T = unknown> = {
|
|
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<string, KpiPayload> = {
|
|
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<string, () => Promise<WidgetDataResult<AdminWidgetPayload>>> = {
|
|
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<WidgetDataResult<AdminWidgetPayload>> {
|
|
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.',
|
|
}));
|
|
}
|