fromis_9/frontend-temp/src/hooks/useCalendar.js

145 lines
3.8 KiB
JavaScript
Raw Normal View History

import { useState, useMemo, useCallback } from 'react';
import { MIN_YEAR, WEEKDAYS, MONTH_NAMES } from '@/constants';
import { getTodayKST } from '@/utils';
/**
* 캘린더
* 날짜 선택, 이동 캘린더 로직 제공
* @param {Date|string} initialDate - 초기 날짜
*/
export function useCalendar(initialDate = new Date()) {
// initialDate가 Date 객체가 아니면 변환
const ensureDate = (date) => {
if (date instanceof Date) return date;
if (typeof date === 'string') return new Date(date);
return new Date();
};
const [currentDate, setCurrentDate] = useState(() => ensureDate(initialDate));
const [selectedDate, setSelectedDate] = useState(getTodayKST());
const year = currentDate.getFullYear();
const month = currentDate.getMonth();
// 캘린더 데이터 계산
const calendarData = useMemo(() => {
const firstDay = new Date(year, month, 1).getDay();
const daysInMonth = new Date(year, month + 1, 0).getDate();
const prevMonthDays = new Date(year, month, 0).getDate();
// 캘린더에 표시할 날짜 배열 생성
const days = [];
// 이전 달 날짜
for (let i = firstDay - 1; i >= 0; i--) {
days.push({
day: prevMonthDays - i,
isCurrentMonth: false,
date: new Date(year, month - 1, prevMonthDays - i),
});
}
// 현재 달 날짜
for (let i = 1; i <= daysInMonth; i++) {
days.push({
day: i,
isCurrentMonth: true,
date: new Date(year, month, i),
});
}
// 다음 달 날짜 (6주 채우기)
const remaining = 42 - days.length; // 6주 * 7일 = 42
for (let i = 1; i <= remaining; i++) {
days.push({
day: i,
isCurrentMonth: false,
date: new Date(year, month + 1, i),
});
}
return {
year,
month,
monthName: MONTH_NAMES[month],
firstDay,
daysInMonth,
prevMonthDays,
weekdays: WEEKDAYS,
days,
};
}, [year, month]);
// 이전 월로 이동 가능 여부
const canGoPrevMonth = !(year === MIN_YEAR && month === 0);
// 선택 날짜 업데이트 헬퍼
const updateSelectedDate = useCallback((newDate) => {
const today = new Date();
if (
newDate.getFullYear() === today.getFullYear() &&
newDate.getMonth() === today.getMonth()
) {
setSelectedDate(getTodayKST());
} else {
const firstDay = `${newDate.getFullYear()}-${String(newDate.getMonth() + 1).padStart(2, '0')}-01`;
setSelectedDate(firstDay);
}
}, []);
// 이전 월로 이동
const goToPrevMonth = useCallback(() => {
if (!canGoPrevMonth) return;
const newDate = new Date(year, month - 1, 1);
setCurrentDate(newDate);
updateSelectedDate(newDate);
}, [year, month, canGoPrevMonth, updateSelectedDate]);
// 다음 월로 이동
const goToNextMonth = useCallback(() => {
const newDate = new Date(year, month + 1, 1);
setCurrentDate(newDate);
updateSelectedDate(newDate);
}, [year, month, updateSelectedDate]);
// 특정 월로 이동
const goToMonth = useCallback(
(newYear, newMonth) => {
const newDate = new Date(newYear, newMonth, 1);
setCurrentDate(newDate);
updateSelectedDate(newDate);
},
[updateSelectedDate]
);
// 오늘로 이동
const goToToday = useCallback(() => {
const today = new Date();
setCurrentDate(today);
setSelectedDate(getTodayKST());
}, []);
// 날짜 선택
const selectDate = useCallback(
(day) => {
const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
setSelectedDate(dateStr);
},
[year, month]
);
return {
...calendarData,
currentDate,
selectedDate,
canGoPrev: canGoPrevMonth,
canGoPrevMonth,
goToPrevMonth,
goToNextMonth,
goToMonth,
goToToday,
selectDate,
setSelectedDate,
};
}