Skip to content

Commit 98d123a

Browse files
authored
[F] Fix Calendar.vue recurring events display (#31)
1 parent 145ca11 commit 98d123a

1 file changed

Lines changed: 40 additions & 2 deletions

File tree

content/Calendar.vue

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,45 @@ const fetchIcal = async () => {
2929
3030
const _tmp = [];
3131
for (let k in cal) _tmp.push(cal[k]);
32-
const events = _tmp.filter((ev) => ev.type == 'VEVENT' && ev.start && ev.start > now);
32+
33+
const events: CalendarComponent[] = [];
34+
_tmp.forEach((ev) => {
35+
if (ev.type !== 'VEVENT' || !ev.start) return;
36+
37+
if (ev.rrule) {
38+
// Expand the recurring events for the next 30 days to avoid clutter
39+
const limit = new Date(now);
40+
limit.setDate(limit.getDate() + 30);
41+
let dates = ev.rrule.between(now, limit, true);
42+
43+
// Fallback: If no occurrences in the next 30 days (e.g. quarterly/annual events),
44+
// fetch the immediate next occurrence.
45+
if (dates.length === 0) {
46+
const nextDate = ev.rrule.after(now, true);
47+
if (nextDate) dates = [nextDate];
48+
}
49+
50+
dates.forEach((date) => {
51+
const dateStr = date.toISOString().substring(0, 10);
52+
if (ev.exdate && ev.exdate[dateStr]) return;
53+
54+
if (ev.recurrences && ev.recurrences[dateStr]) {
55+
events.push(ev.recurrences[dateStr]);
56+
return;
57+
}
58+
59+
const clone = { ...ev };
60+
clone.start = date;
61+
if (ev.end) {
62+
const duration = ev.end.getTime() - ev.start.getTime();
63+
clone.end = new Date(date.getTime() + duration);
64+
}
65+
events.push(clone);
66+
});
67+
} else if (ev.start > now) {
68+
events.push(ev);
69+
}
70+
});
3371
3472
// If there are no upcoming events, show one from the past
3573
if (events.length == 0) {
@@ -69,7 +107,7 @@ onMounted(fetchIcal);
69107
<template>
70108
<div class="description" v-if="evs.length === 0">Loading events...</div>
71109
<div role="list" class="events">
72-
<div v-for="ev in evs" role="listitem" :key="ev.summary">
110+
<div v-for="ev in evs" role="listitem" :key="`${ev.uid || ev.summary}-${ev.start ? ev.start.getTime() : ''}`">
73111
<article class="event">
74112
<time class="date" v-if="ev.start" :datetime="getEventDate(ev.start)">
75113
<span class="month">{{ ev.start.toLocaleDateString('default', { month: 'short' }) }}</span>

0 commit comments

Comments
 (0)