From 93c53f3a1581ce6c62d7aa89d60a91c9a160af54 Mon Sep 17 00:00:00 2001 From: Alex Benzer Date: Fri, 14 Nov 2025 12:20:10 -0800 Subject: [PATCH] Add a composer prompt on home --- src/lib/statsig/gates.ts | 1 + src/logger/metrics.ts | 1 + src/view/com/feeds/FeedComposerPrompt.tsx | 115 ++++++++++++++++++++++ src/view/com/posts/PostFeed.tsx | 20 ++++ 4 files changed, 137 insertions(+) create mode 100644 src/view/com/feeds/FeedComposerPrompt.tsx diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts index aa839542f2..ea263e22e5 100644 --- a/src/lib/statsig/gates.ts +++ b/src/lib/statsig/gates.ts @@ -9,5 +9,6 @@ export type Gate = | 'onboarding_add_video_feed' | 'onboarding_suggested_starterpacks' | 'remove_show_latest_button' + | 'show_composer_prompt' | 'test_gate_1' | 'test_gate_2' diff --git a/src/logger/metrics.ts b/src/logger/metrics.ts index 70ce627fa0..01af4b5afa 100644 --- a/src/logger/metrics.ts +++ b/src/logger/metrics.ts @@ -202,6 +202,7 @@ export type MetricEvents = { 'composer:gif:open': {} 'composer:gif:select': {} + 'postComposer:click': {} // Data events 'account:create:begin': {} diff --git a/src/view/com/feeds/FeedComposerPrompt.tsx b/src/view/com/feeds/FeedComposerPrompt.tsx new file mode 100644 index 0000000000..16f41a7d4b --- /dev/null +++ b/src/view/com/feeds/FeedComposerPrompt.tsx @@ -0,0 +1,115 @@ +import React, {useState} from 'react' +import {Pressable, StyleSheet, View} from 'react-native' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {useOpenComposer} from '#/lib/hooks/useOpenComposer' +import {sanitizeDisplayName} from '#/lib/strings/display-names' +import {sanitizeHandle} from '#/lib/strings/handles' +import {logger} from '#/logger' +import {useCurrentAccountProfile} from '#/state/queries/useCurrentAccountProfile' +import {UserAvatar} from '#/view/com/util/UserAvatar' +import {atoms as a, native, useTheme, web} from '#/alf' +import {SubtleHover} from '#/components/SubtleHover' +import {Text} from '#/components/Typography' + +export function FeedComposerPrompt() { + const {_} = useLingui() + const t = useTheme() + const {openComposer} = useOpenComposer() + const profile = useCurrentAccountProfile() + const [hover, setHover] = useState(false) + + const onPress = React.useCallback(() => { + logger.metric('postComposer:click', {}) + openComposer({}) + }, [openComposer]) + + if (!profile) { + return null + } + + const displayName = sanitizeDisplayName( + profile.displayName || sanitizeHandle(profile.handle), + ) + const handle = sanitizeHandle(profile.handle, '@') + + return ( + setHover(true)} + onPointerLeave={() => setHover(false)} + style={({pressed}) => [ + a.relative, + a.flex_row, + a.align_start, + { + paddingLeft: 18, + paddingRight: 15, + }, + a.py_md, + native({ + paddingTop: 15, + paddingBottom: 15, + }), + { + borderTopWidth: StyleSheet.hairlineWidth, + borderColor: t.atoms.border_contrast_low.borderColor, + }, + web({ + cursor: 'pointer', + outline: 'none', + }), + pressed && web({outline: 'none'}), + ]}> + + + + + + {displayName} + + + {handle} + + + + + {_(msg`What's up?`)} + + + + + ) +} diff --git a/src/view/com/posts/PostFeed.tsx b/src/view/com/posts/PostFeed.tsx index f3b3f1061c..094a0365a3 100644 --- a/src/view/com/posts/PostFeed.tsx +++ b/src/view/com/posts/PostFeed.tsx @@ -69,6 +69,7 @@ import { } from '#/components/feeds/PostFeedVideoGridRow' import {TrendingInterstitial} from '#/components/interstitials/Trending' import {TrendingVideos as TrendingVideosInterstitial} from '#/components/interstitials/TrendingVideos' +import {FeedComposerPrompt} from '../feeds/FeedComposerPrompt' import {DiscoverFallbackHeader} from './DiscoverFallbackHeader' import {FeedShutdownMsg} from './FeedShutdownMsg' import {PostFeedErrorMessage} from './PostFeedErrorMessage' @@ -149,6 +150,10 @@ type FeedRow = type: 'ageAssuranceBanner' key: string } + | { + type: 'composerPrompt' + key: string + } export function getItemsForFeedback(feedRow: FeedRow): { item: FeedPostSliceItem @@ -501,6 +506,18 @@ let PostFeed = ({ 'interstitial2-' + sliceIndex + '-' + lastFetchedAt, }) } + // Add composer prompt for Discover and Following feeds (after trending bar if it exists) + // Feature gate disabled - always show + if ( + hasSession && + (feedUriOrActorDid === DISCOVER_FEED_URI || + feed === 'following') + ) { + arr.push({ + type: 'composerPrompt', + key: 'composerPrompt-' + sliceIndex, + }) + } } else if (sliceIndex === 15) { if (areVideoFeedsEnabled && !trendingVideoDisabled) { arr.push({ @@ -622,6 +639,7 @@ let PostFeed = ({ isEmpty, lastFetchedAt, data, + feed, feedType, feedUriOrActorDid, feedTab, @@ -726,6 +744,8 @@ let PostFeed = ({ return } else if (row.type === 'interstitialTrending') { return + } else if (row.type === 'composerPrompt') { + return } else if (row.type === 'interstitialTrendingVideos') { return } else if (row.type === 'fallbackMarker') {