84 lines
3.0 KiB
TypeScript
84 lines
3.0 KiB
TypeScript
// The four operational worklist screens. Each lists the leads at the lifecycle
|
|
// states it owns; every row carries its one primary action (+ Disqualify),
|
|
// launched in a modal. Each screen shows a few compact stat tiles over its rows.
|
|
// (The Lead Pipeline screen is the read-only all-leads dashboard.)
|
|
|
|
import { Worklist, type TileSpec } from '../components/activities';
|
|
import { formatINR } from '../components';
|
|
import type { LeadRecord } from '../api/types';
|
|
|
|
const count = (rows: LeadRecord[]) => String(rows.length);
|
|
const countWhere = (pred: (r: LeadRecord) => boolean) => (rows: LeadRecord[]) => String(rows.filter(pred).length);
|
|
const sumINR = (col: keyof LeadRecord) => (rows: LeadRecord[]) =>
|
|
`₹${formatINR(rows.reduce((s, r) => s + (Number(r[col]) || 0), 0))}`;
|
|
const avg = (col: keyof LeadRecord) => (rows: LeadRecord[]) => {
|
|
const vals = rows.map((r) => Number(r[col])).filter((n) => !Number.isNaN(n));
|
|
return vals.length ? String(Math.round(vals.reduce((a, b) => a + b, 0) / vals.length)) : '—';
|
|
};
|
|
|
|
/** Qualify (New Lead) + Assign (Qualified). */
|
|
const QUALIFY_TILES: TileSpec[] = [
|
|
{ label: 'In queue', value: count },
|
|
{ label: 'Avg lead score', value: avg('lead_score') },
|
|
];
|
|
|
|
export function QualificationScreen() {
|
|
return (
|
|
<Worklist
|
|
states={['New Lead', 'Qualified']}
|
|
tiles={QUALIFY_TILES}
|
|
emptyHint="No new or qualified leads in the queue."
|
|
/>
|
|
);
|
|
}
|
|
|
|
/** Log Contact (Assigned) · Schedule (Contacted) · Recommend (Meeting Scheduled). */
|
|
const ENGAGE_TILES: TileSpec[] = [
|
|
{ label: 'In queue', value: count },
|
|
{ label: 'Meetings booked', value: countWhere((r) => !!r.meeting_mode) },
|
|
{ label: 'Total premium', value: sumINR('premium_amount') },
|
|
];
|
|
|
|
export function InteractionScreen() {
|
|
return (
|
|
<Worklist
|
|
states={['Assigned', 'Contacted', 'Meeting Scheduled']}
|
|
tiles={ENGAGE_TILES}
|
|
emptyHint="No leads awaiting contact, scheduling, or a recommendation."
|
|
/>
|
|
);
|
|
}
|
|
|
|
/** Collect Documents (Product Recommended) · Assess Eligibility (Documents Collected). */
|
|
const DOCS_TILES: TileSpec[] = [
|
|
{ label: 'In queue', value: count },
|
|
{ label: 'Docs collected', value: countWhere((r) => r.current_state_name === 'Documents Collected') },
|
|
];
|
|
|
|
export function DocAssessmentScreen() {
|
|
return (
|
|
<Worklist
|
|
states={['Product Recommended', 'Documents Collected']}
|
|
tiles={DOCS_TILES}
|
|
emptyHint="No leads awaiting document collection or assessment."
|
|
/>
|
|
);
|
|
}
|
|
|
|
/** Underwrite (Eligibility Assessed) · Issue (Underwriting) · Onboard (Policy Issued). */
|
|
const UW_TILES: TileSpec[] = [
|
|
{ label: 'In queue', value: count },
|
|
{ label: 'Policies issued', value: countWhere((r) => r.current_state_name === 'Policy Issued') },
|
|
{ label: 'Total premium', value: sumINR('premium_amount') },
|
|
];
|
|
|
|
export function UnderwritingPolicyScreen() {
|
|
return (
|
|
<Worklist
|
|
states={['Eligibility Assessed', 'Underwriting', 'Policy Issued']}
|
|
tiles={UW_TILES}
|
|
emptyHint="No leads in underwriting, issuance, or onboarding."
|
|
/>
|
|
);
|
|
}
|