DatePicker.tsx (2144B)
1 import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'; 2 import ChevronRightIcon from '@mui/icons-material/ChevronRight'; 3 import { Stack, IconButton, Typography } from '@mui/material'; 4 import { isSameDay } from 'date-fns'; 5 import { useCallback } from 'react'; 6 7 import IconButtonDatePicker from 'client/components/IconButtonDatePicker'; 8 import formatDate from 'common/utils/formatDate'; 9 10 import type { Dispatch, SetStateAction } from 'react'; 11 12 type Props = { 13 dates: Date[]; 14 index: number; 15 setDate: (d: Date) => void; 16 setIndex: Dispatch<SetStateAction<number>>; 17 }; 18 19 export default function DatePickerWithSideButton({ 20 index, 21 dates, 22 setIndex, 23 setDate, 24 }: Props) { 25 const date = dates[index] ?? new Date(); 26 const dateString = formatDate(date, 'yyyy/MM/dd (EEEEE)'); 27 28 const handleChange = (d: Date | null) => { 29 if (d == null) return; 30 setDate(d); 31 }; 32 33 const minDate = dates[0]; 34 const maxDate = dates[dates.length - 1]; 35 const shouldDisableDate = useCallback( 36 (d1: Date) => dates.every((d2) => !isSameDay(d1, d2)), 37 [dates], 38 ); 39 40 const canSelectToday = !shouldDisableDate(new Date()); 41 42 return ( 43 <Stack 44 direction='row' 45 justifyContent='space-between' 46 alignItems='center' 47 spacing={2} 48 width='100%' 49 px={2} 50 > 51 <IconButton 52 disabled={index <= 0} 53 onClick={() => setIndex((old) => old - 1)} 54 title='前の時間割' 55 > 56 <ChevronLeftIcon /> 57 </IconButton> 58 59 <Stack direction='row' spacing={{ xs: 0, sm: 1 }} alignItems='center'> 60 <IconButtonDatePicker 61 value={date} 62 onChange={handleChange} 63 minDate={minDate} 64 maxDate={maxDate} 65 shouldDisableDate={shouldDisableDate} 66 showDaysOutsideCurrentMonth 67 slotProps={{ 68 actionBar: { 69 actions: canSelectToday 70 ? ['today', 'cancel', 'accept'] 71 : ['cancel', 'accept'], 72 }, 73 }} 74 /> 75 <Typography variant='h2' fontSize={{ xs: 18, sm: 20 }}> 76 {dateString} 77 </Typography> 78 </Stack> 79 80 <IconButton 81 disabled={index >= dates.length - 1} 82 onClick={() => setIndex((old) => old + 1)} 83 title='次の時間割' 84 > 85 <ChevronRightIcon /> 86 </IconButton> 87 </Stack> 88 ); 89 }