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

feat: [DHIS2-18310] enable non-Gregorian calendars in views & lists & forms #3900

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
136430d
feat: enable non gregorian calendars in views and lists
alaa-yahia Dec 4, 2024
b8fd941
fix: working list filters to use gregorian
alaa-yahia Dec 4, 2024
e378551
fix: working list filter runtime error when dd-mm-yyyy format is passed
alaa-yahia Dec 10, 2024
8e44c3c
fix: missing rules engine in dependencies
alaa-yahia Dec 11, 2024
1f2518d
fix: working list filter not displaying local date
alaa-yahia Dec 11, 2024
9a3d609
fix: reduce the complexity of getUpdatedValue
alaa-yahia Dec 11, 2024
3a3d0b2
chore: refactor working lists filter component
alaa-yahia Dec 11, 2024
53ef00e
fix: convert age values to local date
alaa-yahia Dec 11, 2024
1d3faa6
feat: [DHIS2 15466] typing the date when editing enrollment and incid…
alaa-yahia Dec 16, 2024
7968ea7
fix: age values not filled correctly
alaa-yahia Dec 16, 2024
e8d226f
fix: keep local calendar date in state in working list filters
alaa-yahia Dec 22, 2024
8ce68dd
fix: rename calendarMaxMoment to calendarMax
alaa-yahia Dec 22, 2024
b0dc55c
fix: remove formating lines
alaa-yahia Dec 22, 2024
2cc70be
fix: day value not giving correct result in age field
alaa-yahia Dec 23, 2024
383c66f
fix: flow errors
alaa-yahia Dec 23, 2024
013db2c
fix: display local time in tooltips
alaa-yahia Jan 6, 2025
8dd1110
fix: date is not valid error not displayed
alaa-yahia Jan 6, 2025
209860c
fix: remove app specific objects
alaa-yahia Jan 9, 2025
c8d1fbd
refactor: simplify converters logic
alaa-yahia Jan 13, 2025
9805435
fix: logic of dateRange & dateTimeRange validators
alaa-yahia Jan 13, 2025
d67810b
chore: pass format and calendar as props
alaa-yahia Jan 13, 2025
068c3ef
fix: status label in the StagesAndEvents widget display ISO date
alaa-yahia Jan 15, 2025
cda3dab
fix: currentSearchTerms are not converted correctly
alaa-yahia Jan 16, 2025
217dc25
fix: enrollment and incident date display in iso
alaa-yahia Jan 16, 2025
d05011a
fix: runtime error when selecting a date in age field in ethiopian ca…
alaa-yahia Jan 16, 2025
78a2af8
Merge remote-tracking branch 'origin/master' into DHIS2-18310-enable-…
alaa-yahia Jan 16, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/components/AppLoader/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -158,7 +158,7 @@ export async function initializeAsync(
const systemSettings = await onQueryApi({
resource: 'system/info',
params: {
fields: 'dateFormat,serverTimeZoneId',
fields: 'dateFormat,serverTimeZoneId,calendar',
},
});

Expand Down
3 changes: 3 additions & 0 deletions src/core_modules/capture-core-utils/date/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
// @flow
export { getFormattedStringFromMomentUsingEuropeanGlyphs } from './date.utils';
export { padWithZeros } from './padWithZeros';
export { temporalToString } from './temporalToString';
export { stringToTemporal } from './stringToTemporal';
12 changes: 12 additions & 0 deletions src/core_modules/capture-core-utils/date/padWithZeros.js
Original file line number Diff line number Diff line change
@@ -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');
}
45 changes: 45 additions & 0 deletions src/core_modules/capture-core-utils/date/stringToTemporal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// @flow
import { Temporal } from '@js-temporal/polyfill';

/**
* Converts a date string into a Temporal.PlainDate object using the specified calendar
* @export
* @param {?string} dateString - The date string to convert
* @param {?string} calendarType - The calendar type to use
* @param {?string} dateFormat - The current system date format ('YYYY-MM-DD' or 'DD-MM-YYYY')
* @returns {(Temporal.PlainDate | null)}
*/

type PlainDate = {
year: number,
month: number,
day: number
};

export function stringToTemporal(dateString: ?string,
calendar: ?string,
dateFormat: ?string): PlainDate | null {
if (!dateString) {
return null;
}
try {
const dateWithHyphen = dateString.replace(/[\/\.]/g, '-');

let year; let month; let day;

if (dateFormat === 'YYYY-MM-DD') {
[year, month, day] = dateWithHyphen.split('-').map(Number);
}
if (dateFormat === 'DD-MM-YYYY') {
[day, month, year] = dateWithHyphen.split('-').map(Number);
}
return Temporal.PlainDate.from({
year,
month,
day,
calendar,
});
} catch (error) {
return null;
}
}
33 changes: 33 additions & 0 deletions src/core_modules/capture-core-utils/date/temporalToString.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// @flow
import { padWithZeros } from './padWithZeros';

/**
* Converts a Temporal.PlainDate to a formatted date string (YYYY-MM-DD or DD-MM-YYYY)
* @param {Temporal.PlainDate | null} temporalDate - The Temporal date to convert
* @param {?string} dateFormat - The current system date format ('YYYY-MM-DD' or 'DD-MM-YYYY')
* @returns {string} Formatted date string, or empty string if invalid
*/

type PlainDate = {
year: number,
month: number,
day: number
};

export function temporalToString(temporalDate: PlainDate | null, dateFormat: ?string): string {
if (!temporalDate) {
return '';
}

try {
const year = temporalDate.year;
const month = temporalDate.month;
const day = temporalDate.day;

return dateFormat === 'YYYY-MM-DD' ?
`${padWithZeros(year, 4)}-${padWithZeros(month, 2)}-${padWithZeros(day, 2)}` :
`${padWithZeros(day, 2)}-${padWithZeros(month, 2)}-${padWithZeros(year, 4)}`;
} catch (error) {
return '';
}
}
88 changes: 0 additions & 88 deletions src/core_modules/capture-core-utils/parsers/date.parser.js

This file was deleted.

1 change: 0 additions & 1 deletion src/core_modules/capture-core-utils/parsers/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// @flow
export { parseDate } from './date.parser';
export { parseNumber } from './number.parser';
export { parseTime } from './time.parser';
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { orientations } from '../../../../FormFields/New';
import { createFieldConfig, createProps } from '../base/configBaseDefaultForm';
import { AgeFieldForForm } from '../../Components';
import { systemSettingsStore } from '../../../../../metaDataMemoryStores';
import { type DataElement } from '../../../../../metaData';
import type { QuerySingleResource } from '../../../../../utils/api/api.types';

Expand All @@ -15,6 +16,8 @@ export const getAgeFieldConfig = (metaData: DataElement, options: Object, queryS
shrinkDisabled: options.formHorizontal,
dateCalendarWidth: options.formHorizontal ? 250 : 350,
datePopupAnchorPosition: getCalendarAnchorPosition(options.formHorizontal),
calendarType: systemSettingsStore.get().calendar,
dateFormat: systemSettingsStore.get().dateFormat,
}, options, metaData);

return createFieldConfig({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import moment from 'moment';
import { createFieldConfig, createProps } from '../base/configBaseDefaultForm';
import { DateFieldForForm } from '../../Components';
import { convertDateObjectToDateFormatString } from '../../../../../../capture-core/utils/converters/date';
import { systemSettingsStore } from '../../../../../metaDataMemoryStores';
import type { DateDataElement } from '../../../../../metaData';
import type { QuerySingleResource } from '../../../../../utils/api/api.types';

Expand All @@ -15,7 +17,9 @@ 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,
calendarMax: !metaData.allowFutureDate ? convertDateObjectToDateFormatString(moment()) : undefined,
calendarType: systemSettingsStore.get().calendar,
dateFormat: systemSettingsStore.get().dateFormat,
}, options, metaData);

return createFieldConfig({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import moment from 'moment';
import { createFieldConfig, createProps } from '../base/configBaseCustomForm';
import { DateFieldForCustomForm } from '../../Components';
import { convertDateObjectToDateFormatString } from '../../../../../../capture-core/utils/converters/date';
import { systemSettingsStore } from '../../../../../metaDataMemoryStores';
import type { DateDataElement } from '../../../../../metaData';
import type { QuerySingleResource } from '../../../../../utils/api/api.types';

Expand All @@ -10,7 +12,9 @@ export const getDateFieldConfigForCustomForm = (metaData: DateDataElement, optio
width: 350,
maxWidth: 350,
calendarWidth: 350,
calendarMaxMoment: !metaData.allowFutureDate ? moment() : undefined,
calendarMax: !metaData.allowFutureDate ? convertDateObjectToDateFormatString(moment()) : undefined,
calendarType: systemSettingsStore.get().calendar,
dateFormat: systemSettingsStore.get().dateFormat,
}, metaData);

return createFieldConfig({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow
import { createFieldConfig, createProps } from '../base/configBaseDefaultForm';
import { DateRangeFieldForForm } from '../../Components';
import { systemSettingsStore } from '../../../../../metaDataMemoryStores';
import type { DataElement as MetaDataElement } from '../../../../../metaData';
import type { QuerySingleResource } from '../../../../../utils/api/api.types';

Expand All @@ -14,6 +15,8 @@ export const getDateRangeFieldConfig = (metaData: MetaDataElement, options: Obje
maxWidth: options.formHorizontal ? 150 : 350,
calendarWidth: options.formHorizontal ? 250 : 350,
popupAnchorPosition: getCalendarAnchorPosition(options.formHorizontal),
calendarType: systemSettingsStore.get().calendar,
dateFormat: systemSettingsStore.get().dateFormat,
}, options, metaData);

return createFieldConfig({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { orientations } from '../../../../FormFields/New';
import { createFieldConfig, createProps } from '../base/configBaseDefaultForm';
import { DateTimeFieldForForm } from '../../Components';
import { systemSettingsStore } from '../../../../../metaDataMemoryStores';
import type { DataElement as MetaDataElement } from '../../../../../metaData';
import type { QuerySingleResource } from '../../../../../utils/api/api.types';

Expand All @@ -17,6 +18,8 @@ export const getDateTimeFieldConfig = (metaData: MetaDataElement, options: Objec
shrinkDisabled: options.formHorizontal,
calendarWidth: options.formHorizontal ? '250px' : '350px',
popupAnchorPosition: getCalendarAnchorPosition(options.formHorizontal),
calendarType: systemSettingsStore.get().calendar,
dateFormat: systemSettingsStore.get().dateFormat,
}, options, metaData);

return createFieldConfig({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { orientations } from '../../../../FormFields/New';
import { createFieldConfig, createProps } from '../base/configBaseCustomForm';
import { DateTimeFieldForCustomForm } from '../../Components';
import { systemSettingsStore } from '../../../../../metaDataMemoryStores';
import type { DataElement as MetaDataElement } from '../../../../../metaData';
import type { QuerySingleResource } from '../../../../../utils/api/api.types';

Expand All @@ -12,6 +13,8 @@ export const getDateTimeFieldConfigForCustomForm = (metaData: MetaDataElement, o
calendarWidth: '350px',
orientation: orientations.HORIZONTAL,
shrinkDisabled: false,
calendarType: systemSettingsStore.get().calendar,
dateFormat: systemSettingsStore.get().dateFormat,
}, metaData);

return createFieldConfig({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { orientations } from '../../../../FormFields/New';
import { createFieldConfig, createProps } from '../base/configBaseDefaultForm';
import { DateTimeRangeFieldForForm } from '../../Components';
import { systemSettingsStore } from '../../../../../metaDataMemoryStores';
import type { DataElement as MetaDataElement } from '../../../../../metaData';
import type { QuerySingleResource } from '../../../../../utils/api/api.types';

Expand All @@ -17,6 +18,8 @@ export const getDateTimeRangeFieldConfig = (metaData: MetaDataElement, options:
shrinkDisabled: options.formHorizontal,
calendarWidth: options.formHorizontal ? 250 : 350,
popupAnchorPosition: getCalendarAnchorPosition(options.formHorizontal),
calendarType: systemSettingsStore.get().calendar,
dateFormat: systemSettingsStore.get().dateFormat,
}, options, metaData);

return createFieldConfig({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import {
withAOCFieldBuilder,
withDataEntryFields,
} from '../../DataEntryDhis2Helpers';
import { convertDateObjectToDateFormatString } from '../../../../capture-core/utils/converters/date';
import { systemSettingsStore } from '../../../metaDataMemoryStores';

const overrideMessagePropNames = {
errorMessage: 'validationError',
Expand Down Expand Up @@ -111,7 +113,11 @@ const getEnrollmentDateSettings = () => {
required: true,
calendarWidth: props.formHorizontal ? 250 : 350,
popupAnchorPosition: getCalendarAnchorPosition(props.formHorizontal),
calendarMaxMoment: !props.enrollmentMetadata.allowFutureEnrollmentDate ? moment() : undefined,
calendarMax: !props.enrollmentMetadata.allowFutureEnrollmentDate ?
convertDateObjectToDateFormatString(moment()) :
undefined,
calendarType: systemSettingsStore.get().calendar,
dateFormat: systemSettingsStore.get().dateFormat,
}),
getPropName: () => 'enrolledAt',
getValidatorContainers: getEnrollmentDateValidatorContainer,
Expand Down Expand Up @@ -159,7 +165,11 @@ const getIncidentDateSettings = () => {
required: true,
calendarWidth: props.formHorizontal ? 250 : 350,
popupAnchorPosition: getCalendarAnchorPosition(props.formHorizontal),
calendarMaxMoment: !props.enrollmentMetadata.allowFutureIncidentDate ? moment() : undefined,
calendarMax: !props.enrollmentMetadata.allowFutureIncidentDate ?
convertDateObjectToDateFormatString(moment()) :
undefined,
calendarType: systemSettingsStore.get().calendar,
dateFormat: systemSettingsStore.get().dateFormat,
}),
getPropName: () => 'occurredAt',
getPassOnFieldData: () => true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { withCleanUp } from './withCleanUp';
import { getEventDateValidatorContainers } from './fieldValidators/eventDate.validatorContainersGetter';
import { stageMainDataIds } from './getDataEntryPropsToInclude';
import { withTransformPropName } from '../../../../HOC';
import { systemSettingsStore } from '../../../../metaDataMemoryStores';

const overrideMessagePropNames = {
errorMessage: 'validationError',
Expand Down Expand Up @@ -219,6 +220,8 @@ const getReportDateSettingsFn = () => {
required: true,
calendarWidth: props.formHorizontal ? 250 : 350,
popupAnchorPosition: getCalendarAnchorPosition(props.formHorizontal),
calendarType: systemSettingsStore.get().calendar,
dateFormat: systemSettingsStore.get().dateFormat,
}),
getPropName: () => stageMainDataIds.OCCURRED_AT,
getValidatorContainers: () => getEventDateValidatorContainers(),
Expand Down
Loading
Loading