diff --git a/.env b/.env
index 3c462bb6..3bd290d7 100644
--- a/.env
+++ b/.env
@@ -2,9 +2,9 @@
# eg . npm build android:newlogic --reset-cache
#MIMOTO_HOST=http://mock.mimoto.newlogic.dev
-MIMOTO_HOST=https://api.qa-inji.mosip.net
+MIMOTO_HOST=https://api.qa-inji1.mosip.net
-ESIGNET_HOST=https://api.qa-inji.mosip.net
+ESIGNET_HOST=https://api.qa-inji1.mosip.net
OBSRV_HOST = https://dataset-api.obsrv.mosip.net
@@ -17,3 +17,6 @@ DEBUG_MODE=false
#supported languages( en, fil, ar, hi, kn, ta)
APPLICATION_LANGUAGE=en
+
+#Card Templatization - Render Claims Dynamically.
+CARD_TEMPLATIZATION=false
diff --git a/components/VC/MosipVCItem/MosipVCItemActivationStatus.tsx b/components/VC/MosipVCItem/MosipVCItemActivationStatus.tsx
index 4e7e5aca..29549c6d 100644
--- a/components/VC/MosipVCItem/MosipVCItemActivationStatus.tsx
+++ b/components/VC/MosipVCItem/MosipVCItemActivationStatus.tsx
@@ -1,10 +1,10 @@
import React from 'react';
import {useTranslation} from 'react-i18next';
-import {Dimensions} from 'react-native';
import {Icon} from 'react-native-elements';
import {VerifiableCredential} from '../../../types/VC/ExistingMosipVC/vc';
import {Row, Text} from '../../ui';
import {Theme} from '../../ui/styleUtils';
+import {View} from 'react-native';
const WalletUnverifiedIcon: React.FC = () => {
return (
@@ -41,17 +41,21 @@ const WalletUnverifiedActivationDetails: React.FC<
const {t} = useTranslation('VcDetails');
return (
- {props.verifiableCredential && }
-
+
+ {props.verifiableCredential && }
+
+
+
+
);
};
@@ -62,19 +66,23 @@ const WalletVerifiedActivationDetails: React.FC<
const {t} = useTranslation('WalletBinding');
return (
-
-
+
+
+
+
+
+
);
};
diff --git a/components/VC/VcDetailsContainer.tsx b/components/VC/VcDetailsContainer.tsx
index 51fe02e2..e55a1dd9 100644
--- a/components/VC/VcDetailsContainer.tsx
+++ b/components/VC/VcDetailsContainer.tsx
@@ -1,12 +1,16 @@
import React from 'react';
import {
- MosipVCItemDetails,
- ExistingMosipVCItemDetailsProps,
EsignetMosipVCItemDetailsProps,
+ ExistingMosipVCItemDetailsProps,
+ MosipVCItemDetails,
} from './MosipVCItem/MosipVCItemDetails';
+import {CARD_TEMPLATIZATION} from 'react-native-dotenv';
+import {VCDetailView} from './Views/VCDetailView';
+
export const VcDetailsContainer: React.FC<
ExistingMosipVCItemDetailsProps | EsignetMosipVCItemDetailsProps
> = props => {
+ if (CARD_TEMPLATIZATION === 'true') return ;
return ;
};
diff --git a/components/VC/VcItemContainer.tsx b/components/VC/VcItemContainer.tsx
index 2dd0377b..98d26255 100644
--- a/components/VC/VcItemContainer.tsx
+++ b/components/VC/VcItemContainer.tsx
@@ -1,12 +1,15 @@
import React from 'react';
import {
EsignetMosipVCItemProps,
- MosipVCItem,
ExistingMosipVCItemProps,
+ MosipVCItem,
} from './MosipVCItem/MosipVCItem';
+import {CARD_TEMPLATIZATION} from 'react-native-dotenv';
+import {VCCardView} from './Views/VCCardView';
export const VcItemContainer: React.FC<
ExistingMosipVCItemProps | EsignetMosipVCItemProps
> = props => {
+ if (CARD_TEMPLATIZATION === 'true') return ;
return ;
};
diff --git a/components/VC/Views/VCCardView.tsx b/components/VC/Views/VCCardView.tsx
new file mode 100644
index 00000000..d6ed30bf
--- /dev/null
+++ b/components/VC/Views/VCCardView.tsx
@@ -0,0 +1,166 @@
+import React, {useEffect, useState} from 'react';
+import {Pressable, View} from 'react-native';
+import {ActorRefFrom} from 'xstate';
+import {
+ ExistingMosipVCItemEvents,
+ ExistingMosipVCItemMachine,
+} from '../../../machines/VCItemMachine/ExistingMosipVCItem/ExistingMosipVCItemMachine';
+import {ErrorMessageOverlay} from '../../MessageOverlay';
+import {Theme} from '../../ui/styleUtils';
+import {Row} from '../../ui';
+import {KebabPopUp} from '../../KebabPopUp';
+import {VCMetadata} from '../../../shared/VCMetadata';
+import {format} from 'date-fns';
+import {EsignetMosipVCItemMachine} from '../../../machines/VCItemMachine/EsignetMosipVCItem/EsignetMosipVCItemMachine';
+
+import {VCCardSkeleton} from '../common/VCCardSkeleton';
+import {VCCardViewContent} from './VCCardViewContent';
+import {MosipVCItemActivationStatus} from '../MosipVCItem/MosipVCItemActivationStatus';
+import {useVcItemController} from '../MosipVCItem/VcItemController';
+import {getCredentialIssuersWellKnownConfig} from '../../../shared/openId4VCI/Utils';
+import {
+ CARD_VIEW_ADD_ON_FIELDS,
+ CARD_VIEW_DEFAULT_FIELDS,
+} from '../../../shared/constants';
+import {isVCLoaded} from '../common/VCUtils';
+
+export const VCCardView: React.FC<
+ ExistingMosipVCItemProps | EsignetMosipVCItemProps
+> = props => {
+ let {
+ service,
+ context,
+ verifiableCredential,
+ emptyWalletBindingId,
+ isKebabPopUp,
+ isSavingFailedInIdle,
+ storeErrorTranslationPath,
+ generatedOn,
+
+ DISMISS,
+ KEBAB_POPUP,
+ } = useVcItemController(props);
+
+ let formattedDate =
+ generatedOn && format(new Date(generatedOn), 'MM/dd/yyyy');
+
+ useEffect(() => {
+ service.send(
+ ExistingMosipVCItemEvents.UPDATE_VC_METADATA(props.vcMetadata),
+ );
+ }, [props.vcMetadata]);
+
+ const credential = props.isDownloading
+ ? null
+ : props.vcMetadata.isFromOpenId4VCI()
+ ? verifiableCredential?.credential
+ : verifiableCredential;
+
+ const [fields, setFields] = useState([]);
+ const [wellknown, setWellknown] = useState(null);
+ useEffect(() => {
+ getCredentialIssuersWellKnownConfig(
+ props?.vcMetadata.issuer,
+ verifiableCredential?.wellKnown,
+ CARD_VIEW_DEFAULT_FIELDS,
+ ).then(response => {
+ setWellknown(response.wellknown);
+ setFields(response.fields.slice(0, 1).concat(CARD_VIEW_ADD_ON_FIELDS));
+ });
+ }, [verifiableCredential?.wellKnown]);
+
+ if (!isVCLoaded(verifiableCredential, fields)) {
+ return ;
+ }
+
+ return (
+
+ props.onPress(service)}
+ disabled={!verifiableCredential}
+ style={
+ props.selected
+ ? Theme.Styles.selectedBindedVc
+ : Theme.Styles.closeCardBgContainer
+ }>
+ props.onPress(service)}
+ isDownloading={props.isDownloading}
+ />
+
+ {props.isSharingVc ? null : (
+
+
+
+
+
+
+
+
+
+
+
+ )}
+
+
+
+ );
+};
+
+export interface ExistingMosipVCItemProps {
+ vcMetadata: VCMetadata;
+ margin?: string;
+ selectable?: boolean;
+ selected?: boolean;
+ showOnlyBindedVc?: boolean;
+ onPress?: (vcRef?: ActorRefFrom) => void;
+ onShow?: (vcRef?: ActorRefFrom) => void;
+ isSharingVc?: boolean;
+ isDownloading?: boolean;
+ isPinned?: boolean;
+}
+
+export interface EsignetMosipVCItemProps {
+ vcMetadata: VCMetadata;
+ margin?: string;
+ selectable?: boolean;
+ selected?: boolean;
+ showOnlyBindedVc?: boolean;
+ onPress?: (vcRef?: ActorRefFrom) => void;
+ onShow?: (vcRef?: ActorRefFrom) => void;
+ isSharingVc?: boolean;
+ isDownloading?: boolean;
+ isPinned?: boolean;
+}
diff --git a/components/VC/Views/VCCardViewContent.tsx b/components/VC/Views/VCCardViewContent.tsx
new file mode 100644
index 00000000..ff9aec77
--- /dev/null
+++ b/components/VC/Views/VCCardViewContent.tsx
@@ -0,0 +1,132 @@
+import React from 'react';
+import {ImageBackground} from 'react-native';
+import {VerifiableCredential} from '../../../types/VC/ExistingMosipVC/vc';
+import {Column, Row} from '../../ui';
+import {Theme} from '../../ui/styleUtils';
+import {CheckBox, Icon} from 'react-native-elements';
+import {SvgImage} from '../../ui/svg';
+import {
+ fieldItemIterator,
+ getIssuerLogo,
+ isVCLoaded,
+ setBackgroundColour,
+} from '../common/VCUtils';
+import VerifiedIcon from '../../VerifiedIcon';
+import {VCItemField} from '../common/VCItemField';
+import {useTranslation} from 'react-i18next';
+
+export const VCCardViewContent: React.FC<
+ ExistingMosipVCItemContentProps | EsignetMosipVCItemContentProps
+> = props => {
+ const {t} = useTranslation('VcDetails');
+ const selectableOrCheck = props.selectable ? (
+
+ }
+ uncheckedIcon={
+
+ }
+ onPress={() => props.onPress()}
+ />
+ ) : null;
+
+ return (
+
+
+
+
+ {SvgImage.VcItemContainerProfileImage(props, props.credential)}
+
+ {fieldItemIterator(
+ props.fields.slice(0, 2),
+ props.credential,
+ props.wellknown,
+ props,
+ )}
+
+
+ {props.credential ? selectableOrCheck : null}
+
+ {fieldItemIterator(
+ props.fields.slice(2),
+ props.credential,
+ props.wellknown,
+ props,
+ )}
+
+
+ )
+ }
+ wellknown={props.wellknown}
+ verifiableCredential={props.credential}
+ />
+
+ {!isVCLoaded(props.credential, props.fields)
+ ? null
+ : getIssuerLogo(
+ props.vcMetadata.isFromOpenId4VCI(),
+ props.verifiableCredential?.issuerLogo,
+ )}
+
+
+
+
+ );
+};
+
+export interface ExistingMosipVCItemContentProps {
+ context: any;
+ verifiableCredential: VerifiableCredential;
+ credential: VerifiableCredential;
+ fields: [];
+ wellknown: {};
+ generatedOn: string;
+ selectable: boolean;
+ selected: boolean;
+ isPinned?: boolean;
+ service: any;
+ onPress?: () => void;
+ isDownloading?: boolean;
+}
+
+export interface EsignetMosipVCItemContentProps {
+ context: any;
+ credential: VerifiableCredential;
+ fields: [];
+ wellknown: {};
+ generatedOn: string;
+ selectable: boolean;
+ selected: boolean;
+ isPinned?: boolean;
+ service: any;
+ onPress?: () => void;
+ isDownloading?: boolean;
+}
+
+VCCardViewContent.defaultProps = {
+ isPinned: false,
+};
diff --git a/components/VC/Views/VCDetailView.tsx b/components/VC/Views/VCDetailView.tsx
new file mode 100644
index 00000000..6cd16291
--- /dev/null
+++ b/components/VC/Views/VCDetailView.tsx
@@ -0,0 +1,248 @@
+import {formatDistanceToNow} from 'date-fns';
+import React, {useEffect, useState} from 'react';
+import * as DateFnsLocale from 'date-fns/locale';
+import {useTranslation} from 'react-i18next';
+import {Image, ImageBackground} from 'react-native';
+import {Icon} from 'react-native-elements';
+import {VC} from '../../../types/VC/ExistingMosipVC/vc';
+import {Button, Column, Row, Text} from '../../ui';
+import {Theme} from '../../ui/styleUtils';
+import {TextItem} from '../../ui/TextItem';
+import {QrCodeOverlay} from '../../QrCodeOverlay';
+import {VCMetadata} from '../../../shared/VCMetadata';
+import {
+ VcIdType,
+ VCSharingReason,
+ VerifiableCredential,
+ VerifiablePresentation,
+} from '../../../types/VC/EsignetMosipVC/vc';
+import {WalletBindingResponse} from '../../../shared/cryptoutil/cryptoUtil';
+import {logoType} from '../../../machines/issuersMachine';
+import {SvgImage} from '../../ui/svg';
+import {getCredentialIssuersWellKnownConfig} from '../../../shared/openId4VCI/Utils';
+import {
+ DETAIL_VIEW_ADD_ON_FIELDS,
+ DETAIL_VIEW_DEFAULT_FIELDS,
+} from '../../../shared/constants';
+import {
+ fieldItemIterator,
+ isVCLoaded,
+ setBackgroundColour,
+} from '../common/VCUtils';
+import {ActivityIndicator} from '../../ui/ActivityIndicator';
+
+const getIssuerLogo = (isOpenId4VCI: boolean, issuerLogo: logoType) => {
+ if (isOpenId4VCI) {
+ return (
+
+ );
+ }
+ return SvgImage.MosipLogo(Theme.Styles.vcDetailsLogo);
+};
+
+const getProfileImage = (
+ props: ExistingMosipVCItemDetailsProps | EsignetMosipVCItemDetailsProps,
+ verifiableCredential,
+ isOpenId4VCI,
+) => {
+ if (isOpenId4VCI) {
+ if (verifiableCredential?.credentialSubject.face) {
+ return {uri: verifiableCredential?.credentialSubject.face};
+ }
+ } else {
+ if (props.vc?.credential?.biometrics?.face) {
+ return {uri: props.vc?.credential.biometrics.face};
+ }
+ }
+ return ;
+};
+
+export const VCDetailView: React.FC<
+ ExistingMosipVCItemDetailsProps | EsignetMosipVCItemDetailsProps
+> = props => {
+ const {t, i18n} = useTranslation('VcDetails');
+
+ let isOpenId4VCI = VCMetadata.fromVC(props.vc.vcMetadata).isFromOpenId4VCI();
+ const issuerLogo = getIssuerLogo(
+ isOpenId4VCI,
+ props.vc?.verifiableCredential?.issuerLogo,
+ );
+ const verifiableCredential = isOpenId4VCI
+ ? props.vc?.verifiableCredential.credential
+ : props.vc?.verifiableCredential;
+
+ let [fields, setFields] = useState([]);
+ const [wellknown, setWellknown] = useState(null);
+ useEffect(() => {
+ getCredentialIssuersWellKnownConfig(
+ VCMetadata.fromVC(props.vc.vcMetadata).issuer,
+ props.vc?.verifiableCredential?.wellKnown,
+ DETAIL_VIEW_DEFAULT_FIELDS,
+ ).then(response => {
+ setWellknown(response.wellknown);
+ setFields(response.fields.concat(DETAIL_VIEW_ADD_ON_FIELDS));
+ });
+ }, [props.verifiableCredential?.wellKnown]);
+
+ if (!isVCLoaded(verifiableCredential, fields)) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+
+
+
+ {issuerLogo}
+
+
+ {fieldItemIterator(fields, verifiableCredential, wellknown, props)}
+
+
+
+
+ {props.vc?.reason?.length > 0 && (
+
+ {t('reasonForSharing')}
+
+ )}
+
+ {props.vc?.reason?.map((reason, index) => (
+
+ ))}
+
+ {props.activeTab !== 1 ? (
+ props.isBindingPending ? (
+
+
+
+
+ {t('offlineAuthDisabledHeader')}
+
+
+
+ {t('offlineAuthDisabledMessage')}
+
+
+
+
+ ) : (
+
+
+
+
+
+
+ )
+ ) : (
+ <>>
+ )}
+
+ );
+};
+
+export interface ExistingMosipVCItemDetailsProps {
+ vc: VC;
+ isBindingPending: boolean;
+ onBinding?: () => void;
+ activeTab?: Number;
+}
+
+export interface EsignetMosipVCItemDetailsProps {
+ vc: EsignetVC;
+ isBindingPending: boolean;
+ onBinding?: () => void;
+ activeTab?: number;
+}
+
+export interface EsignetVC {
+ id: string;
+ idType: VcIdType;
+ verifiableCredential: VerifiableCredential;
+ verifiablePresentation?: VerifiablePresentation;
+ generatedOn: Date;
+ requestId: string;
+ isVerified: boolean;
+ lastVerifiedOn: number;
+ locked: boolean;
+ reason?: VCSharingReason[];
+ shouldVerifyPresence?: boolean;
+ walletBindingResponse?: WalletBindingResponse;
+ credentialRegistry: string;
+ isPinned?: boolean;
+ hashedId: string;
+}
diff --git a/components/VC/common/VCCardInnerSkeleton.tsx b/components/VC/common/VCCardInnerSkeleton.tsx
new file mode 100644
index 00000000..a7d470ce
--- /dev/null
+++ b/components/VC/common/VCCardInnerSkeleton.tsx
@@ -0,0 +1,69 @@
+import {Theme} from '../../ui/styleUtils';
+import {Column, Row} from '../../ui';
+import {ImageBackground} from 'react-native';
+import {VCItemField} from './VCItemField';
+import React from 'react';
+import {SvgImage} from '../../ui/svg';
+import LinearGradient from 'react-native-linear-gradient';
+import ShimmerPlaceHolder from 'react-native-shimmer-placeholder';
+
+export const VCCardInnerSkeleton = () => {
+ return (
+
+
+
+
+ {SvgImage.VcItemContainerProfileImage(undefined, null)}
+
+
+ {
+ <>
+
+
+ >
+ }
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/components/VC/common/VCCardSkeleton.tsx b/components/VC/common/VCCardSkeleton.tsx
new file mode 100644
index 00000000..4f16a223
--- /dev/null
+++ b/components/VC/common/VCCardSkeleton.tsx
@@ -0,0 +1,27 @@
+import {View} from 'react-native';
+import {Theme} from '../../ui/styleUtils';
+import {Row} from '../../ui';
+import React from 'react';
+import {VCCardInnerSkeleton} from './VCCardInnerSkeleton';
+import LinearGradient from 'react-native-linear-gradient';
+import ShimmerPlaceHolder from 'react-native-shimmer-placeholder';
+
+export const VCCardSkeleton = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/components/VC/common/VCItemField.tsx b/components/VC/common/VCItemField.tsx
new file mode 100644
index 00000000..096166d7
--- /dev/null
+++ b/components/VC/common/VCItemField.tsx
@@ -0,0 +1,63 @@
+import {Column, Text} from '../../ui';
+import {Theme} from '../../ui/styleUtils';
+import React from 'react';
+import {setTextColor} from './VCUtils';
+import LinearGradient from 'react-native-linear-gradient';
+import ShimmerPlaceHolder from 'react-native-shimmer-placeholder';
+import {Tooltip} from 'react-native-elements';
+
+export const VCItemField = ({
+ verifiableCredential,
+ fieldName,
+ fieldValue,
+ wellknown,
+}) => {
+ if (!verifiableCredential) {
+ return (
+
+
+
+
+ );
+ }
+
+ return (
+
+
+ {fieldName}
+
+ 20}
+ containerStyle={{
+ width: 200,
+ height: null,
+ overflow: 'hidden',
+ }}
+ skipAndroidStatusBar={true}
+ backgroundColor={Theme.Colors.Icon}
+ popover={{fieldValue}}>
+
+ {fieldValue}
+
+
+
+ );
+};
diff --git a/components/VC/common/VCUtils.tsx b/components/VC/common/VCUtils.tsx
new file mode 100644
index 00000000..3a8eda6e
--- /dev/null
+++ b/components/VC/common/VCUtils.tsx
@@ -0,0 +1,159 @@
+import {
+ CredentialSubject,
+ VerifiableCredential,
+} from '../../../types/VC/ExistingMosipVC/vc';
+import VerifiedIcon from '../../VerifiedIcon';
+import i18n, {getLocalizedField} from '../../../i18n';
+import {Row} from '../../ui';
+import {VCItemField} from './VCItemField';
+import React from 'react';
+import {format, parse} from 'date-fns';
+import {logoType} from '../../../machines/issuersMachine';
+import {Image} from 'react-native';
+import {Theme} from '../../ui/styleUtils';
+import {SvgImage} from '../../ui/svg';
+import {CREDENTIAL_REGISTRY_EDIT} from 'react-native-dotenv';
+
+export const getFieldValue = (
+ verifiableCredential: VerifiableCredential,
+ field: string,
+ props: any,
+) => {
+ switch (field) {
+ case 'status':
+ return ;
+ case 'idType':
+ return i18n.t('VcDetails:nationalCard');
+ case 'dateOfBirth':
+ return formattedDateOfBirth(verifiableCredential);
+ case 'credentialRegistry':
+ return props?.vc?.credentialRegistry;
+ case 'address':
+ return getLocalizedField(
+ getFullAddress(verifiableCredential?.credentialSubject),
+ );
+ default:
+ return getLocalizedField(verifiableCredential?.credentialSubject[field]);
+ }
+};
+
+export const getFieldName = (field: string, wellknown: any) => {
+ if (wellknown && wellknown.credentials_supported) {
+ const fieldObj =
+ wellknown.credentials_supported[0].credential_definition
+ .credentialSubject[field];
+ if (fieldObj) {
+ const newFieldObj = fieldObj.display.map(obj => {
+ return {language: obj.locale, value: obj.name};
+ });
+ return getLocalizedField(newFieldObj);
+ }
+ }
+ return i18n.t(`VcDetails:${field}`);
+};
+
+export const setBackgroundColour = (wellknown: any) => {
+ if (wellknown && wellknown.credentials_supported[0]?.display) {
+ return {
+ backgroundColor: wellknown.credentials_supported[0].display[0]
+ ?.background_color
+ ? wellknown.credentials_supported[0].display[0].background_color
+ : Theme.Colors.textValue,
+ };
+ }
+};
+
+export const setTextColor = (wellknown: any) => {
+ if (wellknown && wellknown.credentials_supported[0]?.display) {
+ return {
+ color: wellknown.credentials_supported[0].display[0]?.text_color
+ ? wellknown.credentials_supported[0].display[0].text_color
+ : Theme.Colors.textValue,
+ };
+ }
+};
+
+function getFullAddress(credential: CredentialSubject) {
+ if (!credential) {
+ return '';
+ }
+
+ const fields = [
+ 'addressLine1',
+ 'addressLine2',
+ 'addressLine3',
+ 'city',
+ 'province',
+ 'region',
+ ];
+
+ return fields
+ .map(field => getLocalizedField(credential[field]))
+ .concat(credential.postalCode)
+ .filter(Boolean)
+ .join(', ');
+}
+
+function formattedDateOfBirth(verifiableCredential: any) {
+ const dateOfBirth = verifiableCredential?.credentialSubject.dateOfBirth;
+ if (dateOfBirth) {
+ const formatString =
+ dateOfBirth.split('/').length === 1 ? 'yyyy' : 'yyyy/MM/dd';
+ const parsedDate = parse(dateOfBirth, formatString, new Date());
+ return format(parsedDate, 'MM/dd/yyyy');
+ }
+ return dateOfBirth;
+}
+
+export const fieldItemIterator = (
+ fields: any[],
+ verifiableCredential: any,
+ wellknown: any,
+ props: any,
+) => {
+ return fields.map(field => {
+ const fieldName = getFieldName(field, wellknown);
+ const fieldValue = getFieldValue(verifiableCredential, field, props);
+ if (
+ (field === 'credentialRegistry' &&
+ CREDENTIAL_REGISTRY_EDIT === 'false') ||
+ !fieldValue
+ )
+ return;
+ return (
+
+
+
+ );
+ });
+};
+
+export const isVCLoaded = (verifiableCredential: any, fields: string[]) => {
+ return verifiableCredential != null && fields.length > 0;
+};
+
+export const getIssuerLogo = (isOpenId4VCI: boolean, issuerLogo: logoType) => {
+ if (isOpenId4VCI) {
+ return (
+
+ );
+ }
+ return SvgImage.MosipLogo(Theme.Styles.logo);
+};
diff --git a/components/ui/ActivityIndicator.tsx b/components/ui/ActivityIndicator.tsx
new file mode 100644
index 00000000..055b9780
--- /dev/null
+++ b/components/ui/ActivityIndicator.tsx
@@ -0,0 +1,36 @@
+import {Centered, Column} from './Layout';
+import {View} from 'react-native';
+import {Theme} from './styleUtils';
+import testIDProps from '../../shared/commonUtil';
+import Spinner from 'react-native-spinkit';
+import React from 'react';
+import {SvgImage} from './svg';
+
+export const ActivityIndicator = () => {
+ return (
+
+
+ {SvgImage.ProgressIcon()}
+
+
+
+
+
+ );
+};
diff --git a/components/ui/Text.tsx b/components/ui/Text.tsx
index 03dfcfcf..7d503a84 100644
--- a/components/ui/Text.tsx
+++ b/components/ui/Text.tsx
@@ -1,6 +1,6 @@
import React from 'react';
-import {StyleProp, TextStyle, Text as RNText} from 'react-native';
-import {Theme, Spacing} from './styleUtils';
+import {StyleProp, Text as RNText, TextStyle} from 'react-native';
+import {Spacing, Theme} from './styleUtils';
import testIDProps from '../../shared/commonUtil';
export const Text: React.FC = (props: TextProps) => {
@@ -21,6 +21,7 @@ export const Text: React.FC = (props: TextProps) => {
{...testIDProps(props.testID)}
style={textStyles}
numberOfLines={props.numLines}
+ ellipsizeMode={props.ellipsizeMode}
accessible={props.accessible}>
{props.children}
@@ -37,6 +38,7 @@ interface TextProps {
size?: 'small' | 'extraSmall' | 'smaller' | 'regular' | 'large';
lineHeight?: number;
numLines?: number;
+ ellipsizeMode?: 'head' | 'middle' | 'tail' | 'clip' | undefined;
style?: StyleProp;
accessible?: boolean | true;
}
diff --git a/components/ui/themes/DefaultTheme.ts b/components/ui/themes/DefaultTheme.ts
index d91a04cb..32f476f9 100644
--- a/components/ui/themes/DefaultTheme.ts
+++ b/components/ui/themes/DefaultTheme.ts
@@ -338,6 +338,7 @@ export const DefaultTheme = {
flex: 1,
padding: 10,
overflow: 'hidden',
+ borderRadius: 10,
},
successTag: {
backgroundColor: Colors.Green,
@@ -372,8 +373,8 @@ export const DefaultTheme = {
height: 60,
},
vcDetailsLogo: {
- height: 35,
- width: 90,
+ height: 50,
+ width: 50,
},
homeCloseCardDetailsHeader: {
flex: 1,
@@ -756,6 +757,7 @@ export const DefaultTheme = {
color: 'transparent',
backgroundColor: Colors.Grey5,
borderRadius: 4,
+ marginBottom: 2,
},
subtitle: {
backgroundColor: 'transparent',
diff --git a/components/ui/themes/PurpleTheme.ts b/components/ui/themes/PurpleTheme.ts
index 020394e5..9448cda7 100644
--- a/components/ui/themes/PurpleTheme.ts
+++ b/components/ui/themes/PurpleTheme.ts
@@ -342,6 +342,7 @@ export const PurpleTheme = {
flex: 1,
padding: 10,
overflow: 'hidden',
+ borderRadius: 10,
},
successTag: {
backgroundColor: Colors.Green,
@@ -376,8 +377,8 @@ export const PurpleTheme = {
height: 60,
},
vcDetailsLogo: {
- width: 90,
- height: 35,
+ width: 50,
+ height: 50,
},
homeCloseCardDetailsHeader: {
flex: 1,
@@ -759,6 +760,7 @@ export const PurpleTheme = {
color: 'transparent',
backgroundColor: Colors.Grey5,
borderRadius: 4,
+ marginBottom: 2,
},
subtitle: {
backgroundColor: 'transparent',
diff --git a/machines/issuersMachine.ts b/machines/issuersMachine.ts
index b0e79e6d..1490182e 100644
--- a/machines/issuersMachine.ts
+++ b/machines/issuersMachine.ts
@@ -576,7 +576,16 @@ export const IssuersMachine = model.createMachine(
},
checkInternet: async () => await NetInfo.fetch(),
downloadIssuerConfig: async (context, _) => {
- return await CACHED_API.fetchIssuerConfig(context.selectedIssuerId);
+ let issuersConfig = await CACHED_API.fetchIssuerConfig(
+ context.selectedIssuerId,
+ );
+ if (context.selectedIssuer['.well-known']) {
+ await CACHED_API.fetchIssuerWellknownConfig(
+ context.selectedIssuerId,
+ context.selectedIssuer['.well-known'],
+ );
+ }
+ return issuersConfig;
},
downloadCredential: async context => {
const body = await getBody(context);
diff --git a/package-lock.json b/package-lock.json
index 3fd8087a..b1090798 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -75,6 +75,7 @@
"react-native-screens": "~3.20.0",
"react-native-secure-key-store": "^2.0.10",
"react-native-securerandom": "^1.0.1",
+ "react-native-shimmer-placeholder": "^2.0.9",
"react-native-spinkit": "^1.5.1",
"react-native-svg": "13.4.0",
"react-native-vector-icons": "^10.0.0",
@@ -8664,21 +8665,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@svgr/core/node_modules/typescript": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
- "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
- "dev": true,
- "optional": true,
- "peer": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
"node_modules/@svgr/hast-util-to-babel-ast": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz",
@@ -8783,21 +8769,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/@svgr/plugin-svgo/node_modules/typescript": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
- "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
- "dev": true,
- "optional": true,
- "peer": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@@ -12529,29 +12500,6 @@
"node": ">= 0.8"
}
},
- "node_modules/encoding": {
- "version": "0.1.13",
- "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
- "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
- "optional": true,
- "peer": true,
- "dependencies": {
- "iconv-lite": "^0.6.2"
- }
- },
- "node_modules/encoding/node_modules/iconv-lite": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
- "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "optional": true,
- "peer": true,
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@@ -13856,7 +13804,6 @@
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.5.1.tgz",
"integrity": "sha512-yt5a1VCp2BF9CrsO689PCD5oXKP14MMhnOanQMvDn4BDpURYfzAlDVGC5fZrNQKtwn/eq3bcrxIwZ7D9QjVVRg==",
- "peer": true,
"dependencies": {
"@expo/config": "~8.1.0",
"chalk": "^4.1.0",
@@ -13873,7 +13820,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "peer": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -13888,7 +13834,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "peer": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -13904,7 +13849,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "peer": true,
"dependencies": {
"color-name": "~1.1.4"
},
@@ -13921,7 +13865,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
- "peer": true,
"engines": {
"node": ">= 10"
}
@@ -13930,7 +13873,6 @@
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
- "peer": true,
"dependencies": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
@@ -13945,7 +13887,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "peer": true,
"engines": {
"node": ">=8"
}
@@ -13954,7 +13895,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "peer": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -13966,7 +13906,6 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
- "peer": true,
"engines": {
"node": ">= 10.0.0"
}
@@ -24738,9 +24677,9 @@
"integrity": "sha512-c7Cs+YQN26UaQsRG1dmlXL7VL2ctnXwH/dl0IOMEQ7ZaL2NdN313YSAI8ZEZZjrVhNmPsyWEuvTFqWrdpItqQg=="
},
"node_modules/react-native-linear-gradient": {
- "version": "2.8.2",
- "resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.2.tgz",
- "integrity": "sha512-hgmCsgzd58WNcDCyPtKrvxsaoETjb/jLGxis/dmU3Aqm2u4ICIduj4ECjbil7B7pm9OnuTkmpwXu08XV2mpg8g==",
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz",
+ "integrity": "sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA==",
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -24898,6 +24837,15 @@
"react-native": "*"
}
},
+ "node_modules/react-native-shimmer-placeholder": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/react-native-shimmer-placeholder/-/react-native-shimmer-placeholder-2.0.9.tgz",
+ "integrity": "sha512-s2pfAAO6uaybREYM2KcaxP3c2XlZvLfHfzmhMlGEoOhSKaoM92KpA1Hx0BeC75yilkliJuowqO/hFzvLB0h7hg==",
+ "peerDependencies": {
+ "prop-types": ">=15.6.0",
+ "react-native-linear-gradient": ">=2.4.0"
+ }
+ },
"node_modules/react-native-size-matters": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.3.1.tgz",
@@ -35406,14 +35354,6 @@
"json-parse-even-better-errors": "^2.3.0",
"lines-and-columns": "^1.1.6"
}
- },
- "typescript": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
- "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
- "dev": true,
- "optional": true,
- "peer": true
}
}
},
@@ -35473,14 +35413,6 @@
"json-parse-even-better-errors": "^2.3.0",
"lines-and-columns": "^1.1.6"
}
- },
- "typescript": {
- "version": "5.2.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
- "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
- "dev": true,
- "optional": true,
- "peer": true
}
}
},
@@ -38349,28 +38281,6 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
- "encoding": {
- "version": "0.1.13",
- "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
- "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
- "optional": true,
- "peer": true,
- "requires": {
- "iconv-lite": "^0.6.2"
- },
- "dependencies": {
- "iconv-lite": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
- "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "optional": true,
- "peer": true,
- "requires": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- }
- }
- }
- },
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
@@ -39390,7 +39300,6 @@
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/expo-modules-autolinking/-/expo-modules-autolinking-1.5.1.tgz",
"integrity": "sha512-yt5a1VCp2BF9CrsO689PCD5oXKP14MMhnOanQMvDn4BDpURYfzAlDVGC5fZrNQKtwn/eq3bcrxIwZ7D9QjVVRg==",
- "peer": true,
"requires": {
"@expo/config": "~8.1.0",
"chalk": "^4.1.0",
@@ -39404,7 +39313,6 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "peer": true,
"requires": {
"color-convert": "^2.0.1"
}
@@ -39413,7 +39321,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "peer": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -39423,7 +39330,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "peer": true,
"requires": {
"color-name": "~1.1.4"
}
@@ -39442,7 +39348,6 @@
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
- "peer": true,
"requires": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
@@ -39459,7 +39364,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "peer": true,
"requires": {
"has-flag": "^4.0.0"
}
@@ -47566,9 +47470,9 @@
"integrity": "sha512-c7Cs+YQN26UaQsRG1dmlXL7VL2ctnXwH/dl0IOMEQ7ZaL2NdN313YSAI8ZEZZjrVhNmPsyWEuvTFqWrdpItqQg=="
},
"react-native-linear-gradient": {
- "version": "2.8.2",
- "resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.2.tgz",
- "integrity": "sha512-hgmCsgzd58WNcDCyPtKrvxsaoETjb/jLGxis/dmU3Aqm2u4ICIduj4ECjbil7B7pm9OnuTkmpwXu08XV2mpg8g==",
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.3.tgz",
+ "integrity": "sha512-KflAXZcEg54PXkLyflaSZQ3PJp4uC4whM7nT/Uot9m0e/qxFV3p6uor1983D1YOBJbJN7rrWdqIjq0T42jOJyA==",
"requires": {}
},
"react-native-localize": {
@@ -47670,6 +47574,12 @@
"base64-js": "*"
}
},
+ "react-native-shimmer-placeholder": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/react-native-shimmer-placeholder/-/react-native-shimmer-placeholder-2.0.9.tgz",
+ "integrity": "sha512-s2pfAAO6uaybREYM2KcaxP3c2XlZvLfHfzmhMlGEoOhSKaoM92KpA1Hx0BeC75yilkliJuowqO/hFzvLB0h7hg==",
+ "requires": {}
+ },
"react-native-size-matters": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.3.1.tgz",
diff --git a/package.json b/package.json
index e300b9f1..b4b66db1 100644
--- a/package.json
+++ b/package.json
@@ -78,6 +78,7 @@
"react-native-screens": "~3.20.0",
"react-native-secure-key-store": "^2.0.10",
"react-native-securerandom": "^1.0.1",
+ "react-native-shimmer-placeholder": "^2.0.9",
"react-native-spinkit": "^1.5.1",
"react-native-svg": "13.4.0",
"react-native-vector-icons": "^10.0.0",
diff --git a/shared/api.ts b/shared/api.ts
index ffddfa28..83594c71 100644
--- a/shared/api.ts
+++ b/shared/api.ts
@@ -15,6 +15,10 @@ export const API_URLS: ApiUrls = {
buildURL: (issuerId: string): `/${string}` =>
`/residentmobileapp/issuers/${issuerId}`,
},
+ issuerWellknownConfig: {
+ method: 'GET',
+ buildURL: (requestUrl: `/${string}`): `/${string}` => requestUrl,
+ },
allProperties: {
method: 'GET',
buildURL: (): `/${string}` => '/residentmobileapp/allProperties',
@@ -96,7 +100,13 @@ export const API = {
);
return response.response;
},
-
+ fetchIssuerWellknownConfig: async (requestUrl: string) => {
+ const response = await request(
+ API_URLS.issuerWellknownConfig.method,
+ API_URLS.issuerWellknownConfig.buildURL(requestUrl),
+ );
+ return response;
+ },
fetchAllProperties: async () => {
const response = await request(
API_URLS.allProperties.method,
@@ -118,6 +128,11 @@ export const CACHED_API = {
cacheKey: API_CACHED_STORAGE_KEYS.fetchIssuerConfig(issuerId),
fetchCall: API.fetchIssuerConfig.bind(null, issuerId),
}),
+ fetchIssuerWellknownConfig: (issuerId: string, requestUrl: string) =>
+ generateCacheAPIFunction({
+ cacheKey: API_CACHED_STORAGE_KEYS.fetchIssuerWellknownConfig(issuerId),
+ fetchCall: API.fetchIssuerWellknownConfig.bind(null, requestUrl),
+ }),
getAllProperties: (isCachePreferred: boolean) =>
generateCacheAPIFunction({
@@ -246,6 +261,7 @@ type Api_Params = {
type ApiUrls = {
issuersList: Api_Params;
issuerConfig: Api_Params;
+ issuerWellknownConfig: Api_Params;
allProperties: Api_Params;
getIndividualId: Api_Params;
reqIndividualOTP: Api_Params;
diff --git a/shared/constants.ts b/shared/constants.ts
index 1ad3155e..03343613 100644
--- a/shared/constants.ts
+++ b/shared/constants.ts
@@ -1,5 +1,5 @@
import {Platform} from 'react-native';
-import {MIMOTO_HOST, ESIGNET_HOST, DEBUG_MODE} from 'react-native-dotenv';
+import {DEBUG_MODE, ESIGNET_HOST, MIMOTO_HOST} from 'react-native-dotenv';
import {Argon2iConfig} from './commonUtil';
import {VcIdType} from '../types/VC/ExistingMosipVC/vc';
@@ -31,9 +31,9 @@ export const APP_ID_LENGTH = 12;
// Numbers and Upper case Alphabets without confusing characters like 0, 1, 2, I, O, Z
// prettier-ignore
export const APP_ID_DICTIONARY = [
- '3', '4', '5', '6', '7', '8', '9',
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L',
- 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
+ '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L',
+ 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y',
];
export function isIOS(): boolean {
@@ -74,3 +74,23 @@ export type IndividualId = {
export const NETWORK_REQUEST_FAILED = 'Network request failed';
export const REQUEST_TIMEOUT = 'request timedout';
export const BIOMETRIC_CANCELLED = 'User has cancelled biometric';
+
+export const CARD_VIEW_DEFAULT_FIELDS = ['fullName'];
+
+export const DETAIL_VIEW_DEFAULT_FIELDS = [
+ 'fullName',
+ 'gender',
+ 'phone',
+ 'dateOfBirth',
+ 'email',
+ 'address',
+];
+
+//todo UIN & VID to be removed once we get the fields in the wellknown endpoint
+export const CARD_VIEW_ADD_ON_FIELDS = ['idType', 'UIN', 'VID'];
+export const DETAIL_VIEW_ADD_ON_FIELDS = [
+ 'UIN',
+ 'VID',
+ 'status',
+ 'credentialRegistry',
+];
diff --git a/shared/openId4VCI/Utils.ts b/shared/openId4VCI/Utils.ts
index d24ec7a3..3440a1c2 100644
--- a/shared/openId4VCI/Utils.ts
+++ b/shared/openId4VCI/Utils.ts
@@ -8,6 +8,7 @@ import {CredentialWrapper} from '../../types/VC/EsignetMosipVC/vc';
import {VCMetadata} from '../VCMetadata';
import i18next from 'i18next';
import {getJWT} from '../cryptoutil/cryptoUtil';
+import {CACHED_API} from '../api';
export const Protocols = {
OpenId4VCI: 'OpenId4VCI',
@@ -66,6 +67,10 @@ export const updateCredentialInformation = (context, credential) => {
credentialWrapper.verifiableCredential = credential;
credentialWrapper.identifier = getIdentifier(context, credential);
credentialWrapper.generatedOn = new Date();
+ credentialWrapper.verifiableCredential.wellKnown =
+ context.selectedIssuer['.well-known'];
+ // credentialWrapper.verifiableCredential.wellKnown =
+ // 'https://esignet.collab.mosip.net/.well-known/openid-credential-issuer';
credentialWrapper.verifiableCredential.issuerLogo =
getDisplayObjectForCurrentLanguage(context.selectedIssuer.display)?.logo;
return credentialWrapper;
@@ -136,6 +141,28 @@ export const getJWK = async publicKey => {
}
};
+export const getCredentialIssuersWellKnownConfig = async (
+ issuer: string,
+ wellknown: string,
+ defaultFields: string[],
+) => {
+ let fields: string[] = defaultFields;
+ let response = null;
+ if (wellknown) {
+ response = await CACHED_API.fetchIssuerWellknownConfig(issuer, wellknown);
+ fields = !response
+ ? []
+ : Object.keys(
+ response?.credentials_supported[0].credential_definition
+ .credentialSubject,
+ );
+ }
+ return {
+ wellknown: response,
+ fields: fields,
+ };
+};
+
export const vcDownloadTimeout = async (): Promise => {
const response = await getAllConfigurations();
@@ -150,6 +177,7 @@ export enum OIDCErrors {
INVALID_TOKEN_SPECIFIED = 'Invalid token specified',
OIDC_CONFIG_ERROR_PREFIX = 'Config error',
}
+
// ErrorMessage is the type of error message shown in the UI
export enum ErrorMessage {
NO_INTERNET = 'noInternetConnection',
diff --git a/shared/request.ts b/shared/request.ts
index 958ac52d..2720caf9 100644
--- a/shared/request.ts
+++ b/shared/request.ts
@@ -27,20 +27,21 @@ export async function request(
if (path.includes('residentmobileapp'))
headers['X-AppId'] = __AppId.getValue();
let response;
+ const requestUrl = path.indexOf('https://') != -1 ? path : host + path;
if (timeoutMillis === undefined) {
- response = await fetch(host + path, {
+ response = await fetch(requestUrl, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
});
} else {
- console.log(`making a web request to ${host + path}`);
+ console.log(`making a web request to ${requestUrl}`);
let controller = new AbortController();
setTimeout(() => {
controller.abort();
}, timeoutMillis);
try {
- response = await fetch(host + path, {
+ response = await fetch(requestUrl, {
method,
headers,
body: body ? JSON.stringify(body) : undefined,
diff --git a/shared/storage.ts b/shared/storage.ts
index fae050ae..fd4e81b9 100644
--- a/shared/storage.ts
+++ b/shared/storage.ts
@@ -42,6 +42,8 @@ export const API_CACHED_STORAGE_KEYS = {
fetchIssuers: 'CACHE_FETCH_ISSUERS',
fetchIssuerConfig: (issuerId: string) =>
`CACHE_FETCH_ISSUER_CONFIG_${issuerId}`,
+ fetchIssuerWellknownConfig: (issuerId: string) =>
+ `CACHE_FETCH_ISSUER_WELLKNOWN_CONFIG_${issuerId}`,
};
async function generateHmac(
diff --git a/types/VC/EsignetMosipVC/vc.ts b/types/VC/EsignetMosipVC/vc.ts
index 61b91935..de2e6d61 100644
--- a/types/VC/EsignetMosipVC/vc.ts
+++ b/types/VC/EsignetMosipVC/vc.ts
@@ -72,6 +72,7 @@ export interface VerifiableCredential {
issuerLogo: logoType;
format: string;
credential: Credential;
+ wellKnown: string;
}
export interface CredentialWrapper {