# Notification system overhaul

Status: Planned

Replace floating toast/flash notifications with inline feedback and persistent top banners. Based on usability testing (March 2026) — flash messages overlay UI, auto-dismiss means users miss them, and the overall pattern feels messy.

## Current state

Phoenix flash messages shown as floating toasts. 110+ flash messages across 28 files (65 info, 45+ error). Auto-dismiss after a few seconds. Overlay existing UI content.

## New approach: two layers

### 1. Inline feedback (primary)

Contextual to the field or action. Persistent until the state changes.

- **Success:** green tick/label next to the saved field or action area. E.g. "Saved" next to a settings field after change.
- **Error:** red border on the field + error text below it. Stays visible until fixed. Bold, clearly coloured, impossible to miss — same visual weight as validation errors.
- **Loading/progress:** subtle indicator while an async action is in-flight (e.g. "Syncing..." next to sync button).

Best for: form saves, field validation, toggle changes, individual actions.

### 2. Top banner (page-level confirmations)

For actions that affect the whole page or aren't tied to a specific field.

- Bold, clearly coloured background: green for success, red for errors, amber for warnings
- Non-overlapping: pushes content down (not an overlay)
- **Persistent until manually dismissed** (click to close) — no auto-dismiss, because users may be looking elsewhere
- Clear close button (x icon)
- Positioned at top of the content area, below the header/nav

Best for: "Products synced successfully", "Page saved", "Email provider connected", navigation-result confirmations, operation outcomes.

### 3. No floating toasts

Remove the floating toast pattern entirely. Between inline feedback and top banners, every use case is covered with better UX.

## Migration plan

### Category 1: Form saves → inline feedback

These should become contextual inline confirmations near the action:

| Current flash | Location | Inline replacement |
|---|---|---|
| "Theme saved successfully" | Theme editor | Green tick next to save button, brief "Saved" label |
| "Email settings saved" | Email settings | Green tick/label near save area |
| "Settings saved" | Provider form | Green tick near save |
| "Navigation saved" | Navigation editor | Green tick near save |
| "Page settings saved" | Page editor | Green tick near save |
| "Metadata updated" | Media library | Green tick on the metadata form |
| "Product updated" | Product show | Green tick near the field that changed |

### Category 2: Validation errors → inline field errors

Already partially in place via changesets, but some are flash-based:

| Current flash | Location | Inline replacement |
|---|---|---|
| "Please enter your API token" | Setup wizard | Red border + error text on the API key field |
| "Missing required fields: {labels}" | Email settings | Red border on each missing field |
| "Please enter your Stripe secret key" | Settings | Red border + error on the Stripe key field |
| "Please fill in all required fields" | Contact form | Red border on each empty required field |
| "Please enter a valid email address" | Newsletter | Red border + error on email field |
| "Please enter your email address" | Various | Red border + error on email field |
| "Password must be at least 12 characters" | Setup recover | Red border + error on password field |
| "Please enter a shop name" / "email address" | Setup | Red border on the relevant field |

### Category 3: State changes → top banner

These are page-level outcomes, best as persistent top banners:

| Current flash | Location | Banner replacement |
|---|---|---|
| "Shop is now live" / "Shop taken offline" | Settings | Green/amber banner at top of settings |
| "Connected to {provider}!" | Provider form | Green banner on the provider page |
| "Email provider disconnected" | Email settings | Amber banner |
| "Stripe connected and webhook endpoint created" | Settings | Green banner |
| "Provider connection deleted" | Providers index | Green banner |
| "Page saved" | Page editor | Green banner |
| "Page deleted" / "Page created" | Pages index | Green banner |

### Category 4: Operation outcomes → top banner

Async or significant operations:

| Current flash | Location | Banner replacement |
|---|---|---|
| "Sync started for {name}" | Providers/settings | Green banner with progress note |
| "Connected! Product sync started in the background." | Setup | Green banner |
| "Submission retry enqueued" | Activity log | Green banner |
| "Image uploaded" / "Image deleted" | Media library | Green banner |
| "Campaign is being sent!" | Newsletter | Green banner |
| "Test email sent to {email}" | Email settings | Green banner |
| "Added to basket" | Shop cart | Inline: brief confirmation near the add button or cart icon update |
| "Removed from basket" | Shop cart | Inline: item visually removed, no separate message needed |
| "Message sent! We'll get back to you soon." | Contact | Green banner above the form (or replace form with success state) |

### Category 5: Auth/system messages → top banner (keep as-is pattern)

These are inherently page-level and work fine as top banners:

| Current flash | Location | Notes |
|---|---|---|
| "Welcome back!" | Login redirect | Green banner on dashboard |
| "Logged out successfully" | Post-logout | Green banner on login page |
| "Invalid email or password" | Login | Could be inline under the form, or red banner |
| "User confirmed successfully" | Email confirm | Green banner |
| "Your basket is empty" | Checkout | Redirect + banner or inline empty state |

### Category 6: Error/failure messages → inline or banner

| Current flash | Replacement |
|---|---|
| "Could not connect — check your API key" | Inline error on the API key field + help link |
| "Stripe connection failed: {message}" | Inline error near Stripe key field |
| "Failed to send test email: {reason}" | Inline error near the test email button |
| "Upload failed" | Inline error near the upload area |
| "Cannot delete — image is still in use" | Red banner with explanation |
| "Something went wrong. Please try again." | Red banner |

## Implementation

### Phase 1: Build the notification components

1. **Inline feedback component** — reusable component that shows success/error state next to any action. Props: status (success/error/loading), message, auto-clear timing (optional, for success only after state persists).
2. **Top banner component** — replaces the current flash component. Pushes content down, persistent until dismissed, coloured by type.
3. **Remove** the existing floating toast CSS/JS.

### Phase 2: Migrate admin forms (highest impact)

Start with the most-used admin pages:
- Theme editor
- Page editor
- Settings
- Email settings
- Provider forms

### Phase 3: Migrate remaining admin pages

- Media library
- Products
- Activity log
- Newsletter
- Redirects
- Navigation

### Phase 4: Migrate shop pages

- Cart (add/remove feedback)
- Contact form
- Checkout errors
- Auth flows (login, registration, confirmation)

### Phase 5: Migrate setup wizard

Update the setup flow (ties into the onboarding-ux v2 plan).

## Task breakdown

| # | Task | Est | Status |
|---|------|-----|--------|
| 1 | Build inline feedback component | 1.5h | planned |
| 2 | Build persistent top banner component (replaces flash) | 1.5h | planned |
| 3 | Migrate admin forms to inline feedback (theme, pages, settings, email, providers) | 3h | planned |
| 4 | Migrate remaining admin pages (media, products, activity, newsletter, redirects, nav) | 2h | planned |
| 5 | Migrate shop pages (cart, contact, checkout, auth) | 2h | planned |
| 6 | Migrate setup wizard notifications | 1h | planned |
| 7 | Remove old flash/toast CSS and JS | 30m | planned |

Total estimate: ~11.5h
