Skip to content

Commit

Permalink
chore(IT Wallet): [SIW-740] Refactor claims list (#5321)
Browse files Browse the repository at this point in the history
## Short description
Depends on #5310, #5315 and #5321.

This PR introduces a refactors in how we render the claims list. The
general idea behind this refactor is that we are parsing the `unknown`
value of a claim with io-ts decoders to known which kind of claim we are
manipulating, thus rendering an appropriate component to display it.

## List of changes proposed in this pull request
- Defines a set of decoders for our claims; 
- Adds a `itwCredentialClaim.tsx` which decodes the claim and renders
the appropriate component;
- Align `ItwCredentialClaimsList.tsx` to the new changes;
- Moves every claim related util to `ItwClaimsUtils`.

## How to test
Test the available credentials, each claim should be render properly
formatted.

---------

Co-authored-by: Mario Perrotta <mario.perrotta@pagopa.it>
  • Loading branch information
LazyAfternoons and hevelius committed Dec 18, 2023
1 parent 84e55db commit e207bff
Show file tree
Hide file tree
Showing 9 changed files with 564 additions and 212 deletions.
2 changes: 1 addition & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1042,4 +1042,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 0d78c2a7f58353c7eed2163b7e3b3747b00ff101

COCOAPODS: 1.14.2
COCOAPODS: 1.12.1
4 changes: 4 additions & 0 deletions locales/en/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3467,6 +3467,10 @@ features:
securityLevels:
high: "High"
na: "Not available"
mdl:
category: "License {{category}}"
issuedDate: "Valid from"
expirationDate: "Valid until"
unrecognizedData:
title: "Not recognizing some data?"
body: "If there are errors in the data or if you want to better understand their meaning, you can contact the {{issuer}}."
Expand Down
6 changes: 5 additions & 1 deletion locales/it/index.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3468,6 +3468,10 @@ features:
securityLevels:
high: "Alto"
na: "Non disponibile"
mdl:
category: "Licenza {{category}}"
issuedDate: "Valida dal"
expirationDate: "Valida fino"
unrecognizedData:
title: "Non riconosci alcuni dati?"
body: "Se ci sono errori nei dati o vuoi capire meglio cosa significano, puoi contattare il Ministero dell’Interno."
Expand All @@ -3490,7 +3494,7 @@ features:
credential: "Credenziale"
attribute: "Attributo"
placeholders:
claimNotAvailable: "Attributo non presente"
claimNotAvailable: "Attributo non riconosciuto"
claimLabelNotAvailable: "Etichetta attributo non presente"
organizationName: "Nome ente non disponibile"
webView:
Expand Down
273 changes: 273 additions & 0 deletions ts/features/it-wallet/components/ItwCredentialClaim.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
import React from "react";
import { Divider, ListItemInfo } from "@pagopa/io-app-design-system";
import * as E from "fp-ts/Either";
import { pipe } from "fp-ts/lib/function";
import { View, Image } from "react-native";
import { DateFromString } from "@pagopa/ts-commons/lib/dates";
import {
ClaimValue,
DrivingPrivilegesClaim,
DrivingPrivilegesClaimType,
EvidenceClaim,
ImageClaim,
PlaceOfBirthClaim,
PlaceOfBirthClaimType,
PlainTextClaim
} from "../utils/itwClaimsUtils";
import I18n from "../../../i18n";
import { useItwInfoBottomSheet } from "../hooks/useItwInfoBottomSheet";
import { localeDateFormat } from "../../../utils/locale";
import { useIOBottomSheetAutoresizableModal } from "../../../utils/hooks/bottomSheet";
import { Claim } from "./ItwCredentialClaimsList";

/**
* Component which renders a place of birth type claim.
* @param label - the label of the claim
* @param claim - the claim value
*/
const PlaceOfBirthClaimItem = ({
label,
claim
}: {
label: string;
claim: PlaceOfBirthClaimType;
}) => {
const value = `${claim.locality} (${claim.country})`;
return (
<>
<ListItemInfo label={label} value={value} accessibilityLabel={value} />
<Divider />
</>
);
};

/**
* Component which renders a generic text type claim.
* @param label - the label of the claim
* @param claim - the claim value
*/
const PlainTextClaimItem = ({
label,
claim
}: {
label: string;
claim: string;
}) => (
<>
<ListItemInfo
label={label}
value={claim}
accessibilityLabel={`${label} ${claim}`}
/>
<Divider />
</>
);

/**
* Component which renders a date type claim.
* @param label - the label of the claim
* @param claim - the value of the claim
*/
const DateClaimItem = ({ label, claim }: { label: string; claim: Date }) => {
const value = localeDateFormat(
claim,
I18n.t("global.dateFormats.shortFormat")
);
return (
<View key={`${label}-${value}`}>
<ListItemInfo
label={label}
value={value}
accessibilityLabel={`${label} ${value}`}
/>
<Divider />
</View>
);
};

/**
* Component which renders a evidence type claim.
* It features a bottom sheet with information about the issuer of the claim.
* @param issuerName - the organization name of the issuer of the evidence claim.
*/
const EvidenceClaimItem = ({ issuerName }: { issuerName: string }) => {
const issuedByBottomSheet = useItwInfoBottomSheet({
title: issuerName,
content: [
{
title: I18n.t(
"features.itWallet.issuing.credentialPreviewScreen.bottomSheet.about.title"
),
body: I18n.t(
"features.itWallet.issuing.credentialPreviewScreen.bottomSheet.about.subtitle"
)
},
{
title: I18n.t(
"features.itWallet.issuing.credentialPreviewScreen.bottomSheet.data.title"
),
body: I18n.t(
"features.itWallet.issuing.credentialPreviewScreen.bottomSheet.data.subtitle"
)
}
]
});
const label = I18n.t(
"features.itWallet.verifiableCredentials.claims.issuedByNew"
);
return (
<>
<ListItemInfo
endElement={{
type: "iconButton",
componentProps: {
icon: "info",
accessibilityLabel: "test",
onPress: () => issuedByBottomSheet.present()
}
}}
label={label}
value={issuerName}
accessibilityLabel={`${label} ${issuerName}`}
/>
{issuedByBottomSheet.bottomSheet}
<Divider />
</>
);
};

/**
* Component which renders a claim of unknown type with a placeholder.
* @param label - the label of the claim
* @param _claim - the claim value of unknown type. We are not interested in its value but it's needed for the exaustive type checking.
*/
const UnknownClaimItem = ({ label }: { label: string; _claim?: never }) => (
<PlainTextClaimItem
label={label}
claim={I18n.t("features.itWallet.generic.placeholders.claimNotAvailable")}
/>
);

/**
* Component which renders a image type claim in a square container.
* @param label - the label of the claim
* @param claim - the claim value
*/
const ImageClaimItem = ({ label, claim }: { label: string; claim: string }) => (
<>
<ListItemInfo
label={label}
value={
<Image
source={{ uri: claim }}
style={{
width: 250,
height: 250
}}
resizeMode="contain"
/>
}
accessibilityLabel={`${label} ${claim}`}
/>
<Divider />
</>
);

/**
* Component which renders a driving privileges type claim.
* It features a bottom sheet with information about the issued and expiration date of the claim.
* @param label - the label of the claim
* @param claim - the claim value
* @returns
*/
const DrivingPrivilegesClaimItem = ({
label,
claim
}: {
label: string;
claim: DrivingPrivilegesClaimType;
}) => {
const privilegeBottomSheet = useIOBottomSheetAutoresizableModal({
title: I18n.t(
"features.itWallet.verifiableCredentials.claims.mdl.category",
{ category: claim.vehicle_category_code }
),
component: (
<>
<ListItemInfo
label={I18n.t(
"features.itWallet.verifiableCredentials.claims.mdl.issuedDate"
)}
value={claim.issue_date}
accessibilityLabel={`${label} ${claim.issue_date}`}
/>
<Divider />
<ListItemInfo
label={I18n.t(
"features.itWallet.verifiableCredentials.claims.mdl.expirationDate"
)}
value={claim.expiry_date}
accessibilityLabel={`${label} ${claim.expiry_date}`}
/>
</>
)
});
return (
<>
<ListItemInfo
label={label}
value={claim.vehicle_category_code}
endElement={{
type: "iconButton",
componentProps: {
icon: "info",
accessibilityLabel: "test",
onPress: () => privilegeBottomSheet.present()
}
}}
accessibilityLabel={`${label} ${claim}`}
/>
<Divider />
{privilegeBottomSheet.bottomSheet}
</>
);
};

/**
* Component which renders a claim.
* It renders a different component based on the type of the claim.
* @param claim - the claim to render
*/
const ItwCredentialClaim = ({ claim }: { claim: Claim }) =>
pipe(
claim.value,
ClaimValue.decode,
E.fold(
() => <UnknownClaimItem label={claim.label} />,
decoded => {
if (PlaceOfBirthClaim.is(decoded)) {
return <PlaceOfBirthClaimItem label={claim.label} claim={decoded} />;
} else if (DateFromString.is(decoded)) {
return <DateClaimItem label={claim.label} claim={decoded} />;
} else if (EvidenceClaim.is(decoded)) {
return (
<EvidenceClaimItem
issuerName={decoded[0].record.source.organization_name}
/>
);
} else if (ImageClaim.is(decoded)) {
return <ImageClaimItem label={claim.label} claim={decoded} />;
} else if (DrivingPrivilegesClaim.is(decoded)) {
return (
<DrivingPrivilegesClaimItem label={claim.label} claim={decoded} />
);
} else if (PlainTextClaim.is(decoded)) {
return <PlainTextClaimItem label={claim.label} claim={decoded} />; // must be the last one to be checked due to overlap with IPatternStringTag
} else {
return <UnknownClaimItem label={claim.label} _claim={decoded} />;
}
}
)
);

export default ItwCredentialClaim;
Loading

0 comments on commit e207bff

Please sign in to comment.