@@ -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