-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathDateCalendarServerRequest.js
More file actions
114 lines (99 loc) · 3.34 KB
/
DateCalendarServerRequest.js
File metadata and controls
114 lines (99 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import * as React from 'react';
import dayjs from 'dayjs';
import Badge from '@mui/material/Badge';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { PickerDay } from '@mui/x-date-pickers/PickerDay';
import { DateCalendar } from '@mui/x-date-pickers/DateCalendar';
import { DayCalendarSkeleton } from '@mui/x-date-pickers/DayCalendarSkeleton';
function getRandomNumber(min, max) {
// eslint-disable-next-line no-restricted-properties -- used for interactive server simulation
return Math.round(Math.random() * (max - min) + min);
}
/**
* Mimic fetch with abort controller https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort
* ⚠️ No IE11 support
*/
function fakeFetch(date, { signal }) {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
const daysInMonth = date.daysInMonth();
const daysToHighlight = [1, 2, 3].map(() => getRandomNumber(1, daysInMonth));
resolve({ daysToHighlight });
}, 500);
signal.onabort = () => {
clearTimeout(timeout);
reject(new DOMException('aborted', 'AbortError'));
};
});
}
const initialValue = dayjs('2022-04-17');
function ServerDay(props) {
const { highlightedDays = [], day, outsideCurrentMonth, ...other } = props;
const isSelected =
!props.outsideCurrentMonth && highlightedDays.indexOf(props.day.date()) >= 0;
return (
<Badge
key={props.day.toString()}
overlap="circular"
badgeContent={isSelected ? '🌚' : undefined}
>
<PickerDay {...other} outsideCurrentMonth={outsideCurrentMonth} day={day} />
</Badge>
);
}
export default function DateCalendarServerRequest() {
const requestAbortController = React.useRef(null);
const [isLoading, setIsLoading] = React.useState(false);
const [highlightedDays, setHighlightedDays] = React.useState([1, 2, 15]);
const fetchHighlightedDays = (date) => {
const controller = new AbortController();
fakeFetch(date, {
signal: controller.signal,
})
.then(({ daysToHighlight }) => {
setHighlightedDays(daysToHighlight);
setIsLoading(false);
})
.catch((error) => {
// ignore the error if it's caused by `controller.abort`
if (error.name !== 'AbortError') {
throw error;
}
});
requestAbortController.current = controller;
};
React.useEffect(() => {
fetchHighlightedDays(initialValue);
// abort request on unmount
return () => requestAbortController.current?.abort();
}, []);
const handleMonthChange = (date) => {
if (requestAbortController.current) {
// make sure that you are aborting useless requests
// because it is possible to switch between months pretty quickly
requestAbortController.current.abort();
}
setIsLoading(true);
setHighlightedDays([]);
fetchHighlightedDays(date);
};
return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<DateCalendar
defaultValue={initialValue}
loading={isLoading}
onMonthChange={handleMonthChange}
renderLoading={() => <DayCalendarSkeleton />}
slots={{
day: ServerDay,
}}
slotProps={{
day: {
highlightedDays,
},
}}
/>
</LocalizationProvider>
);
}