({
children,
maxNumCards,
}: PropsWithChildren<FeedLayoutProviderProps>)
| 123 | } |
| 124 | |
| 125 | export function FeedLayoutProvider({ |
| 126 | children, |
| 127 | maxNumCards, |
| 128 | }: PropsWithChildren<FeedLayoutProviderProps>): ReactElement { |
| 129 | const { sidebarExpanded } = useSettingsContext(); |
| 130 | const { sidebarRendered } = useSidebarRendered(); |
| 131 | const { isPlus } = usePlusSubscription(); |
| 132 | const feedAdTemplateFeature = useConditionalFeature({ |
| 133 | feature: featureFeedAdTemplate, |
| 134 | shouldEvaluate: !isPlus, |
| 135 | }); |
| 136 | |
| 137 | // Debounce sidebar expanded state to sync with sidebar CSS transition |
| 138 | // This prevents the feed layout from jumping mid-animation |
| 139 | const [debouncedSidebarExpanded, setDebouncedSidebarExpanded] = |
| 140 | useState(sidebarExpanded); |
| 141 | |
| 142 | useEffect(() => { |
| 143 | const timer = setTimeout(() => { |
| 144 | setDebouncedSidebarExpanded(sidebarExpanded); |
| 145 | }, SIDEBAR_TRANSITION_DURATION); |
| 146 | |
| 147 | return () => clearTimeout(timer); |
| 148 | }, [sidebarExpanded]); |
| 149 | |
| 150 | const { feedSettings, defaultFeedSettings } = useMemo(() => { |
| 151 | const enhancedFeedSettings = Object.entries(baseFeedSettings).reduce( |
| 152 | (acc, [feedSettingsKey, feedSettingsValue]) => { |
| 153 | acc[feedSettingsKey] = { |
| 154 | ...feedSettingsValue, |
| 155 | adTemplate: |
| 156 | feedAdTemplateFeature.value[feedSettingsKey] || |
| 157 | feedAdTemplateFeature.value.default, |
| 158 | }; |
| 159 | |
| 160 | return acc; |
| 161 | }, |
| 162 | {}, |
| 163 | ) as typeof baseFeedSettings; |
| 164 | |
| 165 | return { |
| 166 | feedSettings: [ |
| 167 | enhancedFeedSettings.desktop, |
| 168 | enhancedFeedSettings.laptopXL, |
| 169 | enhancedFeedSettings.laptopL, |
| 170 | enhancedFeedSettings.laptop, |
| 171 | enhancedFeedSettings.tablet, |
| 172 | ], |
| 173 | defaultFeedSettings: enhancedFeedSettings.default, |
| 174 | }; |
| 175 | }, [feedAdTemplateFeature.value]); |
| 176 | |
| 177 | // Generate the breakpoints for the feed settings |
| 178 | // Uses debounced sidebar state to sync layout change with sidebar animation |
| 179 | const feedBreakpoints = useMemo(() => { |
| 180 | const breakpoints = feedSettings.map((setting) => |
| 181 | setting.breakpoint.replace('@media ', ''), |
| 182 | ); |
nothing calls this directly
no test coverage detected