You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
2.3 KiB
TypeScript

// frontend/components/calendar/MonthView.tsx — 월 뷰 (실제 날짜 기반, 셀당 이벤트 ≤3 + +N개 더)
"use client";
import type { MouseEvent } from "react";
import { dayNum, monthCells, toMin } from "@/lib/calendar/time";
import type { CalEvent, Calendar } from "@/lib/calendar/types";
export function MonthView({
events,
calMap,
monthRef,
weekdays,
todayDate,
onOpen,
onSelDay,
}: {
events: CalEvent[];
calMap: Record<string, Calendar>;
monthRef: string; // 보여줄 달(ISO)
weekdays: string[];
todayDate: string;
onOpen: (ev: CalEvent, e: MouseEvent) => void;
onSelDay: (iso: string) => void;
}) {
const byDate: Record<string, CalEvent[]> = {};
events.forEach((e) => {
(byDate[e.date] = byDate[e.date] || []).push(e);
});
Object.values(byDate).forEach((a) => a.sort((x, y) => toMin(x.start) - toMin(y.start)));
const cells = monthCells(monthRef);
return (
<div className="cpanel">
<div className="mo-head">
{weekdays.map((w, i) => (
<div key={w} className={"mo-wd" + (i === 0 || i === 6 ? " wknd" : "")}>
{w}
</div>
))}
</div>
<div className="mo-grid">
{cells.map((c) => {
const evs = c.inMonth ? byDate[c.date] || [] : [];
return (
<div
key={c.date}
className={
"mo-cell" +
(c.inMonth ? "" : " out") +
(c.inMonth && c.date === todayDate ? " today" : "")
}
onClick={() => c.inMonth && onSelDay(c.date)}
>
<div className="mo-dn">{dayNum(c.date)}</div>
{evs.slice(0, 3).map((ev) => (
<div
key={ev.id}
className={"mo-ev tint-" + (calMap[ev.cal]?.tone ?? "ink")}
onClick={(e) => {
e.stopPropagation();
onOpen(ev, e);
}}
>
<span className="pdot" />
<span className="mt">{ev.start || "종일"}</span>
<span className="mn">{ev.title}</span>
</div>
))}
{evs.length > 3 && <div className="mo-more">+{evs.length - 3} </div>}
</div>
);
})}
</div>
</div>
);
}