react-native-unit-components
Version:
Unit React Native components
108 lines (95 loc) • 4.19 kB
text/typescript
import { useEffect, useState, useRef } from 'react';
import { UNWalletCode, UNWalletName } from '../../../types/shared/wallet.types';
import type { UNWallet } from '../../../types/shared/wallet.types';
import { UnitSDK } from '../../../unitSdkManager/UnitSdkManager';
import { getMobileWalletPayload } from '../../../networking/requests/UNWalletPayloadRequest';
import { useSelector, useDispatch } from 'react-redux';
import { selectWallet, setSignedNonce } from '../../../slices/pushProvisioningSlice';
import { useLaunchInitialize } from './useLaunchInitialize';
import { UNVPErrorType } from '../types';
import { promiseRejectToUNVPErrorType } from '../helpers';
import { UNErrorCodes, UNErrorData } from '../../../types/shared/error.types';
import { isUNError } from '../../../types/internal/errorHelpers';
export type CardToEncryptedPayload = {
[cardId: string]: string;
};
export const useCardWallet = (cardId: string) => {
const [currentUNWallet, setCurrentUNWallet] = useState<UNWallet>();
const { signedNonce } = useSelector(selectWallet);
const { initializePushProvisioning } = useLaunchInitialize();
const dispatch = useDispatch();
const isRecoveringSignedNonceRef = useRef<boolean>(false);
const shouldRecoverVPSDKForError = (errorType: UNVPErrorType) => {
const recoveringTypes = [UNVPErrorType.PayloadDecryptionFailed, UNVPErrorType.SessionExpired, UNVPErrorType.InvalidNonce];
return recoveringTypes.includes(errorType);
};
useEffect(() => {
const getEncryptedPayload = async () => {
const env = UnitSDK.getEnv();
const customerToken = UnitSDK.getCustomerToken();
if (!env || !customerToken) return;
// In case we use flow
if (!signedNonce) {
await initializePushProvisioning();
return;
}
const encryptedPayload = await getMobileWalletPayload(customerToken, cardId, env, signedNonce);
return encryptedPayload;
};
const getCardWalletData = async () => {
const currentProvisioningModule = UnitSDK.getPushProvisionModule();
if (!currentProvisioningModule) return;
try {
const encryptedPayload = await getEncryptedPayload();
if (!encryptedPayload) return;
const walletsResponse = await currentProvisioningModule.launchGetWallets(JSON.stringify({ encPayload: encryptedPayload }));
const unWallet: UNWallet | null = parseWalletsResponse(walletsResponse);
if (!unWallet) return;
setCurrentUNWallet(unWallet);
return;
} catch (error) {
console.error('Coudln\'t get card wallet data:', error);
if (isRecoveringSignedNonceRef.current) return;
isRecoveringSignedNonceRef.current = true;
// handle unit network api errors
if (isUNError(error)) {
const errors: UNErrorData[] = error.errors;
// errors will return in an array but hold only a single error element
if (errors[0]?.code === UNErrorCodes.INVALID_NONCE) {
dispatch(setSignedNonce(null));
}
return;
}
// handle VDE SDK errors
const errorType = promiseRejectToUNVPErrorType(error);
if (!errorType) return;
if (shouldRecoverVPSDKForError(errorType)) {
dispatch(setSignedNonce(null));
return;
}
}
};
getCardWalletData();
}, [signedNonce, cardId]);
return {
currentUNWallet,
};
};
const parseWalletsResponse = (walletsResponse: string): UNWallet | null => {
try {
const parsedWalletsResponse = JSON.parse(walletsResponse);
const wallets = parsedWalletsResponse.wallets;
if (!wallets) return null;
if (wallets[0].code === UNWalletCode.Apple) {
return ({ name: UNWalletName.Apple, code: UNWalletCode.Apple, status: wallets[0].status });
} else {
const googleWallet = wallets.filter((wallet: { name: UNWalletName }) => {
return wallet.name === UNWalletName.Google;
});
if (!googleWallet) return null;
return ({ name: UNWalletName.Google, code: UNWalletCode.Google, status: googleWallet[0].status });
}
} catch (error) {
throw new Error('Error parsing wallet response');
}
};