Skip to content

Commit

Permalink
feat: enable non gregorian calendars in views and lists
Browse files Browse the repository at this point in the history
  • Loading branch information
alaa-yahia committed Dec 5, 2024
1 parent 416cfa4 commit 556079f
Show file tree
Hide file tree
Showing 19 changed files with 129 additions and 44 deletions.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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",
Expand Down
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
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
withAOCFieldBuilder,
withDataEntryFields,
} from '../../DataEntryDhis2Helpers';
import { convertDateObjectToDateFormatString } from '../../../../capture-core/utils/converters/date';

const overrideMessagePropNames = {
errorMessage: 'validationError',
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -50,7 +49,6 @@ export class D2Date extends React.Component<Props, State> {

render() {
const {
calendar,
calendarWidth,
inputWidth,
classes,
Expand All @@ -62,7 +60,7 @@ export class D2Date extends React.Component<Props, State> {
...passOnProps
} = this.props;

const calendarType = calendar || 'gregory';
const calendarType = systemSettingsStore.get().calendar || 'gregory';
const format = systemSettingsStore.get().dateFormat;

return (
Expand Down
11 changes: 6 additions & 5 deletions src/core_modules/capture-core/converters/clientToForm.js
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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,
};
}
Expand Down
10 changes: 6 additions & 4 deletions src/core_modules/capture-core/converters/clientToList.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
12 changes: 8 additions & 4 deletions src/core_modules/capture-core/converters/clientToView.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,26 @@ 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';


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');
Expand Down
19 changes: 13 additions & 6 deletions src/core_modules/capture-core/converters/formToClient.js
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -25,18 +26,24 @@ 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();
}

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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export class SystemSettings {
dateFormat: string;
dir: string;
trackerAppRelativePath: string;
calendar: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
{
Expand All @@ -25,6 +25,10 @@ export async function cacheSystemSettings(
id: 'serverTimeZoneId',
value: systemSettings.serverTimeZoneId,
},
{
id: 'calendar',
value: systemSettings.calendar,
},
];

const storageController = getMainStorageController();
Expand Down
Original file line number Diff line number Diff line change
@@ -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)}`;
}
Original file line number Diff line number Diff line change
@@ -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() : '';
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
// @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
* @export
* @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);
}
3 changes: 3 additions & 0 deletions src/core_modules/capture-core/utils/converters/date/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
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');
}
Loading

0 comments on commit 556079f

Please sign in to comment.