1 | import React, { useMemo } from 'react';
|
2 | import dayjs from 'dayjs';
|
3 | import utc from 'dayjs/plugin/utc';
|
4 |
|
5 | import BaseCalendarWrappedInProviders from './Providers';
|
6 | import type { DateProperties, WrapperCalendarProps } from '../Entities';
|
7 |
|
8 | dayjs.extend(utc);
|
9 |
|
10 | interface SpecificProps {
|
11 | onSelectDates: (dates: string[]) => void;
|
12 | selectedDates: string[];
|
13 | }
|
14 |
|
15 | type Props = SpecificProps & WrapperCalendarProps;
|
16 |
|
17 |
|
18 | const MultiDateSelectionCalendar: React.FC<Props> = ({
|
19 | onSelectDates,
|
20 | disabledDates,
|
21 | selectedDates,
|
22 | allowYearView = true,
|
23 | ...others
|
24 | }) => {
|
25 | if (!selectedDates) {
|
26 | throw new Error(
|
27 | 'The `selectedDates` prop is required. Use an empty array if no dates should be selected.'
|
28 | );
|
29 | }
|
30 |
|
31 | if (typeof selectedDates !== 'object') {
|
32 | throw new Error(
|
33 | 'The `selectedDates` prop should be an array of date strings in YYYY-MM-DD format.'
|
34 | );
|
35 | }
|
36 |
|
37 | if (!onSelectDates) {
|
38 | throw new Error('The `onSelectDates` prop is required.');
|
39 | }
|
40 |
|
41 | if (typeof onSelectDates !== 'function') {
|
42 | throw new Error(
|
43 | 'The `onSelectDates` prop should be function that receives an array of date strings as paramater.'
|
44 | );
|
45 | }
|
46 |
|
47 | const selDatesRef = React.useRef<string[]>(selectedDates);
|
48 |
|
49 | const dateProperties = useMemo(() => {
|
50 | const disabledDateProperties = disabledDates?.reduce(
|
51 | (disabled: Record<string, DateProperties>, date) => {
|
52 | disabled[date] = { isDisabled: true };
|
53 | return disabled;
|
54 | },
|
55 | {}
|
56 | );
|
57 |
|
58 | const selectedDateProperties = selectedDates.reduce(
|
59 | (selected: Record<string, DateProperties>, date) => {
|
60 | selected[date] = { isSelected: true };
|
61 | return selected;
|
62 | },
|
63 | {}
|
64 | );
|
65 |
|
66 |
|
67 | return {
|
68 | ...disabledDateProperties,
|
69 | ...selectedDateProperties,
|
70 | };
|
71 | }, [selectedDates, disabledDates]);
|
72 |
|
73 | const remove = (dateToRemove: string) => {
|
74 | const newSelectedDates = selDatesRef.current.filter((date) => date !== dateToRemove);
|
75 | selDatesRef.current = newSelectedDates;
|
76 | return newSelectedDates;
|
77 | };
|
78 |
|
79 | const append = (dateToAppend: string) => {
|
80 | const newSelectedDates = [...selDatesRef.current, dateToAppend].sort();
|
81 | selDatesRef.current = newSelectedDates;
|
82 | return newSelectedDates;
|
83 | };
|
84 |
|
85 | const onPressDay = React.useCallback(
|
86 | (date: string) => {
|
87 | if (selDatesRef.current.includes(date)) {
|
88 | onSelectDates(remove(date));
|
89 | } else {
|
90 | onSelectDates(append(date));
|
91 | }
|
92 | },
|
93 | [onSelectDates]
|
94 | );
|
95 |
|
96 | return (
|
97 | <BaseCalendarWrappedInProviders
|
98 | onPressDay={onPressDay}
|
99 | allowYearView={allowYearView}
|
100 | dateProperties={dateProperties}
|
101 | {...others}
|
102 | />
|
103 | );
|
104 | };
|
105 |
|
106 | export default MultiDateSelectionCalendar;
|