import { zodResolver } from "@hookform/resolvers/zod"; import { isValidPhoneNumber } from "libphonenumber-js"; import { useEffect } from "react"; import { Controller, useForm, useWatch } from "react-hook-form"; import { z } from "zod"; import { LocationOptionsToString } from "@calcom/app-store/locations"; import { LocationType } from "@calcom/core/location"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { inferQueryOutput, trpc } from "@calcom/trpc/react"; import { Button } from "@calcom/ui"; import { Dialog, DialogContent } from "@calcom/ui/Dialog"; import { Icon } from "@calcom/ui/Icon"; import PhoneInput from "@calcom/ui/form/PhoneInputLazy"; import { Form } from "@calcom/ui/form/fields"; import { QueryCell } from "@lib/QueryCell"; import { linkValueToString } from "@lib/linkValueToString"; import CheckboxField from "@components/ui/form/CheckboxField"; import Select from "@components/ui/form/Select"; type BookingItem = inferQueryOutput<"viewer.bookings">["bookings"][number]; type OptionTypeBase = { label: string; value: LocationType; disabled?: boolean; }; type LocationFormValues = { locationType: LocationType; locationAddress?: string; locationLink?: string; locationPhoneNumber?: string; displayLocationPublicly?: boolean; }; interface ISetLocationDialog { saveLocation: (newLocationType: LocationType, details: { [key: string]: string }) => void; selection?: OptionTypeBase; booking?: BookingItem; defaultValues?: { type: LocationType; address?: string | undefined; link?: string | undefined; hostPhoneNumber?: string | undefined; displayLocationPublicly?: boolean | undefined; }[]; setShowLocationModal: React.Dispatch>; isOpenDialog: boolean; setSelectedLocation?: (param: OptionTypeBase | undefined) => void; } export const EditLocationDialog = (props: ISetLocationDialog) => { const { saveLocation, selection, booking, setShowLocationModal, isOpenDialog, defaultValues, setSelectedLocation, } = props; const { t } = useLocale(); const locationsQuery = trpc.useQuery(["viewer.locationOptions"]); useEffect(() => { if (selection) { locationFormMethods.setValue("locationType", selection?.value); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [selection]); const locationFormSchema = z.object({ locationType: z.string(), locationAddress: z.string().optional(), locationLink: selection?.value === LocationType.Whereby ? z .string() .regex(/^http(s)?:\/\/(www\.)?whereby.com\/[a-zA-Z0-9]*/) .optional() : selection?.value === LocationType.Around ? z .string() .regex(/^http(s)?:\/\/(www\.)?around.co\/[a-zA-Z0-9]*/) .optional() : selection?.value === LocationType.Ping ? z .string() .regex(/^http(s)?:\/\/(www\.)?ping.gg\/call\/[a-zA-Z0-9]*/) .optional() : selection?.value === LocationType.Riverside ? z .string() .regex(/^http(s)?:\/\/(www\.)?riverside.fm\/studio\/[a-zA-Z0-9]*/) .optional() : z.string().url().optional(), displayLocationPublicly: z.boolean().optional(), locationPhoneNumber: z .string() .refine((val) => isValidPhoneNumber(val)) .optional(), }); const locationFormMethods = useForm({ mode: "onSubmit", resolver: zodResolver(locationFormSchema), }); const selectedLocation = useWatch({ control: locationFormMethods.control, name: "locationType", }); const LocationOptions = selectedLocation === LocationType.InPerson ? ( <>
location.type === LocationType.InPerson )?.address : undefined } />
{!booking && (
( location.type === LocationType.InPerson) ?.displayLocationPublicly : undefined } description={t("display_location_label")} onChange={(e) => locationFormMethods.setValue("displayLocationPublicly", e.target.checked) } informationIconText={t("display_location_info_badge")} /> )} />
)}
) : selectedLocation === LocationType.Link ? (
location.type === LocationType.Link )?.link : undefined } /> {locationFormMethods.formState.errors.locationLink && (

{t("url_start_with_https")}

)}
{!booking && (
( location.type === LocationType.Link) ?.displayLocationPublicly : undefined } onChange={(e) => locationFormMethods.setValue("displayLocationPublicly", e.target.checked)} informationIconText={t("display_location_info_badge")} /> )} />
)}
) : selectedLocation === LocationType.UserPhone ? (
control={locationFormMethods.control} name="locationPhoneNumber" required id="locationPhoneNumber" placeholder={t("host_phone_number")} defaultValue={ defaultValues ? defaultValues.find( (location: { type: LocationType }) => location.type === LocationType.UserPhone )?.hostPhoneNumber : undefined } /> {locationFormMethods.formState.errors.locationPhoneNumber && (

{t("invalid_number")}

)}
) : selectedLocation === LocationType.Whereby ? ( <>
location.type === LocationType.Whereby )?.address : undefined } /> {locationFormMethods.formState.errors.locationLink && (

{t("invalid_whereby_link")}

)}
{!booking && (
( location.type === LocationType.Whereby) ?.displayLocationPublicly : undefined } description={t("display_location_label")} onChange={(e) => locationFormMethods.setValue("displayLocationPublicly", e.target.checked) } informationIconText={t("display_location_info_badge")} /> )} />
)}
) : selectedLocation === LocationType.Around ? ( <>
location.type === LocationType.Around )?.address : undefined } /> {locationFormMethods.formState.errors.locationLink && (

{t("invalid_around_link")}

)}
{!booking && (
( location.type === LocationType.Around) ?.displayLocationPublicly : undefined } description={t("display_location_label")} onChange={(e) => locationFormMethods.setValue("displayLocationPublicly", e.target.checked) } informationIconText={t("display_location_info_badge")} /> )} />
)}
) : selectedLocation === LocationType.Ping ? ( <>
location.type === LocationType.Ping )?.address : undefined } /> {locationFormMethods.formState.errors.locationLink && (

{t("invalid_ping_link")}

)}
{!booking && (
( location.type === LocationType.Ping) ?.displayLocationPublicly : undefined } description={t("display_location_label")} onChange={(e) => locationFormMethods.setValue("displayLocationPublicly", e.target.checked) } informationIconText={t("display_location_info_badge")} /> )} />
)}
) : selectedLocation === LocationType.Riverside ? ( <>
location.type === LocationType.Riverside )?.address : undefined } /> {locationFormMethods.formState.errors.locationLink && (

{t("invalid_riverside_link")}

)}
{!booking && (
( location.type === LocationType.Riverside) ?.displayLocationPublicly : undefined } description={t("display_location_label")} onChange={(e) => locationFormMethods.setValue("displayLocationPublicly", e.target.checked) } informationIconText={t("display_location_info_badge")} /> )} />
)}
) : (

{LocationOptionsToString(selectedLocation, t)}

); return (
{!booking && (

{t("this_input_will_shown_booking_this_event")}

)}
{booking && ( <>

{t("current_location")}:

{linkValueToString(booking.location, t)}

)}
{ const { locationType: newLocation, displayLocationPublicly } = values; let details = {}; if (newLocation === LocationType.InPerson) { details = { address: values.locationAddress, displayLocationPublicly, }; } if ( newLocation === LocationType.Link || newLocation === LocationType.Whereby || newLocation === LocationType.Around || newLocation === LocationType.Riverside || newLocation === LocationType.Ping ) { details = { link: values.locationLink, displayLocationPublicly }; } if (newLocation === LocationType.UserPhone) { details = { hostPhoneNumber: values.locationPhoneNumber }; } saveLocation(newLocation, details); setShowLocationModal(false); setSelectedLocation?.(undefined); locationFormMethods.unregister([ "locationType", "locationLink", "locationAddress", "locationPhoneNumber", ]); }}> { if (!locationOptions.length) return null; return ( (