[Contacts] Contacts matching flow (#9486)

* add expo-contacts

* add expo-sms

* update copy

* add basic settings screen

* state machine, flow screen

* phone input screen

* otp screen

* tweak spacing

* resend code logic

* add layoutanimationconfig

* check availablility in settings screen

* get contacts

* matches screen

* search, temp setup for matches UI

* add a bunch of number parsing logic with libphonenumber

* cast to looser type

* rename sync to find

FCF (Find Contacts Flow)

* update geolocation hook

* nicer design for settings screen

* add completed state

* up border contrast

* update expo deps

* add pending spinner

* add country whitelist

* add empty state screen

* drop add more functionality

* upload -> import

* fix typo

* fix permission string

* copy updates

* rm envelope icon

* update sms copy

* add inviteinfo component

* woke is back

* [Contacts] NUXes (#9515)

* add a bunch of number parsing logic with libphonenumber

* add banner nux

* add announcement nux

* native only nux

* rm shitty animation

* move isNative check

* [Contacts] Onboarding step (#9489)

* add a bunch of number parsing logic with libphonenumber

* restructure onboarding to better support dynamic screens

* integrate existing flow into onboarding

* add intro step

* lift state up to allow going back freely

* gate onboarding by geo if unsupported country

* add done button to standalone flow

* [Contacts] Add `contact-match` notification type to feed (#9519)

* add a bunch of number parsing logic with libphonenumber

* add contact-joined notif type

* update string, api package

* Update NotificationFeedItem.tsx

* Update NotificationFeedItem.tsx

* Delete SyncContactsFlow.web.tsx

* fix follow back btn for this case

* [Contacts] API integration (#9487)

* api integration for flow

* copy tweak

* tweaks after running it

* wire up status page

* rename toast

* use api lib

* rm temp code

* maybe fix otp error

* clear code on error/resend

* add 1s delay to verify success

* update package versions

* Delete SyncContactsFlow.web.tsx

* try and fix yarn.lock lint

* even woker

* fix uppercase friends

* surfdude feedback

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>

* rm log

* allow resend on invalid code

* Update GetContacts.tsx

* overwrite country code if possible

* fix Apple's Best Feature

* devenv latest

* disable bounces

* interactive keyboard dismiss

* copy changes

* national format

* allow resending immediately

* move success state down a bit

* Update FindContactsSettings.tsx

* [Contacts] More onboarding changes (#9491)

* integrate existing flow into onboarding

* refreshed onboarding styles, rm stepper

* center content on web

* Add back dismiss button for internal onboarding

* Import sort

---------

Co-authored-by: Eric Bailey <git@esb.lol>

* add matches query to shadow

* add clockwise arrow

* update status design, fix dismiss, fix queries

* add metrics

* add more comments

* Update metrics.ts

* refetch both queries on PTR

* fix shadow state in matches page

* reduce empty space at bottom

* show contact info on matches

* filter out contacts without numbers at an earlier stage

* Error handling ✨

* get notifs working

* filter out businesses

* rm log

* remove TODO from learn more links

* try and exclude from web bundle

---------

Co-authored-by: surfdude29 <149612116+surfdude29@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>
This commit is contained in:
Samuel Newman
2025-12-12 20:32:06 +02:00
committed by GitHub
parent d3a6db4594
commit ad7d49ef8f
98 changed files with 4906 additions and 1079 deletions
+21 -25
View File
@@ -19,11 +19,12 @@ import {isCancelledError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {isNative, isWeb} from '#/platform/detection'
import {
DescriptionText,
OnboardingControls,
TitleText,
OnboardingDescriptionText,
OnboardingPosition,
OnboardingTitleText,
} from '#/screens/Onboarding/Layout'
import {Context} from '#/screens/Onboarding/state'
import {useOnboardingInternalState} from '#/screens/Onboarding/state'
import {AvatarCircle} from '#/screens/Onboarding/StepProfile/AvatarCircle'
import {AvatarCreatorCircle} from '#/screens/Onboarding/StepProfile/AvatarCreatorCircle'
import {AvatarCreatorItems} from '#/screens/Onboarding/StepProfile/AvatarCreatorItems'
@@ -32,13 +33,10 @@ import {
type PlaceholderCanvasRef,
} from '#/screens/Onboarding/StepProfile/PlaceholderCanvas'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {Button, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {useSheetWrapper} from '#/components/Dialog/sheet-wrapper'
import {IconCircle} from '#/components/IconCircle'
import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron'
import {CircleInfo_Stroke2_Corner0_Rounded} from '#/components/icons/CircleInfo'
import {StreamingLive_Stroke2_Corner0_Rounded as StreamingLive} from '#/components/icons/StreamingLive'
import {Text} from '#/components/Typography'
import {type AvatarColor, avatarColors, type Emoji, emojiItems} from './types'
@@ -78,7 +76,7 @@ export function StepProfile() {
const creatorControl = Dialog.useDialogControl()
const [error, setError] = React.useState('')
const {state, dispatch} = React.useContext(Context)
const {state, dispatch} = useOnboardingInternalState()
const [avatar, setAvatar] = React.useState<Avatar>({
image: state.profileStepResults?.image,
placeholder: state.profileStepResults.creatorState?.emoji || emojiItems.at,
@@ -237,19 +235,21 @@ export function StepProfile() {
return (
<AvatarContext.Provider value={value}>
<View style={[a.align_start, t.atoms.bg, a.justify_between]}>
<IconCircle icon={StreamingLive} style={[a.mb_2xl]} />
<TitleText>
<Trans>Give your profile a face</Trans>
</TitleText>
<DescriptionText>
<Trans>
Help people know you're not a bot by uploading a picture or creating
an avatar.
</Trans>
</DescriptionText>
<View style={[a.align_start]}>
<View style={[a.gap_sm]}>
<OnboardingPosition />
<OnboardingTitleText>
<Trans>Give your profile a face</Trans>
</OnboardingTitleText>
<OnboardingDescriptionText>
<Trans>
Help people know you're not a bot by uploading a picture or
creating an avatar.
</Trans>
</OnboardingDescriptionText>
</View>
<View
style={[a.w_full, a.align_center, {paddingTop: gtMobile ? 80 : 40}]}>
style={[a.w_full, a.align_center, {paddingTop: gtMobile ? 80 : 60}]}>
<AvatarCircle
openLibrary={openLibrary}
openCreator={creatorControl.open}
@@ -279,7 +279,6 @@ export function StepProfile() {
<View style={[a.gap_md, gtMobile && a.flex_row_reverse]}>
<Button
testID="onboardingContinue"
variant="solid"
color="primary"
size="large"
label={_(msg`Continue to next step`)}
@@ -287,12 +286,10 @@ export function StepProfile() {
<ButtonText>
<Trans>Continue</Trans>
</ButtonText>
<ButtonIcon icon={ChevronRight} position="right" />
</Button>
<Button
testID="onboardingAvatarCreator"
variant="ghost"
color="primary"
color="primary_subtle"
size="large"
label={_(msg`Open avatar creator`)}
onPress={onSecondaryPress}>
@@ -335,7 +332,6 @@ export function StepProfile() {
</View>
<View style={[a.pt_4xl]}>
<Button
variant="solid"
color="primary"
size="large"
label={_(msg`Done`)}