Skip to content

Commit 69126af

Browse files
feat(api): calculate last meeting time server-side
1 parent ba52543 commit 69126af

File tree

3 files changed

+24
-5
lines changed

3 files changed

+24
-5
lines changed

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,10 @@ with a specific time and venue (e.g. a specific Zoom link). In order to support
8383
exception to a recurring meeting.
8484
- **Last:** The last possible meeting end time. If a meeting is recurring,
8585
this will be the end time of the last meeting instance in that recurring
86-
range. Or, if the recurring range is infinite, we use [JavaScript's max
87-
date](https://stackoverflow.com/questions/11526504/minimum-and-maximum-date)
88-
(Fri Sep 12 275760) which is more than sufficient. This is calculated and
89-
assigned server-side using [`rrule`](https://www.npmjs.com/package/rrule). It
90-
is completely ignored client-side (in favor of the `to` property).
86+
range. Or, if the recurring range is infinite, we use Firestore's max date
87+
(Dec 31 9999) which is more than sufficient. This is calculated and assigned
88+
server-side using [`rrule`](https://www.npmjs.com/package/rrule). It is
89+
completely ignored client-side (in favor of the `to` property).
9190

9291
Upon creation, Tutorbook sends an email to all of the `people` in the new
9392
meeting's match with the meeting time, venue, and everyone's contact info.

lib/api/get/last-time.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { RRule } from 'rrule';
2+
3+
import { Timeslot } from 'lib/model';
4+
5+
/**
6+
* Get the last possible timeslot end time taking into account recurrence rules.
7+
* Calculated at indexing time and used query time to filter meetings.
8+
* @see {@link https://github.com/tutorbookapp/tutorbook#recurring-meetings}
9+
* @see {@link https://npmjs.com/package/rrule}
10+
* @see {@link https://bit.ly/3q7ZaBk}
11+
*/
12+
export default function getLastTime(time: Timeslot): Date {
13+
const options = RRule.parseString(time.recur || 'RRULE:COUNT=1');
14+
const rrule = new RRule({ ...options, dtstart: time.from });
15+
if (!options.until && !options.count) return new Date(253402300799999);
16+
return new Date((rrule.all().pop() || time.from).valueOf() + time.duration);
17+
}

lib/api/routes/meetings/create.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import createMatchSearchObj from 'lib/api/create/match-search-obj';
88
import createMeetingDoc from 'lib/api/create/meeting-doc';
99
import createMeetingSearchObj from 'lib/api/create/meeting-search-obj';
1010
import createZoom from 'lib/api/create/zoom';
11+
import getLastTime from 'lib/api/get/last-time';
1112
import getMatch from 'lib/api/get/match';
1213
import getOrg from 'lib/api/get/org';
1314
import getPeople from 'lib/api/get/people';
@@ -86,6 +87,8 @@ export default async function createMeeting(
8687
}
8788

8889
body.venue = await createZoom(body, people);
90+
body.time.last = getLastTime(body.time);
91+
8992
const meeting = await createMeetingDoc(body);
9093
await createMeetingSearchObj(meeting);
9194

0 commit comments

Comments
 (0)