trithuc-mvc-react 1.6.13 → 1.6.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,8 +2,11 @@
2
2
  "use client";
3
3
  import { useEffect, useState } from "react";
4
4
  import * as dateFns from "date-fns";
5
- import { Box, Paper, Stack } from "@mui/material";
5
+ import { Box, Button, ButtonBase, Divider, IconButton, Paper, Stack, Typography, useTheme } from "@mui/material";
6
+ import NavigateBeforeIcon from "@mui/icons-material/NavigateBefore";
7
+ import NavigateNextIcon from "@mui/icons-material/NavigateNext";
6
8
  import viLocale from "date-fns/locale/vi";
9
+ import { useDateRangeContext } from ".";
7
10
  // import "tailwindcss/tailwind.css";
8
11
 
9
12
  const isBetween = (date, from, to, inclusivity) => {
@@ -20,23 +23,86 @@ const isBetween = (date, from, to, inclusivity) => {
20
23
  );
21
24
  };
22
25
  const days = ["CN", "T2", "T3", "T4", "T5", "T6", "T7"];
23
- console.log(viLocale.localize.day);
26
+ const DayInWeekHeader = () => {
27
+ return (
28
+ <Stack direction="row" alignItems={"center"} sx={{ px: 1, py: 1 }}>
29
+ {days.map((v, i) => (
30
+ <Typography
31
+ key={i}
32
+ variant="subtitle2"
33
+ align="center"
34
+ sx={{ display: "flex", alignItems: "center", justifyContent: "center", flex: 1 }}
35
+ >
36
+ {v}
37
+ </Typography>
38
+ ))}
39
+ </Stack>
40
+ );
41
+ };
42
+ const DayStatus = {
43
+ normal: "normal",
44
+ boundary: "bounary",
45
+ between: "between",
46
+ currentDate: "currentDate"
47
+ };
24
48
 
25
- const StaticDateRangePicker = ({ value, onUpdate }) => {
49
+ const DayButton = ({ onClick, children, status }) => {
50
+ const theme = useTheme();
51
+ let styleDayCell = {};
52
+
53
+ if (status == DayStatus.currentDate) {
54
+ styleDayCell = {
55
+ border: `1px solid ${theme.palette.grey[500]}`
56
+ };
57
+ }
58
+ if (status == DayStatus.between) {
59
+ styleDayCell = {
60
+ border: `1px solid transparent`,
61
+ backgroundColor: theme.palette.primary.lighter
62
+ };
63
+ }
64
+ if (status == DayStatus.boundary) {
65
+ styleDayCell = {
66
+ backgroundColor: theme.palette.primary.main,
67
+ color: theme.palette.primary.contrastText
68
+ };
69
+ }
70
+ return (
71
+ <ButtonBase
72
+ onClick={onClick}
73
+ sx={{
74
+ borderRadius: "50%",
75
+ height: 36,
76
+ width: 36,
77
+ display: "inline-flex",
78
+ alignItems: "center",
79
+ justifyContent: "center",
80
+ ":root": {
81
+ background: "transparent"
82
+ },
83
+ "&:hover": {
84
+ border: `1px solid ${theme.palette.grey[400]}`
85
+ },
86
+ ...styleDayCell
87
+ }}
88
+ >
89
+ {children}
90
+ </ButtonBase>
91
+ );
92
+ };
93
+ const StaticDateRangePicker = () => {
26
94
  const [currCalendar, setCurrCalendar] = useState([]);
27
95
  const [nextCalendar, setNextCalendar] = useState([]);
28
96
  const [currMonth, setCurrMonth] = useState(new Date().getMonth());
29
97
  const [currYear, setCurrYear] = useState(new Date().getFullYear());
30
98
 
31
- const [dateRange, setDateRange] = useState({
32
- startDate: value?.startDate,
33
- endDate: value?.endDate
34
- });
99
+ const { dateRange, setDateRange, closePoper } = useDateRangeContext();
100
+
35
101
  // Thanks to https://github.com/date-fns/date-fns/issues/366#issuecomment-270408980
36
102
 
37
103
  const generateCalendar = ({ month, year }) => {
38
104
  const startOfMonth = dateFns.startOfMonth(new Date(year, month));
39
- const endOfMonth = dateFns.endOfMonth(new Date(year, month));
105
+ // const endOfMonth = dateFns.endOfMonth(new Date(year, month));
40
106
  const startDay = startOfMonth.getDay();
41
107
  const daysInMonth = dateFns.getDaysInMonth(startOfMonth);
42
108
  const days = [...Array(daysInMonth).keys()].map((v) => v + 1);
@@ -66,33 +132,19 @@ const StaticDateRangePicker = ({ value, onUpdate }) => {
66
132
  setNextCalendar(_nextCalendar);
67
133
  }, [currMonth, currYear]);
68
134
 
69
- useEffect(() => {
70
- onUpdate?.(dateRange);
71
- }, [dateRange]);
135
+ // useEffect(() => {
136
+ // onUpdate?.(dateRange);
137
+ // }, [dateRange]);
72
138
 
73
139
  useEffect(() => {
74
- if (!value) return;
140
+ if (!dateRange.startDate) return;
75
141
 
76
- if (value.startDate && !dateFns.isSameDay(value.startDate, dateRange.startDate)) {
77
- if (dateFns.isBefore(value.startDate, dateRange.endDate)) {
78
- setDateRange((old) => ({ ...old, startDate: value.startDate }));
79
- } else {
80
- setDateRange((old) => ({ startDate: value.startDate, endDate: null }));
81
- }
82
- let month = value.startDate.getMonth();
83
- let year = value.startDate.getFullYear();
84
- if (isNaN(month) || isNaN(year)) return;
85
- setCurrMonth(month);
86
- setCurrYear(year);
87
- } else if (value.endDate && !dateFns.isSameDay(value.endDate, dateRange.endDate)) {
88
- setDateRange((old) => ({ ...old, endDate: value.endDate }));
89
- let month = value.endDate.getMonth();
90
- let year = value.endDate.getFullYear();
91
- if (isNaN(month) || isNaN(year)) return;
92
- setCurrMonth(month - 1);
93
- setCurrYear(year);
94
- }
95
- }, [value]);
142
+ let month = dateRange.startDate.getMonth();
143
+ let year = dateRange.startDate.getFullYear();
144
+ if (isNaN(month) || isNaN(year)) return;
145
+ setCurrMonth(month);
146
+ setCurrYear(year);
147
+ }, [dateRange]);
96
148
 
97
149
  const handleUpdateDateRangeOnLeftCalendar = (day) => {
98
150
  let thisDate = new Date(currYear, currMonth, day);
@@ -128,6 +180,7 @@ const StaticDateRangePicker = ({ value, onUpdate }) => {
128
180
  // year: currYear,
129
181
  // }),
130
182
  }));
183
+ closePoper();
131
184
  }
132
185
  } else if (dateRange.startDate && dateRange.endDate) {
133
186
  setDateRange({
@@ -189,6 +242,7 @@ const StaticDateRangePicker = ({ value, onUpdate }) => {
189
242
  // year: currYear,
190
243
  // }),
191
244
  }));
245
+ closePoper();
192
246
  }
193
247
  } else if (dateRange.startDate && dateRange.endDate) {
194
248
  setDateRange({
@@ -218,278 +272,188 @@ const StaticDateRangePicker = ({ value, onUpdate }) => {
218
272
  return (
219
273
  <Paper>
220
274
  <Box sx={{ display: "flex" }} className="date-range-piker-wrapper">
221
- <div className="drop-shadow-sm shadow-sm min-w-[10rem] p-3 rounded-lg border border-r-0 flex flex-col">
222
- <div className="flex justify-between items-center">
223
- <h3 className="text-lg">
224
- {" "}
275
+ <div className="drop-shadow-sm shadow-sm min-w-[10rem] rounded-lg border border-r-0 flex flex-col">
276
+ <Stack direction="row" spacing={2} alignItems={"center"} justifyContent={"space-between"} sx={{ p: 2 }}>
277
+ <IconButton
278
+ size="medium"
279
+ onClick={() => {
280
+ const d = dateFns.sub(new Date(currYear, currMonth), {
281
+ months: 1
282
+ });
283
+ setCurrMonth(d.getMonth());
284
+ setCurrYear(d.getFullYear());
285
+ }}
286
+ >
287
+ <NavigateBeforeIcon />
288
+ </IconButton>
289
+ <Typography variant="subtitle1" sx={{ height: "24px", alignSelf: "center" }}>
225
290
  {dateFns.format(new Date(currYear, currMonth), "MMMMMM yyyy", {
226
291
  locale: viLocale
227
292
  })}
228
- </h3>
293
+ </Typography>
294
+ <IconButton
295
+ onClick={() => {
296
+ const d = dateFns.add(new Date(currYear, currMonth), {
297
+ months: 1
298
+ });
299
+ setCurrMonth(d.getMonth());
300
+ setCurrYear(d.getFullYear());
301
+ }}
302
+ >
303
+ <NavigateNextIcon />
304
+ </IconButton>
305
+ </Stack>
306
+ <DayInWeekHeader />
307
+
308
+ <Box
309
+ sx={{
310
+ display: "grid",
311
+ gridTemplateColumns: "repeat(7, 1fr)",
312
+ p: 3,
313
+ gap: 1
314
+ }}
315
+ >
316
+ {currCalendar.map((v, i) => {
317
+ if (v) {
318
+ let status = DayStatus.normal;
229
319
 
230
- <Stack direction="row" spacing={2} alignItems={"center"}>
231
- <button
232
- type="button"
233
- className="p-2 rounded-lg hover:bg-gray-300 border drop-shadow-sm"
234
- onClick={() => {
235
- const d = dateFns.sub(new Date(currYear, currMonth), {
236
- months: 1
237
- });
238
- setCurrMonth(d.getMonth());
239
- setCurrYear(d.getFullYear());
240
- }}
241
- >
242
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-4 h-4">
243
- <path strokeLinecap="round" strokeLinejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
244
- </svg>
245
- </button>
246
- <button
247
- type="button"
248
- className="p-2 rounded-lg hover:bg-gray-300 border drop-shadow-sm"
249
- onClick={() => {
250
- const d = dateFns.add(new Date(currYear, currMonth), {
251
- months: 1
252
- });
253
- setCurrMonth(d.getMonth());
254
- setCurrYear(d.getFullYear());
255
- }}
256
- >
257
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-4 h-4">
258
- <path strokeLinecap="round" strokeLinejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
259
- </svg>
260
- </button>
261
- </Stack>
262
- </div>
263
- <div className="grid grid-cols-7 p-3 gap-2 mt-3">
264
- {days.map((v, i) => (
265
- <div key={i} className="text-center w-12">
266
- {v}
267
- </div>
268
- ))}
269
- </div>
320
+ if (dateFns.isSameDay(new Date(currYear, currMonth, v), new Date())) {
321
+ status = DayStatus.currentDate;
322
+ }
270
323
 
271
- <div className="grid grid-cols-7 p-3 gap-2">
272
- {currCalendar.map((v, i) =>
273
- v ? (
274
- <button
275
- type="button"
276
- key={i}
277
- className={`rounded-lg border flex w-12 justify-center p-2 hover:bg-blue-600 hover:text-white ${
278
- dateFns.isSameDay(new Date(currYear, currMonth, v), dateRange.startDate)
279
- ? // dateRange.startDate?.isSame(
280
- // moment({ day: v, month: currMonth, year: currYear }),
281
- // "day"
282
- // )
283
- "bg-blue-600 text-white"
284
- : ""
285
- } ${
286
- dateFns.isSameDay(new Date(currYear, currMonth, v), new Date())
287
- ? // moment({ day: v, month: currMonth, year: currYear }).isSame(
288
- // moment(),
289
- // "day"
290
- // )
291
- "ring-blue-400 ring-2"
292
- : ""
293
- } ${
294
- dateFns.isSameDay(new Date(currYear, currMonth, v), dateRange.endDate)
295
- ? // dateRange.endDate?.isSame(
296
- // moment({ day: v, month: currMonth, year: currYear }),
297
- // "day"
298
- // )
299
- "bg-blue-600 text-white"
300
- : ""
301
- } ${
302
- isBetween(new Date(currYear, currMonth, v), dateRange.startDate, dateRange.endDate, "[]")
303
- ? // moment({
304
- // day: v,
305
- // month: currMonth,
306
- // year: currYear,
307
- // }).isBetween(
308
- // dateRange.startDate,
309
- // dateRange.endDate,
310
- // "day",
311
- // "()"
312
- // )
313
- "bg-blue-200"
314
- : ""
315
- }`}
316
- onClick={() => {
317
- handleUpdateDateRangeOnLeftCalendar(v);
318
- }}
319
- >
320
- {v}
321
- </button>
322
- ) : (
323
- <span key={i}></span>
324
- )
325
- )}
326
- </div>
324
+ if (
325
+ dateFns.isSameDay(new Date(currYear, currMonth, v), dateRange.startDate) ||
326
+ dateFns.isSameDay(new Date(currYear, currMonth, v), dateRange.endDate)
327
+ ) {
328
+ status = DayStatus.boundary;
329
+ } else if (isBetween(new Date(currYear, currMonth, v), dateRange.startDate, dateRange.endDate, "[]")) {
330
+ status = DayStatus.between;
331
+ }
332
+
333
+ return (
334
+ <DayButton
335
+ key={i}
336
+ status={status}
337
+ onClick={() => {
338
+ handleUpdateDateRangeOnLeftCalendar(v);
339
+ }}
340
+ >
341
+ {v}
342
+ </DayButton>
343
+ );
344
+ }
345
+
346
+ return <span key={i}></span>;
347
+ })}
348
+ </Box>
327
349
  </div>
328
- <div className="drop-shadow-sm shadow-sm min-w-[10rem] p-3 rounded-lg border flex flex-col">
329
- <div className="flex justify-between items-center">
330
- <h3 className="text-lg">
350
+ <Divider orientation="vertical" />
351
+ <div className="drop-shadow-sm shadow-sm min-w-[10rem] rounded-lg border flex flex-col">
352
+ <Stack direction="row" spacing={2} alignItems={"center"} justifyContent={"space-between"} sx={{ p: 2 }}>
353
+ <IconButton
354
+ size="medium"
355
+ onClick={() => {
356
+ const d = dateFns.sub(new Date(currYear, currMonth), {
357
+ months: 1
358
+ });
359
+ // moment({ month: currMonth, year: currYear }).subtract(
360
+ // 1,
361
+ // "month"
362
+ // )
363
+ setCurrMonth(d.getMonth());
364
+ setCurrYear(d.getFullYear());
365
+ }}
366
+ >
367
+ <NavigateBeforeIcon />
368
+ </IconButton>
369
+ <Typography variant="subtitle1" sx={{ height: "24px", alignSelf: "center" }}>
331
370
  {dateFns.format(dateFns.add(new Date(currYear, currMonth), { months: 1 }), "MMMM yyyy", {
332
371
  locale: viLocale
333
372
  })}
334
- </h3>
335
- <div className="flex gap-x-2 items-center">
336
- <button
337
- type="button"
338
- className="p-2 rounded-lg hover:bg-gray-300 border drop-shadow-sm"
339
- onClick={() => {
340
- const d = dateFns.sub(new Date(currYear, currMonth), {
341
- months: 1
342
- });
343
- // moment({ month: currMonth, year: currYear }).subtract(
344
- // 1,
345
- // "month"
346
- // )
347
- setCurrMonth(d.getMonth());
348
- setCurrYear(d.getFullYear());
349
- }}
350
- >
351
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-4 h-4">
352
- <path strokeLinecap="round" strokeLinejoin="round" d="M15.75 19.5L8.25 12l7.5-7.5" />
353
- </svg>
354
- </button>
355
- <button
356
- type="button"
357
- className="p-2 rounded-lg hover:bg-gray-300 border drop-shadow-sm"
358
- onClick={() => {
359
- const d = dateFns.add(new Date(currYear, currMonth), {
360
- months: 1
361
- });
362
- // moment({ month: currMonth }).add(1, "month")
363
- setCurrMonth(d.getMonth());
364
- setCurrYear(d.getFullYear());
365
- }}
366
- >
367
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-4 h-4">
368
- <path strokeLinecap="round" strokeLinejoin="round" d="M8.25 4.5l7.5 7.5-7.5 7.5" />
369
- </svg>
370
- </button>
371
- </div>
372
- </div>
373
- <div className="grid grid-cols-7 p-3 gap-2 mt-3">
374
- {days.map((v, i) => (
375
- <div key={i} className="text-center w-12">
376
- {v}
377
- </div>
378
- ))}
379
- </div>
373
+ </Typography>
374
+ <IconButton
375
+ onClick={() => {
376
+ const d = dateFns.add(new Date(currYear, currMonth), {
377
+ months: 1
378
+ });
379
+ // moment({ month: currMonth }).add(1, "month")
380
+ setCurrMonth(d.getMonth());
381
+ setCurrYear(d.getFullYear());
382
+ }}
383
+ >
384
+ <NavigateNextIcon />
385
+ </IconButton>
386
+ </Stack>
387
+
388
+ <DayInWeekHeader />
389
+ <Box
390
+ sx={{
391
+ display: "grid",
392
+ gridTemplateColumns: "repeat(7, 1fr)",
393
+ p: 3,
394
+ gap: 1
395
+ }}
396
+ >
397
+ {" "}
398
+ {nextCalendar.map((v, i) => {
399
+ if (v) {
400
+ let status = DayStatus.normal;
401
+
402
+ if (
403
+ dateFns.isSameDay(
404
+ dateFns.add(new Date(currYear, currMonth, v), {
405
+ months: 1
406
+ }),
407
+ new Date()
408
+ )
409
+ ) {
410
+ status = DayStatus.currentDate;
411
+ }
412
+
413
+ if (
414
+ dateFns.isSameDay(
415
+ dateFns.add(new Date(currYear, currMonth, v), {
416
+ months: 1
417
+ }),
418
+ dateRange.startDate
419
+ ) ||
420
+ dateFns.isSameDay(
421
+ dateFns.add(new Date(currYear, currMonth, v), {
422
+ months: 1
423
+ }),
424
+ dateRange.endDate
425
+ )
426
+ ) {
427
+ status = DayStatus.boundary;
428
+ } else if (
429
+ isBetween(
430
+ dateFns.add(new Date(currYear, currMonth, v), {
431
+ months: 1
432
+ }),
433
+ dateRange.startDate,
434
+ dateRange.endDate,
435
+ "[]"
436
+ )
437
+ ) {
438
+ status = DayStatus.between;
439
+ }
440
+
441
+ return (
442
+ <DayButton
443
+ key={i}
444
+ status={status}
445
+ onClick={() => {
446
+ handleUpdateDateRangeOnRightCalendar(v);
447
+ }}
448
+ >
449
+ {v}
450
+ </DayButton>
451
+ );
452
+ }
380
453
 
381
- <div className="grid grid-cols-7 p-3 gap-2">
382
- {nextCalendar.map((day, i) =>
383
- day ? (
384
- <button
385
- type="button"
386
- key={i}
387
- className={`rounded-lg border flex w-12 justify-center p-2 hover:bg-blue-600 hover:text-white ${
388
- dateFns.isSameDay(
389
- dateFns.add(new Date(currYear, currMonth, day), {
390
- months: 1
391
- }),
392
- dateRange.startDate
393
- )
394
- ? // dateRange.startDate?.isSame(
395
- // moment({
396
- // day: v,
397
- // month: moment({
398
- // day: v,
399
- // month: currMonth,
400
- // year: currYear,
401
- // })
402
- // .add(1, "month")
403
- // .month(),
404
- // year: moment({ day: v, month: currMonth, year: currYear })
405
- // .add(1, "month")
406
- // .year(),
407
- // }),
408
- // "day"
409
- // )
410
- "bg-blue-600 text-white"
411
- : ""
412
- } ${
413
- dateFns.isSameDay(
414
- dateFns.add(new Date(currYear, currMonth, day), {
415
- months: 1
416
- }),
417
- new Date()
418
- )
419
- ? // moment({
420
- // day: v,
421
- // month: moment({ day: v, month: currMonth, year: currYear })
422
- // .add(1, "month")
423
- // .month(),
424
- // year: moment({ day: v, month: currMonth, year: currYear })
425
- // .add(1, "month")
426
- // .year(),
427
- // }).isSame(moment(), "day")
428
- "ring-blue-400 ring-2"
429
- : ""
430
- } ${
431
- dateFns.isSameDay(
432
- dateFns.add(new Date(currYear, currMonth, day), {
433
- months: 1
434
- }),
435
- dateRange.endDate
436
- )
437
- ? // dateRange.endDate?.isSame(
438
- // moment({
439
- // day: v,
440
- // month: moment({
441
- // day: v,
442
- // month: currMonth,
443
- // year: currYear,
444
- // })
445
- // .add(1, "month")
446
- // .month(),
447
- // year: moment({ day: v, month: currMonth, year: currYear })
448
- // .add(1, "month")
449
- // .year(),
450
- // }),
451
- // "day"
452
- // )
453
- "bg-blue-600 text-white"
454
- : ""
455
- } ${
456
- // isBetween(new Date(currYear, currMonth, v), {}))
457
- isBetween(
458
- dateFns.add(new Date(currYear, currMonth, day), {
459
- months: 1
460
- }),
461
- dateRange.startDate,
462
- dateRange.endDate,
463
- "[]"
464
- )
465
- ? // moment({
466
- // day: v,
467
- // month: moment({ day: v, month: currMonth, year: currYear })
468
- // .add(1, "month")
469
- // .month(),
470
- // year: moment({ day: v, month: currMonth, year: currYear })
471
- // .add(1, "month")
472
- // .year(),
473
- // }).isBetween(
474
- // dateRange.startDate,
475
- // dateRange.endDate,
476
- // "day",
477
- // "()"
478
- // )
479
- "bg-blue-200"
480
- : ""
481
- }`}
482
- onClick={() => {
483
- handleUpdateDateRangeOnRightCalendar(day);
484
- }}
485
- >
486
- {day}
487
- </button>
488
- ) : (
489
- <span key={i}></span>
490
- )
491
- )}
492
- </div>
454
+ return <span key={i}></span>;
455
+ })}
456
+ </Box>
493
457
  </div>
494
458
  </Box>
495
459
  </Paper>
File without changes