Skip to content

Commit

Permalink
feat(datetime)!: make daterange type to use custom strings from presets
Browse files Browse the repository at this point in the history
  • Loading branch information
jlopezcur committed Jan 3, 2025
1 parent 6a804ed commit b4dae51
Show file tree
Hide file tree
Showing 12 changed files with 49 additions and 86 deletions.
4 changes: 2 additions & 2 deletions packages/datetime/src/components/Calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
type IStyledOverloadCss,
type IStyledPolymorphic,
} from '@devoinc/genesys-ui';
import type { IParseResult } from '../../declarations';
import type { IParseResult, TDateRange } from '../../declarations';
import { toTimestamp } from '../../helpers';
import { parseAllDates } from '../../parsers';
import { CalendarWeekDay, Cell, type CellProps } from './components';
Expand Down Expand Up @@ -48,7 +48,7 @@ export interface CalendarProps
* One of `number` or `Date`. */
hoverDay?: Date | number;
/** Selected range. */
value?: (number | Date)[];
value?: TDateRange;
/** Days of the week to show in the calendar. The first day of the week is Monday. */
weekDays?: [string, string, string, string, string, string, string];
weekStart?: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { compareDesc } from 'date-fns';

export const rangeBehavior = (range: (number | Date)[], dt: number | Date) =>
import type { TDate, TDateRange } from '../../../declarations';

export const rangeBehavior = (range: TDateRange, dt: TDate) =>
range.length === 1
? compareDesc(dt, range[0]) < 0
? [range[0], dt]
Expand Down
6 changes: 3 additions & 3 deletions packages/datetime/src/components/Calendar/day.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { set, getDate, getTime, format } from 'date-fns';

import type { TParseDate } from '../../declarations';
import type { TDateRange, TParseDate } from '../../declarations';
import type {
TCalendarI18n,
TConditionFunction,
Expand Down Expand Up @@ -181,7 +181,7 @@ export const getClassNameFromProperties = (dayProps: TDayProperties) => [
...(dayProps.isRightHover ? ['rightmost'] : []),
];

export const getFrom = (value: (number | Date)[]) => {
export const getFrom = (value: TDateRange) => {
if (value[0] && getTime(value[0]) > 0) {
return getTime(
set(value[0], { hours: 0, minutes: 0, seconds: 0, milliseconds: 0 }),
Expand All @@ -190,7 +190,7 @@ export const getFrom = (value: (number | Date)[]) => {
return 0;
};

export const getTo = (value: (number | Date)[]) => {
export const getTo = (value: TDateRange) => {
if (value[1] && getTime(value[1]) > 0) {
return getTime(
set(value[1], {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ The hook `useTimeRangePreserve` return a callback that is aware of changes in
the range from calendars or from time pickers and is modifying the final range
result to give it to the state management of the upper layer.

## With presets

<Canvas of={Stories.WithPresets} />

## Related components

- [DateTime](?path=/docs/components-datetime-datetime--docs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Meta, StoryObj } from '@storybook/react';
import { DateTimeRange } from './DateTimeRange';
import { useTimeRangePreserve } from './hooks';
import { defaultPresets } from '../Presets';
import type { TDateRange } from '../../declarations';

const meta: Meta<typeof DateTimeRange> = {
title: 'Components/Datetime/DateTimeRange',
Expand All @@ -16,7 +17,7 @@ type Story = StoryObj<typeof DateTimeRange>;
export const Playground: Story = {
render: () =>
((args) => {
const [value, setValue] = React.useState<(number | Date)[]>([]);
const [value, setValue] = React.useState<TDateRange>([]);
const [monthDate, setMonthDate] = React.useState<number | Date>(
new Date(),
);
Expand All @@ -30,6 +31,7 @@ export const Playground: Story = {
onChangeMonthDate={(dt) => {
setMonthDate(dt);
}}
presets={defaultPresets}
/>
);
})(),
Expand Down Expand Up @@ -58,29 +60,3 @@ export const PreservingTime: Story = {
);
})(),
};

export const WithPresets: Story = {
tags: ['isHidden'],
render: () => {
return ((args) => {
const [value, setValue] = React.useState<(number | Date)[]>([]);
const [monthDate, setMonthDate] = React.useState<number | Date>(
new Date(),
);
const { onChangeRange } = useTimeRangePreserve(setValue);

return (
<DateTimeRange
{...args}
value={value}
onChange={onChangeRange}
monthDate={monthDate}
onChangeMonthDate={(dt) => {
setMonthDate(dt);
}}
presets={defaultPresets}
/>
);
})();
},
};
45 changes: 23 additions & 22 deletions packages/datetime/src/components/DateTimeRange/DateTimeRange.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@ import {
} from './constants';
import { defaultDateTimeRangeI18n } from './i18n';
import { useMergeI18n } from '../../hooks';
import type { TDateRange } from '../../declarations';

export interface DateTimeRangeProps
extends Pick<CalendarProps, 'monthDate' | 'parseDate' | 'value' | 'weekDays'>,
extends Pick<CalendarProps, 'monthDate' | 'parseDate' | 'weekDays'>,
Pick<TimeProps, 'hasMillis' | 'hasSeconds'>,
Pick<PresetsProps, 'presets'>,
Required<Pick<IGlobalAttrs, 'id'>>,
Expand All @@ -38,16 +39,13 @@ export interface DateTimeRangeProps
/** Show the time input HTML element. */
hasTime?: boolean;
/** Function called when clicking a cell or editing a time input HTML. */
onChange?: (value: (number | Date)[], source: TDateTimeRangeSource) => void;
onChange?: (value: TDateRange, source: TDateTimeRangeSource) => void;
/** Placeholder for the presets list */
presetsPlaceholder?: PresetsProps['placeholder'];
/** Function called when the displayed month is changed (the left one). One
* of `number` or `Date`. */
onChangeMonthDate?: (monthDate: number | Date) => void;
/** Function called when clicking an option from preset date list. */
onChangePreset?: (preset: string) => void;
/** Selected preset */
preset?: string;
value?: TDateRange;
}

export const DateTimeRange: React.FC<DateTimeRangeProps> = ({
Expand All @@ -65,8 +63,6 @@ export const DateTimeRange: React.FC<DateTimeRangeProps> = ({
weekDays,
presetsPlaceholder,
presets,
preset,
onChangePreset = () => null,
style,
}) => {
const i18n = useMergeI18n(
Expand All @@ -89,6 +85,11 @@ export const DateTimeRange: React.FC<DateTimeRangeProps> = ({
setHoverDay(null);
}, []);

const canCalendarRender = React.useMemo(
() => value.length > 0 && value.every((x) => typeof x !== 'string'),
[value],
);

return (
<HFlex as={as} alignItems={'flex-start'} style={style}>
<VFlex flex={`1 1 ${presets ? '35%' : '50%'}`} alignItems="stretch">
Expand All @@ -108,7 +109,7 @@ export const DateTimeRange: React.FC<DateTimeRangeProps> = ({
onClick={(dt) => {
onChange(
rangeBehavior(
value,
value as (number | Date)[],
set(dt, {
hours: 0,
minutes: 0,
Expand All @@ -119,9 +120,9 @@ export const DateTimeRange: React.FC<DateTimeRangeProps> = ({
DATE_TIME_RANGE_SOURCE_CAL_LEFT,
);
}}
value={value}
hasLeftHoverEffect={value.length === 1}
hasRightHoverEffect={value.length === 1}
value={canCalendarRender ? (value as (number | Date)[]) : []}
hasLeftHoverEffect={canCalendarRender ? value.length === 1 : false}
hasRightHoverEffect={canCalendarRender ? value.length === 1 : false}
parseDate={parseDate}
weekDays={weekDays}
hoverDay={hoverDay}
Expand Down Expand Up @@ -150,8 +151,8 @@ export const DateTimeRange: React.FC<DateTimeRangeProps> = ({
);
}}
size="sm"
value={value.length >= 2 ? value[0] : null}
disabled={value.length < 2}
value={canCalendarRender && value.length >= 2 ? value[0] : ''}
disabled={!canCalendarRender || value.length < 2}
/>
</Flex>
)}
Expand Down Expand Up @@ -184,9 +185,9 @@ export const DateTimeRange: React.FC<DateTimeRangeProps> = ({
DATE_TIME_RANGE_SOURCE_CAL_RIGHT,
);
}}
value={value}
hasLeftHoverEffect={value.length === 1}
hasRightHoverEffect={value.length === 1}
value={canCalendarRender ? value : []}
hasLeftHoverEffect={canCalendarRender ? value.length === 1 : false}
hasRightHoverEffect={canCalendarRender ? value.length === 1 : false}
parseDate={parseDate}
weekDays={weekDays}
hoverDay={hoverDay}
Expand Down Expand Up @@ -215,22 +216,22 @@ export const DateTimeRange: React.FC<DateTimeRangeProps> = ({
);
}}
size="sm"
value={value.length >= 2 ? value[1] : null}
disabled={value.length < 2}
value={canCalendarRender && value.length >= 2 ? value[1] : ''}
disabled={!canCalendarRender || value.length < 2}
/>
</Flex>
)}
</VFlex>
{presets && (
<VFlex flex={'1 1 30%'} alignItems="stretch" minWidth="16rem">
<Presets
value={preset}
value={canCalendarRender ? [] : value}
id={`${id}-presets`}
maxMenuHeight={224}
placeholder={presetsPlaceholder}
presets={presets}
onChange={(newPreset) => {
onChangePreset(newPreset);
onChange={(newValue) => {
onChange(newValue, 'presets');
}}
/>
</VFlex>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { TMonthSelectorI18n } from "../MonthSelector";
import { TMonthSelectorI18n } from '../MonthSelector';

export type TDateTimeRangeSource =
| 'cal-left'
| 'cal-right'
| 'time-left'
| 'time-right';
| 'time-right'
| 'presets';

export type TDateTimeRangeI18n = TMonthSelectorI18n & {
/** The from month text */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { parseStrDate } from '../../parsers';
import { formatDate as formatDateHelper } from '../../helpers';

import type { IParseResult, ITime } from '../../declarations';
import type { IParseResult, ITime, TDateRange } from '../../declarations';
import { DateTimeRange, type DateTimeRangeProps } from '../DateTimeRange';
import {
DateTimeRangeInput,
Expand All @@ -32,12 +32,7 @@ export interface DateTimeRangeFloatingPickerProps
>,
Pick<
DateTimeRangeProps,
| 'monthDate'
| 'preset'
| 'presets'
| 'presetsPlaceholder'
| 'onChangePreset'
| 'weekDays'
'monthDate' | 'presets' | 'presetsPlaceholder' | 'weekDays'
>,
Pick<
DateTimeRangeInputProps,
Expand All @@ -55,7 +50,7 @@ export interface DateTimeRangeFloatingPickerProps
/** Internacionalization object */
i18n?: TDateTimeRangeFloatingPickerI18n;
/** Initial value for the input. */
value: (string | number | Date)[];
value: TDateRange;
/** Enable or disable the Apply button. */
disableApplyButton: boolean;
/** Function called when Cancel button is clicked. */
Expand Down Expand Up @@ -84,13 +79,10 @@ export const DateTimeRangeFloatingPicker: React.FC<
placement,
size = 'md',
value,
preset,
presets = defaultPresets,
presetsPlaceholder,
onChangePreset = () => null,
autoApply = false,
onRealTimeClick,

}) => {
const i18n = useMergeI18n(
userI18n,
Expand Down Expand Up @@ -179,13 +171,7 @@ export const DateTimeRangeFloatingPicker: React.FC<
i18n={i18n}
id={id ? `${id}-datetime-range` : null}
onChange={setTmpValue}
onChangePreset={onChangePreset}
value={
typeof tmpValue[0] === 'string'
? null
: (tmpValue as (number | Date)[])
}
preset={preset}
value={tmpValue}
presets={presets}
presetsPlaceholder={presetsPlaceholder}
monthDate={monthDate}
Expand Down
2 changes: 1 addition & 1 deletion packages/datetime/src/components/Presets/eq.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { TDateRange } from '../../declarations';

export const arePresetValuesEqual = (a: TDateRange, b: TDateRange) =>
a.length === b.length
a?.length === b?.length
? a.every((item, index) =>
typeof item === typeof b[index]
? typeof item === 'number' || typeof item === 'string'
Expand Down
6 changes: 3 additions & 3 deletions packages/datetime/src/components/Time/Time.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
type IStyledPolymorphic,
} from '@devoinc/genesys-ui';

import type { ITime } from '../../declarations';
import type { ITime, TDate } from '../../declarations';
import { getFormatTimeStr, formatDate } from '../../helpers';
import { TTimeI18n } from './declarations';
import { defaultTimeI18n } from './i18n';
Expand All @@ -26,7 +26,7 @@ export interface TimeProps
/** The size of the Time, specially the input. */
size?: TFieldSize;
/** Initial value. One of `number` or `Date`. */
value?: Date | number;
value?: TDate;
/** Diable the time field */
disabled?: boolean;
/** Internacionalization object */
Expand All @@ -41,7 +41,7 @@ export const Time: React.FC<TimeProps> = ({
onChange,
size = 'md',
style,
value,
value = '',
disabled = false,
i18n: userI18n = defaultTimeI18n,
minDate,
Expand Down
3 changes: 2 additions & 1 deletion packages/datetime/src/declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ export interface IParseResult {

export type TParseDate = (dt: number | Date) => IParseResult;

export type TDateRange = (number | string | Date)[];
export type TDate = number | string | Date;
export type TDateRange = TDate[];
4 changes: 2 additions & 2 deletions packages/datetime/src/helpers/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ export const getFormatDateStr = () => 'yyyy-MM-dd';
* Formats a date string based on the provided parameters
*/
export const formatDate = (
dt: Date | number,
dt: string | number | Date,
format: string = 'yyyy-MM-dd HH:mm:ss',
): string => formatFNS(dt, format);
): string => (typeof dt === 'string' ? dt : formatFNS(dt, format));

0 comments on commit b4dae51

Please sign in to comment.