feat: migrate to Next.js for Mini App and enhance project structure
- Replaced the previous webapp with a new Mini App built using Next.js, improving performance and maintainability. - Updated the `.gitignore` to exclude Next.js build artifacts and node modules. - Revised documentation in `AGENTS.md`, `README.md`, and `architecture.md` to reflect the new Mini App structure and technology stack. - Enhanced Dockerfile to support the new build process for the Next.js application. - Updated CI workflow to build and test the Next.js application. - Added new configuration options for the Mini App, including `MINI_APP_SHORT_NAME` for improved deep linking. - Refactored frontend testing setup to accommodate the new structure and testing framework. - Removed legacy webapp files and dependencies to streamline the project.
This commit is contained in:
93
webapp-next/src/components/calendar/CalendarGrid.tsx
Normal file
93
webapp-next/src/components/calendar/CalendarGrid.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* 6-week (42-cell) calendar grid starting from Monday. Composes CalendarDay cells.
|
||||
* Ported from webapp/js/calendar.js renderCalendar.
|
||||
*/
|
||||
|
||||
"use client";
|
||||
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
firstDayOfMonth,
|
||||
getMonday,
|
||||
localDateString,
|
||||
} from "@/lib/date-utils";
|
||||
import type { CalendarEvent, DutyWithUser } from "@/types";
|
||||
import { dutiesByDate, calendarEventsByDate } from "@/lib/calendar-data";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { CalendarDay } from "./CalendarDay";
|
||||
|
||||
export interface CalendarGridProps {
|
||||
/** Currently displayed month. */
|
||||
currentMonth: Date;
|
||||
/** All duties for the visible range (will be grouped by date). */
|
||||
duties: DutyWithUser[];
|
||||
/** All calendar events for the visible range. */
|
||||
calendarEvents: CalendarEvent[];
|
||||
/** Called when a day cell is clicked (opens day detail). Receives date key and cell rect for popover. */
|
||||
onDayClick: (dateKey: string, anchorRect: DOMRect) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const CELLS = 42;
|
||||
|
||||
export function CalendarGrid({
|
||||
currentMonth,
|
||||
duties,
|
||||
calendarEvents,
|
||||
onDayClick,
|
||||
className,
|
||||
}: CalendarGridProps) {
|
||||
const dutiesByDateMap = useMemo(
|
||||
() => dutiesByDate(duties),
|
||||
[duties]
|
||||
);
|
||||
const calendarEventsByDateMap = useMemo(
|
||||
() => calendarEventsByDate(calendarEvents),
|
||||
[calendarEvents]
|
||||
);
|
||||
const todayKey = localDateString(new Date());
|
||||
|
||||
const cells = useMemo(() => {
|
||||
const first = firstDayOfMonth(currentMonth);
|
||||
const start = getMonday(first);
|
||||
const result: { date: Date; key: string; month: number }[] = [];
|
||||
const d = new Date(start);
|
||||
for (let i = 0; i < CELLS; i++) {
|
||||
const key = localDateString(d);
|
||||
result.push({ date: new Date(d), key, month: d.getMonth() });
|
||||
d.setDate(d.getDate() + 1);
|
||||
}
|
||||
return result;
|
||||
}, [currentMonth]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"calendar-grid grid grid-cols-7 gap-1 mb-4 min-h-[var(--calendar-grid-min-height)]",
|
||||
className
|
||||
)}
|
||||
role="grid"
|
||||
aria-label="Calendar"
|
||||
>
|
||||
{cells.map(({ date, key, month }) => {
|
||||
const isOtherMonth = month !== currentMonth.getMonth();
|
||||
const dayDuties = dutiesByDateMap[key] ?? [];
|
||||
const eventSummaries = calendarEventsByDateMap[key] ?? [];
|
||||
|
||||
return (
|
||||
<div key={key} role="gridcell" className="min-h-0">
|
||||
<CalendarDay
|
||||
dateKey={key}
|
||||
dayOfMonth={date.getDate()}
|
||||
isToday={key === todayKey}
|
||||
isOtherMonth={isOtherMonth}
|
||||
duties={dayDuties}
|
||||
eventSummaries={eventSummaries}
|
||||
onDayClick={onDayClick}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user