Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion libs/it-wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
"zod": "catalog:",
"@pagopa/io-react-native-crypto": "^1.2.3",
"@pagopa/io-react-native-jwt": "2.1.0",
"@types/color": "^4.2.0"
"@types/color": "^4.2.0",
"react-native-barcode-builder": "^2.0.0",
"react-native-svg": "catalog:"
},
"peerDependencies": {
"react": "^19.1.0",
Expand Down
Binary file added libs/it-wallet/src/assets/img/cards/bonus.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added libs/it-wallet/src/assets/img/cards/bonus@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added libs/it-wallet/src/assets/img/cards/bonus@3x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this asset used anywhere in the app? If not, could you please remove it?

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 29 additions & 0 deletions libs/it-wallet/src/lib/components/ItwBarcodeCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { H4, IOColors, VSpacer } from '@pagopa/io-app-design-system';
import { StyleSheet, View } from 'react-native';
import Barcode from 'react-native-barcode-builder';

type ItwBarcodeCardProps = {
value: string;
};

export const ItwBarcodeCard = ({ value }: ItwBarcodeCardProps) => (
<View style={styles.container}>
<VSpacer size={4} />
<Barcode format="CODE128" value={value} height={70} width={1.15} />
<VSpacer size={4} />
<H4 textStyle={StyleSheet.flatten([styles.label])}>{value}</H4>
</View>
);

const styles = StyleSheet.create({
container: {
borderColor: IOColors['grey-100'],
borderWidth: 1,
padding: 5,
borderRadius: 8
},
label: {
alignSelf: 'center',
textAlign: 'center'
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -104,5 +104,6 @@ const credentialCardBackgrounds: {
} = {
[wellKnownCredential.PID]: require('../../../assets/img/cards/pid.png'),
[wellKnownCredential.DRIVING_LICENSE]: require('../../../assets/img/cards/mdl.png'),
[wellKnownCredential.DISABILITY_CARD]: require('../../../assets/img/cards/disabilityCard.png')
[wellKnownCredential.DISABILITY_CARD]: require('../../../assets/img/cards/disabilityCard.png'),
[wellKnownCredential.BONUS_PARI]: require('../../../assets/img/cards/bonus.png')
};
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ const assetsMap: Record<string, CardAssets> = {
[wellKnownCredential.DISABILITY_CARD]: {
front: require('../../../../assets/img/credential/dc_front.png'),
back: require('../../../../assets/img/credential/dc_back.png')
},
[wellKnownCredential.BONUS_PARI]: {
front: require('../../../../assets/img/cards/bonus.png'),
back: require('../../../../assets/img/cards/bonus.png')
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ type Props = {
const credentialIconByType: Record<string, IOIcons> = {
[wellKnownCredential.DRIVING_LICENSE]: 'car',
[wellKnownCredential.PID]: 'fingerprint',
[wellKnownCredential.DISABILITY_CARD]: 'accessibility'
[wellKnownCredential.DISABILITY_CARD]: 'accessibility',
[wellKnownCredential.BONUS_PARI]: 'bonus'
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,11 @@ export const ItwPresentationClaimsSection = ({

const claims = Object.entries(parsedClaims);
const filteredClaims = useMemo(
() => claims.filter(([id]) => id !== WellKnownClaim.link_qr_code),
() =>
claims.filter(
([id]) =>
id !== WellKnownClaim.link_qr_code && id !== WellKnownClaim.barcode
),
[claims]
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ type ItwPresentationDetailsHeaderProps = {
*/
const credentialsWithSkeumorphicCard: ReadonlyArray<string> = [
wellKnownCredential.DRIVING_LICENSE,
wellKnownCredential.DISABILITY_CARD
wellKnownCredential.DISABILITY_CARD,
wellKnownCredential.BONUS_PARI
];

/**
Expand Down Expand Up @@ -75,7 +76,7 @@ const ItwPresentationDetailsHeader = ({
</ContentWrapper>
</View>
);
}, [credential, backgroundColor, textColor, isExperimental, parsedClaims]);
}, [credential, parsedClaims, backgroundColor, textColor, isExperimental]);

return (
<View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ const ItwPresentationDetailsScreenBase = ({
supportRequest: true,
enableDiscreteTransition: true,
animatedRef: animatedScrollViewRef,
...headerProps
...headerProps,
variant: 'neutral'
});

const actions: IOScrollViewActions | undefined = ctaProps
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
setProximityStatusStopped
} from '../../store/proximity';
import { parseClaimsToRecord } from '../../utils/claims';
import { WellKnownClaim } from '../../utils/itwClaimsUtils';
import { wellKnownCredential } from '../../utils/credentials';
import { getCredentialStatus } from '../../utils/itwCredentialStatusUtils';
import { CredentialFormat, StoredCredential } from '../../utils/itwTypesUtils';
Expand All @@ -49,6 +50,7 @@ import {
useDebugInfo
} from '@io-eudiw-app/debug-info';
import { MainNavigatorParamsList } from '../../navigation/main/MainStackNavigator';
import { ItwBarcodeCard } from '../../components/ItwBarcodeCard';

export type ItwPresentationCredentialDetailNavigationParams = {
credentialType: string;
Expand Down Expand Up @@ -191,13 +193,21 @@ const ItwPresentationCredentialDetail = ({
}

return undefined;
}, [credential.credentialType, t, dispatch, QrCodeModal]);
}, [QrCodeModal, credential.credentialType, dispatch, t]);

const parsedClaims = useMemo(
() => parseClaimsToRecord(credential.parsedCredential),
[credential.parsedCredential]
);

const barcodeClaim = useMemo(
() =>
Object.entries(parsedClaims).find(
([id]) => id === WellKnownClaim.barcode
)?.[1],
[parsedClaims]
);

if (status === 'unknown') {
return <ItwPresentationCredentialUnknownStatus credential={credential} />;
}
Expand All @@ -215,6 +225,10 @@ const ItwPresentationCredentialDetail = ({
<ContentWrapper>
<VStack space={24}>
<ItwPresentationCredentialStatusAlert credential={credential} />
{barcodeClaim?.parsed?.value &&
typeof barcodeClaim.parsed.value === 'string' && (
<ItwBarcodeCard value={barcodeClaim.parsed.value} />
)}
<ItwPresentationCredentialInfoAlert credential={credential} />
<ItwPresentationClaimsSection
credential={credential}
Expand Down
14 changes: 12 additions & 2 deletions libs/it-wallet/src/lib/utils/claims.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ export const claimType = {
image: 'image',
stringArray: 'stringArray',
placeOfBirth: 'placeOfBirth',
verification: 'verification'
verification: 'verification',
barcode: 'barcode'
} as const;

/**
Expand Down Expand Up @@ -263,6 +264,14 @@ export const placeofBirthSchema = z
});
export type PlaceOfBirthClaimType = z.infer<typeof placeofBirthSchema>;

/**
* Schema to validate a barcode claim value (e.g. discount code for PARI_BONUS)
*/
const barcodeSchema = z.string().transform(str => ({
value: str,
type: claimType.barcode
}));

export const verificationScheme = z
.object({
assurance_level: z.object({
Expand Down Expand Up @@ -301,7 +310,8 @@ export const claimScheme = z.union([
numberSchema,
emptyStringSchema,
verificationScheme,
stringSchema
stringSchema,
barcodeSchema
])
)
]);
Expand Down
14 changes: 11 additions & 3 deletions libs/it-wallet/src/lib/utils/credentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ import { ItwCredentialStatus, ItwJwtCredentialStatus } from '../types';
import { ParsedDcql } from './itwTypesUtils';
import { CredentialType } from './itwMocksUtils';

export type CredentialsKeys = 'DRIVING_LICENSE' | 'PID' | 'DISABILITY_CARD';
export type CredentialsKeys =
| 'DRIVING_LICENSE'
| 'PID'
| 'DISABILITY_CARD'
| 'BONUS_PARI';

/**
* Map which, for each wallet available credential, stores its corresponding
Expand All @@ -13,7 +17,8 @@ export type CredentialsKeys = 'DRIVING_LICENSE' | 'PID' | 'DISABILITY_CARD';
export const wellKnownCredential = {
DRIVING_LICENSE: 'org.iso.18013.5.1.mDL',
PID: 'urn:eudi:pid:it:1',
DISABILITY_CARD: 'urn:eu.europa.ec.eudi:edc:1'
DISABILITY_CARD: 'urn:eu.europa.ec.eudi:edc:1',
BONUS_PARI: 'urn:pagopa:pari-bonus:1'
} as const satisfies Record<CredentialsKeys, string>;

/**
Expand All @@ -33,7 +38,8 @@ export const wellKnownCredentialConfigurationIDs: Record<
> = {
DRIVING_LICENSE: 'org.iso.18013.5.1.mDL',
PID: 'dc_sd_jwt_PersonIdentificationData',
DISABILITY_CARD: 'dc_sd_jwt_EuropeanDisabilityCard'
DISABILITY_CARD: 'dc_sd_jwt_EuropeanDisabilityCard',
BONUS_PARI: 'dc_sd_jwt_PariBonus'
};

/**
Expand Down Expand Up @@ -82,6 +88,8 @@ export const getCredentialNameByType = (type?: string): string => {
return t(['credentials.names.pid'], { ns: 'wallet' });
case wellKnownCredential.DISABILITY_CARD:
return t(['credentials.names.disabilityCard'], { ns: 'wallet' });
case wellKnownCredential.BONUS_PARI:
return t(['credentials.names.bonusPari'], { ns: 'wallet' });
default:
return t(['credentials.names.unknown'], { ns: 'wallet' });
}
Expand Down
9 changes: 8 additions & 1 deletion libs/it-wallet/src/lib/utils/itwClaimsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ export enum WellKnownClaim {
/**
* Claims that contains the document number, if applicable for the credential
*/

fiscal_code = 'fiscal_code',

document_number = 'document_number',
/**
* Claim that contains the first name, if applicable for the credential
Expand All @@ -75,7 +78,11 @@ export enum WellKnownClaim {
/**
* Claim that contains signature usual mark
*/
signature_usual_mark = 'signature_usual_mark'
signature_usual_mark = 'signature_usual_mark',
/**
* Claim that contains the barcode
*/
barcode = 'barcode'
}

/**
Expand Down
4 changes: 3 additions & 1 deletion libs/it-wallet/src/lib/utils/itwCredentialStatusUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ export const getCredentialStatus = (
const credentialTypesByVct: { [vct: string]: CredentialType } = {
[wellKnownCredential.PID]: CredentialType.PID,
[wellKnownCredential.DRIVING_LICENSE]: CredentialType.DRIVING_LICENSE,
[wellKnownCredential.DISABILITY_CARD]: CredentialType.EUROPEAN_DISABILITY_CARD
[wellKnownCredential.DISABILITY_CARD]:
CredentialType.EUROPEAN_DISABILITY_CARD,
[wellKnownCredential.BONUS_PARI]: CredentialType.BONUS_PARI
};

/**
Expand Down
3 changes: 3 additions & 0 deletions libs/it-wallet/src/lib/utils/itwCredentialUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ const itwGetCredentialNameByCredentialType = (): Record<string, string> => ({
}),
[wellKnownCredential.PID]: t('credentials.names.pid', {
ns: 'wallet'
}),
[wellKnownCredential.BONUS_PARI]: t('credentials.names.bonusPari', {
ns: 'wallet'
})
});

Expand Down
3 changes: 2 additions & 1 deletion libs/it-wallet/src/lib/utils/itwMocksUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ export enum CredentialType {
PID = 'PersonIdentificationData',
EDUCATION_DEGREE = 'education_degree',
EDUCATION_ENROLLMENT = 'education_enrollment',
RESIDENCY = 'residency'
RESIDENCY = 'residency',
BONUS_PARI = 'bonus_pari'
}

export const ItwStoredCredentialsMocks = {
Expand Down
5 changes: 5 additions & 0 deletions libs/it-wallet/src/lib/utils/itwStyleUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ export const useThemeColorByCredentialType = (
backgroundColor: '#315B76',
textColor: '#17406F'
};
case wellKnownCredential.BONUS_PARI:
return {
backgroundColor: '#7AC1FA',
textColor: '#000000'
};
}
}, [credentialType, theme, withL3Design]);

Expand Down
6 changes: 6 additions & 0 deletions libs/it-wallet/src/locales/it/wallet.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"mdl": "Patente di guida",
"pid": "IT-Wallet ID",
"disabilityCard": "Carta Europea della Disabilità",
"bonusPari": "Bonus Elettrodomestici",
"unknown": "Credenziale Sconosciuta"
},
"status": {
Expand Down Expand Up @@ -240,6 +241,11 @@
},
"authSource": "PagoPa S.p.A."
},
"bonusPari": {
"barcode": {
"copyButton": "Copia codice sconto"
}
},
"proximity": {
"showQr": {
"title": "Show QR",
Expand Down
17 changes: 17 additions & 0 deletions patches/PATCHES.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,20 @@ This patch fixes the touch issue on SVG buttons. It's caused by SVG stealing tou

- This should be removed once the patch gets applied to the design system library.

### react-native-barcode-builder__svg.patch

Created on: **25/05/2026**

#### Reason

- The `@react-native-community/art` library is deprecated and causes build/compatibility issues in newer React Native environments.
- This patch replaces `@react-native-community/art` (Surface, Shape) with `react-native-svg` (Svg, Path) for rendering barcodes.
- It refactors the component to use dedicated `renderSvg`, `renderBars`, and `renderBar` methods, binding them in the constructor.
- The SVG `d` path commands in `drawRect` are also normalized to use spaces instead of commas for better SVG compatibility.

### How to remove in the future:

- Remove the patch once the upstream `react-native-barcode-builder` package migrates to `react-native-svg` (or resolves the `@react-native-community/art` deprecation) and the version used in the project is updated.
- Remove the patch file from the `patches/` directory.
- Remove this entry from `patches.md`.

Loading
Loading