Skip to content

Commit

Permalink
Extract date operations in DateRangeFilter to utility functions
Browse files Browse the repository at this point in the history
Signed-off-by: Radoslaw Szwajkowski <rszwajko@redhat.com>
  • Loading branch information
rszwajko committed Oct 12, 2023
1 parent e27168c commit f442d71
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 37 deletions.
63 changes: 33 additions & 30 deletions packages/common/src/components/Filter/DateRangeFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import React, { FormEvent, useState } from 'react';
import { DateTime, Interval } from 'luxon';
import { DateTime } from 'luxon';

import { DatePicker, InputGroup, ToolbarFilter } from '@patternfly/react-core';
import {
DatePicker,
InputGroup,
isValidDate as isValidJSDate,
ToolbarFilter,
} from '@patternfly/react-core';

import {
isValidDate,
isValidInterval,
parseISOtoJSDate,
toISODate,
toISODateInterval,
} from '../../utils';

import { FilterTypeProps } from './types';

Expand All @@ -24,43 +37,33 @@ export const DateRangeFilter = ({
placeholderLabel,
showFilter = true,
}: FilterTypeProps) => {
const validFilters =
selectedFilters
?.map((str) => Interval.fromISO(str))
?.filter((range: Interval) => range.isValid) ?? [];

const [from, setFrom] = useState<DateTime>();
const [to, setTo] = useState<DateTime>();
const validFilters = selectedFilters?.filter(isValidInterval) ?? [];

const rangeToOption = (range: Interval): string => range.toISODate().replace('/', ' - ');
const [from, setFrom] = useState<Date>();
const [to, setTo] = useState<Date>();

const optionToRange = (option: string): Interval => Interval.fromISO(option.replace(' - ', '/'));
const rangeToOption = (range: string): string => range.replace('/', ' - ');
const optionToRange = (option: string): string => option.replace(' - ', '/');

const clearSingleRange = (option) => {
const target = optionToRange(option);
onFilterUpdate([
...validFilters.filter((range) => range.equals(target)).map((range) => range.toISODate()),
]);
onFilterUpdate([...validFilters.filter((range) => range !== target)]);
};

const onFromDateChange = (even: FormEvent<HTMLInputElement>, value: string) => {
if (value?.length === 10 && DateTime.fromISO(value).isValid) {
setFrom(DateTime.fromISO(value));
if (value?.length === 10 && isValidDate(value)) {
setFrom(parseISOtoJSDate(value));
setTo(undefined);
}
};

const onToDateChange = (even: FormEvent<HTMLInputElement>, value: string) => {
if (value?.length === 10 && DateTime.fromISO(value).isValid) {
const newTo = DateTime.fromISO(value);
if (value?.length === 10 && isValidDate(value)) {
const newTo = parseISOtoJSDate(value);
setTo(newTo);
const target = Interval.fromDateTimes(from, newTo);
if (target.isValid) {
onFilterUpdate(
[...validFilters.filter((range) => !range.equals(target)), target].map((range) =>
range.toISODate(),
),
);
const target = toISODateInterval(from, newTo);
if (target) {
onFilterUpdate([...validFilters.filter((range) => range !== target), target]);
}
}
};
Expand All @@ -75,7 +78,7 @@ export const DateRangeFilter = ({
>
<InputGroup>
<DatePicker
value={from?.toISODate()}
value={toISODate(from)}
dateFormat={(date) => DateTime.fromJSDate(date).toISODate()}
dateParse={(str) => DateTime.fromISO(str).toJSDate()}
onChange={onFromDateChange}
Expand All @@ -86,12 +89,12 @@ export const DateRangeFilter = ({
appendTo={document.body}
/>
<DatePicker
value={to?.toISODate()}
value={toISODate(to)}
onChange={onToDateChange}
isDisabled={!from?.isValid}
rangeStart={from?.toJSDate()}
isDisabled={isValidJSDate(from)}
rangeStart={from}
aria-label="Interval end"
placeholder="YYYY-MM-DD"
placeholder={placeholderLabel}
appendTo={document.body}
/>
</InputGroup>
Expand Down
6 changes: 2 additions & 4 deletions packages/common/src/components/FilterGroup/matchers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import jsonpath from 'jsonpath';
import { DateTime, Interval } from 'luxon';

import { areSameDayInUTCZero, ResourceField } from '../../utils';
import { areSameDayInUTCZero, isInRange, ResourceField } from '../../utils';
import {
DateFilter,
DateRangeFilter,
Expand Down Expand Up @@ -111,8 +110,7 @@ const dateMatcher = {

const dateRangeMatcher = {
filterType: 'dateRange',
matchValue: (value: string) => (filter: string) =>
Interval.fromISO(filter).contains(DateTime.fromISO(value)),
matchValue: (value: string) => (filter: string) => isInRange(filter, value),
};

const sliderMatcher = {
Expand Down
22 changes: 19 additions & 3 deletions packages/common/src/utils/dates.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DateTime } from 'luxon';
import { DateTime, Interval } from 'luxon';

/**
* Converts a given ISO date time string to UTC+00:00 time zone.
Expand Down Expand Up @@ -28,7 +28,7 @@ export const changeFormatToISODate = (isoDateString: string): string | undefined
* @param date
* @returns ISO date string if input is valid or undefined otherwise.
*/
export const toISODate = (date: Date): string => {
export const toISODate = (date: Date): string | undefined => {
const dt = DateTime.fromJSDate(date);
return dt.isValid ? dt.toISODate() : undefined;
};
Expand All @@ -40,7 +40,7 @@ export const isValidDate = (isoDateString: string) => DateTime.fromISO(isoDateSt
* @param isoDateString
* @returns JS Date instance if input is valid or undefined otherwise.
*/
export const parseISOtoJSDate = (isoDateString: string) => {
export const parseISOtoJSDate = (isoDateString: string): Date | undefined => {
const date = DateTime.fromISO(isoDateString);
return date.isValid ? date.toJSDate() : undefined;
};
Expand All @@ -56,3 +56,19 @@ export const areSameDayInUTCZero = (dateTime: string, calendarDate: string): boo
// which results in shifting to previous day for zones with positive offsets
return DateTime.fromISO(dateTime).toUTC().hasSame(DateTime.fromISO(calendarDate), 'day');
};

/**
*
* @param interval ISO time interval
* @param date ISO date time
* @returns true if the provided date is in the time interval
*/
export const isInRange = (interval: string, date: string): boolean =>
Interval.fromISO(interval).contains(DateTime.fromISO(date));

export const isValidInterval = (interval: string): boolean => Interval.fromISO(interval).isValid;

export const toISODateInterval = (from: Date, to: Date): string | undefined => {
const target = Interval.fromDateTimes(DateTime.fromJSDate(from), DateTime.fromJSDate(to));
return target.isValid ? target.toISODate() : undefined;
};

0 comments on commit f442d71

Please sign in to comment.