Separate date and datetime components (#9161)
Add a 2 components solution for FormDate and FormDateTime
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
import { FormAddressFieldInput } from '@/object-record/record-field/form-types/components/FormAddressFieldInput';
|
||||
import { FormBooleanFieldInput } from '@/object-record/record-field/form-types/components/FormBooleanFieldInput';
|
||||
import { FormDateTimeFieldInputBase } from '@/object-record/record-field/form-types/components/FormDateTimeFieldInputBase';
|
||||
import { FormDateFieldInput } from '@/object-record/record-field/form-types/components/FormDateFieldInput';
|
||||
import { FormEmailsFieldInput } from '@/object-record/record-field/form-types/components/FormEmailsFieldInput';
|
||||
import { FormFullNameFieldInput } from '@/object-record/record-field/form-types/components/FormFullNameFieldInput';
|
||||
import { FormLinksFieldInput } from '@/object-record/record-field/form-types/components/FormLinksFieldInput';
|
||||
@ -34,6 +34,7 @@ import { isFieldSelect } from '@/object-record/record-field/types/guards/isField
|
||||
import { isFieldText } from '@/object-record/record-field/types/guards/isFieldText';
|
||||
import { isFieldUuid } from '@/object-record/record-field/types/guards/isFieldUuid';
|
||||
import { JsonValue } from 'type-fest';
|
||||
import { FormDateTimeFieldInput } from '@/object-record/record-field/form-types/components/FormDateTimeFieldInput';
|
||||
|
||||
type FormFieldInputProps = {
|
||||
field: FieldDefinition<FieldMetadata>;
|
||||
@ -109,16 +110,14 @@ export const FormFieldInput = ({
|
||||
VariablePicker={VariablePicker}
|
||||
/>
|
||||
) : isFieldDate(field) ? (
|
||||
<FormDateTimeFieldInputBase
|
||||
mode="date"
|
||||
<FormDateFieldInput
|
||||
label={field.label}
|
||||
defaultValue={defaultValue as string | undefined}
|
||||
onPersist={onPersist}
|
||||
VariablePicker={VariablePicker}
|
||||
/>
|
||||
) : isFieldDateTime(field) ? (
|
||||
<FormDateTimeFieldInputBase
|
||||
mode="datetime"
|
||||
<FormDateTimeFieldInput
|
||||
label={field.label}
|
||||
defaultValue={defaultValue as string | undefined}
|
||||
onPersist={onPersist}
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
import { FormDateTimeFieldInput } from '@/object-record/record-field/form-types/components/FormDateTimeFieldInput';
|
||||
import { VariablePickerComponent } from '@/object-record/record-field/form-types/types/VariablePickerComponent';
|
||||
|
||||
type FormDateFieldInputProps = {
|
||||
label?: string;
|
||||
defaultValue: string | undefined;
|
||||
onPersist: (value: string | null) => void;
|
||||
VariablePicker?: VariablePickerComponent;
|
||||
};
|
||||
|
||||
export const FormDateFieldInput = ({
|
||||
label,
|
||||
defaultValue,
|
||||
onPersist,
|
||||
VariablePicker,
|
||||
}: FormDateFieldInputProps) => {
|
||||
return (
|
||||
<FormDateTimeFieldInput
|
||||
dateOnly
|
||||
label={label}
|
||||
defaultValue={defaultValue}
|
||||
onPersist={onPersist}
|
||||
VariablePicker={VariablePicker}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -69,27 +69,26 @@ type DraftValue =
|
||||
value: string;
|
||||
};
|
||||
|
||||
type FormDateTimeFieldInputBaseProps = {
|
||||
mode: 'date' | 'datetime';
|
||||
type FormDateTimeFieldInputProps = {
|
||||
dateOnly?: boolean;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
defaultValue: string | undefined;
|
||||
onPersist: (value: string | null) => void;
|
||||
VariablePicker?: VariablePickerComponent;
|
||||
};
|
||||
|
||||
export const FormDateTimeFieldInputBase = ({
|
||||
mode,
|
||||
export const FormDateTimeFieldInput = ({
|
||||
dateOnly,
|
||||
label,
|
||||
defaultValue,
|
||||
onPersist,
|
||||
VariablePicker,
|
||||
}: FormDateTimeFieldInputBaseProps) => {
|
||||
}: FormDateTimeFieldInputProps) => {
|
||||
const { timeZone } = useContext(UserContext);
|
||||
|
||||
const inputId = useId();
|
||||
|
||||
const placeholder = mode === 'date' ? 'mm/dd/yyyy' : 'mm/dd/yyyy hh:mm';
|
||||
|
||||
const [draftValue, setDraftValue] = useState<DraftValue>(
|
||||
isStandaloneVariableString(defaultValue)
|
||||
? {
|
||||
@ -116,7 +115,7 @@ export const FormDateTimeFieldInputBase = ({
|
||||
isDefined(draftValueAsDate) && !isStandaloneVariableString(defaultValue)
|
||||
? parseDateToString({
|
||||
date: draftValueAsDate,
|
||||
isDateTimeInput: mode === 'datetime',
|
||||
isDateTimeInput: !dateOnly,
|
||||
userTimezone: timeZone,
|
||||
})
|
||||
: '',
|
||||
@ -143,6 +142,8 @@ export const FormDateTimeFieldInputBase = ({
|
||||
const displayDatePicker =
|
||||
draftValue.type === 'static' && draftValue.mode === 'edit';
|
||||
|
||||
const placeholder = dateOnly ? 'mm/dd/yyyy' : 'mm/dd/yyyy hh:mm';
|
||||
|
||||
useListenClickOutside({
|
||||
refs: [datePickerWrapperRef],
|
||||
listenerId: 'FormDateTimeFieldInputBase',
|
||||
@ -168,7 +169,7 @@ export const FormDateTimeFieldInputBase = ({
|
||||
isDefined(newDate)
|
||||
? parseDateToString({
|
||||
date: newDate,
|
||||
isDateTimeInput: mode === 'datetime',
|
||||
isDateTimeInput: !dateOnly,
|
||||
userTimezone: timeZone,
|
||||
})
|
||||
: '',
|
||||
@ -226,7 +227,7 @@ export const FormDateTimeFieldInputBase = ({
|
||||
isDefined(newDate)
|
||||
? parseDateToString({
|
||||
date: newDate,
|
||||
isDateTimeInput: mode === 'datetime',
|
||||
isDateTimeInput: !dateOnly,
|
||||
userTimezone: timeZone,
|
||||
})
|
||||
: '',
|
||||
@ -262,7 +263,7 @@ export const FormDateTimeFieldInputBase = ({
|
||||
|
||||
const parsedInputDateTime = parseStringToDate({
|
||||
dateAsString: inputDateTimeTrimmed,
|
||||
isDateTimeInput: mode === 'datetime',
|
||||
isDateTimeInput: !dateOnly,
|
||||
userTimezone: timeZone,
|
||||
});
|
||||
|
||||
@ -288,7 +289,7 @@ export const FormDateTimeFieldInputBase = ({
|
||||
setInputDateTime(
|
||||
parseDateToString({
|
||||
date: validatedDate,
|
||||
isDateTimeInput: mode === 'datetime',
|
||||
isDateTimeInput: !dateOnly,
|
||||
userTimezone: timeZone,
|
||||
}),
|
||||
);
|
||||
@ -0,0 +1,370 @@
|
||||
import { MAX_DATE } from '@/ui/input/components/internal/date/constants/MaxDate';
|
||||
import { MIN_DATE } from '@/ui/input/components/internal/date/constants/MinDate';
|
||||
import { parseDateToString } from '@/ui/input/components/internal/date/utils/parseDateToString';
|
||||
import { expect } from '@storybook/jest';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import {
|
||||
fn,
|
||||
userEvent,
|
||||
waitFor,
|
||||
waitForElementToBeRemoved,
|
||||
within,
|
||||
} from '@storybook/test';
|
||||
import { DateTime } from 'luxon';
|
||||
import { FormDateFieldInput } from '../FormDateFieldInput';
|
||||
|
||||
const meta: Meta<typeof FormDateFieldInput> = {
|
||||
title: 'UI/Data/Field/Form/Input/FormDateFieldInput',
|
||||
component: FormDateFieldInput,
|
||||
args: {},
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof FormDateFieldInput>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await canvas.findByText('Created At');
|
||||
await canvas.findByDisplayValue('12/09/2024');
|
||||
},
|
||||
};
|
||||
|
||||
export const WithDefaultEmptyValue: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await canvas.findByText('Created At');
|
||||
await canvas.findByDisplayValue('');
|
||||
await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
},
|
||||
};
|
||||
|
||||
export const SetsDateWithInput: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const dialog = await canvas.findByRole('dialog');
|
||||
expect(dialog).toBeVisible();
|
||||
|
||||
await userEvent.type(input, '12/08/2024{enter}');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith('2024-12-08T00:00:00.000Z');
|
||||
});
|
||||
|
||||
expect(dialog).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const SetsDateWithDatePicker: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
const dayToChoose = await within(datePicker).findByRole('option', {
|
||||
name: 'Choose Saturday, December 7th, 2024',
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(dayToChoose),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/^2024-12-07/),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(canvas.getByDisplayValue('12/07/2024')).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const ResetsDateByClickingButton: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
const clearButton = await canvas.findByText('Clear');
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(clearButton),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(null);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue('');
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const ResetsDateByErasingInputContent: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
expect(input).toHaveDisplayValue('12/09/2024');
|
||||
|
||||
await userEvent.clear(input);
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '{Enter}'),
|
||||
|
||||
waitForElementToBeRemoved(() => canvas.queryByRole('dialog')),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(null);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue('');
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DefaultsToMinValueWhenTypingReallyOldDate: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '02/02/1500{Enter}'),
|
||||
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(MIN_DATE.toISOString());
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue(
|
||||
parseDateToString({
|
||||
date: MIN_DATE,
|
||||
isDateTimeInput: false,
|
||||
userTimezone: undefined,
|
||||
}),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
const expectedDate = DateTime.fromJSDate(MIN_DATE)
|
||||
.toLocal()
|
||||
.set({
|
||||
day: MIN_DATE.getUTCDate(),
|
||||
month: MIN_DATE.getUTCMonth() + 1,
|
||||
year: MIN_DATE.getUTCFullYear(),
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
});
|
||||
|
||||
const selectedDay = within(datePicker).getByRole('option', {
|
||||
selected: true,
|
||||
name: (accessibleName) => {
|
||||
// The name looks like "Choose Sunday, December 31st, 1899"
|
||||
return accessibleName.includes(expectedDate.toFormat('yyyy'));
|
||||
},
|
||||
});
|
||||
expect(selectedDay).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DefaultsToMaxValueWhenTypingReallyFarDate: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '02/02/2500{Enter}'),
|
||||
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(MAX_DATE.toISOString());
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue(
|
||||
parseDateToString({
|
||||
date: MAX_DATE,
|
||||
isDateTimeInput: false,
|
||||
userTimezone: undefined,
|
||||
}),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
const expectedDate = DateTime.fromJSDate(MAX_DATE)
|
||||
.toLocal()
|
||||
.set({
|
||||
day: MAX_DATE.getUTCDate(),
|
||||
month: MAX_DATE.getUTCMonth() + 1,
|
||||
year: MAX_DATE.getUTCFullYear(),
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
});
|
||||
|
||||
const selectedDay = within(datePicker).getByRole('option', {
|
||||
selected: true,
|
||||
name: (accessibleName) => {
|
||||
// The name looks like "Choose Thursday, December 30th, 2100"
|
||||
return accessibleName.includes(expectedDate.toFormat('yyyy'));
|
||||
},
|
||||
});
|
||||
expect(selectedDay).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const SwitchesToStandaloneVariable: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
VariablePicker: ({ onVariableSelect }) => {
|
||||
return (
|
||||
<button
|
||||
onClick={() => {
|
||||
onVariableSelect('{{test}}');
|
||||
}}
|
||||
>
|
||||
Add variable
|
||||
</button>
|
||||
);
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const addVariableButton = await canvas.findByText('Add variable');
|
||||
await userEvent.click(addVariableButton);
|
||||
|
||||
const variableTag = await canvas.findByText('test');
|
||||
expect(variableTag).toBeVisible();
|
||||
|
||||
const removeVariableButton = canvas.getByTestId(/^remove-icon/);
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(removeVariableButton),
|
||||
|
||||
waitForElementToBeRemoved(variableTag),
|
||||
waitFor(() => {
|
||||
const input = canvas.getByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const ClickingOutsideDoesNotResetInputState: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const defaultValueAsDisplayString = parseDateToString({
|
||||
date: new Date(args.defaultValue!),
|
||||
isDateTimeInput: false,
|
||||
userTimezone: undefined,
|
||||
});
|
||||
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
expect(input).toHaveDisplayValue(defaultValueAsDisplayString);
|
||||
|
||||
await userEvent.type(input, '{Backspace}{Backspace}');
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(canvasElement),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
]);
|
||||
|
||||
expect(args.onPersist).not.toHaveBeenCalled();
|
||||
|
||||
expect(input).toHaveDisplayValue(defaultValueAsDisplayString.slice(0, -2));
|
||||
},
|
||||
};
|
||||
@ -0,0 +1,397 @@
|
||||
import { MAX_DATE } from '@/ui/input/components/internal/date/constants/MaxDate';
|
||||
import { MIN_DATE } from '@/ui/input/components/internal/date/constants/MinDate';
|
||||
import { parseDateToString } from '@/ui/input/components/internal/date/utils/parseDateToString';
|
||||
import { expect } from '@storybook/jest';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import {
|
||||
fn,
|
||||
userEvent,
|
||||
waitFor,
|
||||
waitForElementToBeRemoved,
|
||||
within,
|
||||
} from '@storybook/test';
|
||||
import { DateTime } from 'luxon';
|
||||
import { FormDateTimeFieldInput } from '@/object-record/record-field/form-types/components/FormDateTimeFieldInput';
|
||||
|
||||
const meta: Meta<typeof FormDateTimeFieldInput> = {
|
||||
title: 'UI/Data/Field/Form/Input/FormDateTimeFieldInput',
|
||||
component: FormDateTimeFieldInput,
|
||||
args: {},
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof FormDateTimeFieldInput>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await canvas.findByText('Created At');
|
||||
await canvas.findByDisplayValue(/12\/09\/2024 \d{2}:20/);
|
||||
},
|
||||
};
|
||||
|
||||
export const WithDefaultEmptyValue: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await canvas.findByText('Created At');
|
||||
await canvas.findByDisplayValue('');
|
||||
await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
},
|
||||
};
|
||||
|
||||
export const SetsDateTimeWithInput: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const dialog = await canvas.findByRole('dialog');
|
||||
expect(dialog).toBeVisible();
|
||||
|
||||
await userEvent.type(input, '12/08/2024 12:10{enter}');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/2024-12-08T\d{2}:10:00.000Z/),
|
||||
);
|
||||
});
|
||||
|
||||
expect(dialog).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const DoesNotSetDateWithoutTime: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const dialog = await canvas.findByRole('dialog');
|
||||
expect(dialog).toBeVisible();
|
||||
|
||||
await userEvent.type(input, '12/08/2024{enter}');
|
||||
|
||||
expect(args.onPersist).not.toHaveBeenCalled();
|
||||
expect(dialog).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const SetsDateTimeWithDatePicker: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
const dayToChoose = await within(datePicker).findByRole('option', {
|
||||
name: 'Choose Saturday, December 7th, 2024',
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(dayToChoose),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/^2024-12-07/),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(
|
||||
canvas.getByDisplayValue(/12\/07\/2024 \d{2}:\d{2}/),
|
||||
).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const ResetsDateByClickingButton: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
const clearButton = await canvas.findByText('Clear');
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(clearButton),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(null);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue('');
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const ResetsDateByErasingInputContent: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
expect(input).toHaveDisplayValue(/12\/09\/2024 \d{2}:\d{2}/);
|
||||
|
||||
await userEvent.clear(input);
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '{Enter}'),
|
||||
|
||||
waitForElementToBeRemoved(() => canvas.queryByRole('dialog')),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(null);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue('');
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DefaultsToMinValueWhenTypingReallyOldDate: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '02/02/1500 10:10{Enter}'),
|
||||
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(MIN_DATE.toISOString());
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue(
|
||||
parseDateToString({
|
||||
date: MIN_DATE,
|
||||
isDateTimeInput: true,
|
||||
userTimezone: undefined,
|
||||
}),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
const expectedDate = DateTime.fromJSDate(MIN_DATE)
|
||||
.toLocal()
|
||||
.set({
|
||||
day: MIN_DATE.getUTCDate(),
|
||||
month: MIN_DATE.getUTCMonth() + 1,
|
||||
year: MIN_DATE.getUTCFullYear(),
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
});
|
||||
|
||||
const selectedDay = within(datePicker).getByRole('option', {
|
||||
selected: true,
|
||||
name: (accessibleName) => {
|
||||
// The name looks like "Choose Sunday, December 31st, 1899"
|
||||
return accessibleName.includes(expectedDate.toFormat('yyyy'));
|
||||
},
|
||||
});
|
||||
expect(selectedDay).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DefaultsToMaxValueWhenTypingReallyFarDate: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '02/02/2500 10:10{Enter}'),
|
||||
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(MAX_DATE.toISOString());
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue(
|
||||
parseDateToString({
|
||||
date: MAX_DATE,
|
||||
isDateTimeInput: true,
|
||||
userTimezone: undefined,
|
||||
}),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
const expectedDate = DateTime.fromJSDate(MAX_DATE)
|
||||
.toLocal()
|
||||
.set({
|
||||
day: MAX_DATE.getUTCDate(),
|
||||
month: MAX_DATE.getUTCMonth() + 1,
|
||||
year: MAX_DATE.getUTCFullYear(),
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
});
|
||||
|
||||
const selectedDay = within(datePicker).getByRole('option', {
|
||||
selected: true,
|
||||
name: (accessibleName) => {
|
||||
// The name looks like "Choose Thursday, December 30th, 2100"
|
||||
return accessibleName.includes(expectedDate.toFormat('yyyy'));
|
||||
},
|
||||
});
|
||||
expect(selectedDay).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const SwitchesToStandaloneVariable: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
VariablePicker: ({ onVariableSelect }) => {
|
||||
return (
|
||||
<button
|
||||
onClick={() => {
|
||||
onVariableSelect('{{test}}');
|
||||
}}
|
||||
>
|
||||
Add variable
|
||||
</button>
|
||||
);
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const addVariableButton = await canvas.findByText('Add variable');
|
||||
await userEvent.click(addVariableButton);
|
||||
|
||||
const variableTag = await canvas.findByText('test');
|
||||
expect(variableTag).toBeVisible();
|
||||
|
||||
const removeVariableButton = canvas.getByTestId(/^remove-icon/);
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(removeVariableButton),
|
||||
|
||||
waitForElementToBeRemoved(variableTag),
|
||||
waitFor(() => {
|
||||
const input = canvas.getByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const ClickingOutsideDoesNotResetInputState: Story = {
|
||||
args: {
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const defaultValueAsDisplayString = parseDateToString({
|
||||
date: new Date(args.defaultValue!),
|
||||
isDateTimeInput: true,
|
||||
userTimezone: undefined,
|
||||
});
|
||||
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
expect(input).toHaveDisplayValue(defaultValueAsDisplayString);
|
||||
|
||||
await userEvent.type(input, '{Backspace}{Backspace}');
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(canvasElement),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
]);
|
||||
|
||||
expect(args.onPersist).not.toHaveBeenCalled();
|
||||
|
||||
expect(input).toHaveDisplayValue(defaultValueAsDisplayString.slice(0, -2));
|
||||
},
|
||||
};
|
||||
@ -1,765 +0,0 @@
|
||||
import { MAX_DATE } from '@/ui/input/components/internal/date/constants/MaxDate';
|
||||
import { MIN_DATE } from '@/ui/input/components/internal/date/constants/MinDate';
|
||||
import { parseDateToString } from '@/ui/input/components/internal/date/utils/parseDateToString';
|
||||
import { expect } from '@storybook/jest';
|
||||
import { Meta, StoryObj } from '@storybook/react';
|
||||
import {
|
||||
fn,
|
||||
userEvent,
|
||||
waitFor,
|
||||
waitForElementToBeRemoved,
|
||||
within,
|
||||
} from '@storybook/test';
|
||||
import { DateTime } from 'luxon';
|
||||
import { FormDateTimeFieldInputBase } from '../FormDateTimeFieldInputBase';
|
||||
|
||||
const meta: Meta<typeof FormDateTimeFieldInputBase> = {
|
||||
title: 'UI/Data/Field/Form/Input/FormDateTimeFieldInputBase',
|
||||
component: FormDateTimeFieldInputBase,
|
||||
args: {},
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof FormDateTimeFieldInputBase>;
|
||||
|
||||
export const DateDefault: Story = {
|
||||
args: {
|
||||
mode: 'date',
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await canvas.findByText('Created At');
|
||||
await canvas.findByDisplayValue('12/09/2024');
|
||||
},
|
||||
};
|
||||
|
||||
export const DateWithDefaultEmptyValue: Story = {
|
||||
args: {
|
||||
mode: 'date',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await canvas.findByText('Created At');
|
||||
await canvas.findByDisplayValue('');
|
||||
await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
},
|
||||
};
|
||||
|
||||
export const DateSetsDateWithInput: Story = {
|
||||
args: {
|
||||
mode: 'date',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const dialog = await canvas.findByRole('dialog');
|
||||
expect(dialog).toBeVisible();
|
||||
|
||||
await userEvent.type(input, '12/08/2024{enter}');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith('2024-12-08T00:00:00.000Z');
|
||||
});
|
||||
|
||||
expect(dialog).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const DateSetsDateWithDatePicker: Story = {
|
||||
args: {
|
||||
mode: 'date',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
const dayToChoose = await within(datePicker).findByRole('option', {
|
||||
name: 'Choose Saturday, December 7th, 2024',
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(dayToChoose),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/^2024-12-07/),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(canvas.getByDisplayValue('12/07/2024')).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateResetsDateByClickingButton: Story = {
|
||||
args: {
|
||||
mode: 'date',
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
const clearButton = await canvas.findByText('Clear');
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(clearButton),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(null);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue('');
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateResetsDateByErasingInputContent: Story = {
|
||||
args: {
|
||||
mode: 'date',
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
expect(input).toHaveDisplayValue('12/09/2024');
|
||||
|
||||
await userEvent.clear(input);
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '{Enter}'),
|
||||
|
||||
waitForElementToBeRemoved(() => canvas.queryByRole('dialog')),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(null);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue('');
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateDefaultsToMinValueWhenTypingReallyOldDate: Story = {
|
||||
args: {
|
||||
mode: 'date',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '02/02/1500{Enter}'),
|
||||
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(MIN_DATE.toISOString());
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue(
|
||||
parseDateToString({
|
||||
date: MIN_DATE,
|
||||
isDateTimeInput: false,
|
||||
userTimezone: undefined,
|
||||
}),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
const expectedDate = DateTime.fromJSDate(MIN_DATE)
|
||||
.toLocal()
|
||||
.set({
|
||||
day: MIN_DATE.getUTCDate(),
|
||||
month: MIN_DATE.getUTCMonth() + 1,
|
||||
year: MIN_DATE.getUTCFullYear(),
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
});
|
||||
|
||||
const selectedDay = within(datePicker).getByRole('option', {
|
||||
selected: true,
|
||||
name: (accessibleName) => {
|
||||
// The name looks like "Choose Sunday, December 31st, 1899"
|
||||
return accessibleName.includes(expectedDate.toFormat('yyyy'));
|
||||
},
|
||||
});
|
||||
expect(selectedDay).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateDefaultsToMaxValueWhenTypingReallyFarDate: Story = {
|
||||
args: {
|
||||
mode: 'date',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '02/02/2500{Enter}'),
|
||||
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(MAX_DATE.toISOString());
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue(
|
||||
parseDateToString({
|
||||
date: MAX_DATE,
|
||||
isDateTimeInput: false,
|
||||
userTimezone: undefined,
|
||||
}),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
const expectedDate = DateTime.fromJSDate(MAX_DATE)
|
||||
.toLocal()
|
||||
.set({
|
||||
day: MAX_DATE.getUTCDate(),
|
||||
month: MAX_DATE.getUTCMonth() + 1,
|
||||
year: MAX_DATE.getUTCFullYear(),
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
});
|
||||
|
||||
const selectedDay = within(datePicker).getByRole('option', {
|
||||
selected: true,
|
||||
name: (accessibleName) => {
|
||||
// The name looks like "Choose Thursday, December 30th, 2100"
|
||||
return accessibleName.includes(expectedDate.toFormat('yyyy'));
|
||||
},
|
||||
});
|
||||
expect(selectedDay).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateSwitchesToStandaloneVariable: Story = {
|
||||
args: {
|
||||
mode: 'date',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
VariablePicker: ({ onVariableSelect }) => {
|
||||
return (
|
||||
<button
|
||||
onClick={() => {
|
||||
onVariableSelect('{{test}}');
|
||||
}}
|
||||
>
|
||||
Add variable
|
||||
</button>
|
||||
);
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const addVariableButton = await canvas.findByText('Add variable');
|
||||
await userEvent.click(addVariableButton);
|
||||
|
||||
const variableTag = await canvas.findByText('test');
|
||||
expect(variableTag).toBeVisible();
|
||||
|
||||
const removeVariableButton = canvas.getByTestId(/^remove-icon/);
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(removeVariableButton),
|
||||
|
||||
waitForElementToBeRemoved(variableTag),
|
||||
waitFor(() => {
|
||||
const input = canvas.getByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateClickingOutsideDoesNotResetInputState: Story = {
|
||||
args: {
|
||||
mode: 'date',
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const defaultValueAsDisplayString = parseDateToString({
|
||||
date: new Date(args.defaultValue!),
|
||||
isDateTimeInput: false,
|
||||
userTimezone: undefined,
|
||||
});
|
||||
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy');
|
||||
expect(input).toBeVisible();
|
||||
expect(input).toHaveDisplayValue(defaultValueAsDisplayString);
|
||||
|
||||
await userEvent.type(input, '{Backspace}{Backspace}');
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(canvasElement),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
]);
|
||||
|
||||
expect(args.onPersist).not.toHaveBeenCalled();
|
||||
|
||||
expect(input).toHaveDisplayValue(defaultValueAsDisplayString.slice(0, -2));
|
||||
},
|
||||
};
|
||||
|
||||
// ----
|
||||
|
||||
export const DateTimeDefault: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await canvas.findByText('Created At');
|
||||
await canvas.findByDisplayValue(/12\/09\/2024 \d{2}:20/);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateTimeWithDefaultEmptyValue: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
await canvas.findByText('Created At');
|
||||
await canvas.findByDisplayValue('');
|
||||
await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
},
|
||||
};
|
||||
|
||||
export const DateTimeSetsDateTimeWithInput: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const dialog = await canvas.findByRole('dialog');
|
||||
expect(dialog).toBeVisible();
|
||||
|
||||
await userEvent.type(input, '12/08/2024 12:10{enter}');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/2024-12-08T\d{2}:10:00.000Z/),
|
||||
);
|
||||
});
|
||||
|
||||
expect(dialog).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const DateTimeDoesNotSetDateWithoutTime: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const dialog = await canvas.findByRole('dialog');
|
||||
expect(dialog).toBeVisible();
|
||||
|
||||
await userEvent.type(input, '12/08/2024{enter}');
|
||||
|
||||
expect(args.onPersist).not.toHaveBeenCalled();
|
||||
expect(dialog).toBeVisible();
|
||||
},
|
||||
};
|
||||
|
||||
export const DateTimeSetsDateTimeWithDatePicker: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
const dayToChoose = await within(datePicker).findByRole('option', {
|
||||
name: 'Choose Saturday, December 7th, 2024',
|
||||
});
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(dayToChoose),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(
|
||||
expect.stringMatching(/^2024-12-07/),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(
|
||||
canvas.getByDisplayValue(/12\/07\/2024 \d{2}:\d{2}/),
|
||||
).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateTimeResetsDateByClickingButton: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
const clearButton = await canvas.findByText('Clear');
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(clearButton),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(null);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue('');
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateTimeResetsDateByErasingInputContent: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
expect(input).toHaveDisplayValue(/12\/09\/2024 \d{2}:\d{2}/);
|
||||
|
||||
await userEvent.clear(input);
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '{Enter}'),
|
||||
|
||||
waitForElementToBeRemoved(() => canvas.queryByRole('dialog')),
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(null);
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue('');
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateTimeDefaultsToMinValueWhenTypingReallyOldDate: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '02/02/1500 10:10{Enter}'),
|
||||
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(MIN_DATE.toISOString());
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue(
|
||||
parseDateToString({
|
||||
date: MIN_DATE,
|
||||
isDateTimeInput: true,
|
||||
userTimezone: undefined,
|
||||
}),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
const expectedDate = DateTime.fromJSDate(MIN_DATE)
|
||||
.toLocal()
|
||||
.set({
|
||||
day: MIN_DATE.getUTCDate(),
|
||||
month: MIN_DATE.getUTCMonth() + 1,
|
||||
year: MIN_DATE.getUTCFullYear(),
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
});
|
||||
|
||||
const selectedDay = within(datePicker).getByRole('option', {
|
||||
selected: true,
|
||||
name: (accessibleName) => {
|
||||
// The name looks like "Choose Sunday, December 31st, 1899"
|
||||
return accessibleName.includes(expectedDate.toFormat('yyyy'));
|
||||
},
|
||||
});
|
||||
expect(selectedDay).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateTimeDefaultsToMaxValueWhenTypingReallyFarDate: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
|
||||
await userEvent.click(input);
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.type(input, '02/02/2500 10:10{Enter}'),
|
||||
|
||||
waitFor(() => {
|
||||
expect(args.onPersist).toHaveBeenCalledWith(MAX_DATE.toISOString());
|
||||
}),
|
||||
waitFor(() => {
|
||||
expect(input).toHaveDisplayValue(
|
||||
parseDateToString({
|
||||
date: MAX_DATE,
|
||||
isDateTimeInput: true,
|
||||
userTimezone: undefined,
|
||||
}),
|
||||
);
|
||||
}),
|
||||
waitFor(() => {
|
||||
const expectedDate = DateTime.fromJSDate(MAX_DATE)
|
||||
.toLocal()
|
||||
.set({
|
||||
day: MAX_DATE.getUTCDate(),
|
||||
month: MAX_DATE.getUTCMonth() + 1,
|
||||
year: MAX_DATE.getUTCFullYear(),
|
||||
hour: 0,
|
||||
minute: 0,
|
||||
second: 0,
|
||||
millisecond: 0,
|
||||
});
|
||||
|
||||
const selectedDay = within(datePicker).getByRole('option', {
|
||||
selected: true,
|
||||
name: (accessibleName) => {
|
||||
// The name looks like "Choose Thursday, December 30th, 2100"
|
||||
return accessibleName.includes(expectedDate.toFormat('yyyy'));
|
||||
},
|
||||
});
|
||||
expect(selectedDay).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateTimeSwitchesToStandaloneVariable: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: undefined,
|
||||
onPersist: fn(),
|
||||
VariablePicker: ({ onVariableSelect }) => {
|
||||
return (
|
||||
<button
|
||||
onClick={() => {
|
||||
onVariableSelect('{{test}}');
|
||||
}}
|
||||
>
|
||||
Add variable
|
||||
</button>
|
||||
);
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const addVariableButton = await canvas.findByText('Add variable');
|
||||
await userEvent.click(addVariableButton);
|
||||
|
||||
const variableTag = await canvas.findByText('test');
|
||||
expect(variableTag).toBeVisible();
|
||||
|
||||
const removeVariableButton = canvas.getByTestId(/^remove-icon/);
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(removeVariableButton),
|
||||
|
||||
waitForElementToBeRemoved(variableTag),
|
||||
waitFor(() => {
|
||||
const input = canvas.getByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
}),
|
||||
]);
|
||||
},
|
||||
};
|
||||
|
||||
export const DateTimeClickingOutsideDoesNotResetInputState: Story = {
|
||||
args: {
|
||||
mode: 'datetime',
|
||||
label: 'Created At',
|
||||
defaultValue: '2024-12-09T13:20:19.631Z',
|
||||
onPersist: fn(),
|
||||
},
|
||||
play: async ({ canvasElement, args }) => {
|
||||
const defaultValueAsDisplayString = parseDateToString({
|
||||
date: new Date(args.defaultValue!),
|
||||
isDateTimeInput: true,
|
||||
userTimezone: undefined,
|
||||
});
|
||||
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
const input = await canvas.findByPlaceholderText('mm/dd/yyyy hh:mm');
|
||||
expect(input).toBeVisible();
|
||||
expect(input).toHaveDisplayValue(defaultValueAsDisplayString);
|
||||
|
||||
await userEvent.type(input, '{Backspace}{Backspace}');
|
||||
|
||||
const datePicker = await canvas.findByRole('dialog');
|
||||
expect(datePicker).toBeVisible();
|
||||
|
||||
await Promise.all([
|
||||
userEvent.click(canvasElement),
|
||||
|
||||
waitForElementToBeRemoved(datePicker),
|
||||
]);
|
||||
|
||||
expect(args.onPersist).not.toHaveBeenCalled();
|
||||
|
||||
expect(input).toHaveDisplayValue(defaultValueAsDisplayString.slice(0, -2));
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user