feat: add Daily Digest and Push Notifications toggles to User Profile with corresponding functionality
Some checks failed
Chore App Build, Test, and Push Docker Images / build-and-push (push) Failing after 2m4s

This commit is contained in:
2026-04-18 23:03:23 -04:00
parent d3ce54a1ff
commit 9efbb455d7
5 changed files with 300 additions and 112 deletions

View File

@@ -191,7 +191,9 @@ email_digest_enabled: boolean;
6. `ParentView` uses vertically stacked `ScrollingList` sections (not tabs). The existing `scrollTo` + `entityType` query params call `scrollToItem()` on the correct list ref, which scrolls the card into view and centers it. After scrolling, apply a temporary pulse/highlight CSS animation (e.g. a 2-second `@keyframes highlight-pulse` using `--item-card-ready-shadow` or `--accent`) to draw the parent's eye to the target card. The animation class should be removed after it completes.
7. **Parent mode timeout — return URL:** When the router guard redirects a non-parent-authenticated user away from a `/parent/...` deep link (e.g. from a notification body tap or email digest redirect), it saves the intended URL to `localStorage['parentReturnUrl']`. `LoginButton` checks for a pending return URL on mount and auto-opens the PIN modal. On successful PIN entry, `consumePendingReturnUrl()` is called and the user is redirected to the saved deep link instead of the default `/parent`. If the parent cancels the PIN modal, `clearPendingReturnUrl()` removes the saved URL so the prompt does not re-appear. The URL is validated to start with `/parent` before saving to prevent open redirect.
8. Existing SSE in-app toast/badge behavior is unchanged — it remains the secondary channel when the tab is active.
9. On `UserProfile.vue`, add an "Email Digest" toggle below the existing action buttons. When toggled, call `PUT /api/user/profile` with `{ email_digest_enabled: <value> }`. Initialize the toggle state from the `GET /api/user/profile` response (which now includes `email_digest_enabled`).
9. On `UserProfile.vue`, add a **Daily Digest** `ToggleField` and a **Push Notifications** `ToggleField` below the email field.
- **Daily Digest**: When toggled, call `PUT /api/user/profile` with `{ email_digest_enabled: <value> }`. Initialize from `GET /api/user/profile` (`email_digest_enabled` field).
- **Push Notifications**: When toggled on, call `subscribeToPushWithResult()` from `pushSubscription.ts`; on `permission_denied` show an inline error message. When toggled off, call `unsubscribeFromPush()`. Initialize by calling `isSubscribedToPush()` in `onMounted`. Disable the toggle (but keep it visible) when `getPushPermissionState() === 'denied'`.
## Frontend Tests
@@ -214,6 +216,13 @@ email_digest_enabled: boolean;
- [x] User Profile page shows an "Email Digest" toggle
- [x] Toggling Email Digest off calls `PUT /api/user/profile` with `email_digest_enabled: false`
- [x] Toggling Email Digest on calls `PUT /api/user/profile` with `email_digest_enabled: true`
- [x] User Profile page shows a "Push Notifications" toggle
- [x] Push Notifications toggle initialises to `true` when the browser already has an active push subscription
- [x] Push Notifications toggle initialises to `false` when no subscription exists
- [x] Toggling Push Notifications on triggers `subscribeToPushWithResult()` and posts subscription to the backend
- [x] Toggling Push Notifications off calls `unsubscribeFromPush()` and removes the subscription from the backend
- [x] Push Notifications toggle is disabled (not hidden) when browser notification permission is `"denied"`
- [x] An inline error message is shown when enabling push notifications is blocked by the browser
---