fix bugs, improve layouts, improve UX on tab selection

This commit is contained in:
Rémi Colin
2024-02-08 09:36:07 +01:00
parent dbf6652d39
commit 7df20a74e2
10 changed files with 1351 additions and 1007 deletions

View File

@@ -1,22 +1,13 @@
import React, { useEffect, useState } from 'react';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
useColorScheme,
NativeModules,
DeviceEventEmitter,
TextInput,
Platform,
} from 'react-native';
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions,
} from 'react-native/Libraries/NewAppScreen';
import Toast, { BaseToast, ErrorToast, SuccessToast, ToastProps } from 'react-native-toast-message';
// @ts-ignore
@@ -449,7 +440,7 @@ function App(): JSX.Element {
// setProofTime(response.duration);
setGeneratingProof(false)
setStep('proofGenerated');
setStep(Steps.PROOF_GENERATED);
} catch (err: any) {
console.log('err', err);
setError(
@@ -540,47 +531,33 @@ function App(): JSX.Element {
};
return (
<YStack f={1}>
<SafeAreaView style={backgroundStyle}>
<StatusBar
barStyle={isDarkMode ? 'light-content' : 'dark-content'}
backgroundColor={Colors.red}
<YStack h="100%" w="100%">
<YStack h="100%" w="100%">
<MainScreen
onStartCameraScan={startCameraScan}
nfcScan={scan}
passportData={passportData}
disclosure={disclosure}
handleDisclosureChange={handleDisclosureChange}
address={address}
setAddress={setAddress}
generatingProof={generatingProof}
handleProve={handleProve}
step={step}
mintText={mintText}
proof={proof}
proofTime={proofTime}
handleMint={handleMint}
totalTime={totalTime}
setStep={setStep}
passportNumber={passportNumber}
setPassportNumber={setPassportNumber}
dateOfBirth={dateOfBirth}
setDateOfBirth={setDateOfBirth}
dateOfExpiry={dateOfExpiry}
setDateOfExpiry={setDateOfExpiry}
/>
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={{
backgroundColor: isDarkMode ? Colors.black : Colors.black,
}}
contentContainerStyle={{ flexGrow: 1 }}
>
<YStack style={styles.view}>
<MainScreen
onStartCameraScan={startCameraScan}
nfcScan={scan}
passportData={passportData}
disclosure={disclosure}
handleDisclosureChange={handleDisclosureChange}
address={address}
setAddress={setAddress}
generatingProof={generatingProof}
handleProve={handleProve}
step={step}
mintText={mintText}
proof={proof}
proofTime={proofTime}
handleMint={handleMint}
totalTime={totalTime}
setStep={setStep}
passportNumber={passportNumber}
setPassportNumber={setPassportNumber}
dateOfBirth={dateOfBirth}
setDateOfBirth={setDateOfBirth}
dateOfExpiry={dateOfExpiry}
setDateOfExpiry={setDateOfExpiry}
/>
</YStack>
</ScrollView>
</SafeAreaView>
</YStack>
<Toast config={toastConfig} />
</YStack>
);

View File

@@ -12,9 +12,9 @@
"dependencies": {
"@babel/plugin-transform-private-methods": "^7.23.3",
"@ethersproject/shims": "^5.7.0",
"@tamagui/config": "^1.89.3",
"@tamagui/core": "^1.89.3",
"@tamagui/lucide-icons": "^1.89.3",
"@tamagui/config": "^1.89.10",
"@tamagui/core": "^1.89.10",
"@tamagui/lucide-icons": "^1.89.10",
"axios": "^1.6.3",
"body-parser": "^1.20.2",
"buffer": "^6.0.3",
@@ -30,7 +30,7 @@
"react-native-passport-reader": "^1.0.3",
"react-native-svg": "13.4.0",
"react-native-toast-message": "^2.2.0",
"tamagui": "^1.89.3"
"tamagui": "^1.89.10"
},
"devDependencies": {
"@babel/core": "^7.20.0",
@@ -58,4 +58,4 @@
"engines": {
"node": ">=16"
}
}
}

View File

@@ -9,7 +9,7 @@ interface AppCardProps {
background: string | undefined;
id: string | number;
onTouchStart?: () => void;
eleva?: string;
selected?: boolean;
}
const AppCard: React.FC<AppCardProps> = ({
@@ -19,20 +19,20 @@ const AppCard: React.FC<AppCardProps> = ({
background,
id,
onTouchStart,
eleva
selected
}) => {
return (
<Card
key={id}
borderRadius="$10"
elevation={eleva}
elevation={0}
onTouchStart={onTouchStart}
shadowColor="black"
bg="transparent"
>
<XStack
<XStack w="100%"
>
<Card.Header w="100%">
<XStack w="100%" ai="center" py="$1" >
<XStack ai="center" py="$1" >
<YStack>
<H3 color={colorOfTheText} selectable={false} >{title}</H3>
<Text theme="alt2" color={colorOfTheText} selectable={false}>{description}</Text>
@@ -41,15 +41,21 @@ const AppCard: React.FC<AppCardProps> = ({
<ChevronRight size="$4" color={colorOfTheText} />
</XStack>
</Card.Header>
{background && (
<Card.Background>
<Image
{(
<Card.Background
animation="quick"
borderColor={(selected) ? "#E0E0E0" : "transparent"}
borderWidth={(selected) ? 4 : 0}
borderRadius="$10"
bg="#F0F0F0"
>
{background && <Image
flex={1}
borderRadius="$10"
source={{
uri: background
}}
/>
/>}
</Card.Background>
)}
</XStack>

View File

@@ -40,7 +40,7 @@ const AppScreen: React.FC<AppScreenProps> = ({ selectedApp, setSelectedApp }) =>
];
return (
<YStack gap="$5" w="100%" p="$5">
<YStack gap="$5" px="$5" pt="$12">
{cardsData.map(card => (
<AppCard
@@ -51,7 +51,7 @@ const AppScreen: React.FC<AppScreenProps> = ({ selectedApp, setSelectedApp }) =>
background={card.background}
id={card.app.id}
onTouchStart={() => handleCardSelect(card.app)}
eleva={selectedApp && selectedApp.id === card.app.id ? "$0" : "$12"}
selected={selectedApp && selectedApp.id === card.app.id ? true : false}
/>
))}

View File

@@ -0,0 +1,313 @@
import React, { useState, useEffect } from 'react';
import { YStack, XStack, Text, Button, Tabs, styled, Dialog, Adapt, Sheet, Label, Fieldset, Input, Switch, ThemeableStack, Separator } from 'tamagui'
import { Scan, UserCheck, HelpCircle, XCircle, IterationCw, LayoutGrid, Sparkles } from '@tamagui/lucide-icons';
import ScanScreen from './ScanScreen';
import ProveScreen from './ProveScreen';
import { Steps } from '../utils/utils';
import AppScreen from './AppScreen';
import { App } from '../utils/AppClass';
interface MainScreenProps {
onStartCameraScan: () => void;
nfcScan: () => void;
passportData: any;
disclosure: boolean;
handleDisclosureChange: (disclosure: boolean) => void;
address: string;
setAddress: (address: string) => void;
generatingProof: boolean;
handleProve: () => void;
step: number;
mintText: string;
proof: any;
proofTime: number;
handleMint: () => void;
totalTime: number;
setStep: (step: number) => void;
passportNumber: string;
setPassportNumber: (number: string) => void;
dateOfBirth: string;
setDateOfBirth: (date: string) => void;
dateOfExpiry: string;
setDateOfExpiry: (date: string) => void;
}
const MainScreen: React.FC<MainScreenProps> = ({
onStartCameraScan,
nfcScan,
passportData,
disclosure,
handleDisclosureChange,
address,
setAddress,
generatingProof,
handleProve,
step,
mintText,
proof,
proofTime,
handleMint,
totalTime,
setStep,
passportNumber,
setPassportNumber,
dateOfBirth,
setDateOfBirth,
dateOfExpiry,
setDateOfExpiry
}) => {
const [selectedTab, setSelectedTab] = useState("scan");
const [selectedApp, setSelectedApp] = useState<App | null>(null);
const [brokenCamera, setBrokenCamera] = useState(false);
const [open, setOpen] = useState(false)
const AppCard = styled(ThemeableStack, {
hoverTheme: true,
pressTheme: true,
focusTheme: true,
elevate: true
})
const handleRestart = () => {
setStep(Steps.MRZ_SCAN);
setSelectedApp(null)
setPassportNumber("");
setDateOfBirth("");
setDateOfExpiry("");
}
const handleSkip = () => {
setStep(Steps.NFC_SCAN_COMPLETED);
setPassportNumber("");
setDateOfBirth("");
setDateOfExpiry("");
}
useEffect(() => {
// Check if length of each field is correct and move to step MRZ_SCAN_COMPLETED if so
if (passportNumber?.length === 9 && (dateOfBirth?.length === 6 && dateOfExpiry?.length === 6)) {
setStep(Steps.MRZ_SCAN_COMPLETED);
}
}, [passportNumber, dateOfBirth, dateOfExpiry]);
return (
<YStack f={1} bc="white">
<YStack >
<XStack jc="space-between" ai="center" p="$2">
<XStack w="33%" ></XStack>
<Text w="33%">
{selectedTab === "scan" ? "Scan" : (selectedTab === "app" ? "Apps" : "Prove")}
</Text>
<Dialog
modal
>
<Dialog.Trigger p="$2">
<HelpCircle />
</Dialog.Trigger>
<Adapt when="sm" platform="touch">
<Sheet animation="medium" zIndex={200000} modal dismissOnSnapToBottom>
<Sheet.Frame padding="$4" gap="$4">
<Adapt.Contents />
</Sheet.Frame>
<Sheet.Overlay
animation="lazy"
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
/>
</Sheet>
</Adapt>
<Dialog.Portal>
<Dialog.Overlay
key="overlay"
animation="quick"
opacity={0.5}
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
/>
<Dialog.Content
bordered
elevate
key="content"
animateOnly={['transform', 'opacity']}
animation={[
'quick',
{
opacity: {
overshootClamping: true,
},
},
]}
enterStyle={{ x: 0, y: -20, opacity: 0, scale: 0.9 }}
exitStyle={{ x: 0, y: 10, opacity: 0, scale: 0.95 }}
gap="$4"
>
<XStack >
<Dialog.Title>Settings</Dialog.Title>
</XStack>
<Fieldset gap="$4" mt="$2" horizontal>
<Label width={200} justifyContent="flex-end" htmlFor="restart" fow="bold">
Restart to step 1
</Label>
<Button size="$4" m="$2" onPress={handleRestart}>
<IterationCw />
</Button>
</Fieldset>
<Fieldset gap="$4" mt="$2" horizontal>
<Label width={200} justifyContent="flex-end" htmlFor="skip" fow="bold">
Use mock passport data
</Label>
<Button size="$4" m="$2" onPress={handleSkip}>
<Sparkles />
</Button>
</Fieldset>
<Fieldset gap="$4" mt="$2" horizontal>
<Label width={205} justifyContent="flex-end" htmlFor="name" fow="bold">
Broken camera
</Label>
<Switch size="$4" checked={brokenCamera} onCheckedChange={setBrokenCamera}>
<Switch.Thumb animation="bouncy" backgroundColor="white" color />
</Switch>
</Fieldset>
{
brokenCamera &&
<YStack pl="$3">
<Fieldset gap="$4" horizontal>
<Label width={160} justifyContent="flex-end" htmlFor="name">
Passport Number
</Label>
<Input borderColor={passportNumber?.length === 9 ? "green" : "unset"} flex={1} id="passport_number" onChangeText={(text) => setPassportNumber(text.toUpperCase())} value={passportNumber} keyboardType="default" />
</Fieldset>
<Fieldset gap="$4" mt="$2" horizontal>
<Label width={160} justifyContent="flex-end" htmlFor="name">
Date of birth (yymmdd)
</Label>
<Input borderColor={dateOfBirth?.length === 6 ? "green" : "unset"} flex={1} id="date_of_birth" onChangeText={setDateOfBirth} value={dateOfBirth} keyboardType="numeric" />
</Fieldset>
<Fieldset gap="$4" mt="$2" horizontal>
<Label width={160} justifyContent="flex-end" htmlFor="name">
Date of expiry (yymmdd)
</Label>
<Input borderColor={dateOfExpiry?.length === 6 ? "green" : "unset"} flex={1} id="date_of_expiry" onChangeText={setDateOfExpiry} value={dateOfExpiry} keyboardType="numeric" />
</Fieldset>
</YStack>
}
<YStack flex={1}>
<YStack flex={1}></YStack>
<Dialog.Close mb="$4" displayWhenAdapted alignSelf='center'>
<XCircle size="$3" />
</Dialog.Close>
</YStack>
</Dialog.Content>
</Dialog.Portal>
</Dialog>
</XStack>
<YStack w="100%" h={2} backgroundColor="#DCDCDC" opacity={0.16}></YStack>
</YStack>
<Tabs f={1} orientation="horizontal" flexDirection="column" defaultValue="scan" onValueChange={setSelectedTab}>
<Tabs.Content value="scan" f={1}>
<ScanScreen
onStartCameraScan={onStartCameraScan}
nfcScan={nfcScan}
step={step} />
</Tabs.Content>
<Tabs.Content value="app" f={1}>
<AppScreen
selectedApp={selectedApp}
setSelectedApp={setSelectedApp} />
</Tabs.Content>
<Tabs.Content value="generate" f={1}>
<ProveScreen
passportData={passportData}
disclosure={disclosure}
selectedApp={selectedApp}
handleDisclosureChange={handleDisclosureChange}
address={address}
setAddress={setAddress}
generatingProof={generatingProof}
handleProve={handleProve}
step={step}
mintText={mintText}
proof={proof}
proofTime={proofTime}
handleMint={handleMint}
totalTime={totalTime} />
</Tabs.Content>
<Separator />
<Tabs.List separator={<Separator vertical />}
pt="$4" pb="$3">
<Tabs.Tab value="scan" unstyled w="33%">
<YStack ai="center">
<Scan color='black' />
<Text color='black'>Scan</Text>
</YStack>
</Tabs.Tab>
<Tabs.Tab value="app" unstyled w="33%">
<YStack ai="center" >
<LayoutGrid color="black" />
<Text color="black">Apps</Text>
</YStack>
</Tabs.Tab>
<Tabs.Tab value="generate" unstyled w="33%">
<YStack ai="center">
<UserCheck color='black' />
<Text color='black'>Prove</Text>
</YStack>
</Tabs.Tab>
</Tabs.List>
</Tabs>
{/*
<XStack justifyContent='space-between'>
<Button h="$5" w="33%" unstyled bg="blue" jc='center' ai='center'>
<YStack>
<Scan color='black' mt={3} />
<Text>Scan</Text>
</YStack>
</Button>
<Button h="$5" w="33%" unstyled bg="blue" jc='center' ai='center'>
<YStack>
<Scan color='black' mt={3} />
<Text>Scan</Text>
</YStack>
</Button>
<Button h="$5" w="33%" unstyled bg="blue" jc='center' ai='center'>
<YStack>
<Scan color='black' mt={3} />
<Text>Scan</Text>
</YStack>
</Button>
</XStack>
*/}
</YStack >
);
};
export default MainScreen;

View File

@@ -1,11 +1,12 @@
import React, { useState, useEffect } from 'react';
import { YStack, XStack, Text, Button, Tabs, styled, Dialog, Adapt, Sheet, Label, Fieldset, Input, Switch, ThemeableStack } from 'tamagui'
import { YStack, XStack, Text, Button, Tabs, styled, Dialog, Adapt, Sheet, Label, Fieldset, Input, Switch, ThemeableStack, Separator } from 'tamagui'
import { Scan, UserCheck, HelpCircle, XCircle, IterationCw, LayoutGrid, Sparkles } from '@tamagui/lucide-icons';
import ScanScreen from './ScanScreen';
import ProveScreen from './ProveScreen';
import { Steps } from '../utils/utils';
import AppScreen from './AppScreen';
import { App } from '../utils/AppClass';
import { Keyboard } from 'react-native';
interface MainScreenProps {
@@ -90,13 +91,30 @@ const MainScreen: React.FC<MainScreenProps> = ({
}
}, [passportNumber, dateOfBirth, dateOfExpiry]);
return (
<YStack f={1} ai="center" jc="space-between" bc="#fff">
const [keyboardVisible, setKeyboardVisible] = useState(false);
<YStack w="100%">
<XStack w="100%" jc="space-between" ai="center" ph="$4" pv="$2" bc="#fff" p="$3">
<XStack></XStack>
<Text>
useEffect(() => {
const showSubscription = Keyboard.addListener('keyboardDidShow', () => {
setKeyboardVisible(true);
});
const hideSubscription = Keyboard.addListener('keyboardDidHide', () => {
setKeyboardVisible(false);
});
return () => {
showSubscription.remove();
hideSubscription.remove();
};
}, []);
return (
<YStack f={1} bc="white">
<YStack >
<XStack jc="space-between" ai="center" p="$2">
<XStack w="33%" ></XStack>
<Text w="33%">
{selectedTab === "scan" ? "Scan" : (selectedTab === "app" ? "Apps" : "Prove")}
</Text>
@@ -151,8 +169,8 @@ const MainScreen: React.FC<MainScreenProps> = ({
</XStack>
<Fieldset gap="$4" mt="$2" horizontal>
<Label width={160} justifyContent="flex-end" htmlFor="restart" fow="bold">
<Fieldset gap="$4" mt="$6" horizontal>
<Label width={200} justifyContent="flex-end" htmlFor="restart" fow="bold">
Restart to step 1
</Label>
<Button size="$4" m="$2" onPress={handleRestart}>
@@ -162,8 +180,8 @@ const MainScreen: React.FC<MainScreenProps> = ({
<Fieldset gap="$4" mt="$2" horizontal>
<Label width={160} justifyContent="flex-end" htmlFor="skip" fow="bold">
Enter mock passport data
<Label width={200} justifyContent="flex-end" htmlFor="skip" fow="bold">
Use mock passport data
</Label>
<Button size="$4" m="$2" onPress={handleSkip}>
<Sparkles />
@@ -171,7 +189,7 @@ const MainScreen: React.FC<MainScreenProps> = ({
</Fieldset>
<Fieldset gap="$4" mt="$2" horizontal>
<Label width={160} justifyContent="flex-end" htmlFor="name" fow="bold">
<Label width={205} justifyContent="flex-end" htmlFor="name" fow="bold">
Broken camera
</Label>
<Switch size="$4" checked={brokenCamera} onCheckedChange={setBrokenCamera}>
@@ -180,7 +198,7 @@ const MainScreen: React.FC<MainScreenProps> = ({
</Fieldset>
{
brokenCamera &&
<YStack space pl="$3">
<YStack pl="$3">
<Fieldset gap="$4" horizontal>
<Label width={160} justifyContent="flex-end" htmlFor="name">
Passport Number
@@ -212,95 +230,99 @@ const MainScreen: React.FC<MainScreenProps> = ({
</Dialog.Content>
</Dialog.Portal>
</Dialog>
</XStack>
<YStack w="100%" h={2} backgroundColor="#DCDCDC" opacity={0.16}></YStack>
<Separator />
</YStack>
<Tabs f={1} defaultValue="scan" orientation='horizontal' dir='ltr' shadowColor="black" onValueChange={(newValue) => setSelectedTab(newValue)}>
<YStack ai="center" jc="space-between" bc="" >
<XStack flexGrow={0} ai="center" />
<Tabs f={1} orientation="horizontal" flexDirection="column" defaultValue="scan" onValueChange={setSelectedTab}>
<Tabs.Content value="scan" f={1}>
<ScanScreen
onStartCameraScan={onStartCameraScan}
nfcScan={nfcScan}
step={step} />
</Tabs.Content>
<Tabs.Content value="scan">
<ScanScreen
onStartCameraScan={onStartCameraScan}
nfcScan={nfcScan}
step={step} />
</Tabs.Content>
<Tabs.Content value="app">
<AppScreen
selectedApp={selectedApp}
setSelectedApp={setSelectedApp}
/>
</Tabs.Content>
<Tabs.Content value="generate">
<ProveScreen
passportData={passportData}
disclosure={disclosure}
selectedApp={selectedApp}
handleDisclosureChange={handleDisclosureChange}
address={address}
setAddress={setAddress}
generatingProof={generatingProof}
handleProve={handleProve}
step={step}
mintText={mintText}
proof={proof}
proofTime={proofTime}
handleMint={handleMint}
totalTime={totalTime}
/>
</Tabs.Content>
<Tabs.Content value="app" f={1}>
<AppScreen
selectedApp={selectedApp}
setSelectedApp={setSelectedApp} />
</Tabs.Content>
<YStack w="100%" backgroundColor="white">
<YStack w="100%" h={2} backgroundColor="#DCDCDC" opacity={0.16}></YStack>
<Tabs.Content value="generate" f={1}>
<ProveScreen
passportData={passportData}
disclosure={disclosure}
selectedApp={selectedApp}
handleDisclosureChange={handleDisclosureChange}
address={address}
setAddress={setAddress}
generatingProof={generatingProof}
handleProve={handleProve}
step={step}
mintText={mintText}
proof={proof}
proofTime={proofTime}
handleMint={handleMint}
totalTime={totalTime} />
</Tabs.Content>
<Tabs.List w="100%" pt="$4" pb="$3">
<Tabs.Tab unstyled value="scan" w="33%" backgroundColor="transparent" >
<YStack ai="center">
<Scan color={selectedTab === "scan" ? '#3185FC' : 'black'} />
<Text color={selectedTab === "scan" ? '#3185FC' : 'black'}>Scan</Text>
</YStack>
</Tabs.Tab>
<Separator />
{step < Steps.NFC_SCAN_COMPLETED ?
<Tabs.Tab unstyled value="scan" w="33%" backgroundColor="transparent" >
<YStack ai="center">
<LayoutGrid color="#eeeeee" />
<Text color="#eeeeee">Apps</Text>
</YStack>
</Tabs.Tab>
:
<Tabs.Tab unstyled value="app" w="33%" backgroundColor="transparent" >
<YStack ai="center">
<LayoutGrid color={selectedTab === "app" ? '#3185FC' : 'black'} />
<Text color={selectedTab === "app" ? '#3185FC' : 'black'}>Apps</Text>
</YStack>
</Tabs.Tab>
}
{!keyboardVisible ? <Tabs.List separator={<Separator vertical />} pt="$4" pb="$3">
<Tabs.Tab value="scan" unstyled w="33%">
<YStack ai="center">
<Scan color={selectedTab === "scan" ? '#3185FC' : 'black'} />
<Text color={selectedTab === "scan" ? '#3185FC' : 'black'}>Scan</Text>
</YStack>
</Tabs.Tab>
<Tabs.Tab value="app" unstyled w="33%">
<YStack ai="center">
<LayoutGrid color={selectedTab === "app" ? '#3185FC' : 'black'} />
<Text color={selectedTab === "app" ? '#3185FC' : 'black'}>Apps</Text>
</YStack>
</Tabs.Tab>
{selectedApp === null ?
<Tabs.Tab unstyled value={step < Steps.NFC_SCAN_COMPLETED ? "scan" : "app"} w="33%" backgroundColor="transparent">
<YStack ai="center">
<UserCheck color="#eeeeee" />
<Text color="#eeeeee">Prove</Text>
</YStack>
</Tabs.Tab>
:
<Tabs.Tab unstyled value="generate" w="33%" backgroundColor="transparent">
<YStack ai="center">
<UserCheck color={selectedTab === "generate" ? '#3185FC' : 'black'} />
<Text color={selectedTab === "generate" ? '#3185FC' : 'black'}>Prove</Text>
</YStack>
</Tabs.Tab>
}
</Tabs.List>
<Tabs.Tab value="generate" unstyled w="33%">
<YStack ai="center">
<UserCheck color={selectedTab === "generate" ? '#3185FC' : 'black'} />
<Text color={selectedTab === "generate" ? '#3185FC' : 'black'}>Prove</Text>
</YStack>
</Tabs.Tab>
</Tabs.List> : (<XStack />)}
</Tabs>
{/*
// This component is WIP in case tamagui can't afford to deliver Tabs component without error on time
<XStack justifyContent='space-between'>
<Button h="$5" w="33%" unstyled bg="blue" jc='center' ai='center'>
<YStack>
<Scan color='black' mt={3} />
<Text>Scan</Text>
</YStack>
</YStack>
</Tabs >
</Button>
<Button h="$5" w="33%" unstyled bg="blue" jc='center' ai='center'>
<YStack>
<Scan color='black' mt={3} />
<Text>Scan</Text>
</YStack>
</Button>
<Button h="$5" w="33%" unstyled bg="blue" jc='center' ai='center'>
<YStack>
<Scan color='black' mt={3} />
<Text>Scan</Text>
</YStack>
</Button>
</XStack>
*/}
</YStack >
);
};

View File

@@ -1,6 +1,6 @@
import React from 'react';
import { YStack, XStack, Text, Checkbox, Input, Button, Spinner, Image } from 'tamagui';
import { Check } from '@tamagui/lucide-icons';
import { YStack, XStack, Text, Checkbox, Input, Button, Spinner, Image, TextArea } from 'tamagui';
import { Check, LayoutGrid, Scan, Sparkles } from '@tamagui/lucide-icons';
import { getFirstName, formatDuration } from '../../utils/utils';
import { attributeToPosition } from '../../../common/src/constants/constants';
import { Steps } from '../utils/utils';
@@ -44,24 +44,25 @@ const ProveScreen: React.FC<ProveScreenProps> = ({
}) => {
return (
<YStack space="$4" p="$4" >
{
step < Steps.PROOF_GENERATED ? (
<YStack >
<YStack w="100%" ai="center">
<YStack px="$4" f={1} >
{(step >= Steps.NFC_SCAN_COMPLETED && selectedApp != null) ?
(step < Steps.PROOF_GENERATED ? (
<YStack flex={1} m="$2" gap="$2">
<XStack flex={1} />
<YStack alignSelf='center'>
<Image
w="$12"
h="$12"
flex={1}
borderRadius="$10"
source={{
uri: USER
}}
/>
</YStack>
<YStack mt="$12">
<Text mb="$1">Hi {getFirstName(passportData.mrz)},</Text>
<Text mb="$2">{selectedApp?.name} is asking for the following information:</Text>
<XStack flex={1} />
<YStack mt="$8">
<Text mb="$1" fontWeight="bold">Hi {getFirstName(passportData.mrz)},</Text>
<Text mb="$2">{selectedApp?.disclosurephrase}</Text>
{selectedApp && Object.keys(selectedApp.disclosure).map((key) => {
const key_ = key as keyof typeof disclosure;
const indexes = attributeToPosition[key_];
@@ -70,8 +71,7 @@ const ProveScreen: React.FC<ProveScreenProps> = ({
const mrzAttributeFormatted = mrzAttribute.replace(/</g, ' ');
return (
<XStack key={key} m="$2" w="$full" gap="$2">
<XStack key={key} m="$2" gap="$4">
<Checkbox
value={key}
checked={disclosure[key_]}
@@ -83,48 +83,75 @@ const ProveScreen: React.FC<ProveScreenProps> = ({
<Check />
</Checkbox.Indicator>
</Checkbox>
<Text fontWeight="bold">{keyFormatted}: </Text>
<Text>{mrzAttributeFormatted}</Text>
</XStack>
);
})}
</YStack>
<Text mt="$3">Enter your address or ens</Text>
<Text mt="$8">Enter your address or ens:</Text>
<Input
size="md"
fontSize={13}
mt="$3"
placeholder="Your Address or ens name"
value={address}
onChangeText={setAddress}
/>
<Button borderRadius={100} onPress={handleProve} mt="$6" backgroundColor="#3185FC" >
<Button borderRadius={100} onPress={handleProve} mt="$5" mb="$3" backgroundColor="#3185FC" alignSelf='center' >
{generatingProof ? (
<XStack ai="center">
<Spinner />
<Text color="white" marginLeft="$2" fow="bold">Generating zk proof</Text>
<Text color="white" marginLeft="$2" fow="bold" >Generating ZK proof</Text>
</XStack>
) : (
<Text color="white" fow="bold">Generate zk proof</Text>
<Text color="white" fow="bold">Generate ZK proof</Text>
)}
</Button>
<Text fontSize={10} color={generatingProof ? "gray" : "white"} alignSelf='center'>This operation can take about 2 mn</Text>
<Text fontSize={9} color={generatingProof ? "gray" : "white"} pb="$2" alignSelf='center'>The application may freeze during this time (hard work)</Text>
</YStack>
) : (
<YStack m="$2" justifyContent='center' alignItems='center' gap="$5">
<Text fontWeight="bold">Zero-knowledge proof generated:</Text>
<YStack flex={1} m="$2" justifyContent='center' alignItems='center' gap="$5">
<ProofGrid proof={proof} />
<Text fontWeight="bold" mt="$2">Proof Duration: {formatDuration(proofTime)}</Text>
<Text fontWeight="bold">Total Duration: {formatDuration(totalTime)}</Text>
<YStack>
<Text fontWeight="bold" fontSize="$6" mt="$6">Congrats 🎉</Text>
<Text fontWeight="bold" fontSize="$5">You just generated this Zero Knowledge proof !</Text>
<Text color="gray" fontSize="$5" mt="$1" fow="bold" textAlign='left'>You can now share this proof with the selected app.</Text>
<Button borderRadius={100} onPress={handleMint} marginTop="$4" mb="$4" backgroundColor="#3185FC">
<Text color="white" fow="bold">Mint Proof of Passport</Text>
<Text color="gray" mt="$3">Proof generation duration: {formatDuration(proofTime)}</Text>
</YStack>
<XStack flex={1} />
{mintText && <Text color="gray">{mintText}</Text>}
<Button borderRadius={100} onPress={handleMint} marginTop="$4" mb="$8" backgroundColor="#3185FC">
<Text color="white" fow="bold" >{selectedApp?.mintphrase}</Text>
</Button>
{mintText && <Text>{mintText}</Text>}
</YStack>
)
) :
(
<YStack flex={1} justifyContent='center' alignItems='center'>
<Text fontSize={18} textAlign='center' fow="bold">Please scan your passport and select an app to generate ZK proof</Text>
<XStack mt="$10" gap="$6">
<Scan size="$4" color={step < Steps.NFC_SCAN_COMPLETED ? "black" : "#3185FC"} />
<LayoutGrid size="$4" color={selectedApp == null ? "black" : "#3185FC"} />
</XStack>
</YStack>
)
}
</YStack >
);

View File

@@ -10,8 +10,8 @@ interface ScanScreenProps {
const ScanScreen: React.FC<ScanScreenProps> = ({ onStartCameraScan, nfcScan, step }) => {
return (
<YStack gap="$1" >
<ZStack alignSelf='center' maxWidth={50} maxHeight={50} width={50} flex={0} space="$0">
<YStack f={1} p="$5" gap="$1" px="$5" pt="$12">
<ZStack alignSelf='center' maxWidth={50} maxHeight={50} width={50} flex={0} >
<Circle
alignSelf='center'
h={22}
@@ -29,10 +29,8 @@ const ScanScreen: React.FC<ScanScreenProps> = ({ onStartCameraScan, nfcScan, ste
fow="bold"
>1</Text>
</ZStack>
<Text textAlign='center' mt="$5" px="$4" fow={step === Steps.MRZ_SCAN ? "bold" : "normal"} >Scan the machine readable zone on the main page of your passport</Text>
<ZStack alignSelf='center' mt="$5" maxWidth={50} maxHeight={50} width={50} flex={0} space="$0">
<Text textAlign='center' mt="$5" fow={step === Steps.MRZ_SCAN ? "bold" : "normal"} >Scan the machine readable zone on the main page of your passport</Text>
<ZStack alignSelf='center' mt="$5" maxWidth={50} maxHeight={50} width={50} flex={0} >
<Circle
alignSelf='center'
h={22}
@@ -50,9 +48,9 @@ const ScanScreen: React.FC<ScanScreenProps> = ({ onStartCameraScan, nfcScan, ste
fow="bold"
>2</Text>
</ZStack>
<Text textAlign='center' mt="$5" px="$4" fow={(step === Steps.MRZ_SCAN_COMPLETED) || (step === Steps.NFC_SCANNING) ? "bold" : "normal"}>Hold your passport against your device to read the biometric chip</Text>
<Text textAlign='center' mt="$5" fow={(step === Steps.MRZ_SCAN_COMPLETED) || (step === Steps.NFC_SCANNING) ? "bold" : "normal"}>Hold your passport against your device to read the biometric chip</Text>
<ZStack alignSelf='center' mt="$5" maxWidth={50} maxHeight={50} width={50} flex={0} space="$0">
<ZStack alignSelf='center' mt="$5" maxWidth={50} maxHeight={50} width={50} flex={0} >
<Circle
alignSelf='center'
h={22}
@@ -70,9 +68,9 @@ const ScanScreen: React.FC<ScanScreenProps> = ({ onStartCameraScan, nfcScan, ste
fow="bold"
>3</Text>
</ZStack>
<Text textAlign='center' mt="$5" px="$4" fow={step >= Steps.NFC_SCAN_COMPLETED ? "bold" : "normal"}>Select App</Text>
<Text textAlign='center' mt="$5" fow={step >= Steps.NFC_SCAN_COMPLETED ? "bold" : "normal"}>Select App</Text>
<YStack w="100%" ai="center">
<YStack ai="center">
{
step < Steps.NFC_SCAN_COMPLETED
? (

View File

@@ -1,5 +1,3 @@
// AppClass.ts
type Disclosure = {
[key: string]: boolean;
};
@@ -8,15 +6,18 @@ export class App {
id: string;
name: string;
disclosure: Disclosure;
mintphrase: string;
disclosurephrase: string;
constructor(id: string, name: string, disclosure: Disclosure) {
constructor(id: string, name: string, disclosure: Disclosure, mintphrase: string, disclosurephrase: string) {
this.id = id;
this.name = name;
this.disclosure = disclosure;
this.disclosurephrase = disclosurephrase;
this.mintphrase = mintphrase;
}
}
// Create instances of the App class
export const gitcoin = new App("gitcoin", "Gitcoin", {});
export const soulbond = new App("soulbond", "Soulbond token", { nationality: false, expiry_date: false });
export const zuzalu = new App("zuzalu", "Zupass", { date_of_birth: false });
export const gitcoin = new App("gitcoin", "Gitcoin", {}, "Add to Gitcoin passport", "Gitcoin passport doesn't require to disclosure any data.");
export const soulbond = new App("soulbond", "Soulbond token", { nationality: false, expiry_date: false }, "Mint Soulbond token", "Disclosure the information you want and mint your SBT:");
export const zuzalu = new App("zuzalu", "Zupass", { date_of_birth: false }, "Add to Zupass", "Zupass requires the following information:");

File diff suppressed because it is too large Load Diff