From 2965c47b71bcdb33fb52e3bd2f1a81e38ed62500 Mon Sep 17 00:00:00 2001 From: Yashas Date: Wed, 9 Sep 2026 10:46:38 +0530 Subject: [PATCH] =?UTF-8?q?console:=20consolidate=20the=20lead=20page=20?= =?UTF-8?q?=E2=80=94=20say=20each=20thing=20once,=20weight=20by=20importan?= =?UTF-8?q?ce?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The layout placed information by convenience, not importance, and repeated itself. This is the consolidation pass, no new look. - METRICS: seven at equal weight became four, money first — Premium, Commission, AI confidence, Renewal-countdown. Dropped lead age and time-in-stage (they overlapped each other, and the feed already carries timing), and product / vehicle (the rail's "The vehicle" holds them). Nothing is lost; every removed measure is still on the page once, where it belongs. - STAGE stops appearing as a metric — the rail is where the lead's position lives, and the feed shows each transition. - NEXT STEP no longer repeats the status. Its heading and "nothing is waiting on you" subtitle rendered even when nothing was owed, saying a third time what the status strip and the header already said. The heading shows only for a real step now; secondary actions (add a document, mark lost) still render, without the framing. Co-Authored-By: Claude Opus 5 (1M context) --- src/screens/Lead.jsx | 89 ++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 61 deletions(-) diff --git a/src/screens/Lead.jsx b/src/screens/Lead.jsx index 0b7a069..c36bc72 100644 --- a/src/screens/Lead.jsx +++ b/src/screens/Lead.jsx @@ -16,13 +16,6 @@ import { actionsFor, rolesOf } from '../api/permissions.js' import { describeError } from '../api/errors.js' import './screens.css' -function fmtWhen(ts) { - if (!ts) return null - const d = new Date(ts) - if (isNaN(d)) return String(ts) - return d.toLocaleString('en-IN', { day: 'numeric', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' }) -} - /** The countdown, not just the date. On a renewal book this is the number * that decides whether anyone should act today. */ function expiryOf(dateStr) { @@ -38,14 +31,6 @@ function expiryOf(dateStr) { } } -/** Whole days since a timestamp. Age and dwell time are the two numbers that - * say whether a lead is moving, and neither is on the record. */ -function daysSince(ts) { - if (!ts) return null - const t = Date.parse(ts) - return isNaN(t) ? null : Math.floor((Date.now() - t) / 86400000) -} - function inrShort(v) { const n = Number(v) if (!Number.isFinite(n) || !n) return null @@ -380,7 +365,6 @@ export default function Lead() { }).length }, 0) - const isClosed = stage?.kind === 'end' // An automated stage that has stopped for a stated reason. Checked before // the "in progress" strip below, which would otherwise keep promising that // something is happening for as long as the lead is left alone. @@ -462,46 +446,28 @@ export default function Lead() { which no label/value pair on the page could. */} {(() => { const e = expiryOf(row.renewal_due_date) - const age = daysSince(row.created_at) - const dwell = daysSince(row.updated_at) const premium = inrShort(row.quoted_premium) const commission = inrShort(row.commission_amount) const conf = Number(row.ai_recommendation_confidence) + // FOUR NUMBERS, NOT SEVEN. Money leads, because that is what a renewal + // is about; the AI's confidence in the cover sits beside it; the + // renewal countdown is the one deadline that matters. Dropped: lead age + // and time-in-stage (they overlapped each other and the feed carries + // timing), and product/vehicle (the rail's "The vehicle" holds them). + // Nothing is lost — every removed measure is still on the page once, + // where it belongs. return (
-
- Renewal - {e ? e.label : '—'} - {e ? e.on : 'no date on file'} -
-
- Lead age - {age === null ? '—' : age === 0 ? 'Today' : age + 'd'} - {row.created_at ? fmtWhen(row.created_at) : ''} -
-
- In this stage - {dwell === null ? '—' : dwell === 0 ? '<1d' : dwell + 'd'} - last activity {row.updated_at ? fmtWhen(row.updated_at) : '—'} -
Premium {premium ?? '—'} - {premium ? 'quoted' : 'not yet rated'} + {premium ? 'quoted, incl. GST' : 'not yet rated'}
Commission {commission ?? '—'} - {row.commission_rate_pct ? row.commission_rate_pct + '% of premium' : 'on placement'} - -
-
- Product - {PRODUCTS[row.product_line] ?? '—'} - - {row.motor_reg_no || row.entity_name || ''} - {row.current_insurer ? ` · from ${row.current_insurer}` : ''} + {row.commission_rate_pct ? row.commission_rate_pct + '% · on issue' : 'on placement'}
{Number.isFinite(conf) && conf > 0 ? ( @@ -511,6 +477,11 @@ export default function Lead() { on the cover advice
) : null} +
+ Renewal + {e ? e.label : '—'} + {e ? e.on : 'no date on file'} +
) })()} @@ -653,25 +624,21 @@ export default function Lead() { return (
-
-
-

Next step

-

- {step.length - ? 'This is what this lead is waiting on.' - : isClosed - ? 'This lead is closed.' - : blocked - ? 'The chain has stopped. The fix is above.' - : accepted && stage?.uid === 'zk-state-quoted' - /* What is RUNNING is the strip's job now, so this - records only the fact — otherwise the two lines - said the same thing twice, one above the other. */ - ? `Accepted by the customer${row.accepted_at ? ' on ' + row.accepted_at : ''}${row.acceptance_ref === 'whatsapp' ? ', over WhatsApp' : ''}. Nothing is waiting on you.` - : `Nothing is waiting on you — ${stage?.by ?? 'someone else'} has this one.`} -

+ {/* THE HEADING IS FOR A REAL STEP ONLY. When there is no `do` + action, the "what is happening / nothing owed" story is + already told once — by the status strip above and the + header — so repeating it here as "Next step: nothing is + waiting on you" was the same sentence a third time. The + secondary actions (add a document, mark lost) still render + below, without the framing. */} + {step.length ? ( +
+
+

Next step

+

This is what this lead is waiting on.

+
-
+ ) : null} {/* The step. One button, sized like a decision. Referred has two because clear and decline are a pair, not a choice