# Phase 11: Snackbar Notifications **Status**: Pending **Parent**: [primary-plan.md](primary-plan.md) --- ## Goal Replace browser `alert()` calls, silent failures, and inconsistent error handling with a unified snackbar/toast notification system. Every user-triggered action (save, delete, test, etc.) should provide clear visual feedback via a dismissable snackbar that appears at the bottom of the screen. --- ## Design ### Snackbar Types | Type | Color | Icon | Auto-dismiss | Use Case | |---|---|---|---|---| | `success` | Green | `mdiCheckCircle` | 3s | Save, delete, test passed | | `error` | Red | `mdiAlertCircle` | 5s (or manual) | API errors, validation failures | | `info` | Blue | `mdiInformation` | 3s | Status updates, copy-to-clipboard | | `warning` | Amber | `mdiAlert` | 4s | Non-critical issues, deprecation notices | ### Behavior - Appears at bottom-center of viewport, above the mobile nav bar - Stacks vertically (newest on top, max 3 visible) - Slide-up entrance, fade-out exit animation - Manual dismiss via X button on all types - Errors with detail: expandable to show full error message - `position: fixed` with inline styles (per project convention) --- ## Implementation Plan ### Task 1: Create Snackbar Store + Component **Files to create:** - `frontend/src/lib/stores/snackbar.svelte.ts` — reactive store using `$state` - `addSnack(type, message, options?)` — push notification - `removeSnack(id)` — dismiss - `snacks` — reactive array of active notifications - Auto-dismiss timer per snack - `frontend/src/lib/components/Snackbar.svelte` — renders snack stack - Fixed position at bottom-center - Svelte transitions (fly + fade) - Icon per type, dismiss button, optional detail expand - Responsive: full-width on mobile, max-width on desktop ### Task 2: Mount Snackbar in Layout **Files to modify:** - `frontend/src/routes/+layout.svelte` — add `` component (renders globally) ### Task 3: Replace All Alert/Silent Patterns **Files to modify (each page):** | Page | Current Pattern | Replace With | |---|---|---| | `servers/+page.svelte` | `alert()` on error, silent success | `snack.success('Server saved')`, `snack.error(err.message)` | | `trackers/+page.svelte` | `alert()` on error, silent success | `snack.success('Tracker created')`, etc. | | `targets/+page.svelte` | `alert()` on error, silent success | `snack.success('Target saved')`, `snack.error(...)` | | `template-configs/+page.svelte` | `alert()` on error, silent success | `snack.success('Template saved')`, etc. | | `tracking-configs/+page.svelte` | `alert()` on error, silent success | `snack.success('Config saved')`, etc. | | `telegram-bots/+page.svelte` | `alert()` on error, silent success | `snack.success('Bot registered')`, etc. | | `users/+page.svelte` | `alert()` on error, silent success | `snack.success('User updated')`, etc. | | `login/+page.svelte` | `alert()` on error | `snack.error('Invalid credentials')` | ### Task 4: Add i18n Keys **Files to modify:** - `frontend/src/lib/i18n/en.json` — add `snack.*` keys for all messages - `frontend/src/lib/i18n/ru.json` — Russian translations ### Task 5: Add Snackbar to API Helper **Files to create/modify:** - Consider a shared `api.ts` helper that wraps `fetch()` and auto-shows error snackbars on non-2xx responses, reducing boilerplate in each page. --- ## Acceptance Criteria - [ ] Every create/update/delete action shows a success snackbar - [ ] Every API error shows an error snackbar with the server's message - [ ] No remaining `alert()` calls in the codebase - [ ] Snackbars auto-dismiss (success: 3s, error: 5s) - [ ] Snackbars are accessible (role="alert", aria-live) - [ ] Stacking works correctly (max 3, newest on top) - [ ] Animations are smooth (slide-up in, fade out) - [ ] Mobile: snackbar appears above bottom nav bar - [ ] All snackbar messages are i18n'd (EN + RU)