mirror of
https://github.com/nfonteyne/octane-website.git
synced 2026-09-03 23:24:48 +02:00
update: integrate ics calendar
This commit is contained in:
parent
b602093246
commit
63fb6cd45a
22 changed files with 845 additions and 193 deletions
57
src/lib/calendarAvailability.js
Normal file
57
src/lib/calendarAvailability.js
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
const { parisWallClockToUTC } = require('./calendarDates');
|
||||
|
||||
// Default rehearsal-availability windows, Europe/Paris local time — used
|
||||
// whenever no admin-configured slotConfig is passed in (and by the pure-logic
|
||||
// tests below, so those keep testing this exact default without needing to
|
||||
// know about the DB-backed override path in calendarRepo/calendarSync).
|
||||
const DEFAULT_SLOT_CONFIG = {
|
||||
weekday: { startHour: 18, startMinute: 30, endHour: 21, endMinute: 0 },
|
||||
weekend: { startHour: 15, startMinute: 0, endHour: 19, endMinute: 0 },
|
||||
};
|
||||
const MAX_WEEKS = 3;
|
||||
|
||||
// One slot per day for the next `weeks` weeks (capped at 3, same as the rest
|
||||
// of the calendar feature), starting from today's Paris-local calendar date
|
||||
// — not the server's own timezone, which may not be Europe/Paris.
|
||||
function generateSlots(weeks = MAX_WEEKS, slotConfig = DEFAULT_SLOT_CONFIG) {
|
||||
const days = Math.min(weeks || MAX_WEEKS, MAX_WEEKS) * 7;
|
||||
const parisToday = new Intl.DateTimeFormat('en-CA', { timeZone: 'Europe/Paris' }).format(new Date());
|
||||
const [ty, tm, td] = parisToday.split('-').map(Number);
|
||||
const anchor = Date.UTC(ty, tm - 1, td);
|
||||
|
||||
const slots = [];
|
||||
for (let i = 0; i < days; i++) {
|
||||
// This is only ever used to walk calendar dates one day at a time, never
|
||||
// treated as a real instant — the actual Paris-local conversion happens
|
||||
// below via parisWallClockToUTC, so there's no timezone ambiguity here.
|
||||
const dayAnchor = new Date(anchor + i * 86400000);
|
||||
const year = dayAnchor.getUTCFullYear();
|
||||
const month = dayAnchor.getUTCMonth() + 1;
|
||||
const day = dayAnchor.getUTCDate();
|
||||
const isWeekend = dayAnchor.getUTCDay() === 0 || dayAnchor.getUTCDay() === 6;
|
||||
const spec = isWeekend ? slotConfig.weekend : slotConfig.weekday;
|
||||
|
||||
slots.push({
|
||||
lower: parisWallClockToUTC(year, month, day, spec.startHour, spec.startMinute),
|
||||
upper: parisWallClockToUTC(year, month, day, spec.endHour, spec.endMinute),
|
||||
});
|
||||
}
|
||||
return slots;
|
||||
}
|
||||
|
||||
// intervals: [{start: Date, end: Date}] — flat, already-expanded busy blocks
|
||||
// (recurring events expanded, all-day events resolved to a concrete local-day
|
||||
// span) so this stays a plain half-open-interval overlap check.
|
||||
function isBusyDuring(intervals, slotLower, slotUpper) {
|
||||
return intervals.some((interval) => interval.start < slotUpper && interval.end > slotLower);
|
||||
}
|
||||
|
||||
// Widens a slot by `marginMinutes` on each side — used only for the busy/free
|
||||
// check (to account for travel time between back-to-back calendar events),
|
||||
// never for the slot that actually gets stored/displayed.
|
||||
function widenWindow(lower, upper, marginMinutes) {
|
||||
const marginMs = (marginMinutes || 0) * 60000;
|
||||
return { lower: new Date(lower.getTime() - marginMs), upper: new Date(upper.getTime() + marginMs) };
|
||||
}
|
||||
|
||||
module.exports = { generateSlots, isBusyDuring, widenWindow, DEFAULT_SLOT_CONFIG };
|
||||
Loading…
Add table
Add a link
Reference in a new issue