Vite/React 19 console and enterprise PWA. Officer console screens, offline ledger and sync, data feeds and trip-wire rules screens with freshness chip. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
98 lines
4.3 KiB
TypeScript
98 lines
4.3 KiB
TypeScript
import { enterpriseSession } from '../../lib/api'
|
|
import { Empty } from '../../components/ui/bits'
|
|
import { findEnterprise, reasonCodesFor, tripWiresFor } from '../../lib/demo/enterprises'
|
|
import { alertForEnterprise } from '../../lib/demo/ops'
|
|
import { inr, monthRef } from '../../lib/demo/seed'
|
|
import { useLang } from '../../lib/i18n'
|
|
|
|
/**
|
|
* Alert history for the owner. Same reason codes the officer sees, but only
|
|
* ever as plain sentences — no scores, no model vocabulary, nothing that reads
|
|
* like a credit rating handed to the borrower.
|
|
*/
|
|
export function AppAlertsPage() {
|
|
const session = enterpriseSession()
|
|
const { lang, t } = useLang('hi')
|
|
const hi = lang === 'hi'
|
|
|
|
const e = session ? findEnterprise(session.enterpriseId) : undefined
|
|
if (!session || !e) return <Empty text="—" />
|
|
|
|
const alert = alertForEnterprise(e.enterpriseId)
|
|
const reasons = reasonCodesFor(e)
|
|
const fired = tripWiresFor(e).filter((w) => w.fired)
|
|
|
|
if (!alert) {
|
|
return (
|
|
<div className="bg-green-soft border border-green/20 rounded-xl px-4 py-6 text-center">
|
|
<div className="w-12 h-12 rounded-full bg-white text-green grid place-items-center text-[22px] mx-auto mb-2.5">
|
|
✓
|
|
</div>
|
|
<div className="text-[14px] font-bold text-forest">{t('alerts.none')}</div>
|
|
<p className="text-[12px] text-slate-600 mt-1">{t('home.allGoodDetail')}</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const breachRef = alert.breachMonth ? monthRef(new Date(`${alert.breachMonth}-01T00:00:00`)) : null
|
|
|
|
return (
|
|
<div className="space-y-3">
|
|
<section className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
|
<div className="bg-risk-red text-white px-4 py-3">
|
|
<div className="text-[13.5px] font-bold">{hi ? alert.titleHi : alert.title}</div>
|
|
<div className="text-[12px] text-white/85 mt-0.5">
|
|
{t('home.estimate')}: <b>{inr(alert.shortfall)}</b> {t('home.shortfall')}
|
|
{breachRef && ` · ${hi ? breachRef.fullHi : breachRef.fullEn}`}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="px-4 py-3">
|
|
<div className="text-[11px] font-semibold text-slate-500 mb-2">
|
|
{hi ? 'ऐसा क्यों लग रहा है' : 'Why this is expected'}
|
|
</div>
|
|
<ul className="space-y-2.5">
|
|
{reasons.map((r) => (
|
|
<li key={r.driver} className="flex gap-2.5">
|
|
<span className="w-1.5 h-1.5 rounded-full bg-amber mt-[7px] shrink-0" />
|
|
<span className="text-[12.5px] text-slate-700 leading-snug">{hi ? r.sentenceHi : r.sentenceEn}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
<div className="px-4 py-3 border-t border-slate-100 bg-amber-soft">
|
|
<div className="text-[11px] font-semibold text-slate-600 mb-1">{t('alerts.whatToDo')}</div>
|
|
<p className="text-[12.5px] text-slate-700 leading-snug">
|
|
{hi
|
|
? 'अपने फ़ील्ड अधिकारी से बात करें — किस्त की तारीख़ कमाई के मौसम से मिलाई जा सकती है।'
|
|
: 'Speak to your field officer — the instalment date can be aligned to your earning season.'}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="px-4 py-2 border-t border-slate-100 text-[10.5px] text-slate-400">
|
|
{t('alerts.raisedOn')}: {alert.raisedAt} · {alert.alertId}
|
|
</div>
|
|
</section>
|
|
|
|
{fired.length > 0 && (
|
|
<section className="bg-white rounded-xl border border-slate-200 px-4 py-3">
|
|
<div className="text-[11px] font-semibold text-slate-500 mb-2">
|
|
{hi ? 'किन बातों पर नज़र है' : 'What is being watched'}
|
|
</div>
|
|
<ul className="space-y-2">
|
|
{fired.map((w) => (
|
|
<li key={w.code} className="flex gap-2.5 items-start">
|
|
<span className="w-4 h-4 rounded-full bg-risk-soft text-risk-red grid place-items-center text-[9px] font-bold mt-0.5 shrink-0">
|
|
!
|
|
</span>
|
|
<span className="text-[12px] text-slate-700 leading-snug">{hi ? w.labelHi : w.label}</span>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|