ERP-node/frontend/components/admin/dashboard/widgets/calendarUtils.ts

163 lines
4.6 KiB
TypeScript

/**
* 달력 유틸리티 함수
*/
// 한국 공휴일 데이터 (2025년 기준)
export interface Holiday {
date: string; // 'MM-DD' 형식
name: string;
isRecurring: boolean;
}
export const KOREAN_HOLIDAYS: Holiday[] = [
{ date: "01-01", name: "신정", isRecurring: true },
{ date: "01-28", name: "설날 연휴", isRecurring: false },
{ date: "01-29", name: "설날", isRecurring: false },
{ date: "01-30", name: "설날 연휴", isRecurring: false },
{ date: "03-01", name: "삼일절", isRecurring: true },
{ date: "05-05", name: "어린이날", isRecurring: true },
{ date: "06-06", name: "현충일", isRecurring: true },
{ date: "08-15", name: "광복절", isRecurring: true },
{ date: "10-03", name: "개천절", isRecurring: true },
{ date: "10-09", name: "한글날", isRecurring: true },
{ date: "12-25", name: "크리스마스", isRecurring: true },
];
/**
* 특정 월의 첫 날 Date 객체 반환
*/
export function getFirstDayOfMonth(year: number, month: number): Date {
return new Date(year, month, 1);
}
/**
* 특정 월의 마지막 날짜 반환
*/
export function getLastDateOfMonth(year: number, month: number): number {
return new Date(year, month + 1, 0).getDate();
}
/**
* 특정 월의 첫 날의 요일 반환 (0=일요일, 1=월요일, ...)
*/
export function getFirstDayOfWeek(year: number, month: number): number {
return new Date(year, month, 1).getDay();
}
/**
* 달력 그리드에 표시할 날짜 배열 생성
* @param year 년도
* @param month 월 (0-11)
* @param startWeekOn 주 시작 요일 ('monday' | 'sunday')
* @returns 6주 * 7일 = 42개의 날짜 정보 배열
*/
export interface CalendarDay {
date: Date;
day: number;
isCurrentMonth: boolean;
isToday: boolean;
isWeekend: boolean;
isHoliday: boolean;
holidayName?: string;
}
export function generateCalendarDays(
year: number,
month: number,
startWeekOn: "monday" | "sunday" = "sunday",
): CalendarDay[] {
const days: CalendarDay[] = [];
const firstDay = getFirstDayOfWeek(year, month);
const lastDate = getLastDateOfMonth(year, month);
const today = new Date();
today.setHours(0, 0, 0, 0);
// 시작 오프셋 계산
let startOffset = firstDay;
if (startWeekOn === "monday") {
startOffset = firstDay === 0 ? 6 : firstDay - 1;
}
// 이전 달 날짜들
const prevMonthLastDate = getLastDateOfMonth(year, month - 1);
for (let i = startOffset - 1; i >= 0; i--) {
const date = new Date(year, month - 1, prevMonthLastDate - i);
days.push(createCalendarDay(date, false, today));
}
// 현재 달 날짜들
for (let day = 1; day <= lastDate; day++) {
const date = new Date(year, month, day);
days.push(createCalendarDay(date, true, today));
}
// 다음 달 날짜들 (42개 채우기)
const remainingDays = 42 - days.length;
for (let day = 1; day <= remainingDays; day++) {
const date = new Date(year, month + 1, day);
days.push(createCalendarDay(date, false, today));
}
return days;
}
/**
* CalendarDay 객체 생성
*/
function createCalendarDay(date: Date, isCurrentMonth: boolean, today: Date): CalendarDay {
const dayOfWeek = date.getDay();
const isToday = date.getTime() === today.getTime();
const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
// 공휴일 체크
const monthStr = String(date.getMonth() + 1).padStart(2, "0");
const dayStr = String(date.getDate()).padStart(2, "0");
const dateKey = `${monthStr}-${dayStr}`;
const holiday = KOREAN_HOLIDAYS.find((h) => h.date === dateKey);
return {
date,
day: date.getDate(),
isCurrentMonth,
isToday,
isWeekend,
isHoliday: !!holiday,
holidayName: holiday?.name,
};
}
/**
* 요일 이름 배열 반환
*/
export function getWeekDayNames(startWeekOn: "monday" | "sunday" = "sunday"): string[] {
const sundayFirst = ["일", "월", "화", "수", "목", "금", "토"];
const mondayFirst = ["월", "화", "수", "목", "금", "토", "일"];
return startWeekOn === "monday" ? mondayFirst : sundayFirst;
}
/**
* 월 이름 반환
*/
export function getMonthName(month: number): string {
const months = ["1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"];
return months[month];
}
/**
* 이전/다음 월로 이동
*/
export function navigateMonth(year: number, month: number, direction: "prev" | "next"): { year: number; month: number } {
if (direction === "prev") {
if (month === 0) {
return { year: year - 1, month: 11 };
}
return { year, month: month - 1 };
} else {
if (month === 11) {
return { year: year + 1, month: 0 };
}
return { year, month: month + 1 };
}
}