From 7b6698de8c2ba000677a8fa0881923347c18c1a2 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 14 Jan 2026 10:32:22 -0600 Subject: [PATCH] Handle previews --- src/App.native.tsx | 92 +++++++++---------- src/App.web.tsx | 84 ++++++++--------- ...verFeedLiveEventFeedsAndTrendingBanner.tsx | 29 +++--- .../components/LiveEventFeedCardWide.tsx | 11 ++- src/features/liveEvents/context.tsx | 43 ++++++++- src/lib/hooks/useIsBskyTeam.ts | 8 ++ src/lib/statsig/gates.ts | 1 + 7 files changed, 156 insertions(+), 112 deletions(-) create mode 100644 src/lib/hooks/useIsBskyTeam.ts diff --git a/src/App.native.tsx b/src/App.native.tsx index 02f0179906..2c4d6fa413 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -146,49 +146,51 @@ function InnerApp() { - - - - {/* LabelDefsProvider MUST come before ModerationOptsProvider */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + {/* LabelDefsProvider MUST come before ModerationOptsProvider */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -235,9 +237,7 @@ function App() { - - - + diff --git a/src/App.web.tsx b/src/App.web.tsx index d31bb56010..460d9ff174 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -122,45 +122,47 @@ function InnerApp() { - - - - {/* LabelDefsProvider MUST come before ModerationOptsProvider */} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + {/* LabelDefsProvider MUST come before ModerationOptsProvider */} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -203,9 +205,7 @@ function App() { - - - + diff --git a/src/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner.tsx b/src/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner.tsx index 4ba392abac..d2decb6df4 100644 --- a/src/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner.tsx +++ b/src/features/liveEvents/components/DiscoverFeedLiveEventFeedsAndTrendingBanner.tsx @@ -12,26 +12,15 @@ import { LiveEventFeedOptionsMenu, useDialogControl, } from '#/features/liveEvents/components/LiveEventFeedOptionsMenu' -import {useLiveEvents} from '#/features/liveEvents/context' -import {useLiveEventPreferences} from '#/features/liveEvents/preferences' +import {useUserPreferencedLiveEvents} from '#/features/liveEvents/context' +import {type LiveEventFeed} from '#/features/liveEvents/types' export function DiscoverFeedLiveEventFeedsAndTrendingBanner() { - const t = useTheme() - const {_} = useLingui() - const events = useLiveEvents() + const events = useUserPreferencedLiveEvents() const {rightNavVisible} = useLayoutBreakpoints() const {trendingDisabled} = useTrendingSettings() - const optionsMenuControl = useDialogControl() - const {data, isLoading} = useLiveEventPreferences() - // user prefs should be loaded by now, but for TS-sake - if (isLoading) return null - - const {hideAllFeeds, hiddenFeedIds} = data - const feed = events.feeds.at(0) - const feedHidden = feed?.id ? hiddenFeedIds.includes(feed?.id || '') : false - - if (!feed || hideAllFeeds || feedHidden) { + if (!events.feeds.length) { if (!rightNavVisible && !trendingDisabled) { // only show trending on mobile when live event banner is not shown return @@ -44,7 +33,13 @@ export function DiscoverFeedLiveEventFeedsAndTrendingBanner() { // On desktop, we show in the sidebar if (rightNavVisible) return null - const image = feed.images.wide + return events.feeds.map(feed => ) +} + +function Inner({feed}: {feed: LiveEventFeed}) { + const t = useTheme() + const {_} = useLingui() + const optionsMenuControl = useDialogControl() return ( <> @@ -76,7 +71,7 @@ export function DiscoverFeedLiveEventFeedsAndTrendingBanner() { { // Validated in multiple places on the backend if (isBskyCustomFeedUrl(feed.url)) { @@ -106,16 +107,20 @@ export function LiveEventFeedCardWide({ style={[ a.leading_snug, gtPhone ? a.text_xs : a.text_2xs, - {color: 'white', opacity: 0.8}, + {color: textColor, opacity: 0.8}, ]}> - Happening now + {feed.preview ? ( + Preview + ) : ( + Happening now + )} {feed.title} diff --git a/src/features/liveEvents/context.tsx b/src/features/liveEvents/context.tsx index 4cd8520962..05e44620cd 100644 --- a/src/features/liveEvents/context.tsx +++ b/src/features/liveEvents/context.tsx @@ -1,12 +1,19 @@ import {createContext, useContext} from 'react' import {QueryClient, useQuery} from '@tanstack/react-query' +import {useIsBskyTeam} from '#/lib/hooks/useIsBskyTeam' import {IS_DEV, LIVE_EVENTS_URL} from '#/env' +import {useLiveEventPreferences} from '#/features/liveEvents/preferences' import {type LiveEventsWorkerResponse} from '#/features/liveEvents/types' +import {useDevMode} from '#/storage/hooks/dev-mode' const qc = new QueryClient() const liveEventsQueryKey = ['live-events'] +export const DEFAULT_LIVE_EVENTS = { + feeds: [], +} + async function fetchLiveEvents(): Promise { try { const res = await fetch(`${LIVE_EVENTS_URL}/config`) @@ -18,17 +25,29 @@ async function fetchLiveEvents(): Promise { } } -const Context = createContext({ - feeds: [], -}) +const Context = createContext(DEFAULT_LIVE_EVENTS) export function Provider({children}: React.PropsWithChildren<{}>) { + const [isDevMode] = useDevMode() + const isBskyTeam = useIsBskyTeam() const {data} = useQuery( { staleTime: IS_DEV ? 5e3 : 1000 * 60, queryKey: liveEventsQueryKey, async queryFn() { - return fetchLiveEvents() + const events = await fetchLiveEvents() + if (!events) return null + const feeds = events.feeds.filter(f => { + if (f.preview && !isBskyTeam) { + return false + } + return true + }) + return { + ...events, + // only one at a time for now, unless bsky team and dev mode + feeds: isBskyTeam && isDevMode ? feeds : feeds.slice(0, 1), + } }, }, qc, @@ -53,3 +72,19 @@ export function useLiveEvents() { } return ctx } + +export function useUserPreferencedLiveEvents() { + const events = useLiveEvents() + const {data, isLoading} = useLiveEventPreferences() + if (isLoading) return DEFAULT_LIVE_EVENTS + const {hideAllFeeds, hiddenFeedIds} = data + return { + ...events, + feeds: hideAllFeeds + ? [] + : events.feeds.filter(f => { + const hidden = f?.id ? hiddenFeedIds.includes(f?.id || '') : false + return !hidden + }), + } +} diff --git a/src/lib/hooks/useIsBskyTeam.ts b/src/lib/hooks/useIsBskyTeam.ts new file mode 100644 index 0000000000..d653e7fd5e --- /dev/null +++ b/src/lib/hooks/useIsBskyTeam.ts @@ -0,0 +1,8 @@ +import {useMemo} from 'react' + +import {useGate} from '#/lib/statsig/statsig' + +export function useIsBskyTeam() { + const gate = useGate() + return useMemo(() => gate('is_bsky_team_member'), [gate]) +} diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts index 357548d3b1..dcb330764c 100644 --- a/src/lib/statsig/gates.ts +++ b/src/lib/statsig/gates.ts @@ -7,6 +7,7 @@ export type Gate = | 'disable_settings_find_contacts' | 'explore_show_suggested_feeds' | 'feed_reply_button_open_thread' + | 'is_bsky_team_member' // special, do not remove | 'old_postonboarding' | 'onboarding_add_video_feed' | 'onboarding_suggested_starterpacks'