'use client'; import { toast } from 'sonner'; import { ApiError } from '@/lib/api/client'; /** * Render an API error as a toast in the consistent platform format: * * ┌─────────────────────────────────────────────┐ * │ {plain-text message} │ * │ │ * │ Error code: EXPENSES_RECEIPT_REQUIRED │ * │ Reference ID: ab12-cd34-… [Copy] │ * └─────────────────────────────────────────────┘ * * Use this anywhere a `useMutation({ onError })` would otherwise just * call `toast.error(err.message)`. Falls back gracefully when the error * isn't an ApiError (network errors, programmer errors, etc.). */ export function toastError(err: unknown, fallback = 'Something went wrong.'): void { if (err instanceof ApiError) { const lines: string[] = []; if (err.code) lines.push(`Error code: ${err.code}`); if (err.requestId) lines.push(`Reference ID: ${err.requestId}`); toast.error(err.message, { description: lines.length > 0 ? lines.join('\n') : undefined, // Long enough to read the message + grab the reference id. duration: 8_000, action: err.requestId ? { label: 'Copy ID', onClick: () => { if (typeof navigator !== 'undefined' && navigator.clipboard) { void navigator.clipboard.writeText(err.requestId!); toast.success('Reference ID copied'); } }, } : undefined, }); return; } if (err instanceof Error) { toast.error(err.message || fallback); return; } toast.error(fallback); }