[INJIMOB-3193]add preauth and credential offer support (#1949)

[INJIMOB-3058]temp commit2



[INJIMOB-3058]temp commit2



[INJIMOB-3058] add support for pre-auth flow by credential-offer



[INJIMOB-3187] animo working chcekpoint

Signed-off-by: Abhishek Paul <paul.apaul.abhishek.ap@gmail.com>
This commit is contained in:
abhip2565
2025-06-04 14:46:07 +05:30
committed by GitHub
parent ddf5244f32
commit bd90b342e0
63 changed files with 3510 additions and 2063 deletions

View File

@@ -11,13 +11,17 @@ export const PinInput: React.FC<PinInputProps> = props => {
const [focusedIndex, setFocusedIndex] = useState(0);
useEffect(() => {
if (props.onDone && values.filter(Boolean).length === inputRefs.length) {
props.onDone(values.join(''));
const current = values.join('');
props.onChange?.(current);
if (props.autosubmit && props.onDone && values.filter(Boolean).length === inputRefs.length) {
props.onDone(current);
}
}, [state]);
}, [values]);
return (
<Row width="100%" testID={props.testID} removeClippedSubviews={true}>
<Row width={`${(100 / 6) * props.length}%`} testID={props.testID} removeClippedSubviews={true}>
{inputRefs.map((input, index) => (
<TextInput
contextMenuHidden={true}
@@ -53,4 +57,6 @@ interface PinInputProps {
testID?: string;
length: number;
onDone?: (value: string) => void;
onChange?: (value: string) => void;
autosubmit?: boolean;
}

View File

@@ -69,7 +69,7 @@ export const VCCardView: React.FC<VCItemProps> = ({
credentialConfigurationId,
vcMetadata: { format },
} = verifiableCredentialData;
if (vcMetadata.issuerHost) {
if (vcMetadata) {
getCredentialIssuersWellKnownConfig(
issuer,
CARD_VIEW_DEFAULT_FIELDS,

View File

@@ -50,7 +50,7 @@ export const VCDetailView: React.FC<VCItemDetailsProps> = (
} else if (
props.verifiableCredentialData.vcMetadata.format === VCFormat.mso_mdoc
) {
const namespaces = verifiableCredential['issuerSigned']['nameSpaces'];
const namespaces = verifiableCredential['issuerSigned']?.['nameSpaces'] ?? verifiableCredential['nameSpaces']??{};
Object.keys(namespaces).forEach(namespace => {
(namespaces[namespace] as Array<Object>).forEach(element => {
availableFieldNames.push(
@@ -119,7 +119,8 @@ export const VCDetailView: React.FC<VCItemDetailsProps> = (
margin={'0 0 0 24'}
style={{flex: 1}}>
{fieldItemIterator(
props.fields,
props.fields,
props.wellknownFieldsFlag,
verifiableCredential,
props.wellknown,
wellknownDisplayProperty,
@@ -141,6 +142,7 @@ export const VCDetailView: React.FC<VCItemDetailsProps> = (
{shouldShowHrLine(verifiableCredential) &&
fieldItemIterator(
DETAIL_VIEW_BOTTOM_SECTION_FIELDS,
props.wellknownFieldsFlag,
verifiableCredential,
props.wellknown,
wellknownDisplayProperty,
@@ -240,6 +242,7 @@ export const VCDetailView: React.FC<VCItemDetailsProps> = (
export interface VCItemDetailsProps {
fields: any[];
wellknown: any;
wellknownFieldsFlag: boolean;
credential: VerifiableCredential | Credential;
verifiableCredentialData: VerifiableCredentialData;
walletBindingResponse?: WalletBindingResponse;

View File

@@ -154,7 +154,7 @@ export const getFieldName = (
}
}
}
return i18n.t(`VcDetails:${field}`);
return field;
};
export function getAddressFields() {
@@ -181,17 +181,72 @@ function getFullAddress(credential: CredentialSubject) {
.filter(Boolean)
.join(', ');
}
const renderFieldRecursively = (
key: string,
value: any,
fieldNameColor: string,
fieldValueColor: string,
parentKey = '',
depth = 0
): JSX.Element[] => {
const fullKey = parentKey ? `${parentKey}.${key}` : key;
if (value === null || value === undefined) return [];
if (Array.isArray(value)) {
return value.flatMap((item, index) =>
renderFieldRecursively(`${key}[${index}]`, item, fieldNameColor,fieldValueColor,parentKey, depth + 1)
);
} else if (typeof value === 'object') {
return Object.entries(value).flatMap(([childKey, childValue]) =>
renderFieldRecursively(childKey, childValue, fieldNameColor,fieldValueColor,fullKey, depth + 1)
);
} else {
let displayValue = String(value);
// Truncate base64 if it's an image data URI or very long string
if (displayValue.startsWith('data:image') || displayValue.length > 100) {
displayValue = displayValue.slice(0, 60) + '...';
}
return [
<Row
key={`extra-${fullKey}`}
style={{
flexDirection: 'row',
flex: 1,
paddingLeft: depth * 12, // Indent nested levels
}}
align="space-between"
margin="0 8 15 0"
>
<VCItemField
key={`extra-${fullKey}`}
fieldName={fullKey}
fieldValue={displayValue}
fieldNameColor={fieldNameColor}
fieldValueColor={fieldValueColor}
testID={`extra-${fullKey}`}
/>
</Row>,
];
}
};
export const fieldItemIterator = (
fields: any[],
wellknownFieldsFlag: boolean,
verifiableCredential: VerifiableCredential | Credential,
wellknown: any,
display: Display,
props: VCItemDetailsProps,
) => {
): JSX.Element[] => {
const fieldNameColor = display.getTextColor(Theme.Colors.DetailsLabel);
const fieldValueColor = display.getTextColor(Theme.Colors.Details);
return fields.map(field => {
const renderedFields = new Set<string>();
const renderedMainFields = fields.map(field => {
const fieldName = getFieldName(
field,
wellknown,
@@ -205,16 +260,20 @@ export const fieldItemIterator = (
display,
props.verifiableCredentialData.vcMetadata.format,
);
renderedFields.add(field);
if (
(field === 'credentialRegistry' &&
CREDENTIAL_REGISTRY_EDIT === 'false') ||
!fieldValue
)
return;
) {
return null;
}
return (
<Row
key={field}
style={{flexDirection: 'row', flex: 1}}
style={{ flexDirection: 'row', flex: 1 }}
align="space-between"
margin="0 8 15 0">
<VCItemField
@@ -228,13 +287,83 @@ export const fieldItemIterator = (
</Row>
);
});
let renderedExtraFields: JSX.Element[] = [];
if (!wellknownFieldsFlag) {
const renderedAll: JSX.Element[] = [];
// Extra fields from credentialSubject
const credentialSubjectFields =
(verifiableCredential.credentialSubject as Record<string, any>) || {};
const renderedSubjectFields = Object.entries(credentialSubjectFields)
.filter(([key]) => !renderedFields.has(key))
.flatMap(([key, value]) =>
renderFieldRecursively(key, value, fieldNameColor, fieldValueColor)
);
renderedAll.push(...renderedSubjectFields);
// Render fields from nameSpaces (mso_mdoc)
const nameSpaces: Record<string, any> =
verifiableCredential.nameSpaces ??
verifiableCredential.issuerSigned?.nameSpaces ??
verifiableCredential.issuerAuth?.nameSpaces ??
{};
const renderedNamespaceFields = Object.entries(nameSpaces).flatMap(
([namespace, entries]) => {
if (!Array.isArray(entries)) return [];
return [
<VCItemField
key={`ns-title-${namespace}`}
fieldName={(namespace)}
fieldValue=""
fieldNameColor={fieldNameColor}
fieldValueColor={fieldValueColor}
testID={`ns-title-${namespace}`}
/>,
...entries.flatMap((entry, index) => [
<VCItemField
key={`entry-heading-${namespace}-${index}`}
fieldName={"--"}
fieldValue=""
fieldNameColor={fieldNameColor}
fieldValueColor={fieldValueColor}
testID={`entry-heading-${namespace}-${index}`}
/>,
...Object.entries(entry).flatMap(([key, value]) =>
renderFieldRecursively(
key,
value,
fieldNameColor,
fieldValueColor,
`${namespace}[${index}]`,
1
)
),
]),
];
}
);
renderedAll.push(...renderedNamespaceFields);
renderedExtraFields = renderedAll;
}
return [...renderedMainFields, ...renderedExtraFields];
};
export const isVCLoaded = (
verifiableCredential: Credential | null,
fields: string[],
) => {
return verifiableCredential != null && fields.length > 0;
return verifiableCredential != null
};
export const getMosipLogo = () => {
@@ -365,4 +494,4 @@ const ProtectedCurve = {
const PROOF_TYPE_ALGORITHM_MAP = {
[-7]: 'ES256',
};
};

View File

@@ -1,36 +1,39 @@
import React from 'react';
import {Pressable, View} from 'react-native';
import {Theme} from '../ui/styleUtils';
import { Pressable, View } from 'react-native';
import { Theme } from '../ui/styleUtils';
import testIDProps from '../../shared/commonUtil';
import {Text} from '../ui';
import {displayType} from '../../machines/Issuers/IssuersMachine';
import {SvgImage} from '../ui/svg';
import { Text } from '../ui';
import { displayType } from '../../machines/Issuers/IssuersMachine';
import { SvgImage } from '../ui/svg';
export const Issuer: React.FC<IssuerProps> = (props: IssuerProps) => {
return (
<Pressable
accessible={false}
{...testIDProps(`issuer-${props.testID}`)}
onPress={props.onPress}
style={({pressed}) =>
style={({ pressed }) =>
pressed
? [
Theme.IssuersScreenStyles.issuerBoxContainerPressed,
Theme.Styles.boxShadow,
]
Theme.IssuersScreenStyles.issuerBoxContainerPressed,
Theme.Styles.boxShadow,
]
: [
Theme.IssuersScreenStyles.issuerBoxContainer,
Theme.Styles.boxShadow,
]
Theme.IssuersScreenStyles.issuerBoxContainer,
Theme.Styles.boxShadow,
]
}>
<View style={Theme.IssuersScreenStyles.issuerBoxIconContainer}>
{SvgImage.IssuerIcon(props)}
{props.displayDetails.logo
? SvgImage.IssuerIcon(props)
: SvgImage.defaultIssuerLogo(props.defaultLogo)}
</View>
<View style={Theme.IssuersScreenStyles.issuerBoxContent}>
<Text
testID={`issuerHeading-${props.testID}`}
style={Theme.IssuersScreenStyles.issuerHeading}>
{props.displayDetails.title}
{props.displayDetails.title ?? props.displayDetails.name}
</Text>
<Text
testID={`issuerDescription-${props.testID}`}
@@ -46,4 +49,5 @@ export interface IssuerProps {
displayDetails: displayType;
onPress: () => void;
testID: string;
defaultLogo?: any;
}

View File

@@ -21,10 +21,12 @@ export const Text: React.FC<TextProps> = (props: TextProps) => {
{...testIDProps(props.testID)}
style={textStyles}
numberOfLines={props.numLines}
onTextLayout={props.onTextLayout}
ellipsizeMode={props.ellipsizeMode}
accessible={props.accessible}
onPress={props.onPress}>
{props.children}
</RNText>
);
};
@@ -43,4 +45,5 @@ interface TextProps {
style?: StyleProp<TextStyle>;
accessible?: boolean | true;
onPress?: () => void;
onTextLayout?: (e: any) => void;
}

View File

@@ -98,6 +98,11 @@ export class SvgImage {
);
}
static defaultIssuerLogo(defaultLogo: any) {
const DefaultLogo=defaultLogo
return <DefaultLogo/>
}
static starIcon() {
return (
<StarIcon
@@ -593,7 +598,7 @@ export class SvgImage {
}
function getIssuerLogo(props: displayType) {
return {uri: props.logo.url};
return {uri: props.logo.url || props.logo.uri};
}
interface LogoProps {

View File

@@ -864,7 +864,7 @@ export const DefaultTheme = {
flex: 1,
fontSize: 33,
fontFamily: 'Inter_600SemiBold',
height: 40,
height: 50,
lineHeight: 28,
margin: 8,
textAlign: 'center',
@@ -876,7 +876,7 @@ export const DefaultTheme = {
flex: 1,
fontFamily: 'Inter_700Bold',
fontSize: 29,
height: 40,
height: 50,
margin: 8,
textAlign: 'center',
},
@@ -1940,6 +1940,120 @@ export const DefaultTheme = {
},
}),
TransactionCodeScreenStyle: StyleSheet.create({
showMoreButton: {
alignItems: 'flex-end',
marginTop: 6,
marginBottom: 10,
marginRight: -Dimensions.get('window').width + 150,
fontSize: 12,
fontWeight: '600',
color: Colors.Grey,
},
errorView: {
backgroundColor: '#FAEFEF',
padding: 8,
borderRadius: 10,
marginBottom: 10,
marginTop: 10,
width: '80%',
},
inputStyle: {
fontSize: 20,
fontWeight: '500',
textAlign: 'center',
},
confirmationModalView: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.4)',
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 40,
},
confirmationModalContentHeading: {
fontSize: 18,
fontWeight: '600',
textAlign: 'center',
marginBottom: 5,
},
confirmationModalContentSubHeading: {
fontSize: 14,
color: '#888',
marginTop: 12,
textAlign: 'center',
lineHeight: 20,
marginBottom: 20,
},
confirmationModalInnerView: {
backgroundColor: 'white',
borderRadius: 20,
paddingVertical: 35,
paddingHorizontal: 24,
alignItems: 'center',
},
}),
TrustIssuerScreenStyle: StyleSheet.create({
modalOverlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
modalContainer: {
backgroundColor: '#fff',
borderRadius: 20,
width: '100%',
padding: 20,
alignItems: 'center',
},
issuerHeader: {
padding: 10,
alignItems: 'center',
marginBottom: 16,
},
issuerLogo: {
width: 60,
height: 60,
resizeMode: 'contain',
},
issuerName: {
marginTop: 8,
fontWeight: 'bold',
fontSize: 16,
},
description: {
fontSize: 14,
color: '#666',
textAlign: 'center',
lineHeight: 20,
marginBottom: 24,
},
}),
AuthWebViewScreenStyle: StyleSheet.create({
header: {
height: 56,
paddingHorizontal: 16,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: '#F5F5F5',
borderBottomWidth: 1,
borderColor: '#E0E0E0',
},
headerText: {
fontSize: 18,
fontWeight: '500',
},
loader: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
}),
ICON_SMALL_SIZE: 16,
ICON_MID_SIZE: 22,
ICON_LARGE_SIZE: 33,

View File

@@ -1943,6 +1943,118 @@ export const PurpleTheme = {
paddingTop: 10,
},
}),
TransactionCodeScreenStyle: StyleSheet.create({
showMoreButton: {
alignItems: 'flex-end',
marginTop: 6,
marginBottom: 10,
marginRight: -Dimensions.get('window').width + 150,
fontSize: 12,
fontWeight: '600',
color: Colors.Grey,
},
errorView: {
backgroundColor: '#FAEFEF',
padding: 8,
borderRadius: 10,
marginBottom: 10,
marginTop: 10,
width: '80%',
},
inputStyle: {
fontSize: 20,
fontWeight: '500',
textAlign: 'center',
},
confirmationModalView: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.4)',
justifyContent: 'center',
alignItems: 'center',
paddingHorizontal: 40,
},
confirmationModalContentHeading: {
fontSize: 18,
fontWeight: '600',
textAlign: 'center',
marginBottom: 5,
},
confirmationModalContentSubHeading: {
fontSize: 14,
color: '#888',
marginTop: 12,
textAlign: 'center',
lineHeight: 20,
marginBottom: 20,
},
confirmationModalInnerView: {
backgroundColor: 'white',
borderRadius: 20,
paddingVertical: 35,
paddingHorizontal: 24,
alignItems: 'center',
},
}),
TrustIssuerScreenStyle: StyleSheet.create({
modalOverlay: {
flex: 1,
backgroundColor: 'rgba(0, 0, 0, 0.5)',
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
modalContainer: {
backgroundColor: '#fff',
borderRadius: 20,
width: '100%',
padding: 20,
alignItems: 'center',
},
issuerHeader: {
padding: 10,
alignItems: 'center',
marginBottom: 16,
},
issuerLogo: {
width: 60,
height: 60,
resizeMode: 'contain',
},
issuerName: {
marginTop: 8,
fontWeight: 'bold',
fontSize: 16,
},
description: {
fontSize: 14,
color: '#666',
textAlign: 'center',
lineHeight: 20,
marginBottom: 24,
},
}),
AuthWebViewScreenStyle: StyleSheet.create({
header: {
height: 56,
paddingHorizontal: 16,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: '#F5F5F5',
borderBottomWidth: 1,
borderColor: '#E0E0E0',
},
headerText: {
fontSize: 18,
fontWeight: '500',
},
loader: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
}),
ICON_SMALL_SIZE: 16,
ICON_MID_SIZE: 22,