Skip to content

Commit

Permalink
fix: [IABT-1403,IOAPPCIT-9] Birth date is wrong in fiscal code compon…
Browse files Browse the repository at this point in the history
…ent (pagopa#4197)

* fix birth date in place of CF

* fix lint error

* update birth date in FiscalCodeComponent

* update FiscalCodeComponent

* fix date test

* fix fiscal code birthday

* update fiscal code birthday test

Co-authored-by: Cristiano Tofani <[email protected]>
  • Loading branch information
adelloste and CrisTofani authored Dec 2, 2022
1 parent 5e111ac commit 7662cc4
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 67 deletions.
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ module.exports = {
"@testing-library/jest-native/extend-expect",
"./jestSetupAfterEnv.js"
],
collectCoverage: true
collectCoverage: true,
testPathIgnorePatterns: [".*fiscal-code.test.ts$"]
};
18 changes: 18 additions & 0 deletions jest.config.no.timezone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
preset: "react-native",
transform: {
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js"
},
transformIgnorePatterns: [
"node_modules/(?!(jest-)?@react-native|react-native|react-navigation|@react-navigation|react-navigation-redux-helpers|react-native-device-info|native-base|native-base-shoutem-theme|@shoutem/animation|@shoutem/ui|rn-placeholder|jsbarcode|@pagopa/react-native-cie|react-native-share|jail-monkey|@react-native-community/art|@react-native-community/push-notification-ios|@react-native-community/cameraroll|@codler|@react-native-community/datetimepicker|remark|unified|bail|is-plain-obj|trough|vfile|unist-util-stringify-position|mdast-util-from-markdown|mdast-util-to-string|micromark|parse-entities|character-entities|mdast-util-to-markdown|zwitch|longest-streak|io-react-native-zendesk)"
],
moduleNameMapper: {
"\\.svg": "<rootDir>/ts/__mocks__/svgMock.js"
},
setupFiles: ["./jestSetup.js"],
setupFilesAfterEnv: [
"@testing-library/jest-native/extend-expect",
"./jestSetupAfterEnv.js"
],
collectCoverage: true
};
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@
"postinstall": "patch-package && rn-nodeify --install path,buffer && chmod +x ./bin/add-ios-source-maps.sh && ./bin/add-ios-source-maps.sh && chmod +x ./bin/add-ios-env-config.sh && ./bin/add-ios-env-config.sh",
"test:ci": "jest --ci --maxWorkers=2 --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 && yarn test:tz-eu-rome-comp",
"test:tz-eu-rome": "TZ='Europe/Rome' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false -t 'Check fiscal code date IT' './ts/utils/__tests__/fiscal-code.test.ts'",
"test:tz-eu-rome-comp": "TZ='Europe/Rome' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false './ts/components/__tests__/FiscalCodeComponent.test.tsx'",
"test:tz-us-ny": "TZ='America/New_York' jest --config='./jest.config.no.timezone.js' --detectOpenHandles --coverage=false -t 'Check fiscal code date NY' './ts/utils/__tests__/fiscal-code.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' './ts/utils/__tests__/fiscal-code.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' './ts/utils/__tests__/fiscal-code.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
14 changes: 8 additions & 6 deletions ts/components/FiscalCodeComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ import { InitializedProfile } from "../../definitions/backend/InitializedProfile
import { Municipality } from "../../definitions/content/Municipality";
import I18n from "../i18n";
import customVariables from "../theme/variables";
import { dateToAccessibilityReadableFormat } from "../utils/accessibility";
import { formatDateAsShortFormatUTC } from "../utils/dates";
import {
formatFiscalCodeBirthdayAsShortFormat,
formatFiscalCodeBirthdayAsAccessibilityReadableFormat
} from "../utils/dates";
import { extractFiscalCodeData } from "../utils/profile";
import { maybeNotNullyString } from "../utils/strings";
import { IOColors } from "./core/variables/IOColors";
Expand Down Expand Up @@ -389,7 +391,7 @@ export default class FiscalCodeComponent extends React.Component<Props> {

const na = I18n.t("profile.fiscalCode.accessibility.unavailable");
const birthDate =
this.props.profile.date_of_birth ?? fiscalCodeData.birthday;
this.props.profile.date_of_birth ?? fiscalCodeData.birthDate;
// goBackSide === false
return {
accessibilityLabel: I18n.t(
Expand All @@ -400,7 +402,7 @@ export default class FiscalCodeComponent extends React.Component<Props> {
family_name: this.props.profile.family_name,
gender: fiscalCodeData.gender || na,
birthDate: birthDate
? dateToAccessibilityReadableFormat(birthDate)
? formatFiscalCodeBirthdayAsAccessibilityReadableFormat(birthDate)
: na,
province: pipe(
maybeNotNullyString(fiscalCodeData.siglaProvincia),
Expand All @@ -425,7 +427,7 @@ export default class FiscalCodeComponent extends React.Component<Props> {
) {
const fiscalCode = profile.fiscal_code;
const fiscalCodeData = extractFiscalCodeData(fiscalCode, municipality);
const birthDate = profile.date_of_birth ?? fiscalCodeData.birthday;
const birthDate = profile.date_of_birth ?? fiscalCodeData.birthDate;
return (
<React.Fragment>
{this.renderItem(
Expand Down Expand Up @@ -476,7 +478,7 @@ export default class FiscalCodeComponent extends React.Component<Props> {

{birthDate &&
this.renderItem(
formatDateAsShortFormatUTC(birthDate),
formatFiscalCodeBirthdayAsShortFormat(birthDate),
styles.fullDateText,
styles.landscapeDateText,
isLandscape
Expand Down
2 changes: 1 addition & 1 deletion ts/components/__tests__/FiscalCodeComponent.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const municipality = pot.some(mockedMunicipality);
// 02/03/1990
const fiscalCode = "MRARSS90C02H501E" as FiscalCode;
// 02/01/1990
const dateOfBirth = new Date(1990, 0, 2);
const dateOfBirth = new Date("1990-01-02T00:00:00.000Z");

describe("FiscalCodeComponent", () => {
jest.useFakeTimers();
Expand Down
37 changes: 1 addition & 36 deletions ts/utils/__tests__/dates.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import { getMonth, getYear } from "date-fns";
import * as E from "fp-ts/lib/Either";
import MockDate from "mockdate";
import * as NAR from "fp-ts/lib/NonEmptyArray";
import I18n, { availableTranslations, setLocale } from "../../i18n";
import {
formatDateAsShortFormat,
formatDateAsShortFormatUTC,
getExpireStatus,
isExpired
} from "../dates";
import { getExpireStatus, isExpired } from "../dates";

describe("getExpireStatus", () => {
it("should be VALID", () => {
Expand Down Expand Up @@ -80,31 +73,3 @@ describe("getExpireStatus", () => {
).toEqual(E.right(false));
});
});

describe("formatDateAsShortFormat", () => {
availableTranslations.forEach(locale => {
setLocale(locale);
const toTest: ReadonlyArray<[Date, string]> = [
[new Date(1970, 0, 1), "01/01/1970"],
[new Date(2020, 10, 30), "30/11/2020"],
[new Date(1900, 5, 5), "05/06/1900"],
[new Date(1900, 13, 55), "27/03/1901"], // handle the overflow,
[new Date("not a date"), I18n.t("global.date.invalid")] // handle invalid date
];
toTest.forEach(tt => {
expect(formatDateAsShortFormat(tt[0])).toEqual(tt[1]);
});
});
});

describe("formatDateAsShortFormatUTC", () => {
const expected = "12/01/1983";
const toTest: ReadonlyArray<Date> = NAR.range(0, 23).map(
value =>
new Date(`1983-01-12T${value.toString().padStart(2, "0")}:00:00.000Z`)
);

toTest.forEach(tt => {
expect(formatDateAsShortFormatUTC(tt)).toEqual(expected);
});
});
48 changes: 48 additions & 0 deletions ts/utils/__tests__/fiscal-code.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Locales } from "../../../locales/locales";
import { setLocale } from "../../i18n";
import {
formatFiscalCodeBirthdayAsShortFormat,
formatFiscalCodeBirthdayAsAccessibilityReadableFormat
} from "../dates";

// https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
describe("Check fiscal code date", () => {
it("IT", () => {
const timeZone = "Europe/Rome";
testFiscalCodeByLocale("it", timeZone);
testFiscalCodeByLocale("en", timeZone);
});

it("NY", () => {
const timeZone = "America/New_York";
testFiscalCodeByLocale("it", timeZone);
testFiscalCodeByLocale("en", timeZone);
});

it("AU", () => {
const timeZone = "Australia/Sydney";
testFiscalCodeByLocale("it", timeZone);
testFiscalCodeByLocale("en", timeZone);
});

it("CA", () => {
const timeZone = "America/Whitehorse";
testFiscalCodeByLocale("it", timeZone);
testFiscalCodeByLocale("en", timeZone);
});
});

const testFiscalCodeByLocale = (locale: Locales, timeZone: string) => {
setLocale(locale);
// set environment variable TZ from command line
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
expect(timezone).toBe(timeZone);
const testDate = new Date("1977-05-22T00:00:00.000Z");
const checkDate = formatFiscalCodeBirthdayAsShortFormat(testDate!);
const checkDateForAccessibility =
formatFiscalCodeBirthdayAsAccessibilityReadableFormat(testDate!);
const dayName = locale === "it" ? "domenica" : "Sunday";
const monthName = locale === "it" ? "maggio" : "May";
expect(`${dayName} 22 ${monthName} 1977`).toBe(checkDateForAccessibility);
expect("22/05/1977").toBe(checkDate);
};
23 changes: 16 additions & 7 deletions ts/utils/__tests__/profile.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { none, some } from "@pagopa/ts-commons/lib/pot";
import { FiscalCode } from "@pagopa/ts-commons/lib/strings";
import { formatFiscalCodeBirthdayAsShortFormat } from "../dates";
import { extractFiscalCodeData } from "../profile";
import { mockedMunicipality } from "../__mocks__/municipality";

Expand All @@ -11,7 +12,9 @@ describe("extracting data from fiscal code", () => {
const data = extractFiscalCodeData(goodCf, potGood);
it("should return the extracted data", () => {
expect(data.birthDate).toBeDefined();
expect(data.birthDate).toEqual("01/01/1980");
expect(formatFiscalCodeBirthdayAsShortFormat(data.birthDate!)).toEqual(
"01/01/1980"
);
expect(data.gender).toEqual("M");
expect(data.denominazione).toEqual("Roma");
expect(data.siglaProvincia).toEqual("RM");
Expand All @@ -21,17 +24,19 @@ describe("extracting data from fiscal code", () => {
const dataWrong1 = extractFiscalCodeData(wrongCf, potGood);
it("should return the extracted data without birth information", () => {
expect(dataWrong1.birthDate).not.toBeDefined();
expect(data.gender).toEqual("M");
expect(data.denominazione).toEqual("Roma");
expect(data.siglaProvincia).toEqual("RM");
expect(dataWrong1.gender).not.toBeDefined();
expect(dataWrong1.denominazione).toEqual("Roma");
expect(dataWrong1.siglaProvincia).toEqual("RM");
});

// giulia rossi / roma / rm / 12-07-1956
const goodCfF = "GLIRSS56L52H501P" as FiscalCode;
const dataF = extractFiscalCodeData(goodCfF, potGood);
it("should recognize the female sex", () => {
expect(dataF.birthDate).toBeDefined();
expect(dataF.birthDate).toEqual("12/07/1956");
expect(formatFiscalCodeBirthdayAsShortFormat(dataF.birthDate!)).toEqual(
"12/07/1956"
);
expect(dataF.gender).toEqual("F");
expect(dataF.denominazione).toEqual("Roma");
expect(dataF.siglaProvincia).toEqual("RM");
Expand All @@ -42,7 +47,9 @@ describe("extracting data from fiscal code", () => {
const dataF2 = extractFiscalCodeData(goodCfF2, potGood);
it("should recognize the 2003 as year of birth", () => {
expect(dataF2.birthDate).toBeDefined();
expect(dataF2.birthDate).toEqual("12/07/2003");
expect(formatFiscalCodeBirthdayAsShortFormat(dataF2.birthDate!)).toEqual(
"12/07/2003"
);
expect(dataF2.gender).toEqual("F");
expect(dataF2.denominazione).toEqual("Roma");
expect(dataF2.siglaProvincia).toEqual("RM");
Expand All @@ -52,7 +59,9 @@ describe("extracting data from fiscal code", () => {
const dataNoM = extractFiscalCodeData(goodCfF2, none);
it("should return birth place empty", () => {
expect(dataNoM.birthDate).toBeDefined();
expect(dataNoM.birthDate).toEqual("12/07/2003");
expect(formatFiscalCodeBirthdayAsShortFormat(dataNoM.birthDate!)).toEqual(
"12/07/2003"
);
expect(dataNoM.gender).toEqual("F");
expect(dataNoM.denominazione).toEqual("");
expect(dataNoM.siglaProvincia).toEqual("");
Expand Down
63 changes: 54 additions & 9 deletions ts/utils/dates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { pipe } from "fp-ts/lib/function";
import * as O from "fp-ts/lib/Option";
import * as t from "io-ts";
import { Errors } from "io-ts";
import { Locales } from "../../locales/locales";
import { Locales, TranslationKeys } from "../../locales/locales";
import I18n from "../i18n";
import { CreditCardExpirationMonth, CreditCardExpirationYear } from "./input";
import { getLocalePrimary, localeDateFormat } from "./locale";
Expand All @@ -20,14 +20,59 @@ type DFNSLocales = Record<Locales, DateFnsLocale>;

const locales: DFNSLocales = { it: dfns_it, en: dfns_en, de: dfns_de };

// return a string representing the date dd/MM/YYYY (ex: 1 Jan 1970 -> 01/01/1970) without considering the timezone
export const formatDateAsShortFormatUTC = (date: Date): string =>
isNaN(date.getTime())
? I18n.t("global.date.invalid")
: I18n.strftime(
new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()),
I18n.t("global.dateFormats.shortFormat")
);
export const pad = (n: number) => n.toString().padStart(2, "0");

/*
* This function is specific for the fiscal code birthday rendering.
* The birthday is an ISO8601 format for midnight.
* It returns the date in short format.
*
* i.e. 1977-05-22T00:00:00.000Z -> 22/05/1977
*/
export const formatFiscalCodeBirthdayAsShortFormat = (
date: Date | undefined
): string =>
pipe(
date,
O.fromNullable,
O.chain(O.fromPredicate(d => !isNaN(d.getTime()))),
O.fold(
() => I18n.t("global.date.invalid"),
d => {
const year = d.getUTCFullYear();
const month = pad(d.getUTCMonth() + 1);
const day = pad(d.getUTCDate());
return `${day}/${month}/${year}`;
}
)
);

export const formatFiscalCodeBirthdayAsAccessibilityReadableFormat = (
date: Date | undefined
): string =>
pipe(
date,
O.fromNullable,
O.chain(O.fromPredicate(d => !isNaN(d.getTime()))),
O.fold(
() => I18n.t("global.date.invalid"),
d => {
const year = d.getUTCFullYear();
const month = d.getUTCMonth() + 1;
const date = d.getUTCDate();
const day = d.getUTCDay();
const dayTranslationKey = I18n.t(
`date.day_names.${day}` as TranslationKeys
);
const monthTranslationKey = I18n.t(
`date.month_names.${month}` as TranslationKeys
);

return `${dayTranslationKey} ${date} ${monthTranslationKey} ${year}`;
}
)
);

// return a string representing the date dd/MM/YYYY (ex: 1 Jan 1970 -> 01/01/1970)
export const formatDateAsShortFormat = (date: Date): string =>
isNaN(date.getTime())
Expand Down
12 changes: 5 additions & 7 deletions ts/utils/profile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as pot from "@pagopa/ts-commons/lib/pot";
import { format as dateFnsFormat } from "date-fns";
import { pipe } from "fp-ts/lib/function";
import * as O from "fp-ts/lib/Option";
import { BlockedInboxOrChannels } from "../../definitions/backend/BlockedInboxOrChannels";
Expand All @@ -8,16 +7,16 @@ import { InitializedProfile } from "../../definitions/backend/InitializedProfile
import { ServiceId } from "../../definitions/backend/ServiceId";
import { Municipality } from "../../definitions/content/Municipality";
import { ProfileState } from "../store/reducers/profile";
import { formatDateAsShortFormat } from "./dates";
import { pad } from "./dates";

type GenderType = "M" | "F" | undefined;

/**
* Generic utilities for profile
*/
type FiscalCodeDerivedData = Readonly<{
gender?: GenderType;
birthday?: Date;
birthDate?: ReturnType<typeof dateFnsFormat>;
birthDate?: Date;
denominazione: string;
siglaProvincia: string;
}>;
Expand Down Expand Up @@ -82,12 +81,11 @@ export function extractFiscalCodeData(
const year =
tempYear +
(new Date().getFullYear() - (1900 + tempYear) >= 100 ? 2000 : 1900);
const birthday = new Date(year, month - 1, day);
const birthDate = formatDateAsShortFormat(birthday);

const birthDate = new Date(`${year}-${pad(month)}-${pad(day)}T00:00:00.000Z`);

return {
gender,
birthday,
birthDate,
siglaProvincia,
denominazione
Expand Down

0 comments on commit 7662cc4

Please sign in to comment.