Files
udyamlinc/src/features/enterprise/AppAlertsPage.tsx
T
LincPayandClaude Opus 5 f430f85202 chore: initial commit — UdyamLinc UI, phases A-E
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>
2026-08-06 13:30:24 +05:30

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>
)
}