"use client"; import React, { useMemo } from "react"; import { cn } from "@/lib/utils"; import { DateCell, ZoomLevel } from "../types"; import { dayLabels, monthLabels } from "../config"; interface TimelineHeaderProps { /** 시작 날짜 */ startDate: Date; /** 종료 날짜 */ endDate: Date; /** 줌 레벨 */ zoomLevel: ZoomLevel; /** 셀 너비 */ cellWidth: number; /** 헤더 높이 */ headerHeight: number; /** 리소스 컬럼 너비 */ resourceColumnWidth: number; /** 오늘 표시선 */ showTodayLine?: boolean; } /** * 날짜 범위 내의 모든 날짜 셀 생성 */ const generateDateCells = ( startDate: Date, endDate: Date, zoomLevel: ZoomLevel ): DateCell[] => { const cells: DateCell[] = []; const today = new Date(); today.setHours(0, 0, 0, 0); const current = new Date(startDate); current.setHours(0, 0, 0, 0); while (current <= endDate) { const date = new Date(current); const dayOfWeek = date.getDay(); const isToday = date.getTime() === today.getTime(); const isWeekend = dayOfWeek === 0 || dayOfWeek === 6; const isMonthStart = date.getDate() === 1; let label = ""; if (zoomLevel === "day") { label = `${date.getDate()}(${dayLabels[dayOfWeek]})`; } else if (zoomLevel === "week") { // 주간: 월요일 기준 주 시작 if (dayOfWeek === 1 || cells.length === 0) { label = `${date.getMonth() + 1}/${date.getDate()}`; } } else if (zoomLevel === "month") { // 월간: 월 시작일만 표시 if (isMonthStart || cells.length === 0) { label = monthLabels[date.getMonth()]; } } cells.push({ date, label, isToday, isWeekend, isMonthStart, }); current.setDate(current.getDate() + 1); } return cells; }; /** * 월 헤더 그룹 생성 (상단 행) */ const generateMonthGroups = ( cells: DateCell[] ): { month: string; year: number; count: number }[] => { const groups: { month: string; year: number; count: number }[] = []; cells.forEach((cell) => { const month = monthLabels[cell.date.getMonth()]; const year = cell.date.getFullYear(); if ( groups.length === 0 || groups[groups.length - 1].month !== month || groups[groups.length - 1].year !== year ) { groups.push({ month, year, count: 1 }); } else { groups[groups.length - 1].count++; } }); return groups; }; export function TimelineHeader({ startDate, endDate, zoomLevel, cellWidth, headerHeight, resourceColumnWidth, showTodayLine = true, }: TimelineHeaderProps) { // 날짜 셀 생성 const dateCells = useMemo( () => generateDateCells(startDate, endDate, zoomLevel), [startDate, endDate, zoomLevel] ); // 월 그룹 생성 const monthGroups = useMemo(() => generateMonthGroups(dateCells), [dateCells]); // 오늘 위치 계산 const todayPosition = useMemo(() => { const today = new Date(); today.setHours(0, 0, 0, 0); const todayIndex = dateCells.findIndex( (cell) => cell.date.getTime() === today.getTime() ); if (todayIndex === -1) return null; return resourceColumnWidth + todayIndex * cellWidth + cellWidth / 2; }, [dateCells, cellWidth, resourceColumnWidth]); return (