Files
haos-hacs-immich-album-watcher/plans/phase-11-snackbar-notifications.md
alexei.dolgolyov e6ff0a423a
All checks were successful
Validate / Hassfest (push) Successful in 3s
Phase 10: Telegram bot commands + Phase 11: Snackbar notifications
Phase 10 — Telegram Bot Commands:
- Add commands_config JSON field to TelegramBot model (enabled cmds,
  default count, response mode, rate limits, locale)
- Create command handler with 14 commands: /status, /albums, /events,
  /summary, /latest, /memory, /random, /search, /find, /person,
  /place, /favorites, /people, /help
- Add search_smart, search_metadata, search_by_person, get_random,
  download_asset, get_asset_thumbnail to ImmichClient
- Auto-register commands with Telegram setMyCommands API (EN+RU)
- Rate limiting per chat per command category
- Media mode: download thumbnails and send as photos to Telegram
- Webhook handler routes /commands before falling through to AI chat
- Frontend: expandable Commands section per bot with checkboxes,
  count/mode/locale settings, rate limit inputs, sync button

Phase 11 — Snackbar Notifications:
- Create snackbar store (snackbar.svelte.ts) with $state rune
- Create Snackbar component with fly/fade transitions, typed colors
- Mount globally in +layout.svelte
- Replace all alert() calls with typed snackbar notifications
- Add success snacks to all CRUD operations across all pages
- 4 types: success (3s), error (5s), info (3s), warning (4s)
- Max 3 visible, auto-dismiss, manual dismiss via X button

Both: Add ~30 i18n keys (EN+RU) for commands UI and snack messages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:39:05 +03:00

97 lines
3.8 KiB
Markdown

# Phase 11: Snackbar Notifications
**Status**: Done
**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 `<Snackbar />` 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)