import Head from "next/head"; import Link from "next/link"; import { useRouter } from "next/router"; import { CalendarIcon, ClockIcon, ExclamationIcon, LocationMarkerIcon } from "@heroicons/react/solid"; import prisma, { whereAndSelect } from "../../lib/prisma"; import { EventTypeCustomInputType } from "@prisma/client"; import { collectPageParameters, telemetryEventTypes, useTelemetry } from "../../lib/telemetry"; import { useEffect, useState } from "react"; import dayjs from "dayjs"; import utc from "dayjs/plugin/utc"; import timezone from "dayjs/plugin/timezone"; import "react-phone-number-input/style.css"; import PhoneInput from "react-phone-number-input"; import { LocationType } from "../../lib/location"; import Avatar from "../../components/Avatar"; import Button from "../../components/ui/Button"; import Theme from "@components/Theme"; import { ReactMultiEmail } from "react-multi-email"; dayjs.extend(utc); dayjs.extend(timezone); export default function Book(props: any): JSX.Element { const router = useRouter(); const { date, user, rescheduleUid } = router.query; const [is24h, setIs24h] = useState(false); const [preferredTimeZone, setPreferredTimeZone] = useState(""); const [loading, setLoading] = useState(false); const [error, setError] = useState(false); const [guestToggle, setGuestToggle] = useState(false); const [guestEmails, setGuestEmails] = useState([]); const locations = props.eventType.locations || []; const [selectedLocation, setSelectedLocation] = useState( locations.length === 1 ? locations[0].type : "" ); const { isReady } = Theme(props.user.theme); const telemetry = useTelemetry(); useEffect(() => { setPreferredTimeZone(localStorage.getItem("timeOption.preferredTimeZone") || dayjs.tz.guess()); setIs24h(!!localStorage.getItem("timeOption.is24hClock")); telemetry.withJitsu((jitsu) => jitsu.track(telemetryEventTypes.timeSelected, collectPageParameters())); }); function toggleGuestEmailInput() { setGuestToggle(!guestToggle); } const locationInfo = (type: LocationType) => locations.find((location) => location.type === type); // TODO: Move to translations const locationLabels = { [LocationType.InPerson]: "In-person meeting", [LocationType.Phone]: "Phone call", [LocationType.GoogleMeet]: "Google Meet", [LocationType.Zoom]: "Zoom Video", }; const bookingHandler = (event) => { const book = async () => { setLoading(true); setError(false); let notes = ""; if (props.eventType.customInputs) { notes = props.eventType.customInputs .map((input) => { const data = event.target["custom_" + input.id]; if (data) { if (input.type === EventTypeCustomInputType.BOOL) { return input.label + "\n" + (data.checked ? "Yes" : "No"); } else { return input.label + "\n" + data.value; } } }) .join("\n\n"); } if (!!notes && !!event.target.notes.value) { notes += "\n\nAdditional notes:\n" + event.target.notes.value; } else { notes += event.target.notes.value; } const payload = { start: dayjs(date).format(), end: dayjs(date).add(props.eventType.length, "minute").format(), name: event.target.name.value, email: event.target.email.value, notes: notes, guests: guestEmails, timeZone: preferredTimeZone, eventTypeId: props.eventType.id, rescheduleUid: rescheduleUid, }; if (selectedLocation) { switch (selectedLocation) { case LocationType.Phone: payload["location"] = event.target.phone.value; break; case LocationType.InPerson: payload["location"] = locationInfo(selectedLocation).address; break; // Catches all other location types, such as Google Meet, Zoom etc. default: payload["location"] = selectedLocation; } } telemetry.withJitsu((jitsu) => jitsu.track(telemetryEventTypes.bookingConfirmed, collectPageParameters()) ); /*const res = await */ fetch("/api/book/" + user, { body: JSON.stringify(payload), headers: { "Content-Type": "application/json", }, method: "POST", }); // TODO When the endpoint is fixed, change this to await the result again //if (res.ok) { let successUrl = `/success?date=${date}&type=${props.eventType.id}&user=${ props.user.username }&reschedule=${!!rescheduleUid}&name=${payload.name}`; if (payload["location"]) { if (payload["location"].includes("integration")) { successUrl += "&location=" + encodeURIComponent("Web conferencing details to follow."); } else { successUrl += "&location=" + encodeURIComponent(payload["location"]); } } await router.push(successUrl); /*} else { setLoading(false); setError(true); }*/ }; event.preventDefault(); book(); }; return ( isReady && (
{rescheduleUid ? "Reschedule" : "Confirm"} your {props.eventType.title} with{" "} {props.user.name || props.user.username} | Calendso

{props.user.name}

{props.eventType.title}

{props.eventType.length} minutes

{selectedLocation === LocationType.InPerson && (

{locationInfo(selectedLocation).address}

)}

{preferredTimeZone && dayjs(date) .tz(preferredTimeZone) .format((is24h ? "H:mm" : "h:mma") + ", dddd DD MMMM YYYY")}

{props.eventType.description}

{locations.length > 1 && (
Location {locations.map((location) => ( ))}
)} {selectedLocation === LocationType.Phone && (
{ /* DO NOT REMOVE: Callback required by PhoneInput, comment added to satisfy eslint:no-empty-function */ }} />
)} {props.eventType.customInputs && props.eventType.customInputs .sort((a, b) => a.id - b.id) .map((input) => (
{input.type !== EventTypeCustomInputType.BOOL && ( )} {input.type === EventTypeCustomInputType.TEXTLONG && (