Skip to content

Commit cf64e91

Browse files
authored
feat: add react native verifier sdk tutorial sample app (#199)
* feat: init rn mdocs verifier starter template * chore: update app configuration and dependencies for rn-mdocs-verifier-sample-app - Updated package.json dependencies to latest versions: - @mattrglobal/mobile-credential-verifier-react-native: "^8.1.0" - expo: "^53.0.9" - expo-build-properties: "^0.14.6" - expo-camera: "~16.1.11" - expo-status-bar: "~2.0.1" - react: "19.0.0" - react-native: "0.79.2" - Updated TypeScript and React types to match new React version.
1 parent 3fcedf0 commit cf64e91

29 files changed

+12927
-0
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Learn more https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files
2+
3+
# dependencies
4+
node_modules/
5+
6+
# Expo
7+
.expo/
8+
dist/
9+
web-build/
10+
11+
# Native
12+
*.orig.*
13+
*.jks
14+
*.p8
15+
*.p12
16+
*.key
17+
*.mobileprovision
18+
19+
# Metro
20+
.metro-health-check*
21+
22+
# debug
23+
npm-debug.*
24+
yarn-debug.*
25+
yarn-error.*
26+
27+
# macOS
28+
.DS_Store
29+
*.pem
30+
31+
# local env files
32+
.env*.local
33+
34+
# typescript
35+
*.tsbuildinfo
36+
37+
ios
38+
android
39+
# @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
40+
# The following patterns were generated by expo-cli
41+
42+
expo-env.d.ts
43+
# @end expo-cli
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
// Initialize SDK - Step 1.1: Import MobileCredentialVerifierSDK
2+
import {
3+
type MobileCredentialResponse,
4+
type TrustedIssuerCertificate,
5+
createProximityPresentationSession,
6+
getTrustedIssuerCertificates,
7+
initialize,
8+
sendProximityPresentationRequest,
9+
terminateProximityPresentationSession,
10+
} from "@mattrglobal/mobile-credential-verifier-react-native";
11+
import { useCameraPermissions } from "expo-camera";
12+
import { StatusBar } from "expo-status-bar";
13+
import { useEffect, useState } from "react";
14+
import {
15+
ActivityIndicator,
16+
Alert,
17+
SafeAreaView,
18+
Text,
19+
TouchableOpacity,
20+
View,
21+
} from "react-native";
22+
import { CertificateManagementModal } from "./CertificateManagementModal";
23+
import { QRScannerModal } from "./QRScannerModal";
24+
import { VerificationResultsModal } from "./VerificationResultsModal";
25+
import { styles } from "./styles";
26+
27+
export default function App() {
28+
// Initialize SDK - Step 1.2: Add state variables for SDK and loading
29+
const [isSDKInitialized, setIsSDKInitialized] = useState(false);
30+
const [loadingMessage, setLoadingMessage] = useState<string | false>(false);
31+
32+
// Manage Certificates - Step 1.1: Add certificates state variable
33+
const [trustedCertificates, setTrustedCertificates] = useState<
34+
TrustedIssuerCertificate[]
35+
>([]);
36+
37+
// Verify mDocs - Step 1.2: Create receivedDocuments variable
38+
const [verificationResults, setVerificationResults] =
39+
useState<MobileCredentialResponse | null>(null);
40+
41+
// Modal states for navigation
42+
const [showCertificateManagement, setShowCertificateManagement] =
43+
useState(false);
44+
const [isScanning, setIsScanning] = useState(false);
45+
const [showVerificationResults, setShowVerificationResults] = useState(false);
46+
47+
const [permission, requestPermission] = useCameraPermissions();
48+
49+
// Initialize SDK - Step 2.1: Initialize the SDK
50+
useEffect(() => {
51+
const initializeSDK = async () => {
52+
try {
53+
setLoadingMessage("Initializing SDK...");
54+
console.log("Initializing verifier SDK...");
55+
await initialize();
56+
console.log("SDK initialized successfully");
57+
setIsSDKInitialized(true);
58+
59+
setLoadingMessage("Loading certificates...");
60+
const certificates = await getTrustedIssuerCertificates();
61+
if (certificates) {
62+
console.log(`Loaded ${certificates.length} trusted certificates`);
63+
setTrustedCertificates(certificates);
64+
}
65+
} catch (error) {
66+
console.error("Failed to initialize SDK:", error);
67+
Alert.alert(
68+
"Error",
69+
`Failed to initialize the verifier SDK: ${error instanceof Error ? error.message : String(error)}`,
70+
);
71+
} finally {
72+
setLoadingMessage(false);
73+
}
74+
};
75+
76+
initializeSDK();
77+
}, []);
78+
79+
// Verify mDocs - Step 3.2: Create setupProximityPresentationSession
80+
const handleQRCodeDetected = async (qrData: string) => {
81+
try {
82+
setLoadingMessage("Establishing secure connection...");
83+
84+
await createProximityPresentationSession({
85+
deviceEngagement: qrData,
86+
onEstablished: async () => {
87+
console.log("Session established successfully");
88+
setLoadingMessage("Requesting verification data...");
89+
try {
90+
const response = await sendProximityPresentationRequest({
91+
mobileCredentialRequests: [
92+
{
93+
docType: "org.iso.18013.5.1.mDL",
94+
namespaces: {
95+
"org.iso.18013.5.1": {
96+
family_name: false,
97+
given_name: false,
98+
birth_date: false,
99+
},
100+
},
101+
},
102+
],
103+
});
104+
105+
if (response.isErr()) {
106+
throw new Error(
107+
`Failed to verify presentation: ${response.error.message}`,
108+
);
109+
}
110+
111+
setLoadingMessage("Verifying credentials...");
112+
setVerificationResults(response.value);
113+
setShowVerificationResults(true);
114+
await terminateProximityPresentationSession();
115+
} catch (error) {
116+
console.error("Error during presentation request:", error);
117+
Alert.alert("Error", "Failed to verify mDocs");
118+
await terminateProximityPresentationSession();
119+
} finally {
120+
setLoadingMessage(false);
121+
}
122+
},
123+
onTerminated: () => {
124+
console.log("Session terminated");
125+
setLoadingMessage(false);
126+
},
127+
onError: (error) => {
128+
console.error("Session error:", JSON.stringify(error, null, 2));
129+
Alert.alert(
130+
"Error",
131+
`Session failed: ${error.message || JSON.stringify(error)}`,
132+
);
133+
setLoadingMessage(false);
134+
},
135+
});
136+
137+
console.log(
138+
"createProximityPresentationSession call completed (waiting for callbacks)",
139+
);
140+
} catch (error) {
141+
console.error("Error during QR code processing:", error);
142+
Alert.alert(
143+
"Error",
144+
`Failed to process QR code: ${error instanceof Error ? error.message : String(error)}`,
145+
);
146+
setLoadingMessage(false);
147+
}
148+
};
149+
150+
return (
151+
<SafeAreaView style={styles.container}>
152+
<StatusBar style="auto" />
153+
<View style={styles.header}>
154+
<Text style={styles.title}>mDocs Verifier</Text>
155+
</View>
156+
157+
{loadingMessage ? (
158+
<View style={[styles.content, styles.center]}>
159+
<ActivityIndicator size="large" color="#007AFF" />
160+
<Text style={styles.loadingText}>{loadingMessage}</Text>
161+
</View>
162+
) : (
163+
<View style={styles.content}>
164+
<View style={styles.buttonContainer}>
165+
<TouchableOpacity
166+
style={[
167+
styles.button,
168+
!isSDKInitialized && styles.buttonDisabled,
169+
]}
170+
onPress={() => setShowCertificateManagement(true)}
171+
disabled={!isSDKInitialized}
172+
>
173+
<Text style={styles.buttonText}>Certificate Management</Text>
174+
</TouchableOpacity>
175+
176+
<TouchableOpacity
177+
style={[
178+
styles.button,
179+
(!isSDKInitialized || trustedCertificates.length === 0) &&
180+
styles.buttonDisabled,
181+
]}
182+
onPress={() => setIsScanning(true)}
183+
disabled={!isSDKInitialized || trustedCertificates.length === 0}
184+
>
185+
<Text style={styles.buttonText}>Scan QR Code</Text>
186+
</TouchableOpacity>
187+
</View>
188+
189+
{!isSDKInitialized && (
190+
<Text style={styles.errorText}>
191+
SDK not initialized. Please restart the app.
192+
</Text>
193+
)}
194+
{isSDKInitialized && trustedCertificates.length === 0 && (
195+
<Text style={styles.errorText}>
196+
No trusted issuer certificates added. Add certificates to verify
197+
mDocs.
198+
</Text>
199+
)}
200+
</View>
201+
)}
202+
203+
{/* Manage Certificates - Step 2.6: Create CertificateManagementView */}
204+
<CertificateManagementModal
205+
visible={showCertificateManagement}
206+
onClose={() => setShowCertificateManagement(false)}
207+
trustedCertificates={trustedCertificates}
208+
setTrustedCertificates={setTrustedCertificates}
209+
/>
210+
211+
{/* Verify mDocs - Step 1.2: Create QRScannerView */}
212+
<QRScannerModal
213+
visible={isScanning}
214+
onClose={() => setIsScanning(false)}
215+
permission={permission}
216+
requestPermission={requestPermission}
217+
onQRCodeDetected={handleQRCodeDetected}
218+
/>
219+
220+
{/* Verify mDocs - Step 4.2: Create PresentationResponseView */}
221+
<VerificationResultsModal
222+
visible={showVerificationResults}
223+
onClose={() => setShowVerificationResults(false)}
224+
verificationResults={verificationResults}
225+
/>
226+
</SafeAreaView>
227+
);
228+
}

0 commit comments

Comments
 (0)