Skip to content

Commit d21b708

Browse files
committed
feat: enhance DateTimePicker with range selection and disabled state styling
1 parent e860234 commit d21b708

3 files changed

Lines changed: 75 additions & 24 deletions

File tree

src/Shared/Components/DatePicker/DateTimePicker.scss

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@
5252
}
5353
}
5454

55+
.rdp-day.rdp-disabled {
56+
.rdp-day_button {
57+
opacity: 0.5;
58+
cursor: not-allowed;
59+
}
60+
}
61+
5562
.rdp-caption_label {
5663
color: var(--N900);
5764
font-size: 16px;

src/Shared/Components/DatePicker/DateTimePicker.tsx

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,16 @@ const isDateUpdateRange = (
4040
handler: DateTimePickerProps['onChange'],
4141
): handler is UpdateDateRangeType => isRange
4242

43+
const getTodayDate = (): Date => {
44+
const today = dayjs()
45+
return today.toDate()
46+
}
47+
4348
const DateTimePicker = ({
44-
date: dateObject = new Date(),
49+
date: dateObject = getTodayDate(),
4550
dateRange = {
46-
from: new Date(),
47-
to: new Date(),
51+
from: getTodayDate(),
52+
to: getTodayDate(),
4853
},
4954
onChange,
5055
timePickerProps = {} as SelectInstance,
@@ -54,12 +59,15 @@ const DateTimePicker = ({
5459
required,
5560
hideTimeSelect = false,
5661
readOnly = false,
57-
isTodayBlocked = false,
5862
dataTestIdForTime = DATE_PICKER_IDS.TIME,
5963
error = '',
6064
isRangePicker = false,
65+
isTodayBlocked = false,
6166
blockPreviousDates = true,
67+
isOutsideRange,
68+
rangeShortcutOptions,
6269
}: DateTimePickerProps) => {
70+
const today = getTodayDate()
6371
const calendarPopoverId = useRef<string>(getUniqueId())
6472

6573
const { open, overlayProps, popoverProps, triggerProps, scrollableRef } = usePopover({
@@ -97,7 +105,7 @@ const DateTimePicker = ({
97105
onChange(updateTime(dateObject, option.value).value)
98106
}
99107

100-
const handleRangeSelect: OnSelectHandler<DateRange> = (range) => {
108+
const handleDateRangeChange = (range: DateRange) => {
101109
if (isDateUpdateRange(isRangePicker, onChange)) {
102110
const fromDate = range.from ? range.from : new Date()
103111
const toDate = range.to ? range.to : undefined
@@ -109,6 +117,14 @@ const DateTimePicker = ({
109117
}
110118
}
111119

120+
const handleRangeSelect: OnSelectHandler<DateRange> = (range) => {
121+
handleDateRangeChange(range)
122+
}
123+
124+
const getRangeUpdateHandler = (range: DateRange) => () => {
125+
handleDateRangeChange(range)
126+
}
127+
112128
const handleSingleDateSelect: OnSelectHandler<Date> = (date) => {
113129
if (!isDateUpdateRange(isRangePicker, onChange)) {
114130
const updatedDate = date ? updateDate(dateObject, date) : null
@@ -121,33 +137,50 @@ const DateTimePicker = ({
121137
return true
122138
}
123139

140+
const isOutsideRangeFn = isOutsideRange || (() => false)
141+
124142
if (isTodayBlocked) {
125-
const today = new Date()
126143
return (date: Date) => date <= today
127144
}
128145

129146
if (blockPreviousDates) {
130-
const today = new Date()
131-
return (date: Date) => date < today
147+
return (date: Date) => date < today || isOutsideRangeFn(date)
132148
}
133149

134-
return false
150+
return isOutsideRangeFn
135151
}
136152

137153
const renderDatePicker = () => {
138154
if (isRangePicker) {
139155
return (
140-
<DayPicker
141-
mode="range"
142-
navLayout="around"
143-
selected={{
144-
from: dateRange[0],
145-
to: dateRange[1],
146-
}}
147-
onSelect={handleRangeSelect}
148-
disabled={getDisabledState()}
149-
components={DATE_PICKER_CUSTOM_COMPONENTS}
150-
/>
156+
<div className="flexbox">
157+
{!!rangeShortcutOptions?.length && (
158+
<div className="flexbox-col py-20 px-16 w-200">
159+
{rangeShortcutOptions.map(({ label: optionLabel, value, onClick }) => (
160+
<button
161+
type="button"
162+
key={optionLabel}
163+
className="bg__hover cn-9 dc__tab-focus dc__align-left dc__transparent p-8 br-4"
164+
onClick={onClick || getRangeUpdateHandler(value)}
165+
>
166+
{optionLabel}
167+
</button>
168+
))}
169+
</div>
170+
)}
171+
172+
<DayPicker
173+
mode="range"
174+
navLayout="around"
175+
selected={{
176+
from: dateRange.from,
177+
to: dateRange.to,
178+
}}
179+
onSelect={handleRangeSelect}
180+
disabled={getDisabledState()}
181+
components={DATE_PICKER_CUSTOM_COMPONENTS}
182+
/>
183+
</div>
151184
)
152185
}
153186

@@ -185,6 +218,7 @@ const DateTimePicker = ({
185218
value: '',
186219
startIcon: <Icon name="ic-calendar" color={null} />,
187220
}}
221+
size={ComponentSizeType.large}
188222
/>
189223
)
190224

src/Shared/Components/DatePicker/types.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,6 @@ export type DateTimePickerProps = Pick<
114114
TimeSelectProps,
115115
'timePickerProps' | 'error' | 'disabled' | 'dataTestIdForTime'
116116
> & {
117-
/**
118-
* Props for the date picker
119-
*/
120-
datePickerProps?: any
121117
/**
122118
* Id for the component
123119
*/
@@ -139,12 +135,25 @@ export type DateTimePickerProps = Pick<
139135
*/
140136
isTodayBlocked?: boolean
141137
blockPreviousDates?: boolean
138+
isOutsideRange?: (day: Date) => boolean
142139
} & (
143140
| {
144141
isRangePicker: true
145142
hideTimeSelect: true
146143
dateRange: DateRangeType
147144
onChange: UpdateDateRangeType
145+
rangeShortcutOptions?: (
146+
| {
147+
label: string
148+
onClick: () => void
149+
value?: never
150+
}
151+
| {
152+
label: string
153+
onClick?: never
154+
value: DateRangeType
155+
}
156+
)[]
148157
date?: never
149158
}
150159
| {
@@ -156,5 +165,6 @@ export type DateTimePickerProps = Pick<
156165
*/
157166
hideTimeSelect?: boolean
158167
dateRange?: never
168+
rangeShortcutOptions?: never
159169
}
160170
)

0 commit comments

Comments
 (0)