Skip to content

Commit

Permalink
fix: update minDate conditional logic (M2-8317, M2-8275, M2-8032) (#2023
Browse files Browse the repository at this point in the history
)

* fix date parse errors in Date type conditions

* update minDate value in DatePicker

* add maxDate value to DatePicker

* prevents setting a max date that is lower than minDate

* add parseDateToMidnightUTC to dateFormat utils
  • Loading branch information
ChaconC authored Feb 4, 2025
1 parent d837c75 commit dff3c7d
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,14 @@ export const SwitchCondition = ({
onCloseCallback={onCloseStartDateCallback}
data-testid={`${dataTestid}-start-date-value`}
skipMinDate
maxDate={maxDateValue}
{...commonDateInputProps}
/>
<StyledBodyLarge sx={{ m: theme.spacing(0, 0.4) }}>{t('and')}</StyledBodyLarge>
<DatePicker
name={maxDateValueName}
key={`max-date-value-${isRangeValueShown}`}
minDate={minValue as Date}
minDate={minDateValue}
data-testid={`${dataTestid}-end-date-value`}
{...commonDateInputProps}
/>
Expand Down
10 changes: 10 additions & 0 deletions src/modules/Builder/pages/BuilderApplet/BuilderApplet.const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ export const TIME_INTERVAL_CONDITION_TYPES = [
ConditionType.BetweenTimesRange,
ConditionType.OutsideOfTimesRange,
];
export const DATE_SINGLE_CONDITION_TYPES = [
ConditionType.GreaterThanDate,
ConditionType.LessThanDate,
ConditionType.EqualToDate,
ConditionType.NotEqualToDate,
];
export const DATE_INTERVAL_CONDITION_TYPES = [
ConditionType.BetweenDates,
ConditionType.OutsideOfDates,
];
export const SLIDER_ROWS_CONDITION_TYPES = [
ConditionType.GreaterThanSliderRows,
ConditionType.LessThanSliderRows,
Expand Down
28 changes: 28 additions & 0 deletions src/modules/Builder/pages/BuilderApplet/BuilderApplet.utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import {
TimeRangeIntervalValueCondition,
TimeSingleValueCondition,
TimeRangeSingleValueCondition,
DateSingleValueCondition,
DateRangeValueCondition,
} from 'shared/state';
import {
createArray,
Expand All @@ -42,6 +44,7 @@ import {
getTextBetweenBrackets,
INTERVAL_SYMBOL,
isSystemItem,
parseDateToMidnightUTC,
Path,
pluck,
} from 'shared/utils';
Expand Down Expand Up @@ -96,6 +99,8 @@ import {
import {
ALLOWED_TYPES_IN_VARIABLES,
CONDITION_TYPES_TO_HAVE_OPTION_ID,
DATE_INTERVAL_CONDITION_TYPES,
DATE_SINGLE_CONDITION_TYPES,
defaultFlankerBtnObj,
ordinalStrings,
SAMPLE_SIZE,
Expand Down Expand Up @@ -783,8 +788,31 @@ const formatTime = (hours: number, minutes: number) => {
return `${formattedHours}:${formattedMinutes}`;
};

const formatDate = (dateValue: string) => {
const date = dateValue ? parseDateToMidnightUTC(dateValue) : undefined;

return date;
};

const getConditionPayload = (item: Item, condition: Condition) => {
const conditionType = condition.type as ConditionType;
if (DATE_SINGLE_CONDITION_TYPES.includes(conditionType)) {
const conditionPayload = condition.payload as DateSingleValueCondition['payload'];

return {
...conditionPayload,
date: formatDate(conditionPayload.date),
};
}
if (DATE_INTERVAL_CONDITION_TYPES.includes(conditionType)) {
const conditionPayload = condition.payload as DateRangeValueCondition['payload'];

return {
...conditionPayload,
minDate: formatDate(conditionPayload.minDate),
maxDate: formatDate(conditionPayload.maxDate),
};
}
if (TIME_SINGLE_CONDITION_TYPES.includes(conditionType)) {
const conditionPayload = condition.payload as
| TimeSingleValueCondition<string>['payload']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { useAsync } from 'shared/hooks';
import { StyledContainer, theme } from 'shared/styles';
import { users } from 'redux/modules';
import { page } from 'resources';
import { parseDateToMidnightUTC } from 'shared/utils';

import { Feedback } from './Feedback';
import { ActivityResponses } from './ActivityResponses';
Expand Down Expand Up @@ -143,8 +144,7 @@ export const RespondentDataReview = () => {
const datesResult = data?.result;
if (!datesResult) return;

// Map each date string to a Date object, appending 'T00:00:00' to remove timezone offset
const submitDates = datesResult.dates.map((date: string) => new Date(`${date}T00:00:00`));
const submitDates = datesResult.dates.map(parseDateToMidnightUTC);
setResponseDates(submitDates);
});

Expand Down Expand Up @@ -235,8 +235,7 @@ export const RespondentDataReview = () => {
const lastActivityCompletedDate = lastActivityCompleted && new Date(lastActivityCompleted);

if (selectedDateParam) {
// Map the date string to a Date object, appending 'T00:00:00' to remove timezone offset
const selectedDate = new Date(`${selectedDateParam}T00:00:00`);
const selectedDate = parseDateToMidnightUTC(selectedDateParam);
if (isValid(selectedDate)) {
handleSetInitialDate(selectedDate);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { addDays, endOfYear, setHours, setMinutes, setSeconds } from 'date-fns';

import { Periodicity, TimerType } from 'modules/Dashboard/api';
import { formatToYearMonthDate } from 'shared/utils/dateFormat';
import { formatToYearMonthDate, parseDateToMidnightUTC } from 'shared/utils/dateFormat';

import {
getEventsWithHiddenInTimeView,
Expand Down Expand Up @@ -325,9 +325,9 @@ describe('getEventEndDateTime', () => {
const dateString = '2023-12-15';
const dateStringNextYear = '2024-07-15';
const endTime = '16:30:00';
const eventStart = new Date(`${dateString}T00:00:00`);
const eventStart = parseDateToMidnightUTC(dateString);
const eventStartNextYear = parseDateToMidnightUTC(dateStringNextYear);
const eventStartWithTime = new Date(`${dateString}T${endTime}`);
const eventStartNextYear = new Date(`${dateStringNextYear}T00:00:00`);
const currentYear = '2023';

test.each`
Expand Down
33 changes: 33 additions & 0 deletions src/shared/utils/dateFormat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
getDayName,
getMonthName,
getMoreText,
parseDateToMidnightUTC,
} from './dateFormat';

const firstDate = new Date('2023-10-22T12:00:00Z');
Expand Down Expand Up @@ -57,3 +58,35 @@ describe('getMonthName', () => {
expect(getMonthName(date, length)).toBe(expected);
});
});

describe('parseDateToMidnightUTC', () => {
it('should return a Date object for a valid date string', () => {
const dateStr = '2025-01-01';
const result = parseDateToMidnightUTC(dateStr);
expect(result).toBeInstanceOf(Date);
expect(result.toISOString()).toBe('2025-01-01T00:00:00.000Z');
});

test('should throw error for invalid formats', () => {
expect(() => parseDateToMidnightUTC('2025/01/01')).toThrow(
'[parseDateToMidnightUTC] Invalid date string format',
);
expect(() => parseDateToMidnightUTC('2025-01')).toThrow(
'[parseDateToMidnightUTC] Invalid date string format',
);
expect(() => parseDateToMidnightUTC('invalid-date')).toThrow(
'[parseDateToMidnightUTC] Invalid date string format',
);
expect(() => parseDateToMidnightUTC('')).toThrow(
'[parseDateToMidnightUTC] Invalid date string format',
);
});

it('should handle timezone inconsistencies correctly', () => {
const dateStr = '2024-06-15';
const result = parseDateToMidnightUTC(dateStr);
expect(result.getUTCDate()).toBe(15);
expect(result.getUTCMonth()).toBe(5);
expect(result.getUTCFullYear()).toBe(2024);
});
});
23 changes: 23 additions & 0 deletions src/shared/utils/dateFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,26 @@ export const getMonthName = (date: Date, length?: NameLength) =>
date.toLocaleString(i18n.language, { month: length || NameLength.Long });

export const formatToNumberDate = (date: Date) => format(new Date(date), DateFormats.YearMonthDay);

/**
* Parses a date string to a Date object, appending 'T00:00:00Z' to remove timezone offset
*
* @param {String} dateStr - The date string from which to extract the raw hours and minutes.
* @returns {Date} An object containing the extracted raw hours and minutes.
* @throws {Error} Throws an error if the date string format is invalid.
*
* @example
* const dateStr = '2025-01-01';
* const date = parseDateToMidnightUTC(dateStr);
* // date: 2025-01-01T00:00:00.000Z
*/

export const parseDateToMidnightUTC = (dateStr: string): Date => {
const dateMatch = dateStr.match(/(\d{4})-(\d{2})-(\d{2})/);

if (!dateMatch) {
throw new Error('[parseDateToMidnightUTC] Invalid date string format');
}

return new Date(`${dateStr}T00:00:00Z`);
};
1 change: 1 addition & 0 deletions src/shared/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,4 @@ export * from './nullReturnFunc';
export * from './isObject';
export * from './responseType';
export * from './regex';
export * from './dateFormat';

0 comments on commit dff3c7d

Please sign in to comment.