From 412b7b29a809cabf9f06e4196cf054e9a11570ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Colin?= Date: Mon, 5 Feb 2024 20:37:01 +0100 Subject: [PATCH] add proof visualization and follow tsx best practices --- .DS_Store | Bin 0 -> 6148 bytes app/App.tsx | 4 +- app/ios/Podfile.lock | 12 +-- .../ProofOfPassport.xcodeproj/project.pbxproj | 11 ++- .../contents.xcworkspacedata | 7 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++ app/package.json | 1 + app/src/components/AppCard.tsx | 21 +++- app/src/components/ProofGrid.tsx | 74 ++++++++++++++ app/src/screens/AppScreen.tsx | 8 +- app/src/screens/MainScreen.tsx | 92 +++++++++++------- app/src/screens/ProveScreen.tsx | 52 ++++++---- app/src/screens/ScanScreen.tsx | 42 ++++---- app/yarn.lock | 12 +++ 14 files changed, 262 insertions(+), 82 deletions(-) create mode 100644 .DS_Store create mode 100644 app/ios/ProofOfPassport.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 app/ios/ProofOfPassport.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 app/src/components/ProofGrid.tsx diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..15460fc1e2bd446b9b8512dd8fa44f5014a6801e GIT binary patch literal 6148 zcmeHKL2uJA6n<{AEn!0H0VFseMdDhOjiNP#6B5Dzli^AyKL3NAqIF~JJ z7>@@Ooa03%$8jcO^f{q5tAJJD|5kvXU57e!Nhwve=l2w2onOk-BKE*bDWM5PHRiV( zvq=$6X}ZZ0k8Wqh^Kxo-jqmX^OUtU;{UI7nXK(+&J#Y`*_u)r5538t}m4m2w%e_}p zX7NosieIOb`KWd8Oy*UT=95ANq{#%7cW=@>k@JC^bxLp|Vnt~Y8uTrB#>y|#bU zKkhHv{^I0mx9#_y^_EM|z5n>h^NZ1^>?)VnN&phr=9JwvcmrS1FpK^i7I`M~OL&;= z(iox@sAnuOl{HZ~^Sa3UU`o2eM^awn{;Y95#m$kmfZ*fp><#`F>)AcJpmREu&F>(cUye^pa1#(zZqnERspNPPAMRqVK^LMN#< iI93fliXWgT!(Steps.MRZ_SCAN); const [testResult, setTestResult] = useState(null); const [error, setError] = useState(null); const [generatingProof, setGeneratingProof] = useState(false); @@ -224,7 +224,7 @@ function App(): JSX.Element { console.log('encryptedDigest', passportData.encryptedDigest); setPassportData(passportData); - setStep('scanCompleted'); + setStep(Steps.NFC_SCAN_COMPLETED); } async function handleResponseAndroid(response: any) { diff --git a/app/ios/Podfile.lock b/app/ios/Podfile.lock index afdcabe3b..bba520d01 100644 --- a/app/ios/Podfile.lock +++ b/app/ios/Podfile.lock @@ -555,13 +555,13 @@ SPEC CHECKSUMS: React-Core: 8293312ad137ea82fd2c29deb163dbc24aa4e00e React-CoreModules: 32fab1d62416849a3b6dac6feff9d54e5ddc2d1e React-cxxreact: 55d0f7cb6b4cc09ba9190797f1da87182d1a2fb6 - React-debug: 7e61555c8158126c6cd98c3154381ad3821aaaca + React-debug: 5dab69ef4d475ac86ea0dadf78f6453298e02d62 React-jsc: 0db8e8cc2074d979c37ffa7b8d7c914833960497 React-jsi: 58677ff4848ceb6aeb9118fe03448a843ea5e16a React-jsiexecutor: 2c15ba1bace70177492368d5180b564f165870fd React-jsinspector: b511447170f561157547bc0bef3f169663860be7 React-logger: c5b527272d5f22eaa09bb3c3a690fee8f237ae95 - React-NativeModulesApple: 0438665fc7473be6edc496e823e6ea0b0537b46c + React-NativeModulesApple: 79820f35406d83c153c9ff6a3c774d87ac888b16 React-perflogger: 6bd153e776e6beed54c56b0847e1220a3ff92ba5 React-RCTActionSheet: c0b62af44e610e69d9a2049a682f5dba4e9dff17 React-RCTAnimation: fe7005136b58f58871cab2f70732343b6e330d30 @@ -575,13 +575,13 @@ SPEC CHECKSUMS: React-RCTVibration: ea3a68a49873a54ced927c90923fc6932baf344a React-rncore: 9672a017af4a7da7495d911f0b690cbcae9dd18d React-runtimeexecutor: 369ae9bb3f83b65201c0c8f7d50b72280b5a1dbc - React-runtimescheduler: ec1066a4f2d1152eb1bc3fb61d69376b3bc0dde0 - React-utils: d55ba834beb39f01b0b470ae43478c0a3a024abe - ReactCommon: 68e3a815fbb69af3bb4196e04c6ae7abb306e7a8 + React-runtimescheduler: 749452b413819c5903d575089edcf0eda74eded9 + React-utils: f37c388aaf8b292278d2dd83d0aa36ac579d8057 + ReactCommon: ad66a3a68f98db6309f30f4e4ebd0751a9548876 RNSVG: 07dbd870b0dcdecc99b3a202fa37c8ca163caec2 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce PODFILE CHECKSUM: d401e6efe0c933985349c8c115c7edca8fef3182 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.0 diff --git a/app/ios/ProofOfPassport.xcodeproj/project.pbxproj b/app/ios/ProofOfPassport.xcodeproj/project.pbxproj index b9f442f7f..e47f6f599 100644 --- a/app/ios/ProofOfPassport.xcodeproj/project.pbxproj +++ b/app/ios/ProofOfPassport.xcodeproj/project.pbxproj @@ -490,8 +490,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = ProofOfPassport/ProofOfPassport.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 5B29R5LYHQ; + DEVELOPMENT_TEAM = X53ZR86F22; ENABLE_BITCODE = NO; INFOPLIST_FILE = ProofOfPassport/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.0; @@ -512,8 +514,9 @@ "-ObjC", "-lc++", ); - PRODUCT_BUNDLE_IDENTIFIER = com.warroom.proofofpassport; + PRODUCT_BUNDLE_IDENTIFIER = com.warroom.proofofpassportdev; PRODUCT_NAME = ProofOfPassport; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -528,7 +531,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = ProofOfPassport/ProofOfPassport.entitlements; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 5B29R5LYHQ; + DEVELOPMENT_TEAM = X53ZR86F22; INFOPLIST_FILE = ProofOfPassport/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( @@ -547,7 +550,7 @@ "-ObjC", "-lc++", ); - PRODUCT_BUNDLE_IDENTIFIER = com.warroom.proofofpassport; + PRODUCT_BUNDLE_IDENTIFIER = com.warroom.proofofpassportdev; PRODUCT_NAME = ProofOfPassport; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/app/ios/ProofOfPassport.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/app/ios/ProofOfPassport.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000..919434a62 --- /dev/null +++ b/app/ios/ProofOfPassport.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/app/ios/ProofOfPassport.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app/ios/ProofOfPassport.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000..18d981003 --- /dev/null +++ b/app/ios/ProofOfPassport.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/app/package.json b/app/package.json index bb067d7e2..88a12b645 100644 --- a/app/package.json +++ b/app/package.json @@ -25,6 +25,7 @@ "pvutils": "^1.1.3", "react": "18.2.0", "react-native": "0.72.3", + "react-native-canvas": "^0.1.39", "react-native-passport-reader": "^1.0.3", "react-native-svg": "13.4.0", "react-native-toast-message": "^2.2.0", diff --git a/app/src/components/AppCard.tsx b/app/src/components/AppCard.tsx index 05ed8e7b4..1b0fca874 100644 --- a/app/src/components/AppCard.tsx +++ b/app/src/components/AppCard.tsx @@ -2,13 +2,32 @@ import React from 'react'; import { Text, YStack, XStack, Card, H3, Image } from 'tamagui'; import { ChevronRight } from '@tamagui/lucide-icons'; -const AppCard = ({ title, description, colorOfTheText, background, id, onTouchStart, eleva }) => { +interface AppCardProps { + title: string; + description: string; + colorOfTheText: string; + background: string | undefined; + id: string | number; + onTouchStart?: () => void; + eleva?: string; +} + +const AppCard: React.FC = ({ + title, + description, + colorOfTheText, + background, + id, + onTouchStart, + eleva +}) => { return ( diff --git a/app/src/components/ProofGrid.tsx b/app/src/components/ProofGrid.tsx new file mode 100644 index 000000000..b94cbdc3f --- /dev/null +++ b/app/src/components/ProofGrid.tsx @@ -0,0 +1,74 @@ +import React, { useMemo } from 'react'; +import { Svg, Rect } from 'react-native-svg'; +import { YStack } from 'tamagui'; + +interface ProofGridProps { + proof: { proof: string; inputs: string } | null; +} + +const ProofGrid: React.FC = ({ proof }) => { + const gridSize = 8; + const pixelSize = 15; + + const sumAndScaleDigits = useMemo(() => (values: string[]) => { + const sum = values.reduce((acc, val) => acc + BigInt(val), BigInt(0)); + const digits = sum.toString().split('').map(Number); + return digits.map(digit => Math.round(digit * (256 / 9))); + }, []); + + // Prepare the RGB values + const { rValues, gValues, bValues } = useMemo(() => { + if (!proof) { + return { rValues: [], gValues: [], bValues: [] }; + } + + const parsedProof = JSON.parse(proof.proof); + return { + rValues: sumAndScaleDigits(parsedProof.a), + gValues: sumAndScaleDigits(parsedProof.b.flat()), + bValues: sumAndScaleDigits(parsedProof.c) + }; + }, [proof, sumAndScaleDigits]); + + // Generate the grid data + const gridData = useMemo(() => + Array.from({ length: gridSize }, (_, rowIndex) => + Array.from({ length: gridSize }, (_, colIndex) => { + const index = rowIndex * gridSize + colIndex; + const r = index < rValues.length ? rValues[index] : 0; + const g = index < gValues.length ? gValues[index] : 0; + const b = index < bValues.length ? bValues[index] : 0; + return `rgb(${r}, ${g}, ${b})`; + }) + ) + , [gridSize, rValues, gValues, bValues]); + + // Render the grid using SVG and Rect + return ( + + + {gridData.map((row, i) => + row.map((fill, j) => ( + + )) + )} + + + + ); +}; + +export default ProofGrid; diff --git a/app/src/screens/AppScreen.tsx b/app/src/screens/AppScreen.tsx index b2394ff55..497658d4a 100644 --- a/app/src/screens/AppScreen.tsx +++ b/app/src/screens/AppScreen.tsx @@ -4,7 +4,13 @@ import GITCOIN from '../images/gitcoin.png'; import { YStack } from 'tamagui'; import AppCard from '../components/AppCard'; import { App, gitcoin, soulbond, zuzalu } from '../utils/AppClass'; -const AppScreen = ({ selectedApp, setSelectedApp }) => { + +interface AppScreenProps { + selectedApp: App | null; + setSelectedApp: (app: App | null) => void; +} + +const AppScreen: React.FC = ({ selectedApp, setSelectedApp }) => { const handleCardSelect = (app: App) => { setSelectedApp(app); diff --git a/app/src/screens/MainScreen.tsx b/app/src/screens/MainScreen.tsx index cc3a3d942..677c2d3b2 100644 --- a/app/src/screens/MainScreen.tsx +++ b/app/src/screens/MainScreen.tsx @@ -1,36 +1,63 @@ import React, { useState, useEffect } from 'react'; -import { YStack, XStack, Text, Button, SizableText, 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 } 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'; -const MainScreen = ( - { onStartCameraScan, - nfcScan, - passportData, - disclosure, - handleDisclosureChange, - address, - setAddress, - generatingProof, - handleProve, - step, - mintText, - proof, - proofTime, - handleMint, - totalTime, - setStep, - passportNumber, - setPassportNumber, - dateOfBirth, - setDateOfBirth, - dateOfExpiry, - setDateOfExpiry - } -) => { + + +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 = ({ + 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(null); const [brokenCamera, setBrokenCamera] = useState(false); @@ -70,7 +97,7 @@ const MainScreen = ( - {selectedTab === "scan" ? "Scan" : (selectedTab === "app" ? "App" : "Prove")} + {selectedTab === "scan" ? "Scan" : (selectedTab === "app" ? "Apps" : "Prove")} @@ -235,7 +261,7 @@ const MainScreen = ( - Scan + Scan @@ -243,14 +269,14 @@ const MainScreen = ( - App + Apps : - App + Apps } @@ -261,14 +287,14 @@ const MainScreen = ( - Prove + Prove : - Prove + Prove } diff --git a/app/src/screens/ProveScreen.tsx b/app/src/screens/ProveScreen.tsx index 317e0ec22..daa315924 100644 --- a/app/src/screens/ProveScreen.tsx +++ b/app/src/screens/ProveScreen.tsx @@ -1,12 +1,32 @@ import React from 'react'; -import { YStack, XStack, Text, Checkbox, Input, Button, Spinner, SizableText, Image } from 'tamagui'; +import { YStack, XStack, Text, Checkbox, Input, Button, Spinner, Image } from 'tamagui'; import { Check } from '@tamagui/lucide-icons'; import { getFirstName, formatDuration } from '../../utils/utils'; import { attributeToPosition } from '../../../common/src/constants/constants'; import { Steps } from '../utils/utils'; import USER from '../images/user.png' +import ProofGrid from '../components/ProofGrid'; +import { App } from '../utils/AppClass'; -const ProveScreen = ({ + +interface ProveScreenProps { + selectedApp: App | null; + passportData: any; + disclosure: any; + handleDisclosureChange: (disclosure: boolean) => void; + address: string; + setAddress: (address: string) => void; + generatingProof: boolean; + handleProve: () => void; + handleMint: () => void; + step: number; + mintText: string; + proof: { proof: string, inputs: string } | null; + proofTime: number; + totalTime: number; +} + +const ProveScreen: React.FC = ({ passportData, disclosure, selectedApp, @@ -16,13 +36,13 @@ const ProveScreen = ({ generatingProof, handleProve, step, - setStep, mintText, proof, proofTime, handleMint, totalTime }) => { + return ( { @@ -40,12 +60,12 @@ const ProveScreen = ({ /> - Hi {getFirstName(passportData.mrz)}, - {selectedApp.name} is asking for the following information: - {Object.keys(selectedApp.disclosure).map((key) => { - const keyy = key as keyof typeof disclosure; - const indexes = attributeToPosition[keyy]; - const keyFormatted = keyy.replace(/_/g, ' ').split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); + Hi {getFirstName(passportData.mrz)}, + {selectedApp?.name} is asking for the following information: + {selectedApp && Object.keys(selectedApp.disclosure).map((key) => { + const key_ = key as keyof typeof disclosure; + const indexes = attributeToPosition[key_]; + const keyFormatted = key_.replace(/_/g, ' ').split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' '); const mrzAttribute = passportData.mrz.slice(indexes[0], indexes[1]); const mrzAttributeFormatted = mrzAttribute.replace(/ handleDisclosureChange(keyy)} + checked={disclosure[key_]} + onCheckedChange={() => handleDisclosureChange(key_)} aria-label={keyFormatted} size="$5" > @@ -91,13 +111,11 @@ const ProveScreen = ({ ) : ( - - Zero-knowledge proof generated + + Zero-knowledge proof generated: + - Proof: - {JSON.stringify(proof)} - - Proof Duration: {formatDuration(proofTime)} + Proof Duration: {formatDuration(proofTime)} Total Duration: {formatDuration(totalTime)}