import { useState } from 'react' import { Button, ConfirmDialog, useToast } from '@sims/ui' import { dismissReminder, getReminderPreview, sendReminder, type QueueItem } from '../api' /** Fallback kind labels for queue rows whose server `label` is empty. */ export const RULE_LABEL: Record = { invoice_overdue: 'Overdue invoice', renewal_due: 'Renewal due', amc_expiring: 'AMC expiring', follow_up: 'Follow-up', recurring_generated: 'Recurring invoice', email_bounced: 'Email bounced', quote_followup: 'Quote follow-up', } /** Rule kinds with a client-facing email; the rest are internal work items (dismiss only). */ export const SENDABLE = new Set(['invoice_overdue', 'renewal_due', 'amc_expiring', 'recurring_generated', 'quote_followup']) /** Badge tone for a reminder status: failed red, sent green, dismissed neutral, queued amber. */ export const reminderTone = (status: string): 'ok' | 'warn' | 'err' | undefined => status === 'failed' ? 'err' : status === 'sent' ? 'ok' : status === 'dismissed' ? undefined : 'warn' /** * Send / Preview / Dismiss for one queue row — shared by the Dashboard queue card and * the Reminders page (WS-C: one set of actions, two views). Reloads via `onDone` even * on failure: the server has already parked the reminder as 'failed' with its error, * and the row must flip live. */ export function QueueActions(props: { rem: QueueItem; onDone: () => void; onError: (m: string) => void }) { const toast = useToast() const [busy, setBusy] = useState(false) const [mail, setMail] = useState<{ subject: string; body: string } | undefined>() const [loading, setLoading] = useState(false) const [confirmSend, setConfirmSend] = useState(false) // Toast on success only — onDone still fires on failure too (the server has // already parked the reminder as 'failed' and the row must flip live). const run = (start: () => Promise, okMsg: string) => { if (busy) return // Button has no disabled prop — guard re-entry here setBusy(true); props.onError('') start() .then(() => toast.ok(okMsg)) .catch((e: Error) => props.onError(e.message)) .then(props.onDone) .finally(() => setBusy(false)) } const preview = () => { if (mail !== undefined) { setMail(undefined); return } // toggle closed if (loading) return setLoading(true); props.onError('') getReminderPreview(props.rem.id) .then(setMail) .catch((e: Error) => props.onError(e.message)) .finally(() => setLoading(false)) } return (
{SENDABLE.has(props.rem.ruleKind) && ( <> )}
{confirmSend && ( setConfirmSend(false)} onConfirm={() => run(() => sendReminder(props.rem.id), 'Reminder sent')} title="Send reminder" body={`Email this reminder to ${props.rem.clientName}${props.rem.docNo !== null ? ` for ${props.rem.docNo}` : ''} now?`} confirmLabel="Send" /> )} {mail !== undefined && (
Subject
{mail.subject}
Body
{mail.body}
)}
) }