Files
rotaryclubofvellore/src/lib/meetings.ts
T
2026-09-25 14:41:56 +05:30

102 lines
3.1 KiB
TypeScript

// 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,
}));
}