Link/In person location (#2104)

This commit is contained in:
sean-brydon 2022-03-13 15:56:56 +00:00 committed by GitHub
parent 3e3e802b28
commit f0b1767b3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 66 additions and 8 deletions

View File

@ -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<typeof getServerSideProps>) => {
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<typeof getServerSideProps>) => {
</div>
</div>
);
case LocationType.Link:
return (
<div>
<label htmlFor="address" className="block text-sm font-medium text-gray-700">
{t("set_link_meeting")}
</label>
<div className="mt-1">
<input
type="text"
{...locationFormMethods.register("locationLink")}
id="address"
required
className="focus:border-primary-500 focus:ring-primary-500 block w-full rounded-sm border-gray-300 shadow-sm sm:text-sm"
defaultValue={
formMethods.getValues("locations").find((location) => location.type === LocationType.Link)
?.link
}
/>
{locationFormMethods.formState.errors.locationLink && (
<p className="mt-1 text-red-500">
{locationFormMethods.formState.errors.locationLink.message}
</p>
)}
</div>
</div>
);
case LocationType.Phone:
return <p className="text-sm">{t("cal_invitee_phone_number_scheduling")}</p>;
case LocationType.GoogleMeet:
@ -351,7 +380,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
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<typeof getServerSideProps>) => {
},
});
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 (
<div className="w-full">
@ -422,6 +459,16 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
/>
</div>
)}
{location.type === LocationType.Link && (
<div className="flex flex-grow items-center">
<GlobeAltIcon className="h-6 w-6" />
<input
disabled
className="w-full border-0 bg-transparent text-sm ltr:ml-2 rtl:mr-2"
value={location.link}
/>
</div>
)}
{location.type === LocationType.Phone && (
<div className="flex flex-grow items-center">
<PhoneIcon className="h-6 w-6" />
@ -690,10 +737,12 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
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<typeof getServerSideProps>) => {
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<typeof getServerSideProps>) => {
formMethods.getValues("locations").concat({ type: values.locationType, ...details })
);
}
setShowLocationModal(false);
}}>
<Controller

View File

@ -405,7 +405,8 @@
"share_additional_notes": "Please share anything that will help prepare for our meeting.",
"booking_confirmation": "Confirm your {{eventTypeTitle}} with {{profileName}}",
"booking_reschedule_confirmation": "Reschedule your {{eventTypeTitle}} with {{profileName}}",
"in_person_meeting": "Link or In-person meeting",
"in_person_meeting": "In-person meeting",
"link_meeting":"Link meeting",
"phone_call": "Phone call",
"phone_number": "Phone Number",
"enter_phone_number": "Enter phone number",
@ -574,6 +575,7 @@
"calendar_days": "calendar days",
"business_days": "business days",
"set_address_place": "Set an address or place",
"set_link_meeting": "Set a link to the meeting",
"cal_invitee_phone_number_scheduling": "Cal will ask your invitee to enter a phone number before scheduling.",
"cal_provide_google_meet_location": "Cal will provide a Google Meet location.",
"cal_provide_zoom_meeting_url": "Cal will provide a Zoom meeting URL.",

View File

@ -1,6 +1,7 @@
export enum LocationType {
InPerson = "inPerson",
Phone = "phone",
Link = "link",
GoogleMeet = "integrations:google:meet",
Zoom = "integrations:zoom",
Daily = "integrations:daily",

View File

@ -4,7 +4,11 @@ import { LocationType } from "@calcom/lib/location";
import { slugify } from "@calcom/lib/slugify";
export const eventTypeLocations = z.array(
z.object({ type: z.nativeEnum(LocationType), address: z.string().optional() })
z.object({
type: z.nativeEnum(LocationType),
address: z.string().optional(),
link: z.string().url().optional(),
})
);
export const eventTypeSlug = z.string().transform((val) => slugify(val.trim()));