Fix URL by removing slash and backslash (#1733)

* Fix URl by removing slash and backslash

* Implement slugify

* Add data type

* Fixing folder structure

* Solve zod-utils conflict
pull/1931/head
Juan Esteban Nieto Cifuentes 2022-02-21 11:53:16 -05:00 committed by GitHub
parent 95b3397e42
commit 7585e9b32e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 90 additions and 84 deletions

View File

@ -12,6 +12,7 @@ import { HttpError } from "@lib/core/http/error";
import { useLocale } from "@lib/hooks/useLocale";
import { useToggleQuery } from "@lib/hooks/useToggleQuery";
import showToast from "@lib/notification";
import { slugify } from "@lib/slugify";
import { trpc } from "@lib/trpc";
import { Dialog, DialogClose, DialogContent } from "@components/Dialog";
@ -67,7 +68,7 @@ export default function CreateEventTypeButton(props: Props) {
useEffect(() => {
const subscription = watch((value, { name, type }) => {
if (name === "title" && type === "change") {
if (value.title) setValue("slug", value.title.replace(/\s+/g, "-").toLowerCase());
if (value.title) setValue("slug", slugify(value.title));
else setValue("slug", "");
}
});

View File

@ -38,6 +38,7 @@ import showToast from "@lib/notification";
import prisma from "@lib/prisma";
import { trpc } from "@lib/trpc";
import { inferSSRProps } from "@lib/types/inferSSRProps";
import { slugify } from "@lib/slugify";
import DestinationCalendarSelector from "@components/DestinationCalendarSelector";
import { Dialog, DialogContent, DialogTrigger } from "@components/Dialog";
@ -253,7 +254,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
{...locationFormMethods.register("locationAddress")}
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"
className="block w-full border-gray-300 rounded-sm shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
defaultValue={
formMethods
.getValues("locations")
@ -383,7 +384,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
options={locationOptions}
isSearchable={false}
classNamePrefix="react-select"
className="react-select-container focus:border-primary-500 focus:ring-primary-500 block w-full min-w-0 flex-1 rounded-sm border border-gray-300 sm:text-sm"
className="flex-1 block w-full min-w-0 border border-gray-300 rounded-sm react-select-container focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
onChange={(e) => {
if (e?.value) {
locationFormMethods.setValue("locationType", e.value);
@ -401,25 +402,25 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
className="mb-2 rounded-sm border border-neutral-300 py-1.5 px-2 shadow-sm">
<div className="flex justify-between">
{location.type === LocationType.InPerson && (
<div className="flex flex-grow items-center">
<LocationMarkerIcon className="h-6 w-6" />
<div className="flex items-center flex-grow">
<LocationMarkerIcon className="w-6 h-6" />
<input
disabled
className="w-full border-0 bg-transparent text-sm ltr:ml-2 rtl:mr-2"
className="w-full text-sm bg-transparent border-0 ltr:ml-2 rtl:mr-2"
value={location.address}
/>
</div>
)}
{location.type === LocationType.Phone && (
<div className="flex flex-grow items-center">
<PhoneIcon className="h-6 w-6" />
<div className="flex items-center flex-grow">
<PhoneIcon className="w-6 h-6" />
<span className="text-sm ltr:ml-2 rtl:mr-2">{t("phone_call")}</span>
</div>
)}
{location.type === LocationType.GoogleMeet && (
<div className="flex flex-grow items-center">
<div className="flex items-center flex-grow">
<svg
className="h-6 w-6"
className="w-6 h-6"
viewBox="0 0 64 54"
fill="none"
xmlns="http://www.w3.org/2000/svg">
@ -448,7 +449,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
)}
{location.type === LocationType.Huddle01 && (
<div className="flex flex-grow items-center">
<div className="flex items-center flex-grow">
<svg
width="1.25em"
height="1.25em"
@ -521,9 +522,9 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
)}
{location.type === LocationType.Zoom && (
<div className="flex flex-grow items-center">
<div className="flex items-center flex-grow">
<svg
className="h-6 w-6"
className="w-6 h-6"
viewBox="0 0 64 64"
fill="none"
xmlns="http://www.w3.org/2000/svg">
@ -548,7 +549,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
)}
{location.type === LocationType.Tandem && (
<div className="flex flex-grow items-center">
<div className="flex items-center flex-grow">
<svg
width="1.25em"
height="1.25em"
@ -572,9 +573,9 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
)}
{location.type === LocationType.Jitsi && (
<div className="flex flex-grow items-center">
<div className="flex items-center flex-grow">
<svg
className="h-6 w-6"
className="w-6 h-6"
viewBox="0 0 64 64"
fill="none"
xmlns="http://www.w3.org/2000/svg">
@ -602,11 +603,11 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<button
type="button"
onClick={() => openLocationModal(location.type)}
className="mr-1 p-1 text-gray-500 hover:text-gray-900">
<PencilIcon className="h-4 w-4" />
className="p-1 mr-1 text-gray-500 hover:text-gray-900">
<PencilIcon className="w-4 h-4" />
</button>
<button type="button" onClick={() => removeLocation(location)}>
<XIcon className="border-l-1 h-6 w-6 pl-1 text-gray-500 hover:text-gray-900 " />
<XIcon className="w-6 h-6 pl-1 text-gray-500 border-l-1 hover:text-gray-900 " />
</button>
</div>
</div>
@ -617,7 +618,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<li>
<button
type="button"
className="flex rounded-sm px-3 py-2 hover:bg-gray-100"
className="flex px-3 py-2 rounded-sm hover:bg-gray-100"
onClick={() => setShowLocationModal(true)}>
<PlusIcon className="mt-0.5 h-4 w-4 text-neutral-900" />
<span className="ml-1 text-sm font-medium text-neutral-700">{t("add_location")}</span>
@ -636,7 +637,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
centered
title={t("event_type_title", { eventTypeTitle: eventType.title })}
heading={
<div className="group relative cursor-pointer" onClick={() => setEditIcon(false)}>
<div className="relative cursor-pointer group" onClick={() => setEditIcon(false)}>
{editIcon ? (
<>
<h1
@ -644,7 +645,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
className="inline pl-0 text-gray-900 focus:text-black group-hover:text-gray-500">
{eventType.title}
</h1>
<PencilIcon className="ml-1 -mt-1 inline h-4 w-4 text-gray-700 group-hover:text-gray-500" />
<PencilIcon className="inline w-4 h-4 ml-1 -mt-1 text-gray-700 group-hover:text-gray-500" />
</>
) : (
<div style={{ marginBottom: -11 }}>
@ -653,7 +654,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
autoFocus
style={{ top: -6, fontSize: 22 }}
required
className="relative h-10 w-full cursor-pointer border-none bg-transparent pl-0 text-gray-900 hover:text-gray-700 focus:text-black focus:outline-none focus:ring-0"
className="relative w-full h-10 pl-0 text-gray-900 bg-transparent border-none cursor-pointer hover:text-gray-700 focus:text-black focus:outline-none focus:ring-0"
placeholder={t("quick_chat")}
{...formMethods.register("title")}
defaultValue={eventType.title}
@ -663,9 +664,9 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
}
subtitle={eventType.description || ""}>
<div className="mx-auto block sm:flex md:max-w-5xl">
<div className="block mx-auto sm:flex md:max-w-5xl">
<div className="w-full ltr:mr-2 rtl:ml-2 sm:w-9/12">
<div className="-mx-4 rounded-sm border border-neutral-200 bg-white p-4 py-6 sm:mx-0 sm:px-8">
<div className="p-4 py-6 -mx-4 bg-white border rounded-sm border-neutral-200 sm:mx-0 sm:px-8">
<Form
form={formMethods}
handleSubmit={async (values) => {
@ -685,8 +686,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
}}
className="space-y-6">
<div className="space-y-3">
<div className="block items-center sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="items-center block sm:flex">
<div className="mb-4 min-w-48 sm:mb-0">
<label htmlFor="slug" className="flex text-sm font-medium text-neutral-700">
<LinkIcon className="mt-0.5 h-4 w-4 text-neutral-500 ltr:mr-2 rtl:ml-2" />
{t("url")}
@ -694,15 +695,18 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
<div className="w-full">
<div className="flex rounded-sm shadow-sm">
<span className="inline-flex items-center rounded-l-sm border border-r-0 border-gray-300 bg-gray-50 px-3 text-gray-500 sm:text-sm">
<span className="inline-flex items-center px-3 text-gray-500 border border-r-0 border-gray-300 rounded-l-sm bg-gray-50 sm:text-sm">
{process.env.NEXT_PUBLIC_APP_URL?.replace(/^(https?:|)\/\//, "")}/
{team ? "team/" + team.slug : eventType.users[0].username}/
</span>
<input
type="text"
required
className="focus:border-primary-500 focus:ring-primary-500 block w-full min-w-0 flex-1 rounded-none rounded-r-sm border-gray-300 sm:text-sm"
className="flex-1 block w-full min-w-0 border-gray-300 rounded-none rounded-r-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
defaultValue={eventType.slug}
onKeyUp={(event) => {
formMethods.setValue("slug", slugify(String(event.target.value)));
}}
{...formMethods.register("slug")}
/>
</div>
@ -753,7 +757,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<div className="space-y-3">
<div className="block sm:flex">
<div className="min-w-48 mb-4 mt-2.5 sm:mb-0">
<label htmlFor="description" className="mt-0 flex text-sm font-medium text-neutral-700">
<label htmlFor="description" className="flex mt-0 text-sm font-medium text-neutral-700">
<DocumentIcon className="mt-0.5 h-4 w-4 text-neutral-500 ltr:mr-2 rtl:ml-2" />
{t("description")}
</label>
@ -761,7 +765,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<div className="w-full">
<textarea
id="description"
className="focus:border-primary-500 focus:ring-primary-500 block w-full rounded-sm border-gray-300 shadow-sm sm:text-sm"
className="block w-full border-gray-300 rounded-sm shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
placeholder={t("quick_video_meeting")}
{...formMethods.register("description")}
defaultValue={asStringOrUndefined(eventType.description)}></textarea>
@ -772,11 +776,11 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
{team && (
<div className="space-y-3">
<div className="block sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="mb-4 min-w-48 sm:mb-0">
<label
htmlFor="schedulingType"
className="mt-2 flex text-sm font-medium text-neutral-700">
<UsersIcon className="h-5 w-5 text-neutral-500 ltr:mr-2 rtl:ml-2" />{" "}
className="flex mt-2 text-sm font-medium text-neutral-700">
<UsersIcon className="w-5 h-5 text-neutral-500 ltr:mr-2 rtl:ml-2" />{" "}
{t("scheduling_type")}
</label>
</div>
@ -798,9 +802,9 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
<div className="block sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="mb-4 min-w-48 sm:mb-0">
<label htmlFor="users" className="flex text-sm font-medium text-neutral-700">
<UserAddIcon className="h-5 w-5 text-neutral-500 ltr:mr-2 rtl:ml-2" />{" "}
<UserAddIcon className="w-5 h-5 text-neutral-500 ltr:mr-2 rtl:ml-2" />{" "}
{t("attendees")}
</label>
</div>
@ -849,8 +853,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
* This will fallback to each user selected destination calendar.
*/}
{!!connectedCalendarsQuery.data?.connectedCalendars.length && !team && (
<div className="block items-center sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="items-center block sm:flex">
<div className="mb-4 min-w-48 sm:mb-0">
<label
htmlFor="createEventsOn"
className="flex text-sm font-medium text-neutral-700">
@ -875,8 +879,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
</div>
)}
<div className="block items-center sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="items-center block sm:flex">
<div className="mb-4 min-w-48 sm:mb-0">
<label htmlFor="eventName" className="flex text-sm font-medium text-neutral-700">
{t("event_name")} <InfoBadge content={t("event_name_tooltip")} />
</label>
@ -885,7 +889,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<div className="relative mt-1 rounded-sm shadow-sm">
<input
type="text"
className="focus:border-primary-500 focus:ring-primary-500 block w-full rounded-sm border-gray-300 shadow-sm sm:text-sm"
className="block w-full border-gray-300 rounded-sm shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
placeholder={t("meeting_with_user")}
defaultValue={eventType.eventName || ""}
{...formMethods.register("eventName")}
@ -894,8 +898,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
</div>
{eventType.isWeb3Active && (
<div className="block items-center sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="items-center block sm:flex">
<div className="mb-4 min-w-48 sm:mb-0">
<label
htmlFor="smartContractAddress"
className="flex text-sm font-medium text-neutral-700">
@ -907,7 +911,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
{
<input
type="text"
className="focus:border-primary-500 focus:ring-primary-500 block w-full rounded-sm border-gray-300 shadow-sm sm:text-sm"
className="block w-full border-gray-300 rounded-sm shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
placeholder={t("Example: 0x71c7656ec7ab88b098defb751b7401b5f6d8976f")}
defaultValue={(eventType.metadata.smartContractAddress || "") as string}
{...formMethods.register("smartContractAddress")}
@ -917,20 +921,20 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
</div>
)}
<div className="block items-center sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="items-center block sm:flex">
<div className="mb-4 min-w-48 sm:mb-0">
<label
htmlFor="additionalFields"
className="flexflex mt-2 text-sm font-medium text-neutral-700">
className="mt-2 text-sm font-medium flexflex text-neutral-700">
{t("additional_inputs")}
</label>
</div>
<div className="w-full">
<ul className="mt-1">
{customInputs.map((customInput: EventTypeCustomInput, idx: number) => (
<li key={idx} className="bg-secondary-50 mb-2 border p-2">
<li key={idx} className="p-2 mb-2 border bg-secondary-50">
<div className="flex justify-between">
<div className="w-0 flex-1">
<div className="flex-1 w-0">
<div className="truncate">
<span
className="text-sm ltr:ml-2 rtl:mr-2"
@ -969,7 +973,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
{t("edit")}
</Button>
<button type="button" onClick={() => removeCustom(idx)}>
<XIcon className="h-6 w-6 border-l-2 pl-1 hover:text-red-500 " />
<XIcon className="w-6 h-6 pl-1 border-l-2 hover:text-red-500 " />
</button>
</div>
</div>
@ -1046,8 +1050,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
)}
/>
<div className="block items-center sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="items-center block sm:flex">
<div className="mb-4 min-w-48 sm:mb-0">
<label htmlFor="eventName" className="flex text-sm font-medium text-neutral-700">
{t("slot_interval")}
</label>
@ -1072,7 +1076,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<Select
isSearchable={false}
classNamePrefix="react-select"
className="react-select-container focus:border-primary-500 focus:ring-primary-500 block w-full min-w-0 flex-1 rounded-sm border border-gray-300 sm:text-sm"
className="flex-1 block w-full min-w-0 border border-gray-300 rounded-sm react-select-container focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
onChange={(val) => {
formMethods.setValue(
"slotInterval",
@ -1094,7 +1098,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
<div className="block sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="mb-4 min-w-48 sm:mb-0">
<label
htmlFor="inviteesCanSchedule"
className="mt-2.5 flex text-sm font-medium text-neutral-700">
@ -1113,12 +1117,12 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
formMethods.setValue("periodType", val as PeriodType)
}>
{PERIOD_TYPES.map((period) => (
<div className="mb-2 flex items-center text-sm" key={period.type}>
<div className="flex items-center mb-2 text-sm" key={period.type}>
<RadioGroup.Item
id={period.type}
value={period.type}
className="flex h-4 w-4 cursor-pointer items-center rounded-full border border-black bg-white focus:border-2 focus:outline-none ltr:mr-2 rtl:ml-2">
<RadioGroup.Indicator className="relative flex h-4 w-4 items-center justify-center after:block after:h-2 after:w-2 after:rounded-full after:bg-black" />
className="flex items-center w-4 h-4 bg-white border border-black rounded-full cursor-pointer focus:border-2 focus:outline-none ltr:mr-2 rtl:ml-2">
<RadioGroup.Indicator className="relative flex items-center justify-center w-4 h-4 after:block after:h-2 after:w-2 after:rounded-full after:bg-black" />
</RadioGroup.Item>
{period.prefix ? <span>{period.prefix}&nbsp;</span> : null}
{period.type === "ROLLING" && (
@ -1132,7 +1136,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
/>
<select
id=""
className="focus:border-primary-500 focus:ring-primary-500 block w-full rounded-sm border-gray-300 py-2 pl-3 pr-10 text-base focus:outline-none sm:text-sm"
className="block w-full py-2 pl-3 pr-10 text-base border-gray-300 rounded-sm focus:border-primary-500 focus:ring-primary-500 focus:outline-none sm:text-sm"
{...formMethods.register("periodCountCalendarDays")}
defaultValue={eventType.periodCountCalendarDays ? "1" : "0"}>
<option value="1">{t("calendar_days")}</option>
@ -1172,7 +1176,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<hr className="border-neutral-200" />
<div className="block sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="mb-4 min-w-48 sm:mb-0">
<label htmlFor="availability" className="flex text-sm font-medium text-neutral-700">
{t("availability")}
</label>
@ -1209,20 +1213,20 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
<>
<hr className="border-neutral-200" />
<div className="block sm:flex">
<div className="min-w-48 mb-4 sm:mb-0">
<div className="mb-4 min-w-48 sm:mb-0">
<label
htmlFor="payment"
className="mt-2 flex text-sm font-medium text-neutral-700">
className="flex mt-2 text-sm font-medium text-neutral-700">
{t("payment")}
</label>
</div>
<div className="flex flex-col">
<div className="w-full">
<div className="block items-center sm:flex">
<div className="items-center block sm:flex">
<div className="w-full">
<div className="relative flex items-start">
<div className="flex h-5 items-center">
<div className="flex items-center h-5">
<input
onChange={(event) => {
setRequirePayment(event.target.checked);
@ -1233,7 +1237,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
id="requirePayment"
name="requirePayment"
type="checkbox"
className="text-primary-600 focus:ring-primary-500 h-4 w-4 rounded border-gray-300"
className="w-4 h-4 border-gray-300 rounded text-primary-600 focus:ring-primary-500"
defaultChecked={requirePayment}
/>
</div>
@ -1256,7 +1260,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
{requirePayment && (
<div className="w-full">
<div className="block items-center sm:flex">
<div className="items-center block sm:flex">
<div className="w-full">
<div className="relative mt-1 rounded-sm shadow-sm">
<Controller
@ -1270,7 +1274,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
min="0.5"
type="number"
required
className="focus:border-primary-500 focus:ring-primary-500 block w-full rounded-sm border-gray-300 pl-2 pr-12 sm:text-sm"
className="block w-full pl-2 pr-12 border-gray-300 rounded-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
placeholder="Price"
onChange={(e) => {
field.onChange(e.target.valueAsNumber * 100);
@ -1279,7 +1283,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
/>
)}
/>
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
<div className="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
<span className="text-gray-500 sm:text-sm" id="duration">
{new Intl.NumberFormat("en", {
style: "currency",
@ -1304,7 +1308,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</>
{/* )} */}
</Collapsible>
<div className="mt-4 flex justify-end space-x-2 rtl:space-x-reverse">
<div className="flex justify-end mt-4 space-x-2 rtl:space-x-reverse">
<Button href="/event-types" color="secondary" tabIndex={-1}>
{t("cancel")}
</Button>
@ -1337,8 +1341,8 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
href={permalink}
target="_blank"
rel="noreferrer"
className="text-md inline-flex items-center rounded-sm px-2 py-1 text-sm font-medium text-neutral-700 hover:bg-gray-200 hover:text-gray-900">
<ExternalLinkIcon className="h-4 w-4 text-neutral-500 ltr:mr-2 rtl:ml-2" aria-hidden="true" />
className="inline-flex items-center px-2 py-1 text-sm font-medium rounded-sm text-md text-neutral-700 hover:bg-gray-200 hover:text-gray-900">
<ExternalLinkIcon className="w-4 h-4 text-neutral-500 ltr:mr-2 rtl:ml-2" aria-hidden="true" />
{t("preview")}
</a>
<button
@ -1347,13 +1351,13 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
showToast("Link copied!", "success");
}}
type="button"
className="text-md flex items-center rounded-sm px-2 py-1 text-sm font-medium text-gray-700 hover:bg-gray-200 hover:text-gray-900">
<LinkIcon className="h-4 w-4 text-neutral-500 ltr:mr-2 rtl:ml-2" />
className="flex items-center px-2 py-1 text-sm font-medium text-gray-700 rounded-sm text-md hover:bg-gray-200 hover:text-gray-900">
<LinkIcon className="w-4 h-4 text-neutral-500 ltr:mr-2 rtl:ml-2" />
{t("copy_link")}
</button>
<Dialog>
<DialogTrigger className="text-md flex items-center rounded-sm px-2 py-1 text-sm font-medium text-neutral-700 hover:bg-gray-200 hover:text-gray-900">
<TrashIcon className="h-4 w-4 text-neutral-500 ltr:mr-2 rtl:ml-2" />
<DialogTrigger className="flex items-center px-2 py-1 text-sm font-medium rounded-sm text-md text-neutral-700 hover:bg-gray-200 hover:text-gray-900">
<TrashIcon className="w-4 h-4 text-neutral-500 ltr:mr-2 rtl:ml-2" />
{t("delete")}
</DialogTrigger>
<ConfirmationDialogContent
@ -1369,10 +1373,10 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
</div>
<Dialog open={showLocationModal} onOpenChange={setShowLocationModal}>
<DialogContent asChild>
<div className="inline-block transform rounded-sm bg-white px-4 pt-5 pb-4 text-left align-bottom shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div className="inline-block px-4 pt-5 pb-4 text-left align-bottom transition-all transform bg-white rounded-sm shadow-xl sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div className="mb-4 sm:flex sm:items-start">
<div className="bg-secondary-100 mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full sm:mx-0 sm:h-10 sm:w-10">
<LocationMarkerIcon className="text-primary-600 h-6 w-6" />
<div className="flex items-center justify-center flex-shrink-0 w-12 h-12 mx-auto rounded-full bg-secondary-100 sm:mx-0 sm:h-10 sm:w-10">
<LocationMarkerIcon className="w-6 h-6 text-primary-600" />
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
@ -1423,7 +1427,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
options={locationOptions}
isSearchable={false}
classNamePrefix="react-select"
className="react-select-container focus:border-primary-500 focus:ring-primary-500 my-4 block w-full min-w-0 flex-1 rounded-sm border border-gray-300 sm:text-sm"
className="flex-1 block w-full min-w-0 my-4 border border-gray-300 rounded-sm react-select-container focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
onChange={(val) => {
if (val) {
locationFormMethods.setValue("locationType", val.value);
@ -1434,7 +1438,7 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
)}
/>
<LocationOptions />
<div className="mt-4 flex justify-end space-x-2">
<div className="flex justify-end mt-4 space-x-2">
<Button onClick={() => setShowLocationModal(false)} type="button" color="secondary">
{t("cancel")}
</Button>
@ -1451,10 +1455,10 @@ const EventTypePage = (props: inferSSRProps<typeof getServerSideProps>) => {
render={() => (
<Dialog open={selectedCustomInputModalOpen} onOpenChange={setSelectedCustomInputModalOpen}>
<DialogContent asChild>
<div className="inline-block transform rounded-sm bg-white px-4 pt-5 pb-4 text-left align-bottom shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div className="inline-block px-4 pt-5 pb-4 text-left align-bottom transition-all transform bg-white rounded-sm shadow-xl sm:my-8 sm:w-full sm:max-w-lg sm:p-6 sm:align-middle">
<div className="mb-4 sm:flex sm:items-start">
<div className="bg-secondary-100 mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full sm:mx-0 sm:h-10 sm:w-10">
<PlusIcon className="text-primary-600 h-6 w-6" />
<div className="flex items-center justify-center flex-shrink-0 w-12 h-12 mx-auto rounded-full bg-secondary-100 sm:mx-0 sm:h-10 sm:w-10">
<PlusIcon className="w-6 h-6 text-primary-600" />
</div>
<div className="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">

View File

@ -1,11 +1,12 @@
import { z } from "zod";
import { LocationType } from "@calcom/lib/location";
import { LocationType } from "@lib/location";
import { slugify } from "@lib/slugify";
export const eventTypeLocations = z.array(
z.object({ type: z.nativeEnum(LocationType), address: z.string().optional() })
);
export const eventTypeSlug = z.string().transform((val) => val.trim());
export const eventTypeSlug = z.string().transform((val) => slugify(val.trim()));
export const stringToDate = z.string().transform((a) => new Date(a));
export const stringOrNumber = z.union([z.string().transform((v) => parseInt(v, 10)), z.number().int()]);