Feat disable guests for events (#719)
* Abstracts CheckboxField * Allows disabling the guests field while booking Co-authored-by: Bailey Pumfleet <pumfleet@hey.com>
This commit is contained in:
parent
1c2998fc13
commit
e1f1386332
8 changed files with 104 additions and 64 deletions
|
@ -329,42 +329,48 @@ const BookingPage = (props: any): JSX.Element => {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<div className="mb-4">
|
{!props.eventType.disableGuests && (
|
||||||
{!guestToggle && (
|
<div className="mb-4">
|
||||||
<label
|
{!guestToggle && (
|
||||||
onClick={toggleGuestEmailInput}
|
|
||||||
htmlFor="guests"
|
|
||||||
className="block text-sm font-medium dark:text-white text-blue-500 mb-1 hover:cursor-pointer">
|
|
||||||
+ Additional Guests
|
|
||||||
</label>
|
|
||||||
)}
|
|
||||||
{guestToggle && (
|
|
||||||
<div>
|
|
||||||
<label
|
<label
|
||||||
|
onClick={toggleGuestEmailInput}
|
||||||
htmlFor="guests"
|
htmlFor="guests"
|
||||||
className="block text-sm font-medium dark:text-white text-gray-700 mb-1">
|
className="block text-sm font-medium dark:text-white text-blue-500 mb-1 hover:cursor-pointer">
|
||||||
Guests
|
+ Additional Guests
|
||||||
</label>
|
</label>
|
||||||
<ReactMultiEmail
|
)}
|
||||||
placeholder="guest@example.com"
|
{guestToggle && (
|
||||||
emails={guestEmails}
|
<div>
|
||||||
onChange={(_emails: string[]) => {
|
<label
|
||||||
setGuestEmails(_emails);
|
htmlFor="guests"
|
||||||
}}
|
className="block text-sm font-medium dark:text-white text-gray-700 mb-1">
|
||||||
getLabel={(email: string, index: number, removeEmail: (index: number) => void) => {
|
Guests
|
||||||
return (
|
</label>
|
||||||
<div data-tag key={index}>
|
<ReactMultiEmail
|
||||||
{email}
|
placeholder="guest@example.com"
|
||||||
<span data-tag-handle onClick={() => removeEmail(index)}>
|
emails={guestEmails}
|
||||||
×
|
onChange={(_emails: string[]) => {
|
||||||
</span>
|
setGuestEmails(_emails);
|
||||||
</div>
|
}}
|
||||||
);
|
getLabel={(
|
||||||
}}
|
email: string,
|
||||||
/>
|
index: number,
|
||||||
</div>
|
removeEmail: (index: number) => void
|
||||||
)}
|
) => {
|
||||||
</div>
|
return (
|
||||||
|
<div data-tag key={index}>
|
||||||
|
{email}
|
||||||
|
<span data-tag-handle onClick={() => removeEmail(index)}>
|
||||||
|
×
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<label
|
<label
|
||||||
htmlFor="notes"
|
htmlFor="notes"
|
||||||
|
|
37
components/ui/form/CheckboxField.tsx
Normal file
37
components/ui/form/CheckboxField.tsx
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import React, { forwardRef, InputHTMLAttributes } from "react";
|
||||||
|
|
||||||
|
type Props = InputHTMLAttributes<HTMLInputElement> & {
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CheckboxField = forwardRef<HTMLInputElement, Props>(({ label, description, ...rest }, ref) => {
|
||||||
|
return (
|
||||||
|
<div className="items-center block sm:flex">
|
||||||
|
<div className="mb-4 min-w-44 sm:mb-0">
|
||||||
|
<label htmlFor={rest.id} className="flex text-sm font-medium text-neutral-700">
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="w-full">
|
||||||
|
<div className="relative flex items-start">
|
||||||
|
<div className="flex items-center h-5">
|
||||||
|
<input
|
||||||
|
{...rest}
|
||||||
|
ref={ref}
|
||||||
|
type="checkbox"
|
||||||
|
className="w-4 h-4 border-gray-300 rounded focus:ring-primary-500 text-primary-600"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="ml-3 text-sm">
|
||||||
|
<p className="text-neutral-900">{description}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
CheckboxField.displayName = "CheckboxField";
|
||||||
|
|
||||||
|
export default CheckboxField;
|
|
@ -43,6 +43,7 @@ export async function getServerSideProps(context) {
|
||||||
periodStartDate: true,
|
periodStartDate: true,
|
||||||
periodEndDate: true,
|
periodEndDate: true,
|
||||||
periodCountCalendarDays: true,
|
periodCountCalendarDays: true,
|
||||||
|
disableGuests: true,
|
||||||
users: {
|
users: {
|
||||||
select: {
|
select: {
|
||||||
username: true,
|
username: true,
|
||||||
|
|
|
@ -47,6 +47,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
length: parseInt(req.body.length),
|
length: parseInt(req.body.length),
|
||||||
hidden: req.body.hidden,
|
hidden: req.body.hidden,
|
||||||
requiresConfirmation: req.body.requiresConfirmation,
|
requiresConfirmation: req.body.requiresConfirmation,
|
||||||
|
disableGuests: req.body.disableGuests,
|
||||||
locations: req.body.locations,
|
locations: req.body.locations,
|
||||||
eventName: req.body.eventName,
|
eventName: req.body.eventName,
|
||||||
customInputs: !req.body.customInputs
|
customInputs: !req.body.customInputs
|
||||||
|
|
|
@ -49,6 +49,7 @@ import classNames from "@lib/classNames";
|
||||||
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
import { inferSSRProps } from "@lib/types/inferSSRProps";
|
||||||
import { asStringOrThrow } from "@lib/asStringOrNull";
|
import { asStringOrThrow } from "@lib/asStringOrNull";
|
||||||
import Button from "@components/ui/Button";
|
import Button from "@components/ui/Button";
|
||||||
|
import CheckboxField from "@components/ui/form/CheckboxField";
|
||||||
|
|
||||||
dayjs.extend(utc);
|
dayjs.extend(utc);
|
||||||
dayjs.extend(timezone);
|
dayjs.extend(timezone);
|
||||||
|
@ -194,7 +195,6 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||||
|
|
||||||
const advancedOptionsPayload: AdvancedOptions = {};
|
const advancedOptionsPayload: AdvancedOptions = {};
|
||||||
if (requiresConfirmationRef.current) {
|
if (requiresConfirmationRef.current) {
|
||||||
advancedOptionsPayload.requiresConfirmation = requiresConfirmationRef.current.checked;
|
|
||||||
advancedOptionsPayload.eventName = eventNameRef.current.value;
|
advancedOptionsPayload.eventName = eventNameRef.current.value;
|
||||||
advancedOptionsPayload.periodType = periodType.type;
|
advancedOptionsPayload.periodType = periodType.type;
|
||||||
advancedOptionsPayload.periodDays = parseInt(periodDaysRef?.current?.value);
|
advancedOptionsPayload.periodDays = parseInt(periodDaysRef?.current?.value);
|
||||||
|
@ -208,7 +208,9 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||||
title: enteredTitle,
|
title: enteredTitle,
|
||||||
slug: enteredSlug,
|
slug: enteredSlug,
|
||||||
description: formData.description as string,
|
description: formData.description as string,
|
||||||
length: formData.length as number,
|
length: formData.length as unknown as number,
|
||||||
|
requiresConfirmation: formData.requiresConfirmation === "on",
|
||||||
|
disableGuests: formData.disableGuests === "on",
|
||||||
hidden,
|
hidden,
|
||||||
locations,
|
locations,
|
||||||
customInputs,
|
customInputs,
|
||||||
|
@ -720,35 +722,23 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="items-center block sm:flex">
|
|
||||||
<div className="mb-4 min-w-44 sm:mb-0">
|
<CheckboxField
|
||||||
<label
|
ref={requiresConfirmationRef}
|
||||||
htmlFor="requiresConfirmation"
|
id="requiresConfirmation"
|
||||||
className="flex text-sm font-medium text-neutral-700">
|
name="requiresConfirmation"
|
||||||
Opt-in booking
|
label="Opt-in booking"
|
||||||
</label>
|
description="The booking needs to be manually confirmed before it is pushed to the integrations and a confirmation mail is sent."
|
||||||
</div>
|
defaultChecked={eventType.requiresConfirmation}
|
||||||
<div className="w-full">
|
/>
|
||||||
<div className="relative flex items-start">
|
|
||||||
<div className="flex items-center h-5">
|
<CheckboxField
|
||||||
<input
|
id="disableGuests"
|
||||||
ref={requiresConfirmationRef}
|
name="disableGuests"
|
||||||
id="requiresConfirmation"
|
label="Disable guests"
|
||||||
name="requiresConfirmation"
|
description="Disable adding aditional guests while booking."
|
||||||
type="checkbox"
|
defaultChecked={eventType.disableGuests}
|
||||||
className="w-4 h-4 border-gray-300 rounded focus:ring-primary-500 text-primary-600"
|
/>
|
||||||
defaultChecked={eventType.requiresConfirmation}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="ml-3 text-sm">
|
|
||||||
<p className="text-neutral-900">
|
|
||||||
The booking needs to be manually confirmed before it is pushed to the
|
|
||||||
integrations and a confirmation mail is sent.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr className="border-neutral-200" />
|
<hr className="border-neutral-200" />
|
||||||
|
|
||||||
|
@ -1153,6 +1143,7 @@ export const getServerSideProps = async (context: GetServerSidePropsContext) =>
|
||||||
periodEndDate: true,
|
periodEndDate: true,
|
||||||
periodCountCalendarDays: true,
|
periodCountCalendarDays: true,
|
||||||
requiresConfirmation: true,
|
requiresConfirmation: true,
|
||||||
|
disableGuests: true,
|
||||||
team: {
|
team: {
|
||||||
select: {
|
select: {
|
||||||
slug: true,
|
slug: true,
|
||||||
|
|
|
@ -33,6 +33,7 @@ export async function getServerSideProps(context) {
|
||||||
periodStartDate: true,
|
periodStartDate: true,
|
||||||
periodEndDate: true,
|
periodEndDate: true,
|
||||||
periodCountCalendarDays: true,
|
periodCountCalendarDays: true,
|
||||||
|
disableGuests: true,
|
||||||
team: {
|
team: {
|
||||||
select: {
|
select: {
|
||||||
slug: true,
|
slug: true,
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "EventType" ADD COLUMN "disableGuests" BOOLEAN NOT NULL DEFAULT false;
|
|
@ -38,6 +38,7 @@ model EventType {
|
||||||
periodDays Int?
|
periodDays Int?
|
||||||
periodCountCalendarDays Boolean?
|
periodCountCalendarDays Boolean?
|
||||||
requiresConfirmation Boolean @default(false)
|
requiresConfirmation Boolean @default(false)
|
||||||
|
disableGuests Boolean @default(false)
|
||||||
minimumBookingNotice Int @default(120)
|
minimumBookingNotice Int @default(120)
|
||||||
schedulingType SchedulingType?
|
schedulingType SchedulingType?
|
||||||
Schedule Schedule[]
|
Schedule Schedule[]
|
||||||
|
|
Loading…
Reference in a new issue