Files
famapp/src/lib/reminder-offsets.ts
T
ginnoir e1c2a090fb feat: p2 batch 28-31 reminders lists comments bang stats
Calendar events support multiple reminder offsets with presets and per-user defaults.

Lists index adds inline task entry and list property editing.

Generic entity comments on list detail. New bangs.stats dashboard widget.

Closes Gitea #28, #29, #30, #31. Migrations 0022 and 0023.
2026-07-04 22:17:35 -05:00

63 lines
2.0 KiB
TypeScript

export type ReminderOffsetUnit = "minutes" | "hours" | "days" | "weeks";
export type ReminderPreset = {
label: string;
offsetMinutes: number;
};
export const REMINDER_PRESETS: ReminderPreset[] = [
{ label: "At event time", offsetMinutes: 0 },
{ label: "5 minutes before", offsetMinutes: 5 },
{ label: "15 minutes before", offsetMinutes: 15 },
{ label: "30 minutes before", offsetMinutes: 30 },
{ label: "1 hour before", offsetMinutes: 60 },
{ label: "2 hours before", offsetMinutes: 120 },
{ label: "1 day before", offsetMinutes: 1440 },
{ label: "2 days before", offsetMinutes: 2880 },
{ label: "1 week before", offsetMinutes: 10080 },
];
export function formatReminderOffset(offsetMinutes: number): string {
const preset = REMINDER_PRESETS.find((p) => p.offsetMinutes === offsetMinutes);
if (preset) return preset.label;
if (offsetMinutes === 0) return "At event time";
if (offsetMinutes % 10080 === 0) {
const weeks = offsetMinutes / 10080;
return weeks === 1 ? "1 week before" : `${weeks} weeks before`;
}
if (offsetMinutes % 1440 === 0) {
const days = offsetMinutes / 1440;
return days === 1 ? "1 day before" : `${days} days before`;
}
if (offsetMinutes % 60 === 0) {
const hours = offsetMinutes / 60;
return hours === 1 ? "1 hour before" : `${hours} hours before`;
}
return offsetMinutes === 1 ? "1 minute before" : `${offsetMinutes} minutes before`;
}
export function customOffsetToMinutes(value: number, unit: ReminderOffsetUnit): number {
const safe = Math.max(0, Math.floor(value));
switch (unit) {
case "minutes":
return safe;
case "hours":
return safe * 60;
case "days":
return safe * 1440;
case "weeks":
return safe * 10080;
}
}
export function normalizeReminderOffsets(offsets: number[]): number[] {
return [...new Set(offsets.filter((n) => Number.isFinite(n) && n >= 0))].toSorted(
(a, b) => b - a,
);
}
export function fireAtForEventStart(startAt: Date, offsetMinutes: number): Date {
return new Date(startAt.getTime() - offsetMinutes * 60_000);
}