Skip to content

Commit

Permalink
fix: day value not giving correct result in age field
Browse files Browse the repository at this point in the history
  • Loading branch information
alaa-yahia committed Jan 6, 2025
1 parent b0dc55c commit 2cc70be
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
import * as React from 'react';
import { withStyles, withTheme } from '@material-ui/core/styles';
import { AgeField as UIAgeField } from 'capture-ui';
import moment from 'moment';
import { parseDate, convertMomentToDateFormatString } from '../../../../../utils/converters/date';
import { systemSettingsStore } from '../../../../../metaDataMemoryStores';

const getStyles = (theme: Theme) => ({
Expand Down Expand Up @@ -50,9 +48,6 @@ const AgeFieldPlain = (props: Props) => {
return (
// $FlowFixMe[cannot-spread-inexact] automated comment
<UIAgeField
onParseDate={parseDate}
onGetFormattedDateStringFromMoment={convertMomentToDateFormatString}
moment={moment}
datePlaceholder={systemSettingsStore.get().dateFormat.toLowerCase()}
{...passOnProps}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// @flow
import { Temporal } from '@js-temporal/polyfill';
import { systemSettingsStore } from '../../../metaDataMemoryStores';

/**
* Converts a date string into a Temporal.PlainDate object using the system set calendar
* @export
* @param {*} string - dateString
* @returns {(Temporal.PlainDate | null)}
*/

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

const calendar = systemSettingsStore.get().calendar;
const dateFormat = systemSettingsStore.get().dateFormat;

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 '';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// @flow
import { Temporal } from '@js-temporal/polyfill';
import { padWithZeros } from './padWithZeros';
import { systemSettingsStore } from '../../../../capture-core/metaDataMemoryStores';

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

export function convertTemporalToString(temporalDate: Temporal.PlainDate | null): string {
if (!temporalDate) {
return '';
}
const dateFormat = systemSettingsStore.get().dateFormat;

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 '';
}
}
2 changes: 2 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 @@ -6,3 +6,5 @@ export { convertStringToDateFormat } from './stringToMomentDateFormat';
export { padWithZeros } from './padWithZeros';
export { convertIsoToLocalCalendar } from './convertIsoToLocalCalendar';
export { convertLocalToIsoCalendar } from './convertLocalToIsoCalendar';
export { convertStringToTemporal } from './convertStringToTemporal';
export { convertTemporalToString } from './convertTemporalToString';
85 changes: 32 additions & 53 deletions src/core_modules/capture-ui/AgeField/AgeField.component.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// @flow
import React, { Component } from 'react';
import { Temporal } from '@js-temporal/polyfill';
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';
Expand All @@ -12,6 +12,7 @@ import { AgeDateInput } from '../internal/AgeInput/AgeDateInput.component';
import defaultClasses from './ageField.module.css';
import { orientations } from '../constants/orientations.const';
import { withInternalChangeHandler } from '../HOC/withInternalChangeHandler';
import { convertStringToTemporal, convertTemporalToString } from '../../capture-core/utils/converters/date';

type AgeValues = {
date?: ?string,
Expand Down Expand Up @@ -47,9 +48,6 @@ type Props = {
inputMessageClasses: ?InputMessageClasses,
inFocus?: ?boolean,
shrinkDisabled?: ?boolean,
onParseDate: DateParser,
onGetFormattedDateStringFromMoment: DateStringFromMomentFormatter,
moment: any,
dateCalendarTheme: Object,
dateCalendarWidth?: ?any,
datePopupAnchorPosition?: ?string,
Expand All @@ -59,38 +57,26 @@ type Props = {
datePlaceholder?: ?string,
disabled?: ?boolean,
};
function getCalculatedValues(
dateValue: ?string,
onParseDate: DateParser,
onGetFormattedDateStringFromMoment: DateStringFromMomentFormatter,
moment: any,
): AgeValues {
const parseData = dateValue && onParseDate(dateValue);
if (!parseData || !parseData.isValid) {
return {
date: dateValue,
years: '',
months: '',
days: '',
};
}
const dateFormat = systemSettingsStore.get().dateFormat;
const now = moment(convertDateObjectToDateFormatString(moment()), dateFormat);
const age = moment(parseData.momentDate);

const years = now.diff(age, 'years');
age.add(years, 'years');
function getCalculatedValues(dateValue: ?string): AgeValues {
const calendar = systemSettingsStore.get().calendar;

const now = Temporal.Now.plainDateISO().withCalendar(calendar);

const months = now.diff(age, 'months');
age.add(months, 'months');
const age = convertStringToTemporal(dateValue);

const days = now.diff(age, 'days');
const diff = now.since(age, {
largestUnit: 'years',
smallestUnit: 'days',
});

const date = convertTemporalToString(age);

return {
date: onGetFormattedDateStringFromMoment(parseData.momentDate),
years: years.toString(),
months: months.toString(),
days: days.toString(),
date,
years: diff.years.toString(),
months: diff.months.toString(),
days: diff.days.toString(),
};
}

Expand Down Expand Up @@ -124,7 +110,7 @@ class D2AgeFieldPlain extends Component<Props> {
}

handleNumberBlur = (values: AgeValues) => {
const { onParseDate, onGetFormattedDateStringFromMoment, onRemoveFocus, moment } = this.props;
const { onRemoveFocus } = this.props;

onRemoveFocus && onRemoveFocus();
if (D2AgeFieldPlain.isEmptyNumbers(values)) {
Expand All @@ -136,28 +122,25 @@ class D2AgeFieldPlain extends Component<Props> {
this.props.onBlur({ ...values, date: '' });
return;
}
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');
const calculatedValues = getCalculatedValues(
onGetFormattedDateStringFromMoment(momentDate),
onParseDate,
onGetFormattedDateStringFromMoment,
moment,
);

const calendar = systemSettingsStore.get().calendar;

const now = Temporal.Now.plainDateISO().withCalendar(calendar);

const calculatedDate = now.subtract({
years: D2AgeFieldPlain.getNumberOrZero(values.years),
months: D2AgeFieldPlain.getNumberOrZero(values.months),
days: D2AgeFieldPlain.getNumberOrZero(values.days),
});

const calculatedValues = getCalculatedValues(convertTemporalToString(calculatedDate));
this.props.onBlur(calculatedValues);
}

handleDateBlur = (date: ?string, options: ?ValidationOptions) => {
const { onParseDate, onGetFormattedDateStringFromMoment, onRemoveFocus, moment } = this.props;
const { onRemoveFocus } = this.props;
onRemoveFocus && onRemoveFocus();
const calculatedValues = date ? getCalculatedValues(
date,
onParseDate,
onGetFormattedDateStringFromMoment,
moment) : null;
const calculatedValues = date ? getCalculatedValues(date) : null;
this.props.onBlur(calculatedValues, options);
}

Expand All @@ -184,8 +167,6 @@ class D2AgeFieldPlain extends Component<Props> {
datePopupAnchorPosition,
dateCalendarTheme,
dateCalendarLocale,
moment,
onParseDate,
...passOnProps } = this.props;
return (
<div className={defaultClasses.ageNumberInputContainer}>
Expand All @@ -211,8 +192,6 @@ class D2AgeFieldPlain extends Component<Props> {
shrinkDisabled,
dateCalendarWidth,
datePlaceholder,
moment,
onParseDate,
...passOnProps
} = this.props;

Expand Down

0 comments on commit 2cc70be

Please sign in to comment.