From 089e177b8a605bc7d6ecb23828f7976c136df991 Mon Sep 17 00:00:00 2001 From: Abdullah Date: Tue, 30 Jun 2026 22:49:16 +0530 Subject: [PATCH] fix: handle missing features in feed settings response Normalize feed settings when the API returns a partial body (e.g. on flaky networks) and guard branding_required access in NotificationFeed components. Fixes #1018 Co-authored-by: Cursor --- .changeset/fix-feed-settings-features.md | 7 +++++++ .../src/modules/feed/hooks/useFeedSettings.ts | 10 ++++++++-- .../test/feed/useFeedSettings.test.ts | 20 +++++++++++++++++++ .../NotificationFeed.tsx | 2 +- .../NotificationFeed/NotificationFeed.tsx | 2 +- 5 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 .changeset/fix-feed-settings-features.md diff --git a/.changeset/fix-feed-settings-features.md b/.changeset/fix-feed-settings-features.md new file mode 100644 index 000000000..32c9f7de4 --- /dev/null +++ b/.changeset/fix-feed-settings-features.md @@ -0,0 +1,7 @@ +--- +"@knocklabs/react-core": patch +"@knocklabs/react": patch +"@knocklabs/react-native": patch +--- + +Handle missing `features` in feed settings responses to prevent crashes on partial API responses. diff --git a/packages/react-core/src/modules/feed/hooks/useFeedSettings.ts b/packages/react-core/src/modules/feed/hooks/useFeedSettings.ts index b3a0173f2..598f9db00 100644 --- a/packages/react-core/src/modules/feed/hooks/useFeedSettings.ts +++ b/packages/react-core/src/modules/feed/hooks/useFeedSettings.ts @@ -11,7 +11,7 @@ function useFeedSettings(feedClient: Feed): { settings: FeedSettings | null; loading: boolean; } { - const [settings, setSettings] = useState(null); + const [settings, setSettings] = useState(null); const [isLoading, setIsLoading] = useState(false); // TODO: consider moving this into the feed client and into the feed store state when @@ -29,7 +29,13 @@ function useFeedSettings(feedClient: Feed): { }); if (!response.error) { - setSettings(response.body); + setSettings({ + features: { + branding_required: Boolean( + response.body?.features?.branding_required, + ), + }, + }); } setIsLoading(false); diff --git a/packages/react-core/test/feed/useFeedSettings.test.ts b/packages/react-core/test/feed/useFeedSettings.test.ts index f2d94475a..4730c309e 100644 --- a/packages/react-core/test/feed/useFeedSettings.test.ts +++ b/packages/react-core/test/feed/useFeedSettings.test.ts @@ -55,4 +55,24 @@ describe("useFeedSettings", () => { expect(result.current.settings).toBeNull(); }); + + it("handles partial settings response by defaulting features", async () => { + const { feed, mockApiClient } = createMockFeed("feed_123"); + + mockNetworkSuccess(mockApiClient, {}); + + const { result } = renderHook(() => + useFeedSettings(feed as unknown as Feed), + ); + + await waitFor(() => { + expect(result.current.loading).toBe(false); + }); + + expect(result.current.settings).toEqual({ + features: { + branding_required: false, + }, + }); + }); }); diff --git a/packages/react-native/src/modules/feed/components/NotificationFeedComponents/NotificationFeed.tsx b/packages/react-native/src/modules/feed/components/NotificationFeedComponents/NotificationFeed.tsx index 3e84df321..a7b9c5b8a 100644 --- a/packages/react-native/src/modules/feed/components/NotificationFeedComponents/NotificationFeed.tsx +++ b/packages/react-native/src/modules/feed/components/NotificationFeedComponents/NotificationFeed.tsx @@ -160,7 +160,7 @@ export const NotificationFeed: React.FC = ({ onEndReached={onEndReached} onEndReachedThreshold={0.5} /> - {settings?.features.branding_required && ( + {settings?.features?.branding_required && ( diff --git a/packages/react/src/modules/feed/components/NotificationFeed/NotificationFeed.tsx b/packages/react/src/modules/feed/components/NotificationFeed/NotificationFeed.tsx index bb93ad531..e9a4af704 100644 --- a/packages/react/src/modules/feed/components/NotificationFeed/NotificationFeed.tsx +++ b/packages/react/src/modules/feed/components/NotificationFeed/NotificationFeed.tsx @@ -154,7 +154,7 @@ export const NotificationFeed: React.FC = ({ {!requestInFlight && noItems && EmptyComponent} - {settings?.features.branding_required && ( + {settings?.features?.branding_required && (