useIndexAndDate.ts (1866B)
1 import { addDays, isFuture, set } from 'date-fns'; 2 import { useCallback, useMemo, useState } from 'react'; 3 4 import { DATE_FORMAT } from 'common/constant'; 5 import formatDate from 'common/utils/formatDate'; 6 7 type BaseReturn = { 8 index: number; 9 date: Date | null; 10 dates: Date[]; 11 setDate: (d: Date) => void; 12 setIndex: React.Dispatch<React.SetStateAction<number>>; 13 }; 14 15 type Return = BaseReturn; 16 17 const useIndexAndDate = (dateStrings: string[]): Return => { 18 const size = dateStrings.length; 19 const dates = useMemo( 20 () => dateStrings.map((v) => new Date(v)), 21 [dateStrings], 22 ); 23 24 // 初期設定の日付: 16時以前なら当日; 16時以降なら翌日; その日の時間割がなければ最も近い未来の日付; 未来がなければ最も新しい日付 25 const [index, setIndex] = useState<number>(() => { 26 // 1. 16時以前なら当日、16時以降なら翌日 27 { 28 const todays16hour = set(new Date(), { 29 hours: 16, 30 minutes: 0, 31 seconds: 0, 32 }); 33 const initialDate = isFuture(todays16hour) 34 ? new Date() // 16時以前 35 : addDays(new Date(), 1); // 16時以降 36 const i = dateStrings.indexOf(formatDate(initialDate, DATE_FORMAT)); 37 if (i !== -1) { 38 return i; 39 } 40 } 41 42 // 2. 最も近い未来の日付 43 { 44 const i = dateStrings.findIndex((v) => isFuture(new Date(v))); 45 if (i !== -1) { 46 return i; 47 } 48 } 49 50 // 3. 最も新しい(過去の)日付 51 return size - 1; 52 }); 53 54 const dateString = dateStrings[index]; 55 const date = useMemo( 56 () => (dateString ? new Date(dateString) : null), 57 [dateString], 58 ); 59 60 const setDate = useCallback( 61 (d: Date) => { 62 const newIndex = dateStrings.indexOf(formatDate(d, DATE_FORMAT)); 63 if (newIndex !== -1) { 64 setIndex(newIndex); 65 } 66 }, 67 [dateStrings], 68 ); 69 70 return { 71 index, 72 date, 73 dates, 74 setDate, 75 setIndex, 76 }; 77 }; 78 79 export default useIndexAndDate;