Skip to content

Commit 9cf6968

Browse files
mostly works, need to clean things up
1 parent 7a668ad commit 9cf6968

File tree

2 files changed

+208
-16
lines changed

2 files changed

+208
-16
lines changed

src/components/DatePicker/DateRangePicker.stories.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ const defaultStory = {
2020
placeholder: {
2121
control: "text",
2222
},
23+
predefinedDatesCount: {
24+
control: "number",
25+
},
2326
onSelectDateRange: {
2427
control: "object",
2528
},
@@ -28,13 +31,18 @@ const defaultStory = {
2831
render: (args: Args) => {
2932
const endDate = args.endDate ? new Date(args.endDate) : undefined;
3033
const startDate = args.startDate ? new Date(args.startDate) : undefined;
34+
const predefinedDatesCount = args.predefinedDatesCount
35+
? args.predefinedDatesCount
36+
: undefined;
37+
3138
return (
3239
<DateRangePicker
3340
endDate={endDate}
3441
disabled={args.disabled}
3542
futureDatesDisabled={args.futureDatesDisabled}
3643
onSelectDateRange={args.onSelectDateRange}
3744
placeholder={args.placeholder}
45+
predefinedDatesCount={predefinedDatesCount}
3846
startDate={startDate}
3947
/>
4048
);
@@ -45,6 +53,30 @@ const defaultStory = {
4553

4654
export default defaultStory;
4755

56+
// export const PredefinedRanges = {
57+
// args: {
58+
// ...defaultStory.args
59+
// },
60+
// render: (args: Args) => {
61+
// const endDate = args.endDate ? new Date(args.endDate) : undefined;
62+
// const startDate = args.startDate ? new Date(args.startDate) : undefined;
63+
64+
// console.log('predefined dates story', args.predefinedDatesCount)
65+
// return (
66+
// <DateRangePicker
67+
// endDate={endDate}
68+
// disabled={args.disabled}
69+
// futureDatesDisabled={args.futureDatesDisabled}
70+
// onSelectDateRange={args.onSelectDateRange}
71+
// placeholder={args.placeholder}
72+
// predefinedDatesCount={6}
73+
// startDate={startDate}
74+
// />
75+
// );
76+
// },
77+
// title: "Display/DateRangePickerPredefinedDates"
78+
// };
79+
4880
export const Playground = {
4981
...defaultStory,
5082
};

src/components/DatePicker/DateRangePicker.tsx

Lines changed: 176 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1-
import { useCallback, useEffect, useState } from "react";
1+
import {
2+
Dispatch,
3+
MouseEvent,
4+
SetStateAction,
5+
useCallback,
6+
useEffect,
7+
useState,
8+
} from "react";
29
import { isSameDate, UseCalendarOptions } from "@h6s/calendar";
310
import { styled } from "styled-components";
411
import Dropdown from "../Dropdown/Dropdown";
512
import { Body, CalendarRenderer, DateRangePickerInput, DateTableCell } from "./Common";
13+
import { Container } from "../Container/Container";
14+
import dayjs from "dayjs";
15+
import { Panel } from "../Panel/Panel";
16+
import { Icon } from "../Icon/Icon";
617

718
const DateRangeTableCell = styled(DateTableCell)<{
819
$shouldShowRangeIndicator?: boolean;
@@ -16,6 +27,14 @@ const DateRangeTableCell = styled(DateTableCell)<{
1627
`}
1728
`;
1829

30+
const PredefinedDatesContainer = styled(Container)`
31+
width: 275px;
32+
`;
33+
34+
const StyledDropdownItem = styled(Dropdown.Item)`
35+
min-height: 24px;
36+
`;
37+
1938
interface CalendarProps {
2039
calendarBody: Body;
2140
closeDatepicker: () => void;
@@ -91,7 +110,7 @@ const Calendar = ({
91110
return (
92111
<DateRangeTableCell
93112
$shouldShowRangeIndicator={
94-
shouldShowRangeIndicator || isBetweenStartAndEndDates
113+
!isSelected && (shouldShowRangeIndicator || isBetweenStartAndEndDates)
95114
}
96115
$isCurrentMonth={isCurrentMonth}
97116
$isDisabled={isDisabled}
@@ -111,12 +130,108 @@ const Calendar = ({
111130
});
112131
};
113132

114-
export interface DatePickerProps {
133+
const locale = "en-US";
134+
const monthFormatter = new Intl.DateTimeFormat(locale, {
135+
month: "short",
136+
year: "numeric",
137+
});
138+
139+
interface DateRange {
140+
startDate: Date;
141+
endDate: Date;
142+
}
143+
144+
const getLastMonths = (numberOfMonths: number = 6): Array<DateRange> => {
145+
const now = dayjs();
146+
147+
const lastSixMonths: Array<DateRange> = [];
148+
for (let i = 0; i < numberOfMonths; i++) {
149+
const date = now.subtract(i, "month");
150+
lastSixMonths.push({
151+
startDate: date.startOf("month").toDate(),
152+
endDate: i === 0 ? now.toDate() : date.endOf("month").toDate(),
153+
});
154+
}
155+
156+
return lastSixMonths;
157+
};
158+
159+
interface PredefinedDatesProps {
160+
onSelectDateRange: (selectedStartDate: Date, selectedEndDate: Date) => void;
161+
predefinedDatesCount: number;
162+
selectedEndDate: Date | undefined;
163+
selectedStartDate: Date | undefined;
164+
setEndDate: Dispatch<SetStateAction<Date | undefined>>;
165+
setStartDate: Dispatch<SetStateAction<Date | undefined>>;
166+
shouldShowCustomRange: boolean;
167+
showCustomDateRange: Dispatch<SetStateAction<boolean>>;
168+
}
169+
170+
const PredefinedDates = ({
171+
onSelectDateRange,
172+
predefinedDatesCount,
173+
selectedEndDate,
174+
selectedStartDate,
175+
setEndDate,
176+
setStartDate,
177+
shouldShowCustomRange,
178+
showCustomDateRange,
179+
}: PredefinedDatesProps) => {
180+
const pastSixMonths = getLastMonths(predefinedDatesCount);
181+
182+
const handleCustomTimePeriodClick = (event: MouseEvent) => {
183+
event.preventDefault();
184+
showCustomDateRange(!shouldShowCustomRange);
185+
};
186+
187+
return (
188+
<PredefinedDatesContainer
189+
isResponsive={false}
190+
orientation="vertical"
191+
>
192+
{pastSixMonths.map(({ startDate, endDate }) => {
193+
const handleItemClick = () => {
194+
setStartDate(startDate);
195+
setEndDate(endDate);
196+
onSelectDateRange(startDate, endDate);
197+
};
198+
return (
199+
<StyledDropdownItem
200+
key={startDate.toISOString()}
201+
onClick={handleItemClick}
202+
>
203+
<Container
204+
justifyContent="space-between"
205+
orientation="horizontal"
206+
>
207+
{monthFormatter.format(startDate)}
208+
{selectedEndDate &&
209+
isSameDate(selectedEndDate, endDate) &&
210+
selectedStartDate &&
211+
isSameDate(selectedStartDate, startDate) && <Icon name="check" />}
212+
</Container>
213+
</StyledDropdownItem>
214+
);
215+
})}
216+
<StyledDropdownItem onClick={handleCustomTimePeriodClick}>
217+
<Container
218+
justifyContent="space-between"
219+
orientation="horizontal"
220+
>
221+
Custom time period <Icon name="chevron-right" />
222+
</Container>
223+
</StyledDropdownItem>
224+
</PredefinedDatesContainer>
225+
);
226+
};
227+
228+
export interface DateRangePickerProps {
115229
endDate?: Date;
116230
disabled?: boolean;
117231
futureDatesDisabled?: boolean;
118232
onSelectDateRange: (selectedStartDate: Date, selectedEndDate: Date) => void;
119233
placeholder?: string;
234+
predefinedDatesCount?: number;
120235
startDate?: Date;
121236
}
122237

@@ -127,10 +242,12 @@ export const DateRangePicker = ({
127242
futureDatesDisabled = false,
128243
onSelectDateRange,
129244
placeholder = "start date – end date",
130-
}: DatePickerProps) => {
245+
predefinedDatesCount,
246+
}: DateRangePickerProps) => {
131247
const [isOpen, setIsOpen] = useState<boolean>(false);
132248
const [selectedStartDate, setSelectedStartDate] = useState<Date>();
133249
const [selectedEndDate, setSelectedEndDate] = useState<Date>();
250+
const [shouldShowCustomRange, setShouldShowCustomRange] = useState<boolean>(false);
134251

135252
const calendarOptions: UseCalendarOptions = {};
136253

@@ -153,8 +270,17 @@ export const DateRangePicker = ({
153270

154271
const closeDatePicker = useCallback((): void => {
155272
setIsOpen(false);
273+
setShouldShowCustomRange(false);
156274
}, []);
157275

276+
const handleOpenChange = (isOpen: boolean): void => {
277+
setIsOpen(isOpen);
278+
279+
if (!isOpen) {
280+
setShouldShowCustomRange(false);
281+
}
282+
};
283+
158284
const handleSelectDate = useCallback(
159285
(selectedDate: Date): void => {
160286
// Start date and end date are selected, user clicks any date.
@@ -183,6 +309,7 @@ export const DateRangePicker = ({
183309
// Otherwise, set the end date to the date the user clicked.
184310
setSelectedEndDate(selectedDate);
185311
onSelectDateRange(selectedStartDate, selectedDate);
312+
setShouldShowCustomRange(false);
186313
return;
187314
}
188315

@@ -193,7 +320,7 @@ export const DateRangePicker = ({
193320

194321
return (
195322
<Dropdown
196-
onOpenChange={setIsOpen}
323+
onOpenChange={handleOpenChange}
197324
open={isOpen}
198325
>
199326
<Dropdown.Trigger disabled={disabled}>
@@ -207,18 +334,51 @@ export const DateRangePicker = ({
207334
/>
208335
</Dropdown.Trigger>
209336
<Dropdown.Content align="start">
210-
<CalendarRenderer calendarOptions={calendarOptions}>
211-
{body => (
212-
<Calendar
213-
calendarBody={body}
214-
closeDatepicker={closeDatePicker}
215-
futureDatesDisabled={futureDatesDisabled}
216-
setSelectedDate={handleSelectDate}
217-
startDate={selectedStartDate}
218-
endDate={selectedEndDate}
337+
{predefinedDatesCount !== undefined && predefinedDatesCount > 0 ? (
338+
<Panel
339+
orientation="horizontal"
340+
padding="none"
341+
>
342+
<PredefinedDates
343+
onSelectDateRange={onSelectDateRange}
344+
predefinedDatesCount={Math.min(6, predefinedDatesCount)}
345+
selectedEndDate={selectedEndDate}
346+
selectedStartDate={selectedStartDate}
347+
setEndDate={setSelectedEndDate}
348+
setStartDate={setSelectedStartDate}
349+
shouldShowCustomRange={shouldShowCustomRange}
350+
showCustomDateRange={setShouldShowCustomRange}
219351
/>
220-
)}
221-
</CalendarRenderer>
352+
353+
{shouldShowCustomRange && (
354+
<CalendarRenderer calendarOptions={calendarOptions}>
355+
{body => (
356+
<Calendar
357+
calendarBody={body}
358+
closeDatepicker={closeDatePicker}
359+
futureDatesDisabled={futureDatesDisabled}
360+
setSelectedDate={handleSelectDate}
361+
startDate={selectedStartDate}
362+
endDate={selectedEndDate}
363+
/>
364+
)}
365+
</CalendarRenderer>
366+
)}
367+
</Panel>
368+
) : (
369+
<CalendarRenderer calendarOptions={calendarOptions}>
370+
{body => (
371+
<Calendar
372+
calendarBody={body}
373+
closeDatepicker={closeDatePicker}
374+
futureDatesDisabled={futureDatesDisabled}
375+
setSelectedDate={handleSelectDate}
376+
startDate={selectedStartDate}
377+
endDate={selectedEndDate}
378+
/>
379+
)}
380+
</CalendarRenderer>
381+
)}
222382
</Dropdown.Content>
223383
</Dropdown>
224384
);

0 commit comments

Comments
 (0)