diff --git a/src/App.svelte b/src/App.svelte index dc8b509..94b7c5e 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -10,7 +10,7 @@ import frLocale from '@fullcalendar/core/locales/fr'; import EventModal from './EventModal.svelte'; import FilterBar from './FilterBar.svelte'; - import { refreshEvents, calendarTree } from './calendar'; + import { mkSource, calendarTree } from './calendar'; import { debounce } from 'lodash'; import 'bootstrap/dist/css/bootstrap.css'; @@ -57,34 +57,18 @@ month: mobile ? 'numeric' : 'long', day: 'numeric' }, - events: [], + eventSources: [], themeSystem: 'bootstrap5' }); - let selectedCalendars; - let updateTimer; - - async function reloadEvents(selectedCalendars) { - const evts = await refreshEvents(selectedCalendars); - return evts.flat(); - } + let selectedCalendars = []; const updateEvents = debounce(calendars => { - return reloadEvents(calendars).then(events => { - options.update(opts => ({ - ...opts, - events - })); - }); - }, 300); - - onMount(async () => { - const events = await reloadEvents(selectedCalendars); options.update(opts => ({ ...opts, - events + eventSources: selectedCalendars.map(mkSource).filter(x => !!x) })); - }); + }, 300); $: updateEvents(selectedCalendars); diff --git a/src/calendar.js b/src/calendar.js index f4e1e11..fb433bb 100644 --- a/src/calendar.js +++ b/src/calendar.js @@ -1,5 +1,3 @@ -import ICAL from 'ical.js' - const clouds = { KLUB_RESEAU: 'klub-reseau', ELEVES_ENS: 'eleves-ens' @@ -29,6 +27,10 @@ const calendars = { } } +const calendarsByName = Object.fromEntries( + Object.entries(calendars).map(([id, {name}]) => ([name, id])) +); + export const calendarTree = { 'Clubs COF': { 'Club réseau': {}, @@ -47,12 +49,17 @@ export const calendarTree = { const calendarIds = Object.keys(calendars) -function mkCalendarUrl(id, { cloud }) { - return `/cal/${cloud}/${id}/?export&accept=jcal` +function mkCalendarUrl(id, { cloud }, extra={}) { + return `/cal/${cloud}/${id}/?` + new URLSearchParams({ + ...extra, + export: true, + expand: true, + accept: 'jcal' + }); } -function fetchCalendar(id, cal) { - return fetch(mkCalendarUrl(id, cal), { credentials: 'omit' }) +function fetchCalendar(id, cal, extra={}) { + return fetch(mkCalendarUrl(id, cal, extra), { credentials: 'omit' }) .then(resp => resp.json()) .catch(err => console.error(err)) } @@ -125,25 +132,29 @@ function mkEventsFromCalendar(id, cal) { }) } -export function mkEvent(title, start, duration, ...rest) { - start = new Date(start) - const end = new Date(start) - end.setMinutes(start.getMinutes() + duration) +export function mkSource(name) { + const calendarId = calendarsByName[name]; + if (!calendarId) return null; + const calendar = calendars[calendarId]; + return { - title, - start, - end, - ...rest + id: name, + ...(calendar?.meta || {}), + success: calendarData => { + if (calendarData[0] !== 'vcalendar') return; + const cal = new Calendar(calendarId, calendarData); + return cal.events.map(fcEventFromjCalEvent(cal)); + }, + failure: error => { + console.error(`Fatal error during event source fetching of '${name}': ${error}`); + }, + events: (info, successCallback, failureCallback) => { + const { start, end } = info; + fetchCalendar(calendarId, calendar, { + start: start.valueOf() / 1000, + end: end.valueOf() / 1000 + }) + .then(successCallback, failureCallback); + } } } - -// TODO: move to FullCalendar custom fetcher to control start&end. -export function refreshEvents(selectedCalendars) { - return Promise.all( - calendarIds - .filter(id => - selectedCalendars ? selectedCalendars.includes(calendars[id].name) : true - ) - .map(id => mkEventsFromCalendar(id, calendars[id])) - ) -}