cal.pub0.org/apps/web/components/Embed.tsx

1155 lines
43 KiB
TypeScript
Raw Normal View History

import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@radix-ui/react-collapsible";
import classNames from "classnames";
2022-09-19 09:47:46 +00:00
import { NextRouter, useRouter } from "next/router";
import { createRef, forwardRef, MutableRefObject, RefObject, useRef, useState } from "react";
2022-05-17 20:43:27 +00:00
import { components, ControlProps } from "react-select";
import { useLocale } from "@calcom/lib/hooks/useLocale";
2022-07-27 02:24:00 +00:00
import { Icon } from "@calcom/ui/Icon";
import { InputLeading, Label, TextArea, TextField } from "@calcom/ui/form/fields";
import { Button, HorizontalTabs, showToast, Switch } from "@calcom/ui/v2";
import { Dialog, DialogClose, DialogContent } from "@calcom/ui/v2/core/Dialog";
2022-05-17 20:43:27 +00:00
import { EMBED_LIB_URL, WEBAPP_URL } from "@lib/config/constants";
import ColorPicker from "@components/ui/colorpicker";
import Select from "@components/ui/form/Select";
type EmbedType = "inline" | "floating-popup" | "element-click";
type EmbedFramework = "react" | "HTML";
const enum Theme {
auto = "auto",
light = "light",
dark = "dark",
}
type PreviewState = {
inline: {
width: string;
height: string;
};
theme: Theme;
floatingPopup: Record<string, string>;
elementClick: Record<string, string>;
palette: {
brandColor: string;
};
};
const queryParamsForDialog = ["embedType", "embedTabName", "embedUrl"];
const getDimension = (dimension: string) => {
if (dimension.match(/^\d+$/)) {
dimension = `${dimension}%`;
}
return dimension;
};
2022-09-19 09:47:46 +00:00
const goto = (router: NextRouter, searchParams: Record<string, string>) => {
const newQuery = new URLSearchParams(router.asPath.split("?")[1]);
Object.keys(searchParams).forEach((key) => {
newQuery.set(key, searchParams[key]);
});
router.push(`${router.asPath.split("?")[0]}?${newQuery.toString()}`, undefined, {
shallow: true,
});
};
const removeQueryParams = (router: NextRouter, queryParams: string[]) => {
queryParams.forEach((param) => {
delete router.query[param];
});
router.push(`${router.asPath.split("?")[0]}?${router.query.toString()}`);
};
/**
* It allows us to show code with certain reusable blocks indented according to the block variable placement
* So, if you add a variable ${abc} with indentation of 4 spaces, it will automatically indent all newlines in `abc` with the same indent before constructing the final string
* `A${var}C` with var = "B" -> partsWithoutBlock=['A','C'] blocksOrVariables=['B']
*/
const code = (partsWithoutBlock: TemplateStringsArray, ...blocksOrVariables: string[]) => {
const constructedCode: string[] = [];
for (let i = 0; i < partsWithoutBlock.length; i++) {
const partWithoutBlock = partsWithoutBlock[i];
// blocksOrVariables length would always be 1 less than partsWithoutBlock
// So, last item should be concatenated as is.
if (i >= blocksOrVariables.length) {
constructedCode.push(partWithoutBlock);
continue;
}
const block = blocksOrVariables[i];
const indentedBlock: string[] = [];
let indent = "";
block.split("\n").forEach((line) => {
indentedBlock.push(line);
});
// non-null assertion is okay because we know that we are referencing last element.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const indentationMatch = partWithoutBlock
.split("\n")
.at(-1)!
.match(/(^[\t ]*).*$/);
if (indentationMatch) {
indent = indentationMatch[1];
}
constructedCode.push(partWithoutBlock + indentedBlock.join("\n" + indent));
}
return constructedCode.join("");
};
const getInstructionString = ({
apiName,
instructionName,
instructionArg,
}: {
apiName: string;
instructionName: string;
instructionArg: Record<string, unknown>;
}) => {
return `${apiName}("${instructionName}", ${JSON.stringify(instructionArg)});`;
};
const getEmbedUIInstructionString = ({
apiName,
theme,
brandColor,
}: {
apiName: string;
theme?: string;
brandColor: string;
}) => {
theme = theme !== "auto" ? theme : undefined;
return getInstructionString({
apiName,
instructionName: "ui",
instructionArg: {
theme,
styles: {
branding: {
brandColor,
},
},
},
});
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const Codes: Record<string, Record<string, (...args: any[]) => string>> = {
react: {
inline: ({
calLink,
uiInstructionCode,
previewState,
}: {
calLink: string;
uiInstructionCode: string;
previewState: PreviewState;
}) => {
const width = getDimension(previewState.inline.width);
const height = getDimension(previewState.inline.height);
return code`
import Cal, { getCalApi } from "@calcom/embed-react";
function MyComponent() {
useEffect(()=>{
(async function () {
const cal = await getCalApi();
${uiInstructionCode}
})();
Feat/design system (#3051) * Storybook Boilerplate setup * Inital Setup * First story * Color Design System * Badge Story + Comp * Checkbox UI + Stories * Update Red colors + Button Group * Switch+Stories / Default brand color * Update Version + Button Group combined * Compact Butotn Group * Tidy up Selectors * Adds Tooltip to Button * TextInput * Update SB * Prefix Input * Match text area styles * Prefix Controls * Update spacing on text area * Text Input Suffix * Color Picker * Update storybook * Icon Suffix/Prefix * Datepicker + move components to monorepo * Text color on labels * Move Radio over to monorepo * Move CustomBranding to calcom/ib * Radio * IconBadge Component * Update radio indicator background * Disabled radio state * Delete yarn.lock * Revert "Delete yarn.lock" This reverts commit 9b99d244b70872153a16bec1f1f3bc651e94be7a. * Fix webhook test * Replace old toast location * Update radio path * Empty State * Update Badge.tsx * Update Badge.tsx * Banner Component+story * Creation Modal * Creation Dialog updated * Button hover dialog * Confirmation Modal * Datepicker (Booking) * PageHeader * Fix border width * PageHeader update search bar * Fix input height * Fix button group size * Add spacing between badges - font smoothing * Update button position on banner * Banner update * Fixing focus state on suffix/prefix inputs * Implement A11y addon * Add aria label * error && "text-red-800" * Fix button hover * Change colors * Generate snapshot tests for on hover button * Revert colors to demo * Change colors * Fix Linear Issues * Form Stepper component * Add padding back to input * Move ui to UI_V2 * Use V2 * Update imports for v1 * Update imports for v1 * Upgrade to nextjs in storybook root * Update website submodule * Avatar Groups * Fix webpack again * Vertical Tab Item [WIP] - active state on small item is not working currently * Vertical Tab Group * Add Github action * Fix website submodule * Fix GH action * Rename Workflow * Adds lint report for CI * Lint report fixes * NavigationItem comments * VerticalTabItem type fixes * Fix avatar blur * Fix comments * Adding isEmbed to window object * Disable components that use router mock. * Load inter via google fonts * Started select * Adding base Breadcrumb * Update readme * Formatting * Fixes * Dependencies matching * Linting * Update FormStep.stories.tsx * Linting * Update MultiSelectCheckboxes.tsx Co-authored-by: zomars <zomars@me.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-07-23 00:39:50 +00:00
}, [])
return <Cal calLink="${calLink}" style={{width:"${width}",height:"${height}",overflow:"scroll"}} />;
};`;
},
"floating-popup": ({
floatingButtonArg,
uiInstructionCode,
}: {
floatingButtonArg: string;
uiInstructionCode: string;
}) => {
return code`
import Cal, { getCalApi } from "@calcom/embed-react";
function MyComponent() {
useEffect(()=>{
(async function () {
const cal = await getCalApi();
Cal("floatingButton", ${floatingButtonArg});
${uiInstructionCode}
})();
Feat/design system (#3051) * Storybook Boilerplate setup * Inital Setup * First story * Color Design System * Badge Story + Comp * Checkbox UI + Stories * Update Red colors + Button Group * Switch+Stories / Default brand color * Update Version + Button Group combined * Compact Butotn Group * Tidy up Selectors * Adds Tooltip to Button * TextInput * Update SB * Prefix Input * Match text area styles * Prefix Controls * Update spacing on text area * Text Input Suffix * Color Picker * Update storybook * Icon Suffix/Prefix * Datepicker + move components to monorepo * Text color on labels * Move Radio over to monorepo * Move CustomBranding to calcom/ib * Radio * IconBadge Component * Update radio indicator background * Disabled radio state * Delete yarn.lock * Revert "Delete yarn.lock" This reverts commit 9b99d244b70872153a16bec1f1f3bc651e94be7a. * Fix webhook test * Replace old toast location * Update radio path * Empty State * Update Badge.tsx * Update Badge.tsx * Banner Component+story * Creation Modal * Creation Dialog updated * Button hover dialog * Confirmation Modal * Datepicker (Booking) * PageHeader * Fix border width * PageHeader update search bar * Fix input height * Fix button group size * Add spacing between badges - font smoothing * Update button position on banner * Banner update * Fixing focus state on suffix/prefix inputs * Implement A11y addon * Add aria label * error && "text-red-800" * Fix button hover * Change colors * Generate snapshot tests for on hover button * Revert colors to demo * Change colors * Fix Linear Issues * Form Stepper component * Add padding back to input * Move ui to UI_V2 * Use V2 * Update imports for v1 * Update imports for v1 * Upgrade to nextjs in storybook root * Update website submodule * Avatar Groups * Fix webpack again * Vertical Tab Item [WIP] - active state on small item is not working currently * Vertical Tab Group * Add Github action * Fix website submodule * Fix GH action * Rename Workflow * Adds lint report for CI * Lint report fixes * NavigationItem comments * VerticalTabItem type fixes * Fix avatar blur * Fix comments * Adding isEmbed to window object * Disable components that use router mock. * Load inter via google fonts * Started select * Adding base Breadcrumb * Update readme * Formatting * Fixes * Dependencies matching * Linting * Update FormStep.stories.tsx * Linting * Update MultiSelectCheckboxes.tsx Co-authored-by: zomars <zomars@me.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-07-23 00:39:50 +00:00
}, [])
};`;
},
"element-click": ({ calLink, uiInstructionCode }: { calLink: string; uiInstructionCode: string }) => {
return code`
import Cal, { getCalApi } from "@calcom/embed-react";
function MyComponent() {
useEffect(()=>{
(async function () {
const cal = await getCalApi();
${uiInstructionCode}
})();
Feat/design system (#3051) * Storybook Boilerplate setup * Inital Setup * First story * Color Design System * Badge Story + Comp * Checkbox UI + Stories * Update Red colors + Button Group * Switch+Stories / Default brand color * Update Version + Button Group combined * Compact Butotn Group * Tidy up Selectors * Adds Tooltip to Button * TextInput * Update SB * Prefix Input * Match text area styles * Prefix Controls * Update spacing on text area * Text Input Suffix * Color Picker * Update storybook * Icon Suffix/Prefix * Datepicker + move components to monorepo * Text color on labels * Move Radio over to monorepo * Move CustomBranding to calcom/ib * Radio * IconBadge Component * Update radio indicator background * Disabled radio state * Delete yarn.lock * Revert "Delete yarn.lock" This reverts commit 9b99d244b70872153a16bec1f1f3bc651e94be7a. * Fix webhook test * Replace old toast location * Update radio path * Empty State * Update Badge.tsx * Update Badge.tsx * Banner Component+story * Creation Modal * Creation Dialog updated * Button hover dialog * Confirmation Modal * Datepicker (Booking) * PageHeader * Fix border width * PageHeader update search bar * Fix input height * Fix button group size * Add spacing between badges - font smoothing * Update button position on banner * Banner update * Fixing focus state on suffix/prefix inputs * Implement A11y addon * Add aria label * error && "text-red-800" * Fix button hover * Change colors * Generate snapshot tests for on hover button * Revert colors to demo * Change colors * Fix Linear Issues * Form Stepper component * Add padding back to input * Move ui to UI_V2 * Use V2 * Update imports for v1 * Update imports for v1 * Upgrade to nextjs in storybook root * Update website submodule * Avatar Groups * Fix webpack again * Vertical Tab Item [WIP] - active state on small item is not working currently * Vertical Tab Group * Add Github action * Fix website submodule * Fix GH action * Rename Workflow * Adds lint report for CI * Lint report fixes * NavigationItem comments * VerticalTabItem type fixes * Fix avatar blur * Fix comments * Adding isEmbed to window object * Disable components that use router mock. * Load inter via google fonts * Started select * Adding base Breadcrumb * Update readme * Formatting * Fixes * Dependencies matching * Linting * Update FormStep.stories.tsx * Linting * Update MultiSelectCheckboxes.tsx Co-authored-by: zomars <zomars@me.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com>
2022-07-23 00:39:50 +00:00
}, [])
return <button data-cal-link="${calLink}" />;
};`;
},
},
HTML: {
inline: ({ calLink, uiInstructionCode }: { calLink: string; uiInstructionCode: string }) => {
return code`Cal("inline", {
elementOrSelector:"#my-cal-inline",
calLink: "${calLink}"
});
${uiInstructionCode}`;
},
"floating-popup": ({
floatingButtonArg,
uiInstructionCode,
}: {
floatingButtonArg: string;
uiInstructionCode: string;
}) => {
return code`Cal("floatingButton", ${floatingButtonArg});
${uiInstructionCode}`;
},
"element-click": ({ calLink, uiInstructionCode }: { calLink: string; uiInstructionCode: string }) => {
return code`// Important: Make sure to add \`data-cal-link="${calLink}"\` attribute to the element you want to open Cal on click
${uiInstructionCode}`;
},
},
};
const getEmbedTypeSpecificString = ({
embedFramework,
embedType,
calLink,
previewState,
}: {
embedFramework: EmbedFramework;
embedType: EmbedType;
calLink: string;
previewState: PreviewState;
}) => {
const frameworkCodes = Codes[embedFramework];
if (!frameworkCodes) {
throw new Error(`No code available for the framework:${embedFramework}`);
}
V2 Main (#3549) * Fix breadcrumb colors * HorizontalTabs * Team List Item WIP * Horizontal Tabs * Cards * Remove team list item WIP * Login Page * Add welcome back i118n * EventType page work * Update EventType Icons * WIP Availability * Horizontal Tab Work * Add build command for in root * Update build DIr/command * Add Edit Button + change buttons to v2 * Availablitiy page * Fix IPAD * Make mobile look a little nicer * WIP bookingshell * Remove list items from breaking build * Mian bulk of Booking Page. * Few updates to components * Fix chormatic feedback * Fix banner * Fix Empty Screen * Text area + embded window fixes * Semi fix avatar * Troubleshoot container + Active on count * Improve mobile * NITS * Fix padding on input * Fix icons * Starting to move event types settings to tabs * Begin migration to single page form * Single page tabs * Limits Page * Advanced tab * Add RHF to dependancies * Most of advanced tab * Solved RHF mismtach * Build fixes * RHF conditionals fixes * Improved legibility * Major refactor/organisation into optional V2 UI * Portal EditLocationModal * Fix dialoug form * Update imports * Auto Animate + custom inputs WIP * Custom Inputs * WIP Apps * Fixing stories imports * Stripe app * Remove duplicate dialog * Remove duplicate dialog * Fix embed URL * Fix app toggles + number of active apps * Fix container padding on disabledBorder prop * Removes strict * EventType Team page WIP * Fix embed * NIT * Add Darkmode gray color * V2 Shell WIP * Fix headings on shell V2 * Fix mobile layout with V2 shell * V2 create event type button * Checked Team Select * Hidden to happen on save - not on toggle * Team Attendee Select animation * Fix scheduling type and remove multi select label * Fix overflow on teams url * Even Type move order handles * Fix Embed TS errors * Fix TS errors * Fix Eslint errors * Fix TS errors for UI * Fix ESLINT error * added SidebarCard for promo to v2 and storybook (#3906) Co-authored-by: Julian Benegas <julianbenegas99@gmail.com> Co-authored-by: Alan <alannnc@gmail.com> Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> * Tooltip Provider - Wrapper due to dep upgrade * public event type list darkmode * V2 Color changes to public booking * Remove unused component * Fix typecheck * Removed extra buttons on create ET dialog * ET edit page refactoring * Avoids form wrapping the whole Shell * Nitpicks Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: zomars <zomars@me.com> Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> Co-authored-by: Julian Benegas <julianbenegas99@gmail.com> Co-authored-by: Alan <alannnc@gmail.com>
2022-08-24 20:18:42 +00:00
let uiInstructionStringArg: {
apiName: string;
theme: PreviewState["theme"];
brandColor: string;
};
if (embedFramework === "react") {
uiInstructionStringArg = {
apiName: "cal",
theme: previewState.theme,
brandColor: previewState.palette.brandColor,
};
} else {
uiInstructionStringArg = {
apiName: "Cal",
theme: previewState.theme,
brandColor: previewState.palette.brandColor,
};
}
if (!frameworkCodes[embedType]) {
throw new Error(`Code not available for framework:${embedFramework} and embedType:${embedType}`);
}
if (embedType === "inline") {
return frameworkCodes[embedType]({
calLink,
uiInstructionCode: getEmbedUIInstructionString(uiInstructionStringArg),
previewState,
});
} else if (embedType === "floating-popup") {
const floatingButtonArg = {
calLink,
...previewState.floatingPopup,
};
return frameworkCodes[embedType]({
floatingButtonArg: JSON.stringify(floatingButtonArg),
uiInstructionCode: getEmbedUIInstructionString(uiInstructionStringArg),
previewState,
});
} else if (embedType === "element-click") {
return frameworkCodes[embedType]({
calLink,
uiInstructionCode: getEmbedUIInstructionString(uiInstructionStringArg),
previewState,
});
}
return "";
};
const embeds: {
illustration: React.ReactElement;
title: string;
subtitle: string;
type: EmbedType;
}[] = [
{
title: "Inline Embed",
subtitle: "Loads your Cal scheduling page directly inline with your other website content",
type: "inline",
illustration: (
<svg
width="100%"
height="100%"
className="rounded-md"
viewBox="0 0 308 265"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M0 1.99999C0 0.895423 0.895431 0 2 0H306C307.105 0 308 0.895431 308 2V263C308 264.105 307.105 265 306 265H2C0.895431 265 0 264.105 0 263V1.99999Z"
fill="white"
/>
<rect x="24" width="260" height="38.5" rx="2" fill="#E1E1E1" />
<rect x="24.5" y="51" width="139" height="163" rx="1.5" fill="#F8F8F8" />
<rect opacity="0.8" x="48" y="74.5" width="80" height="8" rx="2" fill="#E1E1E1" />
<rect x="48" y="86.5" width="48" height="4" rx="1" fill="#E1E1E1" />
<rect x="49" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="99.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="73" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="99.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="113.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="125.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<path
d="M61 124.5H67V122.5H61V124.5ZM68 125.5V131.5H70V125.5H68ZM67 132.5H61V134.5H67V132.5ZM60 131.5V125.5H58V131.5H60ZM61 132.5C60.4477 132.5 60 132.052 60 131.5H58C58 133.157 59.3431 134.5 61 134.5V132.5ZM68 131.5C68 132.052 67.5523 132.5 67 132.5V134.5C68.6569 134.5 70 133.157 70 131.5H68ZM67 124.5C67.5523 124.5 68 124.948 68 125.5H70C70 123.843 68.6569 122.5 67 122.5V124.5ZM61 122.5C59.3431 122.5 58 123.843 58 125.5H60C60 124.948 60.4477 124.5 61 124.5V122.5Z"
fill="#3E3E3E"
/>
<rect x="73" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="125.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="73" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="137.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="109" y="137.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="121" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="137.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="73" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="149.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="109" y="149.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="121" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="149.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="49" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="61" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="73" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="85" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="97" y="161.5" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="109" y="161.5" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="24.5" y="51" width="139" height="163" rx="1.5" stroke="#292929" />
<rect x="176" y="50.5" width="108" height="164" rx="2" fill="#E1E1E1" />
<rect x="24" y="226.5" width="260" height="38.5" rx="2" fill="#E1E1E1" />
</svg>
),
},
{
title: "Floating pop-up button",
subtitle: "Adds a floating button on your site that launches Cal in a dialog.",
type: "floating-popup",
illustration: (
<svg
width="100%"
height="100%"
className="rounded-md"
viewBox="0 0 308 265"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M0 1.99999C0 0.895423 0.895431 0 2 0H306C307.105 0 308 0.895431 308 2V263C308 264.105 307.105 265 306 265H2C0.895431 265 0 264.105 0 263V1.99999Z"
fill="white"
/>
<rect x="24" width="260" height="38.5" rx="2" fill="#E1E1E1" />
<rect x="24" y="50.5" width="120" height="76" rx="2" fill="#E1E1E1" />
<rect x="24" y="138.5" width="120" height="76" rx="2" fill="#E1E1E1" />
<rect x="156" y="50.5" width="128" height="164" rx="2" fill="#E1E1E1" />
<rect x="24" y="226.5" width="260" height="38.5" rx="2" fill="#E1E1E1" />
<rect x="226" y="223.5" width="66" height="26" rx="2" fill="#292929" />
<rect x="242" y="235.5" width="34" height="2" rx="1" fill="white" />
</svg>
),
},
{
title: "Pop up via element click",
subtitle: "Open your Cal dialog when someone clicks an element.",
type: "element-click",
illustration: (
<svg
width="100%"
height="100%"
className="rounded-md"
viewBox="0 0 308 265"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
d="M0 1.99999C0 0.895423 0.895431 0 2 0H306C307.105 0 308 0.895431 308 2V263C308 264.105 307.105 265 306 265H2C0.895431 265 0 264.105 0 263V1.99999Z"
fill="white"
/>
<rect x="24" width="260" height="38.5" rx="2" fill="#E1E1E1" />
<rect x="24" y="50.5" width="120" height="76" rx="2" fill="#E1E1E1" />
<rect x="24" y="138.5" width="120" height="76" rx="2" fill="#E1E1E1" />
<rect x="156" y="50.5" width="128" height="164" rx="2" fill="#E1E1E1" />
<rect x="24" y="226.5" width="260" height="38.5" rx="2" fill="#E1E1E1" />
<rect x="84.5" y="61.5" width="139" height="141" rx="1.5" fill="#F8F8F8" />
<rect opacity="0.8" x="108" y="85" width="80" height="8" rx="2" fill="#E1E1E1" />
<rect x="108" y="97" width="48" height="4" rx="1" fill="#E1E1E1" />
<rect x="109" y="110" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="110" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="133" y="110" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="145" y="110" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="157" y="110" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="169" y="110" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="181" y="110" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="193" y="110" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="145" y="124" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="157" y="124" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="169" y="124" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="181" y="124" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="193" y="124" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="136" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="136" width="6" height="6" rx="1" fill="#3E3E3E" />
<path
d="M121 135H127V133H121V135ZM128 136V142H130V136H128ZM127 143H121V145H127V143ZM120 142V136H118V142H120ZM121 143C120.448 143 120 142.552 120 142H118C118 143.657 119.343 145 121 145V143ZM128 142C128 142.552 127.552 143 127 143V145C128.657 145 130 143.657 130 142H128ZM127 135C127.552 135 128 135.448 128 136H130C130 134.343 128.657 133 127 133V135ZM121 133C119.343 133 118 134.343 118 136H120C120 135.448 120.448 135 121 135V133Z"
fill="#3E3E3E"
/>
<rect x="133" y="136" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="145" y="136" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="157" y="136" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="169" y="136" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="181" y="136" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="193" y="136" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="148" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="148" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="148" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="145" y="148" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="157" y="148" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="169" y="148" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="181" y="148" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="193" y="148" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="160" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="160" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="160" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="145" y="160" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="157" y="160" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="169" y="160" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="181" y="160" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="193" y="160" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="109" y="172" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="121" y="172" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="133" y="172" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="145" y="172" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="157" y="172" width="6" height="6" rx="1" fill="#3E3E3E" />
<rect x="169" y="172" width="6" height="6" rx="1" fill="#C6C6C6" />
<rect x="84.5" y="61.5" width="139" height="141" rx="1.5" stroke="#292929" />
</svg>
),
},
];
const tabs = [
{
name: "HTML",
href: "embedTabName=embed-code",
icon: Icon.FiCode,
type: "code",
Component: forwardRef<
HTMLTextAreaElement | HTMLIFrameElement | null,
{ embedType: EmbedType; calLink: string; previewState: PreviewState }
>(function EmbedHtml({ embedType, calLink, previewState }, ref) {
const { t } = useLocale();
if (ref instanceof Function || !ref) {
return null;
}
if (ref.current && !(ref.current instanceof HTMLTextAreaElement)) {
return null;
}
return (
<>
<div>
<small className="flex py-4 text-neutral-500">{t("place_where_cal_widget_appear")}</small>
</div>
<TextArea
data-testid="embed-code"
ref={ref as typeof ref & MutableRefObject<HTMLTextAreaElement>}
name="embed-code"
2022-07-27 02:24:00 +00:00
className="h-[calc(100%-50px)] font-mono"
style={{ resize: "none", overflow: "auto" }}
readOnly
value={
`<!-- Cal ${embedType} embed code begins -->\n` +
(embedType === "inline"
? `<div style="width:${getDimension(previewState.inline.width)};height:${getDimension(
previewState.inline.height
)};overflow:scroll" id="my-cal-inline"></div>\n`
: "") +
`<script type="text/javascript">
${getEmbedSnippetString()}
${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previewState })}
</script>
<!-- Cal ${embedType} embed code ends -->`
2022-07-13 21:14:16 +00:00
}
/>
<p className="hidden text-sm text-gray-500">
{t(
"Need help? See our guides for embedding Cal on Wix, Squarespace, or WordPress, check our common questions, or explore advanced embed options."
)}
</p>
</>
);
}),
},
{
name: "React",
href: "embedTabName=embed-react",
icon: Icon.FiCode,
type: "code",
Component: forwardRef<
HTMLTextAreaElement | HTMLIFrameElement | null,
{ embedType: EmbedType; calLink: string; previewState: PreviewState }
>(function EmbedReact({ embedType, calLink, previewState }, ref) {
const { t } = useLocale();
if (ref instanceof Function || !ref) {
return null;
}
if (ref.current && !(ref.current instanceof HTMLTextAreaElement)) {
return null;
}
return (
<>
<small className="flex py-4 text-neutral-500">{t("create_update_react_component")}</small>
<TextArea
data-testid="embed-react"
ref={ref as typeof ref & MutableRefObject<HTMLTextAreaElement>}
name="embed-react"
2022-07-27 02:24:00 +00:00
className="h-[calc(100%-50px)] font-mono"
readOnly
2022-07-27 02:24:00 +00:00
style={{ resize: "none", overflow: "auto" }}
value={`/* First make sure that you have installed the package */
/* If you are using yarn */
// yarn add @calcom/embed-react
/* If you are using npm */
// npm install @calcom/embed-react
${getEmbedTypeSpecificString({ embedFramework: "react", embedType, calLink, previewState })}
2022-07-13 21:14:16 +00:00
`}
/>
</>
);
}),
},
{
name: "Preview",
href: "embedTabName=embed-preview",
icon: Icon.FiTrello,
type: "iframe",
Component: forwardRef<
HTMLIFrameElement | HTMLTextAreaElement | null,
V2 Main (#3549) * Fix breadcrumb colors * HorizontalTabs * Team List Item WIP * Horizontal Tabs * Cards * Remove team list item WIP * Login Page * Add welcome back i118n * EventType page work * Update EventType Icons * WIP Availability * Horizontal Tab Work * Add build command for in root * Update build DIr/command * Add Edit Button + change buttons to v2 * Availablitiy page * Fix IPAD * Make mobile look a little nicer * WIP bookingshell * Remove list items from breaking build * Mian bulk of Booking Page. * Few updates to components * Fix chormatic feedback * Fix banner * Fix Empty Screen * Text area + embded window fixes * Semi fix avatar * Troubleshoot container + Active on count * Improve mobile * NITS * Fix padding on input * Fix icons * Starting to move event types settings to tabs * Begin migration to single page form * Single page tabs * Limits Page * Advanced tab * Add RHF to dependancies * Most of advanced tab * Solved RHF mismtach * Build fixes * RHF conditionals fixes * Improved legibility * Major refactor/organisation into optional V2 UI * Portal EditLocationModal * Fix dialoug form * Update imports * Auto Animate + custom inputs WIP * Custom Inputs * WIP Apps * Fixing stories imports * Stripe app * Remove duplicate dialog * Remove duplicate dialog * Fix embed URL * Fix app toggles + number of active apps * Fix container padding on disabledBorder prop * Removes strict * EventType Team page WIP * Fix embed * NIT * Add Darkmode gray color * V2 Shell WIP * Fix headings on shell V2 * Fix mobile layout with V2 shell * V2 create event type button * Checked Team Select * Hidden to happen on save - not on toggle * Team Attendee Select animation * Fix scheduling type and remove multi select label * Fix overflow on teams url * Even Type move order handles * Fix Embed TS errors * Fix TS errors * Fix Eslint errors * Fix TS errors for UI * Fix ESLINT error * added SidebarCard for promo to v2 and storybook (#3906) Co-authored-by: Julian Benegas <julianbenegas99@gmail.com> Co-authored-by: Alan <alannnc@gmail.com> Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> * Tooltip Provider - Wrapper due to dep upgrade * public event type list darkmode * V2 Color changes to public booking * Remove unused component * Fix typecheck * Removed extra buttons on create ET dialog * ET edit page refactoring * Avoids form wrapping the whole Shell * Nitpicks Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: zomars <zomars@me.com> Co-authored-by: Hariom Balhara <hariombalhara@gmail.com> Co-authored-by: Julian Benegas <julianbenegas99@gmail.com> Co-authored-by: Alan <alannnc@gmail.com>
2022-08-24 20:18:42 +00:00
{ calLink: string; embedType: EmbedType; previewState: PreviewState }
>(function Preview({ calLink, embedType }, ref) {
if (ref instanceof Function || !ref) {
return null;
}
if (ref.current && !(ref.current instanceof HTMLIFrameElement)) {
return null;
}
return (
<iframe
ref={ref as typeof ref & MutableRefObject<HTMLIFrameElement>}
data-testid="embed-preview"
className="border-1 h-[100vh] border"
width="100%"
height="100%"
src={`${WEBAPP_URL}/embed/preview.html?embedType=${embedType}&calLink=${calLink}`}
/>
);
}),
},
];
function getEmbedSnippetString() {
// TODO: Import this string from @calcom/embed-snippet
return `(function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; typeof namespace === "string" ? (cal.ns[namespace] = api) && p(api, ar) : p(cal, ar); return; } p(cal, ar); }; })(window, "${EMBED_LIB_URL}", "init");
Cal("init", {origin:"${WEBAPP_URL}"});
`;
}
const ThemeSelectControl = ({ children, ...props }: ControlProps<{ value: Theme; label: string }, false>) => {
return (
<components.Control {...props}>
<Icon.FiSun className="ml-2 h-4 w-4 text-gray-500" />
{children}
</components.Control>
);
};
const ChooseEmbedTypesDialogContent = () => {
const { t } = useLocale();
const router = useRouter();
return (
<DialogContent type="creation" useOwnActionButtons size="lg">
<div className="mb-4">
<h3 className="text-lg font-bold leading-6 text-gray-900" id="modal-title">
{t("how_you_want_add_cal_site")}
</h3>
<div>
<p className="text-sm text-gray-500">{t("choose_ways_put_cal_site")}</p>
</div>
</div>
2022-07-27 02:24:00 +00:00
<div className="flex items-start">
{embeds.map((embed, index) => (
<button
2022-07-27 02:24:00 +00:00
className="mr-2 w-1/3 border border-transparent p-3 text-left hover:rounded-md hover:border-gray-200 hover:bg-neutral-100"
key={index}
data-testid={embed.type}
onClick={() => {
2022-09-19 09:47:46 +00:00
goto(router, {
embedType: embed.type,
});
}}>
<div className="order-none box-border flex-none rounded-sm border border-solid bg-white">
{embed.illustration}
</div>
<div className="mt-2 font-medium text-neutral-900">{embed.title}</div>
<p className="text-sm text-gray-500">{embed.subtitle}</p>
</button>
))}
</div>
</DialogContent>
);
};
const EmbedTypeCodeAndPreviewDialogContent = ({
embedType,
embedUrl,
}: {
embedType: EmbedType;
embedUrl: string;
}) => {
const { t } = useLocale();
const router = useRouter();
const iframeRef = useRef<HTMLIFrameElement>(null);
const s = (href: string) => {
2022-09-19 09:47:46 +00:00
const searchParams = new URLSearchParams(router.asPath.split("?")[1] || "");
const [a, b] = href.split("=");
searchParams.set(a, b);
return `${router.asPath.split("?")[0]}?${searchParams.toString()}`;
};
const parsedTabs = tabs.map((t) => ({ ...t, href: s(t.href) }));
const embedCodeRefs: Record<typeof tabs[0]["name"], RefObject<HTMLTextAreaElement>> = {};
tabs
.filter((tab) => tab.type === "code")
.forEach((codeTab) => {
embedCodeRefs[codeTab.name] = createRef();
});
const refOfEmbedCodesRefs = useRef(embedCodeRefs);
const embed = embeds.find((embed) => embed.type === embedType);
const [isEmbedCustomizationOpen, setIsEmbedCustomizationOpen] = useState(true);
const [isBookingCustomizationOpen, setIsBookingCustomizationOpen] = useState(true);
const [previewState, setPreviewState] = useState({
inline: {
width: "100%",
height: "100%",
},
theme: Theme.auto,
floatingPopup: {},
elementClick: {},
palette: {
brandColor: "#000000",
},
});
const close = () => {
2022-09-19 09:47:46 +00:00
removeQueryParams(router, ["dialog", ...queryParamsForDialog]);
};
2022-09-19 09:47:46 +00:00
// Use embed-code as default tab
if (!router.query.embedTabName) {
goto(router, {
embedTabName: "embed-code",
});
2022-09-19 09:47:46 +00:00
}
if (!embed || !embedUrl) {
close();
return null;
}
const calLink = decodeURIComponent(embedUrl);
const addToPalette = (update: typeof previewState["palette"]) => {
setPreviewState((previewState) => {
return {
...previewState,
palette: {
...previewState.palette,
...update,
},
};
});
};
2022-05-17 20:43:27 +00:00
const previewInstruction = (instruction: { name: string; arg: unknown }) => {
iframeRef.current?.contentWindow?.postMessage(
{
mode: "cal:preview",
type: "instruction",
instruction,
},
"*"
);
};
const inlineEmbedDimensionUpdate = ({ width, height }: { width: string; height: string }) => {
iframeRef.current?.contentWindow?.postMessage(
{
mode: "cal:preview",
type: "inlineEmbedDimensionUpdate",
data: {
width: getDimension(width),
height: getDimension(height),
},
},
"*"
);
};
previewInstruction({
name: "ui",
arg: {
theme: previewState.theme,
styles: {
branding: {
...previewState.palette,
},
},
},
});
if (embedType === "floating-popup") {
previewInstruction({
name: "floatingButton",
arg: {
attributes: {
id: "my-floating-button",
},
...previewState.floatingPopup,
},
});
}
if (embedType === "inline") {
inlineEmbedDimensionUpdate({
width: previewState.inline.width,
height: previewState.inline.height,
});
}
const ThemeOptions = [
{ value: Theme.auto, label: "Auto Theme" },
{ value: Theme.dark, label: "Dark Theme" },
{ value: Theme.light, label: "Light Theme" },
];
const FloatingPopupPositionOptions = [
{
value: "bottom-right",
label: "Bottom Right",
},
{
value: "bottom-left",
label: "Bottom Left",
},
];
return (
<DialogContent size="xl" className="p-0.5" type="creation" useOwnActionButtons>
<div className="flex">
<div className="flex w-1/3 flex-col bg-gray-50 p-8">
<h3 className="mb-2 flex text-xl font-bold leading-6 text-gray-900" id="modal-title">
<button
onClick={() => {
2022-09-19 09:47:46 +00:00
removeQueryParams(router, ["embedType", "embedTabName"]);
}}>
<Icon.FiArrowLeft className="mr-4 w-4" />
</button>
{embed.title}
</h3>
2022-07-13 21:14:16 +00:00
<hr className={classNames("mt-4", embedType === "element-click" ? "hidden" : "")} />
<div className={classNames("mt-4 font-medium", embedType === "element-click" ? "hidden" : "")}>
<Collapsible
open={isEmbedCustomizationOpen}
onOpenChange={() => setIsEmbedCustomizationOpen((val) => !val)}>
<CollapsibleTrigger
type="button"
className="flex w-full items-center text-base font-medium text-neutral-900">
<div>
{embedType === "inline"
? "Inline Embed Customization"
: embedType === "floating-popup"
? "Floating Popup Customization"
: "Element Click Customization"}
</div>
<Icon.FiChevronRight
className={`${
isEmbedCustomizationOpen ? "rotate-90 transform" : ""
} ml-auto h-5 w-5 text-neutral-500`}
/>
</CollapsibleTrigger>
<CollapsibleContent className="text-sm">
<div className={classNames("mt-6", embedType === "inline" ? "block" : "hidden")}>
{/*TODO: Add Auto/Fixed toggle from Figma */}
<div className="text-sm">Embed Window Sizing</div>
<div className="justify-left flex items-center">
<TextField
name="width"
labelProps={{ className: "hidden" }}
required
value={previewState.inline.width}
onChange={(e) => {
setPreviewState((previewState) => {
2022-05-17 20:43:27 +00:00
const width = e.target.value || "100%";
return {
...previewState,
inline: {
...previewState.inline,
width,
},
};
});
}}
addOnLeading={<InputLeading>W</InputLeading>}
/>
2022-07-27 02:24:00 +00:00
<span className="p-2">×</span>
<TextField
labelProps={{ className: "hidden" }}
name="height"
value={previewState.inline.height}
required
onChange={(e) => {
const height = e.target.value || "100%";
setPreviewState((previewState) => {
return {
...previewState,
inline: {
...previewState.inline,
height,
},
};
});
}}
addOnLeading={<InputLeading>H</InputLeading>}
/>
</div>
</div>
<div
className={classNames(
"mt-4 items-center justify-between",
embedType === "floating-popup" ? "" : "hidden"
)}>
<div className="mb-2 text-sm">Button Text</div>
{/* Default Values should come from preview iframe */}
<TextField
name="buttonText"
labelProps={{ className: "hidden" }}
onChange={(e) => {
setPreviewState((previewState) => {
return {
...previewState,
floatingPopup: {
...previewState.floatingPopup,
buttonText: e.target.value,
},
};
});
}}
defaultValue="Book my Cal"
required
/>
</div>
<div
className={classNames(
"mt-4 flex items-center justify-start",
embedType === "floating-popup" ? "space-x-2" : "hidden"
)}>
<Switch
defaultChecked={true}
onCheckedChange={(checked) => {
setPreviewState((previewState) => {
return {
...previewState,
floatingPopup: {
...previewState.floatingPopup,
hideButtonIcon: !checked,
},
};
});
2022-07-13 21:14:16 +00:00
}}
/>
<div className="text-sm">Display Calendar Icon Button</div>
</div>
<div
className={classNames(
"mt-4 items-center justify-between",
embedType === "floating-popup" ? "" : "hidden"
)}>
<div className="mb-2">Position of Button</div>
<Select
onChange={(position) => {
setPreviewState((previewState) => {
return {
...previewState,
floatingPopup: {
...previewState.floatingPopup,
buttonPosition: position?.value,
},
};
});
}}
defaultValue={FloatingPopupPositionOptions[0]}
2022-07-13 21:14:16 +00:00
options={FloatingPopupPositionOptions}
/>
</div>
<div className={classNames("mt-4", embedType === "floating-popup" ? "" : "hidden")}>
<div>Button Color</div>
<div className="w-full">
<ColorPicker
defaultValue="#000000"
onChange={(color) => {
setPreviewState((previewState) => {
return {
...previewState,
floatingPopup: {
...previewState.floatingPopup,
buttonColor: color,
},
};
});
2022-07-13 21:14:16 +00:00
}}
/>
</div>
</div>
<div className={classNames("mt-4", embedType === "floating-popup" ? "" : "hidden")}>
<div>Text Color</div>
<div className="w-full">
<ColorPicker
defaultValue="#000000"
onChange={(color) => {
setPreviewState((previewState) => {
return {
...previewState,
floatingPopup: {
...previewState.floatingPopup,
buttonTextColor: color,
},
};
});
2022-07-13 21:14:16 +00:00
}}
/>
</div>
</div>
</CollapsibleContent>
</Collapsible>
</div>
2022-07-13 21:14:16 +00:00
<hr className="mt-4" />
<div className="mt-4 font-medium">
<Collapsible
open={isBookingCustomizationOpen}
onOpenChange={() => setIsBookingCustomizationOpen((val) => !val)}>
<CollapsibleTrigger className="flex w-full" type="button">
<div className="text-base font-medium text-neutral-900">Cal Booking Customization</div>
<Icon.FiChevronRight
className={`${
isBookingCustomizationOpen ? "rotate-90 transform" : ""
} ml-auto h-5 w-5 text-neutral-500`}
/>
</CollapsibleTrigger>
<CollapsibleContent>
<div className="mt-6 text-sm">
<Label className="">
<div className="mb-2">Theme</div>
<Select
className="w-full"
defaultValue={ThemeOptions[0]}
components={{
Control: ThemeSelectControl,
}}
onChange={(option) => {
if (!option) {
return;
}
setPreviewState((previewState) => {
return {
...previewState,
theme: option.value,
};
});
}}
2022-07-13 21:14:16 +00:00
options={ThemeOptions}
/>
</Label>
{[
{ name: "brandColor", title: "Brand Color" },
// { name: "lightColor", title: "Light Color" },
// { name: "lighterColor", title: "Lighter Color" },
// { name: "lightestColor", title: "Lightest Color" },
// { name: "highlightColor", title: "Highlight Color" },
// { name: "medianColor", title: "Median Color" },
].map((palette) => (
<Label key={palette.name} className="pb-4">
<div className="mb-2 pt-2">{palette.title}</div>
<div className="w-full">
<ColorPicker
defaultValue="#000000"
onChange={(color) => {
addToPalette({
2022-05-17 20:43:27 +00:00
[palette.name as keyof typeof previewState["palette"]]: color,
});
2022-05-17 20:43:27 +00:00
}}
/>
</div>
</Label>
))}
</div>
</CollapsibleContent>
</Collapsible>
</div>
</div>
<div className="flex w-2/3 flex-col p-8">
<HorizontalTabs data-testid="embed-tabs" tabs={parsedTabs} linkProps={{ shallow: true }} />
{tabs.map((tab) => {
return (
<div
key={tab.href}
2022-09-19 09:47:46 +00:00
className={classNames(
router.query.embedTabName === tab.href.split("=")[1] ? "flex flex-grow flex-col" : "hidden"
)}>
<div className="flex h-[55vh] flex-grow flex-col">
{tab.type === "code" ? (
<tab.Component
embedType={embedType}
calLink={calLink}
previewState={previewState}
ref={refOfEmbedCodesRefs.current[tab.name]}
/>
) : (
<tab.Component
embedType={embedType}
calLink={calLink}
previewState={previewState}
ref={iframeRef}
/>
)}
</div>
<div className={router.query.embedTabName == "embed-preview" ? "block" : "hidden"} />
<div className="mt-8 flex flex-row-reverse gap-x-2">
{tab.type === "code" ? (
<Button
type="submit"
onClick={() => {
const currentTabCodeEl = refOfEmbedCodesRefs.current[tab.name].current;
if (!currentTabCodeEl) {
return;
}
navigator.clipboard.writeText(currentTabCodeEl.value);
showToast(t("code_copied"), "success");
}}>
{t("copy_code")}
</Button>
) : null}
<DialogClose asChild>
<Button color="secondary">{t("Close")}</Button>
</DialogClose>
</div>
</div>
);
})}
</div>
</div>
</DialogContent>
);
};
export const EmbedDialog = () => {
const router = useRouter();
const embedUrl: string = router.query.embedUrl as string;
return (
<Dialog
name="embed"
clearQueryParamsOnClose={queryParamsForDialog}
onOpenChange={(open) => {
if (!open) window.resetEmbedStatus();
}}>
{!router.query.embedType ? (
<ChooseEmbedTypesDialogContent />
) : (
<EmbedTypeCodeAndPreviewDialogContent
embedType={router.query.embedType as EmbedType}
embedUrl={embedUrl}
/>
)}
</Dialog>
);
};
type EmbedButtonProps<T> = {
embedUrl: string;
children?: React.ReactNode;
V2.0 - Routing Forms and Shell 2.0 everywhere (#3902) * Add duplicate form support * Fix duplication logic * Change to feathericons everywhere and other fixes * Dont allow routes for fallback route * Fix banner * Fix Empty Screen * Text area + embded window fixes * Semi fix avatar * Fix all TS issues * Fix tests * Troubleshoot container + Active on count * Support routing using query params * Improve mobile * NITS * Fix padding on input * Support multiselect in router endpoint * Fix the issue where app goes in embed mode after viewing embed once * Fix icons * Add router url tests * Add Responses download and form toggling tests * Add required validation test * Change Icons everywhere * App typeform app * Improvements in cli * Starting to move event types settings to tabs * Begin migration to single page form * Single page tabs * Limits Page * Advanced tab * Add RHF to dependancies * Add typeform how-to-use page * Add typeform how-to-use page and screenshots * Most of advanced tab * Solved RHF mismtach * Build fixes * RHF conditionals fixes * Improved legibility * Fix TS error * Add missing image * Update CliApp.tsx * Major refactor/organisation into optional V2 UI * Portal EditLocationModal * Fix dialoug form * Update imports * Auto Animate + custom inputs WIP * Custom Inputs * WIP Apps * Fixing stories imports * Stripe app * Remove duplicate dialog * Remove duplicate dialog * Major locations cleanup, 10s of bug fixes and app-store improvements * Fix missing pieces * More fixes * Fix embed URL * Fix app toggles + number of active apps * Fix container padding on disabledBorder prop * Removes strict * more fixes * EventType Team page WIP * Fix embed * Use new Shell * NIT * Add Darkmode gray color * V2 Shell WIP * Fix headings on shell V2 * Fix mobile layout with V2 shell * V2 create event type button * Checked Team Select * Hidden to happen on save - not on toggle * Team Attendee Select animation * Get form-edit page working * Get route-builder page working * Fix scheduling type and remove multi select label * Fix overflow on teams url * Get UI as per designs for form-edit * Make route-builder upto date with design * Add no responses banner * Update forms list as per designs * Button shouldnt decide where it would be positioned, users of it might have different requirements * A single select box in a row(when no other select boxes are present) wasnt taking the correct width in comparison to when it had other select boxes * Small missing pieces * Revert console * Revert api * Fixes * Fix Embed TS errors * Fix TS errors * Fix Eslint errors * Fix TS errors for UI * Fix ESLINT error * Fix TS errors * Add missing import * Fix CLI * Add a default placeholder * Remove hardcoded daily:integrations * Fix message for payment page * Revert api and console to main * Update README * Fix TS errors * Fix Lint warnings * Fix Tests * Streamline actions and make them easy to manage * A much more simplified approach to implementing actions * Fix embed * Fix most TS errors * Fix more TS errors * Reduce TS errors to zero * Fix tests * Fix UI * Fix UI * Self review fixes * TS failures caught merge issues * Security hardening * Use V2 Shell everywhere * Add missing file * Problems created by new shell fixed * Fix Shell * Fix Routing Form Card up and down positons * Fix Embed and other design fixes * Fix dropdown old event-types * Fix type errors * Fix allowed chek * Fix dropdown not closing on clicking EMbed button * Fix dropdown not closing on embed button * Fix event-type button group layout * Add label for switch * Fix dropdown in mobile mode * Remove useless comments * Login with pro for tests * Remove bg gray till App-Store pages are revamped Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: zomars <zomars@me.com>
2022-09-02 19:00:41 +00:00
className?: string;
as?: T;
};
export const EmbedButton = <T extends React.ElementType>({
embedUrl,
2022-07-27 02:24:00 +00:00
children,
className = "",
as,
...props
}: EmbedButtonProps<T> & React.ComponentPropsWithoutRef<T>) => {
const router = useRouter();
V2.0 - Routing Forms and Shell 2.0 everywhere (#3902) * Add duplicate form support * Fix duplication logic * Change to feathericons everywhere and other fixes * Dont allow routes for fallback route * Fix banner * Fix Empty Screen * Text area + embded window fixes * Semi fix avatar * Fix all TS issues * Fix tests * Troubleshoot container + Active on count * Support routing using query params * Improve mobile * NITS * Fix padding on input * Support multiselect in router endpoint * Fix the issue where app goes in embed mode after viewing embed once * Fix icons * Add router url tests * Add Responses download and form toggling tests * Add required validation test * Change Icons everywhere * App typeform app * Improvements in cli * Starting to move event types settings to tabs * Begin migration to single page form * Single page tabs * Limits Page * Advanced tab * Add RHF to dependancies * Add typeform how-to-use page * Add typeform how-to-use page and screenshots * Most of advanced tab * Solved RHF mismtach * Build fixes * RHF conditionals fixes * Improved legibility * Fix TS error * Add missing image * Update CliApp.tsx * Major refactor/organisation into optional V2 UI * Portal EditLocationModal * Fix dialoug form * Update imports * Auto Animate + custom inputs WIP * Custom Inputs * WIP Apps * Fixing stories imports * Stripe app * Remove duplicate dialog * Remove duplicate dialog * Major locations cleanup, 10s of bug fixes and app-store improvements * Fix missing pieces * More fixes * Fix embed URL * Fix app toggles + number of active apps * Fix container padding on disabledBorder prop * Removes strict * more fixes * EventType Team page WIP * Fix embed * Use new Shell * NIT * Add Darkmode gray color * V2 Shell WIP * Fix headings on shell V2 * Fix mobile layout with V2 shell * V2 create event type button * Checked Team Select * Hidden to happen on save - not on toggle * Team Attendee Select animation * Get form-edit page working * Get route-builder page working * Fix scheduling type and remove multi select label * Fix overflow on teams url * Get UI as per designs for form-edit * Make route-builder upto date with design * Add no responses banner * Update forms list as per designs * Button shouldnt decide where it would be positioned, users of it might have different requirements * A single select box in a row(when no other select boxes are present) wasnt taking the correct width in comparison to when it had other select boxes * Small missing pieces * Revert console * Revert api * Fixes * Fix Embed TS errors * Fix TS errors * Fix Eslint errors * Fix TS errors for UI * Fix ESLINT error * Fix TS errors * Add missing import * Fix CLI * Add a default placeholder * Remove hardcoded daily:integrations * Fix message for payment page * Revert api and console to main * Update README * Fix TS errors * Fix Lint warnings * Fix Tests * Streamline actions and make them easy to manage * A much more simplified approach to implementing actions * Fix embed * Fix most TS errors * Fix more TS errors * Reduce TS errors to zero * Fix tests * Fix UI * Fix UI * Self review fixes * TS failures caught merge issues * Security hardening * Use V2 Shell everywhere * Add missing file * Problems created by new shell fixed * Fix Shell * Fix Routing Form Card up and down positons * Fix Embed and other design fixes * Fix dropdown old event-types * Fix type errors * Fix allowed chek * Fix dropdown not closing on clicking EMbed button * Fix dropdown not closing on embed button * Fix event-type button group layout * Add label for switch * Fix dropdown in mobile mode * Remove useless comments * Login with pro for tests * Remove bg gray till App-Store pages are revamped Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: zomars <zomars@me.com>
2022-09-02 19:00:41 +00:00
className = classNames(className, "hidden lg:inline-flex");
const openEmbedModal = () => {
2022-09-19 09:47:46 +00:00
goto(router, {
dialog: "embed",
embedUrl,
});
};
const Component = as ?? Button;
return (
<Component
{...props}
className={className}
data-test-embed-url={embedUrl}
data-testid="embed"
V2.0 - Routing Forms and Shell 2.0 everywhere (#3902) * Add duplicate form support * Fix duplication logic * Change to feathericons everywhere and other fixes * Dont allow routes for fallback route * Fix banner * Fix Empty Screen * Text area + embded window fixes * Semi fix avatar * Fix all TS issues * Fix tests * Troubleshoot container + Active on count * Support routing using query params * Improve mobile * NITS * Fix padding on input * Support multiselect in router endpoint * Fix the issue where app goes in embed mode after viewing embed once * Fix icons * Add router url tests * Add Responses download and form toggling tests * Add required validation test * Change Icons everywhere * App typeform app * Improvements in cli * Starting to move event types settings to tabs * Begin migration to single page form * Single page tabs * Limits Page * Advanced tab * Add RHF to dependancies * Add typeform how-to-use page * Add typeform how-to-use page and screenshots * Most of advanced tab * Solved RHF mismtach * Build fixes * RHF conditionals fixes * Improved legibility * Fix TS error * Add missing image * Update CliApp.tsx * Major refactor/organisation into optional V2 UI * Portal EditLocationModal * Fix dialoug form * Update imports * Auto Animate + custom inputs WIP * Custom Inputs * WIP Apps * Fixing stories imports * Stripe app * Remove duplicate dialog * Remove duplicate dialog * Major locations cleanup, 10s of bug fixes and app-store improvements * Fix missing pieces * More fixes * Fix embed URL * Fix app toggles + number of active apps * Fix container padding on disabledBorder prop * Removes strict * more fixes * EventType Team page WIP * Fix embed * Use new Shell * NIT * Add Darkmode gray color * V2 Shell WIP * Fix headings on shell V2 * Fix mobile layout with V2 shell * V2 create event type button * Checked Team Select * Hidden to happen on save - not on toggle * Team Attendee Select animation * Get form-edit page working * Get route-builder page working * Fix scheduling type and remove multi select label * Fix overflow on teams url * Get UI as per designs for form-edit * Make route-builder upto date with design * Add no responses banner * Update forms list as per designs * Button shouldnt decide where it would be positioned, users of it might have different requirements * A single select box in a row(when no other select boxes are present) wasnt taking the correct width in comparison to when it had other select boxes * Small missing pieces * Revert console * Revert api * Fixes * Fix Embed TS errors * Fix TS errors * Fix Eslint errors * Fix TS errors for UI * Fix ESLINT error * Fix TS errors * Add missing import * Fix CLI * Add a default placeholder * Remove hardcoded daily:integrations * Fix message for payment page * Revert api and console to main * Update README * Fix TS errors * Fix Lint warnings * Fix Tests * Streamline actions and make them easy to manage * A much more simplified approach to implementing actions * Fix embed * Fix most TS errors * Fix more TS errors * Reduce TS errors to zero * Fix tests * Fix UI * Fix UI * Self review fixes * TS failures caught merge issues * Security hardening * Use V2 Shell everywhere * Add missing file * Problems created by new shell fixed * Fix Shell * Fix Routing Form Card up and down positons * Fix Embed and other design fixes * Fix dropdown old event-types * Fix type errors * Fix allowed chek * Fix dropdown not closing on clicking EMbed button * Fix dropdown not closing on embed button * Fix event-type button group layout * Add label for switch * Fix dropdown in mobile mode * Remove useless comments * Login with pro for tests * Remove bg gray till App-Store pages are revamped Co-authored-by: sean-brydon <55134778+sean-brydon@users.noreply.github.com> Co-authored-by: Peer Richelsen <peeroke@gmail.com> Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: zomars <zomars@me.com>
2022-09-02 19:00:41 +00:00
type="button"
onClick={() => {
openEmbedModal();
}}>
2022-07-27 02:24:00 +00:00
{children}
</Component>
);
};