175 lines
5.1 KiB
TypeScript
175 lines
5.1 KiB
TypeScript
// Activity metadata + the per-state "next action" map. Field schemas are no
|
|
// longer mirrored here — <ActivityForm> fetches them live from the form-screens
|
|
// endpoint (see api/schema.ts), so the form layout never drifts from config.
|
|
|
|
export type FieldType =
|
|
| 'text'
|
|
| 'email'
|
|
| 'phone'
|
|
| 'number'
|
|
| 'date'
|
|
| 'datetime'
|
|
| 'longtext'
|
|
| 'select'
|
|
| 'multiselect'
|
|
| 'boolean'
|
|
| 'lookup'
|
|
| 'ocr'
|
|
| 'file';
|
|
|
|
export interface FieldOption {
|
|
value: string;
|
|
label: string;
|
|
}
|
|
|
|
export interface OcrMapping {
|
|
extraction_key: string;
|
|
target_field: string;
|
|
}
|
|
|
|
/** A renderable form field. Built at runtime by api/schema.ts from the live
|
|
* form-screens config; consumed by <ActivityForm> and the bespoke screens. */
|
|
export interface FieldDef {
|
|
id: string;
|
|
label: string;
|
|
type: FieldType;
|
|
required?: boolean;
|
|
options?: FieldOption[];
|
|
prefix?: string;
|
|
placeholder?: string;
|
|
/** Companion/record key to seed from (defaults to id minus the _input suffix). */
|
|
seedKey?: string;
|
|
// lookup
|
|
lookupTemplate?: string;
|
|
lookupDisplay?: string[]; // columns shown in the label
|
|
lookupStorage?: string[]; // columns persisted on submit
|
|
// ocr
|
|
docLabel?: string; // "PAN" / "Aadhaar"
|
|
ocrMappings?: OcrMapping[];
|
|
}
|
|
|
|
/** Activity display copy + uid. Fields come from the schema, not from here. */
|
|
export interface ActivityMeta {
|
|
uid: string;
|
|
name: string;
|
|
submitLabel: string;
|
|
/** Past-tense confirmation, e.g. "advanced to Qualified". */
|
|
done: string;
|
|
}
|
|
|
|
// Activity keys are stable, human-readable handles used by STATE_NEXT.
|
|
export const ACTIVITY_META = {
|
|
capture: {
|
|
uid: 'cc1a73d5-61e1-4416-af30-2b1eeb623a58',
|
|
name: 'Capture Lead',
|
|
submitLabel: 'Create lead',
|
|
done: 'created — added to the pipeline as a New Lead',
|
|
},
|
|
qualify: {
|
|
uid: '6b741e44-37f2-4bb0-90ab-ed139f03b7b3',
|
|
name: 'Qualify Lead',
|
|
submitLabel: 'Qualify lead',
|
|
done: 'advanced to Qualified',
|
|
},
|
|
assign: {
|
|
uid: 'da61aaa1-003b-4601-9f42-f93ff230497f',
|
|
name: 'Assign Lead',
|
|
submitLabel: 'Assign lead',
|
|
done: 'advanced to Assigned',
|
|
},
|
|
contact: {
|
|
uid: 'fea6b3a8-846d-4f6f-8e92-033c4cf4b6e2',
|
|
name: 'Log First Contact',
|
|
submitLabel: 'Log contact',
|
|
done: 'advanced to Contacted',
|
|
},
|
|
schedule: {
|
|
uid: 'c444d32f-ed6a-4e36-b8b7-b82e73a141d4',
|
|
name: 'Schedule Meeting',
|
|
submitLabel: 'Schedule meeting',
|
|
done: 'advanced to Meeting Scheduled',
|
|
},
|
|
assess: {
|
|
uid: 'ba3d3e7f-0d3f-49f2-a156-6cace33c228a',
|
|
name: 'Assess Eligibility',
|
|
submitLabel: 'Submit assessment',
|
|
done: 'advanced to Eligibility Assessed',
|
|
},
|
|
underwrite: {
|
|
uid: 'ed8ec0dc-4c2c-4d9e-b798-757f6a9d4730',
|
|
name: 'Submit Underwriting',
|
|
submitLabel: 'Submit underwriting',
|
|
done: 'advanced to Underwriting',
|
|
},
|
|
issue: {
|
|
uid: '7b8fb734-a780-4c6a-837b-c5e7ca28e489',
|
|
name: 'Issue Policy',
|
|
submitLabel: 'Issue policy',
|
|
done: 'advanced to Policy Issued',
|
|
},
|
|
onboard: {
|
|
uid: 'ae415f4e-a33e-432e-882f-733238de8bcc',
|
|
name: 'Onboard Customer',
|
|
submitLabel: 'Complete onboarding',
|
|
done: 'advanced to Customer 360',
|
|
},
|
|
disqualify: {
|
|
uid: 'ea99fc60-caba-45c1-afc1-7386a2fa9220',
|
|
name: 'Disqualify',
|
|
submitLabel: 'Disqualify lead',
|
|
done: 'moved to Disqualified',
|
|
},
|
|
} satisfies Record<string, ActivityMeta>;
|
|
|
|
export type ActivityKey = keyof typeof ACTIVITY_META;
|
|
|
|
// OCR field configs for Collect Documents (extraction → mapped target inputs).
|
|
export const OCR_FIELDS: Record<string, { id: string; docLabel: string; mappings: OcrMapping[] }> = {
|
|
pan: {
|
|
id: 'pan_ocr_2',
|
|
docLabel: 'PAN',
|
|
mappings: [{ extraction_key: 'pan_number', target_field: 'pan_number_input' }],
|
|
},
|
|
aadhaar: {
|
|
id: 'aadhar_ocr_2',
|
|
docLabel: 'Aadhaar',
|
|
mappings: [{ extraction_key: 'aadhaar_number', target_field: 'aadhaar_number_input' }],
|
|
},
|
|
};
|
|
|
|
// Per-state next action. `route` → dedicated rich screen; else inline form.
|
|
// Routed steps (recommend / documents / underwriting / issue) render their own
|
|
// screen, so `activity` is only set when the step renders an inline form.
|
|
export interface NextAction {
|
|
activity?: ActivityKey;
|
|
route?: string;
|
|
/** Button label for routed steps. */
|
|
label?: string;
|
|
}
|
|
|
|
export const STATE_NEXT: Record<string, NextAction> = {
|
|
'New Lead': { activity: 'qualify' },
|
|
Qualified: { activity: 'assign', route: '/assign', label: 'Assign lead' },
|
|
Assigned: { activity: 'contact' },
|
|
Contacted: { activity: 'schedule' },
|
|
'Meeting Scheduled': { route: '/recommend', label: 'Recommend product' },
|
|
'Product Recommended': { route: '/documents', label: 'Collect documents' },
|
|
'Documents Collected': { activity: 'assess' },
|
|
'Eligibility Assessed': { route: '/underwriting', label: 'Submit underwriting' },
|
|
Underwriting: { route: '/issue', label: 'Issue policy' },
|
|
'Policy Issued': { activity: 'onboard' },
|
|
};
|
|
|
|
// States from which Disqualify is a valid (secondary) action.
|
|
export const DISQUALIFY_STATES = new Set([
|
|
'New Lead',
|
|
'Qualified',
|
|
'Assigned',
|
|
'Contacted',
|
|
'Meeting Scheduled',
|
|
'Product Recommended',
|
|
'Documents Collected',
|
|
'Eligibility Assessed',
|
|
'Underwriting',
|
|
]);
|