From 23918519215ca5a25f4aca28fa29c0595bc8648f Mon Sep 17 00:00:00 2001 From: Kay Kleinvogel Date: Mon, 14 Jun 2021 07:32:25 +0200 Subject: [PATCH] Feat/add dob formats (#92) * feat(entry):allowing multiple date formats * feat(entry): changing dob format selection to dropdown * refactor(entry): extracting date formats from valueset * feat(entry):adding dob format selection to all entry forms * chore(i18n):adding date formats to i18n --- src/api.tsx | 22 ++++++- src/assets/i18n/de/translation.json | 66 ++++++++++--------- src/assets/i18n/en/translation.json | 4 ++ .../modules/form-group.component.tsx | 23 +++++-- .../record-recovery-cert-data.component.tsx | 4 +- .../record-test-cert-data.component.tsx | 6 +- ...record-vaccination-cert-data.component.tsx | 6 +- src/generated-files/DGC.combined-schema.json | 4 +- 8 files changed, 88 insertions(+), 47 deletions(-) diff --git a/src/api.tsx b/src/api.tsx index 60db374..ae7b9ff 100644 --- a/src/api.tsx +++ b/src/api.tsx @@ -31,6 +31,7 @@ import Vaccines from './assets/json-res/vaccine-prophylaxis.json'; import TestManufacturers from './assets/json-res/test-manf.json'; import TestResult from './assets/json-res/test-result.json'; import TestType from './assets/json-res/test-type.json'; +import { useTranslation } from 'react-i18next'; interface IValue { active: boolean, @@ -45,6 +46,23 @@ export interface IValueSet { [key: string]: IValue; } +// Date of Birth Formats +export const useGetDateFormats = () => { + const {t} = useTranslation(); + const [dateFormats] = React.useState({ + "yyyy-MM-dd": { + "display": t('translation:date-full') + }, + "yyyy-MM": { + "display": t('translation:date-no-day') + }, + "yyyy": { + "display": t('translation:date-year') + } + }); + return dateFormats +} + // Medical Products export const useGetVaccinMedicalData = () => { @@ -77,7 +95,7 @@ export const useGetDiseaseAgents = () => { const diseaseAgentsData = DiseaseAgents.valueSetValues; setDiseaseAgents(diseaseAgentsData); }, []) - + return diseaseAgents; } @@ -113,7 +131,7 @@ export const useGetVaccines = () => { const vaccinesData = Vaccines.valueSetValues; setVaccines(vaccinesData); }, []) - + return vaccines; } diff --git a/src/assets/i18n/de/translation.json b/src/assets/i18n/de/translation.json index a4d5ebd..a9de796 100644 --- a/src/assets/i18n/de/translation.json +++ b/src/assets/i18n/de/translation.json @@ -9,6 +9,10 @@ "name": "Name", "standardised-name": "Standardisierter Familienname", "date-of-birth": "Geburtsdatum", + "date-of-birth-format": "Datumsformat Geburtsdatum", + "date-full": "komplettes Datum (yyyy-MM-dd)", + "date-no-day": "Jahr und Monat (yyyy-MM)", + "date-year": "Jahr (yyyy)", "patient-data-correction": "Patientendaten korrigieren", "process-finish": "Vorgang abschließen", "qr-code": "QR Code", @@ -60,34 +64,34 @@ "valid-to": "Zertifikat gültig bis", "pdfSurname": "Surname(s) and forename(s)", "pdfDateOfBirth": "Date of birth", - "pdfCi":"Unique certificate identifier", - "pdfGreenCertificate" : "EU Digital COVID Certificate", - "pdfMemberPlaceholder" : "Member State Placeholder", - "pdfInfoText" : "This certificate is not a travel document. The scientific evidence on COVID-19 vaccination, testing and recovery continues to evolve, also in view of new variants of concern of the virus. Before traveling, please check the applicable public health measures and related restrictions applied at the point of destination.", - "pdfRelevantInformation" : "Relevant information can be found here:", - "pdfInfoURL" : "https://reopen.europa.eu/en", - "pdfFoldingInstruction" : "Folding instructions", - "pdfHeaderVaccination" : "Vaccination certificate", - "pdfDisease" : "Disease or agent targeted", - "pdfVaccineProphylaxis" : "Vaccine/prophylaxis", - "pdfVaccineMedicalProduct" : "Vaccine medicinal product", - "pdfVaccineManufacturer" : "Vaccine marketing authorisation holder or manufacturer", - "pdfNumberOfDoses" : "Number in a series of vaccinations/doses and the overall number of doses in the series", - "pdfDateOfVaccination" : "Date of vaccination", - "pdfMemberStateOfVaccination" : "Member State of vaccination", - "pdfCertificateIssuer" : "Certificate issuer", - "pdfHeaderTest" : "Test Certificate", - "pdfTypeOfTest" : "Type of test", - "pdfTestName" : "Test name (optional for NAAT)", - "pdfTestManufacturer" : "Test manufacturer (optional for NAAT)", - "pdfDateSampleCollection" : "Date and time of the test sample collection", - "pdfDateTestResult" : "Date and time of the test result production (optional for RAT)", - "pdfTestResult" : "Result of the test", - "pdfTestingCentre" : "Testing centre or facility", - "pdfStateOfVaccination" : "Member State of vaccination", - "pdfHeaderRecovery" : "Certificate of Recovery", - "pdfDatePositiveTestResult" : "Date of first positive test result", - "pdfStateOfTest" : "Member State of test", - "pdfValidFrom" : "Certificate valid from", - "pdfValidTo" : "Certificate valid until (not more than 180 days after the date of first positive test result)" -} + "pdfCi": "Unique certificate identifier", + "pdfGreenCertificate": "EU Digital COVID Certificate", + "pdfMemberPlaceholder": "Member State Placeholder", + "pdfInfoText": "This certificate is not a travel document. The scientific evidence on COVID-19 vaccination, testing and recovery continues to evolve, also in view of new variants of concern of the virus. Before traveling, please check the applicable public health measures and related restrictions applied at the point of destination.", + "pdfRelevantInformation": "Relevant information can be found here:", + "pdfInfoURL": "https://reopen.europa.eu/en", + "pdfFoldingInstruction": "Folding instructions", + "pdfHeaderVaccination": "Vaccination certificate", + "pdfDisease": "Disease or agent targeted", + "pdfVaccineProphylaxis": "Vaccine/prophylaxis", + "pdfVaccineMedicalProduct": "Vaccine medicinal product", + "pdfVaccineManufacturer": "Vaccine marketing authorisation holder or manufacturer", + "pdfNumberOfDoses": "Number in a series of vaccinations/doses and the overall number of doses in the series", + "pdfDateOfVaccination": "Date of vaccination", + "pdfMemberStateOfVaccination": "Member State of vaccination", + "pdfCertificateIssuer": "Certificate issuer", + "pdfHeaderTest": "Test Certificate", + "pdfTypeOfTest": "Type of test", + "pdfTestName": "Test name (optional for NAAT)", + "pdfTestManufacturer": "Test manufacturer (optional for NAAT)", + "pdfDateSampleCollection": "Date and time of the test sample collection", + "pdfDateTestResult": "Date and time of the test result production (optional for RAT)", + "pdfTestResult": "Result of the test", + "pdfTestingCentre": "Testing centre or facility", + "pdfStateOfVaccination": "Member State of vaccination", + "pdfHeaderRecovery": "Certificate of Recovery", + "pdfDatePositiveTestResult": "Date of first positive test result", + "pdfStateOfTest": "Member State of test", + "pdfValidFrom": "Certificate valid from", + "pdfValidTo": "Certificate valid until (not more than 180 days after the date of first positive test result)" +} \ No newline at end of file diff --git a/src/assets/i18n/en/translation.json b/src/assets/i18n/en/translation.json index 3a0b4ae..a4141be 100644 --- a/src/assets/i18n/en/translation.json +++ b/src/assets/i18n/en/translation.json @@ -9,6 +9,10 @@ "name": "Family name", "standardised-name": "Standardised Family name", "date-of-birth": "Date of Birth", + "date-of-birth-format": "Date of Birth Format", + "date-full": "full date (yyyy-MM-dd)", + "date-no-day": "year and month (yyyy-MM)", + "date-year": "year only", "patient-data-correction": "Correct patient data", "process-finish": "Finish process", "next": "Next", diff --git a/src/components/modules/form-group.component.tsx b/src/components/modules/form-group.component.tsx index e7365b8..b18cd74 100644 --- a/src/components/modules/form-group.component.tsx +++ b/src/components/modules/form-group.component.tsx @@ -8,7 +8,7 @@ import utils from "../../misc/utils"; import DatePicker from "react-datepicker"; // import { registerLocale } from "react-datepicker"; import "react-datepicker/dist/react-datepicker.css"; -import { IValueSet } from "../../api"; +import { IValueSet, useGetDateFormats } from "../../api"; const iso3311a2 = require('iso-3166-1-alpha-2'); @@ -19,6 +19,7 @@ export interface IPersonData { standardisedGivenName?: string; standardisedFamilyName: string; dateOfBirth: Date | undefined; + dobFormat: string; } export const FormGroupInput = (props: any) => { @@ -96,8 +97,8 @@ export const FormGroupISOCountrySelect = (props: any) => { const options: JSX.Element[] = []; // const codes: string[] = iso3311a2.getCodes().sort(); const eu_country_codes: string[] = ["AT", "BE", "BG", "HR", "CY", "CZ", "DK", "EE", "FI", "FR", - "DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL", "PL", - "PT", "RO", "SK", "SI", "ES", "SE"].sort(); + "DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL", "PL", + "PT", "RO", "SK", "SI", "ES", "SE"].sort(); for (const code of eu_country_codes) { options.push() @@ -139,7 +140,7 @@ export const PersonInputs = (props: any) => { const [standardisedFamilyName, setStandardisedFamilyName] = React.useState(''); const [dateOfBirth, setDateOfBirth] = React.useState(); - + const [dateFormat, setDateFormat] = React.useState('yyyy-MM-dd'); React.useEffect(() => { if (props && props.eudgc && props.eudgc.nam) { @@ -169,7 +170,8 @@ export const PersonInputs = (props: any) => { familyName: familyName ? familyName : undefined, standardisedGivenName: standardisedGivenName ? standardisedGivenName : undefined, standardisedFamilyName: standardisedFamilyName, - dateOfBirth: dateOfBirth + dateOfBirth: dateOfBirth, + dobFormat: dateFormat } props.onChange(result); @@ -244,6 +246,15 @@ export const PersonInputs = (props: any) => {
+ {/* date of birth format */} + setDateFormat(evt.target.value)} + valueSet={useGetDateFormats} + required + /> + + {/* date of birth input */} {t('translation:date-of-birth') + '*'} @@ -252,7 +263,7 @@ export const PersonInputs = (props: any) => { { gn: person!.givenName, gnt: person!.standardisedGivenName }, - dob: person!.dateOfBirth!.toISOString().split('T')[0], + dob: moment(person!.dateOfBirth!) + .format(person!.dobFormat === 'yyyy-MM-dd' ? 'yyyy-MM-DD' : person!.dobFormat), r: [r] } diff --git a/src/components/record-test-cert-data.component.tsx b/src/components/record-test-cert-data.component.tsx index 5ec5837..4aa9b6e 100644 --- a/src/components/record-test-cert-data.component.tsx +++ b/src/components/record-test-cert-data.component.tsx @@ -41,6 +41,7 @@ import CardHeader from './modules/card-header.component'; import { FormGroupInput, FormGroupISOCountrySelect, FormGroupValueSetSelect, IPersonData, PersonInputs } from './modules/form-group.component'; import CardFooter from './modules/card-footer.component'; import useLocalStorage from '../misc/local-storage'; +import moment from 'moment'; const validator = new Validator(); @@ -165,15 +166,14 @@ const RecordTestCertData = (props: any) => { gn: person!.givenName, gnt: person!.standardisedGivenName }, - dob: person!.dateOfBirth!.toISOString().split('T')[0], + dob: moment(person!.dateOfBirth!) + .format(person!.dobFormat === 'yyyy-MM-dd' ? 'yyyy-MM-DD' : person!.dobFormat), t: [test] } var result = validator.validate(eudgc, schema); if (result.valid) { - // console.log(JSON.stringify(eudgc)); - props.setEudgc(eudgc); setTimeout(navigation!.toShowCert, 200); } diff --git a/src/components/record-vaccination-cert-data.component.tsx b/src/components/record-vaccination-cert-data.component.tsx index c8213f3..cabd2b8 100644 --- a/src/components/record-vaccination-cert-data.component.tsx +++ b/src/components/record-vaccination-cert-data.component.tsx @@ -40,6 +40,7 @@ import { Validator } from 'jsonschema'; import CardHeader from './modules/card-header.component'; import { PersonInputs, IPersonData, FormGroupInput, FormGroupValueSetSelect, FormGroupISOCountrySelect } from './modules/form-group.component'; import CardFooter from './modules/card-footer.component'; +import moment from 'moment'; const validator = new Validator(); @@ -154,7 +155,8 @@ const RecordVaccinationCertData = (props: any) => { gn: person!.givenName, gnt: person!.standardisedGivenName }, - dob: person!.dateOfBirth!.toISOString().split('T')[0], + dob: moment(person!.dateOfBirth!) + .format(person!.dobFormat === 'yyyy-MM-dd' ? 'yyyy-MM-DD' : person!.dobFormat), v: [vacc] } @@ -246,7 +248,7 @@ const RecordVaccinationCertData = (props: any) => { /> {/* vacLastDate */} - + {t('translation:vac-last-date') + '*'} diff --git a/src/generated-files/DGC.combined-schema.json b/src/generated-files/DGC.combined-schema.json index 7c9d94c..6500bbf 100644 --- a/src/generated-files/DGC.combined-schema.json +++ b/src/generated-files/DGC.combined-schema.json @@ -28,8 +28,8 @@ "title": "Date of birth", "description": "Date of Birth of the person addressed in the DGC. ISO 8601 date format restricted to range 1900-2099", "type": "string", - "format": "date", - "pattern": "(19|20)\\d{2}-\\d{2}-\\d{2}", + "format": "string", + "pattern": "(19|20)\\d{2}(-\\d{2})?(-\\d{2})?", "examples": [ "1979-04-14" ]