import { Link } from 'react-router-dom'; import { ArrowRight, Sparkles } from 'lucide-react'; import { useQuery, useZino } from '../../api/provider'; import { RV } from '../../api/config'; import { Badge, Bar, Button, Card, Empty, ErrorNote, Kpi, Spinner } from '../../components/core'; import { RecCard, SimTable, useSimulate } from '../../components/widgets'; import { date, inr, mt, num, pct } from '../../format'; import { useDealer } from './useDealer'; export function DealerHome() { const { client, portal } = useZino(); const cust = portal?.customer_no; const d = useDealer(cust); const sim = useSimulate(cust, null); const recs = useQuery(() => client.rows(RV.RECOMMENDATIONS, { limit: 5, sortBy: 'created_at', sortDir: 'desc', filters: [{ field_key: 'customer_no', value: String(cust), data_type: 'string' }] }), [cust], !!cust, 30000); const upcoming = useQuery(() => client.rows(RV.UPCOMING, { params: { customer_no: cust } }), [cust], !!cust); if (!portal) return ; if (!cust) return This login is not mapped to a dealer.; if (d.loading && !d.data) return ; if (d.error) return {d.error}; const s = d.data?.snapshot; if (!s) return No snapshot for {cust}.; const st = d.data?.standing; const asOf = d.data?.as_of ?? ''; const monthEnd = asOf ? new Date(new Date(asOf).getFullYear(), new Date(asOf).getMonth() + 1, 0) : null; const daysLeft = monthEnd && asOf ? Math.round((monthEnd.getTime() - new Date(asOf).getTime()) / 86400000) : null; const earning = (sim.data ?? []).reduce((a, r) => a + num(r.payout_now), 0); const top = recs.data?.[0]; return (

{s.name}

{s.customer_no} · {st?.cluster_name ?? s.cluster} cluster · {s.ao} · as of {date(asOf)}{daysLeft != null ? ` · ${daysLeft} days left in the month` : ''}

{s.gold_star && Gold Star} {s.silver_star && Silver Star} {s.is_new_dealer && New dealer} {s.is_inactive && Revival} {st?.is_weak_market && Weak-market cluster} {st?.is_border && Border cluster} {s.loyalty_tier && {s.loyalty_tier} tier}
Month to date
{mt(s.mtd_mt)}
target {mt(s.month_target_mt)} · {s.month_target_mt ? pct((s.mtd_mt / s.month_target_mt) * 100, 0) : '—'}
0 ? `${inr(s.overdue, { compact: true })} overdue` : 'nothing overdue'} tone={s.overdue > 0 ? 'rose' : undefined} />
Advisor says} subtitle="The latest nudges written for you. Numbers come from the scheme engine, not from the model.">
{recs.loading && !recs.data && } {recs.data && recs.data.length === 0 && No advice yet — place an order and the Advisor reads it.} {top && } {(recs.data ?? []).slice(1, 3).map((r) => )}
All schemes →}> num(r.payout_now) > 0 || (r.mt_to_next_slab != null && num(r.mt_to_next_slab) > 0)).slice(0, 6)} hasHypo={false} loading={sim.loading} error={sim.error} />
{(upcoming.data ?? []).length === 0 && Nothing opening in the next 45 days.} {(upcoming.data ?? []).map((u) => (
{String(u.scheme_name)}
opens {date(u.validity_from)} · in {String(u.starts_in_days)} days · to {date(u.validity_to)}

{String(u.circular_text ?? '').split('\n').slice(2).join(' ')}

))}
{s.open_orders.length === 0 && No open orders in the estate.} {s.open_orders.map((o) => (
{o.so_no}
for {date(o.requested)}
{mt(o.qty_mt)}
{o.status}
))}
); }