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.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user