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)