Most useMutation / useQuery sites in the SPA render results without surfacing pending or error states, so failed sends/moves/searches look indistinguishable from no-ops and double-clicks aren't prevented.
Hot spots
- Mutations in
app/components/email-list.tsx, app/components/AgentPanel.tsx, app/components/ComposeEmail.tsx — wire isPending to disable the trigger button and isError to a toast.
- Search in
app/routes/search-results.tsx — show a skeleton while loading, toast on error.
- Pagination in
app/routes/email-list.tsx — show skeleton on isLoading so the next page doesn't render stale data silently.
Proposal
Use the existing kumo Spinner / Skeleton / disabled-button props plus a shared toast helper. No new deps.
Why
Cheapest credibility win. Today a failed reply-send or quarantine move is invisible to the user.
Effort
Half a day for a sweep across the listed components; can be split per-component if preferred.
Most
useMutation/useQuerysites in the SPA render results without surfacing pending or error states, so failed sends/moves/searches look indistinguishable from no-ops and double-clicks aren't prevented.Hot spots
app/components/email-list.tsx,app/components/AgentPanel.tsx,app/components/ComposeEmail.tsx— wireisPendingto disable the trigger button andisErrorto a toast.app/routes/search-results.tsx— show a skeleton while loading, toast on error.app/routes/email-list.tsx— show skeleton onisLoadingso the next page doesn't render stale data silently.Proposal
Use the existing kumo
Spinner/Skeleton/ disabled-button props plus a shared toast helper. No new deps.Why
Cheapest credibility win. Today a failed reply-send or quarantine move is invisible to the user.
Effort
Half a day for a sweep across the listed components; can be split per-component if preferred.