fix: MC series uses earliest slot date for registration cutoff
Multi-session master classes are a series — once the first session passes, the group has started and registration closes. Changed all MC date logic from "latest slot" / "any future slot" to "earliest slot": - DashboardSummary: upcoming = earliest slot >= today - McRegistrationsTab: archive = earliest slot < today - AddBookingModal: only show MCs where earliest slot >= today - Public MasterClasses: isUpcoming checks earliest slot
This commit is contained in:
@@ -42,10 +42,13 @@ export function AddBookingModal({
|
|||||||
adminFetch("/api/admin/sections/masterClasses").then((r) => r.json()).then((data: { items?: { title: string; slots: { date: string }[] }[] }) => {
|
adminFetch("/api/admin/sections/masterClasses").then((r) => r.json()).then((data: { items?: { title: string; slots: { date: string }[] }[] }) => {
|
||||||
const today = new Date().toISOString().split("T")[0];
|
const today = new Date().toISOString().split("T")[0];
|
||||||
const upcoming = (data.items || [])
|
const upcoming = (data.items || [])
|
||||||
.filter((mc) => mc.slots?.some((s) => s.date >= today))
|
.filter((mc) => {
|
||||||
|
const earliest = mc.slots?.reduce((min, s) => s.date < min ? s.date : min, mc.slots[0]?.date ?? "");
|
||||||
|
return earliest && earliest >= today;
|
||||||
|
})
|
||||||
.map((mc) => ({
|
.map((mc) => ({
|
||||||
title: mc.title,
|
title: mc.title,
|
||||||
date: mc.slots.reduce((latest, s) => s.date > latest ? s.date : latest, ""),
|
date: mc.slots.reduce((min, s) => s.date < min ? s.date : min, mc.slots[0]?.date ?? ""),
|
||||||
}));
|
}));
|
||||||
setMcOptions(upcoming);
|
setMcOptions(upcoming);
|
||||||
if (upcoming.length === 0 && tab === "events") setEventType("open-day");
|
if (upcoming.length === 0 && tab === "events") setEventType("open-day");
|
||||||
|
|||||||
@@ -27,17 +27,17 @@ export function McRegistrationsTab({ filter }: { filter: BookingFilter }) {
|
|||||||
const dates: Record<string, string> = {};
|
const dates: Record<string, string> = {};
|
||||||
const mcItems = mcData.items || [];
|
const mcItems = mcData.items || [];
|
||||||
for (const mc of mcItems) {
|
for (const mc of mcItems) {
|
||||||
const latestSlot = mc.slots?.reduce((latest, s) => s.date > latest ? s.date : latest, "");
|
const earliestSlot = mc.slots?.reduce((min, s) => s.date < min ? s.date : min, mc.slots[0]?.date ?? "");
|
||||||
if (latestSlot) dates[mc.title] = latestSlot;
|
if (earliestSlot) dates[mc.title] = earliestSlot;
|
||||||
}
|
}
|
||||||
const regTitles = new Set(regData.map((r) => r.masterClassTitle));
|
const regTitles = new Set(regData.map((r) => r.masterClassTitle));
|
||||||
for (const regTitle of regTitles) {
|
for (const regTitle of regTitles) {
|
||||||
if (dates[regTitle]) continue;
|
if (dates[regTitle]) continue;
|
||||||
for (const mc of mcItems) {
|
for (const mc of mcItems) {
|
||||||
const latestSlot = mc.slots?.reduce((latest, s) => s.date > latest ? s.date : latest, "");
|
const earliestSlot = mc.slots?.reduce((min, s) => s.date < min ? s.date : min, mc.slots[0]?.date ?? "");
|
||||||
if (!latestSlot) continue;
|
if (!earliestSlot) continue;
|
||||||
if (regTitle.toLowerCase().includes(mc.title.toLowerCase()) || mc.title.toLowerCase().includes(regTitle.toLowerCase())) {
|
if (regTitle.toLowerCase().includes(mc.title.toLowerCase()) || mc.title.toLowerCase().includes(regTitle.toLowerCase())) {
|
||||||
dates[regTitle] = latestSlot;
|
dates[regTitle] = earliestSlot;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -582,7 +582,8 @@ function DashboardSummary({ onNavigate }: { onNavigate: (tab: Tab) => void }) {
|
|||||||
// Build set of upcoming MC titles
|
// Build set of upcoming MC titles
|
||||||
const upcomingTitles = new Set<string>();
|
const upcomingTitles = new Set<string>();
|
||||||
for (const mc of mcData.items || []) {
|
for (const mc of mcData.items || []) {
|
||||||
if (mc.slots?.some((s) => s.date >= today)) upcomingTitles.add(mc.title);
|
const earliest = mc.slots?.reduce((min, s) => s.date < min ? s.date : min, mc.slots[0]?.date ?? "");
|
||||||
|
if (earliest && earliest >= today) upcomingTitles.add(mc.title);
|
||||||
}
|
}
|
||||||
return regs.filter((r) => upcomingTitles.has(r.masterClassTitle));
|
return regs.filter((r) => upcomingTitles.has(r.masterClassTitle));
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -72,16 +72,18 @@ function calcDuration(slot: MasterClassSlot): string {
|
|||||||
|
|
||||||
function isUpcoming(item: MasterClassItem): boolean {
|
function isUpcoming(item: MasterClassItem): boolean {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
return (item.slots ?? []).some((s) => {
|
const slots = item.slots ?? [];
|
||||||
const slotDate = parseDate(s.date);
|
if (slots.length === 0) return false;
|
||||||
if (s.startTime) {
|
// Series MC: check earliest slot — if first session passed, group already started
|
||||||
const [h, m] = s.startTime.split(":").map(Number);
|
const earliestSlot = slots.reduce((min, s) => s.date < min.date ? s : min, slots[0]);
|
||||||
slotDate.setHours(h, m, 0, 0);
|
const d = parseDate(earliestSlot.date);
|
||||||
} else {
|
if (earliestSlot.startTime) {
|
||||||
slotDate.setHours(23, 59, 59, 999);
|
const [h, m] = earliestSlot.startTime.split(":").map(Number);
|
||||||
}
|
d.setHours(h, m, 0, 0);
|
||||||
return slotDate > now;
|
} else {
|
||||||
});
|
d.setHours(23, 59, 59, 999);
|
||||||
|
}
|
||||||
|
return d > now;
|
||||||
}
|
}
|
||||||
|
|
||||||
function MasterClassCard({
|
function MasterClassCard({
|
||||||
|
|||||||
Reference in New Issue
Block a user