Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: pw onboarding #263

Merged
merged 3 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions apps/easypid/src/config/copy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { type AppType, CURRENT_APP_TYPE } from './appType'

export const copy = {
FUNKE_WALLET: {
about: {
description: `This app was created by Animo Solutions in the context of the SPRIN-D Funke ‘EUDI Wallet Prototypes’. It
serves as a prototype for future wallet providers. All code is available under Apache 2.0.`,
emailHeader: 'Reach out from Funke EUDI Wallet',
},
},
PARADYM_WALLET: {
about: {
description:
'This app was created by Animo Solutions as a companion app for Paradym. All code is available under Apache 2.0.',
emailHeader: 'Reach out from Paradym Wallet',
},
},
} satisfies Record<AppType, Record<string, unknown>>

export function useAppCopy() {
return copy[CURRENT_APP_TYPE]
}
15 changes: 8 additions & 7 deletions apps/easypid/src/features/menu/FunkeAboutScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@ import React from 'react'
import { TextBackButton } from 'packages/app'
import { Linking } from 'react-native'

import { useAppCopy } from '@easypid/config/copy'
import pj from '../../../package.json'

export function FunkeAboutScreen() {
const { about } = useAppCopy()

const openContact = () => {
Linking.openURL('mailto:ana@animo.id?subject=Reach out from Funke EUDI Wallet')
Linking.openURL(`mailto:ana@animo.id?subject=${about.emailHeader}`)
}

const openPrivacyPolicy = () => {
Expand All @@ -20,15 +23,13 @@ export function FunkeAboutScreen() {
<HeaderContainer title="About the wallet" />
<YStack fg={1} px="$4" gap="$4">
<YStack gap="$2">
<Paragraph color="$grey-700">
This app was created by Animo Solutions in the context of the SPRIN-D Funke ‘EUDI Wallet Prototypes’. It
serves as a prototype for future wallet providers. All code is available under Apache 2.0.
</Paragraph>
<Paragraph color="$grey-700">{about.description}</Paragraph>
<Paragraph>
For more information on the project visit sprind.org or reach out to{' '}
For more information, reach out to{' '}
<Paragraph fontWeight="$semiBold" color="$primary-500" onPress={openContact}>
ana@animo.id
</Paragraph>
.
</Paragraph>
</YStack>
<YStack gap="$2" fg={1} jc="space-between">
Expand All @@ -40,7 +41,7 @@ export function FunkeAboutScreen() {
onPress={openPrivacyPolicy}
/>
<Paragraph py="$4" mx="auto" variant="sub" fontSize={13} fontWeight="$medium">
EasyPID version: {pj.version}
Paradym Wallet version: {pj.version}
</Paragraph>
</YStack>
</YStack>
Expand Down
46 changes: 25 additions & 21 deletions apps/easypid/src/features/menu/FunkeMenuScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
} from '@package/ui'

import { usePidCredential } from '@easypid/hooks'
import { useFeatureFlag } from '@easypid/hooks/useFeatureFlag'
import { useWalletReset } from '@easypid/hooks/useWalletReset'
import { TextBackButton } from '@package/app'
import { Link } from 'expo-router'
Expand Down Expand Up @@ -53,28 +54,31 @@ export function FunkeMenuScreen() {
const { handleScroll, isScrolledByOffset, scrollEventThrottle } = useScrollViewPosition()
const onResetWallet = useWalletReset()
const { credential } = usePidCredential()
const hasEidCardFeatureFlag = useFeatureFlag('EID_CARD')

const idItem = credential ? (
<MenuItem
key="id"
item={{
href: `credentials/${credential.id}`,
icon: HeroIcons.IdentificationFilled,
title: 'Your digital ID',
}}
idx={0}
/>
) : (
<MenuItem
key="id"
item={{
href: '/pidSetup',
icon: HeroIcons.IdentificationFilled,
title: 'Setup digital ID',
}}
idx={0}
/>
)
const idItem = hasEidCardFeatureFlag ? (
credential ? (
<MenuItem
key="id"
item={{
href: `credentials/${credential.id}`,
icon: HeroIcons.IdentificationFilled,
title: 'Your digital ID',
}}
idx={0}
/>
) : (
<MenuItem
key="id"
item={{
href: '/pidSetup',
icon: HeroIcons.IdentificationFilled,
title: 'Setup digital ID',
}}
idx={0}
/>
)
) : null

return (
<FlexPage gap="$0" paddingHorizontal="$0">
Expand Down
99 changes: 5 additions & 94 deletions apps/easypid/src/features/onboarding/onboardingContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { sendCommand } from '@animo-id/expo-ausweis-sdk'
import type { SdJwtVcHeader } from '@credo-ts/core'
import { type AppAgent, initializeAppAgent, useSecureUnlock } from '@easypid/agent'
import { setWalletServiceProviderPin } from '@easypid/crypto/WalletServiceProviderClient'
import { useFeatureFlag } from '@easypid/hooks/useFeatureFlag'
import { ReceivePidUseCaseCFlow } from '@easypid/use-cases/ReceivePidUseCaseCFlow'
import type {
CardScanningErrorDetails,
Expand All @@ -14,7 +15,6 @@ import {
type OnboardingPage,
type OnboardingStep,
SIMULATOR_PIN,
pidSetupSteps,
} from '@easypid/utils/sharedPidSetup'
import {
BiometricAuthenticationCancelledError,
Expand All @@ -34,99 +34,9 @@ import { Linking, Platform } from 'react-native'
import type { PidSdJwtVcAttributes } from '../../hooks'
import { addReceivedActivity } from '../activity/activityRecord'
import { useHasFinishedOnboarding } from './hasFinishedOnboarding'
import { OnboardingBiometrics } from './screens/biometrics'
import { OnboardingIntroductionSteps } from './screens/introduction-steps'
import OnboardingPinEnter from './screens/pin'
import { OnboardingWalletExplanation } from './screens/wallet-explanation'
import OnboardingWelcome from './screens/welcome'
import { onboardingSteps } from './steps'
import { useShouldUseCloudHsm } from './useShouldUseCloudHsm'

export const onboardingSteps = [
{
step: 'welcome',
alternativeFlow: false,
progress: 0,
page: {
type: 'fullscreen',
},
Screen: OnboardingWelcome,
},
{
step: 'wallet-explanation',
alternativeFlow: false,
progress: 0.1,
page: {
animation: 'delayed',
type: 'content',
title: '',
},
Screen: OnboardingWalletExplanation,
},

{
step: 'introduction-steps',
alternativeFlow: false,
progress: 20,
page: {
animation: 'delayed',
type: 'content',
title: 'Set up your wallet',
subtitle: 'Before you can use the app, we will guide you through these steps.',
},
Screen: OnboardingIntroductionSteps,
},

{
step: 'pin',
alternativeFlow: false,
progress: 30,
page: {
type: 'content',
title: 'Choose a 6-digit PIN',
subtitle: 'This PIN secures your identity wallet. You enter it every time you share data.',
animationKey: 'pin',
},
Screen: OnboardingPinEnter,
},
{
step: 'pin-reenter',
alternativeFlow: false,
progress: 30,
page: {
type: 'content',
title: 'Repeat your PIN',
subtitle: 'This PIN secures your identity wallet. You enter it every time you share data.',
animationKey: 'pin',
},
Screen: OnboardingPinEnter,
},
{
step: 'biometrics',
alternativeFlow: false,
progress: 40,
page: {
type: 'content',
title: 'Set up biometrics',
subtitle:
'Activate the biometrics functionality of your phone to make sure only you can enter your wallet and share data.',
},
Screen: OnboardingBiometrics,
},
{
step: 'biometrics-disabled',
progress: 40,
alternativeFlow: true,
page: {
type: 'content',
title: 'You need to enable biometrics',
subtitle:
'To continue, make sure your device has biometric protection enabled, and that EasyPID is allowed to use biometrics.',
},
Screen: OnboardingBiometrics,
},
...pidSetupSteps,
] as const satisfies Array<OnboardingStep>

export type OnboardingContext = {
currentStep: OnboardingStep['step']
progress: number
Expand Down Expand Up @@ -166,6 +76,7 @@ export function OnboardingContextProvider({
showScanModal: true,
})
const [eidCardRequestedAccessRights, setEidCardRequestedAccessRights] = useState<string[]>()
const hasEidCardFeatureFlag = useFeatureFlag('EID_CARD')

const currentStep = onboardingSteps.find((step) => step.step === currentStepName)
if (!currentStep) throw new Error(`Invalid step ${currentStepName}`)
Expand Down Expand Up @@ -236,7 +147,7 @@ export function OnboardingContextProvider({
// Allows bypassing the eID card and use a simulator card
const isSimulatorPinCode = pin === SIMULATOR_PIN

if (isSimulatorPinCode) {
if (isSimulatorPinCode && hasEidCardFeatureFlag) {
toast.show('Simulator eID card activated', {
customData: {
preset: 'success',
Expand Down Expand Up @@ -677,7 +588,7 @@ export function OnboardingContextProvider({
} else if (currentStep.step === 'biometrics') {
screen = <currentStep.Screen goToNextStep={onEnableBiometrics} actionText="Activate Biometrics" />
} else if (currentStep.step === 'biometrics-disabled') {
screen = <currentStep.Screen goToNextStep={onEnableBiometricsDisabled} actionText="Go to settings" />
screen = <currentStep.Screen goToNextStep={onEnableBiometricsDisabled} actionText="Open settings" />
} else if (currentStep.step === 'data-protection') {
screen = <currentStep.Screen goToNextStep={onIdCardStart} />
} else if (currentStep.step === 'id-card-requested-attributes') {
Expand Down
63 changes: 20 additions & 43 deletions apps/easypid/src/features/onboarding/screens/welcome.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,5 @@
import {
Blob,
Button,
FlexPage,
Heading,
HeroIcons,
IconContainer,
Image,
Paragraph,
Stack,
XStack,
YStack,
} from '@package/ui'
import { Blob, Button, FlexPage, Heading, Image, Paragraph, Stack, XStack, YStack } from '@package/ui'
import type React from 'react'
import { Alert } from 'react-native'

import appIcon from '../../../../assets/icon.png'

Expand All @@ -28,43 +15,33 @@ export default function OnboardingWelcome({ goToNextStep }: OnboardingWelcomePro
<YStack
transform={[{ translateX: -48 }]} // Half of the image width (96/2)
pos="absolute"
br="$6"
top="40%"
left="50%"
ov="hidden"
ai="center"
jc="center"
shadowOffset={{ width: 5, height: 5 }}
shadowColor="$grey-400"
shadowOpacity={0.5}
shadowRadius={24}
>
<Image height={96} width={96} src={appIcon} />
<Stack br="$7" ov="hidden">
<Image height={96} width={96} src={appIcon} />
</Stack>
</YStack>
</YStack>
<FlexPage safeArea="y" p={0} fg={1} jc="space-between" backgroundColor="$transparent">
<YStack px="$4" gap="$4" flex-1 justifyContent="space-between">
<YStack ai="flex-end">
<IconContainer
aria-label="Info"
icon={<HeroIcons.QuestionMarkCircle />}
onPress={() => {
Alert.alert(
'This is the EasyPID wallet',
'\nThis is your digital wallet. With it, you can store and share information about yourself.'
)
}}
/>
</YStack>
<Stack h="$11" />
<YStack gap="$4" jc="center" ai="center">
<Heading fontSize={32}>Paradym Wallet</Heading>
<Paragraph px="$2" ta="center">
This is your digital wallet. With it, you can store and share information about yourself.
</Paragraph>
</YStack>
<XStack gap="$2">
<Button.Solid flexGrow={1} onPress={goToNextStep}>
Get Started
</Button.Solid>
</XStack>
<FlexPage safeArea="y" fg={1} jc="space-between" backgroundColor="$transparent">
<Stack h="40%" />
<YStack gap="$4" ai="center">
<Heading fontSize={32}>Paradym Wallet</Heading>
<Paragraph px="$2" ta="center">
This is your digital wallet. With it, you can store and share information about yourself.
</Paragraph>
</YStack>
<XStack gap="$2">
<Button.Solid flexGrow={1} onPress={goToNextStep}>
Get Started
</Button.Solid>
</XStack>
</FlexPage>
</YStack>
)
Expand Down
Loading