Skip to content

Commit e97ff2f

Browse files
cpathipabnussman-akamaibnussmancoliu-akamainikhagra-akamai
authored
feat: [M3-8936] - Add Date Presets Functionality to Date Picker component. (#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 <[email protected]> * 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 <[email protected]> * 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 <[email protected]> * 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 <[email protected]> Co-authored-by: Banks Nussman <[email protected]> Co-authored-by: Connie Liu <[email protected]> Co-authored-by: Nikhil Agrawal <[email protected]>
1 parent 3511734 commit e97ff2f

File tree

5 files changed

+708
-184
lines changed

5 files changed

+708
-184
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Added
3+
---
4+
5+
Add Date Presets Functionality to Date Picker component ([#11395](https://github.com/linode/manager/pull/11395))

packages/manager/src/components/DatePicker/DateTimePicker.tsx

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Divider } from '@linode/ui';
2+
import { InputAdornment, TextField } from '@linode/ui';
23
import { Box } from '@linode/ui';
3-
import { TextField } from '@linode/ui';
4+
import CalendarTodayIcon from '@mui/icons-material/CalendarToday';
45
import { Grid, Popover } from '@mui/material';
56
import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
67
import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
@@ -66,7 +67,7 @@ export const DateTimePicker = ({
6667
onApply,
6768
onCancel,
6869
onChange,
69-
placeholder = 'yyyy-MM-dd HH:mm',
70+
placeholder = 'Select Date',
7071
showTime = true,
7172
showTimeZone = true,
7273
sx,
@@ -75,13 +76,22 @@ export const DateTimePicker = ({
7576
value = null,
7677
}: DateTimePickerProps) => {
7778
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
79+
80+
// Current and original states
7881
const [selectedDateTime, setSelectedDateTime] = useState<DateTime | null>(
7982
value
8083
);
8184
const [selectedTimeZone, setSelectedTimeZone] = useState<null | string>(
8285
timeZoneSelectProps.value || null
8386
);
8487

88+
const [originalDateTime, setOriginalDateTime] = useState<DateTime | null>(
89+
value
90+
);
91+
const [originalTimeZone, setOriginalTimeZone] = useState<null | string>(
92+
timeZoneSelectProps.value || null
93+
);
94+
8595
const TimePickerFieldProps: TextFieldProps = {
8696
label: timeSelectProps?.label ?? 'Select Time',
8797
noMarginTop: true,
@@ -115,6 +125,8 @@ export const DateTimePicker = ({
115125

116126
const handleApply = () => {
117127
setAnchorEl(null);
128+
setOriginalDateTime(selectedDateTime);
129+
setOriginalTimeZone(selectedTimeZone);
118130
onChange(selectedDateTime);
119131

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

125137
const handleClose = () => {
126138
setAnchorEl(null);
139+
setSelectedDateTime(originalDateTime);
140+
setSelectedTimeZone(originalTimeZone);
141+
127142
if (onCancel) {
128143
onCancel();
129144
}
@@ -139,16 +154,32 @@ export const DateTimePicker = ({
139154
<LocalizationProvider dateAdapter={AdapterLuxon}>
140155
<Box sx={{ minWidth: '300px', ...sx }}>
141156
<TextField
157+
InputProps={{
158+
readOnly: true,
159+
startAdornment: (
160+
<InputAdornment position="start">
161+
<CalendarTodayIcon
162+
sx={{
163+
color: '#c2c2ca !important',
164+
fontSize: '20px !important',
165+
left: '8px',
166+
position: 'absolute',
167+
}}
168+
/>
169+
</InputAdornment>
170+
),
171+
sx: { paddingLeft: '32px' },
172+
}}
142173
value={
143174
selectedDateTime
144175
? `${selectedDateTime.toFormat(format)}${
145176
selectedTimeZone ? ` (${selectedTimeZone})` : ''
146177
}`
147178
: ''
148179
}
149-
InputProps={{ readOnly: true }}
150180
errorText={errorText}
151181
label={label}
182+
noMarginTop
152183
onClick={(event) => setAnchorEl(event.currentTarget)}
153184
placeholder={placeholder}
154185
/>
@@ -247,10 +278,6 @@ export const DateTimePicker = ({
247278
<Divider />
248279
<Box display="flex" justifyContent="flex-end">
249280
<ActionsPanel
250-
primaryButtonProps={{
251-
label: 'Apply',
252-
onClick: handleApply,
253-
}}
254281
secondaryButtonProps={{
255282
buttonType: 'outlined',
256283
label: 'Cancel',
@@ -260,6 +287,7 @@ export const DateTimePicker = ({
260287
marginBottom: theme.spacing(1),
261288
marginRight: theme.spacing(2),
262289
})}
290+
primaryButtonProps={{ label: 'Apply', onClick: handleApply }}
263291
/>
264292
</Box>
265293
</Popover>

packages/manager/src/components/DatePicker/DateTimeRangePicker.stories.tsx

Lines changed: 135 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -10,61 +10,111 @@ type Story = StoryObj<typeof DateTimeRangePicker>;
1010

1111
export const Default: Story = {
1212
args: {
13-
endDateErrorMessage: '',
14-
endDateTimeValue: null,
15-
endLabel: 'End Date and Time',
13+
endDateProps: {
14+
errorMessage: '',
15+
label: 'End Date and Time',
16+
placeholder: '',
17+
showTimeZone: false,
18+
value: null,
19+
},
1620
format: 'yyyy-MM-dd HH:mm',
1721
onChange: action('DateTime range changed'),
18-
showEndTimeZone: true,
19-
showStartTimeZone: true,
20-
startDateErrorMessage: '',
21-
startDateTimeValue: null,
22-
startLabel: 'Start Date and Time',
23-
startTimeZoneValue: null,
22+
presetsProps: {
23+
defaultValue: { label: '', value: '' },
24+
enablePresets: true,
25+
label: '',
26+
placeholder: '',
27+
},
28+
startDateProps: {
29+
errorMessage: '',
30+
label: 'Start Date and Time',
31+
placeholder: '',
32+
showTimeZone: true,
33+
timeZoneValue: null,
34+
value: null,
35+
},
36+
sx: {},
2437
},
2538
render: (args) => <DateTimeRangePicker {...args} />,
2639
};
2740

2841
export const WithInitialValues: Story = {
2942
args: {
30-
endDateTimeValue: DateTime.now(),
31-
endLabel: 'End Date and Time',
43+
endDateProps: {
44+
label: 'End Date and Time',
45+
showTimeZone: true,
46+
value: DateTime.now(),
47+
},
3248
format: 'yyyy-MM-dd HH:mm',
3349
onChange: action('DateTime range changed'),
34-
showEndTimeZone: true,
35-
showStartTimeZone: true,
36-
startDateTimeValue: DateTime.now().minus({ days: 1 }),
37-
startLabel: 'Start Date and Time',
38-
startTimeZoneValue: 'America/New_York',
50+
presetsProps: {
51+
defaultValue: { label: 'Last 7 Days', value: '7days' },
52+
enablePresets: true,
53+
label: 'Time Range',
54+
placeholder: 'Select Range',
55+
},
56+
startDateProps: {
57+
label: 'Start Date and Time',
58+
showTimeZone: true,
59+
timeZoneValue: 'America/New_York',
60+
value: DateTime.now().minus({ days: 1 }),
61+
},
62+
sx: {},
3963
},
4064
};
4165

4266
export const WithCustomErrors: Story = {
4367
args: {
44-
endDateErrorMessage: 'End date must be after the start date.',
45-
endDateTimeValue: DateTime.now().minus({ days: 1 }),
46-
endLabel: 'Custom End Label',
68+
endDateProps: {
69+
errorMessage: 'End date must be after the start date.',
70+
label: 'Custom End Label',
71+
placeholder: '',
72+
showTimeZone: false,
73+
value: DateTime.now().minus({ days: 1 }),
74+
},
4775
format: 'yyyy-MM-dd HH:mm',
4876
onChange: action('DateTime range changed'),
49-
startDateErrorMessage: 'Start date must be before the end date.',
50-
startDateTimeValue: DateTime.now().minus({ days: 2 }),
51-
startLabel: 'Custom Start Label',
77+
presetsProps: {
78+
defaultValue: { label: '', value: '' },
79+
enablePresets: true,
80+
label: '',
81+
placeholder: '',
82+
},
83+
startDateProps: {
84+
errorMessage: 'Start date must be before the end date.',
85+
label: 'Start Date and Time',
86+
placeholder: '',
87+
showTimeZone: true,
88+
timeZoneValue: null,
89+
value: DateTime.now().minus({ days: 2 }),
90+
},
5291
},
5392
};
5493

5594
const meta: Meta<typeof DateTimeRangePicker> = {
5695
argTypes: {
57-
endDateErrorMessage: {
58-
control: 'text',
59-
description: 'Custom error message for invalid end date',
60-
},
61-
endDateTimeValue: {
62-
control: 'date',
63-
description: 'Initial or controlled value for the end date-time',
64-
},
65-
endLabel: {
66-
control: 'text',
67-
description: 'Custom label for the end date-time picker',
96+
endDateProps: {
97+
errorMessage: {
98+
control: 'text',
99+
description: 'Custom error message for invalid end date',
100+
},
101+
label: {
102+
control: 'text',
103+
description: 'Custom label for the end date-time picker',
104+
},
105+
placeholder: {
106+
control: 'text',
107+
description: 'Placeholder for the end date-time',
108+
},
109+
showTimeZone: {
110+
control: 'boolean',
111+
description:
112+
'Whether to show the timezone selector for the end date picker',
113+
},
114+
value: {
115+
control: 'date',
116+
description: 'Initial or controlled value for the end date-time',
117+
},
68118
},
69119
format: {
70120
control: 'text',
@@ -74,41 +124,67 @@ const meta: Meta<typeof DateTimeRangePicker> = {
74124
action: 'DateTime range changed',
75125
description: 'Callback when the date-time range changes',
76126
},
77-
showEndTimeZone: {
78-
control: 'boolean',
79-
description:
80-
'Whether to show the timezone selector for the end date picker',
81-
},
82-
showStartTimeZone: {
83-
control: 'boolean',
84-
description:
85-
'Whether to show the timezone selector for the start date picker',
86-
},
87-
startDateErrorMessage: {
88-
control: 'text',
89-
description: 'Custom error message for invalid start date',
90-
},
91-
startDateTimeValue: {
92-
control: 'date',
93-
description: 'Initial or controlled value for the start date-time',
127+
presetsProps: {
128+
defaultValue: {
129+
label: {
130+
control: 'text',
131+
description: 'Default value label for the presets field',
132+
},
133+
value: {
134+
control: 'text',
135+
description: 'Default value for the presets field',
136+
},
137+
},
138+
enablePresets: {
139+
control: 'boolean',
140+
description:
141+
'If true, shows the date presets field instead of the date pickers',
142+
},
143+
label: {
144+
control: 'text',
145+
description: 'Label for the presets dropdown',
146+
},
147+
placeholder: {
148+
control: 'text',
149+
description: 'Placeholder for the presets dropdown',
150+
},
94151
},
95-
startLabel: {
96-
control: 'text',
97-
description: 'Custom label for the start date-time picker',
98-
},
99-
startTimeZoneValue: {
100-
control: 'text',
101-
description: 'Initial or controlled value for the start timezone',
152+
startDateProps: {
153+
errorMessage: {
154+
control: 'text',
155+
description: 'Custom error message for invalid start date',
156+
},
157+
placeholder: {
158+
control: 'text',
159+
description: 'Placeholder for the start date-time',
160+
},
161+
showTimeZone: {
162+
control: 'boolean',
163+
description:
164+
'Whether to show the timezone selector for the start date picker',
165+
},
166+
startLabel: {
167+
control: 'text',
168+
description: 'Custom label for the start date-time picker',
169+
},
170+
timeZoneValue: {
171+
control: 'text',
172+
description: 'Initial or controlled value for the start timezone',
173+
},
174+
value: {
175+
control: 'date',
176+
description: 'Initial or controlled value for the start date-time',
177+
},
102178
},
103179
sx: {
104180
control: 'object',
105181
description: 'Styles to apply to the root element',
106182
},
107183
},
108184
args: {
109-
endLabel: 'End Date and Time',
185+
endDateProps: { label: 'End Date and Time' },
110186
format: 'yyyy-MM-dd HH:mm',
111-
startLabel: 'Start Date and Time',
187+
startDateProps: { label: 'Start Date and Time' },
112188
},
113189
component: DateTimeRangePicker,
114190
title: 'Components/DatePicker/DateTimeRangePicker',

0 commit comments

Comments
 (0)