diff --git a/src/components/insurance/AIDecisionStream.tsx b/src/components/insurance/AIDecisionStream.tsx index b4a2dba..f4720a8 100644 --- a/src/components/insurance/AIDecisionStream.tsx +++ b/src/components/insurance/AIDecisionStream.tsx @@ -28,8 +28,8 @@ export function AIDecisionStream({ threshold = 0.7, className, }: AIDecisionStreamProps) { - // Single-open accordion; newest (index 0) open by default. - const [openIdx, setOpenIdx] = useState(0); + // Single-open accordion; all collapsed by default (-1 = none open). + const [openIdx, setOpenIdx] = useState(-1); const escalations = decisions.filter((d) => d.confidence < threshold); return ( diff --git a/src/screens/Lead360Screen.tsx b/src/screens/Lead360Screen.tsx index 9806626..3de3021 100644 --- a/src/screens/Lead360Screen.tsx +++ b/src/screens/Lead360Screen.tsx @@ -1,77 +1,24 @@ -import { useMemo, useState } from 'react'; +import { useMemo } from 'react'; import type { ReactNode } from 'react'; -import { useNavigate, useParams } from 'react-router-dom'; +import { useParams } from 'react-router-dom'; import { Ban, CheckCircle2, CircleDashed, Download } from 'lucide-react'; import { AIDecisionStream, Avatar, Badge, - Button, Card, ChannelBadge, formatINR, - RupeeAmount, SegmentBadge, TimelineEntry, WorkflowStepper, } from '../components'; -import { ActivityForm } from '../components/form'; +import { LeadActions, STEP_BY_STATE } from '../components/activities'; import { useQuery, useZino } from '../api/provider'; import { useLeads } from '../api/leads'; import { recordToLead, decisionToCard, auditToTimeline } from '../api/adapters'; import { STAGES, ONBOARD_ACTIVITY_UID } from '../api/config'; -import { ACTIVITY_META, DISQUALIFY_STATES, STATE_NEXT } from '../api/forms'; -import type { LeadRecord } from '../api/types'; - -/** Contextual next-step action for a lead, driven by its current state. - * Routed steps (Assign / Recommend / Documents) deep-link to their rich - * screens; everything else renders its activity form inline. Disqualify is a - * secondary action wherever it's valid. */ -function NextActionPanel({ record, onAdvanced }: { record: LeadRecord; onAdvanced: () => void }) { - const navigate = useNavigate(); - const [showDisqualify, setShowDisqualify] = useState(false); - const state = record.current_state_name ?? ''; - const next = STATE_NEXT[state]; - const inlineMeta = next && !next.route && next.activity ? ACTIVITY_META[next.activity] : undefined; - const canDisqualify = DISQUALIFY_STATES.has(state); - - return ( -
-
- Next action - {canDisqualify && !next?.route && ( - - )} -
- - {showDisqualify ? ( - - ) : next?.route ? ( -
- -
- ) : inlineMeta ? ( - - ) : ( -
- {state === 'Disqualified' ? 'This lead was disqualified.' : 'Lifecycle complete — no further action.'} -
- )} -
- ); -} - +import { DISQUALIFY_STATES } from '../api/forms'; // Compact Indian currency for the small stat tiles, so large cover figures // (₹2,00,00,000) never overflow + get clipped by the card. Crore/lakh short // form above ₹1L; full grouping below. @@ -82,13 +29,15 @@ function compactINR(n: number): string { return `₹${formatINR(n)}`; } -function ProfileRow({ label, value, mono }: { label: string; value: ReactNode; mono?: boolean }) { +/** A compact label/value tile for the Profile grid — fills the wide card width + * far better than full-width key→value rows. */ +function ProfileTile({ label, value, mono }: { label: string; value: ReactNode; mono?: boolean }) { return ( -
- {label} - +
+
{label}
+
{value} - +
); } @@ -159,6 +108,8 @@ export function Lead360Screen() { : null; const issued = lead.stage >= STAGES.indexOf('Policy Issued'); + const state = record.current_state_name ?? ''; + const hasAction = !!STEP_BY_STATE[state] || DISQUALIFY_STATES.has(state); return (
@@ -179,9 +130,12 @@ export function Lead360Screen() { {meetingLabel ? ` · meeting ${meetingLabel}` : ''}
- - {record.current_state_name ?? '—'} - +
+ + {record.current_state_name ?? '—'} + + {hasAction && } +
{/* lifecycle stepper */} @@ -211,16 +165,16 @@ export function Lead360Screen() {
{/* MAIN */}
- -
- -
-
{record.current_state_name ?? 'In progress'}
-
Owned by {lead.owner}
-
-
-
- + +
+ + + + + + + + {lead.interest}} />
@@ -279,40 +233,23 @@ export function Lead360Screen() { )} - {/* Activity log + profile reference sit side by side — profile is - context, not a footer, so it reads next to the audit trail. */} -
- - {timeline.length ? ( - timeline.map((t, i) => ( - - )) - ) : ( -
No activity recorded yet.
- )} -
- - - - - - - } /> - -
- Product interest - {lead.interest} -
-
-
+ + {timeline.length ? ( + timeline.map((t, i) => ( + + )) + ) : ( +
No activity recorded yet.
+ )} +
{/* RAIL — live AI decision feed (manual refresh, no polling). */}