Skip to content

Commit

Permalink
feat: [DI-22550] - Enhance date range picker component (#11495)
Browse files Browse the repository at this point in the history
* feat: [DI-22550] - Enhanced default value logic

* feat: [DI-22550] - Added logic to disable end date calendar dates which are before selected start date

* feat: [DI-222550] - Updated test cases

* feat: [DI-22550] - Updated test case

* feat: [DI-22550] - Updated test cases

* feat: [DI-22550] - Added disabled support for timezone

* feat: [DI-22550] - Added qa id

* feat: [DI-22550] - Added Calcutta as additional timezone for IST

* feat: [DI-22550] - Removed error from date picker on click preset button

* feat: [DI-22550] - Remove end date error condition

* Added changeset

* updated changeset

* feat: [DI-22550] - Removed unused variable

* feat: [DI-22550] - fix typechek error
  • Loading branch information
nikhagra-akamai authored Jan 16, 2025
1 parent d51015d commit ee4ee7a
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 76 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-11495-changed-1736782822155.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Changed
---

add `Asia/Calcutta` zonename in `timezones.ts`, add `disabledTimeZone` property in `DateTimeRangePicker`, add `minDate` property to `DateTimePicker` ([#11495](https://github.com/linode/manager/pull/11495))
5 changes: 5 additions & 0 deletions packages/manager/src/assets/timezones/timezones.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1290,6 +1290,11 @@ export const timezones = [
name: 'Asia/Kolkata',
offset: 5.5,
},
{
label: 'India Standard Time - Calcutta',
name: 'Asia/Calcutta',
offset: 5.5,
},
{
label: 'Nepal Time',
name: 'Asia/Kathmandu',
Expand Down
13 changes: 13 additions & 0 deletions packages/manager/src/components/DatePicker/DateTimePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ import type { DateTime } from 'luxon';
export interface DateTimePickerProps {
/** Additional props for the DateCalendar */
dateCalendarProps?: Partial<DateCalendarProps<DateTime>>;
disabledTimeZone?: boolean;
/** Error text for the date picker field */
errorText?: string;
/** Format for displaying the date-time */
format?: string;
/** Label for the input field */
label?: string;
/** Minimum date-time before which all date-time will be disabled */
minDate?: DateTime;
/** Callback when the "Apply" button is clicked */
onApply?: () => void;
/** Callback when the "Cancel" button is clicked */
Expand Down Expand Up @@ -61,9 +64,11 @@ export interface DateTimePickerProps {

export const DateTimePicker = ({
dateCalendarProps = {},
disabledTimeZone = false,
errorText = '',
format = 'yyyy-MM-dd HH:mm',
label = 'Select Date and Time',
minDate,
onApply,
onCancel,
onChange,
Expand Down Expand Up @@ -193,6 +198,7 @@ export const DateTimePicker = ({
>
<Box padding={2}>
<DateCalendar
minDate={minDate}
onChange={handleDateChange}
value={selectedDateTime || null}
{...dateCalendarProps}
Expand Down Expand Up @@ -228,6 +234,12 @@ export const DateTimePicker = ({
{showTime && (
<Grid item xs={4}>
<TimePicker
minTime={
minDate &&
minDate.toISODate() === selectedDateTime?.toISODate()
? minDate
: undefined
}
slotProps={{
actionBar: {
sx: (theme: Theme) => ({
Expand Down Expand Up @@ -266,6 +278,7 @@ export const DateTimePicker = ({
{showTimeZone && (
<Grid item xs={7}>
<TimeZoneSelect
disabled={disabledTimeZone}
label={timeZoneSelectProps?.label || 'Timezone'}
noMarginTop
onChange={handleTimeZoneChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ type Story = StoryObj<typeof DateTimeRangePicker>;

export const Default: Story = {
args: {
enablePresets: true,
endDateProps: {
errorMessage: '',
label: 'End Date and Time',
placeholder: '',
showTimeZone: false,
value: null,
},

format: 'yyyy-MM-dd HH:mm',
onChange: action('DateTime range changed'),
presetsProps: {
defaultValue: { label: '', value: '' },
enablePresets: true,
defaultValue: '',
label: '',
placeholder: '',
},
Expand All @@ -40,16 +40,17 @@ export const Default: Story = {

export const WithInitialValues: Story = {
args: {
enablePresets: true,
endDateProps: {
label: 'End Date and Time',
showTimeZone: true,
value: DateTime.now(),
},

format: 'yyyy-MM-dd HH:mm',
onChange: action('DateTime range changed'),
presetsProps: {
defaultValue: { label: 'Last 7 Days', value: '7days' },
enablePresets: true,
defaultValue: '7days',
label: 'Time Range',
placeholder: 'Select Range',
},
Expand All @@ -65,8 +66,8 @@ export const WithInitialValues: Story = {

export const WithCustomErrors: Story = {
args: {
enablePresets: true,
endDateProps: {
errorMessage: 'End date must be after the start date.',
label: 'Custom End Label',
placeholder: '',
showTimeZone: false,
Expand All @@ -75,8 +76,8 @@ export const WithCustomErrors: Story = {
format: 'yyyy-MM-dd HH:mm',
onChange: action('DateTime range changed'),
presetsProps: {
defaultValue: { label: '', value: '' },
enablePresets: true,
defaultValue: '',

label: '',
placeholder: '',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import type { DateTimeRangePickerProps } from './DateTimeRangePicker';
const onChangeMock = vi.fn();

const Props: DateTimeRangePickerProps = {
enablePresets: true,
endDateProps: {
label: 'End Date and Time',
},
onChange: onChangeMock,
presetsProps: {
enablePresets: true,
label: 'Date Presets',
},

Expand Down Expand Up @@ -74,7 +74,7 @@ describe('DateTimeRangePicker Component', () => {
});
});

it('should show error when end date-time is before start date-time', async () => {
it('should disable the end date-time which is before the selected start date-time', async () => {
renderWithTheme(<DateTimeRangePicker onChange={onChangeMock} />);

// Set start date-time to the 15th
Expand All @@ -87,20 +87,14 @@ describe('DateTimeRangePicker Component', () => {
const endDateField = screen.getByLabelText('End Date and Time');
await userEvent.click(endDateField);

// Set start date-time to the 10th
await userEvent.click(screen.getByRole('gridcell', { name: '10' }));
await userEvent.click(screen.getByRole('button', { name: 'Apply' }));

// Confirm error message is displayed
expect(
screen.getByText('End date/time cannot be before the start date/time.')
).toBeInTheDocument();
expect(screen.getByRole('gridcell', { name: '10' })).toBeDisabled();
});

it('should show error when start date-time is after end date-time', async () => {
const updateProps = {
...Props,
presetsProps: { ...Props.presetsProps, enablePresets: false },
enablePresets: false,
presetsProps: { ...Props.presetsProps },
};
renderWithTheme(<DateTimeRangePicker {...updateProps} />);

Expand All @@ -125,6 +119,7 @@ describe('DateTimeRangePicker Component', () => {
it('should display custom error messages when start date-time is after end date-time', async () => {
const updatedProps = {
...Props,
enablePresets: false,
endDateProps: {
...Props.endDateProps,
errorMessage: 'Custom end date error',
Expand Down Expand Up @@ -323,24 +318,9 @@ describe('DateTimeRangePicker Component', () => {
await userEvent.click(endDateField);

// Set start date-time to the 12th
await userEvent.click(screen.getByRole('gridcell', { name: '12' }));
await userEvent.click(screen.getByRole('gridcell', { name: '17' }));
await userEvent.click(screen.getByRole('button', { name: 'Apply' }));

// Confirm error message is shown since the click was blocked
expect(
screen.getByText('End date/time cannot be before the start date/time.')
).toBeInTheDocument();

// Set start date-time to the 11th
await userEvent.click(startDateField);
await userEvent.click(screen.getByRole('gridcell', { name: '11' }));
await userEvent.click(screen.getByRole('button', { name: 'Apply' }));

// Confirm error message is not displayed
expect(
screen.queryByText('End date/time cannot be before the start date/time.')
).not.toBeInTheDocument();

// Set start date-time to the 20th
await userEvent.click(startDateField);
await userEvent.click(screen.getByRole('gridcell', { name: '20' }));
Expand Down
Loading

0 comments on commit ee4ee7a

Please sign in to comment.