-
Notifications
You must be signed in to change notification settings - Fork 6
feat: day picker #970
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: kubecon-2025
Are you sure you want to change the base?
feat: day picker #970
Conversation
- Updated package.json to remove react-dates and add react-day-picker. - Created DateTimePicker component using react-day-picker, supporting both single and range date selection. - Removed SingleDatePickerComponent as it is no longer needed. - Added new styles for the DateTimePicker component. - Updated constants and types to accommodate changes in date handling. - Removed old date picker styles and configurations related to react-dates. - Adjusted Vite configuration to exclude react-dates from manual chunks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR migrates the date picker component from the deprecated react-dates library to the modern react-day-picker library. The refactor adds support for both single date and date range selection, improves accessibility, and reduces dependency bloat.
Key Changes:
- Replaced
react-dateswithreact-day-pickerv9.11.2 and removed deprecated dependencies - Introduced discriminated union types to support both single date and range picker modes
- Added custom navigation components using the existing Button and Icon components for consistent styling
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| package.json | Replaced react-dates dependency with react-day-picker and removed related type definitions |
| package-lock.json | Updated lockfile with new dependencies including date-fns, date-fns-jalali, and @date-fns/tz |
| vite.config.ts | Removed react-dates manual chunk configuration |
| src/Shared/Components/DatePicker/types.ts | Refactored types to use discriminated unions for single/range picker modes and defined new handler types |
| src/Shared/Components/DatePicker/utils.tsx | Added generic type parameter to DEFAULT_TIME_OPTIONS and removed outdated eslint comment |
| src/Shared/Components/DatePicker/constants.tsx | Replaced legacy date styles with custom navigation button components using react-day-picker's CustomComponents API |
| src/Shared/Components/DatePicker/DateTimePicker.tsx | Complete rewrite using react-day-picker with Popover component, supporting both single and range selection modes |
| src/Shared/Components/DatePicker/DateTimePicker.scss | New styles customizing react-day-picker appearance with CSS custom properties |
| src/Shared/Components/DatePicker/datePicker.scss | Removed legacy styles for react-dates |
| src/Shared/Components/DatePicker/SingleDatePickerComponent.tsx | Removed deprecated component |
| src/Shared/Components/DatePicker/index.ts | Removed export of deprecated SingleDatePickerComponent |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.
|
|
||
| const renderInputLabel = () => { | ||
| if (isRangePicker) { | ||
| const fromDate = dateRange.from ? dayjs(dateRange.from).format(DATE_TIME_FORMATS.DD_MMM_YYYY) : '' |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] When dateRange.from is falsy in range picker mode, the fromDate will be an empty string, resulting in a label like - .... This could be visually awkward. Consider displaying a more user-friendly placeholder text like "Select start date - ..." when from is not set.
| const fromDate = dateRange.from ? dayjs(dateRange.from).format(DATE_TIME_FORMATS.DD_MMM_YYYY) : '' | |
| const fromDate = dateRange.from ? dayjs(dateRange.from).format(DATE_TIME_FORMATS.DD_MMM_YYYY) : 'Select start date' |
|
|
||
| const triggerElement = ( | ||
| <SelectPicker | ||
| inputId="date-picker-input" |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The label element uses htmlFor={id} but the actual input element inside SelectPicker uses inputId="date-picker-input" (a hardcoded value). This means the label won't properly associate with the input when clicked. Either use the id prop for the inputId or ensure they match for proper accessibility.
| const handleSingleDateSelect: OnSelectHandler<Date> = (date) => { | ||
| if (!isDateUpdateRange(isRangePicker, onChange)) { | ||
| const updatedDate = date ? updateDate(dateObject, date) : null | ||
| onChange(updatedDate) | ||
| } | ||
| } |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The handleSingleDateSelect function might pass null to onChange when no date is selected, but the UpdateSingleDateType type signature expects a non-nullable Date parameter. This could cause a type error. Consider updating the type to UpdateSingleDateType = (date: Date | null) => void or ensure that null dates are properly handled.
| const today = getTodayDate() | ||
| today.setHours(0, 0, 0, 0) |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The getTodayDate() function is called and then mutated with setHours(0, 0, 0, 0). This mutates a fresh Date object on every call to getDisabledState(). Consider creating the normalized today date once using useMemo to avoid unnecessary object mutations on every render when getDisabledState is called.
| dateRange = { | ||
| from: getTodayDate(), | ||
| to: getTodayDate(), | ||
| }, |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The default value for dateRange is set to { from: getTodayDate(), to: getTodayDate() }, which means both start and end dates default to today. This could be confusing for range pickers where typically the end date might be undefined initially. Consider using { from: getTodayDate(), to: undefined } or making the default value conditional based on whether it's a range picker.
| } | ||
|
|
||
| export type UpdateDateRangeType = (dateRange: DateRangeType) => void | ||
| export type UpdateSingleDateType = (date: Date) => void |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The UpdateSingleDateType type is defined as (date: Date) => void, but in the handleSingleDateSelect function on line 130, onChange may be called with null when updatedDate is null. Update the type to (date: Date | null) => void to accurately reflect the function signature.
| export type UpdateSingleDateType = (date: Date) => void | |
| export type UpdateSingleDateType = (date: Date | null) => void |
| value: '', | ||
| startIcon: <Icon name="ic-calendar" color={null} />, | ||
| }} | ||
| size={ComponentSizeType.large} |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The disabled prop is not passed to the date picker trigger element (SelectPicker). When the DateTimePicker is disabled, only the time picker reflects this state (line 257), but the date picker input appears enabled. Consider passing isDisabled={disabled} to the trigger SelectPicker to ensure consistent disabled state across both inputs.
| size={ComponentSizeType.large} | |
| size={ComponentSizeType.large} | |
| isDisabled={disabled} |
| const handleDateRangeChange = (range: DateRange) => { | ||
| if (isDateUpdateRange(isRangePicker, onChange)) { | ||
| const fromDate = range.from ? range.from : new Date() | ||
| const toDate = range.to ? range.to : undefined | ||
|
|
||
| const handleFocusChange = ({ focused }) => { | ||
| setFocused(focused) | ||
| onChange({ | ||
| from: fromDate, | ||
| to: toDate, | ||
| }) |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When range.from is falsy in range selection mode, the code defaults to new Date(). This means that if a user clears the start date, it will automatically default to today instead of allowing an empty/undefined state. Consider whether this is the intended behavior or if it should allow undefined for from.
| */ | ||
| datePickerProps?: any | ||
| interface DateRangeType { | ||
| from: Date |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The DateRangeType interface requires from to always be defined (from: Date), but in the handleDateRangeChange function, when range.from is undefined, it defaults to new Date(). Consider whether from should be optional (from?: Date) to better represent the actual state during range selection, or document that from must always be present.
| from: Date | |
| from?: Date |
| type="button" | ||
| key={optionLabel} | ||
| className="bg__hover cn-9 dc__tab-focus dc__align-left dc__transparent p-8 br-4" | ||
| onClick={onClick || getRangeUpdateHandler(value)} |
Copilot
AI
Dec 1, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The shortcut buttons in the range picker lack accessible labels. Each button should have an aria-label attribute to describe its purpose for screen reader users, especially since the buttons only contain text that might not be self-descriptive in all contexts.
| onClick={onClick || getRangeUpdateHandler(value)} | |
| onClick={onClick || getRangeUpdateHandler(value)} | |
| aria-label={`Select range: ${optionLabel}`} |
Description
This pull request completely refactors the date picker component to replace the
react-dateslibrary withreact-day-picker. The new implementation introduces support for both single date and range selection, improves accessibility and customizability, and updates the styling to match the new library. Several legacy files and dependencies are removed, and the API for the date picker is updated for clarity and flexibility.Migration from
react-datestoreact-day-picker:react-dateswithreact-day-pickerinDateTimePicker.tsx, updating all related logic to support both single date and range selection, and removed the old focus trap and moment.js usage. ([[1]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-dc6bf3a6084005ddabd8b1bf06bec25bfabf5a30ef376cb4835c2c226a755bd6L17-R48),[[2]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-dc6bf3a6084005ddabd8b1bf06bec25bfabf5a30ef376cb4835c2c226a755bd6L52-R189),[[3]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-dc6bf3a6084005ddabd8b1bf06bec25bfabf5a30ef376cb4835c2c226a755bd6L93-R211), [4] [5]SingleDatePickerComponent.tsxand old styles indatePicker.scss. ([[1]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-eca9ccbc1a9c798ae4001b6ef206bc9297843582257199060d25e02c10fd30ebL1-L80),[[2]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-db59d30cff39b6924b419a9f6fd6b4e01a673a3861bb99984a209e50903a2541L1-L103),[[3]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-b22dd3646a7f1a8bd9b1a23ab285cf4c91ebd70e348e125a1613bdf80a46459dL20))Styling and Customization:
DateTimePicker.scssto match the look and feel ofreact-day-pickerand support range selection. ([src/Shared/Components/DatePicker/DateTimePicker.scssR1-R71](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-307fd37871b0ead4448a16ec2cccd71f7a68b3c7848c8c954fe38b9d5bf2986aR1-R71))constants.tsx. ([[1]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-4ccc31505f53c29409f6361ae5d0f498fe4e1824e719c6f487a31ce76590e477L17-R24),[[2]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-4ccc31505f53c29409f6361ae5d0f498fe4e1824e719c6f487a31ce76590e477R124-R154))API and Type Updates:
DateTimePickerPropsto support both single date and range selection, removed references toreact-datestypes, and improved clarity of props. ([[1]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-9031429d6cd8ea472101914a172cd7c014b93160d9632bf4a65ad46b0092a305L17),[[2]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-9031429d6cd8ea472101914a172cd7c014b93160d9632bf4a65ad46b0092a305L106-R116),[[3]](https://github.com/devtron-labs/devtron-fe-common-lib/pull/970/files#diff-9031429d6cd8ea472101914a172cd7c014b93160d9632bf4a65ad46b0092a305L125-L128))These changes modernize the date picker component, reduce dependency bloat, and make it easier to maintain and extend.
Type of change
How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
Checklist