feat: routing form fields as variables in route (#13519)
* add UI for setting up custom event typ url * extract variables when processing route * remove console.log * fix some UI issues * code clean up * add translation * fix type error * Update packages/app-store/routing-forms/pages/route-builder/[...appPages].tsx Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> * make variable check case insensitive * add function * code clean up * code clean up --------- Co-authored-by: CarinaWolli <wollencarina@gmail.com> Co-authored-by: Hariom Balhara <hariombalhara@gmail.com>
This commit is contained in:
co-authored by
CarinaWolli
Hariom Balhara
parent
12466fb064
commit
4aa040d96e
@@ -2242,5 +2242,6 @@
|
||||
"redirect_to": "Redirect to",
|
||||
"having_trouble_finding_time": "Having trouble finding a time?",
|
||||
"show_more": "Show more",
|
||||
"send_booker_to": "Send Booker to",
|
||||
"ADD_NEW_STRINGS_ABOVE_THIS_LINE_TO_PREVENT_MERGE_CONFLICTS": "↑↑↑↑↑↑↑↑↑↑↑↑↑ Add your new strings above here ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import slugify from "@calcom/lib/slugify";
|
||||
|
||||
import type { Response, Route, Field } from "../types/types";
|
||||
import getFieldIdentifier from "./getFieldIdentifier";
|
||||
|
||||
export const substituteVariables = (
|
||||
routeValue: Route["action"]["value"],
|
||||
response: Response,
|
||||
fields: Field[]
|
||||
) => {
|
||||
const regex = /\{([^\}]+)\}/g;
|
||||
const variables: string[] = routeValue.match(regex)?.map((match: string) => match.slice(1, -1)) || [];
|
||||
|
||||
let eventTypeUrl = routeValue;
|
||||
|
||||
variables.forEach((variable) => {
|
||||
for (const key in response) {
|
||||
const identifier = getFieldIdentifier(fields.find((field) => field.id === key));
|
||||
if (identifier.toLowerCase() === variable.toLowerCase()) {
|
||||
eventTypeUrl = eventTypeUrl.replace(`{${variable}}`, slugify(response[key].value.toString() || ""));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return eventTypeUrl;
|
||||
};
|
||||
@@ -92,6 +92,8 @@ const Route = ({
|
||||
appUrl: string;
|
||||
disabled?: boolean;
|
||||
}) => {
|
||||
const { t } = useLocale();
|
||||
|
||||
const index = routes.indexOf(route);
|
||||
|
||||
const { data: eventTypesByGroup } = trpc.viewer.eventTypes.getByViewer.useQuery({
|
||||
@@ -128,6 +130,16 @@ const Route = ({
|
||||
});
|
||||
});
|
||||
|
||||
// /team/{TEAM_SLUG}/{EVENT_SLUG} -> /team/{TEAM_SLUG}
|
||||
const eventTypePrefix =
|
||||
eventOptions.length !== 0
|
||||
? eventOptions[0].value.substring(0, eventOptions[0].value.lastIndexOf("/") + 1)
|
||||
: "";
|
||||
|
||||
const [customEventTypeSlug, setCustomEventTypeSlug] = useState(
|
||||
!isRouter(route) ? route.action.value.split("/").pop() : ""
|
||||
);
|
||||
|
||||
const onChange = (route: Route, immutableTree: ImmutableTree, config: QueryBuilderUpdatedConfig) => {
|
||||
const jsonTree = QbUtils.getTree(immutableTree);
|
||||
setRoute(route.id, {
|
||||
@@ -199,7 +211,7 @@ const Route = ({
|
||||
<div>
|
||||
<div className="text-emphasis flex w-full items-center text-sm">
|
||||
<div className="flex flex-grow-0 whitespace-nowrap">
|
||||
<span>Send Booker to</span>
|
||||
<span>{t("send_booker_to")}</span>
|
||||
</div>
|
||||
<Select
|
||||
isDisabled={disabled}
|
||||
@@ -257,15 +269,50 @@ const Route = ({
|
||||
<Select
|
||||
required
|
||||
isDisabled={disabled}
|
||||
options={eventOptions}
|
||||
options={
|
||||
eventOptions.length !== 0
|
||||
? eventOptions.concat({ label: t("Custom"), value: "custom" })
|
||||
: []
|
||||
}
|
||||
onChange={(option) => {
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
setRoute(route.id, { action: { ...route.action, value: option.value } });
|
||||
if (option.value !== "custom") {
|
||||
setRoute(route.id, { action: { ...route.action, value: option.value } });
|
||||
} else {
|
||||
setRoute(route.id, { action: { ...route.action, value: "custom" } });
|
||||
setCustomEventTypeSlug("");
|
||||
}
|
||||
}}
|
||||
value={eventOptions.find((eventOption) => eventOption.value === route.action.value)}
|
||||
value={
|
||||
eventOptions.length !== 0 && route.action.value !== ""
|
||||
? eventOptions.find((eventOption) => eventOption.value === route.action.value) || {
|
||||
label: t("custom"),
|
||||
value: "custom",
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
{eventOptions.length !== 0 &&
|
||||
route.action.value !== "" &&
|
||||
!eventOptions.find((eventOption) => eventOption.value === route.action.value) && (
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
className="border-default flex w-full flex-grow text-sm"
|
||||
containerClassName="w-full mt-2"
|
||||
addOnLeading={eventTypePrefix}
|
||||
required
|
||||
value={customEventTypeSlug}
|
||||
onChange={(e) => {
|
||||
setCustomEventTypeSlug(e.target.value);
|
||||
setRoute(route.id, {
|
||||
action: { ...route.action, value: `${eventTypePrefix}${e.target.value}` },
|
||||
});
|
||||
}}
|
||||
placeholder="event-url"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
) : null}
|
||||
|
||||
@@ -20,6 +20,7 @@ import { Button, showToast, useCalcomTheme } from "@calcom/ui";
|
||||
import FormInputFields from "../../components/FormInputFields";
|
||||
import getFieldIdentifier from "../../lib/getFieldIdentifier";
|
||||
import { processRoute } from "../../lib/processRoute";
|
||||
import { substituteVariables } from "../../lib/substituteVariables";
|
||||
import transformResponse from "../../lib/transformResponse";
|
||||
import type { Response, Route } from "../../types/types";
|
||||
import { getServerSideProps } from "./getServerSideProps";
|
||||
@@ -101,7 +102,9 @@ function RoutingForm({ form, profile, ...restProps }: Props) {
|
||||
if (decidedAction.type === "customPageMessage") {
|
||||
setCustomPageMessage(decidedAction.value);
|
||||
} else if (decidedAction.type === "eventTypeRedirectUrl") {
|
||||
await router.push(`/${decidedAction.value}?${allURLSearchParams}`);
|
||||
const eventTypeUrlWithVariables = substituteVariables(decidedAction.value, response, fields);
|
||||
|
||||
await router.push(`/${eventTypeUrlWithVariables}?${allURLSearchParams}`);
|
||||
} else if (decidedAction.type === "externalRedirectUrl") {
|
||||
window.parent.location.href = `${decidedAction.value}?${allURLSearchParams}`;
|
||||
}
|
||||
@@ -142,7 +145,7 @@ function RoutingForm({ form, profile, ...restProps }: Props) {
|
||||
|
||||
<form onSubmit={handleOnSubmit}>
|
||||
<div className="mb-8">
|
||||
<h1 className="font-cal text-emphasis mb-1 text-xl font-bold tracking-wide">
|
||||
<h1 className="font-cal text-emphasis mb-1 text-xl font-bold tracking-wide">
|
||||
{form.name}
|
||||
</h1>
|
||||
{form.description ? (
|
||||
|
||||
Reference in New Issue
Block a user