diff --git a/components/booking/DatePicker.tsx b/components/booking/DatePicker.tsx index 1bea6caf..cfcc6a79 100644 --- a/components/booking/DatePicker.tsx +++ b/components/booking/DatePicker.tsx @@ -4,6 +4,7 @@ import dayjs, { Dayjs } from "dayjs"; import utc from "dayjs/plugin/utc"; import timezone from "dayjs/plugin/timezone"; import getSlots from "@lib/slots"; + dayjs.extend(utc); dayjs.extend(timezone); diff --git a/components/booking/Slots.tsx b/components/booking/Slots.tsx index 8f92aaeb..1b4a8bfd 100644 --- a/components/booking/Slots.tsx +++ b/components/booking/Slots.tsx @@ -1,9 +1,10 @@ -import { useState, useEffect } from "react"; +import { useEffect, useState } from "react"; import { useRouter } from "next/router"; import getSlots from "../../lib/slots"; import dayjs, { Dayjs } from "dayjs"; import isBetween from "dayjs/plugin/isBetween"; import utc from "dayjs/plugin/utc"; + dayjs.extend(isBetween); dayjs.extend(utc); diff --git a/components/booking/TimeOptions.tsx b/components/booking/TimeOptions.tsx index 580e174e..a785789f 100644 --- a/components/booking/TimeOptions.tsx +++ b/components/booking/TimeOptions.tsx @@ -1,7 +1,7 @@ import { Switch } from "@headlessui/react"; import TimezoneSelect from "react-timezone-select"; import { useEffect, useState } from "react"; -import { timeZone, is24h } from "../../lib/clock"; +import { is24h, timeZone } from "../../lib/clock"; function classNames(...classes) { return classes.filter(Boolean).join(" "); diff --git a/components/ui/PoweredByCalendso.tsx b/components/ui/PoweredByCalendso.tsx index 2e890fa8..a438189d 100644 --- a/components/ui/PoweredByCalendso.tsx +++ b/components/ui/PoweredByCalendso.tsx @@ -3,10 +3,7 @@ import Link from "next/link"; const PoweredByCalendso = () => (
); -export default PoweredByCalendso; \ No newline at end of file +export default PoweredByCalendso; diff --git a/components/ui/Scheduler.tsx b/components/ui/Scheduler.tsx index 045c726d..edec1319 100644 --- a/components/ui/Scheduler.tsx +++ b/components/ui/Scheduler.tsx @@ -7,6 +7,7 @@ import dayjs from "dayjs"; import utc from "dayjs/plugin/utc"; import timezone from "dayjs/plugin/timezone"; import { Availability } from "@prisma/client"; + dayjs.extend(utc); dayjs.extend(timezone); diff --git a/lib/CalEventParser.ts b/lib/CalEventParser.ts new file mode 100644 index 00000000..a38494f2 --- /dev/null +++ b/lib/CalEventParser.ts @@ -0,0 +1,93 @@ +import { CalendarEvent } from "./calendarClient"; +import { v5 as uuidv5 } from "uuid"; +import short from "short-uuid"; +import { stripHtml } from "./emails/helpers"; + +const translator = short(); + +export default class CalEventParser { + calEvent: CalendarEvent; + + constructor(calEvent: CalendarEvent) { + this.calEvent = calEvent; + } + + /** + * Returns a link to reschedule the given booking. + */ + public getRescheduleLink(): string { + return process.env.BASE_URL + "/reschedule/" + this.getUid(); + } + + /** + * Returns a link to cancel the given booking. + */ + public getCancelLink(): string { + return process.env.BASE_URL + "/cancel/" + this.getUid(); + } + + /** + * Returns a unique identifier for the given calendar event. + */ + public getUid(): string { + return translator.fromUUID(uuidv5(JSON.stringify(this.calEvent), uuidv5.URL)); + } + + /** + * Returns a footer section with links to change the event (as HTML). + */ + public getChangeEventFooterHtml(): string { + return `Loading...
; diff --git a/pages/settings/teams.tsx b/pages/settings/teams.tsx index d74c8ddd..c129939f 100644 --- a/pages/settings/teams.tsx +++ b/pages/settings/teams.tsx @@ -1,18 +1,16 @@ import { GetServerSideProps } from "next"; -import Head from 'next/head'; -import Shell from '../../components/Shell'; -import SettingsShell from '../../components/Settings'; -import { useEffect, useState } from 'react'; +import Head from "next/head"; +import Shell from "../../components/Shell"; +import SettingsShell from "../../components/Settings"; +import { useEffect, useState } from "react"; import type { Session } from "next-auth"; -import { useSession, getSession } from 'next-auth/client'; -import { - UsersIcon, -} from "@heroicons/react/outline"; +import { getSession, useSession } from "next-auth/client"; +import { UsersIcon } from "@heroicons/react/outline"; import TeamList from "../../components/team/TeamList"; import TeamListItem from "../../components/team/TeamListItem"; export default function Teams() { - const [session, loading] = useSession(); + const [, loading] = useSession(); const [teams, setTeams] = useState([]); const [invites, setInvites] = useState([]); const [showCreateTeamModal, setShowCreateTeamModal] = useState(false); @@ -23,17 +21,17 @@ export default function Teams() { throw new Error(err.message); } return resp.json(); - } + }; const loadData = () => { fetch("/api/user/membership") - .then(handleErrors) - .then((data) => { - setTeams(data.membership.filter((m) => m.role !== "INVITEE")); - setInvites(data.membership.filter((m) => m.role === "INVITEE")); - }) - .catch(console.log); - } + .then(handleErrors) + .then((data) => { + setTeams(data.membership.filter((m) => m.role !== "INVITEE")); + setInvites(data.membership.filter((m) => m.role === "INVITEE")); + }) + .catch(console.log); + }; useEffect(() => { loadData(); @@ -46,17 +44,17 @@ export default function Teams() { const createTeam = (e) => { e.preventDefault(); - return fetch('/api/teams', { - method: 'POST', - body: JSON.stringify({ name: e.target.elements['name'].value }), + return fetch("/api/teams", { + method: "POST", + body: JSON.stringify({ name: e.target.elements["name"].value }), headers: { - 'Content-Type': 'application/json' - } + "Content-Type": "application/json", + }, }).then(() => { loadData(); setShowCreateTeamModal(false); }); - } + }; return (View, edit and create teams to organise relationships between users
- {!(invites.length || teams.length) && + {!(invites.length || teams.length) && (Create your first team and invite other users to work together with you.
- Create a new team to collaborate with users. -
+Create a new team to collaborate with users.