From 430453cbff9b23011e64cc1aec58562d7937d5d3 Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Fri, 5 Dec 2025 17:54:08 +0200 Subject: [PATCH] add intro step --- .../StepFindContactsIntro/index.tsx | 78 +++++++++++++++++++ src/screens/Onboarding/index.tsx | 5 ++ src/screens/Onboarding/state.ts | 21 ++++- 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 src/screens/Onboarding/StepFindContactsIntro/index.tsx diff --git a/src/screens/Onboarding/StepFindContactsIntro/index.tsx b/src/screens/Onboarding/StepFindContactsIntro/index.tsx new file mode 100644 index 0000000000..98bd654131 --- /dev/null +++ b/src/screens/Onboarding/StepFindContactsIntro/index.tsx @@ -0,0 +1,78 @@ +import {View} from 'react-native' +import * as Contacts from 'expo-contacts' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useQuery} from '@tanstack/react-query' + +import {atoms as a, useTheme} from '#/alf' +import {Admonition} from '#/components/Admonition' +import {Button, ButtonText} from '#/components/Button' +import {ContactsHeroImage} from '#/components/contacts/components/HeroImage' +import {InlineLinkText} from '#/components/Link' +import {Text} from '#/components/Typography' +import {OnboardingControls} from '../Layout' +import {useOnboardingInternalState} from '../state' + +export function StepFindContactsIntro() { + const {_} = useLingui() + const t = useTheme() + const {dispatch} = useOnboardingInternalState() + + const {data: isAvailable, isSuccess} = useQuery({ + queryKey: ['contacts-available'], + queryFn: async () => await Contacts.isAvailableAsync(), + }) + + return ( + + + + Bluesky is more fun with Friends + + + + Find your friends on Bluesky by verifying your phone number and + matching with your contacts. We protect your information and you + control what happens next.{' '} + + TODO: Learn more + + + + {!isAvailable && isSuccess && ( + + + Contact sync is not available on this device, as the app is unable + to access your contacts. + + + )} + + + + + + + + + ) +} diff --git a/src/screens/Onboarding/index.tsx b/src/screens/Onboarding/index.tsx index 9513a18043..ed9f43ec06 100644 --- a/src/screens/Onboarding/index.tsx +++ b/src/screens/Onboarding/index.tsx @@ -24,6 +24,7 @@ import {Portal} from '#/components/Portal' import {ScreenTransition} from '#/components/ScreenTransition' import {ENV} from '#/env' import {StepFindContacts} from './StepFindContacts' +import {StepFindContactsIntro} from './StepFindContactsIntro' import {StepSuggestedAccounts} from './StepSuggestedAccounts' import {StepSuggestedStarterpacks} from './StepSuggestedStarterpacks' @@ -67,6 +68,7 @@ export function Onboarding() { key={state.activeStep} direction={state.stepTransitionDirection} style={a.flex_1}> + {/* FindContactsFlow cannot be nested in Layout */} {state.activeStep === 'find-contacts' ? ( ) : ( @@ -79,6 +81,9 @@ export function Onboarding() { {state.activeStep === 'suggested-starterpacks' && ( )} + {state.activeStep === 'find-contacts-intro' && ( + + )} {state.activeStep === 'finished' && } )} diff --git a/src/screens/Onboarding/state.ts b/src/screens/Onboarding/state.ts index 9166952fc0..02a4f8a71f 100644 --- a/src/screens/Onboarding/state.ts +++ b/src/screens/Onboarding/state.ts @@ -11,6 +11,7 @@ type OnboardingScreen = | 'interests' | 'suggested-accounts' | 'suggested-starterpacks' + | 'find-contacts-intro' | 'find-contacts' | 'finished' @@ -47,6 +48,9 @@ export type OnboardingAction = | { type: 'prev' } + | { + type: 'skip-contacts' + } | { type: 'finish' } @@ -82,6 +86,7 @@ export function createInitialOnboardingState( interests: true, 'suggested-accounts': true, 'suggested-starterpacks': starterPacksStepEnabled, + 'find-contacts-intro': findContactsStepEnabled, 'find-contacts': findContactsStepEnabled, finished: true, } @@ -130,11 +135,24 @@ export function reducer( const prevIndex = stepOrder.indexOf(next.activeStep) - 1 const prevStep = stepOrder[prevIndex] if (prevStep) { - next.activeStep = prevStep + // override back behaviour for the find contacts screen + // so returning to the flow takes you to the intro screen + if (prevStep === 'find-contacts') { + next.activeStep = 'find-contacts-intro' + } else { + next.activeStep = prevStep + } } next.stepTransitionDirection = 'Backward' break } + case 'skip-contacts': { + const nextIndex = stepOrder.indexOf('find-contacts') + 1 + const nextStep = stepOrder[nextIndex] ?? 'finished' + next.activeStep = nextStep + next.stepTransitionDirection = 'Forward' + break + } case 'finish': { next = createInitialOnboardingState({ starterPacksStepEnabled: s.screens['suggested-starterpacks'], @@ -187,6 +205,7 @@ function getStepOrder(s: OnboardingState): OnboardingScreen[] { s.screens.interests && ('interests' as const), s.screens['suggested-accounts'] && ('suggested-accounts' as const), s.screens['suggested-starterpacks'] && ('suggested-starterpacks' as const), + s.screens['find-contacts-intro'] && ('find-contacts-intro' as const), s.screens['find-contacts'] && ('find-contacts' as const), s.screens.finished && ('finished' as const), ].filter(x => !!x)