Skip to content

Commit

Permalink
feat: [M3-8936] - Add Date Presets Functionality to Date Picker compo…
Browse files Browse the repository at this point in the history
…nent. (#11395)

* unit test coverage for HostNameTableCell

* Revert "unit test coverage for HostNameTableCell"

This reverts commit b274baf.

* chore: [M3-8662] - Update Github Actions actions (#11009)

* update actions

* add changeset

---------

Co-authored-by: Banks Nussman <banks@nussman.us>

* Basci date picker component

* Test coverage for date picker component

* DatePicker Stories

* Custom DateTimePicker component

* Reusable TimeZone Select Component

* Create custom DateTimeRangePicker component

* Storybook for DateTimePicker

* Fix tests and remove console warnings

* changeset

* Update packages/manager/src/components/DatePicker/DateTimeRangePicker.tsx

Co-authored-by: Connie Liu <139280159+coliu-akamai@users.noreply.github.com>

* Adjust styles for DatePicker

* Adjust styles for DateTimePicker

* update imports

* Render time and timezone conditionally in DateTimePicker component

* Move DatePicker to UI package

* Add DatePicker dependencies

* Code cleanup

* PR feedback

* code cleanup

* Move DatePicker back to src/components

* Reverting changes

* Code cleanup

* Adjust broken tests

* Update TimeZoneSelect.tsx

* Code cleanup

* Add validation for start date agains end date.

* Adjust styles for TimePicker component.

* Add the functionality to support Date Presets

* Update presets functionality and add test coverage.

* Added changeset: Add Date Presets Functionality to Date Picker component

* Persist the preset value

* Show the start date and end date fields only when custom is selected

* Add calendar icon to DateTimePicker component

* code cleanup and adjust tests

* Update packages/manager/src/components/DatePicker/DateTimeRangePicker.tsx

Co-authored-by: Nikhil Agrawal <165884194+nikhagra-akamai@users.noreply.github.com>

* update components

* Organize and additional prop support to DateTimeRangePicker component

* Code cleanup

* PR feedback - @coliu-akamai

* Move styles to theme level

* Revert "Move styles to theme level"

This reverts commit 15d9134.

* code cleanup

---------

Co-authored-by: Banks Nussman <115251059+bnussman-akamai@users.noreply.github.com>
Co-authored-by: Banks Nussman <banks@nussman.us>
Co-authored-by: Connie Liu <139280159+coliu-akamai@users.noreply.github.com>
Co-authored-by: Nikhil Agrawal <165884194+nikhagra-akamai@users.noreply.github.com>
  • Loading branch information
5 people authored Jan 8, 2025
1 parent 3511734 commit e97ff2f
Show file tree
Hide file tree
Showing 5 changed files with 708 additions and 184 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-11395-added-1734381247482.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Added
---

Add Date Presets Functionality to Date Picker component ([#11395](https://github.com/linode/manager/pull/11395))
42 changes: 35 additions & 7 deletions packages/manager/src/components/DatePicker/DateTimePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Divider } from '@linode/ui';
import { InputAdornment, TextField } from '@linode/ui';
import { Box } from '@linode/ui';
import { TextField } from '@linode/ui';
import CalendarTodayIcon from '@mui/icons-material/CalendarToday';
import { Grid, Popover } from '@mui/material';
import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
Expand Down Expand Up @@ -66,7 +67,7 @@ export const DateTimePicker = ({
onApply,
onCancel,
onChange,
placeholder = 'yyyy-MM-dd HH:mm',
placeholder = 'Select Date',
showTime = true,
showTimeZone = true,
sx,
Expand All @@ -75,13 +76,22 @@ export const DateTimePicker = ({
value = null,
}: DateTimePickerProps) => {
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);

// Current and original states
const [selectedDateTime, setSelectedDateTime] = useState<DateTime | null>(
value
);
const [selectedTimeZone, setSelectedTimeZone] = useState<null | string>(
timeZoneSelectProps.value || null
);

const [originalDateTime, setOriginalDateTime] = useState<DateTime | null>(
value
);
const [originalTimeZone, setOriginalTimeZone] = useState<null | string>(
timeZoneSelectProps.value || null
);

const TimePickerFieldProps: TextFieldProps = {
label: timeSelectProps?.label ?? 'Select Time',
noMarginTop: true,
Expand Down Expand Up @@ -115,6 +125,8 @@ export const DateTimePicker = ({

const handleApply = () => {
setAnchorEl(null);
setOriginalDateTime(selectedDateTime);
setOriginalTimeZone(selectedTimeZone);
onChange(selectedDateTime);

if (onApply) {
Expand All @@ -124,6 +136,9 @@ export const DateTimePicker = ({

const handleClose = () => {
setAnchorEl(null);
setSelectedDateTime(originalDateTime);
setSelectedTimeZone(originalTimeZone);

if (onCancel) {
onCancel();
}
Expand All @@ -139,16 +154,32 @@ export const DateTimePicker = ({
<LocalizationProvider dateAdapter={AdapterLuxon}>
<Box sx={{ minWidth: '300px', ...sx }}>
<TextField
InputProps={{
readOnly: true,
startAdornment: (
<InputAdornment position="start">
<CalendarTodayIcon
sx={{
color: '#c2c2ca !important',
fontSize: '20px !important',
left: '8px',
position: 'absolute',
}}
/>
</InputAdornment>
),
sx: { paddingLeft: '32px' },
}}
value={
selectedDateTime
? `${selectedDateTime.toFormat(format)}${
selectedTimeZone ? ` (${selectedTimeZone})` : ''
}`
: ''
}
InputProps={{ readOnly: true }}
errorText={errorText}
label={label}
noMarginTop
onClick={(event) => setAnchorEl(event.currentTarget)}
placeholder={placeholder}
/>
Expand Down Expand Up @@ -247,10 +278,6 @@ export const DateTimePicker = ({
<Divider />
<Box display="flex" justifyContent="flex-end">
<ActionsPanel
primaryButtonProps={{
label: 'Apply',
onClick: handleApply,
}}
secondaryButtonProps={{
buttonType: 'outlined',
label: 'Cancel',
Expand All @@ -260,6 +287,7 @@ export const DateTimePicker = ({
marginBottom: theme.spacing(1),
marginRight: theme.spacing(2),
})}
primaryButtonProps={{ label: 'Apply', onClick: handleApply }}
/>
</Box>
</Popover>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,61 +10,111 @@ type Story = StoryObj<typeof DateTimeRangePicker>;

export const Default: Story = {
args: {
endDateErrorMessage: '',
endDateTimeValue: null,
endLabel: 'End Date and Time',
endDateProps: {
errorMessage: '',
label: 'End Date and Time',
placeholder: '',
showTimeZone: false,
value: null,
},
format: 'yyyy-MM-dd HH:mm',
onChange: action('DateTime range changed'),
showEndTimeZone: true,
showStartTimeZone: true,
startDateErrorMessage: '',
startDateTimeValue: null,
startLabel: 'Start Date and Time',
startTimeZoneValue: null,
presetsProps: {
defaultValue: { label: '', value: '' },
enablePresets: true,
label: '',
placeholder: '',
},
startDateProps: {
errorMessage: '',
label: 'Start Date and Time',
placeholder: '',
showTimeZone: true,
timeZoneValue: null,
value: null,
},
sx: {},
},
render: (args) => <DateTimeRangePicker {...args} />,
};

export const WithInitialValues: Story = {
args: {
endDateTimeValue: DateTime.now(),
endLabel: 'End Date and Time',
endDateProps: {
label: 'End Date and Time',
showTimeZone: true,
value: DateTime.now(),
},
format: 'yyyy-MM-dd HH:mm',
onChange: action('DateTime range changed'),
showEndTimeZone: true,
showStartTimeZone: true,
startDateTimeValue: DateTime.now().minus({ days: 1 }),
startLabel: 'Start Date and Time',
startTimeZoneValue: 'America/New_York',
presetsProps: {
defaultValue: { label: 'Last 7 Days', value: '7days' },
enablePresets: true,
label: 'Time Range',
placeholder: 'Select Range',
},
startDateProps: {
label: 'Start Date and Time',
showTimeZone: true,
timeZoneValue: 'America/New_York',
value: DateTime.now().minus({ days: 1 }),
},
sx: {},
},
};

export const WithCustomErrors: Story = {
args: {
endDateErrorMessage: 'End date must be after the start date.',
endDateTimeValue: DateTime.now().minus({ days: 1 }),
endLabel: 'Custom End Label',
endDateProps: {
errorMessage: 'End date must be after the start date.',
label: 'Custom End Label',
placeholder: '',
showTimeZone: false,
value: DateTime.now().minus({ days: 1 }),
},
format: 'yyyy-MM-dd HH:mm',
onChange: action('DateTime range changed'),
startDateErrorMessage: 'Start date must be before the end date.',
startDateTimeValue: DateTime.now().minus({ days: 2 }),
startLabel: 'Custom Start Label',
presetsProps: {
defaultValue: { label: '', value: '' },
enablePresets: true,
label: '',
placeholder: '',
},
startDateProps: {
errorMessage: 'Start date must be before the end date.',
label: 'Start Date and Time',
placeholder: '',
showTimeZone: true,
timeZoneValue: null,
value: DateTime.now().minus({ days: 2 }),
},
},
};

const meta: Meta<typeof DateTimeRangePicker> = {
argTypes: {
endDateErrorMessage: {
control: 'text',
description: 'Custom error message for invalid end date',
},
endDateTimeValue: {
control: 'date',
description: 'Initial or controlled value for the end date-time',
},
endLabel: {
control: 'text',
description: 'Custom label for the end date-time picker',
endDateProps: {
errorMessage: {
control: 'text',
description: 'Custom error message for invalid end date',
},
label: {
control: 'text',
description: 'Custom label for the end date-time picker',
},
placeholder: {
control: 'text',
description: 'Placeholder for the end date-time',
},
showTimeZone: {
control: 'boolean',
description:
'Whether to show the timezone selector for the end date picker',
},
value: {
control: 'date',
description: 'Initial or controlled value for the end date-time',
},
},
format: {
control: 'text',
Expand All @@ -74,41 +124,67 @@ const meta: Meta<typeof DateTimeRangePicker> = {
action: 'DateTime range changed',
description: 'Callback when the date-time range changes',
},
showEndTimeZone: {
control: 'boolean',
description:
'Whether to show the timezone selector for the end date picker',
},
showStartTimeZone: {
control: 'boolean',
description:
'Whether to show the timezone selector for the start date picker',
},
startDateErrorMessage: {
control: 'text',
description: 'Custom error message for invalid start date',
},
startDateTimeValue: {
control: 'date',
description: 'Initial or controlled value for the start date-time',
presetsProps: {
defaultValue: {
label: {
control: 'text',
description: 'Default value label for the presets field',
},
value: {
control: 'text',
description: 'Default value for the presets field',
},
},
enablePresets: {
control: 'boolean',
description:
'If true, shows the date presets field instead of the date pickers',
},
label: {
control: 'text',
description: 'Label for the presets dropdown',
},
placeholder: {
control: 'text',
description: 'Placeholder for the presets dropdown',
},
},
startLabel: {
control: 'text',
description: 'Custom label for the start date-time picker',
},
startTimeZoneValue: {
control: 'text',
description: 'Initial or controlled value for the start timezone',
startDateProps: {
errorMessage: {
control: 'text',
description: 'Custom error message for invalid start date',
},
placeholder: {
control: 'text',
description: 'Placeholder for the start date-time',
},
showTimeZone: {
control: 'boolean',
description:
'Whether to show the timezone selector for the start date picker',
},
startLabel: {
control: 'text',
description: 'Custom label for the start date-time picker',
},
timeZoneValue: {
control: 'text',
description: 'Initial or controlled value for the start timezone',
},
value: {
control: 'date',
description: 'Initial or controlled value for the start date-time',
},
},
sx: {
control: 'object',
description: 'Styles to apply to the root element',
},
},
args: {
endLabel: 'End Date and Time',
endDateProps: { label: 'End Date and Time' },
format: 'yyyy-MM-dd HH:mm',
startLabel: 'Start Date and Time',
startDateProps: { label: 'Start Date and Time' },
},
component: DateTimeRangePicker,
title: 'Components/DatePicker/DateTimeRangePicker',
Expand Down
Loading

0 comments on commit e97ff2f

Please sign in to comment.