From 55c666b121bfca727c63709323d0a15aca22d47e Mon Sep 17 00:00:00 2001 From: KiruthikaJeyashankar <81218987+KiruthikaJeyashankar@users.noreply.github.com> Date: Fri, 22 Sep 2023 17:22:59 +0530 Subject: [PATCH] feat: download credentials from Esignet using openId4VCI (#851) * feat(INJI-245): dowload and view card via issuers Co-authored-by: Harsh Vardhan * fix(INJI-245): remove vc from wallet Co-authored-by: Harsh Vardhan * feat(INJI-245): pin card downloaded via eSignet * refactor(INJI-245): remove debug logs * refactor(INJI-245): rename vcItem related component to ExistingVcItem * refactor(INJI-245): add lock file modifications * refactor(INJI-245): add styles in purple theme for issuer related components * refactor(INJI-245): update VID for wallet binding usecase and issuer logo display in vc * refactor(INJI-245): remove duplicate loader component * refactor(INJI-245): remove unused props in vc details container --------- Co-authored-by: Harsh Vardhan Co-authored-by: Vijay <94220135+vijay151096@users.noreply.github.com> --- .env | 3 + android/app/build.gradle | 3 +- assets/digit-icon.png | Bin 0 -> 3171 bytes assets/no-internet-connection.png | Bin 0 -> 4034 bytes assets/something-went-wrong.png | Bin 0 -> 31433 bytes components/KebabPopUp.tsx | 4 +- components/KebabPopUpController.tsx | 57 +- .../EsignetMosipVCItem/EsignetMosipVCItem.tsx | 105 + .../EsignetMosipVCItemActivationStatus.tsx | 130 + .../EsignetMosipVCItemContent.tsx | 201 + .../EsignetMosipVCItemDetails.tsx | 401 ++ components/VC/EsignetMosipVCItem/vc.ts | 117 + .../ExistingMosipVCItem.tsx} | 47 +- .../ExistingMosipVCItemActivationStatus.tsx} | 20 +- .../ExistingMosipVCItemContent.tsx} | 20 +- .../ExistingMosipVCItemDetails.tsx} | 22 +- components/VC/VcDetailsContainer.tsx | 19 + components/VC/VcItemContainer.tsx | 18 + components/VidItem.tsx | 42 +- components/openId4VCI/Issuer.tsx | 66 + components/ui/Button.tsx | 3 +- components/ui/Error.tsx | 75 + components/ui/Header.tsx | 54 + components/ui/Loader.tsx | 86 + components/ui/themes/DefaultTheme.ts | 153 +- components/ui/themes/PurpleTheme.ts | 149 +- ios/Inji/AppDelegate.h | 11 +- ios/Podfile.lock | 33 +- locales/en.json | 28 + .../EsignetMosipVCItemMachine.ts | 782 ++++ .../EsignetMosipVCItemMachine.typegen.ts | 230 ++ .../ExistingMosipVCItemMachine.ts} | 46 +- .../ExistingMosipVCItemMachine.typegen.ts} | 29 +- machines/issuersMachine.ts | 501 +++ machines/issuersMachine.typegen.ts | 108 + machines/vc.ts | 20 +- machines/vc.typegen.ts | 25 +- package-lock.json | 3305 ++++++++++++++++- package.json | 4 + routes/main.ts | 10 +- screens/Home/HomeScreen.tsx | 76 +- screens/Home/HomeScreenController.ts | 18 +- screens/Home/HomeScreenMachine.ts | 79 +- screens/Home/HomeScreenMachine.typegen.ts | 33 +- screens/Home/MyVcs/HistoryTab.tsx | 4 +- screens/Home/MyVcs/WalletBinding.tsx | 4 +- screens/Home/MyVcs/WalletBindingController.ts | 41 +- screens/Home/MyVcsTab.tsx | 38 +- screens/Home/MyVcsTabController.ts | 11 +- screens/Home/MyVcsTabMachine.ts | 10 +- screens/Home/ReceivedVcsTab.tsx | 4 +- screens/Home/ReceivedVcsTabController.ts | 18 +- screens/Home/ReceivedVcsTabMachine.ts | 26 +- screens/Home/ViewVcModal.tsx | 32 +- screens/Home/ViewVcModalController.ts | 75 +- screens/HomeScreenLayout.tsx | 102 + screens/Issuers/IssuerScreenController.tsx | 45 + screens/Issuers/IssuersScreen.tsx | 141 + screens/QrLogin/MyBindedVcs.tsx | 26 +- screens/QrLogin/QrLoginController.ts | 25 +- screens/Request/ReceiveVcScreen.tsx | 24 +- screens/Scan/SelectVcOverlay.tsx | 20 +- screens/Scan/SelectVcOverlayController.ts | 18 +- screens/Scan/SendVcScreen.tsx | 56 +- screens/Scan/SendVcScreenController.ts | 21 +- screens/Settings/ReceivedCardsModal.tsx | 4 +- screens/Settings/RevokeController.tsx | 32 +- shared/VCMetadata.ts | 39 +- shared/cryptoutil/cryptoUtil.ts | 22 +- shared/openId4VCI/Utils.ts | 86 + shared/vcjs/verifyCredential.ts | 13 +- types/react-native-dotenv/index.d.ts | 5 + 72 files changed, 7501 insertions(+), 574 deletions(-) create mode 100644 assets/digit-icon.png create mode 100644 assets/no-internet-connection.png create mode 100644 assets/something-went-wrong.png create mode 100644 components/VC/EsignetMosipVCItem/EsignetMosipVCItem.tsx create mode 100644 components/VC/EsignetMosipVCItem/EsignetMosipVCItemActivationStatus.tsx create mode 100644 components/VC/EsignetMosipVCItem/EsignetMosipVCItemContent.tsx create mode 100644 components/VC/EsignetMosipVCItem/EsignetMosipVCItemDetails.tsx create mode 100644 components/VC/EsignetMosipVCItem/vc.ts rename components/{VcItem.tsx => VC/ExistingMosipVCItem/ExistingMosipVCItem.tsx} (71%) rename components/{VcItemActivationStatus.tsx => VC/ExistingMosipVCItem/ExistingMosipVCItemActivationStatus.tsx} (82%) rename components/{VcItemContent.tsx => VC/ExistingMosipVCItem/ExistingMosipVCItemContent.tsx} (94%) rename components/{VcDetails.tsx => VC/ExistingMosipVCItem/ExistingMosipVCItemDetails.tsx} (96%) create mode 100644 components/VC/VcDetailsContainer.tsx create mode 100644 components/VC/VcItemContainer.tsx create mode 100644 components/openId4VCI/Issuer.tsx create mode 100644 components/ui/Error.tsx create mode 100644 components/ui/Header.tsx create mode 100644 components/ui/Loader.tsx create mode 100644 machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine.ts create mode 100644 machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine.typegen.ts rename machines/{vcItem.ts => VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine.ts} (97%) rename machines/{vcItem.typegen.ts => VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine.typegen.ts} (97%) create mode 100644 machines/issuersMachine.ts create mode 100644 machines/issuersMachine.typegen.ts create mode 100644 screens/HomeScreenLayout.tsx create mode 100644 screens/Issuers/IssuerScreenController.tsx create mode 100644 screens/Issuers/IssuersScreen.tsx create mode 100644 shared/openId4VCI/Utils.ts diff --git a/.env b/.env index 5a610e11..d9036908 100644 --- a/.env +++ b/.env @@ -18,3 +18,6 @@ CREDENTIAL_REGISTRY_EDIT=true #supported languages( en, fil, ar, hi, kn, ta) APPLICATION_LANGUAGE=en + +#Toggle for openID for VC +ENABLE_OPENID_FOR_VC=false diff --git a/android/app/build.gradle b/android/app/build.gradle index a4d620c6..48608aa1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -121,7 +121,8 @@ android { manifestPlaceholders = [ APP_NAME: APP_NAME_RELEASE, - GOOGLE_NEARBY_MESSAGES_API_KEY: "${properties.getProperty('GOOGLE_NEARBY_MESSAGES_API_KEY')}" + GOOGLE_NEARBY_MESSAGES_API_KEY: "${properties.getProperty('GOOGLE_NEARBY_MESSAGES_API_KEY')}", + appAuthRedirectScheme: 'io.mosip.residentapp.inji' ] } splits { diff --git a/assets/digit-icon.png b/assets/digit-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8c1c1d091b78d431c79c9358f6e22379ed052cb4 GIT binary patch literal 3171 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 literal 0 HcmV?d00001 diff --git a/assets/something-went-wrong.png b/assets/something-went-wrong.png new file mode 100644 index 0000000000000000000000000000000000000000..52d8c34644b8637a1b18939c5b541e43322bd94d GIT binary patch literal 31433 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 void; - service: ActorRefFrom; + service: ActorRefFrom; } diff --git a/components/KebabPopUpController.tsx b/components/KebabPopUpController.tsx index 030699ad..010098ca 100644 --- a/components/KebabPopUpController.tsx +++ b/components/KebabPopUpController.tsx @@ -1,5 +1,5 @@ -import { useSelector } from '@xstate/react'; -import { ActorRefFrom } from 'xstate'; +import {useSelector} from '@xstate/react'; +import {ActorRefFrom} from 'xstate'; import { selectKebabPopUpWalletBindingInProgress, selectKebabPopUp, @@ -11,49 +11,60 @@ import { selectOtpError, selectShowWalletBindingError, selectWalletBindingError, - VcItemEvents, - vcItemMachine, + ExistingMosipVCItemEvents, + ExistingMosipVCItemMachine, selectShowActivities, -} from '../machines/vcItem'; -import { selectActivities } from '../machines/activityLog'; -import { GlobalContext } from '../shared/GlobalContext'; -import { useContext } from 'react'; -import { VCMetadata } from '../shared/VCMetadata'; +} from '../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine'; +import {selectActivities} from '../machines/activityLog'; +import {GlobalContext} from '../shared/GlobalContext'; +import {useContext} from 'react'; +import {VCMetadata} from '../shared/VCMetadata'; +import { + EsignetMosipVCItemEvents, + EsignetMosipVCItemMachine, +} from '../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine'; +import {isVCFromOpenId4VCI} from '../shared/openId4VCI/Utils'; export function useKebabPopUp(props) { - const service = props.service as ActorRefFrom; - const PIN_CARD = () => service.send(VcItemEvents.PIN_CARD()); - const KEBAB_POPUP = () => service.send(VcItemEvents.KEBAB_POPUP()); + const service = props.service as + | ActorRefFrom + | ActorRefFrom; + const vcEvents = + props.vcKey !== undefined && isVCFromOpenId4VCI(props.vcMetadata) + ? EsignetMosipVCItemEvents + : ExistingMosipVCItemEvents; + const PIN_CARD = () => service.send(vcEvents.PIN_CARD()); + const KEBAB_POPUP = () => service.send(vcEvents.KEBAB_POPUP()); const ADD_WALLET_BINDING_ID = () => - service.send(VcItemEvents.ADD_WALLET_BINDING_ID()); - const CONFIRM = () => service.send(VcItemEvents.CONFIRM()); + service.send(vcEvents.ADD_WALLET_BINDING_ID()); + const CONFIRM = () => service.send(vcEvents.CONFIRM()); const REMOVE = (vcMetadata: VCMetadata) => - service.send(VcItemEvents.REMOVE(vcMetadata)); - const DISMISS = () => service.send(VcItemEvents.DISMISS()); - const CANCEL = () => service.send(VcItemEvents.CANCEL()); - const SHOW_ACTIVITY = () => service.send(VcItemEvents.SHOW_ACTIVITY()); - const INPUT_OTP = (otp: string) => service.send(VcItemEvents.INPUT_OTP(otp)); + service.send(vcEvents.REMOVE(vcMetadata)); + const DISMISS = () => service.send(vcEvents.DISMISS()); + const CANCEL = () => service.send(vcEvents.CANCEL()); + const SHOW_ACTIVITY = () => service.send(vcEvents.SHOW_ACTIVITY()); + const INPUT_OTP = (otp: string) => service.send(vcEvents.INPUT_OTP(otp)); const isPinned = useSelector(service, selectIsPinned); const isBindingWarning = useSelector(service, selectKebabPopUpBindingWarning); const isRemoveWalletWarning = useSelector(service, selectRemoveWalletWarning); const isAcceptingOtpInput = useSelector( service, - selectKebabPopUpAcceptingBindingOtp + selectKebabPopUpAcceptingBindingOtp, ); const isWalletBindingError = useSelector( service, - selectShowWalletBindingError + selectShowWalletBindingError, ); const otpError = useSelector(service, selectOtpError); const walletBindingError = useSelector(service, selectWalletBindingError); const WalletBindingInProgress = useSelector( service, - selectKebabPopUpWalletBindingInProgress + selectKebabPopUpWalletBindingInProgress, ); const emptyWalletBindingId = useSelector(service, selectEmptyWalletBindingId); const isKebabPopUp = useSelector(service, selectKebabPopUp); const isShowActivities = useSelector(service, selectShowActivities); - const { appService } = useContext(GlobalContext); + const {appService} = useContext(GlobalContext); const activityLogService = appService.children.get('activityLog'); return { diff --git a/components/VC/EsignetMosipVCItem/EsignetMosipVCItem.tsx b/components/VC/EsignetMosipVCItem/EsignetMosipVCItem.tsx new file mode 100644 index 00000000..016b8712 --- /dev/null +++ b/components/VC/EsignetMosipVCItem/EsignetMosipVCItem.tsx @@ -0,0 +1,105 @@ +import React, {useContext, useRef} from 'react'; +import {useInterpret, useSelector} from '@xstate/react'; +import {Pressable} from 'react-native'; +import {ActorRefFrom} from 'xstate'; +import {GlobalContext} from '../../../shared/GlobalContext'; +import {logState} from '../../../machines/app'; +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 { + EsignetMosipVCItemEvents, + EsignetMosipVCItemMachine, + createEsignetMosipVCItemMachine, + 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__}); + service.subscribe(logState); + 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 new file mode 100644 index 00000000..cb12afc6 --- /dev/null +++ b/components/VC/EsignetMosipVCItem/EsignetMosipVCItemActivationStatus.tsx @@ -0,0 +1,130 @@ +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 './vc'; + +const WalletUnverifiedIcon: React.FC = () => { + return ( + + ); +}; + +const WalletVerifiedIcon: React.FC = () => { + return ( + + ); +}; + +const WalletUnverifiedActivationDetails: React.FC< + WalletUnVerifiedDetailsProps +> = props => { + const {t} = useTranslation('VcDetails'); + return ( + + + {props.verifiableCredential && } + + {t('profileAuthenticated')} + + + + ); +}; + +const WalletVerifiedActivationDetails: React.FC< + WalletVerifiedDetailsProps +> = props => { + const {t} = useTranslation('VcDetails'); + return ( + + + + + {t('profileAuthenticated')} + + + + ); +}; + +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 new file mode 100644 index 00000000..e08d86c1 --- /dev/null +++ b/components/VC/EsignetMosipVCItem/EsignetMosipVCItemContent.tsx @@ -0,0 +1,201 @@ +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 './vc'; +import testIDProps from '../../../shared/commonUtil'; + +const getDetails = (arg1: string, arg2: string, credential: Credential) => { + if (arg1 === 'Status') { + return ( + + + {arg1} + + + + {!credential ? '' : arg2} + + {!credential ? null : } + + + ); + } else { + return ( + + + {arg1} + + + {!credential ? '' : arg2} + + + ); + } +}; + +export const EsignetMosipVCItemContent: React.FC< + EsignetMosipVCItemContentProps +> = props => { + const fullName = !props.credential + ? '' + : getLocalizedField( + props.credential?.credential.credentialSubject?.fullName, + ); + const {t} = useTranslation('VcDetails'); + const isvalid = !props.credential ? '' : t('valid'); + const selectableOrCheck = props.selectable ? ( + } + uncheckedIcon={} + onPress={() => props.onPress()} + /> + ) : null; + + return ( + + + + + + {props.iconName && ( + + )} + + + {getDetails( + t('fullName'), + fullName, + props.credential?.credential, + )} + + + + {t('idType')} + + + {t('nationalCard')} + + + + + + {props.credential ? selectableOrCheck : null} + + + + + {!props.credential + ? getDetails(t('id'), 'newid', props.credential?.credential) + : null} + {getDetails( + t('generatedOn'), + props.generatedOn, + props.credential?.credential, + )} + + + {props.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/EsignetMosipVCItem/EsignetMosipVCItemDetails.tsx b/components/VC/EsignetMosipVCItem/EsignetMosipVCItemDetails.tsx new file mode 100644 index 00000000..b62e089b --- /dev/null +++ b/components/VC/EsignetMosipVCItem/EsignetMosipVCItemDetails.tsx @@ -0,0 +1,401 @@ +import React from 'react'; +import {useTranslation} from 'react-i18next'; +import {Button, Column, Row, Text} from '../../ui'; +import {Image, ImageBackground, View} from 'react-native'; +import {Theme} from '../../ui/styleUtils'; +import {QrCodeOverlay} from '../../QrCodeOverlay'; +import {getLocalizedField} from '../../../i18n'; +import VerifiedIcon from '../../VerifiedIcon'; +import {CREDENTIAL_REGISTRY_EDIT} from 'react-native-dotenv'; +import {TextItem} from '../../ui/TextItem'; +import {format, formatDistanceToNow, parse} from 'date-fns'; +import DateFnsLocale from 'date-fns/locale'; +import {Icon} from 'react-native-elements'; +import {WalletBindingResponse} from '../../../shared/cryptoutil/cryptoUtil'; +import { + CredentialSubject, + VCSharingReason, + VcIdType, + VerifiableCredential, + VerifiablePresentation, +} from './vc'; + +export const EsignetMosipVCItemDetails: React.FC< + EsignetMosipVCItemDetailsProps +> = props => { + const {t, i18n} = useTranslation('VcDetails'); + + if (props.vc?.verifiableCredential == null) { + return Loading details...; + } + + return ( + + + + + + + + + + + + + + + {t('fullName')} + + + {getLocalizedField( + props.vc?.verifiableCredential.credential.credentialSubject + .fullName, + )} + + + + + + + {t('idType')} + + + {t('nationalCard')} + + + {props.vc?.verifiableCredential.credential.credentialSubject + .VID ? ( + + + {t('vid')} + + + { + props.vc?.verifiableCredential.credential + .credentialSubject.VID + } + + + ) : null} + + + {t('dateOfBirth')} + + + {format( + parse( + getLocalizedField( + props.vc?.verifiableCredential.credential + .credentialSubject.dateOfBirth, + ), + 'yyyy/MM/dd', + new Date(), + ), + 'yyy/MM/dd', + )} + + + + + + + {t('gender')} + + + {getLocalizedField( + props.vc?.verifiableCredential.credential + .credentialSubject.gender, + )} + + + + + {t('generatedOn')} + + + {new Date(props.vc?.generatedOn).toLocaleDateString()} + + + + + {t('status')} + + + + {t('valid')} + + {props.vc?.isVerified && } + + + + + {t('phoneNumber')} + + + {getLocalizedField( + props.vc?.verifiableCredential.credential + .credentialSubject.phone, + )} + + + + + + + + + + + {t('email')} + + + 25 + ? {flex: 1} + : {flex: 0} + } + weight="semibold" + size="smaller" + color={Theme.Colors.Details}> + {getLocalizedField( + props.vc?.verifiableCredential.credential.credentialSubject + .email, + )} + + + + + + + {t('address')} + + + + {getFullAddress( + props.vc?.verifiableCredential.credential.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')} + + +