From 443d946c38b91ac53d1bbadcd5df88f669242596 Mon Sep 17 00:00:00 2001 From: vijay151096 <94220135+vijay151096@users.noreply.github.com> Date: Wed, 4 Oct 2023 15:31:31 +0530 Subject: [PATCH] refactor(inji-416): Refactoring Openid4vci components & fixing issues (#889) * refactor(inji-416): merged esignetvcitem and existingvcitem * refactor(inji-416): remove the vc tag feature * refactor(inji-416): wallet binding fixes with vc store key modification * refactor(inji-416): display the vc's in the share vc screen * fix(INJI-416): display issuer logo in VC downloaded via eSignet Co-authored-by: Vijay <94220135+vijay151096@users.noreply.github.com> * fix(INJI-416): display formatted generatedOn date Co-authored-by: Vijay <94220135+vijay151096@users.noreply.github.com> * refactor(INJI-416): add kebab popup operations events in esignetVcItemMachine Co-authored-by: Vijay <94220135+vijay151096@users.noreply.github.com> * fix(INJI-416): vc activation in secure keystore existient android device vc unique identifier UIN is passed to generate keypair while wallet binding * fix(INJI-416): display VC id in removal log Co-authored-by: Vijay <94220135+vijay151096@users.noreply.github.com> * fix(INJI-416): display dateOfBirth in vcDetails in Android date parsing is causing issue in Android device due to JavaScript VM, thus using date-fns to parse. * refactor(INJI-416): modify check for isOpenId4VCIEnabled Co-authored-by: Vijay <94220135+vijay151096@users.noreply.github.com> * refactor(INJI-416): extract method for face image source * fix(INJI-416): show wallet binding success toaster appropriately on secure keystore available devices * refactor(INJI-416): change locale value for download vc description --------- Co-authored-by: Kiruthika Jeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> --- components/KebabPopUp.tsx | 1 + components/KebabPopUpController.tsx | 77 +++- .../EsignetMosipVCItem/EsignetMosipVCItem.tsx | 113 ----- .../EsignetMosipVCItemActivationStatus.tsx | 127 ------ .../EsignetMosipVCItemContent.tsx | 309 ------------- .../ExistingMosipVCItemDetails.tsx | 413 ------------------ .../MosipVCItem.tsx} | 90 ++-- .../MosipVCItemActivationStatus.tsx} | 2 +- .../MosipVCItemContent.tsx} | 115 +++-- .../MosipVCItemDetails.tsx} | 156 ++++--- components/VC/VcDetailsContainer.tsx | 17 +- components/VC/VcItemContainer.tsx | 14 +- locales/ara.json | 2 +- locales/en.json | 2 +- locales/fil.json | 2 +- locales/hin.json | 2 +- locales/kan.json | 2 +- locales/spa.json | 3 +- locales/tam.json | 2 +- .../EsignetMosipVCItemMachine.ts | 158 +++++-- .../EsignetMosipVCItemMachine.typegen.ts | 23 +- .../ExistingMosipVCItemMachine.ts | 54 +-- .../ExistingMosipVCItemMachine.typegen.ts | 10 +- machines/bleShare/request/requestMachine.ts | 2 +- machines/bleShare/scan/scanMachine.ts | 5 +- machines/issuersMachine.ts | 100 ++--- machines/issuersMachine.typegen.ts | 1 + machines/vc.ts | 4 +- machines/vc.typegen.ts | 2 + screens/Home/MyVcs/WalletBinding.tsx | 2 + screens/Home/MyVcsTab.tsx | 40 +- screens/Home/ViewVcModal.strings.json | 3 +- screens/Home/ViewVcModal.tsx | 15 - screens/Home/ViewVcModalController.ts | 5 - shared/VCMetadata.ts | 16 +- shared/openId4VCI/Utils.ts | 1 + shared/vcjs/verifyCredential.ts | 2 +- types/VC/EsignetMosipVC/vc.ts | 5 + 38 files changed, 554 insertions(+), 1343 deletions(-) delete mode 100644 components/VC/EsignetMosipVCItem/EsignetMosipVCItem.tsx delete mode 100644 components/VC/EsignetMosipVCItem/EsignetMosipVCItemActivationStatus.tsx delete mode 100644 components/VC/EsignetMosipVCItem/EsignetMosipVCItemContent.tsx delete mode 100644 components/VC/ExistingMosipVCItem/ExistingMosipVCItemDetails.tsx rename components/VC/{ExistingMosipVCItem/ExistingMosipVCItem.tsx => MosipVCItem/MosipVCItem.tsx} (58%) rename components/VC/{ExistingMosipVCItem/ExistingMosipVCItemActivationStatus.tsx => MosipVCItem/MosipVCItemActivationStatus.tsx} (98%) rename components/VC/{ExistingMosipVCItem/ExistingMosipVCItemContent.tsx => MosipVCItem/MosipVCItemContent.tsx} (75%) rename components/VC/{EsignetMosipVCItem/EsignetMosipVCItemDetails.tsx => MosipVCItem/MosipVCItemDetails.tsx} (80%) diff --git a/components/KebabPopUp.tsx b/components/KebabPopUp.tsx index 11c1ae01..504acaeb 100644 --- a/components/KebabPopUp.tsx +++ b/components/KebabPopUp.tsx @@ -59,6 +59,7 @@ export const KebabPopUp: React.FC = props => { label={t('offlineAuthenticationDisabled!')} content={t('offlineAuthDisabledMessage')} service={props.service} + vcMetadata={props.vcMetadata} /> service.send(vcEvents.SHOW_ACTIVITY()); const INPUT_OTP = (otp: string) => service.send(vcEvents.INPUT_OTP(otp)); const RESEND_OTP = () => service.send(vcEvents.RESEND_OTP()); - const isPinned = useSelector(service, selectIsPinned); - const isBindingWarning = useSelector(service, selectKebabPopUpBindingWarning); - const isRemoveWalletWarning = useSelector(service, selectRemoveWalletWarning); - const isAcceptingOtpInput = useSelector( + let isPinned = useSelector(service, selectIsPinned); + let isBindingWarning = useSelector(service, selectKebabPopUpBindingWarning); + let isRemoveWalletWarning = useSelector(service, selectRemoveWalletWarning); + let isAcceptingOtpInput = useSelector( service, selectKebabPopUpAcceptingBindingOtp, ); - const isWalletBindingError = useSelector( - service, - selectShowWalletBindingError, - ); - const otpError = useSelector(service, selectOtpError); - const walletBindingError = useSelector(service, selectWalletBindingError); - const WalletBindingInProgress = useSelector( + let isWalletBindingError = useSelector(service, selectShowWalletBindingError); + let otpError = useSelector(service, selectOtpError); + let walletBindingError = useSelector(service, selectWalletBindingError); + let WalletBindingInProgress = useSelector( service, selectKebabPopUpWalletBindingInProgress, ); - const emptyWalletBindingId = useSelector(service, selectEmptyWalletBindingId); - const isKebabPopUp = useSelector(service, selectKebabPopUp); - const isShowActivities = useSelector(service, selectShowActivities); + let emptyWalletBindingId = useSelector(service, selectEmptyWalletBindingId); + let isKebabPopUp = useSelector(service, selectKebabPopUp); + let isShowActivities = useSelector(service, selectShowActivities); + + if (props.vcMetadata.isFromOpenId4VCI()) { + isPinned = useSelector(service, esignetSelectIsPinned); + isBindingWarning = useSelector( + service, + esignetSelectKebabPopUpBindingWarning, + ); + isRemoveWalletWarning = useSelector( + service, + esignetSelectRemoveWalletWarning, + ); + isAcceptingOtpInput = useSelector( + service, + esignetSelectKebabPopUpAcceptingBindingOtp, + ); + isWalletBindingError = useSelector( + service, + esignetSelectShowWalletBindingError, + ); + otpError = useSelector(service, esignetSelectOtpError); + walletBindingError = useSelector(service, esignetSelectWalletBindingError); + WalletBindingInProgress = useSelector( + service, + esignetSelectKebabPopUpWalletBindingInProgress, + ); + emptyWalletBindingId = useSelector( + service, + esignetSelectEmptyWalletBindingId, + ); + isKebabPopUp = useSelector(service, esignetSelectKebabPopUp); + isShowActivities = useSelector(service, esignetSelectShowActivities); + } const {appService} = useContext(GlobalContext); const activityLogService = appService.children.get('activityLog'); diff --git a/components/VC/EsignetMosipVCItem/EsignetMosipVCItem.tsx b/components/VC/EsignetMosipVCItem/EsignetMosipVCItem.tsx deleted file mode 100644 index 7cbe09b6..00000000 --- a/components/VC/EsignetMosipVCItem/EsignetMosipVCItem.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import React, {useContext, useEffect, useRef} from 'react'; -import {useInterpret, useSelector} from '@xstate/react'; -import {Pressable, View} from 'react-native'; -import {ActorRefFrom} from 'xstate'; -import {GlobalContext} from '../../../shared/GlobalContext'; -import {Theme} from '../../ui/styleUtils'; -import {Row} from '../../ui'; -import {KebabPopUp} from '../../KebabPopUp'; -import {VCMetadata} from '../../../shared/VCMetadata'; -import {EsignetMosipVCItemContent} from './EsignetMosipVCItemContent'; -import {EsignetMosipVCActivationStatus} from './EsignetMosipVCItemActivationStatus'; -import { - createEsignetMosipVCItemMachine, - EsignetMosipVCItemEvents, - EsignetMosipVCItemMachine, - selectContext, - selectGeneratedOn, - selectKebabPopUp, - selectVerifiableCredentials, -} from '../../../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine'; - -export const EsignetMosipVCItem: React.FC = props => { - const {appService} = useContext(GlobalContext); - const machine = useRef( - createEsignetMosipVCItemMachine( - appService.getSnapshot().context.serviceRefs, - props.vcMetadata, - ), - ); - - const service = useInterpret(machine.current, {devTools: __DEV__}); - - useEffect(() => { - service.send(EsignetMosipVCItemEvents.UPDATE_VC_METADATA(props.vcMetadata)); - }, [props.vcMetadata]); - - const context = useSelector(service, selectContext); - - const isKebabPopUp = useSelector(service, selectKebabPopUp); - const DISMISS = () => service.send(EsignetMosipVCItemEvents.DISMISS()); - const KEBAB_POPUP = () => - service.send(EsignetMosipVCItemEvents.KEBAB_POPUP()); - - const credentials = useSelector(service, selectVerifiableCredentials); - const generatedOn = useSelector(service, selectGeneratedOn); - - return ( - - props.onPress(service)} - disabled={!credentials} - style={ - props.selected - ? Theme.Styles.selectedBindedVc - : Theme.Styles.closeCardBgContainer - }> - props.onPress(service)} - /> - - {props.isSharingVc ? null : ( - - {props.activeTab !== 'receivedVcsTab' && - props.activeTab != 'sharingVcScreen' && ( - - )} - - - - - - - - )} - - - ); -}; - -export interface EsignetMosipVCItemProps { - vcMetadata: VCMetadata; - margin?: string; - selectable?: boolean; - selected?: boolean; - showOnlyBindedVc?: boolean; - onPress?: (vcRef?: ActorRefFrom) => void; - onShow?: (vcRef?: ActorRefFrom) => void; - activeTab?: string; - iconName?: string; - iconType?: string; - isSharingVc?: boolean; -} diff --git a/components/VC/EsignetMosipVCItem/EsignetMosipVCItemActivationStatus.tsx b/components/VC/EsignetMosipVCItem/EsignetMosipVCItemActivationStatus.tsx deleted file mode 100644 index 9d79cf59..00000000 --- a/components/VC/EsignetMosipVCItem/EsignetMosipVCItemActivationStatus.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import React from 'react'; -import {useTranslation} from 'react-i18next'; -import {Dimensions} from 'react-native'; -import {Icon} from 'react-native-elements'; -import {Theme} from '../../ui/styleUtils'; -import {Row, Text} from '../../ui'; -import {VerifiableCredential} from '../../../types/VC/EsignetMosipVC/vc'; - -const WalletUnverifiedIcon: React.FC = () => { - return ( - - ); -}; - -const WalletVerifiedIcon: React.FC = () => { - return ( - - ); -}; - -const WalletUnverifiedActivationDetails: React.FC< - WalletUnVerifiedDetailsProps -> = props => { - const {t} = useTranslation('VcDetails'); - return ( - - - {props.verifiableCredential && } - - - - ); -}; - -const WalletVerifiedActivationDetails: React.FC< - WalletVerifiedDetailsProps -> = props => { - const {t} = useTranslation('WalletBinding'); - return ( - - - - - - - ); -}; - -export const EsignetMosipVCActivationStatus: React.FC< - EsignetMosipVCActivationStatusProps -> = props => { - return ( - - {props.emptyWalletBindingId ? ( - - ) : ( - - )} - - ); -}; - -export interface EsignetMosipVCActivationStatusProps { - showOnlyBindedVc: boolean; - verifiableCredential: VerifiableCredential; - emptyWalletBindingId: boolean; -} - -interface WalletVerifiedDetailsProps { - showOnlyBindedVc: boolean; - verifiableCredential: VerifiableCredential; -} - -interface WalletUnVerifiedDetailsProps { - verifiableCredential: VerifiableCredential; -} diff --git a/components/VC/EsignetMosipVCItem/EsignetMosipVCItemContent.tsx b/components/VC/EsignetMosipVCItem/EsignetMosipVCItemContent.tsx deleted file mode 100644 index 1761cb40..00000000 --- a/components/VC/EsignetMosipVCItem/EsignetMosipVCItemContent.tsx +++ /dev/null @@ -1,309 +0,0 @@ -import React from 'react'; -import {useTranslation} from 'react-i18next'; -import {Image, ImageBackground} from 'react-native'; -import {CheckBox, Icon} from 'react-native-elements'; -import {Column, Row, Text} from '../../ui'; -import {Theme} from '../../ui/styleUtils'; -import VerifiedIcon from '../../VerifiedIcon'; -import {getLocalizedField} from '../../../i18n'; -import { - Credential, - VerifiableCredential, -} from '../../../types/VC/EsignetMosipVC/vc'; -import testIDProps from '../../../shared/commonUtil'; - -const getDetails = (arg1: string, arg2: string, credential: Credential) => { - if (arg1 === 'Status') { - return ( - - - {arg1} - - - {!credential ? null : } - - {!credential ? '' : arg2} - - - - ); - } else { - return ( - - - {arg1} - - - {!credential ? '' : arg2} - - - ); - } -}; - -function getIdNumber(id: string) { - if (id) { - return '*'.repeat(id.length - 4) + id.slice(-4); - } -} - -export const EsignetMosipVCItemContent: React.FC< - EsignetMosipVCItemContentProps -> = props => { - //Assigning the UIN and VID from the VC details to display the idtype label - const uin = props.credential?.credential?.credentialSubject.UIN; - const vid = props.credential?.credential?.credentialSubject.VID; - const fullName = !props.credential?.credential - ? '' - : getLocalizedField( - props.credential?.credential.credentialSubject.fullName, - ); - const {t} = useTranslation('VcDetails'); - const isvalid = !props.credential?.credential ? '' : t('valid'); - const selectableOrCheck = props.selectable ? ( - } - uncheckedIcon={} - onPress={() => props.onPress()} - /> - ) : null; - - return ( - - - - - - {props.iconName && ( - - )} - - - - - - {t('fullName')} - - - {fullName} - - - - - - {t('idType')} - - - {t('nationalCard')} - - - - - - - {props.credential?.credential ? selectableOrCheck : null} - - - - - - {uin ? ( - - - {t('uin')} - - - {getIdNumber(uin)} - - - ) : null} - - {vid ? ( - - - {t('vid')} - - - {getIdNumber(vid)} - - - ) : null} - {!props.credential?.credential - ? getDetails(t('id'), uin | vid, props.credential?.credential) - : null} - - - - - - - {t('generatedOn')} - - - {props.generatedOn} - - - - {props.credential?.credential - ? getDetails(t('status'), isvalid, props.credential?.credential) - : null} - - - - - - - - ); -}; - -interface EsignetMosipVCItemContentProps { - context: any; - credential: VerifiableCredential; - generatedOn: string; - selectable: boolean; - selected: boolean; - iconName?: string; - iconType?: string; - service: any; - onPress?: () => void; -} diff --git a/components/VC/ExistingMosipVCItem/ExistingMosipVCItemDetails.tsx b/components/VC/ExistingMosipVCItem/ExistingMosipVCItemDetails.tsx deleted file mode 100644 index 5e3a2971..00000000 --- a/components/VC/ExistingMosipVCItem/ExistingMosipVCItemDetails.tsx +++ /dev/null @@ -1,413 +0,0 @@ -import {formatDistanceToNow} from 'date-fns'; -import React from 'react'; -import * as DateFnsLocale from 'date-fns/locale'; -import {useTranslation} from 'react-i18next'; -import {Image, ImageBackground, View} from 'react-native'; -import {Icon} from 'react-native-elements'; -import {VC, CredentialSubject} from '../../../types/VC/ExistingMosipVC/vc'; -import {Button, Column, Row, Text} from '../../ui'; -import {Theme} from '../../ui/styleUtils'; -import {TextItem} from '../../ui/TextItem'; -import {VcItemTags} from '../common/VcItemTags'; -import VerifiedIcon from '../../VerifiedIcon'; -import {getLocalizedField} from '../../../i18n'; -import {CREDENTIAL_REGISTRY_EDIT} from 'react-native-dotenv'; -import {QrCodeOverlay} from '../../QrCodeOverlay'; - -export const ExistingMosipVCItemDetails: React.FC< - ExistingMosipVCItemDetailsProps -> = props => { - const {t, i18n} = useTranslation('VcDetails'); - - //Assigning the UIN and VID from the VC details to display the idtype label - const uin = props.vc?.verifiableCredential.credentialSubject.UIN; - const vid = props.vc?.verifiableCredential.credentialSubject.VID; - - if (props.vc?.verifiableCredential == null) { - return Loading details...; - } - - return ( - - - - - - - - - - - - - - - {t('fullName')} - - - {getLocalizedField( - props.vc?.verifiableCredential.credentialSubject.fullName, - )} - - - - - - - {t('gender')} - - - {getLocalizedField( - props.vc?.verifiableCredential.credentialSubject.gender, - )} - - - - - {t('idType')} - - - {t('nationalCard')} - - - {uin ? ( - - - {t('uin')} - - - {uin} - - - ) : null} - - {vid ? ( - - - {t('vid')} - - - {vid} - - - ) : null} - - - {t('generatedOn')} - - - {new Date(props.vc?.generatedOn).toLocaleDateString()} - - - - - - - {t('dateOfBirth')} - - - {new Date( - getLocalizedField( - props.vc?.verifiableCredential.credentialSubject - .dateOfBirth, - ), - ).toLocaleDateString()} - - - - - {t('status')} - - - {props.vc?.isVerified && } - - {t('valid')} - - - - - - {t('phoneNumber')} - - - {getLocalizedField( - props.vc?.verifiableCredential.credentialSubject.phone, - )} - - - - - - - - - - - {t('email')} - - - 25 - ? {flex: 1} - : {flex: 0} - } - weight="semibold" - size="smaller" - color={Theme.Colors.Details}> - {getLocalizedField( - props.vc?.verifiableCredential.credentialSubject.email, - )} - - - - - - - {t('address')} - - - - {getFullAddress( - props.vc?.verifiableCredential.credentialSubject, - )} - - - - {CREDENTIAL_REGISTRY_EDIT === 'true' && ( - - - {t('credentialRegistry')} - - - {props.vc?.credentialRegistry} - - - )} - - - - - {props.vc?.reason?.length > 0 && ( - - {t('reasonForSharing')} - - )} - - {props.vc?.reason?.map((reason, index) => ( - - ))} - - {props.activeTab !== 1 ? ( - props.isBindingPending ? ( - - - - - {t('offlineAuthDisabledHeader')} - - - - {t('offlineAuthDisabledMessage')} - - -