@@ -34,8 +34,20 @@ interface TimeProps {
34
34
dateTime ?: Date ;
35
35
}
36
36
37
+ // Set as a date to test the same day function
38
+ // a string in the form "YYYY-MM-DD" can be passed to test a specific date
39
+ const TEST_DATE = undefined ;
40
+
37
41
// Google maps API URL
38
- const url = `https://www.googleapis.com/calendar/v3/calendars/${ config . GOOGLE_CALENDAR_ID } /events?key=${ config . GOOGLE_API_KEY } ` ;
42
+ const today = new Date ( TEST_DATE ?? new Date ( ) . toLocaleDateString ( ) ) ;
43
+ const nextWeek = new Date ( today ) ;
44
+ nextWeek . setDate ( today . getDate ( ) + 7 ) ;
45
+ const url = `https://www.googleapis.com/calendar/v3/calendars/${
46
+ config . GOOGLE_CALENDAR_ID
47
+ } /events?key=${
48
+ config . GOOGLE_API_KEY
49
+ } &timeMax=${ nextWeek . toISOString ( ) } &timeMin=${ today . toISOString ( ) } `;
50
+ console . log ( url ) ;
39
51
40
52
// Function to fetch all of the events
41
53
const fetchEvents = async ( url : string ) => {
@@ -55,19 +67,32 @@ const fetchEvents = async (url: string) => {
55
67
} ;
56
68
57
69
// Check if two dates are the same day
58
- function isSameDay ( date1 : Date , date2 : Date ) : boolean {
59
- return (
60
- date1 . getFullYear ( ) === date2 . getFullYear ( ) &&
61
- date1 . getMonth ( ) === date2 . getMonth ( ) &&
62
- date1 . getDate ( ) === date2 . getDate ( )
70
+ function isSameDay ( date1 : Date , date2 : Date , event ?: string ) : boolean {
71
+ // Normalize dates to midnight UTC
72
+ const normalizeDate = ( date : Date ) =>
73
+ new Date ( Date . UTC ( date . getFullYear ( ) , date . getMonth ( ) , date . getDate ( ) ) ) ;
74
+
75
+ const d1 = normalizeDate ( date1 ) ;
76
+ d1 . setDate ( d1 . getDate ( ) + 1 ) ;
77
+ const d2 = normalizeDate ( date2 ) ;
78
+
79
+ const result = d1 . getTime ( ) === d2 . getTime ( ) ;
80
+
81
+ console . log (
82
+ `Date1: ${ d1 . toISOString ( ) } ` ,
83
+ `Date2: ${ d2 . toISOString ( ) } ` ,
84
+ `Event: ${ event } ` ,
85
+ `Are the same day? ${ result } `
63
86
) ;
87
+
88
+ return result ;
64
89
}
65
90
66
- // remove html tags from a piece of text
91
+ // remove html tags from a piece of text
67
92
// as the returned description from gcal api returns with tags
68
93
function removeHTMLTags ( str : string ) {
69
- if ( str && typeof ( str ) === "string" ) {
70
- return str . replace ( / ( < ( [ ^ > ] + ) > ) / ig , "" ) ;
94
+ if ( str && typeof str === "string" ) {
95
+ return str . replace ( / ( < ( [ ^ > ] + ) > ) / gi , "" ) ;
71
96
} else {
72
97
throw new TypeError (
73
98
"The value passed to removeHTMLTags is not a string!"
@@ -83,7 +108,11 @@ interface DateProps {
83
108
}
84
109
85
110
// Grab the start and end date or time, depending if the event is multi or single day in duration
86
- function getDateProps ( date1 : Date | string , date2 : Date | string ) {
111
+ function getDateProps (
112
+ date1 : Date | string ,
113
+ date2 : Date | string ,
114
+ event ?: string
115
+ ) {
87
116
const dateObject : DateProps = {
88
117
start : "" ,
89
118
end : "" ,
@@ -95,17 +124,27 @@ function getDateProps(date1: Date | string, date2: Date | string) {
95
124
const newDate = new Date ( date1 ) ;
96
125
newDate . setHours ( newDate . getHours ( ) - 4 ) ;
97
126
const month = ( newDate . getMonth ( ) + 1 ) . toString ( ) ;
98
- const day = ( newDate . getDate ( ) ) . toString ( ) ;
127
+ const day = newDate . getDate ( ) . toString ( ) ;
99
128
const year = newDate . getFullYear ( ) . toString ( ) ;
100
129
130
+ newDate . setDate ( newDate . getDate ( ) - 1 ) ;
131
+ if ( event === "Operations Meeting" || event === "Kickstart Meeting" ) {
132
+ newDate . setDate ( newDate . getDate ( ) - 7 ) ;
133
+ }
134
+
101
135
const newDate2 = new Date ( date2 ) ;
102
136
newDate2 . setHours ( newDate2 . getHours ( ) - 4 ) ;
103
137
const month2 = ( newDate2 . getMonth ( ) + 1 ) . toString ( ) ;
104
138
const day2 = newDate2 . getDate ( ) . toString ( ) ;
105
139
const year2 = newDate2 . getFullYear ( ) . toString ( ) ;
106
140
141
+ console . log ( event , newDate , newDate2 ) ;
142
+
107
143
// Set start and end to times, and include the date
108
- if ( isSameDay ( newDate , newDate2 ) ) {
144
+ if (
145
+ isSameDay ( newDate , newDate2 , `${ event } SAME DAY CHECK FOR DATE FORMAT` )
146
+ ) {
147
+ console . log ( "Same day event" ) ;
109
148
const hours1 = newDate . getHours ( ) ;
110
149
const minutes1 = newDate . getMinutes ( ) . toString ( ) . padStart ( 2 , "0" ) ;
111
150
const hours2 = newDate2 . getHours ( ) ;
@@ -134,101 +173,91 @@ async function getValidEvents() {
134
173
const data = await fetchEvents ( url ) ;
135
174
136
175
// sets all consts to a new date with the local timezone.
137
- const today = new Date ( new Date ( ) . toLocaleDateString ( ) ) ;
138
- const tomorrow = new Date ( new Date ( ) . toLocaleDateString ( ) ) ;
139
- const nextWeek = new Date ( new Date ( ) . toLocaleDateString ( ) ) ;
176
+ const today = new Date ( TEST_DATE ?? new Date ( ) . toLocaleDateString ( ) ) ;
177
+ const tomorrow = new Date ( today ) ;
178
+ const nextWeek = new Date ( today ) ;
140
179
141
180
// offsets tomorrow and nextweek appropriately (you can do this to add days to a date)
142
181
tomorrow . setDate ( today . getDate ( ) + 1 ) ;
143
182
nextWeek . setDate ( today . getDate ( ) + 7 ) ;
144
-
183
+
145
184
const validEvents : Messages [ ] = [ ] ;
146
- // filters out "cancelled" events from the initial data
147
- const allEvents = data . items . filter ( ( event ) => event . status !== "cancelled" ) ;
185
+ // filters out "cancelled" events from the initial data and objects that are recurring, and obj.recurrence is not null
186
+ const allEvents = data . items
187
+ . filter ( ( event ) => event . status !== "cancelled" )
188
+ . filter ( ( event ) => event . recurrence !== null )
189
+ // remove elements with the same summary, keeping the greatest date
190
+ // this is to prevent duplicate events from being displayed
191
+ . reduce (
192
+ (
193
+ acc : GoogleCalendarDataProps [ ] ,
194
+ event : GoogleCalendarDataProps
195
+ ) => {
196
+ const existingEvent = acc . find (
197
+ ( e ) => e . summary === event . summary
198
+ ) ;
199
+ if ( existingEvent ) {
200
+ const existingDate = new Date (
201
+ existingEvent . start . dateTime ??
202
+ existingEvent . start . date ??
203
+ ""
204
+ ) ;
205
+ const currentDate = new Date (
206
+ event . start . dateTime ?? event . start . date ?? ""
207
+ ) ;
208
+ if ( currentDate > existingDate ) {
209
+ acc = acc . filter ( ( e ) => e . summary !== event . summary ) ;
210
+ acc . push ( event ) ;
211
+ }
212
+ } else {
213
+ if (
214
+ event . summary === "Operations Meeting" ||
215
+ event . summary === "Kickstart Meeting"
216
+ ) {
217
+ const newDate = new Date (
218
+ event . start . dateTime ?? event . start . date ?? ""
219
+ ) ;
220
+ newDate . setDate ( newDate . getDate ( ) + 7 ) ;
221
+ event . start . dateTime = newDate ;
222
+ }
223
+ acc . push ( event ) ;
224
+ }
225
+ return acc ;
226
+ } ,
227
+ [ ]
228
+ ) ;
229
+
230
+ // Print all summaries and start dates
231
+ allEvents . map ( ( obj : GoogleCalendarDataProps ) => {
232
+ console . log ( obj . summary , obj . start . dateTime ) ;
233
+ } ) ;
148
234
149
235
// maps through the filtered events
150
236
allEvents . map ( ( obj : GoogleCalendarDataProps ) => {
151
237
// gets the event date based on two fields from the API
152
238
// also sets this to local time zone
153
- const eventDate = new Date ( new Date (
154
- obj . start . dateTime ?? obj . start . date ?? "TBA"
155
- ) . toLocaleDateString ( ) ) ;
156
-
157
- // checks if this is a recurring event
158
- if ( obj . recurrence ) {
159
- // parses through the RRULE string provided by the API
160
- // this rule defines recurring events
161
- const rule = RRule . rrulestr ( obj . recurrence [ 0 ] ) ;
162
- // gets all the occurences based on the RRULE
163
- const occurrences = rule . all ( ) ;
164
-
165
- // goes through each occurrence
166
- occurrences . forEach ( ( occurrence : Date ) => {
167
- // gets the local timezone value for the occurrence
168
- occurrence = new Date ( occurrence . toLocaleDateString ( ) ) ;
169
- // if the object is already in the validEvents array, skip over this one
170
- if (
171
- ! validEvents . includes ( { ...obj , range : "Today" } ) &&
172
- ! validEvents . includes ( { ...obj , range : "Tomorrow" } ) &&
173
- ! validEvents . includes ( { ...obj , range : "Next Week" } ) ) {
174
- // checks if today's date is the same as the occurrence,
175
- // and if the eventDate is the same day as the occurrence OR
176
- // its a known recurring event
177
- if (
178
- isSameDay ( today , occurrence ) &&
179
- ( isSameDay ( eventDate , occurrence ) ||
180
- (
181
- obj . summary . includes ( "Operations Meetings" ) ||
182
- obj . summary . includes ( "Kickstart Meeting" )
183
- )
184
- ) ) {
185
- validEvents . push ( {
186
- ...obj ,
187
- range : "Today" ,
188
- } ) ;
189
- // same as above except for tomorrow
190
- } else if (
191
- isSameDay ( tomorrow , occurrence ) &&
192
- isSameDay ( eventDate , occurrence )
193
- ) {
194
- validEvents . push ( {
195
- ...obj ,
196
- range : "Tomorrow" ,
197
- } ) ;
198
- // checks if next weeks date is the same as the occurrence,
199
- // if the eventDate is the same as the occurrence,
200
- // and if a known recurring event is the one we're checking
201
- } else if (
202
- isSameDay ( nextWeek , occurrence ) &&
203
- ! obj . summary . includes ( "Operations Meetings" ) &&
204
- ! obj . summary . includes ( "Kickstart Meeting" ) &&
205
- isSameDay ( eventDate , occurrence )
206
- ) {
207
- validEvents . push ( {
208
- ...obj ,
209
- range : "Next Week" ,
210
- } ) ;
211
- }
212
- }
239
+ const eventDate = new Date (
240
+ new Date (
241
+ obj . start . dateTime ?? obj . start . date ?? "TBA"
242
+ ) . toLocaleDateString ( )
243
+ ) ;
244
+
245
+ console . log ( today , tomorrow , nextWeek ) ;
246
+ if ( isSameDay ( today , eventDate , `${ obj . summary } TODAY` ) ) {
247
+ validEvents . push ( {
248
+ ...obj ,
249
+ range : "Today" ,
250
+ } ) ;
251
+ } else if ( isSameDay ( tomorrow , eventDate , `${ obj . summary } TOMORROW` ) ) {
252
+ validEvents . push ( {
253
+ ...obj ,
254
+ range : "Tomorrow" ,
255
+ } ) ;
256
+ } else if ( isSameDay ( nextWeek , eventDate , `${ obj . summary } NEXT WEEK` ) ) {
257
+ validEvents . push ( {
258
+ ...obj ,
259
+ range : "Next Week" ,
213
260
} ) ;
214
- // if not a recurring event
215
- } else {
216
- if ( isSameDay ( today , eventDate ) ) {
217
- validEvents . push ( {
218
- ...obj ,
219
- range : "Today" ,
220
- } ) ;
221
- } else if ( isSameDay ( tomorrow , eventDate ) ) {
222
- validEvents . push ( {
223
- ...obj ,
224
- range : "Tomorrow" ,
225
- } ) ;
226
- } else if ( isSameDay ( nextWeek , eventDate ) ) {
227
- validEvents . push ( {
228
- ...obj ,
229
- range : "Next Week" ,
230
- } ) ;
231
- }
232
261
}
233
262
} ) ;
234
263
@@ -243,7 +272,8 @@ export async function execute() {
243
272
244
273
try {
245
274
// Check events on a schedule
246
- cron . schedule ( "0 16 * * *" , async ( ) => {
275
+ cron . schedule ( "*/5 * * * * *" , async ( ) => {
276
+ console . log ( "Checking for events..." ) ;
247
277
const events = await getValidEvents ( ) ;
248
278
249
279
if ( events . length === 0 ) {
@@ -258,7 +288,8 @@ export async function execute() {
258
288
const prefix = event . range ;
259
289
const date = getDateProps (
260
290
event . start . dateTime ?? event . start . date ?? "6/9/1969" ,
261
- event . end . dateTime ?? event . end . date ?? "6/9/1969"
291
+ event . end . dateTime ?? event . end . date ?? "6/9/1969" ,
292
+ event . summary
262
293
) ;
263
294
264
295
// Conditionally render the fields based off the date
@@ -297,9 +328,11 @@ export async function execute() {
297
328
name : `${ prefix } !` ,
298
329
iconURL : "https://i.imgur.com/0BR5rSn.png" ,
299
330
} )
300
- . setDescription ( he . decode (
301
- removeHTMLTags ( event . description ?? "TBA" ) ?? "TBA"
302
- ) )
331
+ . setDescription (
332
+ he . decode (
333
+ removeHTMLTags ( event . description ?? "TBA" ) ?? "TBA"
334
+ )
335
+ )
303
336
. addFields ( fields )
304
337
305
338
. setFooter ( {
0 commit comments