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 <privat@nicolasjessen.de> Co-authored-by: Bailey Pumfleet <pumfleet@hey.com> Co-authored-by: Peer_Rich <peeroke@gmail.com> Co-authored-by: Alex van Andel <me@alexvanandel.com>
This commit is contained in:
parent
4c6bf96213
commit
961f297ba8
14 changed files with 41 additions and 39 deletions
|
@ -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 }) {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -23,7 +23,7 @@ dayjs.extend(timezone);
|
|||
|
||||
export default function Success(props: inferSSRProps<typeof getServerSideProps>) {
|
||||
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<typeof getServerSideProps>)
|
|||
return encodeURIComponent(event.value);
|
||||
}
|
||||
|
||||
const needsConfirmation = props.eventType.requiresConfirmation && reschedule != "true";
|
||||
|
||||
return (
|
||||
isReady && (
|
||||
<div className="bg-neutral-50 dark:bg-neutral-900 h-screen">
|
||||
<HeadSeo
|
||||
title={`Booking ${props.eventType.requiresConfirmation ? "Submitted" : "Confirmed"}`}
|
||||
description={`Booking ${props.eventType.requiresConfirmation ? "Submitted" : "Confirmed"}`}
|
||||
title={`Booking ${needsConfirmation ? "Submitted" : "Confirmed"}`}
|
||||
description={`Booking ${needsConfirmation ? "Submitted" : "Confirmed"}`}
|
||||
/>
|
||||
<main className="max-w-3xl mx-auto py-24">
|
||||
<div className="fixed z-50 inset-0 overflow-y-auto">
|
||||
|
@ -83,22 +85,18 @@ export default function Success(props: inferSSRProps<typeof getServerSideProps>)
|
|||
aria-labelledby="modal-headline">
|
||||
<div>
|
||||
<div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-green-100">
|
||||
{!props.eventType.requiresConfirmation && (
|
||||
<CheckIcon className="h-8 w-8 text-green-600" />
|
||||
)}
|
||||
{props.eventType.requiresConfirmation && (
|
||||
<ClockIcon className="h-8 w-8 text-green-600" />
|
||||
)}
|
||||
{!needsConfirmation && <CheckIcon className="h-8 w-8 text-green-600" />}
|
||||
{needsConfirmation && <ClockIcon className="h-8 w-8 text-green-600" />}
|
||||
</div>
|
||||
<div className="mt-3 text-center sm:mt-5">
|
||||
<h3
|
||||
className="text-2xl leading-6 font-semibold dark:text-white text-neutral-900"
|
||||
id="modal-headline">
|
||||
{props.eventType.requiresConfirmation ? "Submitted" : "This meeting is scheduled"}
|
||||
{needsConfirmation ? "Submitted" : "This meeting is scheduled"}
|
||||
</h3>
|
||||
<div className="mt-3">
|
||||
<p className="text-sm text-neutral-600 dark:text-gray-300">
|
||||
{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<typeof getServerSideProps>)
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{!props.eventType.requiresConfirmation && (
|
||||
{!needsConfirmation && (
|
||||
<div className="mt-5 sm:mt-0 sm:pt-4 pt-2 text-center flex">
|
||||
<span className="font-medium text-gray-700 dark:text-gray-50 flex self-center mr-6">
|
||||
Add to calendar
|
||||
|
|
Loading…
Reference in a new issue