Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(IT Wallet): [SIW-1834] Refactor date claim parser #6431

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@
"test:ci": "jest --ci --maxWorkers=4 --silent",
"test:dev": "jest --detectOpenHandles --coverage=false",
"test:tz": "yarn test:tz-eu-rome && yarn test:tz-us-ny && yarn test:tz-us-yt && yarn test:tz-au-syd",
"test:tz-eu-rome": "TZ='Europe/Rome' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false -t 'Check fiscal code date IT|removeTimezoneFromDate should remove the timezone from a date' './ts/utils/__tests__/fiscal-code.test.ts' './ts/utils/__tests__/dates.test.ts'",
"test:tz-us-ny": "TZ='America/New_York' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false -t 'Check fiscal code date NY|removeTimezoneFromDate should remove the timezone from a date' './ts/utils/__tests__/fiscal-code.test.ts' './ts/utils/__tests__/dates.test.ts'",
"test:tz-us-yt": "TZ='America/Whitehorse' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false -t 'Check fiscal code date CA|removeTimezoneFromDate should remove the timezone from a date' './ts/utils/__tests__/fiscal-code.test.ts' './ts/utils/__tests__/dates.test.ts'",
"test:tz-au-syd": "TZ='Australia/Sydney' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false -t 'Check fiscal code date AU|removeTimezoneFromDate should remove the timezone from a date' './ts/utils/__tests__/fiscal-code.test.ts' './ts/utils/__tests__/dates.test.ts'",
"test:tz-eu-rome": "TZ='Europe/Rome' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false -t 'Check fiscal code date IT|SimpleDateClaim should handle valid, invalid, edge cases, and formatting correctly' './ts/utils/__tests__/fiscal-code.test.ts' './ts/features/itwallet/common/utils/__tests__/itwClaimsUtils.test.ts'",
"test:tz-us-ny": "TZ='America/New_York' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false -t 'Check fiscal code date NY|SimpleDateClaim should handle valid, invalid, edge cases, and formatting correctly' './ts/utils/__tests__/fiscal-code.test.ts' './ts/features/itwallet/common/utils/__tests__/itwClaimsUtils.test.ts'",
"test:tz-us-yt": "TZ='America/Whitehorse' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false -t 'Check fiscal code date CA|SimpleDateClaim should handle valid, invalid, edge cases, and formatting correctly' './ts/utils/__tests__/fiscal-code.test.ts' './ts/features/itwallet/common/utils/__tests__/itwClaimsUtils.test.ts'",
"test:tz-au-syd": "TZ='Australia/Sydney' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false -t 'Check fiscal code date AU|SimpleDateClaim should handle valid, invalid, edge cases, and formatting correctly' './ts/utils/__tests__/fiscal-code.test.ts' './ts/features/itwallet/common/utils/__tests__/itwClaimsUtils.test.ts'",
"prettify": "prettier --write \"ts/**/*.(ts|tsx)\"",
"prettier:check": "prettier --check \"ts/**/*.(ts|tsx)\"",
"packager:clear": "rm -rf $TMPDIR/react-native-packager-cache-* && rm -rf $TMPDIR/metro-bundler-cache-*",
Expand Down
31 changes: 11 additions & 20 deletions ts/features/itwallet/common/components/ItwCredentialClaim.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { Divider, ListItemInfo } from "@pagopa/io-app-design-system";
import { DateFromString } from "@pagopa/ts-commons/lib/dates";
import * as E from "fp-ts/Either";
import * as O from "fp-ts/Option";
import { pipe } from "fp-ts/lib/function";
import React, { useMemo } from "react";
import { Image } from "react-native";
import I18n from "../../../../i18n";
import { useIOBottomSheetAutoresizableModal } from "../../../../utils/hooks/bottomSheet";
import { localeDateFormat } from "../../../../utils/locale";
import { useItwInfoBottomSheet } from "../hooks/useItwInfoBottomSheet";
import {
BoolClaim,
Expand All @@ -17,15 +15,17 @@ import {
DrivingPrivilegesClaim,
EmptyStringClaim,
EvidenceClaim,
extractFiscalCode,
FiscalCodeClaim,
getSafeText,
ImageClaim,
isExpirationDateClaim,
PdfClaim,
PlaceOfBirthClaim,
PlaceOfBirthClaimType,
StringClaim,
extractFiscalCode,
isExpirationDateClaim,
getSafeText
SimpleDate,
SimpleDateClaim,
StringClaim
} from "../utils/itwClaimsUtils";
import { ItwCredentialStatus } from "../utils/itwTypesUtils";

Expand Down Expand Up @@ -108,15 +108,12 @@ const DateClaimItem = ({
status
}: {
label: string;
claim: Date;
claim: SimpleDate;
status?: ItwCredentialStatus;
}) => {
// Remove the timezone offset to display the date in its original format

const value = localeDateFormat(
claim,
I18n.t("global.dateFormats.shortFormat")
);
const value = claim.toString("DD/MM/YYYY");

const endElement: ListItemInfo["endElement"] = useMemo(() => {
const ns = "features.itWallet.presentation.credentialDetails.status";
Expand Down Expand Up @@ -270,14 +267,8 @@ const DrivingPrivilegesClaimItem = ({
claim: DrivingPrivilegeClaimType;
detailsButtonVisible?: boolean;
}) => {
const localExpiryDate = localeDateFormat(
claim.expiry_date,
I18n.t("global.dateFormats.shortFormat")
);
const localIssueDate = localeDateFormat(
claim.issue_date,
I18n.t("global.dateFormats.shortFormat")
);
const localExpiryDate = claim.expiry_date.toString("DD/MM/YY");
const localIssueDate = claim.issue_date.toString("DD/MM/YY");
Comment on lines +270 to +271
Copy link
Contributor

Choose a reason for hiding this comment

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

According to the Figma design, these dates should follow the 'DD/MM/YYYY' format.

Suggested change
const localExpiryDate = claim.expiry_date.toString("DD/MM/YY");
const localIssueDate = claim.issue_date.toString("DD/MM/YY");
const localExpiryDate = claim.expiry_date.toString("DD/MM/YYYY");
const localIssueDate = claim.issue_date.toString("DD/MM/YYYY");

const privilegeBottomSheet = useIOBottomSheetAutoresizableModal({
title: I18n.t(
"features.itWallet.verifiableCredentials.claims.mdl.category",
Expand Down Expand Up @@ -371,7 +362,7 @@ export const ItwCredentialClaim = ({
const decoded = hidden ? HIDDEN_CLAIM : _decoded;
if (PlaceOfBirthClaim.is(decoded)) {
return <PlaceOfBirthClaimItem label={claim.label} claim={decoded} />;
} else if (DateFromString.is(decoded)) {
} else if (SimpleDateClaim.is(decoded)) {
return (
<DateClaimItem
label={claim.label}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { WithTestID } from "@pagopa/io-app-design-system";
import { DateFromString } from "@pagopa/ts-commons/lib/dates";
import * as E from "fp-ts/lib/Either";
import * as O from "fp-ts/lib/Option";
import { constNull, pipe } from "fp-ts/lib/function";
import React from "react";
import { Image, StyleSheet, View, ViewStyle } from "react-native";
import { Either, Prettify } from "../../../../../types/helpers";
import { localeDateFormat } from "../../../../../utils/locale";
import {
ClaimValue,
DrivingPrivilegesClaim,
EvidenceClaim,
ImageClaim,
PlaceOfBirthClaim
PlaceOfBirthClaim,
SimpleDateClaim,
SimpleDateFormat
} from "../../utils/itwClaimsUtils";
import { ParsedCredential } from "../../utils/itwTypesUtils";
import { ClaimLabel, ClaimLabelProps } from "./ClaimLabel";
Expand Down Expand Up @@ -48,7 +48,7 @@ export type CardClaimProps = Prettify<
// Claim dimensions
dimensions?: ClaimDimensions;
// Optional format for dates contained in the claim component
dateFormat?: string;
dateFormat?: SimpleDateFormat;
} & ClaimLabelProps
>;

Expand All @@ -61,7 +61,7 @@ const CardClaim = ({
position,
dimensions,
testID,
dateFormat = "%d/%m/%Y",
dateFormat = "DD/MM/YY",
...labelProps
}: WithTestID<CardClaimProps>) => {
const claimContent = React.useMemo(
Expand All @@ -70,8 +70,8 @@ const CardClaim = ({
claim?.value,
ClaimValue.decode,
E.fold(constNull, decoded => {
if (DateFromString.is(decoded)) {
const formattedDate = localeDateFormat(decoded, dateFormat);
if (SimpleDateClaim.is(decoded)) {
const formattedDate = decoded.toString(dateFormat);
return <ClaimLabel {...labelProps}>{formattedDate}</ClaimLabel>;
} else if (EvidenceClaim.is(decoded)) {
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
/* eslint-disable dot-notation */
/* eslint-disable @typescript-eslint/dot-notation */
import { parse } from "date-fns";
import { pipe } from "fp-ts/lib/function";
import * as O from "fp-ts/lib/Option";
import { Fragment, default as React } from "react";
import { default as React, Fragment } from "react";
import { StyleSheet, View } from "react-native";
import { QrCodeImage } from "../../../../../components/QrCodeImage";
import { localeDateFormat } from "../../../../../utils/locale";
import {
DrivingPrivilegesClaim,
StringClaim
Expand Down Expand Up @@ -50,7 +48,7 @@ const MdlFrontData = ({ claims }: DataComponentProps) => {
<CardClaim
claim={claims["birth_date"]}
position={{ left: `${cols[0]}%`, top: `${rows[2]}%` }}
dateFormat="%d/%m/%y"
dateFormat="DD/MM/YY"
/>
<CardClaim
claim={claims["place_of_birth"]}
Expand All @@ -60,6 +58,7 @@ const MdlFrontData = ({ claims }: DataComponentProps) => {
claim={claims["issue_date"]}
position={{ left: `${cols[0]}%`, top: `${rows[3]}%` }}
fontWeight={"Bold"}
dateFormat={"DD/MM/YYYY"}
/>
<CardClaim
claim={claims["issuing_authority"]}
Expand All @@ -69,6 +68,7 @@ const MdlFrontData = ({ claims }: DataComponentProps) => {
claim={claims["expiry_date"]}
position={{ left: `${cols[0]}%`, top: `${rows[4]}%` }}
fontWeight={"Bold"}
dateFormat={"DD/MM/YYYY"}
/>
<CardClaim
claim={claims["document_number"]}
Expand Down Expand Up @@ -134,7 +134,7 @@ const MdlBackData = ({ claims }: DataComponentProps) => {
}}
>
<ClaimLabel fontSize={9}>
{localeDateFormat(parse(issue_date), "%d/%m/%y")}
{issue_date.toString("DD/MM/YY")}
</ClaimLabel>
</CardClaimContainer>
<CardClaimContainer
Expand All @@ -145,7 +145,7 @@ const MdlBackData = ({ claims }: DataComponentProps) => {
}}
>
<ClaimLabel fontSize={9}>
{localeDateFormat(parse(expiry_date), "%d/%m/%y")}
{expiry_date.toString("DD/MM/YY")}
</ClaimLabel>
</CardClaimContainer>
{restrictions_conditions && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ exports[`CardData should match snapshot for DC front data 1`] = `
}
weight="Semibold"
>
15/03/1990
15/03/90
</Text>
</View>
<View
Expand Down Expand Up @@ -342,7 +342,7 @@ exports[`CardData should match snapshot for DC front data 1`] = `
}
weight="Semibold"
>
23/03/2032
23/03/32
</Text>
</View>
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
getCredentialExpireDays,
getCredentialStatus,
getFiscalCodeFromCredential,
ImageClaim
ImageClaim,
SimpleDateClaim
} from "../itwClaimsUtils";
import { StoredCredential } from "../itwTypesUtils";
import { ItwStoredCredentialsMocks } from "../itwMocksUtils";
Expand Down Expand Up @@ -468,3 +469,55 @@ describe("getCredentialStatus", () => {
});
});
});

describe("SimpleDateClaim", () => {
it("should handle valid, invalid, edge cases, and formatting correctly", () => {
// Valid date decoding
const validInput = "2024-11-19";
const validResult = SimpleDateClaim.decode(validInput);
expect(E.isRight(validResult)).toBe(true);
if (E.isRight(validResult)) {
const decodedDate = validResult.right;

// Validate date parts
expect(decodedDate.getFullYear()).toBe(2024);
expect(decodedDate.getMonth()).toBe(10); // 0-indexed month
expect(decodedDate.getDate()).toBe(19);

// Validate default and custom formats
expect(decodedDate.toString()).toBe("19/11/2024");
expect(decodedDate.toString("DD/MM/YY")).toBe("19/11/24");

// Validate Date object conversions
expect(decodedDate.toDate()).toEqual(new Date(2024, 10, 19));
expect(decodedDate.toDateWithoutTimezone().toISOString()).toBe(
"2024-11-19T00:00:00.000Z"
);
}

// Invalid date decoding
const invalidInput = "invalid-date";
const invalidResult = SimpleDateClaim.decode(invalidInput);
expect(E.isLeft(invalidResult)).toBe(true);

// Valid leap year date
const leapYearInput = "2024-02-29";
const leapYearResult = SimpleDateClaim.decode(leapYearInput);
expect(E.isRight(leapYearResult)).toBe(true);
if (E.isRight(leapYearResult)) {
const leapYearDate = leapYearResult.right;
expect(leapYearDate.getFullYear()).toBe(2024);
expect(leapYearDate.getMonth()).toBe(1); // 0-indexed month
expect(leapYearDate.getDate()).toBe(29);
}

// Valid date with padded spaces
const paddedInput = " 2024-11-19 ";
const paddedResult = SimpleDateClaim.decode(paddedInput.trim());
expect(E.isRight(paddedResult)).toBe(true);
if (E.isRight(paddedResult)) {
const paddedDate = paddedResult.right;
expect(paddedDate.toString()).toBe("19/11/2024");
}
});
});
Loading
Loading