# 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.md` before 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 --noEmit` after each phase** to catch type errors early.
- **Run `cd adiuvAI && npm run lint` after 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 `onError` only if missing.
- **When removing `saved`/`setSaved` state patterns:** also remove the `setTimeout`, the button text ternary, and any `setSaved(false)` in `onChange` handlers. 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:

1. **If `src/renderer/components/ui/sonner.tsx` does NOT exist** → Start Phase 1
2. **If `sonner.tsx` exists but settings components still have `setSaved`** → Do Phase 2
3. **If settings are done but CRUD components lack `useNotify`** → Do Phase 3
4. **If CRUD is done but auth/onboarding lack `useNotify`** → Do Phase 4
5. **If all phases are done and `npx tsc --noEmit` + `npm run lint` pass** → Do Phase 5 (verification)

---

## Phase 1: Foundation

### Step 1: Install sonner

```bash
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:

```tsx
// 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

```bash
cd adiuvAI && npx tsc --noEmit
```

### Step 7: Commit

```bash
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):

1. **`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')}`

2. **`src/renderer/components/settings/ProfileSection.tsx`**
   - Remove: `profileSaved`, `displaySaved` states and their `setTimeout`s
   - Profile save → `notify('success', 'toast.settings.memorySaved')`
   - Display save → `notify('success', 'toast.settings.formatPrefsSaved')`
   - Reset onboarding → `notify('info', 'toast.onboarding.reset')`

3. **`src/renderer/components/settings/AccountSection.tsx`**
   - Remove: `urlSaved`, `setUrlSaved` state and `setTimeout`
   - Backend URL save → `notify('success', 'toast.settings.backendUrlSaved')`
   - Add onError → `notifyError('toast.settings.backendUrlError', err)`
   - Logout → `notify('info', 'toast.auth.loggedOut')`

4. **`src/renderer/components/settings/LocalAgentConfigPanel.tsx`**
   - Remove: `saved` state and `setTimeout`
   - Save → `notify('success', 'toast.agent.updated')`
   - Add onError → `notifyError('toast.agent.updateError', err)`

5. **`src/renderer/components/settings/CloudAgentConfigPanel.tsx`**
   - Same as LocalAgentConfigPanel

### Verify and Commit:

```bash
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`: success `toast.task.created` + inline `clients.create`: success `toast.client.created`
- `src/renderer/components/tasks/EditTaskDialog.tsx` → `tasks.update`: success `toast.task.updated`
- `src/renderer/components/tasks/TaskDetailDialog.tsx` → `taskComments.create`: success `toast.comment.created`, `taskComments.delete`: warning `toast.comment.deleted`
- `src/renderer/routes/tasks.tsx` → `tasks.delete`: warning `toast.task.deleted`, `tasks.update` status toggle: **onError only**
- `src/renderer/components/projects/KanbanBoard.tsx` → `tasks.update` drag: **onError only**, `tasks.delete`: warning `toast.task.deleted`
- `src/renderer/components/projects/ProjectDetail.tsx` → `tasks.delete`: warning `toast.task.deleted`, `tasks.update` toggle: **onError only**, `notes.create`: success `toast.note.created`
- `src/renderer/components/ai/blocks/ChatEntityBlock.tsx` → `tasks.delete`: warning `toast.task.deleted`, `tasks.update` toggle: **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`: warning `toast.note.deleted`, `notes.update` auto-save: **onError only** (SILENT)

**Timeline:**
- `src/renderer/components/timeline/AddEventDialog.tsx` → `timelineEvents.create`: success
- `src/renderer/components/timeline/EditEventDialog.tsx` → `timelineEvents.update`: success
- `src/renderer/routes/timeline.tsx` → `timelineEvents.delete`: warning, `timelineEvents.update`: success

**Agents:**
- `src/renderer/components/settings/AgentsSection.tsx` → `agent.*.delete`: warning, `agent.*.update` toggle: **onError only**, `agent.runNow`: use `notifyPromise`
- `src/renderer/components/settings/InlineAgentCreationStepper.tsx` → `agent.*.create`: success

### Verify and Commit:

```bash
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:

1. **`src/renderer/components/auth/LoginForm.tsx`**
   - `auth.login` onError → `notifyError('toast.auth.loginError', err)` (KEEP inline error too)
   - `auth.register` onError → `notifyError('toast.auth.registerError', err)` (KEEP inline error too)
   - `auth.loginWithOAuth` onError → `notifyError('toast.auth.oauthError', err)`

2. **`src/renderer/components/layout/AppShell.tsx`**
   - `auth.logout` onSuccess → `notify('info', 'toast.auth.loggedOut')` (add before `utils.auth.status.invalidate()`)

3. **`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 `notifyPromise` with loading/success/error keys

### Verify and Commit:

```bash
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:

```bash
cd adiuvAI && npx tsc --noEmit
cd adiuvAI && npm run lint
cd adiuvAI && npm run knip
```

Verify:
- No remaining `setSaved` or `setTimeout.*setSaved` patterns in `src/renderer/components/settings/`
- All 5 translation files have the `toast` key with matching sub-keys
- `sonner.tsx` imports from `@/components/theme-provider` (NOT `next-themes`)
- `<Toaster />` renders in `index.tsx` inside `<ThemeProvider>`
- `useNotify.ts` exists in `src/renderer/hooks/`

If everything passes:

<promise>SONNER NOTIFICATIONS COMPLETE</promise>
