Skip to content

Commit

Permalink
feat: toggle C and B' flow
Browse files Browse the repository at this point in the history
Signed-off-by: Berend Sliedrecht <[email protected]>
  • Loading branch information
Berend Sliedrecht committed Aug 19, 2024
1 parent 0fddea5 commit 4004465
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 268 deletions.
2 changes: 1 addition & 1 deletion apps/ausweis/src/crypto/bPrime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import {
TypedArrayEncoder,
getJwkFromKey,
} from '@credo-ts/core'
import type { FullAppAgent } from '@package/agent/src'
import { kdf } from '@package/secure-store/kdf'
import type { FullAppAgent } from 'packages/agent/src'
import { ausweisAes256Gcm } from './aes'

/**
Expand Down
81 changes: 53 additions & 28 deletions apps/ausweis/src/features/onboarding/onboardingContext.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { sendCommand } from '@animo-id/expo-ausweis-sdk'
import { type AppAgent, initializeAppAgent, useSecureUnlock } from '@ausweis/agent'
import { ReceivePidUseCaseBPrimeFlow } from '@ausweis/use-cases/ReceivePidUseCaseBPrimeFlow'
import {
type CardScanningErrorDetails,
ReceivePidUseCaseCFlow,
Expand All @@ -22,7 +23,6 @@ import { OnboardingIdCardStartScan } from './screens/id-card-start-scan'
import { OnboardingIntroductionSteps } from './screens/introduction-steps'
import OnboardingPinEnter from './screens/pin'
import OnboardingWelcome from './screens/welcome'
import { ReceivePidUseCaseBPrimeFlow } from '@ausweis/use-cases/ReceivePidUseCaseBPrimeFlow'

type Page =
| { type: 'fullscreen' }
Expand All @@ -35,7 +35,7 @@ type Page =

// Same animation key means the content won't fade out and then in again. So if the two screens have most content in common
// this looks nicer.
const onboardingStepsCFlow = [
const onboardingSteps = [
{
step: 'welcome',
progress: 0,
Expand Down Expand Up @@ -147,7 +147,7 @@ const onboardingStepsCFlow = [
Screen: React.FunctionComponent<any>
}>

export type OnboardingSteps = typeof onboardingStepsCFlow
export type OnboardingSteps = typeof onboardingSteps
export type OnboardingStep = OnboardingSteps[number]

export type OnboardingContext = {
Expand All @@ -164,15 +164,16 @@ export function OnboardingContextProvider({
children,
}: PropsWithChildren<{
initialStep?: OnboardingStep['step']
flow?: 'c' | 'bprime'
}>) {
const toast = useToastController()
const secureUnlock = useSecureUnlock()
const [currentStepName, setCurrentStepName] = useState<OnboardingStep['step']>(initialStep ?? 'welcome')
const router = useRouter()

const [selectedFlow, setSelectedFlow] = useState<'c' | 'bprime'>('c')
const [receivePidUseCase, setReceivePidUseCase] = useState<ReceivePidUseCaseCFlow | ReceivePidUseCaseBPrimeFlow>()
const [receivePidUseCaseState, setReceivePidUseCaseState] = useState<ReceivePidUseCaseState | 'initializing'>()

const [walletPin, setWalletPin] = useState<string>()
const [idCardPin, setIdCardPin] = useState<string>()
const [userName, setUserName] = useState<string>()
Expand All @@ -189,12 +190,12 @@ export function OnboardingContextProvider({
showScanModal: true,
})

const currentStep = onboardingStepsCFlow.find((step) => step.step === currentStepName)
const currentStep = onboardingSteps.find((step) => step.step === currentStepName)
if (!currentStep) throw new Error(`Invalid step ${currentStepName}`)

const goToNextStep = useCallback(() => {
const currentStepIndex = onboardingStepsCFlow.findIndex((step) => step.step === currentStepName)
const nextStep = onboardingStepsCFlow[currentStepIndex + 1]
const currentStepIndex = onboardingSteps.findIndex((step) => step.step === currentStepName)
const nextStep = onboardingSteps[currentStepIndex + 1]

if (nextStep) {
setCurrentStepName(nextStep.step)
Expand All @@ -205,8 +206,8 @@ export function OnboardingContextProvider({
}, [currentStepName, router])

const goToPreviousStep = useCallback(() => {
const currentStepIndex = onboardingStepsCFlow.findIndex((step) => step.step === currentStepName)
const previousStep = onboardingStepsCFlow[currentStepIndex - 1]
const currentStepIndex = onboardingSteps.findIndex((step) => step.step === currentStepName)
const previousStep = onboardingSteps[currentStepIndex - 1]

if (previousStep) {
setCurrentStepName(previousStep.step)
Expand All @@ -218,6 +219,12 @@ export function OnboardingContextProvider({
goToNextStep()
}

const selectFlow = (flow: 'c' | 'bprime') => {
setSelectedFlow(flow)

goToNextStep()
}

// Bit sad but if we try to call this in the initializeAgent callback sometimes the state hasn't updated
// in the secure unlock yet, which means that it will throw an error, so we use an effect. Probably need
// to do a refactor on this and move more logic outside of the react world, as it's a bit weird with state
Expand Down Expand Up @@ -343,26 +350,42 @@ export function OnboardingContextProvider({
}

if (!receivePidUseCase && receivePidUseCaseState !== 'initializing') {
return ReceivePidUseCaseCFlow.initialize({
agent: secureUnlock.context.agent,
onStateChange: setReceivePidUseCaseState,
onCardAttachedChanged: ({ isCardAttached }) =>
setIdCardScanningState((state) => ({
...state,
isCardAttached,
state: state.state === 'readyToScan' && isCardAttached ? 'scanning' : state.state,
})),
onStatusProgress: ({ progress }) => setIdCardScanningState((state) => ({ ...state, progress })),
onEnterPin: (options) => onEnterPinRef.current.onEnterPin(options),
})
.then((receivePidUseCase) => {
if (selectedFlow === 'c') {
return ReceivePidUseCaseCFlow.initialize({
agent: secureUnlock.context.agent,
onStateChange: setReceivePidUseCaseState,
onCardAttachedChanged: ({ isCardAttached }) =>
setIdCardScanningState((state) => ({
...state,
isCardAttached,
state: state.state === 'readyToScan' && isCardAttached ? 'scanning' : state.state,
})),
onStatusProgress: ({ progress }) => setIdCardScanningState((state) => ({ ...state, progress })),
onEnterPin: (options) => onEnterPinRef.current.onEnterPin(options),
}).then((receivePidUseCase) => {
setReceivePidUseCase(receivePidUseCase)
goToNextStep()
})
.catch((e) => {
reset({ error: e, resetToStep: 'id-card-pin' })
throw e
}
if (selectedFlow === 'bprime') {
if (!walletPin) {
throw new Error('wallet Pin has not been setup!')
}
return ReceivePidUseCaseBPrimeFlow.initialize({
agent: secureUnlock.context.agent,
onStateChange: setReceivePidUseCaseState,
onEnterPin: (options) => onEnterPinRef.current.onEnterPin(options),
pidPin: walletPin.split('').map(Number),
})
.then((receivePidUseCase) => {
setReceivePidUseCase(receivePidUseCase)
goToNextStep()
})
.catch((e) => {
reset({ error: e, resetToStep: 'id-card-pin' })
throw e
})
}
}

goToNextStep()
Expand All @@ -380,8 +403,8 @@ export function OnboardingContextProvider({
}) => {
if (error) console.error(error)

const stepsToCompleteAfterReset = onboardingStepsCFlow
.slice(onboardingStepsCFlow.findIndex((step) => step.step === resetToStep))
const stepsToCompleteAfterReset = onboardingSteps
.slice(onboardingSteps.findIndex((step) => step.step === resetToStep))
.map((step) => step.step)

if (stepsToCompleteAfterReset.includes('pin')) {
Expand Down Expand Up @@ -510,7 +533,9 @@ export function OnboardingContextProvider({
}

let screen: React.JSX.Element
if (currentStep.step === 'pin' || currentStep.step === 'pin-reenter') {
if (currentStep.step === 'welcome') {
screen = <currentStep.Screen goToNextStep={selectFlow} />
} else if (currentStep.step === 'pin' || currentStep.step === 'pin-reenter') {
screen = <currentStep.Screen key="pin-now" goToNextStep={currentStep.step === 'pin' ? onPinEnter : onPinReEnter} />
} else if (currentStep.step === 'id-card-pin') {
screen = <currentStep.Screen goToNextStep={onIdCardPinReEnter ?? onIdCardPinEnter} />
Expand Down
2 changes: 1 addition & 1 deletion apps/ausweis/src/features/onboarding/screens/pin.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { PinDotsInput, type PinDotsInputRef, YStack } from '@package/ui'
import { PinDotsInput, type PinDotsInputRef } from '@package/ui'
import React, { useRef } from 'react'

export interface OnboardingPinEnterProps {
Expand Down
20 changes: 14 additions & 6 deletions apps/ausweis/src/features/onboarding/screens/welcome.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Button, FlexPage, Heading, HeroIcons, Separator, XStack, YStack } from '@package/ui'
import React from 'react'
import { Button, FlexPage, Heading, Separator, XStack, YStack } from '@package/ui'
import React, { useState } from 'react'
import Animated, { FadingTransition } from 'react-native-reanimated'
import { LinearGradient } from 'tamagui/linear-gradient'

export interface OnboardingWelcomeProps {
goToNextStep: () => void
goToNextStep: (selectedFlow: 'c' | 'bprime') => void
}

export default function OnboardingWelcome({ goToNextStep }: OnboardingWelcomeProps) {
const [selectedFlow, setSelectedFlow] = useState<'c' | 'bprime'>('c')

return (
<Animated.View style={{ flex: 1 }} layout={FadingTransition}>
<FlexPage p={0} safeArea={false}>
Expand All @@ -32,10 +34,16 @@ export default function OnboardingWelcome({ goToNextStep }: OnboardingWelcomePro
</YStack>
<YStack flex-1 />
<XStack gap="$2" my="$6">
<Button.Outline p="$0" width="$buttonHeight">
<HeroIcons.GlobeAlt size={24} color="$grey-700" />
<Button.Outline
p="$0"
width="$buttonHeight"
onPress={() => setSelectedFlow((selectedFlow) => (selectedFlow === 'c' ? 'bprime' : 'c'))}
>
<Heading variant="h2" color={'$primary-500'} fontWeight={'bold'}>
{selectedFlow === 'c' ? 'C' : "B'"}
</Heading>
</Button.Outline>
<Button.Solid flexGrow={1} onPress={goToNextStep}>
<Button.Solid flexGrow={1} onPress={() => goToNextStep(selectedFlow)}>
Get Started
</Button.Solid>
</XStack>
Expand Down
Loading

0 comments on commit 4004465

Please sign in to comment.