All checks were successful
Validate / Hassfest (push) Successful in 3s
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>
97 lines
3.8 KiB
Markdown
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)
|