From 961f297ba8054c921b2bbfff25ceec217333a765 Mon Sep 17 00:00:00 2001 From: Nico Date: Fri, 17 Sep 2021 23:31:44 +0200 Subject: [PATCH] No confirmation shall be needed when rescheduling events that need confirmation (#440) * No reconfirmation needed when rescheduling * adapted success page * Parse query as string Co-authored-by: nicolas Co-authored-by: Bailey Pumfleet Co-authored-by: Peer_Rich Co-authored-by: Alex van Andel --- components/ImageUploader.tsx | 2 +- components/team/EditTeam.tsx | 2 +- components/team/TeamListItem.tsx | 4 ++-- components/ui/Alert.tsx | 2 +- components/ui/Schedule/Schedule.tsx | 1 + lib/calendarClient.ts | 4 ++-- .../CalDav/CalDavCalendarAdapter.ts | 12 +++++----- pages/api/book/event.ts | 12 +++++----- .../office365calendar/callback.ts | 1 + pages/event-types/[type].tsx | 3 +-- pages/getting-started.tsx | 11 +++++----- pages/integrations/index.tsx | 2 +- pages/settings/teams.tsx | 2 +- pages/success.tsx | 22 +++++++++---------- 14 files changed, 41 insertions(+), 39 deletions(-) diff --git a/components/ImageUploader.tsx b/components/ImageUploader.tsx index 43a2188e0d..b76bdc6eee 100644 --- a/components/ImageUploader.tsx +++ b/components/ImageUploader.tsx @@ -1,5 +1,5 @@ import Cropper from "react-easy-crop"; -import { useState, useCallback, useRef } from "react"; +import { useCallback, useRef, useState } from "react"; import Slider from "./Slider"; export default function ImageUploader({ target, id, buttonMsg, handleAvatarChange, imageRef }) { diff --git a/components/team/EditTeam.tsx b/components/team/EditTeam.tsx index 02d96d7d36..549dafa268 100644 --- a/components/team/EditTeam.tsx +++ b/components/team/EditTeam.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState, useRef } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { ArrowLeftIcon, PlusIcon, TrashIcon } from "@heroicons/react/outline"; import ErrorAlert from "@components/ui/alerts/Error"; import { UsernameInput } from "@components/ui/UsernameInput"; diff --git a/components/team/TeamListItem.tsx b/components/team/TeamListItem.tsx index 10e1001009..052b82e111 100644 --- a/components/team/TeamListItem.tsx +++ b/components/team/TeamListItem.tsx @@ -1,9 +1,9 @@ import { - TrashIcon, DotsHorizontalIcon, + ExternalLinkIcon, LinkIcon, PencilAltIcon, - ExternalLinkIcon, + TrashIcon, } from "@heroicons/react/outline"; import Dropdown, { DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "../ui/Dropdown"; import { useState } from "react"; diff --git a/components/ui/Alert.tsx b/components/ui/Alert.tsx index a22ce26cf4..08deee22ff 100644 --- a/components/ui/Alert.tsx +++ b/components/ui/Alert.tsx @@ -1,4 +1,4 @@ -import { XCircleIcon, InformationCircleIcon, CheckCircleIcon } from "@heroicons/react/solid"; +import { CheckCircleIcon, InformationCircleIcon, XCircleIcon } from "@heroicons/react/solid"; import classNames from "classnames"; import { ReactNode } from "react"; diff --git a/components/ui/Schedule/Schedule.tsx b/components/ui/Schedule/Schedule.tsx index 20e29eaa25..c70a50041e 100644 --- a/components/ui/Schedule/Schedule.tsx +++ b/components/ui/Schedule/Schedule.tsx @@ -3,6 +3,7 @@ import Text from "@components/ui/Text"; import { PlusIcon, TrashIcon } from "@heroicons/react/outline"; import dayjs, { Dayjs } from "dayjs"; import classnames from "classnames"; + export const SCHEDULE_FORM_ID = "SCHEDULE_FORM_ID"; export const toCalendsoAvailabilityFormat = (schedule: Schedule) => { return schedule; diff --git a/lib/calendarClient.ts b/lib/calendarClient.ts index e9f02ca0c2..d28e5b3688 100644 --- a/lib/calendarClient.ts +++ b/lib/calendarClient.ts @@ -5,11 +5,11 @@ import { Credential } from "@prisma/client"; import CalEventParser from "./CalEventParser"; import { EventResult } from "@lib/events/EventManager"; import logger from "@lib/logger"; - -const log = logger.getChildLogger({ prefix: ["[lib] calendarClient"] }); import { CalDavCalendar } from "./integrations/CalDav/CalDavCalendarAdapter"; import { AppleCalendar } from "./integrations/Apple/AppleCalendarAdapter"; +const log = logger.getChildLogger({ prefix: ["[lib] calendarClient"] }); + // eslint-disable-next-line @typescript-eslint/no-var-requires const { google } = require("googleapis"); diff --git a/lib/integrations/CalDav/CalDavCalendarAdapter.ts b/lib/integrations/CalDav/CalDavCalendarAdapter.ts index 0c83a74bfe..c73ea79a56 100644 --- a/lib/integrations/CalDav/CalDavCalendarAdapter.ts +++ b/lib/integrations/CalDav/CalDavCalendarAdapter.ts @@ -1,17 +1,17 @@ -import { IntegrationCalendar, CalendarApiAdapter, CalendarEvent } from "../../calendarClient"; +import { CalendarApiAdapter, CalendarEvent, IntegrationCalendar } from "../../calendarClient"; import { symmetricDecrypt } from "@lib/crypto"; import { createAccount, - fetchCalendars, - fetchCalendarObjects, - getBasicAuthHeaders, createCalendarObject, - updateCalendarObject, deleteCalendarObject, + fetchCalendarObjects, + fetchCalendars, + getBasicAuthHeaders, + updateCalendarObject, } from "tsdav"; import { Credential } from "@prisma/client"; import ICAL from "ical.js"; -import { createEvent, DurationObject, Attendee, Person } from "ics"; +import { Attendee, createEvent, DurationObject, Person } from "ics"; import dayjs from "dayjs"; import { v4 as uuidv4 } from "uuid"; import { stripHtml } from "../../emails/helpers"; diff --git a/pages/api/book/event.ts b/pages/api/book/event.ts index 088fcc324a..268c9f21ae 100644 --- a/pages/api/book/event.ts +++ b/pages/api/book/event.ts @@ -242,13 +242,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }; // used for invitee emails } + // Initialize EventManager with credentials + const rescheduleUid = req.body.rescheduleUid; + const bookingCreateInput: Prisma.BookingCreateInput = { uid, title: evt.title, startTime: dayjs(evt.startTime).toDate(), endTime: dayjs(evt.endTime).toDate(), description: evt.description, - confirmed: !eventType.requiresConfirmation, + confirmed: !eventType.requiresConfirmation || !!rescheduleUid, location: evt.location, eventType: { connect: { @@ -375,9 +378,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } } - // Initialize EventManager with credentials const eventManager = new EventManager(user.credentials); - const rescheduleUid = req.body.rescheduleUid; + if (rescheduleUid) { // Use EventManager to conditionally use all needed integrations. const updateResults: CreateUpdateResult = await eventManager.update(evt, rescheduleUid); @@ -410,7 +412,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) } } - if (eventType.requiresConfirmation) { + if (eventType.requiresConfirmation && !rescheduleUid) { await new EventOrganizerRequestMail(evt, uid).sendEmail(); } @@ -429,6 +431,6 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) }, }); - // booking succesfull + // booking successful return res.status(201).json(booking); } diff --git a/pages/api/integrations/office365calendar/callback.ts b/pages/api/integrations/office365calendar/callback.ts index a410c214d0..64207f875d 100644 --- a/pages/api/integrations/office365calendar/callback.ts +++ b/pages/api/integrations/office365calendar/callback.ts @@ -1,6 +1,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { getSession } from "@lib/auth"; import prisma from "../../../../lib/prisma"; + const scopes = ["offline_access", "Calendars.Read", "Calendars.ReadWrite"]; export default async function handler(req: NextApiRequest, res: NextApiResponse) { diff --git a/pages/event-types/[type].tsx b/pages/event-types/[type].tsx index d39c9974ee..ad2456a173 100644 --- a/pages/event-types/[type].tsx +++ b/pages/event-types/[type].tsx @@ -3,7 +3,7 @@ import Modal from "@components/Modal"; import React, { useEffect, useRef, useState } from "react"; import Select, { OptionTypeBase } from "react-select"; import prisma from "@lib/prisma"; -import { EventTypeCustomInput, EventTypeCustomInputType, SchedulingType } from "@prisma/client"; +import { Availability, EventTypeCustomInput, EventTypeCustomInputType, SchedulingType } from "@prisma/client"; import { LocationType } from "@lib/location"; import Shell from "@components/Shell"; import { getSession } from "@lib/auth"; @@ -28,7 +28,6 @@ import { import dayjs from "dayjs"; import utc from "dayjs/plugin/utc"; import timezone from "dayjs/plugin/timezone"; -import { Availability } from "@prisma/client"; import { validJson } from "@lib/jsonUtils"; import throttle from "lodash.throttle"; import "react-dates/initialize"; diff --git a/pages/getting-started.tsx b/pages/getting-started.tsx index e7eb8d1c83..d29a8b056d 100644 --- a/pages/getting-started.tsx +++ b/pages/getting-started.tsx @@ -2,15 +2,15 @@ import Head from "next/head"; import prisma from "@lib/prisma"; import { useSession } from "next-auth/client"; import { + EventType, EventTypeCreateInput, + Schedule, ScheduleCreateInput, User, UserUpdateInput, - EventType, - Schedule, } from "@prisma/client"; import { NextPageContext } from "next"; -import React, { useState, useEffect, useRef } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { validJson } from "@lib/jsonUtils"; import TimezoneSelect from "react-timezone-select"; import Text from "@components/ui/Text"; @@ -18,8 +18,6 @@ import ErrorAlert from "@components/ui/alerts/Error"; import dayjs from "dayjs"; import utc from "dayjs/plugin/utc"; import timezone from "dayjs/plugin/timezone"; -dayjs.extend(utc); -dayjs.extend(timezone); import AddCalDavIntegration, { ADD_CALDAV_INTEGRATION_FORM_TITLE, } from "@lib/integrations/CalDav/components/AddCalDavIntegration"; @@ -33,6 +31,9 @@ import { ArrowRightIcon } from "@heroicons/react/outline"; import { getSession } from "@lib/auth"; import Button from "@components/ui/Button"; +dayjs.extend(utc); +dayjs.extend(timezone); + const DEFAULT_EVENT_TYPES = [ { title: "15 Min Meeting", diff --git a/pages/integrations/index.tsx b/pages/integrations/index.tsx index 3d77b7e196..68d83b12c3 100644 --- a/pages/integrations/index.tsx +++ b/pages/integrations/index.tsx @@ -1,7 +1,7 @@ import Link from "next/link"; import prisma from "@lib/prisma"; import Shell from "@components/Shell"; -import { useEffect, useState, useRef, useCallback } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { useSession } from "next-auth/client"; import { CheckCircleIcon, ChevronRightIcon, PlusIcon, XCircleIcon } from "@heroicons/react/solid"; import { InformationCircleIcon } from "@heroicons/react/outline"; diff --git a/pages/settings/teams.tsx b/pages/settings/teams.tsx index 2847567e24..a7a82b0c07 100644 --- a/pages/settings/teams.tsx +++ b/pages/settings/teams.tsx @@ -1,7 +1,7 @@ import { GetServerSideProps } from "next"; import Shell from "@components/Shell"; import SettingsShell from "@components/Settings"; -import { useEffect, useState, useRef } from "react"; +import { useEffect, useRef, useState } from "react"; import type { Session } from "next-auth"; import { useSession } from "next-auth/client"; import { UsersIcon } from "@heroicons/react/outline"; diff --git a/pages/success.tsx b/pages/success.tsx index 84d3b608ae..f80d4748ee 100644 --- a/pages/success.tsx +++ b/pages/success.tsx @@ -23,7 +23,7 @@ dayjs.extend(timezone); export default function Success(props: inferSSRProps) { const router = useRouter(); - const { location, name } = router.query; + const { location, name, reschedule } = router.query; const [is24h, setIs24h] = useState(false); const [date, setDate] = useState(dayjs.utc(asStringOrNull(router.query.date))); @@ -62,12 +62,14 @@ export default function Success(props: inferSSRProps) return encodeURIComponent(event.value); } + const needsConfirmation = props.eventType.requiresConfirmation && reschedule != "true"; + return ( isReady && (
@@ -83,22 +85,18 @@ export default function Success(props: inferSSRProps) aria-labelledby="modal-headline">
- {!props.eventType.requiresConfirmation && ( - - )} - {props.eventType.requiresConfirmation && ( - - )} + {!needsConfirmation && } + {needsConfirmation && }

- {props.eventType.requiresConfirmation + {needsConfirmation ? props.profile.name !== null ? `${props.profile.name} still needs to confirm or reject the booking.` : "Your booking still needs to be confirmed or rejected." @@ -126,7 +124,7 @@ export default function Success(props: inferSSRProps)

- {!props.eventType.requiresConfirmation && ( + {!needsConfirmation && (
Add to calendar