From 556079fb43fb27d60be1570523a9d67eb01e8369 Mon Sep 17 00:00:00 2001 From: alaa-yahia Date: Thu, 5 Dec 2024 00:14:05 +0200 Subject: [PATCH 01/10] feat: enable non gregorian calendars in views and lists --- package.json | 3 +- src/components/AppLoader/init.js | 4 +-- .../configs/dateField/getDateFieldConfig.js | 3 +- .../getDateFieldConfigForCustomForm.js | 3 +- .../EnrollmentDataEntry.component.js | 7 +++-- .../DateAndTime/D2Date/D2Date.component.js | 4 +-- .../capture-core/converters/clientToForm.js | 11 ++++---- .../capture-core/converters/clientToList.js | 10 ++++--- .../capture-core/converters/clientToView.js | 12 +++++--- .../capture-core/converters/formToClient.js | 19 +++++++++---- .../metaData/SystemSettings/SystemSettings.js | 1 + .../systemSettings/cacheSystemSetttings.js | 6 +++- .../date/convertIsoToLocalCalendar.js | 28 +++++++++++++++++++ .../date/convertLocalToIsoCalendar.js | 26 +++++++++++++++++ .../date/dateObjectToDateFormatString.js | 10 +++---- .../utils/converters/date/index.js | 3 ++ .../utils/converters/date/padWithZeros.js | 12 ++++++++ .../DateField/Date.component.js | 9 ++---- yarn.lock | 2 +- 19 files changed, 129 insertions(+), 44 deletions(-) create mode 100644 src/core_modules/capture-core/utils/converters/date/convertIsoToLocalCalendar.js create mode 100644 src/core_modules/capture-core/utils/converters/date/convertLocalToIsoCalendar.js create mode 100644 src/core_modules/capture-core/utils/converters/date/padWithZeros.js diff --git a/package.json b/package.json index 508cea0cfd..9d0350a1fb 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "packages/rules-engine" ], "dependencies": { - "@dhis2/rules-engine-javascript": "101.19.1", + "@dhis2-ui/calendar": "^10.0.3", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", "@dhis2/d2-icons": "^1.0.1", @@ -19,7 +19,6 @@ "@dhis2/d2-ui-rich-text": "^7.4.0", "@dhis2/d2-ui-sharing-dialog": "^7.3.3", "@dhis2/ui": "^9.10.1", - "@dhis2-ui/calendar": "^10.0.3", "@joakim_sm/react-infinite-calendar": "^2.4.2", "@material-ui/core": "3.9.4", "@material-ui/icons": "3", diff --git a/src/components/AppLoader/init.js b/src/components/AppLoader/init.js index f7106fabc4..de3a3153fc 100644 --- a/src/components/AppLoader/init.js +++ b/src/components/AppLoader/init.js @@ -131,7 +131,7 @@ async function initializeMetaDataAsync(dbLocale: string, onQueryApi: Function, m async function initializeSystemSettingsAsync( uiLocale: string, - systemSettings: { dateFormat: string, serverTimeZoneId: string }, + systemSettings: { dateFormat: string, serverTimeZoneId: string, calendar: string, }, ) { const systemSettingsCacheData = await cacheSystemSettings(uiLocale, systemSettings); await buildSystemSettingsAsync(systemSettingsCacheData); @@ -158,7 +158,7 @@ export async function initializeAsync( const systemSettings = await onQueryApi({ resource: 'system/info', params: { - fields: 'dateFormat,serverTimeZoneId', + fields: 'dateFormat,serverTimeZoneId,calendar', }, }); diff --git a/src/core_modules/capture-core/components/D2Form/field/configs/dateField/getDateFieldConfig.js b/src/core_modules/capture-core/components/D2Form/field/configs/dateField/getDateFieldConfig.js index 7c6f480ae7..7415bd7d5f 100644 --- a/src/core_modules/capture-core/components/D2Form/field/configs/dateField/getDateFieldConfig.js +++ b/src/core_modules/capture-core/components/D2Form/field/configs/dateField/getDateFieldConfig.js @@ -2,6 +2,7 @@ import moment from 'moment'; import { createFieldConfig, createProps } from '../base/configBaseDefaultForm'; import { DateFieldForForm } from '../../Components'; +import { convertDateObjectToDateFormatString } from '../../../../../../capture-core/utils/converters/date'; import type { DateDataElement } from '../../../../../metaData'; import type { QuerySingleResource } from '../../../../../utils/api/api.types'; @@ -15,7 +16,7 @@ export const getDateFieldConfig = (metaData: DateDataElement, options: Object, q maxWidth: options.formHorizontal ? 150 : 350, calendarWidth: options.formHorizontal ? 250 : 350, popupAnchorPosition: getCalendarAnchorPosition(options.formHorizontal), - calendarMaxMoment: !metaData.allowFutureDate ? moment() : undefined, + calendarMaxMoment: !metaData.allowFutureDate ? convertDateObjectToDateFormatString(moment()) : undefined, }, options, metaData); return createFieldConfig({ diff --git a/src/core_modules/capture-core/components/D2Form/field/configs/dateField/getDateFieldConfigForCustomForm.js b/src/core_modules/capture-core/components/D2Form/field/configs/dateField/getDateFieldConfigForCustomForm.js index b1b93fe119..8cb139fb73 100644 --- a/src/core_modules/capture-core/components/D2Form/field/configs/dateField/getDateFieldConfigForCustomForm.js +++ b/src/core_modules/capture-core/components/D2Form/field/configs/dateField/getDateFieldConfigForCustomForm.js @@ -2,6 +2,7 @@ import moment from 'moment'; import { createFieldConfig, createProps } from '../base/configBaseCustomForm'; import { DateFieldForCustomForm } from '../../Components'; +import { convertDateObjectToDateFormatString } from '../../../../../../capture-core/utils/converters/date'; import type { DateDataElement } from '../../../../../metaData'; import type { QuerySingleResource } from '../../../../../utils/api/api.types'; @@ -10,7 +11,7 @@ export const getDateFieldConfigForCustomForm = (metaData: DateDataElement, optio width: 350, maxWidth: 350, calendarWidth: 350, - calendarMaxMoment: !metaData.allowFutureDate ? moment() : undefined, + calendarMaxMoment: !metaData.allowFutureDate ? convertDateObjectToDateFormatString(moment()) : undefined, }, metaData); return createFieldConfig({ diff --git a/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentDataEntry.component.js b/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentDataEntry.component.js index 1444a98aea..76ed900ccc 100644 --- a/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentDataEntry.component.js +++ b/src/core_modules/capture-core/components/DataEntries/Enrollment/EnrollmentDataEntry.component.js @@ -42,6 +42,7 @@ import { withAOCFieldBuilder, withDataEntryFields, } from '../../DataEntryDhis2Helpers'; +import { convertDateObjectToDateFormatString } from '../../../../capture-core/utils/converters/date'; const overrideMessagePropNames = { errorMessage: 'validationError', @@ -111,7 +112,7 @@ const getEnrollmentDateSettings = () => { required: true, calendarWidth: props.formHorizontal ? 250 : 350, popupAnchorPosition: getCalendarAnchorPosition(props.formHorizontal), - calendarMaxMoment: !props.enrollmentMetadata.allowFutureEnrollmentDate ? moment() : undefined, + calendarMaxMoment: !props.enrollmentMetadata.allowFutureEnrollmentDate ? convertDateObjectToDateFormatString(moment()) : undefined, }), getPropName: () => 'enrolledAt', getValidatorContainers: getEnrollmentDateValidatorContainer, @@ -159,7 +160,9 @@ const getIncidentDateSettings = () => { required: true, calendarWidth: props.formHorizontal ? 250 : 350, popupAnchorPosition: getCalendarAnchorPosition(props.formHorizontal), - calendarMaxMoment: !props.enrollmentMetadata.allowFutureIncidentDate ? moment() : undefined, + calendarMaxMoment: !props.enrollmentMetadata.allowFutureIncidentDate ? + convertDateObjectToDateFormatString(moment()) : + undefined, }), getPropName: () => 'occurredAt', getPassOnFieldData: () => true, diff --git a/src/core_modules/capture-core/components/FormFields/DateAndTime/D2Date/D2Date.component.js b/src/core_modules/capture-core/components/FormFields/DateAndTime/D2Date/D2Date.component.js index eacca0a466..2adb875ce7 100644 --- a/src/core_modules/capture-core/components/FormFields/DateAndTime/D2Date/D2Date.component.js +++ b/src/core_modules/capture-core/components/FormFields/DateAndTime/D2Date/D2Date.component.js @@ -7,7 +7,6 @@ import { type DateValue } from '../../../FiltersForTypes/Date/types/date.types'; type Props = { label?: ?string, value: ?string, - calendar?: string, calendarWidth?: ?number, inputWidth?: ?number, onBlur: (value: DateValue) => void, @@ -50,7 +49,6 @@ export class D2Date extends React.Component { render() { const { - calendar, calendarWidth, inputWidth, classes, @@ -62,7 +60,7 @@ export class D2Date extends React.Component { ...passOnProps } = this.props; - const calendarType = calendar || 'gregory'; + const calendarType = systemSettingsStore.get().calendar || 'gregory'; const format = systemSettingsStore.get().dateFormat; return ( diff --git a/src/core_modules/capture-core/converters/clientToForm.js b/src/core_modules/capture-core/converters/clientToForm.js index f8e227b6d9..606b7e3f04 100644 --- a/src/core_modules/capture-core/converters/clientToForm.js +++ b/src/core_modules/capture-core/converters/clientToForm.js @@ -1,6 +1,6 @@ // @flow import moment from 'moment'; -import { convertMomentToDateFormatString } from '../utils/converters/date'; +import { convertMomentToDateFormatString, convertIsoToLocalCalendar } from '../utils/converters/date'; import { dataElementTypes } from '../metaData'; import { stringifyNumber } from './common/stringifyNumber'; @@ -23,16 +23,17 @@ type RangeValue = { } function convertDateForEdit(rawValue: string): string { - const momentInstance = moment(rawValue); - return convertMomentToDateFormatString(momentInstance); + const momentDate = moment(rawValue); + const dateString = momentDate.format('YYYY-MM-DD'); + return convertIsoToLocalCalendar(dateString); } function convertDateTimeForEdit(rawValue: string): DateTimeFormValue { const dateTime = moment(rawValue); - const dateString = convertMomentToDateFormatString(dateTime); + const dateString = dateTime.format('YYYY-MM-DD'); const timeString = dateTime.format('HH:mm'); return { - date: dateString, + date: convertIsoToLocalCalendar(dateString), time: timeString, }; } diff --git a/src/core_modules/capture-core/converters/clientToList.js b/src/core_modules/capture-core/converters/clientToList.js index e72b837179..6ee3cb78a7 100644 --- a/src/core_modules/capture-core/converters/clientToList.js +++ b/src/core_modules/capture-core/converters/clientToList.js @@ -5,21 +5,23 @@ import i18n from '@dhis2/d2-i18n'; import { Tag } from '@dhis2/ui'; import { PreviewImage } from 'capture-ui'; import { dataElementTypes, type DataElement } from '../metaData'; -import { convertMomentToDateFormatString } from '../utils/converters/date'; +import { convertIsoToLocalCalendar } from '../utils/converters/date'; import { stringifyNumber } from './common/stringifyNumber'; import { MinimalCoordinates } from '../components/MinimalCoordinates'; import { TooltipOrgUnit } from '../components/Tooltips/TooltipOrgUnit'; function convertDateForListDisplay(rawValue: string): string { const momentDate = moment(rawValue); - return convertMomentToDateFormatString(momentDate); + const dateString = momentDate.format('YYYY-MM-DD'); + return convertIsoToLocalCalendar(dateString); } function convertDateTimeForListDisplay(rawValue: string): string { const momentDate = moment(rawValue); - const dateString = convertMomentToDateFormatString(momentDate); + const dateString = momentDate.format('YYYY-MM-DD'); const timeString = momentDate.format('HH:mm'); - return `${dateString} ${timeString}`; + const localDate = convertIsoToLocalCalendar(dateString); + return `${localDate} ${timeString}`; } function convertTimeForListDisplay(rawValue: string): string { diff --git a/src/core_modules/capture-core/converters/clientToView.js b/src/core_modules/capture-core/converters/clientToView.js index fb7728f723..6f4e2b7e14 100644 --- a/src/core_modules/capture-core/converters/clientToView.js +++ b/src/core_modules/capture-core/converters/clientToView.js @@ -4,7 +4,7 @@ import moment from 'moment'; import i18n from '@dhis2/d2-i18n'; import { PreviewImage } from 'capture-ui'; import { dataElementTypes, type DataElement } from '../metaData'; -import { convertMomentToDateFormatString } from '../utils/converters/date'; +import { convertIsoToLocalCalendar } from '../utils/converters/date'; import { stringifyNumber } from './common/stringifyNumber'; import { MinimalCoordinates } from '../components/MinimalCoordinates'; import { TooltipOrgUnit } from '../components/Tooltips/TooltipOrgUnit'; @@ -12,14 +12,18 @@ import { TooltipOrgUnit } from '../components/Tooltips/TooltipOrgUnit'; function convertDateForView(rawValue: string): string { const momentDate = moment(rawValue); - return convertMomentToDateFormatString(momentDate); + const dateString = momentDate.format('YYYY-MM-DD'); + return convertIsoToLocalCalendar(dateString); } function convertDateTimeForView(rawValue: string): string { const momentDate = moment(rawValue); - const dateString = convertMomentToDateFormatString(momentDate); + const dateString = momentDate.format('YYYY-MM-DD'); const timeString = momentDate.format('HH:mm'); - return `${dateString} ${timeString}`; + + const localDate = convertIsoToLocalCalendar(dateString); + return `${localDate} ${timeString}`; } + function convertTimeForView(rawValue: string): string { const momentDate = moment(rawValue, 'HH:mm', true); return momentDate.format('HH:mm'); diff --git a/src/core_modules/capture-core/converters/formToClient.js b/src/core_modules/capture-core/converters/formToClient.js index 61c286d4d2..61b37923fd 100644 --- a/src/core_modules/capture-core/converters/formToClient.js +++ b/src/core_modules/capture-core/converters/formToClient.js @@ -1,8 +1,9 @@ // @flow +import moment from 'moment'; import isString from 'd2-utilizr/lib/isString'; import { parseNumber, parseTime } from 'capture-core-utils/parsers'; import { dataElementTypes } from '../metaData'; -import { parseDate } from '../utils/converters/date'; +import { parseDate, convertLocalToIsoCalendar } from '../utils/converters/date'; type DateTimeValue = { date: string, @@ -25,9 +26,11 @@ function convertDateTime(formValue: DateTimeValue): ?string { const minutes = momentTime.minute(); const parsedDate = editedDate ? parseDate(editedDate) : null; - if (!(parsedDate && parsedDate.isValid)) return null; - // $FlowFixMe[incompatible-type] automated comment - const momentDateTime: moment$Moment = parsedDate.momentDate; + if (!(parsedDate && parsedDate.isValid && parsedDate.momentDate)) return null; + + const formattedDate = parsedDate.momentDate.format('YYYY-MM-DD'); + const isoDate = convertLocalToIsoCalendar(formattedDate); + const momentDateTime = moment(isoDate); momentDateTime.hour(hours); momentDateTime.minute(minutes); return momentDateTime.toISOString(); @@ -35,8 +38,12 @@ function convertDateTime(formValue: DateTimeValue): ?string { function convertDate(dateValue: string) { const parsedDate = parseDate(dateValue); - // $FlowFixMe[incompatible-use] automated comment - return parsedDate.isValid ? parsedDate.momentDate.toISOString() : null; + if (!parsedDate.isValid || !parsedDate.momentDate) { + return null; + } + const formattedDate = parsedDate.momentDate.format('YYYY-MM-DD'); + + return convertLocalToIsoCalendar(formattedDate); } function convertTime(timeValue: string) { diff --git a/src/core_modules/capture-core/metaData/SystemSettings/SystemSettings.js b/src/core_modules/capture-core/metaData/SystemSettings/SystemSettings.js index 6231d3b637..ec8334b437 100644 --- a/src/core_modules/capture-core/metaData/SystemSettings/SystemSettings.js +++ b/src/core_modules/capture-core/metaData/SystemSettings/SystemSettings.js @@ -4,4 +4,5 @@ export class SystemSettings { dateFormat: string; dir: string; trackerAppRelativePath: string; + calendar: string; } diff --git a/src/core_modules/capture-core/metaDataStoreLoaders/systemSettings/cacheSystemSetttings.js b/src/core_modules/capture-core/metaDataStoreLoaders/systemSettings/cacheSystemSetttings.js index 7ff99e54aa..225c4261ab 100644 --- a/src/core_modules/capture-core/metaDataStoreLoaders/systemSettings/cacheSystemSetttings.js +++ b/src/core_modules/capture-core/metaDataStoreLoaders/systemSettings/cacheSystemSetttings.js @@ -10,7 +10,7 @@ function isLangRTL(code) { export async function cacheSystemSettings( uiLocale: string, - systemSettings: { dateFormat: string, serverTimeZoneId: string }, + systemSettings: { dateFormat: string, serverTimeZoneId: string, calendar: string, }, ) { const systemSettingsArray = [ { @@ -25,6 +25,10 @@ export async function cacheSystemSettings( id: 'serverTimeZoneId', value: systemSettings.serverTimeZoneId, }, + { + id: 'calendar', + value: systemSettings.calendar, + }, ]; const storageController = getMainStorageController(); diff --git a/src/core_modules/capture-core/utils/converters/date/convertIsoToLocalCalendar.js b/src/core_modules/capture-core/utils/converters/date/convertIsoToLocalCalendar.js new file mode 100644 index 0000000000..3f9f99e34b --- /dev/null +++ b/src/core_modules/capture-core/utils/converters/date/convertIsoToLocalCalendar.js @@ -0,0 +1,28 @@ +// @flow +import { + convertFromIso8601, +} from '@dhis2/multi-calendar-dates'; +import { systemSettingsStore } from '../../../../capture-core/metaDataMemoryStores'; +import { padWithZeros } from './padWithZeros'; + +/** + * Converts a date from ISO calendar to local calendar + * @export + * @param {string} isoDate - date in ISO format + * @returns {string} + */ + +export function convertIsoToLocalCalendar(isoDate: string): string { + if (!isoDate) { + return ''; + } + const calendar = systemSettingsStore.get().calendar; + const dateFormat = systemSettingsStore.get().dateFormat; + + const { year, eraYear, month, day } = convertFromIso8601(isoDate, calendar); + const localYear = calendar === 'ethiopian' ? eraYear : year; + + return dateFormat === 'DD-MM-YYYY' + ? `${padWithZeros(day, 2)}-${padWithZeros(month, 2)}-${padWithZeros(localYear, 4)}` + : `${padWithZeros(localYear, 4)}-${padWithZeros(month, 2)}-${padWithZeros(day, 2)}`; +} diff --git a/src/core_modules/capture-core/utils/converters/date/convertLocalToIsoCalendar.js b/src/core_modules/capture-core/utils/converters/date/convertLocalToIsoCalendar.js new file mode 100644 index 0000000000..99b1215919 --- /dev/null +++ b/src/core_modules/capture-core/utils/converters/date/convertLocalToIsoCalendar.js @@ -0,0 +1,26 @@ +// @flow +import moment from 'moment'; +import { + convertToIso8601, +} from '@dhis2/multi-calendar-dates'; +import { systemSettingsStore } from '../../../../capture-core/metaDataMemoryStores'; +import { padWithZeros } from './padWithZeros'; + +/** + * Converts a date from local calendar to ISO calendar + * @export + * @param {string} localDate - date in local calendar format + * @returns {string} + */ +export function convertLocalToIsoCalendar(localDate: string): string { + if (!localDate) { + return ''; + } + const calendar = systemSettingsStore.get().calendar; + + const { year, month, day } = convertToIso8601(localDate, calendar); + const dateString = `${padWithZeros(year, 4)}-${padWithZeros(month, 2)}-${padWithZeros(day, 2)}`; + const parsedMoment = moment(dateString); + + return parsedMoment.isValid() ? parsedMoment.toISOString() : ''; +} diff --git a/src/core_modules/capture-core/utils/converters/date/dateObjectToDateFormatString.js b/src/core_modules/capture-core/utils/converters/date/dateObjectToDateFormatString.js index de59f62d24..bbe748a579 100644 --- a/src/core_modules/capture-core/utils/converters/date/dateObjectToDateFormatString.js +++ b/src/core_modules/capture-core/utils/converters/date/dateObjectToDateFormatString.js @@ -1,6 +1,6 @@ // @flow import moment from 'moment'; -import { systemSettingsStore } from '../../../metaDataMemoryStores'; +import { convertIsoToLocalCalendar } from './convertIsoToLocalCalendar'; /** * Converts a date instance to a string based on the system date format @@ -8,8 +8,8 @@ import { systemSettingsStore } from '../../../metaDataMemoryStores'; * @param {Date} dateValue: the date instance * @returns {string} */ -export function convertDateObjectToDateFormatString(dateValue: Date) { - const dateFormat = systemSettingsStore.get().dateFormat; - const formattedDateString = moment(dateValue).format(dateFormat); - return formattedDateString; +export function convertDateObjectToDateFormatString(dateValue: Date | moment$Moment) { + const momentDate = moment(dateValue); + const dateString = momentDate.format('YYYY-MM-DD'); + return convertIsoToLocalCalendar(dateString); } diff --git a/src/core_modules/capture-core/utils/converters/date/index.js b/src/core_modules/capture-core/utils/converters/date/index.js index f7e46c2971..511298b89d 100644 --- a/src/core_modules/capture-core/utils/converters/date/index.js +++ b/src/core_modules/capture-core/utils/converters/date/index.js @@ -3,3 +3,6 @@ export { parseDate } from './parser'; export { convertDateObjectToDateFormatString } from './dateObjectToDateFormatString'; export { convertMomentToDateFormatString } from './momentToDateFormatString'; export { convertStringToDateFormat } from './stringToMomentDateFormat'; +export { padWithZeros } from './padWithZeros'; +export { convertIsoToLocalCalendar } from './convertIsoToLocalCalendar'; +export { convertLocalToIsoCalendar } from './convertLocalToIsoCalendar'; diff --git a/src/core_modules/capture-core/utils/converters/date/padWithZeros.js b/src/core_modules/capture-core/utils/converters/date/padWithZeros.js new file mode 100644 index 0000000000..5edc85befd --- /dev/null +++ b/src/core_modules/capture-core/utils/converters/date/padWithZeros.js @@ -0,0 +1,12 @@ +// @flow + +/** + * Pads a string or number with zeros at the start to reach a minimum length + * @export + * @param {string|number} value - the value to pad + * @param {number} length - length required + * @returns {string} + */ +export function padWithZeros(value: string | number, length: number): string { + return String(value).padStart(length, '0'); +} diff --git a/src/core_modules/capture-ui/DateAndTimeFields/DateField/Date.component.js b/src/core_modules/capture-ui/DateAndTimeFields/DateField/Date.component.js index b48ee77ae5..95bf289714 100644 --- a/src/core_modules/capture-ui/DateAndTimeFields/DateField/Date.component.js +++ b/src/core_modules/capture-ui/DateAndTimeFields/DateField/Date.component.js @@ -18,7 +18,6 @@ type Props = { onBlur: (value: Object, options: ValidationOptions) => void, onFocus?: ?() => void, onDateSelectedFromCalendar?: () => void, - calendar?: string, placeholder?: string, label?: string, calendarMaxMoment?: any, @@ -36,9 +35,6 @@ type State = { calendarError: ?Validation, }; -const formatDate = (date: any, dateFormat: string): ?string => - (dateFormat === 'dd-MM-yyyy' ? date?.format('DD-MM-YYYY') : date?.format('YYYY-MM-DD')); - export class DateField extends React.Component { handleDateSelected: (value: {calendarDateString: string}) => void; @@ -65,7 +61,6 @@ export class DateField extends React.Component { maxWidth, calendarWidth, inputWidth, - calendar, calendarMaxMoment, value, innerMessage, @@ -73,7 +68,7 @@ export class DateField extends React.Component { const calculatedInputWidth = inputWidth || width; const calculatedCalendarWidth = calendarWidth || width; - const calendarType = calendar || 'gregory'; + const calendarType = systemSettingsStore.get().calendar || 'gregory'; const format = systemSettingsStore.get().dateFormat; const errorProps = innerMessage && innerMessage.messageType === 'error' ? { error: !!innerMessage.message?.dateInnerErrorMessage, @@ -99,7 +94,7 @@ export class DateField extends React.Component { onFocus={this.props.onFocus} disabled={this.props.disabled} {...errorProps} - maxDate={calendarMaxMoment && formatDate(calendarMaxMoment, format)} + maxDate={calendarMaxMoment} /> ); diff --git a/yarn.lock b/yarn.lock index 4c2c7b3910..9a8bd281de 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2718,7 +2718,7 @@ recompose "^0.26.0" rxjs "^5.5.7" -"@dhis2/multi-calendar-dates@2.0.0": +"@dhis2/multi-calendar-dates@2.0.0", "@dhis2/multi-calendar-dates@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@dhis2/multi-calendar-dates/-/multi-calendar-dates-2.0.0.tgz#febf04f873670960804d38c9ebaa1cadf8050db3" integrity sha512-pxu81kkkh70tB+CyAub41ulpNJPHyxDGwH2pdcc+NUqrKu4OTQr5ScdCBL2MndShrEKj9J6qj9zKVagvvymH5w== From 0294f8da478e4ebc5c437a7c9f48542102d32ade Mon Sep 17 00:00:00 2001 From: alaa-yahia Date: Thu, 5 Dec 2024 01:36:14 +0200 Subject: [PATCH 02/10] fix: working list filters to use gregorian --- .../Date/DateFilter.component.js | 28 +++++++++++++++---- .../date/convertIsoToLocalCalendar.js | 2 +- .../date/convertLocalToIsoCalendar.js | 2 +- .../date/dateObjectToDateFormatString.js | 2 +- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js b/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js index c326e4477b..5c995df0d1 100644 --- a/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js +++ b/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js @@ -1,6 +1,7 @@ // @flow import React, { Component } from 'react'; import classNames from 'classnames'; +import moment from 'moment'; import { withStyles } from '@material-ui/core/styles'; import i18n from '@dhis2/d2-i18n'; import { isValidZeroOrPositiveInteger } from 'capture-core-utils/validators/form'; @@ -16,7 +17,8 @@ import './calendarFilterStyles.css'; import { mainOptionKeys, mainOptionTranslatedTexts } from './options'; import { getDateFilterData } from './dateFilterDataGetter'; import { RangeFilter } from './RangeFilter.component'; -import { parseDate } from '../../../utils/converters/date'; +import { parseDate, convertLocalToIsoCalendar, convertIsoToLocalCalendar } from '../../../utils/converters/date'; +import { systemSettingsStore } from '../../../metaDataMemoryStores'; const getStyles = (theme: Theme) => ({ fromToContainer: { @@ -257,12 +259,28 @@ class DateFilterPlain extends Component implements UpdatableFilter return !values || DateFilter.isFilterValid(values.main, values.from, values.to, values.start, values.end); } - getUpdatedValue(valuePart: { [key: string]: string }) { - // $FlowFixMe[cannot-spread-indexer] automated comment + // eslint-disable-next-line complexity + getUpdatedValue(valuePart: Object) { const valueObject = { ...this.props.value, ...valuePart, }; + const dateFormat = systemSettingsStore.get().dateFormat; + + if (valuePart.from && valueObject?.from?.value) { + valueObject.from = { + ...valueObject.from, + value: moment(convertLocalToIsoCalendar(valueObject.from.value)).format(dateFormat), + }; + } + + if (valuePart.to && valueObject?.to?.value) { + valueObject.to = { + ...valueObject.to, + value: moment(convertLocalToIsoCalendar(valueObject.to.value)).format(dateFormat), + }; + } + const isRelativeRangeValue = () => valueObject?.start || valuePart?.start || valuePart?.end; const isAbsoluteRangevalue = () => valueObject?.from || valuePart?.from || valuePart?.to; @@ -358,7 +376,7 @@ class DateFilterPlain extends Component implements UpdatableFilter {/* $FlowSuppress: Flow not working 100% with HOCs */} {/* $FlowFixMe[prop-missing] automated comment */} implements UpdatableFilter {/* $FlowSuppress: Flow not working 100% with HOCs */} {/* $FlowFixMe[prop-missing] automated comment */} Date: Tue, 10 Dec 2024 14:18:33 +0200 Subject: [PATCH 03/10] fix: working list filter runtime error when dd-mm-yyyy format is passed --- .../converters/date/convertIsoToLocalCalendar.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/core_modules/capture-core/utils/converters/date/convertIsoToLocalCalendar.js b/src/core_modules/capture-core/utils/converters/date/convertIsoToLocalCalendar.js index 019872c197..442ad4a60c 100644 --- a/src/core_modules/capture-core/utils/converters/date/convertIsoToLocalCalendar.js +++ b/src/core_modules/capture-core/utils/converters/date/convertIsoToLocalCalendar.js @@ -1,4 +1,5 @@ // @flow +import moment from 'moment'; import { convertFromIso8601, } from '@dhis2/multi-calendar-dates'; @@ -16,10 +17,18 @@ export function convertIsoToLocalCalendar(isoDate: ?string): string { if (!isoDate) { return ''; } + + const momentDate = moment(isoDate); + if (!momentDate.isValid()) { + return ''; + } + + const formattedIsoDate = momentDate.format('YYYY-MM-DD'); + const calendar = systemSettingsStore.get().calendar; const dateFormat = systemSettingsStore.get().dateFormat; - const { year, eraYear, month, day } = convertFromIso8601(isoDate, calendar); + const { year, eraYear, month, day } = convertFromIso8601(formattedIsoDate, calendar); const localYear = calendar === 'ethiopian' ? eraYear : year; return dateFormat === 'DD-MM-YYYY' From fa4ee1b265b602bf5ec6feda96a52ffbea5fc138 Mon Sep 17 00:00:00 2001 From: alaa-yahia Date: Wed, 11 Dec 2024 11:27:52 +0200 Subject: [PATCH 04/10] fix: missing rules engine in dependencies --- package.json | 1 + yarn.lock | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 9d0350a1fb..a3f8ab4ebd 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "packages/rules-engine" ], "dependencies": { + "@dhis2/rules-engine-javascript": "101.19.1", "@dhis2-ui/calendar": "^10.0.3", "@dhis2/app-runtime": "^3.9.3", "@dhis2/d2-i18n": "^1.1.0", diff --git a/yarn.lock b/yarn.lock index 9a8bd281de..4c2c7b3910 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2718,7 +2718,7 @@ recompose "^0.26.0" rxjs "^5.5.7" -"@dhis2/multi-calendar-dates@2.0.0", "@dhis2/multi-calendar-dates@^2.0.0": +"@dhis2/multi-calendar-dates@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@dhis2/multi-calendar-dates/-/multi-calendar-dates-2.0.0.tgz#febf04f873670960804d38c9ebaa1cadf8050db3" integrity sha512-pxu81kkkh70tB+CyAub41ulpNJPHyxDGwH2pdcc+NUqrKu4OTQr5ScdCBL2MndShrEKj9J6qj9zKVagvvymH5w== From 9f6b081b190a736cbfa8189475e99373a6492156 Mon Sep 17 00:00:00 2001 From: alaa-yahia Date: Wed, 11 Dec 2024 13:13:00 +0200 Subject: [PATCH 05/10] fix: working list filter not displaying local date --- .../buttonTextBuilder/converters/dateConverter.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/core_modules/capture-core/components/ListView/Filters/FilterButton/buttonTextBuilder/converters/dateConverter.js b/src/core_modules/capture-core/components/ListView/Filters/FilterButton/buttonTextBuilder/converters/dateConverter.js index 4dce8ba7a9..adbc7c367d 100644 --- a/src/core_modules/capture-core/components/ListView/Filters/FilterButton/buttonTextBuilder/converters/dateConverter.js +++ b/src/core_modules/capture-core/components/ListView/Filters/FilterButton/buttonTextBuilder/converters/dateConverter.js @@ -6,6 +6,8 @@ import { convertMomentToDateFormatString } from '../../../../../../utils/convert import type { DateFilterData, AbsoluteDateFilterData } from '../../../../../FiltersForTypes'; import { areRelativeRangeValuesSupported } from '../../../../../../utils/validation/validators/areRelativeRangeValuesSupported'; +import { convertClientToView } from '../../../../../../../capture-core/converters'; +import { dataElementTypes } from '../../../../../../metaData'; const periods = { TODAY: 'TODAY', @@ -37,8 +39,8 @@ const convertToViewValue = (filterValue: string) => pipe( function translateAbsoluteDate(filter: AbsoluteDateFilterData) { let appliedText = ''; - const fromValue = filter.ge; - const toValue = filter.le; + const fromValue = convertClientToView(filter.ge, dataElementTypes.DATE); + const toValue = convertClientToView(filter.le, dataElementTypes.DATE); if (fromValue && toValue) { const momentFrom = moment(fromValue); From 46146999e171cc4b730ab13e13e47a3443cea121 Mon Sep 17 00:00:00 2001 From: alaa-yahia Date: Wed, 11 Dec 2024 13:27:26 +0200 Subject: [PATCH 06/10] fix: reduce the complexity of getUpdatedValue --- .../FiltersForTypes/Date/DateFilter.component.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js b/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js index 5c995df0d1..f6fbaf0b69 100644 --- a/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js +++ b/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js @@ -259,22 +259,23 @@ class DateFilterPlain extends Component implements UpdatableFilter return !values || DateFilter.isFilterValid(values.main, values.from, values.to, values.start, values.end); } - // eslint-disable-next-line complexity getUpdatedValue(valuePart: Object) { const valueObject = { ...this.props.value, ...valuePart, }; const dateFormat = systemSettingsStore.get().dateFormat; + const hasFromValue = () => valuePart.from && valueObject?.from?.value; + const hasToValue = () => valuePart.to && valueObject?.to?.value; - if (valuePart.from && valueObject?.from?.value) { + if (hasFromValue()) { valueObject.from = { ...valueObject.from, value: moment(convertLocalToIsoCalendar(valueObject.from.value)).format(dateFormat), }; } - if (valuePart.to && valueObject?.to?.value) { + if (hasToValue()) { valueObject.to = { ...valueObject.to, value: moment(convertLocalToIsoCalendar(valueObject.to.value)).format(dateFormat), From 98aed544a6e7260d9b5922014539f8c03224ad25 Mon Sep 17 00:00:00 2001 From: alaa-yahia Date: Wed, 11 Dec 2024 23:37:38 +0200 Subject: [PATCH 07/10] chore: refactor working lists filter component --- .../Date/DateFilter.component.js | 69 ++++++++++++------- .../converters/dateConverter.js | 24 +++---- 2 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js b/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js index f6fbaf0b69..80b002c049 100644 --- a/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js +++ b/src/core_modules/capture-core/components/FiltersForTypes/Date/DateFilter.component.js @@ -119,16 +119,24 @@ const getRelativeRangeErrors = (startValue, endValue, submitAttempted) => { return errors; }; -const isAbsoluteRangeFilterValid = (fromValue, toValue) => { - if (!fromValue && !toValue) { +const isAbsoluteRangeFilterValid = (from, to) => { + if (!from?.value && !to?.value) { return false; } + const fromValue = from?.value; + const toValue = to?.value; + const parseResultFrom = fromValue ? parseDate(fromValue) : { isValid: true, moment: null }; + const parseResultTo = toValue ? parseDate(toValue) : { isValid: true, moment: null }; - if ((fromValue && !fromValue.isValid) || (toValue && !toValue.isValid)) { + if (!(parseResultFrom.isValid && parseResultTo.isValid)) { return false; } + const isValidMomentDate = () => + parseResultFrom.momentDate && + parseResultTo.momentDate && + parseResultFrom.momentDate.isAfter(parseResultTo.momentDate); - return !DateFilter.isFromAfterTo(fromValue?.value, toValue?.value); + return !isValidMomentDate(); }; const isRelativeRangeFilterValid = (startValue, endValue) => { @@ -265,22 +273,18 @@ class DateFilterPlain extends Component implements UpdatableFilter ...valuePart, }; const dateFormat = systemSettingsStore.get().dateFormat; - const hasFromValue = () => valuePart.from && valueObject?.from?.value; - const hasToValue = () => valuePart.to && valueObject?.to?.value; - if (hasFromValue()) { - valueObject.from = { - ...valueObject.from, - value: moment(convertLocalToIsoCalendar(valueObject.from.value)).format(dateFormat), - }; - } - - if (hasToValue()) { - valueObject.to = { - ...valueObject.to, - value: moment(convertLocalToIsoCalendar(valueObject.to.value)).format(dateFormat), - }; - } + ['from', 'to'].forEach((key) => { + if (valuePart[key] && valueObject[key]?.value) { + const isValidDate = valuePart[key]?.isValid; + valueObject[key] = { + ...valueObject[key], + value: isValidDate ? + moment(convertLocalToIsoCalendar(valueObject[key].value)).format(dateFormat) : + valueObject[key].value, + }; + } + }); const isRelativeRangeValue = () => valueObject?.start || valuePart?.start || valuePart?.end; const isAbsoluteRangevalue = () => valueObject?.from || valuePart?.from || valuePart?.to; @@ -354,10 +358,23 @@ class DateFilterPlain extends Component implements UpdatableFilter render() { const { value, classes, onFocusUpdateButton } = this.props; - const fromValue = value?.from; - const toValue = value?.to; const { startValueError, endValueError, dateLogicError, bufferLogicError } = - this.getErrors(); + this.getErrors(); + + const dateFormat = systemSettingsStore.get().dateFormat; + + const formatDate = (dateValue) => { + if (!dateValue) return ''; + const momentValue = moment(dateValue, dateFormat); + if (!momentValue.isValid()) return dateValue; + const isoDate = momentValue.format('YYYY-MM-DD'); + return convertIsoToLocalCalendar(isoDate); + }; + + const from = value?.from; + const to = value?.to; + const fromDate = formatDate(from?.value); + const toDate = formatDate(to?.value); return (
@@ -377,11 +394,11 @@ class DateFilterPlain extends Component implements UpdatableFilter {/* $FlowSuppress: Flow not working 100% with HOCs */} {/* $FlowFixMe[prop-missing] automated comment */}
@@ -390,11 +407,11 @@ class DateFilterPlain extends Component implements UpdatableFilter {/* $FlowSuppress: Flow not working 100% with HOCs */} {/* $FlowFixMe[prop-missing] automated comment */} diff --git a/src/core_modules/capture-core/components/ListView/Filters/FilterButton/buttonTextBuilder/converters/dateConverter.js b/src/core_modules/capture-core/components/ListView/Filters/FilterButton/buttonTextBuilder/converters/dateConverter.js index adbc7c367d..35c60d8d2e 100644 --- a/src/core_modules/capture-core/components/ListView/Filters/FilterButton/buttonTextBuilder/converters/dateConverter.js +++ b/src/core_modules/capture-core/components/ListView/Filters/FilterButton/buttonTextBuilder/converters/dateConverter.js @@ -1,13 +1,10 @@ // @flow import i18n from '@dhis2/d2-i18n'; -import { pipe } from 'capture-core-utils'; import moment from 'moment'; -import { convertMomentToDateFormatString } from '../../../../../../utils/converters/date'; +import { convertIsoToLocalCalendar } from '../../../../../../utils/converters/date'; import type { DateFilterData, AbsoluteDateFilterData } from '../../../../../FiltersForTypes'; import { areRelativeRangeValuesSupported } from '../../../../../../utils/validation/validators/areRelativeRangeValuesSupported'; -import { convertClientToView } from '../../../../../../../capture-core/converters'; -import { dataElementTypes } from '../../../../../../metaData'; const periods = { TODAY: 'TODAY', @@ -32,32 +29,27 @@ const translatedPeriods = { [periods.RELATIVE_RANGE]: i18n.t('Relative range'), }; -const convertToViewValue = (filterValue: string) => pipe( - value => moment(value), - momentDate => convertMomentToDateFormatString(momentDate), -)(filterValue); - function translateAbsoluteDate(filter: AbsoluteDateFilterData) { let appliedText = ''; - const fromValue = convertClientToView(filter.ge, dataElementTypes.DATE); - const toValue = convertClientToView(filter.le, dataElementTypes.DATE); + const fromValue = filter.ge; + const toValue = filter.le; if (fromValue && toValue) { const momentFrom = moment(fromValue); const momentTo = moment(toValue); if (momentFrom.isSame(momentTo)) { - appliedText = convertMomentToDateFormatString(momentFrom); + appliedText = convertIsoToLocalCalendar(fromValue); } else { - const appliedTextFrom = convertMomentToDateFormatString(momentFrom); - const appliedTextTo = convertMomentToDateFormatString(momentTo); + const appliedTextFrom = convertIsoToLocalCalendar(fromValue); + const appliedTextTo = convertIsoToLocalCalendar(toValue); appliedText = i18n.t('{{fromDate}} to {{toDate}}', { fromDate: appliedTextFrom, toDate: appliedTextTo }); } } else if (fromValue) { - const appliedTextFrom = convertToViewValue(fromValue); + const appliedTextFrom = convertIsoToLocalCalendar(fromValue); appliedText = i18n.t('after or equal to {{date}}', { date: appliedTextFrom }); } else { // $FlowFixMe[incompatible-call] automated comment - const appliedTextTo = convertToViewValue(toValue); + const appliedTextTo = convertIsoToLocalCalendar(toValue); appliedText = i18n.t('before or equal to {{date}}', { date: appliedTextTo }); } return appliedText; From b9b22e743ab9fdedc9af6b3ab924695e42c71c53 Mon Sep 17 00:00:00 2001 From: alaa-yahia Date: Wed, 11 Dec 2024 23:45:12 +0200 Subject: [PATCH 08/10] fix: convert age values to local date --- src/core_modules/capture-core/converters/clientToForm.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core_modules/capture-core/converters/clientToForm.js b/src/core_modules/capture-core/converters/clientToForm.js index 606b7e3f04..c0b0d10948 100644 --- a/src/core_modules/capture-core/converters/clientToForm.js +++ b/src/core_modules/capture-core/converters/clientToForm.js @@ -1,6 +1,6 @@ // @flow import moment from 'moment'; -import { convertMomentToDateFormatString, convertIsoToLocalCalendar } from '../utils/converters/date'; +import { convertIsoToLocalCalendar } from '../utils/converters/date'; import { dataElementTypes } from '../metaData'; import { stringifyNumber } from './common/stringifyNumber'; @@ -56,7 +56,7 @@ function convertAgeForEdit(rawValue: string): AgeFormValue { const days = now.diff(age, 'days'); return { - date: convertMomentToDateFormatString(moment(rawValue)), + date: convertIsoToLocalCalendar(rawValue), years: years.toString(), months: months.toString(), days: days.toString(), From 3f4b055d22b0b87a8cac824b0dd94d0136cb2ee2 Mon Sep 17 00:00:00 2001 From: Alaa Yahia <6881345+alaa-yahia@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:44:21 +0200 Subject: [PATCH 09/10] feat: [DHIS2 15466] typing the date when editing enrollment and incident date (#3905) feat: typing the date when editing enrollment and incident date --- .../WidgetEnrollment/Date/Date.component.js | 45 ++++++++++++------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/core_modules/capture-core/components/WidgetEnrollment/Date/Date.component.js b/src/core_modules/capture-core/components/WidgetEnrollment/Date/Date.component.js index 0fdba91aea..1b8dc31ee1 100644 --- a/src/core_modules/capture-core/components/WidgetEnrollment/Date/Date.component.js +++ b/src/core_modules/capture-core/components/WidgetEnrollment/Date/Date.component.js @@ -1,9 +1,8 @@ // @flow import React, { useState, useCallback } from 'react'; -import moment from 'moment'; +import { DateField } from 'capture-core/components/FormFields/New'; import { Button, - CalendarInput, IconCalendar16, IconEdit16, colors, @@ -12,8 +11,11 @@ import { import i18n from '@dhis2/d2-i18n'; import { withStyles } from '@material-ui/core'; import { convertValue as convertValueClientToView } from '../../../converters/clientToView'; +import { convertValue as convertValueFormToClient } from '../../../converters/formToClient'; +import { convertValue as convertValueClientToServer } from '../../../converters/clientToServer'; import { dataElementTypes } from '../../../metaData'; + type Props = { date: string, dateLabel: string, @@ -24,7 +26,7 @@ type Props = { ...CssClasses, } -const styles = { +const styles = (theme: Theme) => ({ editButton: { display: 'inline-flex', alignItems: 'center', @@ -62,7 +64,11 @@ const styles = { fontSize: '12px', color: colors.grey700, }, -}; + error: { + ...theme.typography.caption, + color: theme.palette.error.main, + }, +}); const DateComponentPlain = ({ date, @@ -75,21 +81,23 @@ const DateComponentPlain = ({ }: Props) => { const [editMode, setEditMode] = useState(false); const [selectedDate, setSelectedDate] = useState(); - const dateChangeHandler = useCallback(({ calendarDateString }) => { - setSelectedDate(calendarDateString); + const [validation, setValidation] = useState(); + + const dateChangeHandler = useCallback((dateString, internalComponentError) => { + setSelectedDate(dateString); + setValidation(internalComponentError); }, [setSelectedDate]); const displayDate = String(convertValueClientToView(date, dataElementTypes.DATE)); const onOpenEdit = () => { - // CalendarInput component only supports the YYYY-MM-DD format - setSelectedDate(moment(date).format('YYYY-MM-DD')); + setSelectedDate(String(convertValueClientToView(date, dataElementTypes.DATE))); setEditMode(true); }; const saveHandler = () => { - // CalendarInput component only supports the YYYY-MM-DD format if (selectedDate) { - const newDate = moment.utc(selectedDate, 'YYYY-MM-DD').format('YYYY-MM-DDTHH:mm:ss.SSS'); - if (newDate !== date) { + const newClientDate = convertValueFormToClient(selectedDate, dataElementTypes.DATE); + const newDate = convertValueClientToServer(newClientDate, dataElementTypes.DATE); + if (typeof newDate === 'string' && newDate !== date) { onSave(newDate); } } @@ -99,21 +107,24 @@ const DateComponentPlain = ({ return editMode ? (
- +
+ {validation && validation.error ? i18n.t('Please provide a valid date') : ''} +
From b213bf44d75685e94a565f9b903e1c3006575033 Mon Sep 17 00:00:00 2001 From: alaa-yahia Date: Mon, 16 Dec 2024 11:45:42 +0200 Subject: [PATCH 10/10] fix: age values not filled correctly --- .../capture-ui/AgeField/AgeField.component.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/core_modules/capture-ui/AgeField/AgeField.component.js b/src/core_modules/capture-ui/AgeField/AgeField.component.js index a125ea8900..78abcf4a21 100644 --- a/src/core_modules/capture-ui/AgeField/AgeField.component.js +++ b/src/core_modules/capture-ui/AgeField/AgeField.component.js @@ -1,6 +1,8 @@ // @flow import React, { Component } from 'react'; import { isValidPositiveInteger } from 'capture-core-utils/validators/form'; +import { convertDateObjectToDateFormatString } from 'capture-core/utils/converters/date'; +import { systemSettingsStore } from 'capture-core/metaDataMemoryStores'; import i18n from '@dhis2/d2-i18n'; import classNames from 'classnames'; import { IconButton } from 'capture-ui'; @@ -72,7 +74,8 @@ function getCalculatedValues( days: '', }; } - const now = moment(); + const dateFormat = systemSettingsStore.get().dateFormat; + const now = moment(convertDateObjectToDateFormatString(moment()), dateFormat); const age = moment(parseData.momentDate); const years = now.diff(age, 'years'); @@ -133,8 +136,8 @@ class D2AgeFieldPlain extends Component { this.props.onBlur({ ...values, date: '' }); return; } - - const momentDate = moment(undefined, undefined, true); + const dateFormat = systemSettingsStore.get().dateFormat; + const momentDate = moment(convertDateObjectToDateFormatString(moment(undefined, undefined, true)), dateFormat); momentDate.subtract(D2AgeFieldPlain.getNumberOrZero(values.years), 'years'); momentDate.subtract(D2AgeFieldPlain.getNumberOrZero(values.months), 'months'); momentDate.subtract(D2AgeFieldPlain.getNumberOrZero(values.days), 'days');