// Date helpers shared by the site and the admin panel (no server-only imports). import type { MeetingItem } from "./content"; /** Today's date in India as YYYY-MM-DD. */ export function todayIST() { return new Date().toLocaleDateString("en-CA", { timeZone: "Asia/Kolkata" }); } /** The next meeting on or after today, if any. */ export function getNextMeeting(list: MeetingItem[]): MeetingItem | undefined { const today = todayIST(); return [...list].filter((m) => m.date >= today).sort((a, b) => a.date.localeCompare(b.date))[0]; } export function formatMeetingDate(date: string) { const [y, m, d] = date.split("-").map(Number); return new Date(Date.UTC(y, m - 1, d)).toLocaleDateString("en-IN", { weekday: "short", day: "numeric", month: "short", year: "numeric", timeZone: "UTC", }); } /** Event dates are saved as YYYY-MM-DD (date picker); older free-text dates are shown as typed. */ export function formatEventDate(date: string) { return /^\d{4}-\d{2}-\d{2}$/.test(date) ? formatMeetingDate(date) : date; } /** A card in the website's "Past Events" list: a manual event or a completed meeting. */ export type PastEventCard = { id: string; href: string; image: string; date: string; title: string; text: string; kind: "event" | "meeting"; }; /** Best-effort sortable timestamp from free-text dates like "12 Aug 2026" or "Aug 2026". */ function toTime(date: string): number | null { if (!date) return null; const t = Date.parse(/^\d{4}-\d{2}-\d{2}$/.test(date) ? `${date}T00:00:00Z` : date); return Number.isNaN(t) ? null : t; } /** * Website "Past Events" = events added by the admin + meetings whose date has passed. * Newest first. Admin events without a readable date keep their admin order at the top. */ export function buildPastEvents( events: { id: string; image: string; date: string; title: string; text: string }[], meetings: (MeetingItem & { details?: string })[], ): PastEventCard[] { const today = todayIST(); const cards: (PastEventCard & { t: number | null; i: number })[] = [ ...events.map((e, i) => ({ id: e.id, href: `/events/${e.id}`, image: e.image, date: formatEventDate(e.date), title: e.title, text: e.text, kind: "event" as const, t: toTime(e.date), i, })), ...meetings .filter((m) => m.date < today) .map((m, i) => ({ id: `m-${m.id}`, href: `/meetings/${m.id}`, image: m.poster, date: formatMeetingDate(m.date), title: m.topic || "Club meeting", text: (m.details ?? "").replace(/\s+/g, " ").trim().slice(0, 160) || [m.venue && `Club meeting at ${m.venue}`, m.time].filter(Boolean).join(" ยท "), kind: "meeting" as const, t: toTime(m.date), i: events.length + i, })), ]; cards.sort((a, b) => { if (a.t === null && b.t === null) return a.i - b.i; if (a.t === null) return -1; if (b.t === null) return 1; return b.t - a.t || a.i - b.i; }); return cards.map((c) => ({ id: c.id, href: c.href, image: c.image, date: c.date, title: c.title, text: c.text, kind: c.kind, })); }