import { useState, type ReactNode } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import { formatINR } from '@sims/domain'
import { Badge, DataTable, EmptyState, ErrorState, Notice, PageHeader, Skeleton, StatCard, Stats } from '@sims/ui'
import { getDashboard, isManagerial } from '../api'
import { QueueActions, RULE_LABEL, reminderTone } from '../components/ReminderQueue'
import { useData } from './Clients'
const inr = (p: number) => formatINR(p)
/** Dashboard home — today's money + the manual reminder queue (spec §3). */
export function Dashboard() {
const nav = useNavigate()
// My Day (D18 WS-E): owner/manager toggle Mine ↔ Everyone; staff are always
// scoped to their own book server-side, so they get no toggle.
const managerial = isManagerial()
const [mine, setMine] = useState(false)
const dash = useData(() => getDashboard(mine), [mine])
const [err, setErr] = useState('')
const v = dash.data
return (
),
} : {})}
/>
{dash.error !== undefined && }
{err !== '' && {err}}
{v === undefined && dash.error === undefined ? : v === undefined ? null : (
<>
0 ? { hint: 'needs attention', hintTone: 'err' as const } : {})} />
Reminder queue
View all →
{v.queue.length === 0 ? Nothing waiting — all clear. : (
{
const s = v.queue[i]?.status
return s === 'failed' ? 'err' : undefined
}}
rows={v.queue.map((rem) => ({
kind: rem.label !== '' ? rem.label : RULE_LABEL[rem.ruleKind] ?? rem.ruleKind,
client: rem.clientName,
ref: rem.docNo ?? rem.duePeriod,
status: {rem.status},
error: rem.error ?? '—',
act: ,
}))}
/>
)}
{v.queueTotal > v.queue.length && (
// No silent caps (rule 8): the table is the first page only — say so.
Showing {v.queue.length} of {v.queueTotal} — see the full queue.
)}
nav(`/documents/${v.overdue[i]!.docId}`)}
map={(o) => ({ no: o.docNo ?? '—', client: o.clientName, days: o.daysOverdue, due: inr(o.outstandingPaise) })} />
({ client: d.clientName, on: d.nextRun, amt: d.amountPaise !== null ? inr(d.amountPaise) : 'from price book' })} />
nav(`/clients/${v.renewalsThisMonth[i]!.clientId}`)}
map={(r) => ({ client: r.clientName, on: r.nextRenewal })} />
nav(`/clients/${v.followUpsToday[i]!.clientId}`)}
map={(f) => ({ client: f.clientName, on: f.followUpOn, notes: f.notes !== '' ? f.notes : '—' })} />
({ client: p.clientName, on: p.receivedOn, mode: p.mode, amt: inr(p.amountPaise) })} />
>
)}
)
}
/** A titled table with an empty state — keeps the dashboard body declarative. */
function Section(props: {
title: string; empty: string; rows: T[]
columns: { key: string; label: string; numeric?: boolean }[]
map: (row: T) => Record; onRowClick?: (i: number) => void
}) {
return (
<>
{props.title}
{props.rows.length === 0 ? {props.empty} : (
props.onRowClick!(i) } : {})}
rows={props.rows.map(props.map)}
/>
)}
>
)
}