diff --git a/db/booking.ts b/db/booking.ts index f7a8be0..5538daa 100644 --- a/db/booking.ts +++ b/db/booking.ts @@ -5,7 +5,6 @@ import { createCalendarEvent, deleteCalendarEvent } from '../lib/googlecalendar' import { Bill } from './bill' import { BOOKING_STATUS, VALIDATION_ERRORS } from './enums' -import { getBookedDays } from './index' export type Booking = { uuid: string @@ -76,7 +75,7 @@ const BookingSchema = new mongoose.Schema( validator: async function (days: string[]): Promise { const booking = this as Booking const uuid = booking.uuid && [booking.uuid] - const bookedDays = await getBookedDays(uuid) + const bookedDays = await BookingModel.findBookedDays(uuid) const doubleBookedDays = days.filter((day: string): boolean => bookedDays.includes(day) @@ -155,8 +154,10 @@ BookingSchema.static( } ) -export default (mongoose.models.Booking || +const BookingModel = (mongoose.models.Booking || mongoose.model( 'Booking', BookingSchema )) as BookingModel + +export default BookingModel; diff --git a/db/index.ts b/db/index.ts index 3c0f917..758df94 100644 --- a/db/index.ts +++ b/db/index.ts @@ -1,7 +1,9 @@ import * as mongoose from 'mongoose' import BookingModel, { Booking, BookingDocument } from './booking' import BillModel, { Bill } from './bill' +import { getBookedDays as calendarGetBookedDays } from '../lib/googlecalendar' import { BOOKING_STATUS } from './enums' +import { uniqueFilter } from '../helpers/array' let connectedPromise: Promise @@ -21,7 +23,12 @@ export async function getBookedDays( uuidsToIngore?: string[] ): Promise { await connect() - return BookingModel.findBookedDays(uuidsToIngore) + const bookedInDatabase = await BookingModel.findBookedDays(uuidsToIngore); + const bookedInCalendar = await calendarGetBookedDays(); + + return [ ...bookedInDatabase, ...bookedInCalendar] + .filter(uniqueFilter) + .sort(); } export async function getBookingByUUID(uuid: string): Promise { diff --git a/helpers/array.ts b/helpers/array.ts index 8ac2e20..5493526 100644 --- a/helpers/array.ts +++ b/helpers/array.ts @@ -16,3 +16,7 @@ export function getNextBigger(array: T[], pivot: T): T { return array.sort().find((day) => day > pivot) } + +export function uniqueFilter(value, index, self) { + return self.indexOf(value) === index; +} diff --git a/helpers/date.ts b/helpers/date.ts index 2ed39c3..3d9776f 100644 --- a/helpers/date.ts +++ b/helpers/date.ts @@ -1,4 +1,4 @@ -import { parse, format, addDays } from 'date-fns' +import { parse, format, addDays, subDays } from 'date-fns' import { utcToZonedTime } from 'date-fns-tz' const FRONTEND_FORMAT = 'dd.MM.yyyy' @@ -21,9 +21,11 @@ export function daysFormatFrontend(days: string[]): string { export function getDays({ startDate, endDate, + endDateExclusive = false, }: { startDate: Date endDate: Date + endDateExclusive?: boolean }): string[] { let currentDay = new Date(startDate.getTime()) const days = [dateFormatBackend(currentDay)] @@ -32,7 +34,9 @@ export function getDays({ return days } - while (currentDay < endDate) { + const inclusiveEndDate = endDateExclusive ? subDays(endDate, 1) : endDate; + + while (currentDay < inclusiveEndDate) { currentDay = addDays(currentDay, 1) days.push(dateFormatBackend(currentDay)) } diff --git a/lib/googlecalendar.ts b/lib/googlecalendar.ts index fcae0d2..7098f9f 100644 --- a/lib/googlecalendar.ts +++ b/lib/googlecalendar.ts @@ -1,5 +1,7 @@ import { google } from 'googleapis' +import { getBaseURL } from '../helpers/url'; import { Booking } from '../db/booking' +import { getDays } from '../helpers/date'; const calendarId = process.env.GOOGLE_CALENDAR_ID let credentials: object @@ -23,13 +25,21 @@ const calendar = google.calendar({ auth, }) -export async function getNewEvents() { +export async function getBookedDays() { const { data } = await calendar.events.list({ calendarId, timeMin: new Date().toISOString(), + timeZone: 'utc', }) return data.items + // ignore non all-day events + .filter(event => !!event.start.date) + .flatMap(event => getDays({ + startDate: new Date(event.start.date), + endDate: new Date(event.end.date), + endDateExclusive: true + })) } function getSummary(booking: Partial): string { @@ -44,12 +54,18 @@ function getSummary(booking: Partial): string { return summary } +function getDescription(booking: Booking): string { + const bookingUrl = `${getBaseURL()}/admin/booking/${booking.uuid}`; + + return `Managelink ${bookingUrl}`; +} + export async function createCalendarEvent(booking: Booking): Promise { const response = await calendar.events.insert({ calendarId, requestBody: { summary: getSummary(booking), - // TODO: description, + description: getDescription(booking), start: { date: booking.startDate }, end: { date: booking.endDate }, }, @@ -64,7 +80,9 @@ export async function deleteCalendarEvent(booking: Booking) { await calendar.events.delete({ calendarId, eventId: booking.calendarEventId, - }) + // TODO: really useful? + sendNotifications: true, + }); booking.calendarEventId = null }