mirror of
https://github.com/selfxyz/self.git
synced 2026-04-27 03:01:15 -04:00
update UI/UX
This commit is contained in:
14
app/App.tsx
14
app/App.tsx
@@ -9,28 +9,36 @@ import useNavigationStore from './src/stores/navigationStore';
|
||||
import { AMPLITUDE_KEY } from '@env';
|
||||
import * as amplitude from '@amplitude/analytics-react-native';
|
||||
import useUserStore from './src/stores/userStore';
|
||||
import { bgWhite } from './src/utils/colors';
|
||||
global.Buffer = Buffer;
|
||||
|
||||
function App(): JSX.Element {
|
||||
const toast = useToastController();
|
||||
const setToast = useNavigationStore((state) => state.setToast);
|
||||
const initUserStore = useUserStore((state) => state.initUserStore);
|
||||
const setSelectedTab = useNavigationStore((state) => state.setSelectedTab);
|
||||
|
||||
useEffect(() => {
|
||||
initUserStore();
|
||||
}, [initUserStore]);
|
||||
|
||||
useEffect(() => {
|
||||
setToast(toast);
|
||||
}, [toast, setToast]);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedTab('splash');
|
||||
}, [setSelectedTab]);
|
||||
useEffect(() => {
|
||||
if (AMPLITUDE_KEY) {
|
||||
amplitude.init(AMPLITUDE_KEY);
|
||||
}
|
||||
initUserStore();
|
||||
//initUserStore();
|
||||
}, []);
|
||||
|
||||
// TODO: when passportData already stored, retrieve and jump to main screen
|
||||
|
||||
return (
|
||||
<YStack f={1} bc="#161616" h="100%" w="100%">
|
||||
<YStack f={1} bc={bgWhite} h="100%" w="100%">
|
||||
<YStack h="100%" w="100%">
|
||||
<MainScreen />
|
||||
</YStack>
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-get-random-values": "^1.11.0",
|
||||
"react-native-keychain": "^8.2.0",
|
||||
"react-native-nfc-manager": "^3.15.1",
|
||||
"react-native-passport-reader": "^1.0.3",
|
||||
"react-native-svg": "13.4.0",
|
||||
"react-native-zip-archive": "^6.1.0",
|
||||
|
||||
116
app/src/components/Carousel.tsx
Normal file
116
app/src/components/Carousel.tsx
Normal file
@@ -0,0 +1,116 @@
|
||||
import React, { useState } from 'react'
|
||||
import { AnimatePresence } from '@tamagui/animate-presence'
|
||||
import { ArrowLeft, ArrowRight, Nfc, ShieldCheck } from '@tamagui/lucide-icons'
|
||||
import { Button, Image, XStack, YStack, styled, Text } from 'tamagui'
|
||||
import { bgBlue, bgGreen, borderColor, textBlack, textColor1, textColor2 } from '../utils/colors'
|
||||
import CustomButton from './CustomButton'
|
||||
|
||||
const GalleryItem = styled(YStack, {
|
||||
zIndex: 1,
|
||||
x: 0,
|
||||
opacity: 1,
|
||||
fullscreen: true,
|
||||
|
||||
variants: {
|
||||
going: {
|
||||
':number': (going) => ({
|
||||
enterStyle: {
|
||||
x: going > 0 ? 1000 : -1000,
|
||||
opacity: 0,
|
||||
},
|
||||
exitStyle: {
|
||||
zIndex: 0,
|
||||
x: going < 0 ? 1000 : -1000,
|
||||
opacity: 0,
|
||||
},
|
||||
}),
|
||||
},
|
||||
} as const,
|
||||
})
|
||||
|
||||
const wrap = (min: number, max: number, v: number) => {
|
||||
const rangeSize = max - min
|
||||
return ((((v - min) % rangeSize) + rangeSize) % rangeSize) + min
|
||||
}
|
||||
|
||||
interface CarouselProps {
|
||||
images: string[];
|
||||
height?: number;
|
||||
onSlideChange?: (index: number) => void;
|
||||
handleNfcScan?: () => void;
|
||||
}
|
||||
|
||||
export function Carousel({ images, height = 300, onSlideChange, handleNfcScan }: CarouselProps) {
|
||||
const [[page, going], setPage] = useState([0, 0])
|
||||
|
||||
const imageIndex = wrap(0, images.length, page)
|
||||
const paginate = (going: number) => {
|
||||
const newPage = page + going
|
||||
setPage([newPage, going])
|
||||
onSlideChange?.(newPage)
|
||||
}
|
||||
|
||||
const isLastImage = imageIndex === images.length - 1
|
||||
const slideTexts = [
|
||||
{ header: "Follow this guide carefully", subtitle: "", acknowledgment: "I'm ready to start" },
|
||||
{ header: "Remove your phone case", subtitle: "If your phone does not have a case, you can skip this step.", acknowledgment: "I have removed my phone case" },
|
||||
{ header: "Open your passport to the last page", subtitle: "", acknowledgment: "I have opened my passport to the last page" },
|
||||
{ header: "Put your phone on the passport", subtitle: "Press your phone against the last page of the passport as in the image.", acknowledgment: "I have placed my phone on the passport" },
|
||||
{ header: "Start scanning", subtitle: "Press Start NFC Scan and follow the on-screen instructions.", acknowledgment: "Start scanning" },
|
||||
]
|
||||
|
||||
const currentSlide = slideTexts[imageIndex] || { header: "No header", subtitle: "No subtitle for this slide", acknowledgment: "Continue" }
|
||||
|
||||
return (
|
||||
<YStack f={1} >
|
||||
|
||||
<XStack
|
||||
overflow="hidden"
|
||||
backgroundColor="#000"
|
||||
position="relative"
|
||||
height={height}
|
||||
alignItems="center"
|
||||
borderRadius="$10"
|
||||
mt="$5"
|
||||
>
|
||||
<AnimatePresence initial={false} custom={{ going }}>
|
||||
<GalleryItem key={page} animation="medium" going={going}>
|
||||
<Image source={{ uri: images[imageIndex] }} height={height} resizeMode="contain" />
|
||||
</GalleryItem>
|
||||
</AnimatePresence>
|
||||
|
||||
|
||||
{imageIndex > 0 && (
|
||||
<Button
|
||||
icon={ArrowLeft}
|
||||
size="$5"
|
||||
position="absolute"
|
||||
left="$4"
|
||||
circular
|
||||
elevate
|
||||
onPress={() => paginate(-1)}
|
||||
zi={100}
|
||||
/>
|
||||
)}
|
||||
</XStack>
|
||||
|
||||
<YStack ml="$2">
|
||||
<Text fontSize="$8" mt="$4" color={textBlack} textAlign='center'>{currentSlide.header}</Text>
|
||||
<Text color={textBlack} fontSize="$5" mt="$2" textAlign='center' style={{ opacity: 0.7 }} fontStyle='italic'>{currentSlide.subtitle}</Text>
|
||||
</YStack>
|
||||
|
||||
<XStack justifyContent='center' alignItems='center' gap="$1.5" position="absolute" style={{ bottom: 120, left: 0, right: 0 }}>
|
||||
<ShieldCheck color={textBlack} size={14} />
|
||||
<Text color={textBlack} fontSize="$4" >private and secured</Text>
|
||||
</XStack>
|
||||
<XStack f={1} />
|
||||
|
||||
<CustomButton
|
||||
onPress={isLastImage ? () => handleNfcScan?.() : () => paginate(+1)}
|
||||
text={currentSlide.acknowledgment}
|
||||
Icon={isLastImage ? <Nfc /> : undefined}
|
||||
blueVariant={!isLastImage}
|
||||
/>
|
||||
</YStack>
|
||||
)
|
||||
}
|
||||
@@ -1,23 +1,32 @@
|
||||
import React from 'react';
|
||||
import { Button } from 'tamagui';
|
||||
import { bgGreen, textBlack } from '../utils/colors';
|
||||
import { Button, Text } from 'tamagui';
|
||||
import { bgBlue, bgGreen, textBlack } from '../utils/colors';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
|
||||
interface CustomButtonProps {
|
||||
text: string;
|
||||
onPress: () => void;
|
||||
Icon?: React.ReactNode;
|
||||
bgColor?: string;
|
||||
h?: string;
|
||||
isDisabled?: boolean;
|
||||
disabledOnPress?: () => void;
|
||||
blueVariant?: boolean;
|
||||
}
|
||||
|
||||
const CustomButton: React.FC<CustomButtonProps> = ({ text, onPress, Icon, bgColor }) => {
|
||||
const CustomButton: React.FC<CustomButtonProps> = ({ text, onPress, Icon, bgColor, h, isDisabled, disabledOnPress, blueVariant }) => {
|
||||
const {
|
||||
toast,
|
||||
} = useNavigationStore();
|
||||
return (
|
||||
<Button bg={bgColor ? bgColor : bgGreen} h="$4.5" borderRadius="$10" mx="$3" onPress={onPress}>
|
||||
<Button bg={bgColor ? bgColor : blueVariant ? bgBlue : bgGreen} h={blueVariant ? "$8" : "$4.5"} borderRadius="$10" mx="$3" onPress={isDisabled ? disabledOnPress : onPress}>
|
||||
{Icon && <Button.Icon>{Icon}</Button.Icon>}
|
||||
<Button.Text fontSize="$5" fontWeight="bold" color={textBlack}>
|
||||
<Text textAlign='center' fontSize={blueVariant ? "$6" : "$5"} fontWeight="bold" color={textBlack}>
|
||||
{text}
|
||||
</Button.Text>
|
||||
</Text>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomButton;
|
||||
|
||||
export default CustomButton;
|
||||
20
app/src/components/StepOneStepTwo.tsx
Normal file
20
app/src/components/StepOneStepTwo.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import { XStack } from "tamagui";
|
||||
import { textBlack } from "../utils/colors";
|
||||
|
||||
interface StepOneStepTwoProps {
|
||||
variable: string;
|
||||
step1: string;
|
||||
step2: string;
|
||||
}
|
||||
const StepOneStepTwo = ({ variable, step1, step2 }: StepOneStepTwoProps) => {
|
||||
const isVisible = variable === step1 || variable === step2;
|
||||
|
||||
return (
|
||||
<XStack px="$4" mt="$4" gap="$3" style={{ opacity: isVisible ? 1 : 0 }}>
|
||||
<XStack h="$0.25" f={1} bg={textBlack} borderRadius={100} style={{ opacity: variable === step1 ? 1 : 0.2 }} />
|
||||
<XStack h="$0.25" f={1} bg={textBlack} borderRadius={100} style={{ opacity: variable === step2 ? 1 : 0.2 }} />
|
||||
</XStack>
|
||||
)
|
||||
}
|
||||
|
||||
export default StepOneStepTwo;
|
||||
55
app/src/screens/AppScreen copy.tsx
Normal file
55
app/src/screens/AppScreen copy.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import { ScrollView, YStack } from 'tamagui';
|
||||
import AppCard from '../components/AppCard';
|
||||
import { Steps } from '../utils/utils';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import { AppType } from '../utils/appType';
|
||||
import sbtApp from '../apps/sbt';
|
||||
import zupassApp from '../apps/zupass';
|
||||
import gitcoinApp from '../apps/gitcoin';
|
||||
|
||||
const AppScreen: React.FC = () => {
|
||||
const {
|
||||
selectedApp,
|
||||
update
|
||||
} = useNavigationStore();
|
||||
|
||||
const handleCardSelect = (app: AppType) => {
|
||||
update({
|
||||
selectedTab: "prove",
|
||||
selectedApp: app,
|
||||
step: Steps.APP_SELECTED,
|
||||
})
|
||||
};
|
||||
|
||||
// add new apps here
|
||||
const cardsData = [
|
||||
sbtApp,
|
||||
zupassApp,
|
||||
gitcoinApp
|
||||
];
|
||||
|
||||
return (
|
||||
<ScrollView f={1}>
|
||||
<YStack my="$8" gap="$5" px="$5" jc="center" alignItems='center'>
|
||||
{
|
||||
cardsData.map(app => (
|
||||
<AppCard
|
||||
key={app.id}
|
||||
title={app.title}
|
||||
description={app.description}
|
||||
id={app.id}
|
||||
onTouchStart={() => handleCardSelect(app)}
|
||||
selected={selectedApp && selectedApp.id === app.id ? true : false}
|
||||
selectable={app.selectable}
|
||||
icon={app.icon}
|
||||
tags={app.tags}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</YStack>
|
||||
</ScrollView>
|
||||
);
|
||||
}
|
||||
|
||||
export default AppScreen;
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { ScrollView, YStack } from 'tamagui';
|
||||
import { ScrollView, Text, YStack } from 'tamagui';
|
||||
import AppCard from '../components/AppCard';
|
||||
import { Steps } from '../utils/utils';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
@@ -7,13 +7,26 @@ import { AppType } from '../utils/appType';
|
||||
import sbtApp from '../apps/sbt';
|
||||
import zupassApp from '../apps/zupass';
|
||||
import gitcoinApp from '../apps/gitcoin';
|
||||
import { XStack } from 'tamagui';
|
||||
import CustomButton from '../components/CustomButton';
|
||||
import { BadgeCheck, Binary, LockKeyhole, QrCode, ShieldCheck, Smartphone, UserPlus } from '@tamagui/lucide-icons';
|
||||
import { bgBlue, bgGreen, separatorColor, textBlack } from '../utils/colors';
|
||||
import { orange } from '@tamagui/colors';
|
||||
import useUserStore from '../stores/userStore';
|
||||
|
||||
const AppScreen: React.FC = () => {
|
||||
const {
|
||||
selectedApp,
|
||||
update
|
||||
update,
|
||||
selectedTab,
|
||||
setSelectedTab
|
||||
} = useNavigationStore();
|
||||
|
||||
const {
|
||||
registered,
|
||||
setRegistered
|
||||
} = useUserStore();
|
||||
|
||||
const handleCardSelect = (app: AppType) => {
|
||||
update({
|
||||
selectedTab: "prove",
|
||||
@@ -22,7 +35,6 @@ const AppScreen: React.FC = () => {
|
||||
})
|
||||
};
|
||||
|
||||
// add new apps here
|
||||
const cardsData = [
|
||||
sbtApp,
|
||||
zupassApp,
|
||||
@@ -30,8 +42,76 @@ const AppScreen: React.FC = () => {
|
||||
];
|
||||
|
||||
return (
|
||||
<ScrollView f={1}>
|
||||
<YStack my="$8" gap="$5" px="$5" jc="center" alignItems='center'>
|
||||
<YStack f={1} pb="$3" px="$3">
|
||||
{/* <XStack h="$0.25" bg={separatorColor} mx="$0" /> */}
|
||||
<ScrollView >
|
||||
<YStack >
|
||||
<Text fontSize="$8" mt="$2" >Account</Text>
|
||||
<XStack ml="$2" gap="$2" ai="center">
|
||||
<Text fontSize="$5">status:</Text>
|
||||
{registered ?
|
||||
<XStack bg={bgGreen} px="$2.5" py="$2" borderRadius="$10">
|
||||
<Text color={textBlack} fontSize="$4">registered</Text>
|
||||
</XStack> :
|
||||
<XStack bg={'#FFB897'} px="$2.5" py="$2" borderRadius="$10">
|
||||
<Text color={textBlack} fontSize="$4">not registered</Text>
|
||||
</XStack>}
|
||||
</XStack>
|
||||
{/* <XStack ml="$2" gap="$2" mt="$1">
|
||||
<Text fontSize="$5">userID:</Text>
|
||||
<Text color={textBlack} fontSize="$5">0x1234567890</Text>
|
||||
</XStack> */}
|
||||
</YStack>
|
||||
<YStack>
|
||||
<Text mt="$4" fontSize="$8" >How to use Proof of Passport?</Text>
|
||||
<YStack>
|
||||
<XStack mt="$3" px="$5" gap="$2" >
|
||||
<QrCode size={50} color={textBlack} />
|
||||
<YStack>
|
||||
<Text fontSize="$5" mb="$1">Scan QR code</Text>
|
||||
<XStack gap="$2"><Text fontSize="$3">1</Text><Text fontSize="$3" maxWidth={220}>Find the QR code on the page of the app that asks for proof of passport.</Text></XStack>
|
||||
<XStack mt="$1" gap="$2"><Text fontSize="$3">2</Text><Text fontSize="$3" maxWidth={220}>Scan the QR code.</Text></XStack>
|
||||
</YStack>
|
||||
</XStack>
|
||||
<XStack mt="$4" px="$5" gap="$2" >
|
||||
<BadgeCheck size={50} color={textBlack} />
|
||||
<YStack>
|
||||
<Text fontSize="$5" mb="$1">Generate a Proof</Text>
|
||||
<XStack gap="$2"><Text fontSize="$3">1</Text><Text fontSize="$3" maxWidth={220}>Generate a proof of the selected information.</Text></XStack>
|
||||
<XStack mt="$1" gap="$2"><Text fontSize="$3">2</Text><Text fontSize="$3" maxWidth={220}>Share the proof with the application.</Text></XStack>
|
||||
</YStack>
|
||||
</XStack>
|
||||
</YStack>
|
||||
</YStack>
|
||||
<YStack mb="$4">
|
||||
<Text mt="$5" fontSize="$8" >How does it works?</Text>
|
||||
<YStack>
|
||||
<XStack mt="$3" px="$5" gap="$2" >
|
||||
<Binary size={50} color={textBlack} />
|
||||
<YStack>
|
||||
<Text fontSize="$5" mb="$1">Strong cryptography</Text>
|
||||
<XStack gap="$2"><Text fontSize="$3">·</Text><Text fontSize="$3" maxWidth={220}>Proof of Passport uses ZK technologies which allows you to prove a statement without revealing why it's true.</Text></XStack>
|
||||
<XStack gap="$2"><Text fontSize="$3">·</Text><Text fontSize="$3" maxWidth={220}>You are always anonymous</Text></XStack>
|
||||
</YStack>
|
||||
</XStack>
|
||||
<XStack mt="$3" px="$5" gap="$2" >
|
||||
<Smartphone size={50} color={textBlack} />
|
||||
<YStack>
|
||||
<Text fontSize="$5" mb="$1">Serverless</Text>
|
||||
<XStack gap="$2"><Text fontSize="$3">·</Text><Text fontSize="$3" maxWidth={220}>Proof of Passport will never receive your data and will never know who you are.</Text></XStack>
|
||||
<XStack gap="$2"><Text fontSize="$3">·</Text><Text fontSize="$3" maxWidth={220}>Everything is achieved on your device, even the camera and NFC scanning.</Text></XStack>
|
||||
|
||||
</YStack>
|
||||
</XStack>
|
||||
</YStack>
|
||||
</YStack>
|
||||
</ScrollView>
|
||||
|
||||
|
||||
<XStack f={1} minHeight="$1" />
|
||||
{registered ? <CustomButton text="Scan QR code" onPress={() => setRegistered(false)} Icon={<QrCode size={18} color={textBlack} />} /> :
|
||||
<CustomButton text="Register" onPress={() => { setSelectedTab("start"); setRegistered(true); }} Icon={<UserPlus size={18} color={textBlack} />} />}
|
||||
{/* <YStack my="$8" gap="$5" px="$5" jc="center" alignItems='center'>
|
||||
{
|
||||
cardsData.map(app => (
|
||||
<AppCard
|
||||
@@ -47,8 +127,8 @@ const AppScreen: React.FC = () => {
|
||||
/>
|
||||
))
|
||||
}
|
||||
</YStack>
|
||||
</ScrollView>
|
||||
</YStack> */}
|
||||
</YStack>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import { YStack, Button, Image, Text } from 'tamagui';
|
||||
import { Camera, SquarePen } from '@tamagui/lucide-icons';
|
||||
import { bgColor, borderColor, textColor1, textColor2 } from '../utils/colors';
|
||||
import { YStack, Button, Image, Text, ScrollView, XStack, Separator } from 'tamagui';
|
||||
import { Camera, ShieldCheck, SquarePen, X } from '@tamagui/lucide-icons';
|
||||
import { bgColor, bgGreen, borderColor, componentBgColor, componentBgColor2, separatorColor, textBlack, textColor1, textColor2 } from '../utils/colors';
|
||||
import SCANHelp from '../images/scan_help.png'
|
||||
import { startCameraScan } from '../utils/cameraScanner';
|
||||
import CustomButton from '../components/CustomButton';
|
||||
|
||||
interface CameraScreenProps {
|
||||
sheetIsOpen: boolean
|
||||
@@ -11,30 +12,31 @@ interface CameraScreenProps {
|
||||
}
|
||||
|
||||
const CameraScreen: React.FC<CameraScreenProps> = ({ sheetIsOpen, setSheetIsOpen }) => {
|
||||
|
||||
return (
|
||||
<YStack f={1} p="$3">
|
||||
<YStack f={1} jc="center">
|
||||
<Image borderRadius="$5"
|
||||
<YStack f={1} mt="$16">
|
||||
<Text ml="$1" fontSize={34} color={textBlack}><Text style={{ textDecorationLine: 'underline', textDecorationColor: bgGreen }}>Scan</Text> or type your passport ID</Text>
|
||||
<Text ml="$2" mt="$8" fontSize="$8" color={textBlack}>Open your passport on the <Text style={{ textDecorationLine: 'underline', textDecorationColor: bgGreen }}>main page</Text> to scan it.</Text>
|
||||
<Text ml="$2" mt="$2" fontSize="$8" color={textBlack} style={{ opacity: 0.7 }}>Your data never leaves your device.</Text>
|
||||
<XStack f={1} />
|
||||
|
||||
<XStack justifyContent='center' alignItems='center' gap="$1.5">
|
||||
<ShieldCheck color={textBlack} size={14} />
|
||||
<Text color={textBlack} fontSize="$4">private and secured</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
{/* <Image borderRadius="$5"
|
||||
w="full"
|
||||
h="$13"
|
||||
source={{ uri: SCANHelp }}
|
||||
/>
|
||||
<YStack gap="$0.5" mt="$3.5">
|
||||
<Text mt="$1" color={textColor1}>Use your camera to scan the main page of your passport.</Text>
|
||||
<Text fontSize="$2" color={textColor2} mt="$2">You can also enter those data manually.</Text>
|
||||
<Text fontSize="$2" style={{ fontStyle: 'italic' }} color={textColor2}>The app does not take a picture of your passport, it only reads some fields.</Text>
|
||||
</YStack>
|
||||
/> */}
|
||||
|
||||
<YStack gap="$2.5" mt="$5" >
|
||||
<CustomButton text="Open Camera" onPress={startCameraScan} Icon={<Camera color={textBlack} size={24} />} />
|
||||
<CustomButton bgColor='#ffff' text="Manual Input" onPress={() => setSheetIsOpen(true)} Icon={<SquarePen color={textBlack} size={24} />} />
|
||||
</YStack>
|
||||
|
||||
<YStack gap="$2" mb="$6">
|
||||
<Button borderWidth={1.3} borderColor={borderColor} borderRadius="$10" bg="#3185FC" onPress={startCameraScan}><Camera color={textColor1} /></Button>
|
||||
<Button bg={textColor2} borderColor={borderColor} borderRadius="$10" onPress={() => setSheetIsOpen(true)}><SquarePen /></Button>
|
||||
</YStack>
|
||||
|
||||
</YStack >
|
||||
</YStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default CameraScreen;
|
||||
export default CameraScreen;
|
||||
@@ -4,9 +4,9 @@ import forge from 'node-forge';
|
||||
import Dialog from "react-native-dialog";
|
||||
import { ethers } from 'ethers';
|
||||
// import ressources
|
||||
import { YStack, XStack, Text, Button, Tabs, Sheet, Label, Fieldset, Input, Switch, H2, Image, useWindowDimensions, H4, H3 } from 'tamagui'
|
||||
import { HelpCircle, IterationCw, VenetianMask, Cog, CheckCircle2, ChevronLeft, Share, Eraser, CalendarSearch } from '@tamagui/lucide-icons';
|
||||
import X from '../images/x.png'
|
||||
import { YStack, XStack, Text, Button, Tabs, Sheet, Label, Fieldset, Input, Switch, H2, Image, useWindowDimensions, H4, H3, Separator } from 'tamagui'
|
||||
import { HelpCircle, IterationCw, VenetianMask, Cog, CheckCircle2, ChevronLeft, Share, Eraser, CalendarSearch, Cross, X } from '@tamagui/lucide-icons';
|
||||
import Xlogo from '../images/x.png'
|
||||
import Telegram from '../images/telegram.png'
|
||||
import Github from '../images/github.png'
|
||||
import Internet from "../images/internet.png"
|
||||
@@ -17,7 +17,7 @@ import { ToastMessage } from '../components/ToastMessage';
|
||||
import useUserStore from '../stores/userStore';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
// import utils
|
||||
import { bgColor, blueColorLight, borderColor, componentBgColor, componentBgColor2, textColor1, textColor2 } from '../utils/colors';
|
||||
import { bgColor, bgGreen, bgWhite, blueColorLight, borderColor, componentBgColor, componentBgColor2, separatorColor, textBlack, textColor1, textColor2 } from '../utils/colors';
|
||||
import { ModalProofSteps, Steps } from '../utils/utils';
|
||||
import { scan } from '../utils/nfcScanner';
|
||||
import { CircuitName, fetchZkey } from '../utils/zkeyDownload';
|
||||
@@ -41,6 +41,10 @@ import { RPC_URL, SignatureAlgorithm } from '../../../common/src/constants/const
|
||||
import { mock_csca_sha256_rsa_4096, mock_dsc_sha256_rsa_4096 } from '../../../common/src/constants/mockCertificates';
|
||||
|
||||
import DatePicker from 'react-native-date-picker'
|
||||
import StartScreen from './StartScreen';
|
||||
import CustomButton from '../components/CustomButton';
|
||||
import StepOneStepTwo from '../components/StepOneStepTwo';
|
||||
import SplashScreen from './SplashScreen';
|
||||
|
||||
const MainScreen: React.FC = () => {
|
||||
const [NFCScanIsOpen, setNFCScanIsOpen] = useState(false);
|
||||
@@ -51,10 +55,11 @@ const MainScreen: React.FC = () => {
|
||||
const [HelpIsOpen, setHelpIsOpen] = useState(false);
|
||||
const [sheetIsOpen, setSheetIsOpen] = useState(false);
|
||||
const [modalProofStep, setModalProofStep] = useState(0);
|
||||
const [dateOfBirthDatePicker, setDateOfBirthDatePicker] = useState(new Date())
|
||||
const [dateOfExpiryDatePicker, setDateOfExpiryDatePicker] = useState(new Date())
|
||||
const [dateOfBirthDatePicker, setDateOfBirthDatePicker] = useState<Date | null>(null)
|
||||
const [dateOfExpiryDatePicker, setDateOfExpiryDatePicker] = useState<Date | null>(null)
|
||||
const [dateOfBirthDatePickerIsOpen, setDateOfBirthDatePickerIsOpen] = useState(false)
|
||||
const [dateOfExpiryDatePickerIsOpen, setDateOfExpiryDatePickerIsOpen] = useState(false)
|
||||
const [isFormComplete, setIsFormComplete] = useState(false);
|
||||
|
||||
const {
|
||||
passportNumber,
|
||||
@@ -78,6 +83,7 @@ const MainScreen: React.FC = () => {
|
||||
step,
|
||||
setStep,
|
||||
selectedTab,
|
||||
setSelectedTab,
|
||||
hideData,
|
||||
toast,
|
||||
showRegistrationErrorSheet,
|
||||
@@ -86,8 +92,7 @@ const MainScreen: React.FC = () => {
|
||||
|
||||
const handleRestart = () => {
|
||||
updateNavigationStore({
|
||||
selectedTab: "scan",
|
||||
selectedApp: null,
|
||||
selectedTab: "start",
|
||||
step: Steps.MRZ_SCAN,
|
||||
})
|
||||
deleteMrzFields();
|
||||
@@ -145,11 +150,14 @@ const MainScreen: React.FC = () => {
|
||||
}
|
||||
|
||||
const decrementStep = () => {
|
||||
if (selectedTab === "nfc") {
|
||||
setStep(Steps.MRZ_SCAN);
|
||||
if (selectedTab === "scan") {
|
||||
setSelectedTab("start");
|
||||
}
|
||||
else if (selectedTab === "nfc") {
|
||||
setSelectedTab("scan");
|
||||
}
|
||||
else if (selectedTab === "next") {
|
||||
setStep(Steps.MRZ_SCAN_COMPLETED);
|
||||
setSelectedTab("nfc");
|
||||
}
|
||||
else if (selectedTab === "register") {
|
||||
setStep(Steps.NEXT_SCREEN);
|
||||
@@ -218,87 +226,115 @@ const MainScreen: React.FC = () => {
|
||||
}
|
||||
}, [modalProofStep]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (passportNumber?.length === 9 && (dateOfBirth?.length === 6 && dateOfExpiry?.length === 6)) {
|
||||
setStep(Steps.MRZ_SCAN_COMPLETED);
|
||||
}
|
||||
setIsFormComplete(passportNumber?.length === 9 && dateOfBirth?.length === 6 && dateOfExpiry?.length === 6);
|
||||
}, [passportNumber, dateOfBirth, dateOfExpiry]);
|
||||
|
||||
useEffect(() => {
|
||||
if (registered && step < Steps.REGISTERED) {
|
||||
setStep(Steps.REGISTERED);
|
||||
}
|
||||
}, [registered]);
|
||||
// useEffect(() => {
|
||||
// if (registered && step < Steps.REGISTERED) {
|
||||
// setStep(Steps.REGISTERED);
|
||||
// }
|
||||
// }, [registered]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
let timeoutId: ReturnType<typeof setTimeout>;
|
||||
if (step == Steps.MRZ_SCAN) {
|
||||
updateNavigationStore({
|
||||
selectedTab: "scan",
|
||||
})
|
||||
timeoutId = setTimeout(() => {
|
||||
setNFCScanIsOpen(false);
|
||||
}, 0);
|
||||
}
|
||||
else if (step == Steps.MRZ_SCAN_COMPLETED) {
|
||||
updateNavigationStore({
|
||||
selectedTab: "nfc",
|
||||
})
|
||||
timeoutId = setTimeout(() => {
|
||||
setNFCScanIsOpen(false);
|
||||
}, 0);
|
||||
}
|
||||
else if (step == Steps.NEXT_SCREEN) {
|
||||
// Set the timeout and store its ID
|
||||
timeoutId = setTimeout(() => {
|
||||
setNFCScanIsOpen(false);
|
||||
}, 700);
|
||||
}
|
||||
else if (step == Steps.PROOF_GENERATED) {
|
||||
updateNavigationStore({
|
||||
selectedTab: "mint",
|
||||
})
|
||||
}
|
||||
if (step == Steps.NEXT_SCREEN) {
|
||||
updateNavigationStore({
|
||||
selectedTab: "next",
|
||||
})
|
||||
}
|
||||
if (step == Steps.REGISTER) {
|
||||
updateNavigationStore({
|
||||
selectedTab: "register",
|
||||
})
|
||||
}
|
||||
if (step == Steps.REGISTERED) {
|
||||
updateNavigationStore({
|
||||
selectedTab: "app",
|
||||
})
|
||||
}
|
||||
return () => {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
}
|
||||
};
|
||||
}, [step]);
|
||||
// useEffect(() => {
|
||||
// let timeoutId: ReturnType<typeof setTimeout>;
|
||||
// if (step == Steps.START) {
|
||||
// updateNavigationStore({
|
||||
// selectedTab: "start",
|
||||
// })
|
||||
// }
|
||||
|
||||
// if (step == Steps.MRZ_SCAN) {
|
||||
// updateNavigationStore({
|
||||
// selectedTab: "scan",
|
||||
// })
|
||||
// timeoutId = setTimeout(() => {
|
||||
// setNFCScanIsOpen(false);
|
||||
// }, 0);
|
||||
// }
|
||||
// else if (step == Steps.MRZ_SCAN_COMPLETED) {
|
||||
// updateNavigationStore({
|
||||
// selectedTab: "nfc",
|
||||
// })
|
||||
// timeoutId = setTimeout(() => {
|
||||
// setNFCScanIsOpen(false);
|
||||
// }, 0);
|
||||
// }
|
||||
// else if (step == Steps.NEXT_SCREEN) {
|
||||
// // Set the timeout and store its ID
|
||||
// timeoutId = setTimeout(() => {
|
||||
// setNFCScanIsOpen(false);
|
||||
// }, 700);
|
||||
// }
|
||||
// else if (step == Steps.PROOF_GENERATED) {
|
||||
// updateNavigationStore({
|
||||
// selectedTab: "mint",
|
||||
// })
|
||||
// }
|
||||
// if (step == Steps.NEXT_SCREEN) {
|
||||
// updateNavigationStore({
|
||||
// selectedTab: "next",
|
||||
// })
|
||||
// }
|
||||
// if (step == Steps.REGISTER) {
|
||||
// updateNavigationStore({
|
||||
// selectedTab: "register",
|
||||
// })
|
||||
// }
|
||||
// if (step == Steps.REGISTERED) {
|
||||
// updateNavigationStore({
|
||||
// selectedTab: "app",
|
||||
// })
|
||||
// }
|
||||
// return () => {
|
||||
// if (timeoutId) {
|
||||
// clearTimeout(timeoutId);
|
||||
// }
|
||||
// };
|
||||
// }, [step]);
|
||||
|
||||
const { height } = useWindowDimensions();
|
||||
|
||||
return (
|
||||
<>
|
||||
<YStack f={1} bc="#161616" mt={Platform.OS === 'ios' ? "$8" : "$0"} >
|
||||
<YStack f={1}>
|
||||
<ToastViewport portalToRoot flexDirection="column-reverse" top={85} right={0} left={0} />
|
||||
<ToastMessage />
|
||||
<YStack f={1} mt={Platform.OS === 'ios' ? "$8" : "$0"} mb={Platform.OS === 'ios' ? "$4" : "$2"}>
|
||||
<YStack >
|
||||
<XStack jc="space-between" ai="center" px="$3">
|
||||
<Button p="$2" py="$3" unstyled onPress={decrementStep}><ChevronLeft color={(selectedTab === "scan") ? "transparent" : "#a0a0a0"} /></Button>
|
||||
|
||||
<Text fontSize="$6" color="#a0a0a0">
|
||||
{selectedTab === "scan" ? "Scan" : (selectedTab === "app" ? "Apps" : "Prove")}
|
||||
</Text>
|
||||
<XStack>
|
||||
<Button p="$2" py="$3" unstyled onPress={() => setSettingsIsOpen(true)}><Cog color="#a0a0a0" /></Button>
|
||||
<Button p="$2" py="$3" unstyled onPress={() => setHelpIsOpen(true)}><HelpCircle color="#a0a0a0" /></Button>
|
||||
<StepOneStepTwo variable={selectedTab} step1="scan" step2="nfc" />
|
||||
{selectedTab !== "app" && <XStack onPress={() => setSelectedTab("app")} px="$4" py="$2" mt="$3" alignSelf='flex-end'><X size={28} color={textBlack} /></XStack>}
|
||||
{selectedTab === "app" &&
|
||||
<XStack px="$4" py="$2" mt="$0" ai="center">
|
||||
<Text fontSize="$9" >Proof of Passport</Text>
|
||||
{/* <XStack onPress={() => setHelpIsOpen(true)}><HelpCircle size={28} color={textBlack} /></XStack> */}
|
||||
<XStack f={1} />
|
||||
<XStack p="$2" onPress={() => setSettingsIsOpen(true)}><Cog size={24} color={textBlack} /></XStack>
|
||||
</XStack>
|
||||
</XStack>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
{/* {selectedTab !== "start" && selectedTab !== "scan" && selectedTab !== "nfc" && selectedTab !== "next" && selectedTab !== "register" && (
|
||||
<YStack>
|
||||
<XStack jc="space-between" ai="center" px="$3">
|
||||
<Button p="$2" py="$3" unstyled onPress={decrementStep}><ChevronLeft color={(selectedTab === "start") ? "transparent" : "#a0a0a0"} /></Button>
|
||||
|
||||
<Text fontSize="$6" color="#a0a0a0">
|
||||
{selectedTab === "scan" ? "Scan" : (selectedTab === "app" ? "Apps" : "Prove")}
|
||||
</Text>
|
||||
<XStack>
|
||||
<Button p="$2" py="$3" unstyled onPress={() => setSettingsIsOpen(true)}><Cog color="#a0a0a0" /></Button>
|
||||
<Button p="$2" py="$3" unstyled onPress={() => setHelpIsOpen(true)}><HelpCircle color="#a0a0a0" /></Button>
|
||||
</XStack>
|
||||
</XStack>
|
||||
<Separator borderColor={separatorColor} />
|
||||
</YStack>
|
||||
)} */}
|
||||
<Sheet open={NFCScanIsOpen} onOpenChange={setNFCScanIsOpen} dismissOnSnapToBottom modal dismissOnOverlayPress={false} disableDrag animation="medium" snapPoints={[35]}>
|
||||
<Sheet.Overlay />
|
||||
<Sheet.Frame>
|
||||
@@ -464,7 +500,7 @@ const MainScreen: React.FC = () => {
|
||||
</Pressable>
|
||||
<Pressable onPress={() => Linking.openURL('https://x.com/proofofpassport')}>
|
||||
<Image
|
||||
source={{ uri: X, width: 24, height: 24 }}
|
||||
source={{ uri: Xlogo, width: 24, height: 24 }}
|
||||
/>
|
||||
</Pressable>
|
||||
<Pressable onPress={() => Linking.openURL('https://github.com/zk-passport/proof-of-passport')}>
|
||||
@@ -501,28 +537,32 @@ const MainScreen: React.FC = () => {
|
||||
</YStack>
|
||||
|
||||
</YStack>
|
||||
{/* <Button mt="$3" bg={componentBgColor} jc="center" borderColor={borderColor} borderWidth={1.2} size="$3.5" ml="$2" alignSelf='center' w="80%" onPress={() => setHelpIsOpen(false)}>
|
||||
<Text color={textColor1} w="80%" textAlign='center' fow="bold">Close</Text>
|
||||
</Button> */}
|
||||
|
||||
</YStack>
|
||||
</Sheet.Frame>
|
||||
</Sheet>
|
||||
|
||||
<Sheet open={sheetIsOpen} onOpenChange={setSheetIsOpen} dismissOnSnapToBottom modal animation="medium" snapPoints={[80]}>
|
||||
<Sheet open={sheetIsOpen} onOpenChange={setSheetIsOpen} dismissOnSnapToBottom modal animation="medium" snapPoints={[60]}>
|
||||
<Sheet.Overlay />
|
||||
<Sheet.Frame bg={bgColor} borderRadius="$9" pt="$2">
|
||||
<Sheet.Frame bg={bgWhite} borderRadius="$9" pt="$2" mb="$3">
|
||||
<YStack p="$4" f={1} gap="$3">
|
||||
<Text fontSize="$6" mb="$4" color={textColor1}>Please provide the following information</Text>
|
||||
<XStack>
|
||||
<Text fontSize="$8" mb="$2">Manual input ✍️</Text>
|
||||
<XStack f={1} />
|
||||
<XStack onPress={() => setSheetIsOpen(false)} p="$2">
|
||||
<X color={borderColor} size="$1.5" mr="$2" />
|
||||
</XStack>
|
||||
</XStack>
|
||||
<Separator borderColor={separatorColor} />
|
||||
<Fieldset gap="$4" horizontal>
|
||||
<Text color={textColor1} width={160} justifyContent="flex-end" fontSize="$4">
|
||||
<Text color={textBlack} width={160} justifyContent="flex-end" fontSize="$5">
|
||||
Passport Number
|
||||
</Text>
|
||||
<Input
|
||||
bg={componentBgColor}
|
||||
color={textColor1}
|
||||
bg={bgWhite}
|
||||
color={textBlack}
|
||||
h="$3.5"
|
||||
borderColor={passportNumber?.length === 9 ? "green" : "unset"}
|
||||
borderColor={passportNumber?.length === 9 ? bgGreen : textBlack}
|
||||
flex={1}
|
||||
id="passportnumber"
|
||||
onChangeText={(text) => {
|
||||
@@ -535,24 +575,22 @@ const MainScreen: React.FC = () => {
|
||||
|
||||
|
||||
<Fieldset gap="$4" horizontal>
|
||||
<Text color={textColor1} width={160} justifyContent="flex-end" fontSize="$4">
|
||||
<Text color={textBlack} width={160} justifyContent="flex-end" fontSize="$5">
|
||||
Date of birth
|
||||
</Text>
|
||||
<Text color={textColor1}>
|
||||
{dateOfBirthDatePicker.toISOString().slice(0, 10)}
|
||||
<Text color={textBlack} f={1}>
|
||||
{dateOfBirthDatePicker ? dateOfBirthDatePicker.toISOString().slice(0, 10) : ''}
|
||||
</Text>
|
||||
<Button bg="white" onPress={() => setDateOfBirthDatePickerIsOpen(true)}
|
||||
pressStyle={{
|
||||
bg: componentBgColor2,
|
||||
borderColor: componentBgColor2,
|
||||
}}>
|
||||
<Button bg={bgGreen} onPress={() => setDateOfBirthDatePickerIsOpen(true)}
|
||||
borderRadius={"$10"}
|
||||
>
|
||||
<CalendarSearch />
|
||||
</Button>
|
||||
<DatePicker
|
||||
modal
|
||||
mode='date'
|
||||
open={dateOfBirthDatePickerIsOpen}
|
||||
date={dateOfBirthDatePicker}
|
||||
date={dateOfBirthDatePicker || new Date()}
|
||||
onConfirm={(date) => {
|
||||
setDateOfBirthDatePickerIsOpen(false)
|
||||
setDateOfBirthDatePicker(date)
|
||||
@@ -562,39 +600,24 @@ const MainScreen: React.FC = () => {
|
||||
setDateOfBirthDatePickerIsOpen(false)
|
||||
}}
|
||||
/>
|
||||
{/* <Input
|
||||
bg={componentBgColor}
|
||||
color={textColor1}
|
||||
h="$3.5"
|
||||
borderColor={dateOfBirth?.length === 6 ? "green" : "unset"}
|
||||
flex={1}
|
||||
id="dateofbirth"
|
||||
onChangeText={(text) => {
|
||||
update({ dateOfBirth: text })
|
||||
}}
|
||||
value={dateOfBirth}
|
||||
keyboardType={Platform.OS === "ios" ? "default" : "number-pad"}
|
||||
/> */}
|
||||
</Fieldset>
|
||||
<Fieldset gap="$4" horizontal>
|
||||
<Text color={textColor1} width={160} justifyContent="flex-end" fontSize="$4">
|
||||
<Text color={textBlack} width={160} justifyContent="flex-end" fontSize="$5">
|
||||
Date of expiry
|
||||
</Text>
|
||||
<Text color={textColor1}>
|
||||
{dateOfExpiryDatePicker.toISOString().slice(0, 10)}
|
||||
<Text color={textBlack} f={1}>
|
||||
{dateOfExpiryDatePicker ? dateOfExpiryDatePicker.toISOString().slice(0, 10) : ''}
|
||||
</Text>
|
||||
<Button bg="white" onPress={() => setDateOfExpiryDatePickerIsOpen(true)}
|
||||
pressStyle={{
|
||||
bg: componentBgColor2,
|
||||
borderColor: componentBgColor2,
|
||||
}}>
|
||||
<Button bg={bgGreen} onPress={() => setDateOfExpiryDatePickerIsOpen(true)}
|
||||
borderRadius="$10"
|
||||
>
|
||||
<CalendarSearch />
|
||||
</Button>
|
||||
<DatePicker
|
||||
modal
|
||||
mode='date'
|
||||
open={dateOfExpiryDatePickerIsOpen}
|
||||
date={dateOfExpiryDatePicker}
|
||||
date={dateOfExpiryDatePicker || new Date()}
|
||||
onConfirm={(date) => {
|
||||
setDateOfExpiryDatePickerIsOpen(false)
|
||||
setDateOfExpiryDatePicker(date)
|
||||
@@ -604,53 +627,24 @@ const MainScreen: React.FC = () => {
|
||||
setDateOfExpiryDatePickerIsOpen(false)
|
||||
}}
|
||||
/>
|
||||
{/* <Input
|
||||
bg={componentBgColor}
|
||||
color={textColor1}
|
||||
h="$3.5"
|
||||
borderColor={dateOfExpiry?.length === 6 ? "green" : "unset"}
|
||||
flex={1}
|
||||
id="dateofexpiry"
|
||||
onChangeText={(text) => {
|
||||
update({ dateOfExpiry: text })
|
||||
}}
|
||||
value={dateOfExpiry}
|
||||
keyboardType={Platform.OS === "ios" ? "default" : "number-pad"}
|
||||
/> */}
|
||||
</Fieldset>
|
||||
<XStack f={1} />
|
||||
<YStack mb="$6" gap="$2">
|
||||
<Button
|
||||
bg={textColor1}
|
||||
pressStyle={{
|
||||
bg: componentBgColor2,
|
||||
borderColor: componentBgColor2,
|
||||
}}
|
||||
<YStack gap="$2">
|
||||
<CustomButton
|
||||
text="Submit"
|
||||
onPress={() => {
|
||||
setSheetIsOpen(false)
|
||||
setStep(Steps.MRZ_SCAN_COMPLETED)
|
||||
setSelectedTab("nfc");
|
||||
setSheetIsOpen(false);
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
fontSize="$6"
|
||||
color={bgColor}
|
||||
>Submit</Text>
|
||||
</Button>
|
||||
<Button
|
||||
bg="gray"
|
||||
pressStyle={{
|
||||
bg: componentBgColor2,
|
||||
borderColor: componentBgColor2,
|
||||
}}
|
||||
onPress={() => {
|
||||
setSheetIsOpen(false)
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
fontSize="$6"
|
||||
color={bgColor}
|
||||
>Cancel</Text>
|
||||
</Button>
|
||||
bgColor={isFormComplete ? bgGreen : separatorColor}
|
||||
isDisabled={!isFormComplete}
|
||||
disabledOnPress={() => toast.show('✍️', {
|
||||
message: "Please fill in all fields.",
|
||||
customData: {
|
||||
type: "info",
|
||||
},
|
||||
})}
|
||||
/>
|
||||
</YStack>
|
||||
|
||||
</YStack>
|
||||
@@ -686,14 +680,20 @@ const MainScreen: React.FC = () => {
|
||||
</Sheet.Frame>
|
||||
</Sheet>
|
||||
|
||||
<XStack bc="#343434" h={1.2} />
|
||||
</YStack>
|
||||
|
||||
<Tabs f={1} orientation="horizontal" flexDirection="column" defaultValue={"scan"}
|
||||
value={selectedTab}
|
||||
onValueChange={(value) => updateNavigationStore({ selectedTab: value })}
|
||||
>
|
||||
<ToastViewport flexDirection="column-reverse" top={15} right={0} left={0} />
|
||||
<ToastMessage />
|
||||
<Tabs.Content value="splash" f={1}>
|
||||
<SplashScreen
|
||||
/>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="start" f={1}>
|
||||
<StartScreen
|
||||
/>
|
||||
</Tabs.Content>
|
||||
<Tabs.Content value="scan" f={1}>
|
||||
<CameraScreen
|
||||
sheetIsOpen={sheetIsOpen}
|
||||
@@ -749,7 +749,7 @@ const MainScreen: React.FC = () => {
|
||||
</YStack>
|
||||
</YStack>
|
||||
</Modal>
|
||||
</>
|
||||
</YStack >
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import React from 'react';
|
||||
import { YStack, XStack, Text, Button, Image, useWindowDimensions, Fieldset } from 'tamagui';
|
||||
import { Info } from '@tamagui/lucide-icons';
|
||||
import { ArrowRight, Info } from '@tamagui/lucide-icons';
|
||||
import { getFirstName, maskString } from '../../utils/utils';
|
||||
import { attributeToPosition } from '../../../common/src/constants/constants';
|
||||
import USER from '../images/user.png'
|
||||
import { borderColor, componentBgColor, textColor1, textColor2 } from '../utils/colors';
|
||||
import { bgGreen, borderColor, componentBgColor, textBlack, textColor1, textColor2 } from '../utils/colors';
|
||||
import { Platform } from 'react-native';
|
||||
import { formatAttribute, Steps } from '../utils/utils';
|
||||
import useUserStore from '../stores/userStore';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import CustomButton from '../components/CustomButton';
|
||||
|
||||
|
||||
const NextScreen: React.FC = () => {
|
||||
const {
|
||||
hideData,
|
||||
setStep,
|
||||
setSelectedTab
|
||||
|
||||
} = useNavigationStore()
|
||||
|
||||
@@ -33,7 +35,7 @@ const NextScreen: React.FC = () => {
|
||||
|
||||
return (
|
||||
<YStack px="$4" f={1} mb={Platform.OS === 'ios' ? "$5" : "$0"}>
|
||||
<YStack flex={1} mx="$2" gap="$2">
|
||||
<YStack flex={1} mx="$2" gap="$2" mt="$2">
|
||||
<YStack alignSelf='center' my="$3">
|
||||
{hideData
|
||||
? <Image
|
||||
@@ -54,17 +56,19 @@ const NextScreen: React.FC = () => {
|
||||
/>
|
||||
}
|
||||
</YStack>
|
||||
<Text color={textColor1} fontSize="$5" fontWeight="bold">
|
||||
<Text color={textBlack} fontSize="$8" mt="$8" >
|
||||
Hi{" "}
|
||||
{
|
||||
hideData
|
||||
? maskString(getFirstName(passportData.mrz))
|
||||
: getFirstName(passportData.mrz)
|
||||
}
|
||||
<Text color={textBlack} fontSize="$8" style={{
|
||||
textDecorationLine: "underline", textDecorationColor: bgGreen
|
||||
}}>{
|
||||
hideData
|
||||
? maskString(getFirstName(passportData.mrz))
|
||||
: getFirstName(passportData.mrz)
|
||||
}</Text>
|
||||
{" "}👋
|
||||
</Text>
|
||||
|
||||
<YStack gap="$2.5" mt="$2" ml="$2">
|
||||
<YStack gap="$2" mt="$4" >
|
||||
{Object.keys(disclosureOptions).map((key) => {
|
||||
const key_ = key;
|
||||
const indexes = attributeToPosition[key_ as keyof typeof attributeToPosition];
|
||||
@@ -74,11 +78,15 @@ const NextScreen: React.FC = () => {
|
||||
|
||||
return (
|
||||
<Fieldset horizontal key={key} gap="$3" alignItems='center'>
|
||||
<Text color={textColor2} w="$10" justifyContent="flex-end" >
|
||||
<Text color={textBlack} w="$10" justifyContent="flex-end" fontSize="$5" style={{
|
||||
opacity: 0.7
|
||||
}}>
|
||||
{keyFormatted}:
|
||||
</Text>
|
||||
<Text
|
||||
color={textColor1}
|
||||
color={textBlack}
|
||||
fontSize="$5"
|
||||
|
||||
>
|
||||
{hideData ? maskString(mrzAttributeFormatted) : mrzAttributeFormatted}
|
||||
</Text>
|
||||
@@ -89,20 +97,14 @@ const NextScreen: React.FC = () => {
|
||||
</YStack>
|
||||
<YStack f={1} />
|
||||
|
||||
<XStack mt="$6" bg={componentBgColor} borderRadius={100} borderWidth={1} borderColor={borderColor} py="$2.5" px="$3">
|
||||
<Info alignSelf='center' size={24} color={textColor1} />
|
||||
<Text ml="$3" pr="$6" fontSize="$3" color={textColor1}>Your information will remain confidential and will not be used or shared without your explicit consent.</Text>
|
||||
<XStack bg="#ffff" borderRadius={100} py="$2.5" px="$3">
|
||||
<Info alignSelf='center' size={24} color={textBlack} />
|
||||
<Text ml="$3" pr="$6" fontSize="$3" color={textBlack}>Your information will remain confidential and will not be used or shared without your explicit consent.</Text>
|
||||
</XStack>
|
||||
<Button
|
||||
mt="$8"
|
||||
alignSelf='center'
|
||||
onPress={() => setStep(Steps.REGISTER)}
|
||||
borderWidth={1.3} borderColor={borderColor} borderRadius="$10" bg="#3185FC"
|
||||
mb="$6"
|
||||
w="100%"
|
||||
>
|
||||
<Text color="white" fontSize="$5">Next</Text>
|
||||
</Button>
|
||||
<YStack f={1} />
|
||||
|
||||
<CustomButton onPress={() => setSelectedTab("register")} text="Next" Icon={<ArrowRight color={textBlack} />} />
|
||||
|
||||
</YStack >
|
||||
</YStack >
|
||||
);
|
||||
|
||||
@@ -1,57 +1,100 @@
|
||||
import React from 'react';
|
||||
import { YStack, Text, XStack, Button, Image } from 'tamagui';
|
||||
import { Nfc } from '@tamagui/lucide-icons';
|
||||
import { blueColorDark, blueColorLight, borderColor, componentBgColor2, greenColorDark, greenColorLight, redColorDark, redColorLight, textColor1, textColor2 } from '../utils/colors';
|
||||
import NFCHelp from '../images/nfc_help.png'
|
||||
import React, { useState } from 'react';
|
||||
import { YStack, Text, XStack, Button, ScrollView } from 'tamagui';
|
||||
import { Nfc, X } from '@tamagui/lucide-icons';
|
||||
import { bgGreen, borderColor, textBlack, textColor1 } from '../utils/colors';
|
||||
import { Carousel } from '../components/Carousel';
|
||||
import US_PASSPORT from '../images/us-passport.png'
|
||||
import REMOVE_CASE from '../images/remove_case.png'
|
||||
import US_PASSPORT_LASTPAGE from '../images/passport_lastpage_graybg.png'
|
||||
import US_PASSPORT_LASTPAGE_IOS from '../images/passport_lastpage_iphone.png'
|
||||
import US_PASSPORT_LASTPAGE_ANDROID from '../images/passport_lastpage_android.png'
|
||||
import PHONE_SCANBUTTON from "../images/phone_scanbutton.png"
|
||||
|
||||
import Dialog from "react-native-dialog";
|
||||
import NfcManager from 'react-native-nfc-manager';
|
||||
import { Platform, Linking, Dimensions } from 'react-native';
|
||||
|
||||
interface NfcScreenProps {
|
||||
handleNFCScan: () => void;
|
||||
}
|
||||
|
||||
|
||||
const NfcScreen: React.FC<NfcScreenProps> = ({ handleNFCScan }) => {
|
||||
const [isLastSlideReached, setIsLastSlideReached] = useState(false);
|
||||
const [dialogVisible, setDialogVisible] = useState(false);
|
||||
const [dialogMessage, setDialogMessage] = useState('');
|
||||
const [isNfcSupported, setIsNfcSupported] = useState(true);
|
||||
const carouselImages = [US_PASSPORT, REMOVE_CASE, US_PASSPORT_LASTPAGE, Platform.OS === 'ios' ? US_PASSPORT_LASTPAGE_IOS : US_PASSPORT_LASTPAGE_ANDROID, PHONE_SCANBUTTON,];
|
||||
const windowHeight = Dimensions.get('window').height;
|
||||
|
||||
const handleSlideChange = (index: number) => {
|
||||
if (index === carouselImages.length - 1) {
|
||||
setIsLastSlideReached(true);
|
||||
}
|
||||
};
|
||||
|
||||
const openNfcSettings = () => {
|
||||
if (Platform.OS === 'ios') {
|
||||
Linking.openURL('App-Prefs:root=General&path=About');
|
||||
} else {
|
||||
Linking.sendIntent('android.settings.NFC_SETTINGS');
|
||||
}
|
||||
setDialogVisible(false);
|
||||
};
|
||||
|
||||
const checkNfcSupport = async () => {
|
||||
const isSupported = await NfcManager.isSupported();
|
||||
if (isSupported) {
|
||||
const isEnabled = await NfcManager.isEnabled();
|
||||
if (!isEnabled) {
|
||||
setDialogMessage('NFC is not enabled. Would you like to enable it in settings?');
|
||||
setDialogVisible(true);
|
||||
setIsNfcSupported(true);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
setDialogMessage("Sorry, your device doesn't seem to have an NFC reader.");
|
||||
setDialogVisible(true);
|
||||
setIsNfcSupported(false);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleNfcScan = async () => {
|
||||
const nfcSupported = await checkNfcSupport();
|
||||
if (nfcSupported) {
|
||||
handleNFCScan();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<YStack f={1} p="$3">
|
||||
|
||||
<Image borderRadius="$5" alignSelf='center'
|
||||
w="$12"
|
||||
h="$14"
|
||||
source={{ uri: NFCHelp }}
|
||||
/>
|
||||
|
||||
<YStack f={1} gap="$2">
|
||||
<YStack mt="$2">
|
||||
<Text fontSize="$7" fow="bold" mt="$1" color={textColor1}>Scan the NFC chip in your passport.</Text>
|
||||
<Text fontSize="$6" color={textColor1} mt="$2">How do I find and scan the NFC chip?</Text>
|
||||
<YStack ml="$3" gap="$2" mt="$1" >
|
||||
<XStack gap="$1">
|
||||
<Text fontSize="$4" color={textColor2}>1.</Text>
|
||||
<Text fontSize="$4" color={textColor2}>Close your passport and hold the middle of the back cover of your passport to the top of the phoneThe passport should touch the phone.</Text>
|
||||
<ScrollView flex={1} contentContainerStyle={{ flexGrow: 1 }}>
|
||||
<YStack f={1} p="$3" >
|
||||
{/* <Text fontSize="$8" fow="bold" mt="$1.5" mb="$3" color={textColor1} textAlign='center'>Verify your passport using NFC</Text> */}
|
||||
<Text fontSize="$9" mt="$0" color={textBlack} mb="$4" ml="$2">Verify your passport using <Text fontSize="$9" color={textBlack} style={{ textDecorationLine: 'underline', textDecorationColor: bgGreen }}>NFC</Text></Text>
|
||||
<Carousel
|
||||
images={carouselImages}
|
||||
height={300}
|
||||
onSlideChange={handleSlideChange}
|
||||
handleNfcScan={handleNfcScan}
|
||||
/>
|
||||
<Dialog.Container visible={dialogVisible}>
|
||||
<Dialog.Title>NFC Status</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
{dialogMessage}
|
||||
</Dialog.Description>
|
||||
{isNfcSupported ? (
|
||||
<XStack>
|
||||
<XStack f={1} />
|
||||
<Dialog.Button label="Open Settings" onPress={openNfcSettings} />
|
||||
</XStack>
|
||||
<XStack gap="$1">
|
||||
<Text fontSize="$4" color={textColor2}>2.</Text>
|
||||
<Text fontSize="$4" color={textColor2}>If that does not work, try using the front cover of your passport.</Text>
|
||||
</XStack>
|
||||
<XStack gap="$1">
|
||||
<Text fontSize="$4" color={textColor2}>3.</Text>
|
||||
<Text fontSize="$4" color={textColor2}>Move your phone slowly up and down until scanning starts.</Text>
|
||||
</XStack>
|
||||
<XStack gap="$1">
|
||||
<Text fontSize="$4" color={textColor2}>4.</Text>
|
||||
<Text fontSize="$4" color={textColor2}>Hold your device still when scanning starts.</Text>
|
||||
</XStack>
|
||||
</YStack>
|
||||
|
||||
</YStack>
|
||||
|
||||
) : (
|
||||
<Dialog.Button label="OK" onPress={() => setDialogVisible(false)} />
|
||||
)}
|
||||
</Dialog.Container>
|
||||
</YStack>
|
||||
|
||||
<YStack gap="$2" mb="$6">
|
||||
<Button borderWidth={1.3} borderColor={borderColor} borderRadius="$10" bg="#3185FC" onPress={handleNFCScan}><Nfc color={textColor1} /></Button>
|
||||
</YStack>
|
||||
|
||||
</YStack >
|
||||
</ScrollView>
|
||||
);
|
||||
};
|
||||
|
||||
export default NfcScreen;
|
||||
export default NfcScreen;
|
||||
31
app/src/screens/NoSkipCarousel.tsx
Normal file
31
app/src/screens/NoSkipCarousel.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import { YStack, Button, Image, Text, styled } from 'tamagui';
|
||||
import { Camera, SquarePen, UserPlus } from '@tamagui/lucide-icons';
|
||||
import { bgColor, borderColor, textBlack, textColor1, textColor2 } from '../utils/colors';
|
||||
import { Steps } from "../utils/utils";
|
||||
import CustomButton from '../components/CustomButton';
|
||||
|
||||
const NoSkipCarousel: React.FC = () => {
|
||||
const textStyle = styled(Text, {
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
color: textBlack,
|
||||
});
|
||||
|
||||
return (
|
||||
<YStack f={1} p="$3" bg="white">
|
||||
<YStack f={1} jc="center">
|
||||
<YStack gap="$0.5" mt="$3.5">
|
||||
<Text fontSize="$9" mt="$1" >Lorem ipsum doflor siat amet</Text>
|
||||
<Text fontSize="$2" mt="$2" color={textBlack}>Lorem ipsum dolor sit amet</Text>
|
||||
</YStack>
|
||||
|
||||
</YStack>
|
||||
<CustomButton text="Let's start" onPress={() => {
|
||||
console.log("Let's start");
|
||||
}} />
|
||||
</YStack >
|
||||
);
|
||||
};
|
||||
|
||||
export default NoSkipCarousel;
|
||||
@@ -1,10 +1,11 @@
|
||||
import React, { useState } from 'react';
|
||||
import { YStack, XStack, Text, Button, Spinner } from 'tamagui';
|
||||
import { LockKeyhole } from '@tamagui/lucide-icons';
|
||||
import { borderColor, componentBgColor, componentBgColor2, textColor1, textColor2 } from '../utils/colors';
|
||||
import { LockKeyhole, UserPlus } from '@tamagui/lucide-icons';
|
||||
import { bgGreen, borderColor, componentBgColor, componentBgColor2, textBlack } from '../utils/colors';
|
||||
import { Platform } from 'react-native';
|
||||
import useUserStore from '../stores/userStore';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import CustomButton from '../components/CustomButton';
|
||||
|
||||
const RegisterScreen: React.FC = () => {
|
||||
|
||||
@@ -31,21 +32,33 @@ const RegisterScreen: React.FC = () => {
|
||||
return (
|
||||
<YStack px="$4" f={1} mb={Platform.OS === 'ios' ? "$5" : "$0"}>
|
||||
<YStack flex={1} mx="$2" gap="$2">
|
||||
<Text mt="$12" color={textColor1} fontSize="$10" fontWeight="bold">
|
||||
<Text mt="$12" color={textBlack} fontSize="$10" fontWeight="bold">
|
||||
Register
|
||||
</Text>
|
||||
<Text mt="$6" fontSize="$6" color={textColor1}>Join Proof of Passport to start sharing your identity securely.</Text>
|
||||
<Text mt="$1" fontSize="$4" color={textColor2}>Easily verify your nationality, humanity, or age and share only what you want to reveal.</Text>
|
||||
<YStack f={1} />
|
||||
<Text mt="$7" fontSize="$7" color={textBlack}>Join Proof of Passport to start sharing your identity<Text fontSize="$7" style={{
|
||||
textDecorationLine: "underline", textDecorationColor: bgGreen
|
||||
}}> securely. </Text></Text>
|
||||
<Text mt="$0" fontSize="$6" color={textBlack} style={{
|
||||
opacity: 0.7
|
||||
}}>Easily verify your nationality, humanity, or age and share<Text style={{
|
||||
textDecorationLine: "underline", textDecorationColor: bgGreen
|
||||
}}> only </Text>what you want to reveal.</Text>
|
||||
<XStack f={1} />
|
||||
|
||||
<XStack mt="$5" bg={componentBgColor} borderRadius={100} borderWidth={1} borderColor={borderColor} py="$2" px="$3">
|
||||
<XStack bg={componentBgColor2} borderRadius={100} p="$2" >
|
||||
<LockKeyhole alignSelf='center' size={24} color={textColor1} />
|
||||
<XStack mt="$5" bg="white" borderRadius={100} mb="$12" py="$2" px="$3">
|
||||
<XStack p="$2" >
|
||||
<LockKeyhole alignSelf='center' size={24} color={textBlack} />
|
||||
</XStack>
|
||||
<Text alignSelf='center' ml="$3" pr="$5" fontSize="$3" color={textColor1}>Registration does not leak any personal information</Text>
|
||||
<Text alignSelf='center' ml="$3" pr="$5" fontSize="$3" color={textBlack}>Registration does not leak any personal information</Text>
|
||||
</XStack>
|
||||
|
||||
<Button
|
||||
<CustomButton
|
||||
isDisabled={isZkeyDownloading.register_sha256WithRSAEncryption_65537 || registering}
|
||||
onPress={handleRegister}
|
||||
text={isZkeyDownloading.register_sha256WithRSAEncryption_65537 ? "Downloading zkey..." : (registerStep || "Register")}
|
||||
Icon={isZkeyDownloading.register_sha256WithRSAEncryption_65537 || registering ? <Spinner color={textBlack} /> : <UserPlus color={textBlack} />}
|
||||
/>
|
||||
{/* <Button
|
||||
disabled={isZkeyDownloading.register_sha256WithRSAEncryption_65537}
|
||||
mt="$8"
|
||||
alignSelf='center'
|
||||
@@ -56,11 +69,11 @@ const RegisterScreen: React.FC = () => {
|
||||
>
|
||||
<XStack gap="$3">
|
||||
{(registering || isZkeyDownloading.register_sha256WithRSAEncryption_65537) && <Spinner color="white" size="small" />}
|
||||
<Text color={textColor1} fontSize="$5" >
|
||||
<Text color={textBlack} fontSize="$5" >
|
||||
{isZkeyDownloading.register_sha256WithRSAEncryption_65537 ? "Downloading zkey..." : (registerStep || "Register")}
|
||||
</Text>
|
||||
</XStack>
|
||||
</Button>
|
||||
</Button> */}
|
||||
</YStack >
|
||||
</YStack >
|
||||
);
|
||||
|
||||
29
app/src/screens/SplashScreen.tsx
Normal file
29
app/src/screens/SplashScreen.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import useUserStore from '../stores/userStore';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
import { YStack, Text, Spinner, XStack } from 'tamagui';
|
||||
import { bgGreen, textBlack } from '../utils/colors';
|
||||
|
||||
const SplashScreen = () => {
|
||||
const { registered } = useUserStore();
|
||||
const { setSelectedTab } = useNavigationStore();
|
||||
|
||||
// once registered is retrieved from zustand, navigate to the appropriate screen
|
||||
useEffect(() => {
|
||||
if (registered) {
|
||||
setSelectedTab('app');
|
||||
} else {
|
||||
setSelectedTab('start');
|
||||
}
|
||||
}, [registered]);
|
||||
return (
|
||||
<YStack ai="center" f={1} gap="$8" mt="$18" mb="$8">
|
||||
<Text fontSize="$9">Proof of Passport</Text>
|
||||
<XStack f={1} />
|
||||
<Spinner color={textBlack} />
|
||||
</YStack>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default SplashScreen;
|
||||
39
app/src/screens/StartScreen.tsx
Normal file
39
app/src/screens/StartScreen.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import React from 'react';
|
||||
import { YStack, Button, Image, Text, styled } from 'tamagui';
|
||||
import { ArrowRight, Camera, SquarePen, UserPlus } from '@tamagui/lucide-icons';
|
||||
import { bgColor, bgGreen, borderColor, textBlack, textColor1, textColor2 } from '../utils/colors';
|
||||
import { Steps } from "../utils/utils";
|
||||
import CustomButton from '../components/CustomButton';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
|
||||
const StartScreen: React.FC = () => {
|
||||
|
||||
const {
|
||||
setStep,
|
||||
step,
|
||||
selectedTab,
|
||||
setSelectedTab
|
||||
} = useNavigationStore();
|
||||
|
||||
return (
|
||||
<YStack f={1} p="$3">
|
||||
<YStack f={1} mt="$12">
|
||||
<YStack gap="$0.5" mb="$14">
|
||||
<Text fontSize="$9" >Welcome to Proof of Passport 👋</Text>
|
||||
<Text fontSize="$8" mt="$6" color={textBlack}>Proof of Passport allows you to scan your passport, and to prove your identity in a
|
||||
<Text fontSize="$8" color={textBlack} style={{ textDecorationLine: 'underline', textDecorationColor: bgGreen }}> secure </Text>way.
|
||||
</Text>
|
||||
<Text fontSize="$8" mt="$4" color={textBlack} style={{ opacity: 0.7 }}>You can for example prove that you are over 18 yo while staying fully
|
||||
<Text fontSize="$8" color={textBlack} style={{ textDecorationLine: 'underline', textDecorationColor: bgGreen }}> anonymous.</Text>
|
||||
</Text>
|
||||
</YStack>
|
||||
|
||||
</YStack>
|
||||
<CustomButton Icon={<ArrowRight />} text="Let's start" onPress={() => {
|
||||
setSelectedTab("scan");
|
||||
}} />
|
||||
</YStack >
|
||||
);
|
||||
};
|
||||
|
||||
export default StartScreen;
|
||||
@@ -11,6 +11,7 @@ interface NavigationState {
|
||||
hideData: boolean
|
||||
toast: ReturnType<typeof useToastController>
|
||||
selectedTab: string
|
||||
setSelectedTab: (tab: string) => void
|
||||
selectedApp: AppType | null
|
||||
showRegistrationErrorSheet: boolean
|
||||
registrationErrorMessage: string
|
||||
@@ -43,6 +44,7 @@ const useNavigationStore = create<NavigationState>((set, get) => ({
|
||||
setToast: (toast) => set({ toast }),
|
||||
|
||||
setStep: (step) => set({ step }),
|
||||
setSelectedTab: (tab) => set({ selectedTab: tab }),
|
||||
|
||||
update: (patch) => {
|
||||
set({
|
||||
|
||||
@@ -88,7 +88,8 @@ const useUserStore = create<UserState>((set, get) => ({
|
||||
set({
|
||||
passportData: JSON.parse(passportData),
|
||||
});
|
||||
useNavigationStore.getState().setStep(Steps.NEXT_SCREEN);
|
||||
// useNavigationStore.getState().setStep(Steps.NEXT_SCREEN);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -97,7 +98,7 @@ const useUserStore = create<UserState>((set, get) => ({
|
||||
passportData: JSON.parse(passportData),
|
||||
registered: true,
|
||||
});
|
||||
// useNavigationStore.getState().setStep(Steps.REGISTERED);
|
||||
useNavigationStore.getState().setStep(Steps.REGISTERED);
|
||||
},
|
||||
|
||||
// When reading passport for the first time:
|
||||
|
||||
@@ -5,7 +5,7 @@ import useUserStore from '../stores/userStore';
|
||||
import useNavigationStore from '../stores/navigationStore';
|
||||
|
||||
export const startCameraScan = async () => {
|
||||
const {toast, setStep} = useNavigationStore.getState();
|
||||
const { toast, setSelectedTab } = useNavigationStore.getState();
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
try {
|
||||
@@ -19,17 +19,15 @@ export const startCameraScan = async () => {
|
||||
dateOfExpiry: formatDateToYYMMDD(result.expiryDate),
|
||||
})
|
||||
|
||||
setStep(Steps.MRZ_SCAN_COMPLETED);
|
||||
setSelectedTab("nfc");
|
||||
toast.show("Scan successful", {
|
||||
message: 'Nice to meet you!',
|
||||
message: '✅',
|
||||
customData: {
|
||||
type: "success",
|
||||
},
|
||||
})
|
||||
amplitude.track('Camera scan successful');
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
amplitude.track('Camera scan unsuccessful');
|
||||
}
|
||||
} else {
|
||||
NativeModules.CameraActivityModule.startCameraActivity()
|
||||
@@ -43,22 +41,19 @@ export const startCameraScan = async () => {
|
||||
dateOfExpiry: expiryDate,
|
||||
})
|
||||
|
||||
setStep(Steps.MRZ_SCAN_COMPLETED);
|
||||
amplitude.track('Camera scan successful');
|
||||
setSelectedTab("nfc");
|
||||
toast.show("Scan successful", {
|
||||
message: 'Nice to meet you!',
|
||||
message: '✅',
|
||||
customData: {
|
||||
type: "success",
|
||||
},
|
||||
})
|
||||
})
|
||||
} catch (error: any) {
|
||||
console.error('Invalid MRZ format:', error.message);
|
||||
amplitude.track('Camera scan unsuccessful');
|
||||
}
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.error('Camera Activity Error:', error);
|
||||
amplitude.track('Camera scan unsuccessful');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -16,4 +16,5 @@ export const yellowColorLight = "#f5d90a"
|
||||
export const bgWhite = "#F5F5F5"
|
||||
export const textBlack = "#333333"
|
||||
export const bgGreen = "#94FBAB"
|
||||
export const bgBlue = "#69DFFF"
|
||||
export const separatorColor = "#E0E0E0"
|
||||
@@ -195,6 +195,7 @@ const handleResponseIOS = async (
|
||||
sendCSCARequest(inputs_csca, setModalProofStep);
|
||||
|
||||
useNavigationStore.getState().setStep(Steps.NEXT_SCREEN);
|
||||
useNavigationStore.getState().setSelectedTab("next");
|
||||
} catch (e: any) {
|
||||
console.log('error during parsing:', e);
|
||||
useNavigationStore.getState().setStep(Steps.MRZ_SCAN_COMPLETED);
|
||||
@@ -303,4 +304,5 @@ const handleResponseAndroid = async (
|
||||
);
|
||||
sendCSCARequest(inputs_csca, setModalProofStep);
|
||||
useNavigationStore.getState().setStep(Steps.NEXT_SCREEN);
|
||||
useNavigationStore.getState().setSelectedTab("next");
|
||||
};
|
||||
|
||||
@@ -34,6 +34,7 @@ export function formatDateToYYMMDD(inputDate: string) {
|
||||
}
|
||||
|
||||
export const Steps = {
|
||||
START: 0,
|
||||
MRZ_SCAN: 1,
|
||||
MRZ_SCAN_COMPLETED: 2,
|
||||
NFC_SCANNING: 3,
|
||||
|
||||
Reference in New Issue
Block a user