Add progress guide interstitial, put behind gate

This commit is contained in:
Paul Frazee
2024-07-02 22:33:19 -07:00
parent 9c5420c0b2
commit db5cf919dc
6 changed files with 96 additions and 38 deletions
+24
View File
@@ -6,6 +6,7 @@ import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useNavigation} from '@react-navigation/native'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {NavigationProp} from '#/lib/routes/types'
import {logEvent} from '#/lib/statsig/statsig'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
@@ -20,6 +21,7 @@ import {PersonPlus_Stroke2_Corner0_Rounded as Person} from '#/components/icons/P
import {InlineLinkText} from '#/components/Link'
import * as ProfileCard from '#/components/ProfileCard'
import {Text} from '#/components/Typography'
import {ProgressGuideList} from './ProgressGuide/List'
function CardOuter({
children,
@@ -352,3 +354,25 @@ export function SuggestedFeeds() {
</View>
)
}
export function ProgressGuide() {
const t = useTheme()
const {isDesktop} = useWebMediaQueries()
if (isDesktop) {
return null
}
return (
<View
style={[
a.border_t,
t.atoms.border_contrast_low,
a.px_lg,
a.py_lg,
a.pb_lg,
]}>
<ProgressGuideList />
</View>
)
}
+2 -2
View File
@@ -13,7 +13,7 @@ import {TimesLarge_Stroke2_Corner0_Rounded as Times} from '#/components/icons/Ti
import {Text} from '#/components/Typography'
import {ProgressGuideTask} from './Task'
export function ProgressGuideList({style}: {style: StyleProp<ViewStyle>}) {
export function ProgressGuideList({style}: {style?: StyleProp<ViewStyle>}) {
const t = useTheme()
const {_} = useLingui()
const guide = useProgressGuide('like-10-and-follow-7')
@@ -27,7 +27,7 @@ export function ProgressGuideList({style}: {style: StyleProp<ViewStyle>}) {
style={[
t.atoms.text_contrast_medium,
a.font_semibold,
a.text_xs,
a.text_sm,
{textTransform: 'uppercase'},
]}>
<Trans>Get started</Trans>
+17 -20
View File
@@ -6,44 +6,41 @@ import {atoms as a, useTheme} from '#/alf'
import {AnimatedCheck} from '../anim/AnimatedCheck'
import {Text} from '../Typography'
export interface ProgressGuideTaskProps {
current: number
total: number
title: string
subtitle?: string
}
export function ProgressGuideTask({
current,
total,
title,
subtitle,
}: ProgressGuideTaskProps) {
}: {
current: number
total: number
title: string
subtitle?: string
}) {
const t = useTheme()
return (
<View style={[a.flex_row, a.gap_sm, !subtitle && a.align_center]}>
<View style={[a.flex_row, a.gap_md, !subtitle && a.align_center]}>
{current === total ? (
<AnimatedCheck playOnMount fill={t.palette.primary_500} width={16} />
<AnimatedCheck playOnMount fill={t.palette.primary_500} width={24} />
) : (
<Progress.Circle
progress={current / total}
color={t.palette.primary_400}
size={16}
size={24}
thickness={2}
borderWidth={0}
unfilledColor={t.palette.contrast_50}
/>
)}
<View style={[a.flex_col, a.gap_md]}>
<View style={[a.flex_col, a.gap_xs]}>
<Text style={[a.text_sm, a.font_semibold]}>{title}</Text>
{subtitle && (
<Text style={[a.text_xs, t.atoms.text_contrast_medium]}>
{subtitle}
</Text>
)}
</View>
<View style={[a.flex_col, a.gap_xs]}>
<Text style={[a.text_md, a.font_semibold]}>{title}</Text>
{subtitle && (
<Text style={[a.text_sm, t.atoms.text_contrast_medium]}>
{subtitle}
</Text>
)}
</View>
</View>
)
+1
View File
@@ -7,5 +7,6 @@ export type Gate =
| 'show_avi_follow_button'
| 'show_follow_back_label_v2'
| 'new_user_guided_tour'
| 'new_user_progress_guide'
| 'suggested_feeds_interstitial'
| 'suggested_follows_interstitial'
+7 -7
View File
@@ -2,6 +2,7 @@ import React from 'react'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useGate} from '#/lib/statsig/statsig'
import {
ProgressGuideToast,
ProgressGuideToastRef,
@@ -55,14 +56,10 @@ export function useProgressGuideControls() {
export function Provider({children}: React.PropsWithChildren<{}>) {
const {_} = useLingui()
const {mutate} = useSetActiveProgressGuideMutation()
const gate = useGate()
const [activeProgressGuide, setActiveProgressGuide] =
React.useState<ProgressGuide>({
guide: 'like-10-and-follow-7',
numLikes: 0,
numFollows: 0,
isComplete: false,
})
React.useState<ProgressGuide>(undefined)
const firstLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null)
const fifthLikeToastRef = React.useRef<ProgressGuideToastRef | null>(null)
@@ -71,6 +68,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
const controls = React.useMemo(() => {
return {
startProgressGuide(guide: ProgressGuideName) {
if (!gate('new_user_progress_guide')) {
return
}
if (guide === 'like-10-and-follow-7') {
const guideObj = {
guide: 'like-10-and-follow-7',
@@ -127,7 +127,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
setActiveProgressGuide(guide)
},
}
}, [activeProgressGuide, setActiveProgressGuide, mutate])
}, [activeProgressGuide, setActiveProgressGuide, mutate, gate])
return (
<ProgressGuideContext.Provider value={activeProgressGuide}>
+45 -9
View File
@@ -34,7 +34,11 @@ import {useSession} from '#/state/session'
import {useAnalytics} from 'lib/analytics/analytics'
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
import {useTheme} from 'lib/ThemeContext'
import {SuggestedFeeds, SuggestedFollows} from '#/components/FeedInterstitials'
import {
ProgressGuide,
SuggestedFeeds,
SuggestedFollows,
} from '#/components/FeedInterstitials'
import {List, ListRef} from '../util/List'
import {PostFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
@@ -85,14 +89,36 @@ type FeedItem =
}
slot: number
}
| {
type: 'interstitialProgressGuide'
key: string
params: {
variant: 'default' | string
}
slot: number
}
const feedInterstitialType = 'interstitialFeeds'
const followInterstitialType = 'interstitialFollows'
const progressGuideInterstitialType = 'interstitialProgressGuide'
const interstials: Record<
'following' | 'discover',
(FeedItem & {type: 'interstitialFeeds' | 'interstitialFollows'})[]
(FeedItem & {
type:
| 'interstitialFeeds'
| 'interstitialFollows'
| 'interstitialProgressGuide'
})[]
> = {
following: [
{
type: progressGuideInterstitialType,
params: {
variant: 'default',
},
key: progressGuideInterstitialType,
slot: 0,
},
{
type: followInterstitialType,
params: {
@@ -111,6 +137,14 @@ const interstials: Record<
},
],
discover: [
{
type: progressGuideInterstitialType,
params: {
variant: 'default',
},
key: progressGuideInterstitialType,
slot: 0,
},
{
type: feedInterstitialType,
params: {
@@ -336,14 +370,14 @@ let Feed = ({
if (feedType) {
for (const interstitial of interstials[feedType]) {
const feedInterstitialEnabled =
interstitial.type === feedInterstitialType &&
gate('suggested_feeds_interstitial')
const followInterstitialEnabled =
interstitial.type === followInterstitialType &&
gate('suggested_follows_interstitial')
const shouldShow =
(interstitial.type === feedInterstitialType &&
gate('suggested_feeds_interstitial')) ||
(interstitial.type === followInterstitialType &&
gate('suggested_follows_interstitial')) ||
interstitial.type === progressGuideInterstitialType
if (feedInterstitialEnabled || followInterstitialEnabled) {
if (shouldShow) {
const variant = 'default' // replace with experiment variant
const int = {
...interstitial,
@@ -460,6 +494,8 @@ let Feed = ({
return <SuggestedFeeds />
} else if (item.type === followInterstitialType) {
return <SuggestedFollows />
} else if (item.type === progressGuideInterstitialType) {
return <ProgressGuide />
} else if (item.type === 'slice') {
if (item.slice.rootUri === FALLBACK_MARKER_POST.post.uri) {
// HACK