basecafe.jp/src/app/reservation/page.tsx
2025-10-28 20:52:11 +09:00

176 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/app/reservation/page.tsx
import { getRoomReservations, Reservation } from "@/lib/reservation";
import { RoomInfo } from "@/lib/roominfo";
const ROOMS = Object.keys(RoomInfo); // ["ENJI","PINK","MINT"]
const startHour = 7; // 開店時間
const endHour = 22; // 閉店時間
const TIMES = Array.from({ length: endHour - startHour }, (_, i) => `${startHour + i}:00`); // 7:00〜21:00
function getNextWeekDates(): Date[] {
const today = new Date();
const dates: Date[] = [];
const dayOfWeek = today.getDay();
const daysUntilNextSaturday = 6 - dayOfWeek + 7; // 翌週土曜まで
for (let i = 0; i <= daysUntilNextSaturday; i++) {
const d = new Date(today);
d.setDate(today.getDate() + i);
dates.push(d);
}
return dates;
}
function formatDate(date: Date) {
const y = date.getFullYear();
const m = (date.getMonth() + 1).toString().padStart(2, "0");
const d = date.getDate().toString().padStart(2, "0");
return `${y}-${m}-${d}`;
}
function buildReservationMap(reservations: Reservation[], dates: Date[]) {
const map: Record<string, Record<string, "" | "">> = {};
TIMES.forEach((time) => {
map[time] = {};
dates.forEach((date) => {
map[time][formatDate(date)] = "◯";
});
});
reservations.forEach((r) => {
const dateStr = formatDate(new Date(r.sdate));
if (!map[TIMES[0]][dateStr]) return;
if (r.type === "oneday") {
TIMES.forEach((time) => (map[time][dateStr] = "✗"));
} else if (r.type === "range") {
const [startH, startM] = r.start.split(":").map(Number);
const startMinutes = startH * 60 + startM;
const [endH, endM] = r.end.split(":").map(Number);
const endMinutes = endH * 60 + endM;
TIMES.forEach((time) => {
const [hour, minute] = time.split(":").map(Number);
const timeMinutes = hour * 60 + minute;
if (timeMinutes >= startMinutes && timeMinutes < endMinutes) {
map[time][dateStr] = "✗";
}
});
}
});
return map;
}
export default async function ReservationPage() {
const dates = getNextWeekDates();
const dateLabels = dates.map(
(d) =>
`${d.getMonth() + 1}/${d.getDate()} (${
["日", "月", "火", "水", "木", "金", "土"][d.getDay()]
})`
);
// 3部屋の予約データ取得
const roomData: Record<string, Record<string, Record<string, "" | "">>> = {};
for (const room of ROOMS) {
const reservations = await getRoomReservations(room);
roomData[room] = buildReservationMap(reservations, dates);
}
return (
<main className="max-w-7xl mx-auto px-4 py-8 space-y-12 text-stone-700">
{ROOMS.map((room) => (
<section
key={room}
className="bg-white shadow-sm rounded-2xl border border-stone-200 p-6 space-y-6"
>
<h2 className="text-2xl text-stone-800 font-semibold">{room} </h2>
<p>
{" "}
<a
href={RoomInfo[room].url}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 underline"
>
</a>
</p>
<div
className="flex border border-stone-200"
style={{ "--col-count": dates.length } as React.CSSProperties}
>
{/* 固定列(時間) */}
<div className="flex-shrink-0 bg-stone-50">
<table className="border-collapse border border-stone-200 w-full md:w-[10%] text-stone-700">
<thead className="bg-stone-100 text-stone-700">
<tr>
<th className="border border-stone-200 px-2 py-1 text-sm font-semibold whitespace-nowrap">
</th>
</tr>
</thead>
<tbody>
{TIMES.map((time) => (
<tr key={time} className="even:bg-stone-50">
<td className="border border-stone-200 px-2 py-1 text-sm font-medium whitespace-nowrap">
{time}
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* 横スクロール可能列 */}
<div className="overflow-x-auto flex-1 bg-white">
<table className="border-collapse border border-stone-200 w-full md:table-fixed text-stone-700">
<thead className="bg-stone-100 text-stone-800">
<tr>
{dateLabels.map((label) => (
<th
key={label}
className="border border-stone-200 px-2 py-1 text-sm font-medium whitespace-nowrap
md:w-[calc(90%/var(--col-count))]"
>
{label}
</th>
))}
</tr>
</thead>
<tbody>
{TIMES.map((time) => (
<tr key={time} className="even:bg-stone-50">
{dates.map((date) => {
const dateStr = formatDate(date);
const val = roomData[room][time][dateStr];
return (
<td
key={date.toISOString()}
className={`border border-stone-200 px-2 py-1 text-center text-sm font-medium whitespace-nowrap
md:w-[calc(90%/var(--col-count))]
${
val === "✗"
? "bg-stone-100 text-stone-400"
: "bg-white text-stone-700"
}`}
>
{val}
</td>
);
})}
</tr>
))}
</tbody>
</table>
</div>
</div>
</section>
))}
</main>
);
}