Repository navigation
fix: group account notifications by feed - #254
Conversation
The Account > Notifications table showed one row per subscription, and subscribing to a feed creates one subscription per notification type, so a single feed was split across several rows. Rows are now grouped by feed, each listing all of that feed's notification types. Global subscriptions (announcements) keep their own row. Row actions apply to every subscription in the row, and feed rows gain a "Notification Settings" entry that opens the existing settings dialog, which was rendered on this page but never reachable. Closes #252 Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
*Lighthouse ran on https://mobilitydatabase-dlnftyg73-mobility-data.vercel.app/ * (Desktop)
*Lighthouse ran on https://mobilitydatabase-dlnftyg73-mobility-data.vercel.app/feeds * (Desktop)
*Lighthouse ran on https://mobilitydatabase-dlnftyg73-mobility-data.vercel.app/feeds/gtfs/mdb-2126 * (Desktop)
*Lighthouse ran on https://mobilitydatabase-dlnftyg73-mobility-data.vercel.app/feeds/gtfs_rt/mdb-2585 * (Desktop)
*Lighthouse ran on https://mobilitydatabase-dlnftyg73-mobility-data.vercel.app/feeds/gbfs/gbfs-flamingo_porirua * (Desktop)
|
…iptions The backend keeps one subscription per (user, notification type) and merges new feeds into it, so deleting a subscription to unsubscribe from one feed also unsubscribed the user from every other feed of that type. This affected the account page row actions, the feed page Unsubscribe button and the notification settings dialog. - Sync UserServiceAPI.yaml and DatabaseCatalogAPI.yaml from mobility-feed-api main and regenerate the user service types, which adds remove_feed_ids to the subscription update request. - Add removeFeedsFromUserSubscription and use it wherever a single feed is unsubscribed. - Drop Pause/Resume from feed rows on the account page: active is per notification type, so one feed cannot be paused on its own. Global rows (announcements) keep it. - Replace rather than append cached subscriptions on subscribe, since the API can return an existing subscription the feed was merged into. Co-Authored-By: Claude Opus 5.5 <[email protected]>
There was a problem hiding this comment.
🟡 Changes recommended
Paused-subscription settings and concurrent unsubscribe handling can leave notification state inconsistent.
3 open issues
What changed in this PR
Addresses #252 by grouping account notifications by feed and limiting unsubscribe actions to the selected feed.
Changes:
- Adds feed-grouped rows and per-feed notification settings.
- Uses targeted feed removal and updates subscription caching.
- Syncs API definitions and adds helper tests.
Applied vercel-react-best-practices (custom).
| File | Description |
|---|---|
| src/app/utils/subscriptionCache.ts | Adds cache update helpers. |
| src/app/utils/subscriptionCache.spec.ts | Tests cache helpers. |
| src/app/services/user-service-api-types.ts | Updates generated subscription types. |
| src/app/services/notification-service.ts | Adds targeted feed removal. |
| src/app/screens/Feed/components/NotificationSettingsDialog.tsx | Removes only the selected feed. |
| src/app/screens/Feed/components/ClientSubscribeControls.tsx | Updates unsubscribe and cache handling. |
| src/app/[locale]/account/notifications/lib/groupSubscriptions.ts | Groups subscriptions by feed. |
| src/app/[locale]/account/notifications/lib/groupSubscriptions.spec.ts | Tests grouping and titles. |
| src/app/[locale]/account/notifications/AccountNotifications.tsx | Renders feed rows and settings actions. |
| external_types/UserServiceAPI.yaml | Syncs subscription API contracts. |
| external_types/DatabaseCatalogAPI.yaml | Syncs validation-history definitions. |
Review effort: Balanced
Address review feedback on the per-feed subscription actions: - Initialize the notification settings checkboxes from feed membership rather than `active`, so a paused type can still be unchecked and the feed removed from it (account page and feed page). - Add settleAll, which waits for every request before rejecting, and use it for multi-request updates so the resync after a partial failure sees every completed request. The settings dialog now resyncs after a partial failure too. - Disable account page row actions while an update is in flight: feeds share subscriptions, and overlapping mutations on the same SWR key could restore a row that was already removed. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
Important to highlight: The way the backend is setup, we cannot offer the 'pause' action on a per feed basis, only on the notification type as a whole |
|
Important to highlight: The date we display on the table is for the subscription as a whole, but we display the notifications grouped by feed. Would it be possible to get a Another alternative is to just remove the dates all together |
Drop the Subscribed column and its sort option from the account notifications table, along with the now-unused createdAt field on grouped rows and its unit test. Co-Authored-By: Claude Opus 5.5 <[email protected]>
|
LGTM! Thanks for making this improvement |

Closes #252
Problem
The Account > Notifications table showed one row per subscription. The backend keeps a single subscription per (user, notification type) and merges every subscribed feed into it, so the page listed one row per type with all of its feeds joined into the title.
Testing on the preview also showed a related bug: deleting a subscription to unsubscribe from one feed unsubscribed the user from every feed of that type. This affected the feed page's Unsubscribe button and the notification settings dialog.
Changes
account/notifications/lib/groupSubscriptions.ts, with unit tests.PATCH /v1/user/subscriptions/{id}withremove_feed_ids(newremoveFeedsFromUserSubscription). The backend deletes the subscription when its last feed is removed.activeis per notification type, so a single feed can't be paused. Feed rows show Notification Settings and Unsubscribe; Pause/Resume stays on global rows such as Announcements.NotificationSettingsDialog, which was rendered on this page but couldn't be opened.external_types/UserServiceAPI.yamlandDatabaseCatalogAPI.yamlare copied frommobility-feed-apimain, and the user service types are regenerated withyarn generate:user-api-types. The catalog types (feeds/types.ts) regenerate identically, so only the YAML copy changed there.utils/subscriptionCache.ts, with unit tests.Row status is Active if any of the feed's subscriptions is active.
Testing
yarn lint: 0 errorsyarn test:ci: 541/541 passnpx tsc --noEmit: clean🤖 Generated with Claude Code