Link/In person location (#2104)
This commit is contained in:
parent
3e3e802b28
commit
f0b1767b3c
4 changed files with 66 additions and 8 deletions
|
@ -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
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export enum LocationType {
|
||||
InPerson = "inPerson",
|
||||
Phone = "phone",
|
||||
Link = "link",
|
||||
GoogleMeet = "integrations:google:meet",
|
||||
Zoom = "integrations:zoom",
|
||||
Daily = "integrations:daily",
|
||||
|
|
|
@ -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()));
|
||||
|
|
Loading…
Reference in a new issue