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 && (
{t("poweredBy") || "Powered by Knock"}