diff --git a/client/components/BillModal.jsx b/client/components/BillModal.jsx index a918d95..5cba163 100644 --- a/client/components/BillModal.jsx +++ b/client/components/BillModal.jsx @@ -20,6 +20,7 @@ import { api } from '@/api'; import { cn, fmt, fmtDate, todayStr } from '@/lib/utils'; import BillMerchantRules from '@/components/BillMerchantRules'; import DebtDetailsSection from '@/components/bill-modal/DebtDetailsSection'; +import AutopayTrustIndicator from '@/components/bill-modal/AutopayTrustIndicator'; import { BILLING_SCHEDULE_OPTIONS, billingCycleForSchedule, @@ -913,48 +914,13 @@ export default function BillModal({ bill, initialBill, categories, onClose, onSa {/* Autopay trust indicator — edit mode only */} - {!isNew && autopay && (() => { - const stats = bill?.autopay_stats; - const total = stats?.total ?? 0; - const failures = stats?.failures ?? 0; - const daysSince = localVerifiedAt - ? Math.floor((Date.now() - localVerifiedAt.getTime()) / 86400000) - : null; - const needsVerify = daysSince === null || daysSince > 90; - return ( -
-
- 0 ? 'text-amber-500' : total > 0 ? 'text-emerald-500' : 'text-muted-foreground/60')}> - {total > 0 - ? `${failures > 0 ? '⚠' : '✓'} ${total - failures}/${total} successful (12 mo)` - : 'No payment history yet'} - - -
- {needsVerify && ( -

- {daysSince === null - ? "Autopay never confirmed — verify it's still active." - : `Last verified ${daysSince}d ago — confirm autopay is still on.`} -

- )} - {!needsVerify && ( -

Verified {daysSince}d ago

- )} - {failures > 0 && stats?.last_failure_date && ( -

- Last failure: {stats.last_failure_date}{stats?.last_failure_notes ? ` — ${stats.last_failure_notes}` : ''} -

- )} -
- ); - })()} + {/* Notes */}
diff --git a/client/components/bill-modal/AutopayTrustIndicator.jsx b/client/components/bill-modal/AutopayTrustIndicator.jsx new file mode 100644 index 0000000..9fea6c6 --- /dev/null +++ b/client/components/bill-modal/AutopayTrustIndicator.jsx @@ -0,0 +1,49 @@ +import { cn } from '@/lib/utils'; + +// Edit-mode autopay trust panel: success rate over the last 12 months, a +// "Mark verified" action, and staleness / failure warnings. Presentational — +// the parent owns the verify handler and the optimistic verified-at date. +export default function AutopayTrustIndicator({ isNew, autopay, stats, verifiedAt, onVerify }) { + if (isNew || !autopay) return null; + + const total = stats?.total ?? 0; + const failures = stats?.failures ?? 0; + const daysSince = verifiedAt + ? Math.floor((Date.now() - verifiedAt.getTime()) / 86400000) + : null; + const needsVerify = daysSince === null || daysSince > 90; + + return ( +
+
+ 0 ? 'text-amber-500' : total > 0 ? 'text-emerald-500' : 'text-muted-foreground/60')}> + {total > 0 + ? `${failures > 0 ? '⚠' : '✓'} ${total - failures}/${total} successful (12 mo)` + : 'No payment history yet'} + + +
+ {needsVerify && ( +

+ {daysSince === null + ? "Autopay never confirmed — verify it's still active." + : `Last verified ${daysSince}d ago — confirm autopay is still on.`} +

+ )} + {!needsVerify && ( +

Verified {daysSince}d ago

+ )} + {failures > 0 && stats?.last_failure_date && ( +

+ Last failure: {stats.last_failure_date}{stats?.last_failure_notes ? ` — ${stats.last_failure_notes}` : ''} +

+ )} +
+ ); +}