From f0b1767b3c3743baa8e295d68442a4a9e334d02d Mon Sep 17 00:00:00 2001 From: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Date: Sun, 13 Mar 2022 15:56:56 +0000 Subject: [PATCH] Link/In person location (#2104) --- apps/web/pages/event-types/[type].tsx | 63 +++++++++++++++++-- apps/web/public/static/locales/en/common.json | 4 +- packages/lib/location.ts | 1 + packages/prisma/zod-utils.ts | 6 +- 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/apps/web/pages/event-types/[type].tsx b/apps/web/pages/event-types/[type].tsx index 6b466b9b..fbbd1b80 100644 --- a/apps/web/pages/event-types/[type].tsx +++ b/apps/web/pages/event-types/[type].tsx @@ -1,4 +1,4 @@ -import { PhoneIcon, XIcon } from "@heroicons/react/outline"; +import { GlobeAltIcon, PhoneIcon, XIcon } from "@heroicons/react/outline"; import { ChevronRightIcon, ClockIcon, @@ -12,6 +12,7 @@ import { UserAddIcon, UsersIcon, } from "@heroicons/react/solid"; +import { zodResolver } from "@hookform/resolvers/zod"; import { MembershipRole } from "@prisma/client"; import { Availability, EventTypeCustomInput, PeriodType, Prisma, SchedulingType } from "@prisma/client"; import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible"; @@ -26,6 +27,7 @@ import { Controller, useForm } from "react-hook-form"; import { FormattedNumber, IntlProvider } from "react-intl"; import Select from "react-select"; import { JSONObject } from "superjson/dist/types"; +import { z } from "zod"; import { StripeData } from "@calcom/stripe/server"; import Switch from "@calcom/ui/Switch"; @@ -119,6 +121,7 @@ const EventTypePage = (props: inferSSRProps) => { const defaultLocations = [ { value: LocationType.InPerson, label: t("in_person_meeting") }, + { value: LocationType.Link, label: t("link_meeting") }, { value: LocationType.Jitsi, label: "Jitsi Meet" }, { value: LocationType.Phone, label: t("phone_call") }, ]; @@ -273,6 +276,32 @@ const EventTypePage = (props: inferSSRProps) => { ); + case LocationType.Link: + return ( +
+ +
+ location.type === LocationType.Link) + ?.link + } + /> + {locationFormMethods.formState.errors.locationLink && ( +

+ {locationFormMethods.formState.errors.locationLink.message} +

+ )} +
+
+ ); case LocationType.Phone: return

{t("cal_invitee_phone_number_scheduling")}

; case LocationType.GoogleMeet: @@ -351,7 +380,7 @@ const EventTypePage = (props: inferSSRProps) => { schedulingType: SchedulingType | null; price: number; hidden: boolean; - locations: { type: LocationType; address?: string }[]; + locations: { type: LocationType; address?: string; link?: string }[]; customInputs: EventTypeCustomInput[]; users: string[]; availability: { @@ -381,11 +410,19 @@ const EventTypePage = (props: inferSSRProps) => { }, }); + const locationFormSchema = z.object({ + locationType: z.string(), + locationAddress: z.string().optional(), + locationLink: z.string().url().optional(), // URL validates as new URL() - which requires HTTPS:// In the input field + }); + const locationFormMethods = useForm<{ locationType: LocationType; - locationAddress: string; - }>(); - + locationAddress?: string; // TODO: We should validate address or fetch the address from googles api to see if its valid? + locationLink?: string; // Currently this only accepts links that are HTTPS:// + }>({ + resolver: zodResolver(locationFormSchema), + }); const Locations = () => { return (
@@ -422,6 +459,16 @@ const EventTypePage = (props: inferSSRProps) => { />
)} + {location.type === LocationType.Link && ( +
+ + +
+ )} {location.type === LocationType.Phone && (
@@ -690,10 +737,12 @@ const EventTypePage = (props: inferSSRProps) => { smartContractAddress, beforeBufferTime, afterBufferTime, + locations, ...input } = values; updateMutation.mutate({ ...input, + locations, availability: availabilityState, periodStartDate: periodDates.startDate, periodEndDate: periodDates.endDate, @@ -1525,6 +1574,9 @@ const EventTypePage = (props: inferSSRProps) => { details = { address: values.locationAddress }; } + if (newLocation === LocationType.Link) { + details = { link: values.locationLink }; + } const existingIdx = formMethods .getValues("locations") .findIndex((loc) => values.locationType === loc.type); @@ -1541,7 +1593,6 @@ const EventTypePage = (props: inferSSRProps) => { formMethods.getValues("locations").concat({ type: values.locationType, ...details }) ); } - setShowLocationModal(false); }}> slugify(val.trim()));