- Add Google Tasks integration and Apple Reminders support - Add task import/export with list management APIs - Add goal API for weekly goals - Add German holidays library - Add ImportListModal component - Enhance WeeklyView with major UI improvements - Enhance CalendarSettings with new connection options - Add external task fields to database schema - Add Playwright test suites for auth and tasks - Add iCloud reminders Python scripts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
91 lines
3.2 KiB
TypeScript
91 lines
3.2 KiB
TypeScript
/**
|
|
* Holiday detection service to provide hints for upcoming celebrations.
|
|
*/
|
|
|
|
interface Holiday {
|
|
name: string;
|
|
month: number; // 0-indexed (0 = Jan, 11 = Dec)
|
|
day: number;
|
|
description: string;
|
|
}
|
|
|
|
// Fixed-date holidays
|
|
const FIXED_HOLIDAYS: Holiday[] = [
|
|
{ name: 'New Year\'s Day', month: 0, day: 1, description: 'Happy New Year!' },
|
|
{ name: 'Valentine\'s Day', month: 1, day: 14, description: 'Love is in the air!' },
|
|
{ name: 'Halloween', month: 9, day: 31, description: 'Trick or treat!' },
|
|
{ name: 'Armistice Day', month: 10, day: 11, description: 'Lest we forget.' }, // Remembrance Day
|
|
{ name: 'Christmas Eve', month: 11, day: 24, description: 'Twas the night before Christmas...' },
|
|
{ name: 'Christmas Day', month: 11, day: 25, description: 'Merry Christmas!' },
|
|
{ name: 'Boxing Day', month: 11, day: 26, description: 'Happy Boxing Day!' },
|
|
{ name: 'New Year\'s Eve', month: 11, day: 31, description: 'Ring in the New Year!' },
|
|
];
|
|
|
|
/**
|
|
* Calculates Easter Sunday for a given year using the Meeus/Jones/Butcher algorithm.
|
|
*/
|
|
function getEasterSunday(year: number): Date {
|
|
const a = year % 19;
|
|
const b = Math.floor(year / 100);
|
|
const c = year % 100;
|
|
const d = Math.floor(b / 4);
|
|
const e = b % 4;
|
|
const f = Math.floor((b + 8) / 25);
|
|
const g = Math.floor((b - f + 1) / 3);
|
|
const h = (19 * a + b - d - g + 15) % 30;
|
|
const i = Math.floor(c / 4);
|
|
const k = c % 4;
|
|
const l = (32 + 2 * e + 2 * i - h - k) % 7;
|
|
const m = Math.floor((a + 11 * h + 22 * l) / 451);
|
|
const month = Math.floor((h + l - 7 * m + 114) / 31);
|
|
const day = ((h + l - 7 * m + 114) % 31) + 1;
|
|
return new Date(year, month - 1, day);
|
|
}
|
|
|
|
/**
|
|
* Returns a hint if there is a major holiday or celebration in the week starting from weekStart.
|
|
* A "week" is defined as 7 days from weekStart.
|
|
*/
|
|
export function getHolidayHint(weekStart: Date): string | null {
|
|
const weekEnd = new Date(weekStart);
|
|
weekEnd.setDate(weekEnd.getDate() + 7);
|
|
|
|
const year = weekStart.getFullYear();
|
|
|
|
// Check fixed holidays
|
|
for (const holiday of FIXED_HOLIDAYS) {
|
|
// Handle year boundaries for fixed holidays (e.g. looking at Jan 1 from Dec 28)
|
|
const yearsToCheck = [year, year + 1];
|
|
for (const y of yearsToCheck) {
|
|
const holidayDate = new Date(y, holiday.month, holiday.day);
|
|
if (holidayDate >= weekStart && holidayDate < weekEnd) {
|
|
return `Hint: ${holiday.name} is coming up! ${holiday.description}`;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check variable holidays (Easter related)
|
|
const easter = getEasterSunday(year);
|
|
|
|
// Easter Sunday
|
|
if (easter >= weekStart && easter < weekEnd) {
|
|
return "Hint: Easter Sunday is this week! Happy Easter!";
|
|
}
|
|
|
|
// Good Friday (2 days before)
|
|
const goodFriday = new Date(easter);
|
|
goodFriday.setDate(goodFriday.getDate() - 2);
|
|
if (goodFriday >= weekStart && goodFriday < weekEnd) {
|
|
return "Hint: Good Friday is this week.";
|
|
}
|
|
|
|
// Easter Monday (1 day after)
|
|
const easterMonday = new Date(easter);
|
|
easterMonday.setDate(easterMonday.getDate() + 1);
|
|
if (easterMonday >= weekStart && easterMonday < weekEnd) {
|
|
return "Hint: Easter Monday is this week.";
|
|
}
|
|
|
|
return null;
|
|
}
|