feat: subscribe actions feed url update - #177
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR adds real notification subscription functionality (feed-scoped subscriptions like feed.url_updated) and updates the user-service OpenAPI types accordingly, while also refactoring user feature flags to a client-only SWR-based model (removing the previous cookie + server action + BroadcastChannel approach).
Changes:
- Implement notification subscription CRUD via a new
notification-serviceand wire it into feed pages (ClientSubscribeControls/NotificationSettingsDialog) and the account notifications table. - Extend user-service OpenAPI types/schema for subscription feed metadata (
feeds) and create request feed targeting (feed_ids), and update generated TS types. - Migrate user feature flags to a client-only SWR hook (
useUserFeatureFlags) with cache seeding from auth sagas; remove themd_featurescookie route/action/provider and update docs/tests.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/app/utils/notificationTypes.ts | Defines notification type metadata and feed-scoped type lists. |
| src/app/store/saga/auth-saga.ts | Seeds SWR feature-flag cache after login/signup/provider login; removes feature-flag BroadcastChannel logic. |
| src/app/services/user-service-api-types.ts | Updates generated OpenAPI TS types for subscriptions (descriptions, feeds, feed_ids, etc.). |
| src/app/services/user-feature-flag-service.ts | Adds SWR cache fetch/revalidate/seed utilities for per-user feature flags. |
| src/app/services/session-service.ts | Removes legacy feature-flag cookie write/refresh helpers. |
| src/app/services/notification-service.ts | Adds typed client for subscription CRUD endpoints with auth middleware. |
| src/app/services/channel-service.ts | Removes feature-flags channel + same-tab broadcast helper. |
| src/app/screens/Feed/FeedView.tsx | Passes feed id into ClientSubscribeControls. |
| src/app/screens/Feed/components/NotificationSettingsDialog.tsx | Implements real subscription settings persistence via SWR mutation. |
| src/app/screens/Feed/components/ClientSubscribeControls.tsx | Implements subscribe/unsubscribe + optimistic updates + entitlement gating. |
| src/app/providers.tsx | Removes feature-flag provider; mounts UserFeatureFlagsSync. |
| src/app/hooks/useUserFeatureFlags.ts | Adds client-only SWR hook with isResolved and Cypress exposure. |
| src/app/context/UserFeatureFlagProvider.tsx | Removes legacy context-based feature flags implementation. |
| src/app/components/UserFeatureFlagsSync.tsx | Mounts useUserFeatureFlags() globally to warm cache and expose Cypress globals. |
| src/app/components/AuthSessionProvider.tsx | Adds uid + isAuthResolved; revalidates flags on session renewal. |
| src/app/components/AuthSessionProvider.spec.tsx | Mocks feature-flag revalidation service for the updated provider. |
| src/app/api/session/route.ts | Stops deleting the removed md_features cookie on logout. |
| src/app/api/feature-flags/route.ts | Removes legacy cookie-signing feature-flags API route. |
| src/app/actions/feature-flags.ts | Removes legacy server action for reading md_features. |
| src/app/[locale]/layout.tsx | Stops server-seeding feature flags into Providers; keeps only messages + remote config. |
| src/app/[locale]/account/notifications/AccountNotifications.tsx | Replaces mock UI with real subscriptions table, sorting, and actions. |
| messages/fr.json | Adds i18n strings for subscription UX + notification type labels/tooltips. |
| messages/en.json | Adds i18n strings for subscription UX + notification type labels/tooltips. |
| external_types/UserServiceAPI.yaml | Updates OpenAPI spec for subscriptions (descriptions, feeds, feed_ids, removes 501). |
| docs/user-feature-flags.md | Updates documentation to reflect the client-only SWR architecture. |
| cypress/e2e/userFeatureFlags.cy.ts | Reworks e2e coverage for the new client-only feature flag design (no cookie). |
| CLAUDE.md | Updates repo guidance to match the new feature-flag architecture and server/client boundary. |
Suppressed comments (1)
src/app/screens/Feed/components/NotificationSettingsDialog.tsx:137
- applySettingsChange() is awaited via .then(...) but has no .catch(). If it rejects, it will surface as an unhandled promise rejection (and
saveErroralone doesn't prevent that). Add a catch handler (even if it only keeps the dialog open).
applySettingsChange({ addedTypes, removedTypes })
.then(() => {
onSave({ changeTypes });
});
| const handleChangeTypeToggle = (value: string): void => { | ||
| if (value === 'any') { | ||
| setChangeTypes( | ||
| changeTypes.includes('any') ? [] : ['any', ...SPECIFIC_TYPES], | ||
| ); | ||
| } else { | ||
| if (changeTypes.includes(value)) { | ||
| // Remove the type and "any" (partial selection invalidates "any") | ||
| setChangeTypes(changeTypes.filter((t) => t !== value && t !== 'any')); | ||
| } else { | ||
| const withNew = changeTypes.filter((t) => t !== 'any').concat(value); | ||
| // Auto-select "any" when all specific types are checked | ||
| const allSpecificSelected = SPECIFIC_TYPES.every((t) => | ||
| withNew.includes(t), | ||
| ); | ||
| setChangeTypes(allSpecificSelected ? ['any', ...withNew] : withNew); | ||
| } | ||
| setChangeTypes( | ||
| changeTypes.includes(value) | ||
| ? changeTypes.filter((t) => t !== value) | ||
| : [...changeTypes, value], | ||
| ); | ||
| }; |
| {index > 0 && ', '} | ||
| <Link | ||
| component={LocaleLink} | ||
| href={`/feeds/${feed.data_type != null && feed.data_type !== "" ? feed.data_type + "/" : ""}${feed.feed_id}`} |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
*Lighthouse ran on https://mobilitydatabase-gxkc7jg7t-mobility-data.vercel.app/ * (Desktop)
*Lighthouse ran on https://mobilitydatabase-gxkc7jg7t-mobility-data.vercel.app/feeds * (Desktop)
*Lighthouse ran on https://mobilitydatabase-gxkc7jg7t-mobility-data.vercel.app/feeds/gtfs/mdb-2126 * (Desktop)
*Lighthouse ran on https://mobilitydatabase-gxkc7jg7t-mobility-data.vercel.app/feeds/gtfs_rt/mdb-2585 * (Desktop)
*Lighthouse ran on https://mobilitydatabase-gxkc7jg7t-mobility-data.vercel.app/feeds/gbfs/gbfs-flamingo_porirua * (Desktop)
|
Summary:
Closes #171
Expected behavior:
Not logged in user
Logged in user without permissions
Logged in and has permissions
Testing tips:
(Ask or set yourself permission to get access to notifications)
Go to a feed, subscribe to it
See it in your account/notifications
Unsubscribe to it
Why user based feature flag changed to client only architecture
The user based feature flags were initially designed to be available in server side through a cookie and client side through a react context. After testing, an edge case was discovered that if the user starts on a static only page (ex: landing page) the initial feature flags would never be set. There were work arounds, but the complexity of accommodating both server and client feature flags was rising and not worth it. Using SWR, we implemented a client only pattern that manages the state of the user feature flags in an effective simple way
Please make sure these boxes are checked before submitting your pull request - thanks!
yarn testto make sure you didn't break anythingNot logged in state


Logged in with no access state

Logged in with access state




