diff --git a/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/app/claim-credential.tsx b/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/app/claim-credential.tsx index 3e8ca59..c82a5d0 100644 --- a/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/app/claim-credential.tsx +++ b/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/app/claim-credential.tsx @@ -85,10 +85,31 @@ export default function ClaimCredential() { retrieved.error.message || "Failed to retrieve credentials.", ); } else { - Alert.alert( - "Success", - `Retrieved ${retrieved.value.length} credential(s) successfully!`, - ); + // A credential offer can contain more than one credential, and each one is + // retrieved independently. Narrow each item on isSuccess so that a credential + // that failed to retrieve is not reported as a success. + let successCount = 0; + const failureMessages: string[] = []; + + for (const item of retrieved.value) { + if (item.isSuccess) { + successCount++; + } else { + failureMessages.push(`${item.docType}: ${item.error.message}`); + } + } + + if (failureMessages.length === 0) { + Alert.alert( + "Success", + `Retrieved ${successCount} credential(s) successfully!`, + ); + } else { + Alert.alert( + "Partial Success", + `Retrieved ${successCount} credential(s). Failed to retrieve ${failureMessages.length}:\n${failureMessages.join("\n")}`, + ); + } } // Refresh the list of mobile credentials in the holder application await getMobileCredentials(); @@ -155,11 +176,12 @@ export default function ClaimCredential() { {credentialOffer.credentials.map( (cred: OfferedCredential, index: number) => ( - + {cred.name} - Document Type: {cred.doctype} + Document Type: {cred.docType} + {/* An offer only includes claims when it contains claim data */} - Number of Claims: {cred.claims?.length} + Number of Claims: {cred.claims?.length ?? 0} ), diff --git a/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/package.json b/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/package.json index c45931a..4034e61 100644 --- a/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/package.json +++ b/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/package.json @@ -13,7 +13,7 @@ "ios": "expo run:ios" }, "dependencies": { - "@mattrglobal/mobile-credential-holder-react-native": "^8.1.1", + "@mattrglobal/mobile-credential-holder-react-native": "^10.0.0", "expo": "^55", "expo-build-properties": "~55.0.13", "expo-constants": "~55.0.15", diff --git a/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/providers/HolderProvider.tsx b/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/providers/HolderProvider.tsx index 8f2fa0c..e607640 100644 --- a/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/providers/HolderProvider.tsx +++ b/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-complete/providers/HolderProvider.tsx @@ -56,7 +56,7 @@ export function HolderProvider({ children }: { children: React.ReactNode }) { const result = await initialize({ userAuthenticationConfiguration: { userAuthenticationBehavior: UserAuthenticationBehavior.OnInitialize, - userAuthenticationType: UserAuthenticationType.BiometricOrPasscode, + userAuthenticationType: UserAuthenticationType.UserPresence, }, credentialIssuanceConfiguration: { autoTrustMobileCredentialIaca: true, @@ -87,8 +87,23 @@ export function HolderProvider({ children }: { children: React.ReactNode }) { const getMobileCredentials = useCallback(async () => { if (!isHolderInitialized) return; - const credentials = await getCredentials(); - setMobileCredentials(credentials); + + try { + const result = await getCredentials(); + + if (result.isErr()) { + setError(result.error.message || "Failed to get credentials."); + return; + } + + setMobileCredentials(result.value); + } catch (err) { + setError( + err instanceof Error + ? err.message + : "Unknown error while getting credentials", + ); + } }, [isHolderInitialized]); // When the holder is initialized, get the mobile credentials to display in the app @@ -113,7 +128,18 @@ export function HolderProvider({ children }: { children: React.ReactNode }) { style: "destructive", onPress: async () => { try { - await deleteCredential(credentialId); + const result = await deleteCredential(credentialId); + + // Expected failures are returned as an error result rather + // than thrown, so handle them before reporting success + if (result.isErr()) { + Alert.alert( + "Error", + result.error.message || "Failed to delete credential.", + ); + return; + } + Alert.alert("Success", "Credential deleted successfully."); await getMobileCredentials(); } catch (err) { diff --git a/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-starter/package.json b/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-starter/package.json index 3b126a5..5958230 100644 --- a/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-starter/package.json +++ b/react-native-mdocs-holder-tutorial/react-native-mdocs-holder-tutorial-starter/package.json @@ -13,7 +13,7 @@ "ios": "expo run:ios" }, "dependencies": { - "@mattrglobal/mobile-credential-holder-react-native": "^8.1.1", + "@mattrglobal/mobile-credential-holder-react-native": "^10.0.0", "expo": "^55", "expo-build-properties": "~55.0.13", "expo-constants": "~55.0.15",