diff options
author | Alex Benzer <abenzer@users.noreply.github.com> | 2025-08-26 08:52:38 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-08-26 08:52:38 -0700 |
commit | acd7211b357f2bfc74bf0828994e12f0c41d39d5 (patch) | |
tree | 34a09d23bf3862ccb9683ba4975e3af0889c11d0 /src | |
parent | b70e5b2f387e8de6dac5d388aee1ccbf5b217adc (diff) | |
download | voidsky-acd7211b357f2bfc74bf0828994e12f0c41d39d5.tar.zst |
Adds signup CTA tests for logged-out visitors (#8906)
Diffstat (limited to 'src')
-rw-r--r-- | src/components/LoggedOutCTA.tsx | 80 | ||||
-rw-r--r-- | src/lib/statsig/gates.ts | 2 | ||||
-rw-r--r-- | src/screens/PostThread/components/ThreadItemAnchor.tsx | 6 | ||||
-rw-r--r-- | src/screens/PostThread/index.tsx | 3 |
4 files changed, 90 insertions, 1 deletions
diff --git a/src/components/LoggedOutCTA.tsx b/src/components/LoggedOutCTA.tsx new file mode 100644 index 000000000..7ec8c2264 --- /dev/null +++ b/src/components/LoggedOutCTA.tsx @@ -0,0 +1,80 @@ +import {View, type ViewStyle} from 'react-native' +import {Trans} from '@lingui/macro' + +import {type Gate} from '#/lib/statsig/gates' +import {useGate} from '#/lib/statsig/statsig' +import {isWeb} from '#/platform/detection' +import {useSession} from '#/state/session' +import {useLoggedOutViewControls} from '#/state/shell/logged-out' +import {Logo} from '#/view/icons/Logo' +import {atoms as a, useTheme} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import {Text} from '#/components/Typography' + +interface LoggedOutCTAProps { + style?: ViewStyle + gateName: Gate +} + +export function LoggedOutCTA({style, gateName}: LoggedOutCTAProps) { + const {hasSession} = useSession() + const {requestSwitchToAccount} = useLoggedOutViewControls() + const gate = useGate() + const t = useTheme() + + // Only show for logged-out users on web + if (hasSession || !isWeb) { + return null + } + + // Check gate at the last possible moment to avoid counting users as exposed when they won't see the element + if (!gate(gateName)) { + return null + } + + return ( + <View style={[a.pb_md, style]}> + <View + style={[ + a.flex_row, + a.align_center, + a.justify_between, + a.px_lg, + a.py_md, + a.rounded_md, + a.mb_xs, + t.atoms.bg_contrast_25, + ]}> + <View style={[a.flex_row, a.align_center, a.flex_1, a.pr_md]}> + <Logo width={30} style={[a.mr_md]} /> + <View style={[a.flex_1]}> + <Text style={[a.text_lg, a.font_bold, a.leading_snug]}> + <Trans>Join Bluesky</Trans> + </Text> + <Text + style={[ + a.text_md, + a.font_medium, + a.leading_snug, + t.atoms.text_contrast_medium, + ]}> + <Trans>The open social network.</Trans> + </Text> + </View> + </View> + <Button + onPress={() => { + requestSwitchToAccount({requestedAccount: 'new'}) + }} + label="Create account" + size="small" + variant="solid" + color="primary"> + <ButtonText> + <Trans>Create account</Trans> + </ButtonText> + </Button> + </View> + </View> + ) +} diff --git a/src/lib/statsig/gates.ts b/src/lib/statsig/gates.ts index 90ccd3443..114048ab7 100644 --- a/src/lib/statsig/gates.ts +++ b/src/lib/statsig/gates.ts @@ -1,6 +1,8 @@ export type Gate = // Keep this alphabetic please. | 'alt_share_icon' + | 'cta_above_post_heading' + | 'cta_above_post_replies' | 'debug_show_feedcontext' | 'debug_subscriptions' | 'disable_onboarding_policy_update_notice' diff --git a/src/screens/PostThread/components/ThreadItemAnchor.tsx b/src/screens/PostThread/components/ThreadItemAnchor.tsx index 550bddc6a..7b0d567b8 100644 --- a/src/screens/PostThread/components/ThreadItemAnchor.tsx +++ b/src/screens/PostThread/components/ThreadItemAnchor.tsx @@ -40,12 +40,13 @@ import { OUTER_SPACE, REPLY_LINE_WIDTH, } from '#/screens/PostThread/const' -import {atoms as a, useTheme} from '#/alf' +import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {colors} from '#/components/Admonition' import {Button} from '#/components/Button' import {CalendarClock_Stroke2_Corner0_Rounded as CalendarClockIcon} from '#/components/icons/CalendarClock' import {Trash_Stroke2_Corner0_Rounded as TrashIcon} from '#/components/icons/Trash' import {InlineLinkText, Link} from '#/components/Link' +import {LoggedOutCTA} from '#/components/LoggedOutCTA' import {ContentHider} from '#/components/moderation/ContentHider' import {LabelsOnMyPost} from '#/components/moderation/LabelsOnMe' import {PostAlerts} from '#/components/moderation/PostAlerts' @@ -178,6 +179,7 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ const {_, i18n} = useLingui() const {openComposer} = useOpenComposer() const {currentAccount, hasSession} = useSession() + const {gtTablet} = useBreakpoints() const feedFeedback = useFeedFeedback(postSource?.feed, hasSession) const post = postShadow @@ -311,6 +313,8 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ }, isRoot && [a.pt_lg], ]}> + {/* Show CTA for logged-out visitors - hide on desktop and check gate */} + {!gtTablet && <LoggedOutCTA gateName="cta_above_post_heading" />} <View style={[a.flex_row, a.gap_md, a.pb_md]}> <View collapsable={false}> <PreviewableUserAvatar diff --git a/src/screens/PostThread/index.tsx b/src/screens/PostThread/index.tsx index 7432f71db..9cb4173e3 100644 --- a/src/screens/PostThread/index.tsx +++ b/src/screens/PostThread/index.tsx @@ -38,6 +38,7 @@ import { import {atoms as a, native, platform, useBreakpoints, web} from '#/alf' import * as Layout from '#/components/Layout' import {ListFooter} from '#/components/Lists' +import {LoggedOutCTA} from '#/components/LoggedOutCTA' const PARENT_CHUNK_SIZE = 5 const CHILDREN_CHUNK_SIZE = 50 @@ -405,6 +406,8 @@ export function PostThread({uri}: {uri: string}) { onPostSuccess={optimisticOnPostReply} postSource={anchorPostSource} /> + {/* Show CTA for logged-out visitors */} + <LoggedOutCTA style={a.px_lg} gateName="cta_above_post_replies" /> </View> ) } else { |