2021-09-22 18:36:13 +00:00
|
|
|
|
import {
|
|
|
|
|
CalendarIcon,
|
|
|
|
|
ClockIcon,
|
|
|
|
|
CreditCardIcon,
|
|
|
|
|
ExclamationIcon,
|
|
|
|
|
LocationMarkerIcon,
|
|
|
|
|
} from "@heroicons/react/solid";
|
2021-09-14 08:45:28 +00:00
|
|
|
|
import { EventTypeCustomInputType } from "@prisma/client";
|
|
|
|
|
import dayjs from "dayjs";
|
2021-09-22 19:52:38 +00:00
|
|
|
|
import Head from "next/head";
|
|
|
|
|
import { useRouter } from "next/router";
|
|
|
|
|
import { stringify } from "querystring";
|
|
|
|
|
import { useCallback, useEffect, useState } from "react";
|
|
|
|
|
import { FormattedNumber, IntlProvider } from "react-intl";
|
2021-09-14 08:45:28 +00:00
|
|
|
|
import { ReactMultiEmail } from "react-multi-email";
|
2021-09-22 19:52:38 +00:00
|
|
|
|
import PhoneInput from "react-phone-number-input";
|
|
|
|
|
import "react-phone-number-input/style.css";
|
|
|
|
|
|
|
|
|
|
import { createPaymentLink } from "@ee/lib/stripe/client";
|
|
|
|
|
|
2021-09-14 08:45:28 +00:00
|
|
|
|
import { asStringOrNull } from "@lib/asStringOrNull";
|
|
|
|
|
import { timeZone } from "@lib/clock";
|
2021-10-08 11:43:48 +00:00
|
|
|
|
import { useLocale } from "@lib/hooks/useLocale";
|
2021-09-14 08:45:28 +00:00
|
|
|
|
import useTheme from "@lib/hooks/useTheme";
|
2021-09-22 19:52:38 +00:00
|
|
|
|
import { LocationType } from "@lib/location";
|
|
|
|
|
import createBooking from "@lib/mutations/bookings/create-booking";
|
2021-09-15 02:58:29 +00:00
|
|
|
|
import { parseZone } from "@lib/parseZone";
|
2021-09-22 19:52:38 +00:00
|
|
|
|
import { collectPageParameters, telemetryEventTypes, useTelemetry } from "@lib/telemetry";
|
|
|
|
|
import { BookingCreateBody } from "@lib/types/booking";
|
|
|
|
|
|
|
|
|
|
import AvatarGroup from "@components/ui/AvatarGroup";
|
|
|
|
|
import { Button } from "@components/ui/Button";
|
|
|
|
|
|
2021-09-22 18:36:13 +00:00
|
|
|
|
import { BookPageProps } from "../../../pages/[user]/book";
|
|
|
|
|
import { TeamBookingPageProps } from "../../../pages/team/[slug]/book";
|
2021-09-14 08:45:28 +00:00
|
|
|
|
|
2021-09-22 18:36:13 +00:00
|
|
|
|
type BookingPageProps = BookPageProps | TeamBookingPageProps;
|
|
|
|
|
|
|
|
|
|
const BookingPage = (props: BookingPageProps) => {
|
2021-10-08 11:43:48 +00:00
|
|
|
|
const { t } = useLocale({ localeProp: props.localeProp });
|
2021-09-14 08:45:28 +00:00
|
|
|
|
const router = useRouter();
|
|
|
|
|
const { rescheduleUid } = router.query;
|
2021-09-24 22:11:30 +00:00
|
|
|
|
const { isReady } = useTheme(props.profile.theme);
|
2021-09-14 08:45:28 +00:00
|
|
|
|
|
|
|
|
|
const date = asStringOrNull(router.query.date);
|
|
|
|
|
const timeFormat = asStringOrNull(router.query.clock) === "24h" ? "H:mm" : "h:mma";
|
|
|
|
|
|
|
|
|
|
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<LocationType>(
|
|
|
|
|
locations.length === 1 ? locations[0].type : ""
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const telemetry = useTelemetry();
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
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 = {
|
2021-10-08 11:43:48 +00:00
|
|
|
|
[LocationType.InPerson]: t("in_person_meeting"),
|
|
|
|
|
[LocationType.Phone]: t("phone_call"),
|
2021-09-14 08:45:28 +00:00
|
|
|
|
[LocationType.GoogleMeet]: "Google Meet",
|
|
|
|
|
[LocationType.Zoom]: "Zoom Video",
|
2021-10-07 16:12:39 +00:00
|
|
|
|
[LocationType.Daily]: "Daily.co Video",
|
2021-09-14 08:45:28 +00:00
|
|
|
|
};
|
|
|
|
|
|
2021-09-22 18:36:13 +00:00
|
|
|
|
const _bookingHandler = (event) => {
|
2021-09-14 08:45:28 +00:00
|
|
|
|
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) {
|
2021-10-08 11:43:48 +00:00
|
|
|
|
return input.label + "\n" + (data.checked ? t("yes") : t("no"));
|
2021-09-14 08:45:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
return input.label + "\n" + data.value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.join("\n\n");
|
|
|
|
|
}
|
|
|
|
|
if (!!notes && !!event.target.notes.value) {
|
2021-10-08 11:43:48 +00:00
|
|
|
|
notes += `\n\n${t("additional_notes")}:\n` + event.target.notes.value;
|
2021-09-14 08:45:28 +00:00
|
|
|
|
} else {
|
|
|
|
|
notes += event.target.notes.value;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-22 18:36:13 +00:00
|
|
|
|
const payload: BookingCreateBody = {
|
2021-09-14 08:45:28 +00:00
|
|
|
|
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,
|
|
|
|
|
eventTypeId: props.eventType.id,
|
|
|
|
|
timeZone: timeZone(),
|
|
|
|
|
};
|
2021-09-22 18:36:13 +00:00
|
|
|
|
if (typeof rescheduleUid === "string") payload.rescheduleUid = rescheduleUid;
|
|
|
|
|
if (typeof router.query.user === "string") payload.user = router.query.user;
|
2021-09-14 08:45:28 +00:00
|
|
|
|
|
|
|
|
|
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())
|
|
|
|
|
);
|
|
|
|
|
|
2021-09-22 18:36:13 +00:00
|
|
|
|
const content = await createBooking(payload).catch((e) => {
|
|
|
|
|
console.error(e.message);
|
|
|
|
|
setLoading(false);
|
|
|
|
|
setError(true);
|
2021-09-14 08:45:28 +00:00
|
|
|
|
});
|
2021-09-22 18:36:13 +00:00
|
|
|
|
|
|
|
|
|
if (content?.id) {
|
|
|
|
|
const params: { [k: string]: any } = {
|
|
|
|
|
date,
|
|
|
|
|
type: props.eventType.id,
|
|
|
|
|
user: props.profile.slug,
|
|
|
|
|
reschedule: !!rescheduleUid,
|
|
|
|
|
name: payload.name,
|
2021-09-29 15:36:29 +00:00
|
|
|
|
email: payload.email,
|
2021-09-22 18:36:13 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (payload["location"]) {
|
|
|
|
|
if (payload["location"].includes("integration")) {
|
|
|
|
|
params.location = "Web conferencing details to follow.";
|
|
|
|
|
} else {
|
|
|
|
|
params.location = payload["location"];
|
|
|
|
|
}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-22 18:36:13 +00:00
|
|
|
|
const query = stringify(params);
|
|
|
|
|
let successUrl = `/success?${query}`;
|
|
|
|
|
|
|
|
|
|
if (content?.paymentUid) {
|
2021-10-05 22:46:48 +00:00
|
|
|
|
successUrl = createPaymentLink({
|
|
|
|
|
paymentUid: content?.paymentUid,
|
|
|
|
|
name: payload.name,
|
|
|
|
|
date,
|
|
|
|
|
absolute: false,
|
|
|
|
|
});
|
2021-09-22 18:36:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await router.push(successUrl);
|
|
|
|
|
} else {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
setError(true);
|
|
|
|
|
}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
event.preventDefault();
|
|
|
|
|
book();
|
|
|
|
|
};
|
|
|
|
|
|
2021-10-12 08:29:12 +00:00
|
|
|
|
const bookingHandler = useCallback(_bookingHandler, [guestEmails]);
|
2021-09-22 18:36:13 +00:00
|
|
|
|
|
2021-09-14 08:45:28 +00:00
|
|
|
|
return (
|
2021-09-24 22:11:30 +00:00
|
|
|
|
<div>
|
|
|
|
|
<Head>
|
|
|
|
|
<title>
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{rescheduleUid
|
|
|
|
|
? t("booking_reschedule_confirmation", {
|
|
|
|
|
eventTypeTitle: props.eventType.title,
|
|
|
|
|
profileName: props.profile.name,
|
|
|
|
|
})
|
|
|
|
|
: t("booking_confirmation", {
|
|
|
|
|
eventTypeTitle: props.eventType.title,
|
|
|
|
|
profileName: props.profile.name,
|
|
|
|
|
})}{" "}
|
|
|
|
|
| Cal.com
|
2021-09-24 22:11:30 +00:00
|
|
|
|
</title>
|
|
|
|
|
<link rel="icon" href="/favicon.ico" />
|
|
|
|
|
</Head>
|
2021-09-14 08:45:28 +00:00
|
|
|
|
|
2021-09-24 22:11:30 +00:00
|
|
|
|
<main className="max-w-3xl mx-auto my-0 sm:my-24">
|
|
|
|
|
{isReady && (
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<div className="overflow-hidden bg-white border border-gray-200 dark:bg-neutral-900 dark:border-0 sm:rounded-sm">
|
|
|
|
|
<div className="px-4 py-5 sm:flex sm:p-4">
|
2021-09-14 08:45:28 +00:00
|
|
|
|
<div className="sm:w-1/2 sm:border-r sm:dark:border-black">
|
|
|
|
|
<AvatarGroup
|
|
|
|
|
size={16}
|
|
|
|
|
items={[{ image: props.profile.image, alt: props.profile.name }].concat(
|
|
|
|
|
props.eventType.users
|
|
|
|
|
.filter((user) => user.name !== props.profile.name)
|
|
|
|
|
.map((user) => ({
|
|
|
|
|
image: user.avatar,
|
|
|
|
|
title: user.name,
|
|
|
|
|
}))
|
|
|
|
|
)}
|
|
|
|
|
/>
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<h2 className="font-medium text-gray-500 font-cal dark:text-gray-300">
|
2021-09-22 21:23:19 +00:00
|
|
|
|
{props.profile.name}
|
|
|
|
|
</h2>
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<h1 className="mb-4 text-3xl font-semibold text-gray-800 dark:text-white">
|
2021-09-14 08:45:28 +00:00
|
|
|
|
{props.eventType.title}
|
|
|
|
|
</h1>
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<p className="mb-2 text-gray-500">
|
2021-09-14 08:45:28 +00:00
|
|
|
|
<ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{props.eventType.length} {t("minutes")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</p>
|
2021-09-22 18:36:13 +00:00
|
|
|
|
{props.eventType.price > 0 && (
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<p className="px-2 py-1 mb-1 -ml-2 text-gray-500">
|
2021-09-22 18:36:13 +00:00
|
|
|
|
<CreditCardIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
|
|
|
|
<IntlProvider locale="en">
|
|
|
|
|
<FormattedNumber
|
|
|
|
|
value={props.eventType.price / 100.0}
|
|
|
|
|
style="currency"
|
|
|
|
|
currency={props.eventType.currency.toUpperCase()}
|
|
|
|
|
/>
|
|
|
|
|
</IntlProvider>
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
{selectedLocation === LocationType.InPerson && (
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<p className="mb-2 text-gray-500">
|
2021-09-14 08:45:28 +00:00
|
|
|
|
<LocationMarkerIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
|
|
|
|
{locationInfo(selectedLocation).address}
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<p className="mb-4 text-green-500">
|
2021-09-14 08:45:28 +00:00
|
|
|
|
<CalendarIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
2021-09-15 02:58:29 +00:00
|
|
|
|
{parseZone(date).format(timeFormat + ", dddd DD MMMM YYYY")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</p>
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<p className="mb-8 text-gray-600 dark:text-white">{props.eventType.description}</p>
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</div>
|
|
|
|
|
<div className="sm:w-1/2 sm:pl-8 sm:pr-4">
|
|
|
|
|
<form onSubmit={bookingHandler}>
|
|
|
|
|
<div className="mb-4">
|
2021-10-12 08:29:12 +00:00
|
|
|
|
<label htmlFor="name" className="block text-sm font-medium text-gray-700 dark:text-white">
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{t("your_name")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</label>
|
|
|
|
|
<div className="mt-1">
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
name="name"
|
|
|
|
|
id="name"
|
|
|
|
|
required
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block w-full border-gray-300 rounded-md shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black sm:text-sm"
|
2021-09-14 08:45:28 +00:00
|
|
|
|
placeholder="John Doe"
|
|
|
|
|
defaultValue={props.booking ? props.booking.attendees[0].name : ""}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mb-4">
|
|
|
|
|
<label
|
|
|
|
|
htmlFor="email"
|
2021-10-12 08:29:12 +00:00
|
|
|
|
className="block text-sm font-medium text-gray-700 dark:text-white">
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{t("email_address")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</label>
|
|
|
|
|
<div className="mt-1">
|
|
|
|
|
<input
|
|
|
|
|
type="email"
|
|
|
|
|
name="email"
|
|
|
|
|
id="email"
|
2021-09-29 21:33:18 +00:00
|
|
|
|
inputMode="email"
|
2021-09-14 08:45:28 +00:00
|
|
|
|
required
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block w-full border-gray-300 rounded-md shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black sm:text-sm"
|
2021-09-14 08:45:28 +00:00
|
|
|
|
placeholder="you@example.com"
|
|
|
|
|
defaultValue={props.booking ? props.booking.attendees[0].email : ""}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
{locations.length > 1 && (
|
|
|
|
|
<div className="mb-4">
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<span className="block text-sm font-medium text-gray-700 dark:text-white">
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{t("location")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</span>
|
|
|
|
|
{locations.map((location) => (
|
|
|
|
|
<label key={location.type} className="block">
|
|
|
|
|
<input
|
|
|
|
|
type="radio"
|
|
|
|
|
required
|
|
|
|
|
onChange={(e) => setSelectedLocation(e.target.value)}
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="w-4 h-4 mr-2 text-black border-gray-300 location focus:ring-black"
|
2021-09-14 08:45:28 +00:00
|
|
|
|
name="location"
|
|
|
|
|
value={location.type}
|
|
|
|
|
checked={selectedLocation === location.type}
|
|
|
|
|
/>
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<span className="ml-2 text-sm dark:text-gray-500">
|
2021-09-14 08:45:28 +00:00
|
|
|
|
{locationLabels[location.type]}
|
|
|
|
|
</span>
|
|
|
|
|
</label>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{selectedLocation === LocationType.Phone && (
|
|
|
|
|
<div className="mb-4">
|
|
|
|
|
<label
|
|
|
|
|
htmlFor="phone"
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block text-sm font-medium text-gray-700 dark:text-white">
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{t("phone_number")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</label>
|
|
|
|
|
<div className="mt-1">
|
|
|
|
|
<PhoneInput
|
|
|
|
|
name="phone"
|
2021-10-08 11:43:48 +00:00
|
|
|
|
placeholder={t("enter_phone_number")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
id="phone"
|
|
|
|
|
required
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block w-full border-gray-300 rounded-md shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black sm:text-sm"
|
2021-09-14 08:45:28 +00:00
|
|
|
|
onChange={() => {
|
|
|
|
|
/* DO NOT REMOVE: Callback required by PhoneInput, comment added to satisfy eslint:no-empty-function */
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
{props.eventType.customInputs &&
|
|
|
|
|
props.eventType.customInputs
|
|
|
|
|
.sort((a, b) => a.id - b.id)
|
|
|
|
|
.map((input) => (
|
|
|
|
|
<div className="mb-4" key={"input-" + input.label.toLowerCase}>
|
|
|
|
|
{input.type !== EventTypeCustomInputType.BOOL && (
|
|
|
|
|
<label
|
|
|
|
|
htmlFor={"custom_" + input.id}
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block mb-1 text-sm font-medium text-gray-700 dark:text-white">
|
2021-09-14 08:45:28 +00:00
|
|
|
|
{input.label}
|
|
|
|
|
</label>
|
|
|
|
|
)}
|
|
|
|
|
{input.type === EventTypeCustomInputType.TEXTLONG && (
|
|
|
|
|
<textarea
|
|
|
|
|
name={"custom_" + input.id}
|
|
|
|
|
id={"custom_" + input.id}
|
|
|
|
|
required={input.required}
|
|
|
|
|
rows={3}
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block w-full border-gray-300 rounded-md shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black sm:text-sm"
|
2021-09-14 08:45:28 +00:00
|
|
|
|
placeholder={input.placeholder}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
{input.type === EventTypeCustomInputType.TEXT && (
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
name={"custom_" + input.id}
|
|
|
|
|
id={"custom_" + input.id}
|
|
|
|
|
required={input.required}
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block w-full border-gray-300 rounded-md shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black sm:text-sm"
|
2021-09-14 08:45:28 +00:00
|
|
|
|
placeholder={input.placeholder}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
{input.type === EventTypeCustomInputType.NUMBER && (
|
|
|
|
|
<input
|
|
|
|
|
type="number"
|
|
|
|
|
name={"custom_" + input.id}
|
|
|
|
|
id={"custom_" + input.id}
|
|
|
|
|
required={input.required}
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block w-full border-gray-300 rounded-md shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black sm:text-sm"
|
2021-09-14 08:45:28 +00:00
|
|
|
|
placeholder=""
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
{input.type === EventTypeCustomInputType.BOOL && (
|
|
|
|
|
<div className="flex items-center h-5">
|
|
|
|
|
<input
|
|
|
|
|
type="checkbox"
|
|
|
|
|
name={"custom_" + input.id}
|
|
|
|
|
id={"custom_" + input.id}
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="w-4 h-4 mr-2 text-black border-gray-300 rounded focus:ring-black"
|
2021-09-14 08:45:28 +00:00
|
|
|
|
placeholder=""
|
2021-09-21 19:42:44 +00:00
|
|
|
|
required={input.required}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
/>
|
|
|
|
|
<label
|
|
|
|
|
htmlFor={"custom_" + input.id}
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block mb-1 text-sm font-medium text-gray-700 dark:text-white">
|
2021-09-14 08:45:28 +00:00
|
|
|
|
{input.label}
|
|
|
|
|
</label>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
2021-09-22 11:04:32 +00:00
|
|
|
|
{!props.eventType.disableGuests && (
|
|
|
|
|
<div className="mb-4">
|
|
|
|
|
{!guestToggle && (
|
2021-09-14 08:45:28 +00:00
|
|
|
|
<label
|
2021-09-22 11:04:32 +00:00
|
|
|
|
onClick={toggleGuestEmailInput}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
htmlFor="guests"
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block mb-1 text-sm font-medium text-blue-500 dark:text-white hover:cursor-pointer">
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{t("additional_guests")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</label>
|
2021-09-22 11:04:32 +00:00
|
|
|
|
)}
|
|
|
|
|
{guestToggle && (
|
|
|
|
|
<div>
|
|
|
|
|
<label
|
|
|
|
|
htmlFor="guests"
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block mb-1 text-sm font-medium text-gray-700 dark:text-white">
|
2021-09-22 11:04:32 +00:00
|
|
|
|
Guests
|
|
|
|
|
</label>
|
|
|
|
|
<ReactMultiEmail
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="relative"
|
2021-09-22 11:04:32 +00:00
|
|
|
|
placeholder="guest@example.com"
|
|
|
|
|
emails={guestEmails}
|
|
|
|
|
onChange={(_emails: string[]) => {
|
|
|
|
|
setGuestEmails(_emails);
|
|
|
|
|
}}
|
|
|
|
|
getLabel={(
|
|
|
|
|
email: string,
|
|
|
|
|
index: number,
|
|
|
|
|
removeEmail: (index: number) => void
|
|
|
|
|
) => {
|
|
|
|
|
return (
|
|
|
|
|
<div data-tag key={index}>
|
|
|
|
|
{email}
|
|
|
|
|
<span data-tag-handle onClick={() => removeEmail(index)}>
|
|
|
|
|
×
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
<div className="mb-4">
|
|
|
|
|
<label
|
|
|
|
|
htmlFor="notes"
|
2021-09-27 17:59:50 +00:00
|
|
|
|
className="block mb-1 text-sm font-medium text-gray-700 dark:text-white">
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{t("additional_notes")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</label>
|
|
|
|
|
<textarea
|
|
|
|
|
name="notes"
|
|
|
|
|
id="notes"
|
|
|
|
|
rows={3}
|
2021-10-12 08:29:12 +00:00
|
|
|
|
className="block w-full border-gray-300 rounded-md shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-black sm:text-sm"
|
2021-10-08 11:43:48 +00:00
|
|
|
|
placeholder={t("share_additional_notes")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
defaultValue={props.booking ? props.booking.description : ""}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="flex items-start space-x-2">
|
|
|
|
|
{/* TODO: add styling props to <Button variant="" color="" /> and get rid of btn-primary */}
|
|
|
|
|
<Button type="submit" loading={loading}>
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{rescheduleUid ? t("reschedule") : t("confirm")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</Button>
|
|
|
|
|
<Button color="secondary" type="button" onClick={() => router.back()}>
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{t("cancel")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
{error && (
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<div className="p-4 mt-2 border-l-4 border-yellow-400 bg-yellow-50">
|
2021-09-14 08:45:28 +00:00
|
|
|
|
<div className="flex">
|
|
|
|
|
<div className="flex-shrink-0">
|
2021-09-27 17:59:50 +00:00
|
|
|
|
<ExclamationIcon className="w-5 h-5 text-yellow-400" aria-hidden="true" />
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</div>
|
|
|
|
|
<div className="ml-3">
|
|
|
|
|
<p className="text-sm text-yellow-700">
|
2021-10-08 11:43:48 +00:00
|
|
|
|
{rescheduleUid ? t("reschedule_fail") : t("booking_fail")}
|
2021-09-14 08:45:28 +00:00
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2021-09-24 22:11:30 +00:00
|
|
|
|
)}
|
|
|
|
|
</main>
|
|
|
|
|
</div>
|
2021-09-14 08:45:28 +00:00
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default BookingPage;
|