Convert Date utilties to TypeScript

pull/7640/head
Mark McDowall 2 months ago
parent 782af002d6
commit 8482f3da1a
No known key found for this signature in database

@ -1,6 +1,6 @@
import ModelBase from 'App/ModelBase'; import ModelBase from 'App/ModelBase';
import { DateFilterValue } from 'Components/Filter/Builder/DateFilterBuilderRowValue';
import { FilterBuilderTypes } from 'Helpers/Props/filterBuilderTypes'; import { FilterBuilderTypes } from 'Helpers/Props/filterBuilderTypes';
import { DateFilterValue, FilterType } from 'Helpers/Props/filterTypes';
import { Error } from './AppSectionState'; import { Error } from './AppSectionState';
import BlocklistAppState from './BlocklistAppState'; import BlocklistAppState from './BlocklistAppState';
import CalendarAppState from './CalendarAppState'; import CalendarAppState from './CalendarAppState';
@ -42,7 +42,7 @@ export interface FilterBuilderProp<T> {
export interface PropertyFilter { export interface PropertyFilter {
key: string; key: string;
value: string | string[] | number[] | boolean[] | DateFilterValue; value: string | string[] | number[] | boolean[] | DateFilterValue;
type: string; type: FilterType;
} }
export interface Filter { export interface Filter {

@ -4,17 +4,16 @@ import SelectInput from 'Components/Form/SelectInput';
import TextInput from 'Components/Form/TextInput'; import TextInput from 'Components/Form/TextInput';
import usePrevious from 'Helpers/Hooks/usePrevious'; import usePrevious from 'Helpers/Hooks/usePrevious';
import { import {
IN_LAST, DateFilterBuilderTime,
IN_NEXT, DateFilterValue,
NOT_IN_LAST, FilterType,
NOT_IN_NEXT,
} from 'Helpers/Props/filterTypes'; } from 'Helpers/Props/filterTypes';
import { InputChanged, InputOnChange } from 'typings/inputs'; import { InputChanged, InputOnChange } from 'typings/inputs';
import isString from 'Utilities/String/isString'; import isString from 'Utilities/String/isString';
import { FilterBuilderRowValueProps, NAME } from './FilterBuilderRowValue'; import { FilterBuilderRowValueProps, NAME } from './FilterBuilderRowValue';
import styles from './DateFilterBuilderRowValue.css'; import styles from './DateFilterBuilderRowValue.css';
const timeOptions = [ const timeOptions: DateFilterBuilderTime[] = [
{ key: 'seconds', value: 'seconds' }, { key: 'seconds', value: 'seconds' },
{ key: 'minutes', value: 'minutes' }, { key: 'minutes', value: 'minutes' },
{ key: 'hours', value: 'hours' }, { key: 'hours', value: 'hours' },
@ -23,20 +22,15 @@ const timeOptions = [
{ key: 'months', value: 'months' }, { key: 'months', value: 'months' },
]; ];
function isInFilter(filterType: string | undefined) { function isInFilter(filterType: FilterType) {
return ( return (
filterType === IN_LAST || filterType === 'inLast' ||
filterType === NOT_IN_LAST || filterType === 'notInLast' ||
filterType === IN_NEXT || filterType === 'inNext' ||
filterType === NOT_IN_NEXT filterType === 'notInNext'
); );
} }
export interface DateFilterValue {
time: string;
value: number | null;
}
interface DateFilterBuilderRowValueProps<T> interface DateFilterBuilderRowValueProps<T>
extends Omit< extends Omit<
FilterBuilderRowValueProps<T, string>, FilterBuilderRowValueProps<T, string>,

@ -23,10 +23,10 @@ import translate from 'Utilities/String/translate';
import FilterBuilderRow from './FilterBuilderRow'; import FilterBuilderRow from './FilterBuilderRow';
import styles from './FilterBuilderModalContent.css'; import styles from './FilterBuilderModalContent.css';
const NEW_FILTER: Partial<PropertyFilter> = { const NEW_FILTER: PropertyFilter = {
key: undefined, key: '',
value: undefined, value: '',
type: '', type: 'unknown',
}; };
interface FilterBuilderModalContentProps<T> { interface FilterBuilderModalContentProps<T> {
@ -76,7 +76,7 @@ function FilterBuilderModalContent<T>({
const [label, setLabel] = useState(initialLabel); const [label, setLabel] = useState(initialLabel);
// Push an empty filter if there aren't any filters. FilterBuilderRow // Push an empty filter if there aren't any filters. FilterBuilderRow
// will handle initializing the filter. // will handle initializing the filter.
const [filters, setFilters] = useState<Partial<PropertyFilter>[]>( const [filters, setFilters] = useState<PropertyFilter[]>(
initialFilters.length ? initialFilters : [NEW_FILTER] initialFilters.length ? initialFilters : [NEW_FILTER]
); );
const [labelErrors, setLabelErrors] = useState<ValidationMessage[]>([]); const [labelErrors, setLabelErrors] = useState<ValidationMessage[]>([]);

@ -7,12 +7,11 @@ import {
FilterBuilderTypes, FilterBuilderTypes,
possibleFilterTypes, possibleFilterTypes,
} from 'Helpers/Props/filterBuilderTypes'; } from 'Helpers/Props/filterBuilderTypes';
import { DateFilterValue, FilterType } from 'Helpers/Props/filterTypes';
import { InputChanged } from 'typings/inputs'; import { InputChanged } from 'typings/inputs';
import sortByProp from 'Utilities/Array/sortByProp'; import sortByProp from 'Utilities/Array/sortByProp';
import BoolFilterBuilderRowValue from './BoolFilterBuilderRowValue'; import BoolFilterBuilderRowValue from './BoolFilterBuilderRowValue';
import DateFilterBuilderRowValue, { import DateFilterBuilderRowValue from './DateFilterBuilderRowValue';
DateFilterValue,
} from './DateFilterBuilderRowValue';
import DefaultFilterBuilderRowValue from './DefaultFilterBuilderRowValue'; import DefaultFilterBuilderRowValue from './DefaultFilterBuilderRowValue';
import HistoryEventTypeFilterBuilderRowValue from './HistoryEventTypeFilterBuilderRowValue'; import HistoryEventTypeFilterBuilderRowValue from './HistoryEventTypeFilterBuilderRowValue';
import IndexerFilterBuilderRowValue from './IndexerFilterBuilderRowValue'; import IndexerFilterBuilderRowValue from './IndexerFilterBuilderRowValue';
@ -134,7 +133,7 @@ interface FilterBuilderRowProps<T> {
index: number; index: number;
filterKey?: string; filterKey?: string;
filterValue?: (DateFilterValue | string) | string[] | number[] | boolean[]; filterValue?: (DateFilterValue | string) | string[] | number[] | boolean[];
filterType?: string; filterType: FilterType;
filterCount: number; filterCount: number;
filterBuilderProps: FilterBuilderProp<T>[]; filterBuilderProps: FilterBuilderProp<T>[];
sectionItems: T[]; sectionItems: T[];
@ -195,7 +194,7 @@ function FilterBuilderRow<T>({
); );
const handleFilterTypeChange = useCallback( const handleFilterTypeChange = useCallback(
({ value }: InputChanged<string>) => { ({ value }: InputChanged<FilterType>) => {
if (filterKey == null || filterValue == null || filterType == null) { if (filterKey == null || filterValue == null || filterType == null) {
return; return;
} }

@ -6,6 +6,7 @@ import {
filterBuilderValueTypes, filterBuilderValueTypes,
kinds, kinds,
} from 'Helpers/Props'; } from 'Helpers/Props';
import { FilterType } from 'Helpers/Props/filterTypes';
import { InputOnChange } from 'typings/inputs'; import { InputOnChange } from 'typings/inputs';
import convertToBytes from 'Utilities/Number/convertToBytes'; import convertToBytes from 'Utilities/Number/convertToBytes';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
@ -93,7 +94,7 @@ export interface FilterBuilderRowValueProps<
T, T,
V extends string | number | boolean V extends string | number | boolean
> { > {
filterType?: string; filterType: FilterType;
filterValue: V[]; filterValue: V[];
sectionItems: T[]; sectionItems: T[];
selectedFilterBuilderProp: FilterBuilderProp<T>; selectedFilterBuilderProp: FilterBuilderProp<T>;

@ -1,5 +1,5 @@
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import * as filterTypes from './filterTypes'; import { FilterType } from './filterTypes';
export const ARRAY = 'array'; export const ARRAY = 'array';
export const CONTAINS = 'contains'; export const CONTAINS = 'contains';
@ -11,6 +11,11 @@ export const STRING = 'string';
export const all = [ARRAY, CONTAINS, DATE, EQUAL, EXACT, NUMBER, STRING]; export const all = [ARRAY, CONTAINS, DATE, EQUAL, EXACT, NUMBER, STRING];
interface FilterBuilderTypeOption {
key: FilterType;
value: () => string;
}
export type FilterBuilderTypes = export type FilterBuilderTypes =
| 'array' | 'array'
| 'contains' | 'contains'
@ -20,128 +25,131 @@ export type FilterBuilderTypes =
| 'number' | 'number'
| 'string'; | 'string';
export const possibleFilterTypes = { export const possibleFilterTypes: Record<
FilterBuilderTypes,
FilterBuilderTypeOption[]
> = {
array: [ array: [
{ {
key: filterTypes.CONTAINS, key: 'contains',
value: () => translate('FilterContains'), value: () => translate('FilterContains'),
}, },
{ {
key: filterTypes.NOT_CONTAINS, key: 'notContains',
value: () => translate('FilterDoesNotContain'), value: () => translate('FilterDoesNotContain'),
}, },
], ],
contains: [ contains: [
{ {
key: filterTypes.CONTAINS, key: 'contains',
value: () => translate('FilterContains'), value: () => translate('FilterContains'),
}, },
], ],
date: [ date: [
{ {
key: filterTypes.LESS_THAN, key: 'lessThan',
value: () => translate('FilterIsBefore'), value: () => translate('FilterIsBefore'),
}, },
{ {
key: filterTypes.GREATER_THAN, key: 'greaterThan',
value: () => translate('FilterIsAfter'), value: () => translate('FilterIsAfter'),
}, },
{ {
key: filterTypes.IN_LAST, key: 'inLast',
value: () => translate('FilterInLast'), value: () => translate('FilterInLast'),
}, },
{ {
key: filterTypes.NOT_IN_LAST, key: 'notInLast',
value: () => translate('FilterNotInLast'), value: () => translate('FilterNotInLast'),
}, },
{ {
key: filterTypes.IN_NEXT, key: 'inNext',
value: () => translate('FilterInNext'), value: () => translate('FilterInNext'),
}, },
{ {
key: filterTypes.NOT_IN_NEXT, key: 'notInNext',
value: () => translate('FilterNotInNext'), value: () => translate('FilterNotInNext'),
}, },
], ],
equal: [ equal: [
{ {
key: filterTypes.EQUAL, key: 'equal',
value: () => translate('FilterIs'), value: () => translate('FilterIs'),
}, },
], ],
exact: [ exact: [
{ {
key: filterTypes.EQUAL, key: 'equal',
value: () => translate('FilterIs'), value: () => translate('FilterIs'),
}, },
{ {
key: filterTypes.NOT_EQUAL, key: 'notEqual',
value: () => translate('FilterIsNot'), value: () => translate('FilterIsNot'),
}, },
], ],
number: [ number: [
{ {
key: filterTypes.EQUAL, key: 'equal',
value: () => translate('FilterEqual'), value: () => translate('FilterEqual'),
}, },
{ {
key: filterTypes.GREATER_THAN, key: 'greaterThan',
value: () => translate('FilterGreaterThan'), value: () => translate('FilterGreaterThan'),
}, },
{ {
key: filterTypes.GREATER_THAN_OR_EQUAL, key: 'greaterThanOrEqual',
value: () => translate('FilterGreaterThanOrEqual'), value: () => translate('FilterGreaterThanOrEqual'),
}, },
{ {
key: filterTypes.LESS_THAN, key: 'lessThan',
value: () => translate('FilterLessThan'), value: () => translate('FilterLessThan'),
}, },
{ {
key: filterTypes.LESS_THAN_OR_EQUAL, key: 'lessThanOrEqual',
value: () => translate('FilterLessThanOrEqual'), value: () => translate('FilterLessThanOrEqual'),
}, },
{ {
key: filterTypes.NOT_EQUAL, key: 'notEqual',
value: () => translate('FilterNotEqual'), value: () => translate('FilterNotEqual'),
}, },
], ],
string: [ string: [
{ {
key: filterTypes.CONTAINS, key: 'contains',
value: () => translate('FilterContains'), value: () => translate('FilterContains'),
}, },
{ {
key: filterTypes.NOT_CONTAINS, key: 'notContains',
value: () => translate('FilterDoesNotContain'), value: () => translate('FilterDoesNotContain'),
}, },
{ {
key: filterTypes.EQUAL, key: 'equal',
value: () => translate('FilterEqual'), value: () => translate('FilterEqual'),
}, },
{ {
key: filterTypes.NOT_EQUAL, key: 'notEqual',
value: () => translate('FilterNotEqual'), value: () => translate('FilterNotEqual'),
}, },
{ {
key: filterTypes.STARTS_WITH, key: 'startsWith',
value: () => translate('FilterStartsWith'), value: () => translate('FilterStartsWith'),
}, },
{ {
key: filterTypes.NOT_STARTS_WITH, key: 'notStartsWith',
value: () => translate('FilterDoesNotStartWith'), value: () => translate('FilterDoesNotStartWith'),
}, },
{ {
key: filterTypes.ENDS_WITH, key: 'endsWith',
value: () => translate('FilterEndsWith'), value: () => translate('FilterEndsWith'),
}, },
{ {
key: filterTypes.NOT_ENDS_WITH, key: 'notEndsWith',
value: () => translate('FilterDoesNotEndWith'), value: () => translate('FilterDoesNotEndWith'),
}, },
], ],

@ -31,5 +31,42 @@ export const all = [
STARTS_WITH, STARTS_WITH,
NOT_STARTS_WITH, NOT_STARTS_WITH,
ENDS_WITH, ENDS_WITH,
NOT_ENDS_WITH NOT_ENDS_WITH,
]; ];
export type FilterType =
| 'unknown'
| 'contains'
| 'equal'
| 'greaterThan'
| 'greaterThanOrEqual'
| 'inLast'
| 'notInLast'
| 'inNext'
| 'notInNext'
| 'lessThan'
| 'lessThanOrEqual'
| 'notContains'
| 'notEqual'
| 'startsWith'
| 'notStartsWith'
| 'endsWith'
| 'notEndsWith';
export type FilterDateType =
| 'seconds'
| 'minutes'
| 'hours'
| 'days'
| 'weeks'
| 'months';
export interface DateFilterBuilderTime {
key: FilterDateType;
value: string;
}
export interface DateFilterValue {
time: string;
value: number | null;
}

@ -1,43 +0,0 @@
import moment from 'moment';
import * as filterTypes from 'Helpers/Props/filterTypes';
import isAfter from 'Utilities/Date/isAfter';
import isBefore from 'Utilities/Date/isBefore';
export default function(itemValue, filterValue, type) {
if (!itemValue) {
return false;
}
switch (type) {
case filterTypes.LESS_THAN:
return moment(itemValue).isBefore(filterValue);
case filterTypes.GREATER_THAN:
return moment(itemValue).isAfter(filterValue);
case filterTypes.IN_LAST:
return (
isAfter(itemValue, { [filterValue.time]: filterValue.value * -1 }) &&
isBefore(itemValue)
);
case filterTypes.NOT_IN_LAST:
return (
isBefore(itemValue, { [filterValue.time]: filterValue.value * -1 })
);
case filterTypes.IN_NEXT:
return (
isAfter(itemValue) &&
isBefore(itemValue, { [filterValue.time]: filterValue.value })
);
case filterTypes.NOT_IN_NEXT:
return (
isAfter(itemValue, { [filterValue.time]: filterValue.value })
);
default:
return false;
}
}

@ -0,0 +1,50 @@
import moment, { MomentInput } from 'moment';
import { FilterType } from 'Helpers/Props/filterTypes';
import isAfter from 'Utilities/Date/isAfter';
import isBefore from 'Utilities/Date/isBefore';
export default function (
itemValue: MomentInput,
filterValue: string | { time: string; value: number },
type: FilterType
) {
if (!itemValue) {
return false;
}
if (typeof filterValue === 'string') {
if (type === 'lessThan') {
return moment(itemValue).isSame(filterValue);
}
if (type === 'greaterThan') {
return moment(itemValue).isAfter(filterValue);
}
return false;
}
if (type === 'inLast') {
return (
isAfter(itemValue, { [filterValue.time]: filterValue.value * -1 }) &&
isBefore(itemValue)
);
}
if (type === 'notInLast') {
return isBefore(itemValue, { [filterValue.time]: filterValue.value * -1 });
}
if (type === 'inNext') {
return (
isAfter(itemValue) &&
isBefore(itemValue, { [filterValue.time]: filterValue.value })
);
}
if (type === 'notInNext') {
return isAfter(itemValue, { [filterValue.time]: filterValue.value });
}
return false;
}

@ -1,6 +1,6 @@
import moment from 'moment'; import moment, { MomentInput } from 'moment';
function formatDate(date, dateFormat) { function formatDate(date: MomentInput, dateFormat: string) {
if (!date) { if (!date) {
return ''; return '';
} }

@ -1,11 +1,11 @@
import moment from 'moment'; import moment, { MomentInput } from 'moment';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import formatTime from './formatTime'; import formatTime from './formatTime';
import isToday from './isToday'; import isToday from './isToday';
import isTomorrow from './isTomorrow'; import isTomorrow from './isTomorrow';
import isYesterday from './isYesterday'; import isYesterday from './isYesterday';
function getRelativeDay(date, includeRelativeDate) { function getRelativeDay(date: MomentInput, includeRelativeDate: boolean) {
if (!includeRelativeDate) { if (!includeRelativeDate) {
return ''; return '';
} }
@ -25,17 +25,29 @@ function getRelativeDay(date, includeRelativeDate) {
return ''; return '';
} }
function formatDateTime(date, dateFormat, timeFormat, { includeSeconds = false, includeRelativeDay = false } = {}) { function formatDateTime(
date: MomentInput,
dateFormat: string,
timeFormat: string,
{ includeSeconds = false, includeRelativeDay = false } = {}
) {
if (!date) { if (!date) {
return ''; return '';
} }
const relativeDay = getRelativeDay(date, includeRelativeDay); const relativeDay = getRelativeDay(date, includeRelativeDay);
const formattedDate = moment(date).format(dateFormat); const formattedDate = moment(date).format(dateFormat);
const formattedTime = formatTime(date, timeFormat, { includeMinuteZero: true, includeSeconds }); const formattedTime = formatTime(date, timeFormat, {
includeMinuteZero: true,
includeSeconds,
});
if (relativeDay) { if (relativeDay) {
return translate('FormatDateTimeRelative', { relativeDay, formattedDate, formattedTime }); return translate('FormatDateTimeRelative', {
relativeDay,
formattedDate,
formattedTime,
});
} }
return translate('FormatDateTime', { formattedDate, formattedTime }); return translate('FormatDateTime', { formattedDate, formattedTime });
} }

@ -1,7 +1,7 @@
import moment from 'moment'; import moment, { DurationInputArg1 } from 'moment';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
function formatShortTimeSpan(timeSpan) { function formatShortTimeSpan(timeSpan: DurationInputArg1) {
if (!timeSpan) { if (!timeSpan) {
return ''; return '';
} }

@ -1,6 +1,10 @@
import moment from 'moment'; import moment, { MomentInput } from 'moment';
function formatTime(date, timeFormat, { includeMinuteZero = false, includeSeconds = false } = {}) { function formatTime(
date: MomentInput,
timeFormat: string,
{ includeMinuteZero = false, includeSeconds = false } = {}
) {
if (!date) { if (!date) {
return ''; return '';
} }

@ -1,8 +1,8 @@
import moment from 'moment'; import moment, { DurationInputArg1 } from 'moment';
import padNumber from 'Utilities/Number/padNumber'; import padNumber from 'Utilities/Number/padNumber';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
function formatTimeSpan(timeSpan) { function formatTimeSpan(timeSpan: DurationInputArg1) {
if (!timeSpan) { if (!timeSpan) {
return ''; return '';
} }

@ -74,7 +74,7 @@ function getRelativeDate({
return includeTime ? translate('DayOfWeekAt', { day, time }) : day; return includeTime ? translate('DayOfWeekAt', { day, time }) : day;
} }
return includeTime return includeTime && timeFormat
? formatDateTime(date, shortDateFormat, timeFormat, { includeSeconds }) ? formatDateTime(date, shortDateFormat, timeFormat, { includeSeconds })
: moment(date).format(shortDateFormat); : moment(date).format(shortDateFormat);
} }

@ -1,17 +0,0 @@
import moment from 'moment';
function isAfter(date, offsets = {}) {
if (!date) {
return false;
}
const offsetTime = moment();
Object.keys(offsets).forEach((key) => {
offsetTime.add(offsets[key], key);
});
return moment(date).isAfter(offsetTime);
}
export default isAfter;

@ -0,0 +1,21 @@
import moment, { MomentInput } from 'moment';
import { FilterDateType } from 'Helpers/Props/filterTypes';
function isAfter(
date: MomentInput,
offsets: Partial<Record<FilterDateType, number>> = {}
) {
if (!date) {
return false;
}
const offsetTime = moment();
Object.entries(offsets).forEach(([key, value]) => {
offsetTime.add(value, key as FilterDateType);
});
return moment(date).isAfter(offsetTime);
}
export default isAfter;

@ -1,17 +0,0 @@
import moment from 'moment';
function isBefore(date, offsets = {}) {
if (!date) {
return false;
}
const offsetTime = moment();
Object.keys(offsets).forEach((key) => {
offsetTime.add(offsets[key], key);
});
return moment(date).isBefore(offsetTime);
}
export default isBefore;

@ -0,0 +1,21 @@
import moment, { MomentInput } from 'moment';
import { FilterDateType } from 'Helpers/Props/filterTypes';
function isBefore(
date: MomentInput,
offsets: Partial<Record<FilterDateType, number>> = {}
) {
if (!date) {
return false;
}
const offsetTime = moment();
Object.entries(offsets).forEach(([key, value]) => {
offsetTime.add(value, key as FilterDateType);
});
return moment(date).isBefore(offsetTime);
}
export default isBefore;

@ -1,6 +1,6 @@
import moment from 'moment'; import moment, { MomentInput } from 'moment';
function isInNextWeek(date) { function isInNextWeek(date: MomentInput) {
if (!date) { if (!date) {
return false; return false;
} }

@ -1,6 +1,6 @@
import moment from 'moment'; import moment, { MomentInput } from 'moment';
function isSameWeek(date) { function isSameWeek(date: MomentInput) {
if (!date) { if (!date) {
return false; return false;
} }

@ -1,6 +1,6 @@
import moment from 'moment'; import moment, { MomentInput } from 'moment';
function isToday(date) { function isToday(date: MomentInput) {
if (!date) { if (!date) {
return false; return false;
} }

@ -1,6 +1,6 @@
import moment from 'moment'; import moment, { MomentInput } from 'moment';
function isTomorrow(date) { function isTomorrow(date: MomentInput) {
if (!date) { if (!date) {
return false; return false;
} }

@ -1,6 +1,6 @@
import moment from 'moment'; import moment, { MomentInput } from 'moment';
function isYesterday(date) { function isYesterday(date: MomentInput) {
if (!date) { if (!date) {
return false; return false;
} }
Loading…
Cancel
Save