-
Notifications
You must be signed in to change notification settings - Fork 7
/
meetup-events.ts
153 lines (136 loc) · 4.26 KB
/
meetup-events.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import type { MeetupEventType } from '@api/meetup/event.graqhql.types';
import {
startOfMonth,
nextWednesday,
isWednesday,
isSameDay,
isBefore,
addMonths,
} from 'date-fns';
import { parseMonthsList } from './time';
export interface MeetupEventsApiResponse {
events: Pick<
MeetupEventType,
'id' | 'title' | 'dateTime' | 'eventUrl' | 'group' | 'duration' | 'venue'
>[];
}
export type ScheduledEvent = {
type: 'scheduled';
data: MeetupEventType;
epochTimeMs: number;
};
export type PlaceholderEvent = {
type: 'placeholder';
date: Date;
epochTimeMs: number;
};
export type UpcomingEvent = ScheduledEvent | PlaceholderEvent;
export function computeMeetupEventsApiResponse(
meetupEvents: MeetupEventType[] | null | undefined
): MeetupEventsApiResponse {
return {
events: (meetupEvents || [])?.map(
({ id, eventUrl, title, dateTime, group, duration, venue }) => ({
id,
title,
dateTime,
eventUrl,
group,
duration,
venue,
})
),
};
}
export const pastEventsPageSise =
parseInt(import.meta.env.PUBLIC_MEETUP_PAGE_SIZE, 10) || 10;
/**
* Computes the 3rd Wednesday of the month of the input date
* and returns it as a Date.
* @param date input date.
*/
export function computeThirdWednesdayOfMonth(date: Date | number): Date {
const firstDayOfNextMonth = startOfMonth(date);
if (isWednesday(firstDayOfNextMonth)) {
return nextWednesday(nextWednesday(firstDayOfNextMonth));
}
return nextWednesday(nextWednesday(nextWednesday(firstDayOfNextMonth)));
}
export function computeScheduledEvents(
scheduledUpcomingEvents: MeetupEventType[] | undefined | null
): ScheduledEvent[] {
return (
scheduledUpcomingEvents?.map(
(data): ScheduledEvent => ({
type: 'scheduled',
data,
epochTimeMs: new Date(data.dateTime).getTime(),
})
) || []
);
}
export interface ComputeUpcomingEventsOptions {
monthsWithoutGeneratedUpcomingEvents?: string | undefined | null;
}
export function createPlaceholderEvents({
scheduledEvents,
curentEpochTimeMs,
monthsWithoutGeneratedUpcomingEvents,
}: {
scheduledEvents: ScheduledEvent[];
curentEpochTimeMs: number;
monthsWithoutGeneratedUpcomingEvents: ComputeUpcomingEventsOptions['monthsWithoutGeneratedUpcomingEvents'];
}) {
const meetupOfThisMonth = computeThirdWednesdayOfMonth(curentEpochTimeMs);
const isNowBeforeMeetup =
!isSameDay(curentEpochTimeMs, meetupOfThisMonth) &&
isBefore(curentEpochTimeMs, meetupOfThisMonth);
const placeholderMonths = isNowBeforeMeetup ? [0, 1, 2, 3] : [1, 2, 3];
const { parsedMonths: monthsWithoutGeneratedEventsSet } = parseMonthsList(
monthsWithoutGeneratedUpcomingEvents
);
return placeholderMonths
.map((month): PlaceholderEvent => {
const date = computeThirdWednesdayOfMonth(
addMonths(new Date(curentEpochTimeMs), month)
);
return {
type: 'placeholder',
date,
epochTimeMs: date.getTime(),
};
})
.filter(
(placeholder) =>
!monthsWithoutGeneratedEventsSet.has(placeholder.date.getMonth()) &&
!scheduledEvents.some(
(scheduled) =>
isSameDay(scheduled.epochTimeMs, placeholder.epochTimeMs) // filter out placeholder if overlaps with a scheduled event
)
);
}
/**
* Given a list of scheduled events, returns a list of scheduled and placeholder
* events sorted by date in ascending order.
* @param scheduledUpcomingEvents Scheduled events
* @param curentEpochTimeMs built time epoch time i.e. Date.now().
* @param {ComputeUpcomingEventsOptions} options Additional options.
* @see {@link UpcomingEvent}
* @see {@link ComputeUpcomingEventsOptions}
*/
export function computeUpcomingEvents(
scheduledUpcomingEvents: MeetupEventType[] | undefined | null,
curentEpochTimeMs: number,
options?: ComputeUpcomingEventsOptions
): UpcomingEvent[] {
const scheduledEvents = computeScheduledEvents(scheduledUpcomingEvents);
const placeholderEvents = createPlaceholderEvents({
scheduledEvents,
curentEpochTimeMs,
monthsWithoutGeneratedUpcomingEvents:
options?.monthsWithoutGeneratedUpcomingEvents,
});
return (scheduledEvents as UpcomingEvent[])
.concat(placeholderEvents)
.sort((a, b) => a.epochTimeMs - b.epochTimeMs);
}