9.6 KiB
Sonner Global Notification System — Ralph Loop Prompt
You are implementing a global toast notification system in the adiuvAI Electron app using shadcn's sonner component.
Full plan: Read docs/plan-sonner-notifications.md for the complete architecture, file list, i18n keys, and categorization of every mutation.
Rules
- Always read the plan first at
docs/plan-sonner-notifications.mdbefore doing any work. - Always read a file before editing it. Never edit blind.
- One phase per iteration. Complete one phase fully, verify it compiles, then move on.
- Run
cd adiuvAI && npx tsc --noEmitafter each phase to catch type errors early. - Run
cd adiuvAI && npm run lintafter Phase 3 and Phase 4 to catch lint issues. - Commit after each phase with a descriptive message.
- i18n: add keys to ALL 5 language files (
en,it,es,fr,de). The plan has complete translations for each. - Do NOT touch silent mutations (note auto-save, kanban drag, sidebar toggle, AI chat/streaming). For these, add
onErroronly if missing. - When removing
saved/setSavedstate patterns: also remove thesetTimeout, the button text ternary, and anysetSaved(false)inonChangehandlers. Replace button text with{t('common.save')}. - Import path for useNotify:
import { useNotify } from '@/hooks/useNotify'; - Import path for toast (direct):
import { toast } from 'sonner';(only in useNotify.ts itself)
Progress Tracking
Check the state of the codebase to determine which phase to work on:
- If
src/renderer/components/ui/sonner.tsxdoes NOT exist → Start Phase 1 - If
sonner.tsxexists but settings components still havesetSaved→ Do Phase 2 - If settings are done but CRUD components lack
useNotify→ Do Phase 3 - If CRUD is done but auth/onboarding lack
useNotify→ Do Phase 4 - If all phases are done and
npx tsc --noEmit+npm run lintpass → Do Phase 5 (verification)
Phase 1: Foundation
Step 1: Install sonner
cd adiuvAI && npx shadcn@latest add sonner --yes
Step 2: Fix theme import in generated sonner.tsx
The generated file imports useTheme from next-themes. This app does NOT use next-themes. Fix the import:
// WRONG (generated):
import { useTheme } from "next-themes"
// CORRECT:
import { useTheme } from "@/components/theme-provider"
Also set position="bottom-right" and add richColors on the <Sonner> component.
Step 3: Add <Toaster /> to src/renderer/index.tsx
Import Toaster from @/components/ui/sonner and render it as the last child inside <QueryClientProvider>, AFTER <RouterProvider />. This ensures toasts work during login, onboarding, AND normal app usage.
Step 4: Create src/renderer/hooks/useNotify.ts
Create the hook exactly as specified in the plan (Section 1.4). The hook exports { notify, notifyError, notifyPromise }.
Step 5: Add i18n keys to all 5 translation files
Add the "toast" top-level key with all sub-keys to:
src/renderer/locales/en/translation.json(English — from plan)src/renderer/locales/it/translation.json(Italian — from plan)src/renderer/locales/es/translation.json(Spanish — from plan)src/renderer/locales/fr/translation.json(French — from plan)src/renderer/locales/de/translation.json(German — from plan)
Step 6: Verify
cd adiuvAI && npx tsc --noEmit
Step 7: Commit
cd adiuvAI && git add -A && git commit -m "feat(notifications): add sonner toast foundation with useNotify hook and i18n keys"
Phase 2: Settings Components
For each of these 5 files, apply the pattern: add useNotify(), remove saved/setSaved state, remove setTimeout, replace button text ternary, add notify() in onSuccess, add notifyError() in onError.
Files (in order):
-
src/renderer/components/settings/GeneralSection.tsx- Remove:
saved,setSaved,error,setError,setTimeout, inline<p>error,setSaved(false)in onChange - Add:
notify('success', 'toast.profile.updated')in handleSave onSuccess - Add:
notifyError('toast.profile.updateError', err)in handleSave onError - Add:
notify('info', 'toast.settings.languageChanged')in handleLanguageChange - Button text:
{t('common.save')}
- Remove:
-
src/renderer/components/settings/ProfileSection.tsx- Remove:
profileSaved,displaySavedstates and theirsetTimeouts - Profile save →
notify('success', 'toast.settings.memorySaved') - Display save →
notify('success', 'toast.settings.formatPrefsSaved') - Reset onboarding →
notify('info', 'toast.onboarding.reset')
- Remove:
-
src/renderer/components/settings/AccountSection.tsx- Remove:
urlSaved,setUrlSavedstate andsetTimeout - Backend URL save →
notify('success', 'toast.settings.backendUrlSaved') - Add onError →
notifyError('toast.settings.backendUrlError', err) - Logout →
notify('info', 'toast.auth.loggedOut')
- Remove:
-
src/renderer/components/settings/LocalAgentConfigPanel.tsx- Remove:
savedstate andsetTimeout - Save →
notify('success', 'toast.agent.updated') - Add onError →
notifyError('toast.agent.updateError', err)
- Remove:
-
src/renderer/components/settings/CloudAgentConfigPanel.tsx- Same as LocalAgentConfigPanel
Verify and Commit:
cd adiuvAI && npx tsc --noEmit && npm run lint
cd adiuvAI && git add -A && git commit -m "feat(notifications): replace settings saved-state patterns with sonner toasts"
Phase 3: CRUD Operations
Add useNotify() to each component and wire notify / notifyError into existing onSuccess / onError callbacks. If onError doesn't exist, add it.
Files and mutations:
Tasks:
src/renderer/components/tasks/NewTaskDialog.tsx→tasks.create: successtoast.task.created+ inlineclients.create: successtoast.client.createdsrc/renderer/components/tasks/EditTaskDialog.tsx→tasks.update: successtoast.task.updatedsrc/renderer/components/tasks/TaskDetailDialog.tsx→taskComments.create: successtoast.comment.created,taskComments.delete: warningtoast.comment.deletedsrc/renderer/routes/tasks.tsx→tasks.delete: warningtoast.task.deleted,tasks.updatestatus toggle: onError onlysrc/renderer/components/projects/KanbanBoard.tsx→tasks.updatedrag: onError only,tasks.delete: warningtoast.task.deletedsrc/renderer/components/projects/ProjectDetail.tsx→tasks.delete: warningtoast.task.deleted,tasks.updatetoggle: onError only,notes.create: successtoast.note.createdsrc/renderer/components/ai/blocks/ChatEntityBlock.tsx→tasks.delete: warningtoast.task.deleted,tasks.updatetoggle: onError only
Projects & Clients:
src/renderer/components/projects/ProjectSidebar.tsx→projects.create: success,projects.update: success,projects.delete: warning,projects.archiveByClient: warning (check if archiving or unarchiving),clients.create: success,clients.update: success,clients.deleteWithCascade: warning
Notes:
src/renderer/routes/notes.$noteId.tsx→notes.delete: warningtoast.note.deleted,notes.updateauto-save: onError only (SILENT)
Timeline:
src/renderer/components/timeline/AddEventDialog.tsx→timelineEvents.create: successsrc/renderer/components/timeline/EditEventDialog.tsx→timelineEvents.update: successsrc/renderer/routes/timeline.tsx→timelineEvents.delete: warning,timelineEvents.update: success
Agents:
src/renderer/components/settings/AgentsSection.tsx→agent.*.delete: warning,agent.*.updatetoggle: onError only,agent.runNow: usenotifyPromisesrc/renderer/components/settings/InlineAgentCreationStepper.tsx→agent.*.create: success
Verify and Commit:
cd adiuvAI && npx tsc --noEmit && npm run lint
cd adiuvAI && git add -A && git commit -m "feat(notifications): add sonner toasts to all CRUD operations"
Phase 4: Auth + Onboarding
Files:
-
src/renderer/components/auth/LoginForm.tsxauth.loginonError →notifyError('toast.auth.loginError', err)(KEEP inline error too)auth.registeronError →notifyError('toast.auth.registerError', err)(KEEP inline error too)auth.loginWithOAuthonError →notifyError('toast.auth.oauthError', err)
-
src/renderer/components/layout/AppShell.tsxauth.logoutonSuccess →notify('info', 'toast.auth.loggedOut')(add beforeutils.auth.status.invalidate())
-
src/renderer/components/onboarding/OnboardingFlow.tsx- Final save onSuccess →
notify('success', 'toast.onboarding.completed', { descriptionKey: 'toast.onboarding.completedDescription' }) - Final save onError →
notifyError('toast.onboarding.error', err) - Normalize call → use
notifyPromisewith loading/success/error keys
- Final save onSuccess →
Verify and Commit:
cd adiuvAI && npx tsc --noEmit && npm run lint
cd adiuvAI && git add -A && git commit -m "feat(notifications): add sonner toasts to auth and onboarding flows"
Phase 5: Final Verification
Run these checks:
cd adiuvAI && npx tsc --noEmit
cd adiuvAI && npm run lint
cd adiuvAI && npm run knip
Verify:
- No remaining
setSavedorsetTimeout.*setSavedpatterns insrc/renderer/components/settings/ - All 5 translation files have the
toastkey with matching sub-keys sonner.tsximports from@/components/theme-provider(NOTnext-themes)<Toaster />renders inindex.tsxinside<ThemeProvider>useNotify.tsexists insrc/renderer/hooks/
If everything passes:
SONNER NOTIFICATIONS COMPLETE