tailwind prettier (#1646)
* tailwind prettier * Minor fixes * Sorts components and pages Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: zomars <zomars@me.com>pull/1764/head
parent
1e9234ea67
commit
51d553559f
|
@ -9,4 +9,5 @@ module.exports = {
|
|||
arrowParens: "always",
|
||||
importOrder: ["^@ee/(.*)$", "^@lib/(.*)$", "^@components/(.*)$", "^@(server|trpc)/(.*)$", "^[./]"],
|
||||
importOrderSeparation: true,
|
||||
plugins: [require("prettier-plugin-tailwindcss")],
|
||||
};
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
"esbenp.prettier-vscode", // prettier plugin
|
||||
"dbaeumer.vscode-eslint", // eslint plugin
|
||||
"bradlc.vscode-tailwindcss", // hinting / autocompletion for tailwind
|
||||
"heybourn.headwind", // automatically sort tailwind classes in predictable order, kinda like "prettier for tailwind",
|
||||
"ban.spellright", // Spell check for docs
|
||||
"stripe.vscode-stripe" // stripe VSCode extension
|
||||
]
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
declare module "@wojtekmaj/react-daterange-picker/dist/entry.nostyle" {
|
||||
import { CalendarProps } from "react-calendar";
|
||||
export type DateRangePickerCalendarProps = Omit<
|
||||
CalendarProps,
|
||||
"calendarClassName" | "onChange" | "value"
|
||||
> & {
|
||||
calendarClassName?: string;
|
||||
onChange: (value: [Date, Date]) => void;
|
||||
value: [Date, Date];
|
||||
clearIcon: JSX.Element | null;
|
||||
calendarIcon: JSX.Element | null;
|
||||
rangeDivider: JSX.Element | null;
|
||||
};
|
||||
export default function DateRangePicker(props: DateRangePickerCalendarProps): JSX.Element;
|
||||
}
|
|
@ -14,13 +14,13 @@ export default function AddToHomescreen() {
|
|||
}
|
||||
return !closeBanner ? (
|
||||
<div className="fixed inset-x-0 bottom-0 pb-2 sm:hidden sm:pb-5">
|
||||
<div className="px-2 mx-auto max-w-7xl sm:px-6 lg:px-8">
|
||||
<div className="p-2 rounded-lg shadow-lg sm:p-3" style={{ background: "#2F333D" }}>
|
||||
<div className="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8">
|
||||
<div className="rounded-lg p-2 shadow-lg sm:p-3" style={{ background: "#2F333D" }}>
|
||||
<div className="flex flex-wrap items-center justify-between">
|
||||
<div className="flex items-center flex-1 w-0">
|
||||
<span className="flex p-2 rounded-lg bg-opacity-30 bg-brand text-brandcontrast">
|
||||
<div className="flex w-0 flex-1 items-center">
|
||||
<span className="flex rounded-lg bg-brand bg-opacity-30 p-2 text-brandcontrast">
|
||||
<svg
|
||||
className="text-indigo-500 fill-current h-7 w-7"
|
||||
className="h-7 w-7 fill-current text-indigo-500"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 50 50"
|
||||
enableBackground="new 0 0 50 50">
|
||||
|
@ -34,13 +34,13 @@ export default function AddToHomescreen() {
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex-shrink-0 order-2 sm:order-3">
|
||||
<div className="order-2 flex-shrink-0 sm:order-3">
|
||||
<button
|
||||
onClick={() => setCloseBanner(true)}
|
||||
type="button"
|
||||
className="flex p-2 -mr-1 rounded-md hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-white">
|
||||
className="-mr-1 flex rounded-md p-2 hover:bg-gray-800 focus:outline-none focus:ring-2 focus:ring-white">
|
||||
<span className="sr-only">{t("dismiss")}</span>
|
||||
<XIcon className="w-6 h-6 text-white" aria-hidden="true" />
|
||||
<XIcon className="h-6 w-6 text-white" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -56,8 +56,8 @@ const DestinationCalendarSelector = ({
|
|||
<div className="relative">
|
||||
{/* There's no easy way to customize the displayed value for a Select, so we fake it. */}
|
||||
{!hidePlaceholder && (
|
||||
<div className="absolute z-10 pointer-events-none">
|
||||
<Button size="sm" color="secondary" className="border-transparent m-[1px] rounded-sm">
|
||||
<div className="pointer-events-none absolute z-10">
|
||||
<Button size="sm" color="secondary" className="m-[1px] rounded-sm border-transparent">
|
||||
{t("select_destination_calendar")}: {selectedOption?.label || ""}
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -67,7 +67,7 @@ const DestinationCalendarSelector = ({
|
|||
placeholder={!hidePlaceholder ? `${t("select_destination_calendar")}:` : undefined}
|
||||
options={options}
|
||||
isSearchable={false}
|
||||
className="flex-1 block w-full min-w-0 mt-1 mb-2 border-gray-300 rounded-none focus:ring-primary-500 focus:border-primary-500 rounded-r-md sm:text-sm"
|
||||
className="mt-1 mb-2 block w-full min-w-0 flex-1 rounded-none rounded-r-md border-gray-300 focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
|
||||
onChange={(option) => {
|
||||
setSelectedOption(option);
|
||||
if (!option) {
|
||||
|
|
|
@ -6,7 +6,7 @@ export function Dialog(props: DialogProps) {
|
|||
const { children, ...other } = props;
|
||||
return (
|
||||
<DialogPrimitive.Root {...other}>
|
||||
<DialogPrimitive.Overlay className="fixed inset-0 transition-opacity bg-gray-500 bg-opacity-75" />
|
||||
<DialogPrimitive.Overlay className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
|
||||
{children}
|
||||
</DialogPrimitive.Root>
|
||||
);
|
||||
|
@ -17,7 +17,7 @@ export const DialogContent = React.forwardRef<HTMLDivElement, DialogContentProps
|
|||
({ children, ...props }, forwardedRef) => (
|
||||
<DialogPrimitive.Content
|
||||
{...props}
|
||||
className="min-w-[360px] fixed left-1/2 top-1/2 p-6 text-left bg-white rounded shadow-xl -translate-x-1/2 -translate-y-1/2 sm:align-middle sm:w-full sm:max-w-lg"
|
||||
className="fixed left-1/2 top-1/2 min-w-[360px] -translate-x-1/2 -translate-y-1/2 rounded bg-white p-6 text-left shadow-xl sm:w-full sm:max-w-lg sm:align-middle"
|
||||
ref={forwardedRef}>
|
||||
{children}
|
||||
</DialogPrimitive.Content>
|
||||
|
@ -32,7 +32,7 @@ type DialogHeaderProps = {
|
|||
export function DialogHeader(props: DialogHeaderProps) {
|
||||
return (
|
||||
<div className="mb-8">
|
||||
<h3 className="text-xl text-gray-900 leading-16 font-cal" id="modal-title">
|
||||
<h3 className="leading-16 font-cal text-xl text-gray-900" id="modal-title">
|
||||
{props.title}
|
||||
</h3>
|
||||
{props.subtitle && <div className="text-sm text-gray-400">{props.subtitle}</div>}
|
||||
|
@ -43,7 +43,7 @@ export function DialogHeader(props: DialogHeaderProps) {
|
|||
export function DialogFooter(props: { children: ReactNode }) {
|
||||
return (
|
||||
<div>
|
||||
<div className="flex justify-end mt-5 rtl:space-x-reverse space-x-2">{props.children}</div>
|
||||
<div className="mt-5 flex justify-end space-x-2 rtl:space-x-reverse">{props.children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,12 +13,12 @@ export default function EmptyScreen({
|
|||
}) {
|
||||
return (
|
||||
<>
|
||||
<div className="min-h-80 border border-dashed rounded-sm flex justify-center items-center flex-col my-6">
|
||||
<div className="bg-white w-[72px] h-[72px] flex justify-center items-center rounded-full">
|
||||
<Icon className="inline-block w-10 h-10 bg-white" />
|
||||
<div className="my-6 flex min-h-80 flex-col items-center justify-center rounded-sm border border-dashed">
|
||||
<div className="flex h-[72px] w-[72px] items-center justify-center rounded-full bg-white">
|
||||
<Icon className="inline-block h-10 w-10 bg-white" />
|
||||
</div>
|
||||
<div className="max-w-[420px] text-center">
|
||||
<h2 className="text-lg font-medium mt-6 mb-1">{headline}</h2>
|
||||
<h2 className="mt-6 mb-1 text-lg font-medium">{headline}</h2>
|
||||
<p className="text-sm leading-6 text-gray-600">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -38,8 +38,8 @@ function CropContainer({
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="w-40 h-40 rounded-full crop-container max-h-40">
|
||||
<div className="relative w-40 h-40 rounded-full">
|
||||
<div className="crop-container h-40 max-h-40 w-40 rounded-full">
|
||||
<div className="relative h-40 w-40 rounded-full">
|
||||
<Cropper
|
||||
image={imageSrc}
|
||||
crop={crop}
|
||||
|
@ -119,38 +119,38 @@ export default function ImageUploader({
|
|||
<DialogContent>
|
||||
<div className="mb-4 sm:flex sm:items-start">
|
||||
<div className="mt-3 text-center sm:mt-0 sm:text-left">
|
||||
<h3 className="text-lg font-bold leading-6 text-gray-900 font-cal" id="modal-title">
|
||||
<h3 className="font-cal text-lg font-bold leading-6 text-gray-900" id="modal-title">
|
||||
{t("upload_target", { target })}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<div className="flex flex-col items-center justify-center p-8 mt-6 cropper">
|
||||
<div className="cropper mt-6 flex flex-col items-center justify-center p-8">
|
||||
{!result && (
|
||||
<div className="flex items-center justify-start w-20 h-20 bg-gray-50 rounded-full max-h-20">
|
||||
<div className="flex h-20 max-h-20 w-20 items-center justify-start rounded-full bg-gray-50">
|
||||
{!imageSrc && (
|
||||
<p className="w-full text-sm text-center text-white sm:text-xs">
|
||||
<p className="w-full text-center text-sm text-white sm:text-xs">
|
||||
{t("no_target", { target })}
|
||||
</p>
|
||||
)}
|
||||
{imageSrc && <img className="w-20 h-20 rounded-full" src={imageSrc} alt={target} />}
|
||||
{imageSrc && <img className="h-20 w-20 rounded-full" src={imageSrc} alt={target} />}
|
||||
</div>
|
||||
)}
|
||||
{result && <CropContainer imageSrc={result as string} onCropComplete={setCroppedAreaPixels} />}
|
||||
<label className="px-3 py-1 mt-8 text-xs font-medium leading-4 text-gray-700 bg-white border border-gray-300 rounded-sm hover:bg-gray-50 hover:text-gray-900 hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-1 focus:ring-neutral-900 dark:bg-transparent dark:text-white dark:border-gray-800 dark:hover:bg-gray-900">
|
||||
<label className="mt-8 rounded-sm border border-gray-300 bg-white px-3 py-1 text-xs font-medium leading-4 text-gray-700 hover:bg-gray-50 hover:text-gray-900 hover:shadow-sm focus:outline-none focus:ring-2 focus:ring-neutral-900 focus:ring-offset-1 dark:border-gray-800 dark:bg-transparent dark:text-white dark:hover:bg-gray-900">
|
||||
<input
|
||||
onInput={onInputFile}
|
||||
type="file"
|
||||
name={id}
|
||||
placeholder={t("upload_image")}
|
||||
className="absolute mt-4 opacity-0 pointer-events-none"
|
||||
className="pointer-events-none absolute mt-4 opacity-0"
|
||||
accept="image/*"
|
||||
/>
|
||||
{t("choose_a_file")}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse gap-x-2">
|
||||
<div className="mt-5 gap-x-2 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||
<DialogClose asChild>
|
||||
<Button onClick={() => showCroppedImage(croppedAreaPixels)}>{t("save")}</Button>
|
||||
</DialogClose>
|
||||
|
|
|
@ -5,7 +5,7 @@ import classNames from "@lib/classNames";
|
|||
|
||||
export function List(props: JSX.IntrinsicElements["ul"]) {
|
||||
return (
|
||||
<ul {...props} className={classNames("sm:overflow-hidden rounded-sm sm:mx-0 -mx-4", props.className)}>
|
||||
<ul {...props} className={classNames("-mx-4 rounded-sm sm:mx-0 sm:overflow-hidden", props.className)}>
|
||||
{props.children}
|
||||
</ul>
|
||||
);
|
||||
|
|
|
@ -3,7 +3,7 @@ export default function Logo({ small, icon }: { small?: boolean; icon?: boolean
|
|||
<h1 className="inline">
|
||||
<strong>
|
||||
{icon ? (
|
||||
<img className="w-9 mx-auto" alt="Cal" title="Cal" src="/cal-com-icon-white.svg" />
|
||||
<img className="mx-auto w-9" alt="Cal" title="Cal" src="/cal-com-icon-white.svg" />
|
||||
) : (
|
||||
<img
|
||||
className={small ? "h-4 w-auto" : "h-5 w-auto"}
|
||||
|
|
|
@ -18,7 +18,7 @@ const NavTabs: FC<Props> = ({ tabs, linkProps }) => {
|
|||
return (
|
||||
<>
|
||||
<nav
|
||||
className="flex -mb-px space-x-2 space-x-5 rtl:space-x-reverse sm:rtl:space-x-reverse"
|
||||
className="-mb-px flex space-x-2 space-x-5 rtl:space-x-reverse sm:rtl:space-x-reverse"
|
||||
aria-label="Tabs">
|
||||
{tabs.map((tab) => {
|
||||
const isCurrent = router.asPath === tab.href;
|
||||
|
@ -28,15 +28,15 @@ const NavTabs: FC<Props> = ({ tabs, linkProps }) => {
|
|||
className={classNames(
|
||||
isCurrent
|
||||
? "border-neutral-900 text-neutral-900"
|
||||
: "border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300",
|
||||
"group inline-flex items-center py-4 px-1 border-b-2 font-medium text-sm"
|
||||
: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700",
|
||||
"group inline-flex items-center border-b-2 py-4 px-1 text-sm font-medium"
|
||||
)}
|
||||
aria-current={isCurrent ? "page" : undefined}>
|
||||
{tab.icon && (
|
||||
<tab.icon
|
||||
className={classNames(
|
||||
isCurrent ? "text-neutral-900" : "text-gray-400 group-hover:text-gray-500",
|
||||
"-ml-0.5 ltr:mr-2 rtl:ml-2 h-5 w-5 hidden sm:inline-block"
|
||||
"-ml-0.5 hidden h-5 w-5 ltr:mr-2 rtl:ml-2 sm:inline-block"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
|
|
@ -104,12 +104,12 @@ export function ShellSubHeading(props: {
|
|||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={classNames("block sm:flex justify-between mb-3", props.className)}>
|
||||
<div className={classNames("mb-3 block justify-between sm:flex", props.className)}>
|
||||
<div>
|
||||
<h2 className="flex items-center content-center space-x-2 text-base font-bold leading-6 text-gray-900 rtl:space-x-reverse">
|
||||
<h2 className="flex content-center items-center space-x-2 text-base font-bold leading-6 text-gray-900 rtl:space-x-reverse">
|
||||
{props.title}
|
||||
</h2>
|
||||
{props.subtitle && <p className="text-sm ltr:mr-4 text-neutral-500">{props.subtitle}</p>}
|
||||
{props.subtitle && <p className="text-sm text-neutral-500 ltr:mr-4">{props.subtitle}</p>}
|
||||
</div>
|
||||
{props.actions && <div className="flex-shrink-0">{props.actions}</div>}
|
||||
</div>
|
||||
|
@ -184,7 +184,7 @@ export default function Shell(props: {
|
|||
if (i18n.status === "loading" || isRedirectingToOnboarding || loading) {
|
||||
// show spinner whilst i18n is loading to avoid language flicker
|
||||
return (
|
||||
<div className="absolute z-50 flex items-center w-full h-screen bg-gray-50">
|
||||
<div className="absolute z-50 flex h-screen w-full items-center bg-gray-50">
|
||||
<Loader />
|
||||
</div>
|
||||
);
|
||||
|
@ -206,9 +206,9 @@ export default function Shell(props: {
|
|||
|
||||
<div className="flex h-screen overflow-hidden bg-gray-100" data-testid="dashboard-shell">
|
||||
<div className="hidden md:flex lg:flex-shrink-0">
|
||||
<div className="flex flex-col w-14 lg:w-56">
|
||||
<div className="flex flex-col flex-1 h-0 bg-white border-r border-gray-200">
|
||||
<div className="flex flex-col flex-1 pt-3 pb-4 overflow-y-auto lg:pt-5">
|
||||
<div className="flex w-14 flex-col lg:w-56">
|
||||
<div className="flex h-0 flex-1 flex-col border-r border-gray-200 bg-white">
|
||||
<div className="flex flex-1 flex-col overflow-y-auto pt-3 pb-4 lg:pt-5">
|
||||
<Link href="/event-types">
|
||||
<a className="px-4 md:hidden lg:inline">
|
||||
<Logo small />
|
||||
|
@ -220,7 +220,7 @@ export default function Shell(props: {
|
|||
<Logo small icon />
|
||||
</a>
|
||||
</Link>
|
||||
<nav className="flex-1 px-2 mt-2 space-y-1 bg-white lg:mt-5">
|
||||
<nav className="mt-2 flex-1 space-y-1 bg-white px-2 lg:mt-5">
|
||||
{navigation.map((item) => (
|
||||
<Link key={item.name} href={item.href}>
|
||||
<a
|
||||
|
@ -228,14 +228,14 @@ export default function Shell(props: {
|
|||
item.current
|
||||
? "bg-neutral-100 text-neutral-900"
|
||||
: "text-neutral-500 hover:bg-gray-50 hover:text-neutral-900",
|
||||
"group flex items-center px-2 py-2 text-sm font-medium rounded-sm"
|
||||
"group flex items-center rounded-sm px-2 py-2 text-sm font-medium"
|
||||
)}>
|
||||
<item.icon
|
||||
className={classNames(
|
||||
item.current
|
||||
? "text-neutral-500"
|
||||
: "text-neutral-400 group-hover:text-neutral-500",
|
||||
"ltr:mr-3 rtl:ml-3 flex-shrink-0 h-5 w-5"
|
||||
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
@ -246,7 +246,7 @@ export default function Shell(props: {
|
|||
</nav>
|
||||
</div>
|
||||
<TrialBanner />
|
||||
<div className="p-2 pt-2 pr-2 m-2 rounded-sm hover:bg-gray-100">
|
||||
<div className="m-2 rounded-sm p-2 pt-2 pr-2 hover:bg-gray-100">
|
||||
<span className="hidden lg:inline">
|
||||
<UserDropdown />
|
||||
</span>
|
||||
|
@ -258,25 +258,25 @@ export default function Shell(props: {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col flex-1 w-0 overflow-hidden">
|
||||
<div className="flex w-0 flex-1 flex-col overflow-hidden">
|
||||
<main
|
||||
className={classNames(
|
||||
"flex-1 relative z-0 overflow-y-auto focus:outline-none max-w-[1700px]",
|
||||
"relative z-0 max-w-[1700px] flex-1 overflow-y-auto focus:outline-none",
|
||||
props.flexChildrenContainer && "flex flex-col"
|
||||
)}>
|
||||
{/* show top navigation for md and smaller (tablet and phones) */}
|
||||
<nav className="flex items-center justify-between p-4 bg-white border-b border-gray-200 md:hidden">
|
||||
<nav className="flex items-center justify-between border-b border-gray-200 bg-white p-4 md:hidden">
|
||||
<Link href="/event-types">
|
||||
<a>
|
||||
<Logo />
|
||||
</a>
|
||||
</Link>
|
||||
<div className="flex items-center self-center gap-3">
|
||||
<button className="p-2 text-gray-400 bg-white rounded-full hover:text-gray-500 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black">
|
||||
<div className="flex items-center gap-3 self-center">
|
||||
<button className="rounded-full bg-white p-2 text-gray-400 hover:bg-gray-50 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2">
|
||||
<span className="sr-only">{t("view_notifications")}</span>
|
||||
<Link href="/settings/profile">
|
||||
<a>
|
||||
<CogIcon className="w-6 h-6" aria-hidden="true" />
|
||||
<CogIcon className="h-6 w-6" aria-hidden="true" />
|
||||
</a>
|
||||
</Link>
|
||||
</button>
|
||||
|
@ -285,8 +285,8 @@ export default function Shell(props: {
|
|||
</nav>
|
||||
<div
|
||||
className={classNames(
|
||||
props.centered && "md:max-w-5xl mx-auto",
|
||||
props.flexChildrenContainer && "flex flex-col flex-1",
|
||||
props.centered && "mx-auto md:max-w-5xl",
|
||||
props.flexChildrenContainer && "flex flex-1 flex-col",
|
||||
"py-8"
|
||||
)}>
|
||||
{!!props.backPath && (
|
||||
|
@ -299,25 +299,25 @@ export default function Shell(props: {
|
|||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div className="block sm:flex justify-between px-4 sm:px-6 md:px-8 min-h-[80px]">
|
||||
<div className="block min-h-[80px] justify-between px-4 sm:flex sm:px-6 md:px-8">
|
||||
{props.HeadingLeftIcon && <div className="ltr:mr-4">{props.HeadingLeftIcon}</div>}
|
||||
<div className="w-full mb-8">
|
||||
<h1 className="mb-1 text-xl font-bold tracking-wide text-gray-900 font-cal">
|
||||
<div className="mb-8 w-full">
|
||||
<h1 className="mb-1 font-cal text-xl font-bold tracking-wide text-gray-900">
|
||||
{props.heading}
|
||||
</h1>
|
||||
<p className="text-sm ltr:mr-4 rtl:ml-4 text-neutral-500">{props.subtitle}</p>
|
||||
<p className="text-sm text-neutral-500 ltr:mr-4 rtl:ml-4">{props.subtitle}</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0 mb-4">{props.CTA}</div>
|
||||
<div className="mb-4 flex-shrink-0">{props.CTA}</div>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
"px-4 sm:px-6 md:px-8",
|
||||
props.flexChildrenContainer && "flex flex-col flex-1"
|
||||
props.flexChildrenContainer && "flex flex-1 flex-col"
|
||||
)}>
|
||||
{props.children}
|
||||
</div>
|
||||
{/* show bottom navigation for md and smaller (tablet and phones) */}
|
||||
<nav className="fixed bottom-0 z-40 flex w-full bg-white shadow bottom-nav md:hidden">
|
||||
<nav className="bottom-nav fixed bottom-0 z-40 flex w-full bg-white shadow md:hidden">
|
||||
{/* note(PeerRich): using flatMap instead of map to remove settings from bottom nav */}
|
||||
{navigation.flatMap((item, itemIdx) =>
|
||||
item.href === "/settings/profile" ? (
|
||||
|
@ -329,13 +329,13 @@ export default function Shell(props: {
|
|||
item.current ? "text-gray-900" : "text-neutral-400 hover:text-gray-700",
|
||||
itemIdx === 0 ? "rounded-l-lg" : "",
|
||||
itemIdx === navigation.length - 1 ? "rounded-r-lg" : "",
|
||||
"group relative min-w-0 flex-1 overflow-hidden bg-white py-2 px-2 text-xs sm:text-sm font-medium text-center hover:bg-gray-50 focus:z-10"
|
||||
"group relative min-w-0 flex-1 overflow-hidden bg-white py-2 px-2 text-center text-xs font-medium hover:bg-gray-50 focus:z-10 sm:text-sm"
|
||||
)}
|
||||
aria-current={item.current ? "page" : undefined}>
|
||||
<item.icon
|
||||
className={classNames(
|
||||
item.current ? "text-gray-900" : "text-gray-400 group-hover:text-gray-500",
|
||||
"block mx-auto flex-shrink-0 h-5 w-5 mb-1 text-center"
|
||||
"mx-auto mb-1 block h-5 w-5 flex-shrink-0 text-center"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
@ -370,11 +370,11 @@ function UserDropdown({ small }: { small?: boolean }) {
|
|||
return (
|
||||
<Dropdown>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<div className="flex items-center w-full appearance-none cursor-pointer group">
|
||||
<div className="group flex w-full cursor-pointer appearance-none items-center">
|
||||
<span
|
||||
className={classNames(
|
||||
small ? "w-8 h-8" : "w-10 h-10",
|
||||
"bg-gray-300 rounded-full flex-shrink-0 relative ltr:mr-3 rtl:ml-3"
|
||||
small ? "h-8 w-8" : "h-10 w-10",
|
||||
"relative flex-shrink-0 rounded-full bg-gray-300 ltr:mr-3 rtl:ml-3"
|
||||
)}>
|
||||
<img
|
||||
className="rounded-full"
|
||||
|
@ -387,24 +387,24 @@ function UserDropdown({ small }: { small?: boolean }) {
|
|||
alt={user?.username || "Nameless User"}
|
||||
/>
|
||||
{!user?.away && (
|
||||
<div className="absolute bottom-0 right-0 w-3 h-3 bg-green-500 border-2 border-white rounded-full"></div>
|
||||
<div className="absolute bottom-0 right-0 h-3 w-3 rounded-full border-2 border-white bg-green-500"></div>
|
||||
)}
|
||||
{user?.away && (
|
||||
<div className="absolute bottom-0 right-0 w-3 h-3 bg-yellow-500 border-2 border-white rounded-full"></div>
|
||||
<div className="absolute bottom-0 right-0 h-3 w-3 rounded-full border-2 border-white bg-yellow-500"></div>
|
||||
)}
|
||||
</span>
|
||||
{!small && (
|
||||
<span className="flex items-center flex-grow truncate">
|
||||
<span className="flex-grow text-sm truncate">
|
||||
<span className="block font-medium text-gray-900 truncate">
|
||||
<span className="flex flex-grow items-center truncate">
|
||||
<span className="flex-grow truncate text-sm">
|
||||
<span className="block truncate font-medium text-gray-900">
|
||||
{user?.username || "Nameless User"}
|
||||
</span>
|
||||
<span className="block font-normal truncate text-neutral-500">
|
||||
<span className="block truncate font-normal text-neutral-500">
|
||||
{user?.username ? `cal.com/${user.username}` : "No public page"}
|
||||
</span>
|
||||
</span>
|
||||
<SelectorIcon
|
||||
className="flex-shrink-0 w-5 h-5 text-gray-400 group-hover:text-gray-500"
|
||||
className="h-5 w-5 flex-shrink-0 text-gray-400 group-hover:text-gray-500"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
|
@ -418,13 +418,13 @@ function UserDropdown({ small }: { small?: boolean }) {
|
|||
mutation.mutate({ away: !user?.away });
|
||||
utils.invalidateQueries("viewer.me");
|
||||
}}
|
||||
className="flex px-4 py-2 text-sm cursor-pointer hover:bg-gray-100 hover:text-gray-900">
|
||||
className="flex cursor-pointer px-4 py-2 text-sm hover:bg-gray-100 hover:text-gray-900">
|
||||
<MoonIcon
|
||||
className={classNames(
|
||||
user?.away
|
||||
? "text-purple-500 group-hover:text-purple-700"
|
||||
: "text-gray-500 group-hover:text-gray-700",
|
||||
"ltr:mr-3 rtl:ml-3 flex-shrink-0 h-5 w-5"
|
||||
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
@ -439,7 +439,7 @@ function UserDropdown({ small }: { small?: boolean }) {
|
|||
rel="noopener noreferrer"
|
||||
href={`${process.env.NEXT_PUBLIC_APP_URL}/${user.username}`}
|
||||
className="flex items-center px-4 py-2 text-sm text-gray-700">
|
||||
<ExternalLinkIcon className="w-5 h-5 text-gray-500 ltr:mr-3 rtl:ml-3" /> {t("view_public_page")}
|
||||
<ExternalLinkIcon className="h-5 w-5 text-gray-500 ltr:mr-3 rtl:ml-3" /> {t("view_public_page")}
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
@ -454,7 +454,7 @@ function UserDropdown({ small }: { small?: boolean }) {
|
|||
viewBox="0 0 2447.6 2452.5"
|
||||
className={classNames(
|
||||
"text-gray-500 group-hover:text-gray-700",
|
||||
"mt-0.5 ltr:mr-2 rtl:ml-2 flex-shrink-0 h-4 w-4"
|
||||
"mt-0.5 h-4 w-4 flex-shrink-0 ltr:mr-2 rtl:ml-2"
|
||||
)}
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g clipRule="evenodd" fillRule="evenodd">
|
||||
|
@ -481,7 +481,7 @@ function UserDropdown({ small }: { small?: boolean }) {
|
|||
rel="noopener noreferrer"
|
||||
href="https://cal.com/roadmap"
|
||||
className="flex items-center px-4 py-2 text-sm text-gray-700">
|
||||
<MapIcon className="w-5 h-5 text-gray-500 ltr:mr-3 rtl:ml-3" /> {t("visit_roadmap")}
|
||||
<MapIcon className="h-5 w-5 text-gray-500 ltr:mr-3 rtl:ml-3" /> {t("visit_roadmap")}
|
||||
</a>
|
||||
</DropdownMenuItem>
|
||||
<HelpMenuItemDynamic />
|
||||
|
@ -489,11 +489,11 @@ function UserDropdown({ small }: { small?: boolean }) {
|
|||
<DropdownMenuItem>
|
||||
<a
|
||||
onClick={() => signOut({ callbackUrl: "/auth/logout" })}
|
||||
className="flex px-4 py-2 text-sm cursor-pointer hover:bg-gray-100 hover:text-gray-900">
|
||||
className="flex cursor-pointer px-4 py-2 text-sm hover:bg-gray-100 hover:text-gray-900">
|
||||
<LogoutIcon
|
||||
className={classNames(
|
||||
"text-gray-500 group-hover:text-gray-700",
|
||||
"ltr:mr-3 rtl:ml-3 flex-shrink-0 h-5 w-5"
|
||||
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
|
|
@ -12,7 +12,7 @@ const Slider = ({
|
|||
changeHandler: (value: number) => void;
|
||||
}) => (
|
||||
<SliderPrimitive.Root
|
||||
className="mt-2 slider"
|
||||
className="slider mt-2"
|
||||
value={[value]}
|
||||
aria-label={label}
|
||||
onValueChange={(value: number[]) => changeHandler(value[0] ?? value)}
|
||||
|
|
|
@ -9,15 +9,15 @@ export type SwatchProps = {
|
|||
const Swatch = (props: SwatchProps) => {
|
||||
const { size, backgroundColor, onClick } = props;
|
||||
return (
|
||||
<div className="p-1 border-2 border-gray-200 shadow-sm">
|
||||
<div className="border-2 border-gray-200 p-1 shadow-sm">
|
||||
<div
|
||||
onClick={onClick}
|
||||
style={{ backgroundColor }}
|
||||
className={classNames(
|
||||
"cursor-pointer",
|
||||
size === "sm" && "w-6 h-6 rounded-sm",
|
||||
size === "base" && "w-16 h-16 rounded-sm",
|
||||
size === "lg" && "w-24 h-24 rounded-sm"
|
||||
size === "sm" && "h-6 w-6 rounded-sm",
|
||||
size === "base" && "h-16 w-16 rounded-sm",
|
||||
size === "lg" && "h-24 w-24 rounded-sm"
|
||||
)}></div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -23,7 +23,7 @@ export function Tooltip({
|
|||
onOpenChange={onOpenChange}>
|
||||
<TooltipPrimitive.Trigger asChild>{children}</TooltipPrimitive.Trigger>
|
||||
<TooltipPrimitive.Content
|
||||
className="bg-black text-xs -mt-2 text-white px-1 py-0.5 shadow-lg rounded-sm"
|
||||
className="-mt-2 rounded-sm bg-black px-1 py-0.5 text-xs text-white shadow-lg"
|
||||
side="top"
|
||||
align="center"
|
||||
{...props}>
|
||||
|
|
|
@ -35,7 +35,7 @@ export default function SAMLLogin(props: Props) {
|
|||
<Button
|
||||
color="secondary"
|
||||
data-testid={"saml"}
|
||||
className="flex justify-center w-full"
|
||||
className="flex w-full justify-center"
|
||||
onClick={async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ export default function TwoFactor() {
|
|||
const className = "h-12 w-12 !text-xl text-center";
|
||||
|
||||
return (
|
||||
<div className="max-w-sm mx-auto !mt-0">
|
||||
<div className="mx-auto !mt-0 max-w-sm">
|
||||
<p className="mb-4 text-sm text-gray-500">{t("2fa_enabled_instructions")}</p>
|
||||
<input hidden type="hidden" value={value} {...methods.register("totpCode")} />
|
||||
<div className="flex flex-row space-x-1">
|
||||
|
|
|
@ -55,8 +55,8 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col mt-8 text-center sm:pl-4 sm:mt-0 sm:w-1/3 md:-mb-5">
|
||||
<div className="mb-4 text-lg font-light text-left text-gray-600">
|
||||
<div className="mt-8 flex flex-col text-center sm:mt-0 sm:w-1/3 sm:pl-4 md:-mb-5">
|
||||
<div className="mb-4 text-left text-lg font-light text-gray-600">
|
||||
<span className="w-1/2 text-gray-600 dark:text-white">
|
||||
<strong>{date.toDate().toLocaleString(i18n.language, { weekday: "long" })}</strong>
|
||||
<span className="text-gray-500">
|
||||
|
@ -65,7 +65,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex-grow md:h-[364px] overflow-y-auto">
|
||||
<div className="flex-grow overflow-y-auto md:h-[364px]">
|
||||
{!loading &&
|
||||
slots?.length > 0 &&
|
||||
slots.map((slot) => {
|
||||
|
@ -95,7 +95,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||
<Link href={bookingUrl}>
|
||||
<a
|
||||
className={classNames(
|
||||
"block py-4 mb-2 font-medium bg-white border rounded-sm dark:bg-gray-600 text-primary-500 dark:text-neutral-200 dark:border-transparent hover:text-white hover:bg-brand hover:text-brandcontrast dark:hover:border-black dark:hover:bg-brand dark:hover:text-brandcontrast",
|
||||
"mb-2 block rounded-sm border bg-white py-4 font-medium text-primary-500 hover:bg-brand hover:text-white hover:text-brandcontrast dark:border-transparent dark:bg-gray-600 dark:text-neutral-200 dark:hover:border-black dark:hover:bg-brand dark:hover:text-brandcontrast",
|
||||
brand === "#fff" || brand === "#ffffff" ? "border-brandcontrast" : "border-brand"
|
||||
)}
|
||||
data-testid="time">
|
||||
|
@ -106,7 +106,7 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||
);
|
||||
})}
|
||||
{!loading && !error && !slots.length && (
|
||||
<div className="flex flex-col items-center content-center justify-center w-full h-full -mt-4">
|
||||
<div className="-mt-4 flex h-full w-full flex-col content-center items-center justify-center">
|
||||
<h1 className="my-6 text-xl text-black dark:text-white">{t("all_booked_today")}</h1>
|
||||
</div>
|
||||
)}
|
||||
|
@ -114,10 +114,10 @@ const AvailableTimes: FC<AvailableTimesProps> = ({
|
|||
{loading && <Loader />}
|
||||
|
||||
{error && (
|
||||
<div className="p-4 border-l-4 border-yellow-400 bg-yellow-50">
|
||||
<div className="border-l-4 border-yellow-400 bg-yellow-50 p-4">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<ExclamationIcon className="w-5 h-5 text-yellow-400" aria-hidden="true" />
|
||||
<ExclamationIcon className="h-5 w-5 text-yellow-400" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ltr:ml-3 rtl:mr-3">
|
||||
<p className="text-sm text-yellow-700">{t("slots_load_fail")}</p>
|
||||
|
|
|
@ -74,13 +74,13 @@ function BookingListItem(booking: BookingItem) {
|
|||
|
||||
return (
|
||||
<tr className="flex">
|
||||
<td className="hidden py-4 align-top ltr:pl-6 rtl:pr-6 sm:table-cell whitespace-nowrap">
|
||||
<td className="hidden whitespace-nowrap py-4 align-top ltr:pl-6 rtl:pr-6 sm:table-cell">
|
||||
<div className="text-sm leading-6 text-gray-900">{startTime}</div>
|
||||
<div className="text-sm text-gray-500">
|
||||
{dayjs(booking.startTime).format("HH:mm")} - {dayjs(booking.endTime).format("HH:mm")}
|
||||
</div>
|
||||
</td>
|
||||
<td className={"ltr:pl-4 rtl:pr-4 py-4 flex-1" + (booking.rejected ? " line-through" : "")}>
|
||||
<td className={"flex-1 py-4 ltr:pl-4 rtl:pr-4" + (booking.rejected ? " line-through" : "")}>
|
||||
<div className="sm:hidden">
|
||||
{!booking.confirmed && !booking.rejected && (
|
||||
<Tag className="mb-2 ltr:mr-2 rtl:ml-2">{t("unconfirmed")}</Tag>
|
||||
|
@ -97,7 +97,7 @@ function BookingListItem(booking: BookingItem) {
|
|||
</div>
|
||||
<div
|
||||
title={booking.title}
|
||||
className="text-sm font-medium leading-6 truncate text-neutral-900 max-w-56 md:max-w-max">
|
||||
className="max-w-56 truncate text-sm font-medium leading-6 text-neutral-900 md:max-w-max">
|
||||
{booking.eventType?.team && <strong>{booking.eventType.team.name}: </strong>}
|
||||
{booking.title}
|
||||
{!!booking?.eventType?.price && !booking.paid && (
|
||||
|
@ -108,7 +108,7 @@ function BookingListItem(booking: BookingItem) {
|
|||
)}
|
||||
</div>
|
||||
{booking.description && (
|
||||
<div className="text-sm text-gray-500 truncate max-w-52 md:max-w-96" title={booking.description}>
|
||||
<div className="max-w-52 truncate text-sm text-gray-500 md:max-w-96" title={booking.description}>
|
||||
"{booking.description}"
|
||||
</div>
|
||||
)}
|
||||
|
@ -119,7 +119,7 @@ function BookingListItem(booking: BookingItem) {
|
|||
)}
|
||||
</td>
|
||||
|
||||
<td className="py-4 text-sm font-medium text-right ltr:pr-4 rtl:pl-4 whitespace-nowrap">
|
||||
<td className="whitespace-nowrap py-4 text-right text-sm font-medium ltr:pr-4 rtl:pl-4">
|
||||
{isUpcoming && !isCancelled ? (
|
||||
<>
|
||||
{!booking.confirmed && !booking.rejected && <TableActions actions={pendingActions} />}
|
||||
|
@ -137,7 +137,7 @@ function BookingListItem(booking: BookingItem) {
|
|||
const Tag = ({ children, className = "" }: React.PropsWithChildren<{ className?: string }>) => {
|
||||
return (
|
||||
<span
|
||||
className={`inline-flex items-center px-1.5 py-0.5 rounded-sm text-xs font-medium bg-yellow-100 text-yellow-800 ${className}`}>
|
||||
className={`inline-flex items-center rounded-sm bg-yellow-100 px-1.5 py-0.5 text-xs font-medium text-yellow-800 ${className}`}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
|
|
|
@ -163,10 +163,10 @@ function DatePicker({
|
|||
className={
|
||||
"mt-8 sm:mt-0 sm:min-w-[455px] " +
|
||||
(date
|
||||
? "w-full sm:w-1/2 md:w-1/3 sm:border-r sm:dark:border-gray-800 sm:pl-4 sm:pr-6 "
|
||||
? "w-full sm:w-1/2 sm:border-r sm:pl-4 sm:pr-6 sm:dark:border-gray-800 md:w-1/3 "
|
||||
: "w-full sm:pl-4")
|
||||
}>
|
||||
<div className="flex mb-4 text-xl font-light text-gray-600">
|
||||
<div className="mb-4 flex text-xl font-light text-gray-600">
|
||||
<span className="w-1/2 text-gray-600 dark:text-white">
|
||||
<strong className="text-gray-900 dark:text-white">{month}</strong>{" "}
|
||||
<span className="text-gray-500">{year}</span>
|
||||
|
@ -175,21 +175,21 @@ function DatePicker({
|
|||
<button
|
||||
onClick={decrementMonth}
|
||||
className={classNames(
|
||||
"group ltr:mr-2 rtl:ml-2 p-1",
|
||||
"group p-1 ltr:mr-2 rtl:ml-2",
|
||||
isFirstMonth && "text-gray-400 dark:text-gray-600"
|
||||
)}
|
||||
disabled={isFirstMonth}
|
||||
data-testid="decrementMonth">
|
||||
<ChevronLeftIcon className="w-5 h-5 group-hover:text-black dark:group-hover:text-white" />
|
||||
<ChevronLeftIcon className="h-5 w-5 group-hover:text-black dark:group-hover:text-white" />
|
||||
</button>
|
||||
<button className="p-1 group" onClick={incrementMonth} data-testid="incrementMonth">
|
||||
<ChevronRightIcon className="w-5 h-5 group-hover:text-black dark:group-hover:text-white" />
|
||||
<button className="group p-1" onClick={incrementMonth} data-testid="incrementMonth">
|
||||
<ChevronRightIcon className="h-5 w-5 group-hover:text-black dark:group-hover:text-white" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-7 gap-4 text-center border-t border-b dark:border-gray-800 sm:border-0">
|
||||
<div className="grid grid-cols-7 gap-4 border-t border-b text-center dark:border-gray-800 sm:border-0">
|
||||
{weekdayNames(i18n.language, weekStart === "Sunday" ? 0 : 1, "short").map((weekDay) => (
|
||||
<div key={weekDay} className="my-4 text-xs tracking-widest text-gray-500 uppercase">
|
||||
<div key={weekDay} className="my-4 text-xs uppercase tracking-widest text-gray-500">
|
||||
{weekDay}
|
||||
</div>
|
||||
))}
|
||||
|
@ -209,9 +209,9 @@ function DatePicker({
|
|||
onClick={() => onDatePicked(browsingDate.date(day.date))}
|
||||
disabled={day.disabled}
|
||||
className={classNames(
|
||||
"absolute w-full top-0 left-0 right-0 bottom-0 rounded-sm text-center mx-auto",
|
||||
"absolute top-0 left-0 right-0 bottom-0 mx-auto w-full rounded-sm text-center",
|
||||
"hover:border hover:border-brand dark:hover:border-white",
|
||||
day.disabled ? "text-gray-400 font-light hover:border-0 cursor-default" : "font-medium",
|
||||
day.disabled ? "cursor-default font-light text-gray-400 hover:border-0" : "font-medium",
|
||||
date && date.isSame(browsingDate.date(day.date), "day")
|
||||
? "bg-brand text-brandcontrast"
|
||||
: !day.disabled
|
||||
|
|
|
@ -35,8 +35,8 @@ const TimeOptions: FC<Props> = (props) => {
|
|||
};
|
||||
|
||||
return selectedTimeZone !== "" ? (
|
||||
<div className="absolute z-10 w-full px-4 py-2 bg-white border border-gray-200 rounded-sm max-w-80 dark:bg-gray-700 dark:border-0">
|
||||
<div className="flex mb-4">
|
||||
<div className="absolute z-10 w-full max-w-80 rounded-sm border border-gray-200 bg-white px-4 py-2 dark:border-0 dark:bg-gray-700">
|
||||
<div className="mb-4 flex">
|
||||
<div className="w-1/2 font-medium text-gray-600 dark:text-white">{t("time_options")}</div>
|
||||
<div className="w-1/2">
|
||||
<Switch.Group as="div" className="flex items-center justify-end">
|
||||
|
@ -47,15 +47,15 @@ const TimeOptions: FC<Props> = (props) => {
|
|||
checked={is24hClock}
|
||||
onChange={handle24hClockToggle}
|
||||
className={classNames(
|
||||
is24hClock ? "bg-brand text-brandcontrast" : "dark:bg-gray-600 bg-gray-200",
|
||||
"relative inline-flex flex-shrink-0 h-5 w-8 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black"
|
||||
is24hClock ? "bg-brand text-brandcontrast" : "bg-gray-200 dark:bg-gray-600",
|
||||
"relative inline-flex h-5 w-8 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2"
|
||||
)}>
|
||||
<span className="sr-only">{t("use_setting")}</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className={classNames(
|
||||
is24hClock ? "translate-x-3" : "translate-x-0",
|
||||
"pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200"
|
||||
"pointer-events-none inline-block h-4 w-4 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
|
||||
)}
|
||||
/>
|
||||
</Switch>
|
||||
|
@ -69,7 +69,7 @@ const TimeOptions: FC<Props> = (props) => {
|
|||
id="timeZone"
|
||||
value={selectedTimeZone}
|
||||
onChange={(tz: ITimezoneOption) => setSelectedTimeZone(tz.value)}
|
||||
className="block w-full mt-1 mb-2 border-gray-300 rounded-md shadow-sm focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="mt-1 mb-2 block w-full rounded-md border-gray-300 shadow-sm focus:border-brand focus:ring-black sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
) : null;
|
||||
|
|
|
@ -110,11 +110,11 @@ const AvailabilityPage = ({ profile, eventType, workingHours }: Props) => {
|
|||
<div>
|
||||
<main
|
||||
className={
|
||||
"mx-auto my-0 md:my-24 transition-max-width ease-in-out duration-500 " +
|
||||
"transition-max-width mx-auto my-0 duration-500 ease-in-out md:my-24 " +
|
||||
(selectedDate ? "max-w-5xl" : "max-w-3xl")
|
||||
}>
|
||||
{isReady && (
|
||||
<div className="bg-white border-gray-200 rounded-sm sm:dark:border-gray-600 dark:bg-gray-900 md:border">
|
||||
<div className="rounded-sm border-gray-200 bg-white dark:bg-gray-900 sm:dark:border-gray-600 md:border">
|
||||
{/* mobile: details */}
|
||||
<div className="block p-4 sm:p-8 md:hidden">
|
||||
<div className="flex items-center">
|
||||
|
@ -139,12 +139,12 @@ const AvailabilityPage = ({ profile, eventType, workingHours }: Props) => {
|
|||
<div className="flex gap-2 text-xs font-medium text-gray-600">
|
||||
{eventType.title}
|
||||
<div>
|
||||
<ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
||||
<ClockIcon className="mr-1 -mt-1 inline-block h-4 w-4" />
|
||||
{eventType.length} {t("minutes")}
|
||||
</div>
|
||||
{eventType.price > 0 && (
|
||||
<div>
|
||||
<CreditCardIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
||||
<CreditCardIcon className="mr-1 -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={eventType.price / 100.0}
|
||||
|
@ -160,10 +160,10 @@ const AvailabilityPage = ({ profile, eventType, workingHours }: Props) => {
|
|||
<p className="mt-3 text-gray-600 dark:text-gray-200">{eventType.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="px-4 sm:flex sm:py-5 sm:p-4">
|
||||
<div className="px-4 sm:flex sm:p-4 sm:py-5">
|
||||
<div
|
||||
className={
|
||||
"hidden md:block pr-8 sm:border-r sm:dark:border-gray-800 " +
|
||||
"hidden pr-8 sm:border-r sm:dark:border-gray-800 md:block " +
|
||||
(selectedDate ? "sm:w-1/3" : "sm:w-1/2")
|
||||
}>
|
||||
<AvatarGroup
|
||||
|
@ -183,16 +183,16 @@ const AvailabilityPage = ({ profile, eventType, workingHours }: Props) => {
|
|||
truncateAfter={3}
|
||||
/>
|
||||
<h2 className="mt-3 font-medium text-gray-500 dark:text-gray-300">{profile.name}</h2>
|
||||
<h1 className="mb-4 text-3xl font-semibold text-gray-800 font-cal dark:text-white">
|
||||
<h1 className="mb-4 font-cal text-3xl font-semibold text-gray-800 dark:text-white">
|
||||
{eventType.title}
|
||||
</h1>
|
||||
<p className="px-2 py-1 mb-1 -ml-2 text-gray-500">
|
||||
<ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
||||
<p className="mb-1 -ml-2 px-2 py-1 text-gray-500">
|
||||
<ClockIcon className="mr-1 -mt-1 inline-block h-4 w-4" />
|
||||
{eventType.length} {t("minutes")}
|
||||
</p>
|
||||
{eventType.price > 0 && (
|
||||
<p className="px-2 py-1 mb-1 -ml-2 text-gray-500">
|
||||
<CreditCardIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
||||
<p className="mb-1 -ml-2 px-2 py-1 text-gray-500">
|
||||
<CreditCardIcon className="mr-1 -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={eventType.price / 100.0}
|
||||
|
@ -221,7 +221,7 @@ const AvailabilityPage = ({ profile, eventType, workingHours }: Props) => {
|
|||
minimumBookingNotice={eventType.minimumBookingNotice}
|
||||
/>
|
||||
|
||||
<div className="block mt-4 ml-1 sm:hidden">
|
||||
<div className="mt-4 ml-1 block sm:hidden">
|
||||
<TimezoneDropdown />
|
||||
</div>
|
||||
|
||||
|
@ -249,13 +249,13 @@ const AvailabilityPage = ({ profile, eventType, workingHours }: Props) => {
|
|||
function TimezoneDropdown() {
|
||||
return (
|
||||
<Collapsible.Root open={isTimeOptionsOpen} onOpenChange={setIsTimeOptionsOpen}>
|
||||
<Collapsible.Trigger className="px-2 py-1 mb-1 -ml-2 text-left text-gray-500 min-w-32">
|
||||
<GlobeIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
||||
<Collapsible.Trigger className="mb-1 -ml-2 min-w-32 px-2 py-1 text-left text-gray-500">
|
||||
<GlobeIcon className="mr-1 -mt-1 inline-block h-4 w-4" />
|
||||
{timeZone()}
|
||||
{isTimeOptionsOpen ? (
|
||||
<ChevronUpIcon className="inline-block w-4 h-4 ml-1 -mt-1" />
|
||||
<ChevronUpIcon className="ml-1 -mt-1 inline-block h-4 w-4" />
|
||||
) : (
|
||||
<ChevronDownIcon className="inline-block w-4 h-4 ml-1 -mt-1" />
|
||||
<ChevronDownIcon className="ml-1 -mt-1 inline-block h-4 w-4" />
|
||||
)}
|
||||
</Collapsible.Trigger>
|
||||
<Collapsible.Content>
|
||||
|
|
|
@ -291,9 +291,9 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<CustomBranding val={props.profile.brandColor} />
|
||||
<main className="max-w-3xl mx-auto my-0 rounded-sm sm:my-24 sm:border sm:dark:border-gray-600">
|
||||
<main className=" mx-auto my-0 max-w-3xl rounded-sm sm:my-24 sm:border sm:dark:border-gray-600">
|
||||
{isReady && (
|
||||
<div className="overflow-hidden bg-white border border-gray-200 dark:bg-neutral-900 dark:border-0 sm:rounded-sm">
|
||||
<div className="overflow-hidden border border-gray-200 bg-white dark:border-0 dark:bg-neutral-900 sm:rounded-sm">
|
||||
<div className="px-4 py-5 sm:flex sm:p-4">
|
||||
<div className="sm:w-1/2 sm:border-r sm:dark:border-gray-800">
|
||||
<AvatarGroup
|
||||
|
@ -307,19 +307,19 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
}))
|
||||
)}
|
||||
/>
|
||||
<h2 className="mt-2 font-medium text-gray-500 font-cal dark:text-gray-300">
|
||||
<h2 className="mt-2 font-cal font-medium text-gray-500 dark:text-gray-300">
|
||||
{props.profile.name}
|
||||
</h2>
|
||||
<h1 className="mb-4 text-3xl font-semibold text-gray-800 dark:text-white">
|
||||
{props.eventType.title}
|
||||
</h1>
|
||||
<p className="mb-2 text-gray-500">
|
||||
<ClockIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
||||
<ClockIcon className="mr-1 -mt-1 inline-block h-4 w-4" />
|
||||
{props.eventType.length} {t("minutes")}
|
||||
</p>
|
||||
{props.eventType.price > 0 && (
|
||||
<p className="px-2 py-1 mb-1 -ml-2 text-gray-500">
|
||||
<CreditCardIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
||||
<p className="mb-1 -ml-2 px-2 py-1 text-gray-500">
|
||||
<CreditCardIcon className="mr-1 -mt-1 inline-block h-4 w-4" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={props.eventType.price / 100.0}
|
||||
|
@ -331,22 +331,22 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
)}
|
||||
{selectedLocation === LocationType.InPerson && (
|
||||
<p className="mb-2 text-gray-500">
|
||||
<LocationMarkerIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
||||
<LocationMarkerIcon className="mr-1 -mt-1 inline-block h-4 w-4" />
|
||||
{getLocationValue({ locationType: selectedLocation })}
|
||||
</p>
|
||||
)}
|
||||
{selectedLocation === LocationType.Jitsi && (
|
||||
<p className="mb-2 text-gray-500">
|
||||
<LocationMarkerIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
||||
<LocationMarkerIcon className="mr-1 -mt-1 inline-block h-4 w-4" />
|
||||
Jitsi Meet
|
||||
</p>
|
||||
)}
|
||||
<p className="mb-4 text-green-500">
|
||||
<CalendarIcon className="inline-block w-4 h-4 mr-1 -mt-1" />
|
||||
<CalendarIcon className="mr-1 -mt-1 inline-block h-4 w-4" />
|
||||
{parseDate(date)}
|
||||
</p>
|
||||
{eventTypeDetail.isWeb3Active && eventType.metadata.smartContractAddress && (
|
||||
<p className="px-2 py-1 mb-1 -ml-2 text-gray-500">
|
||||
<p className="mb-1 -ml-2 px-2 py-1 text-gray-500">
|
||||
Requires ownership of a token belonging to the following address:{" "}
|
||||
{eventType.metadata.smartContractAddress}
|
||||
</p>
|
||||
|
@ -366,7 +366,7 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
name="name"
|
||||
id="name"
|
||||
required
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-brand focus:ring-black dark:border-gray-900 dark:bg-black dark:text-white sm:text-sm"
|
||||
placeholder="John Doe"
|
||||
/>
|
||||
</div>
|
||||
|
@ -381,7 +381,7 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
<EmailInput
|
||||
{...bookingForm.register("email")}
|
||||
required
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-brand focus:ring-black dark:border-gray-900 dark:bg-black dark:text-white sm:text-sm"
|
||||
placeholder="you@example.com"
|
||||
/>
|
||||
</div>
|
||||
|
@ -395,12 +395,12 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
<label key={i} className="block">
|
||||
<input
|
||||
type="radio"
|
||||
className="w-4 h-4 text-black border-gray-300 ltr:mr-2 rtl:ml-2 location focus:ring-black"
|
||||
className="location h-4 w-4 border-gray-300 text-black focus:ring-black ltr:mr-2 rtl:ml-2"
|
||||
{...bookingForm.register("locationType", { required: true })}
|
||||
value={location.type}
|
||||
defaultChecked={selectedLocation === location.type}
|
||||
/>
|
||||
<span className="ltr:ml-2 rtl:mr-2text-sm dark:text-gray-500">
|
||||
<span className="rtl:mr-2text-sm ltr:ml-2 dark:text-gray-500">
|
||||
{locationLabels[location.type]}
|
||||
</span>
|
||||
</label>
|
||||
|
@ -428,7 +428,7 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
{input.type !== EventTypeCustomInputType.BOOL && (
|
||||
<label
|
||||
htmlFor={"custom_" + input.id}
|
||||
className="block mb-1 text-sm font-medium text-gray-700 dark:text-white">
|
||||
className="mb-1 block text-sm font-medium text-gray-700 dark:text-white">
|
||||
{input.label}
|
||||
</label>
|
||||
)}
|
||||
|
@ -439,7 +439,7 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
})}
|
||||
id={"custom_" + input.id}
|
||||
rows={3}
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-brand focus:ring-black dark:border-gray-900 dark:bg-black dark:text-white sm:text-sm"
|
||||
placeholder={input.placeholder}
|
||||
/>
|
||||
)}
|
||||
|
@ -450,7 +450,7 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
required: input.required,
|
||||
})}
|
||||
id={"custom_" + input.id}
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-brand focus:ring-black dark:border-gray-900 dark:bg-black dark:text-white sm:text-sm"
|
||||
placeholder={input.placeholder}
|
||||
/>
|
||||
)}
|
||||
|
@ -461,24 +461,24 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
required: input.required,
|
||||
})}
|
||||
id={"custom_" + input.id}
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-brand focus:ring-black dark:border-gray-900 dark:bg-black dark:text-white sm:text-sm"
|
||||
placeholder=""
|
||||
/>
|
||||
)}
|
||||
{input.type === EventTypeCustomInputType.BOOL && (
|
||||
<div className="flex items-center h-5">
|
||||
<div className="flex h-5 items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
{...bookingForm.register(`customInputs.${input.id}`, {
|
||||
required: input.required,
|
||||
})}
|
||||
id={"custom_" + input.id}
|
||||
className="w-4 h-4 text-black border-gray-300 rounded ltr:mr-2 rtl:ml-2 focus:ring-black"
|
||||
className="h-4 w-4 rounded border-gray-300 text-black focus:ring-black ltr:mr-2 rtl:ml-2"
|
||||
placeholder=""
|
||||
/>
|
||||
<label
|
||||
htmlFor={"custom_" + input.id}
|
||||
className="block mb-1 text-sm font-medium text-gray-700 dark:text-white">
|
||||
className="mb-1 block text-sm font-medium text-gray-700 dark:text-white">
|
||||
{input.label}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -491,7 +491,7 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
<label
|
||||
onClick={() => setGuestToggle(!guestToggle)}
|
||||
htmlFor="guests"
|
||||
className="block mb-1 text-sm font-medium dark:text-white hover:cursor-pointer">
|
||||
className="mb-1 block text-sm font-medium hover:cursor-pointer dark:text-white">
|
||||
{/*<UserAddIcon className="inline-block w-5 h-5 mr-1 -mt-1" />*/}
|
||||
{t("additional_guests")}
|
||||
</label>
|
||||
|
@ -500,7 +500,7 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
<div>
|
||||
<label
|
||||
htmlFor="guests"
|
||||
className="block mb-1 text-sm font-medium text-gray-700 dark:text-white">
|
||||
className="mb-1 block text-sm font-medium text-gray-700 dark:text-white">
|
||||
{t("guests")}
|
||||
</label>
|
||||
<Controller
|
||||
|
@ -536,14 +536,14 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
<div className="mb-4">
|
||||
<label
|
||||
htmlFor="notes"
|
||||
className="block mb-1 text-sm font-medium text-gray-700 dark:text-white">
|
||||
className="mb-1 block text-sm font-medium text-gray-700 dark:text-white">
|
||||
{t("additional_notes")}
|
||||
</label>
|
||||
<textarea
|
||||
{...bookingForm.register("notes")}
|
||||
id="notes"
|
||||
rows={3}
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm dark:bg-black dark:text-white dark:border-gray-900 focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-brand focus:ring-black dark:border-gray-900 dark:bg-black dark:text-white sm:text-sm"
|
||||
placeholder={t("share_additional_notes")}
|
||||
/>
|
||||
</div>
|
||||
|
@ -557,10 +557,10 @@ const BookingPage = (props: BookingPageProps) => {
|
|||
</div>
|
||||
</Form>
|
||||
{mutation.isError && (
|
||||
<div className="p-4 mt-2 border-l-4 border-yellow-400 bg-yellow-50">
|
||||
<div className="mt-2 border-l-4 border-yellow-400 bg-yellow-50 p-4">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<ExclamationIcon className="w-5 h-5 text-yellow-400" aria-hidden="true" />
|
||||
<ExclamationIcon className="h-5 w-5 text-yellow-400" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ltr:ml-3 rtl:mr-3">
|
||||
<p className="text-sm text-yellow-700">
|
||||
|
|
|
@ -33,26 +33,26 @@ export default function ConfirmationDialogContent(props: PropsWithChildren<Confi
|
|||
<DialogContent>
|
||||
<div className="flex">
|
||||
{variety && (
|
||||
<div className="ltr:mr-3 mt-0.5">
|
||||
<div className="mt-0.5 ltr:mr-3">
|
||||
{variety === "danger" && (
|
||||
<div className="p-2 mx-auto text-center bg-red-100 rounded-full">
|
||||
<ExclamationIcon className="w-5 h-5 text-red-600" />
|
||||
<div className="mx-auto rounded-full bg-red-100 p-2 text-center">
|
||||
<ExclamationIcon className="h-5 w-5 text-red-600" />
|
||||
</div>
|
||||
)}
|
||||
{variety === "warning" && (
|
||||
<div className="p-2 mx-auto text-center bg-orange-100 rounded-full">
|
||||
<ExclamationIcon className="w-5 h-5 text-orange-600" />
|
||||
<div className="mx-auto rounded-full bg-orange-100 p-2 text-center">
|
||||
<ExclamationIcon className="h-5 w-5 text-orange-600" />
|
||||
</div>
|
||||
)}
|
||||
{variety === "success" && (
|
||||
<div className="p-2 mx-auto text-center bg-green-100 rounded-full">
|
||||
<CheckIcon className="w-5 h-5 text-green-600" />
|
||||
<div className="mx-auto rounded-full bg-green-100 p-2 text-center">
|
||||
<CheckIcon className="h-5 w-5 text-green-600" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<DialogPrimitive.Title className="text-xl font-bold text-gray-900 font-cal">
|
||||
<DialogPrimitive.Title className="font-cal text-xl font-bold text-gray-900">
|
||||
{title}
|
||||
</DialogPrimitive.Title>
|
||||
<DialogPrimitive.Description className="text-sm text-neutral-500">
|
||||
|
@ -60,7 +60,7 @@ export default function ConfirmationDialogContent(props: PropsWithChildren<Confi
|
|||
</DialogPrimitive.Description>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-8 sm:flex sm:flex-row-reverse gap-x-2">
|
||||
<div className="mt-5 gap-x-2 sm:mt-8 sm:flex sm:flex-row-reverse">
|
||||
<DialogClose onClick={onConfirm} asChild>
|
||||
{confirmBtn || <Button color="primary">{confirmBtnText}</Button>}
|
||||
</DialogClose>
|
||||
|
|
|
@ -29,15 +29,15 @@ const ErrorDebugPanel: React.FC<{ error: Props["error"]; children?: never }> = (
|
|||
];
|
||||
|
||||
return (
|
||||
<div className="bg-white shadow overflow-hidden sm:rounded-lg">
|
||||
<div className="overflow-hidden bg-white shadow sm:rounded-lg">
|
||||
<div className="border-t border-gray-200 px-4 py-5 sm:p-0">
|
||||
<dl className="sm:divide-y sm:divide-gray-200">
|
||||
{debugMap.map(([key, value]) => {
|
||||
if (value !== undefined) {
|
||||
return (
|
||||
<div key={key} className="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||
<div key={key} className="py-4 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-5 sm:px-6">
|
||||
<dt className="text-sm font-bold text-black">{key}</dt>
|
||||
<dd className="mt-1 text-sm text-black sm:mt-0 sm:col-span-2">{value}</dd>
|
||||
<dd className="mt-1 text-sm text-black sm:col-span-2 sm:mt-0">{value}</dd>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -53,11 +53,11 @@ export const ErrorPage: React.FC<Props> = (props) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className="bg-white min-h-screen px-4">
|
||||
<main className="max-w-xl mx-auto pb-6 pt-16 sm:pt-24">
|
||||
<div className="min-h-screen bg-white px-4">
|
||||
<main className="mx-auto max-w-xl pb-6 pt-16 sm:pt-24">
|
||||
<div className="text-center">
|
||||
<p className="text-sm font-semibold text-black uppercase tracking-wide">{statusCode}</p>
|
||||
<h1 className="mt-2 text-4xl font-extrabold text-gray-900 tracking-tight sm:text-5xl">
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-black">{statusCode}</p>
|
||||
<h1 className="mt-2 text-4xl font-extrabold tracking-tight text-gray-900 sm:text-5xl">
|
||||
{message}
|
||||
</h1>
|
||||
</div>
|
||||
|
|
|
@ -139,7 +139,7 @@ export default function CreateEventTypeButton(props: Props) {
|
|||
{props.options.map((option) => (
|
||||
<DropdownMenuItem
|
||||
key={option.slug}
|
||||
className="px-3 py-2 cursor-pointer hover:bg-neutral-100 focus:outline-none"
|
||||
className="cursor-pointer px-3 py-2 hover:bg-neutral-100 focus:outline-none"
|
||||
onSelect={() => openModal(option)}>
|
||||
<Avatar
|
||||
alt={option.name || ""}
|
||||
|
@ -207,7 +207,7 @@ export default function CreateEventTypeButton(props: Props) {
|
|||
className="pr-20"
|
||||
{...register("length", { valueAsNumber: true })}
|
||||
/>
|
||||
<div className="absolute inset-y-0 right-0 flex items-center pt-4 mt-1.5 pr-3 text-sm text-gray-400">
|
||||
<div className="absolute inset-y-0 right-0 mt-1.5 flex items-center pt-4 pr-3 text-sm text-gray-400">
|
||||
{t("minutes")}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -227,20 +227,20 @@ export default function CreateEventTypeButton(props: Props) {
|
|||
<RadioArea.Group
|
||||
{...register("schedulingType")}
|
||||
onChange={(val) => form.setValue("schedulingType", val as SchedulingType)}
|
||||
className="relative flex mt-1 rtl:space-x-reverse space-x-6 rounded-sm shadow-sm">
|
||||
className="relative mt-1 flex space-x-6 rounded-sm shadow-sm rtl:space-x-reverse">
|
||||
<RadioArea.Item value={SchedulingType.COLLECTIVE} className="w-1/2 text-sm">
|
||||
<strong className="block mb-1">{t("collective")}</strong>
|
||||
<strong className="mb-1 block">{t("collective")}</strong>
|
||||
<p>{t("collective_description")}</p>
|
||||
</RadioArea.Item>
|
||||
<RadioArea.Item value={SchedulingType.ROUND_ROBIN} className="w-1/2 text-sm">
|
||||
<strong className="block mb-1">{t("round_robin")}</strong>
|
||||
<strong className="mb-1 block">{t("round_robin")}</strong>
|
||||
<p>{t("round_robin_description")}</p>
|
||||
</RadioArea.Item>
|
||||
</RadioArea.Group>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-row-reverse mt-8 gap-x-2">
|
||||
<div className="mt-8 flex flex-row-reverse gap-x-2">
|
||||
<Button type="submit" loading={createMutation.isLoading}>
|
||||
{t("continue")}
|
||||
</Button>
|
||||
|
|
|
@ -32,31 +32,31 @@ export const EventTypeDescription = ({ eventType, className }: EventTypeDescript
|
|||
<>
|
||||
<div className={classNames("text-neutral-500 dark:text-white", className)}>
|
||||
{eventType.description && (
|
||||
<h2 className="opacity-60 text-ellipsis overflow-hidden max-w-[280px] sm:max-w-[500px]">
|
||||
<h2 className="max-w-[280px] overflow-hidden text-ellipsis opacity-60 sm:max-w-[500px]">
|
||||
{eventType.description.substring(0, 100)}
|
||||
{eventType.description.length > 100 && "..."}
|
||||
</h2>
|
||||
)}
|
||||
<ul className="flex mt-2 space-x-4 rtl:space-x-reverse ">
|
||||
<ul className="mt-2 flex space-x-4 rtl:space-x-reverse ">
|
||||
<li className="flex whitespace-nowrap">
|
||||
<ClockIcon className="inline mt-0.5 mr-1.5 h-4 w-4 text-neutral-400" aria-hidden="true" />
|
||||
<ClockIcon className="mt-0.5 mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
|
||||
{eventType.length}m
|
||||
</li>
|
||||
{eventType.schedulingType ? (
|
||||
<li className="flex whitespace-nowrap">
|
||||
<UsersIcon className="inline mt-0.5 mr-1.5 h-4 w-4 text-neutral-400" aria-hidden="true" />
|
||||
<UsersIcon className="mt-0.5 mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
|
||||
{eventType.schedulingType === SchedulingType.ROUND_ROBIN && t("round_robin")}
|
||||
{eventType.schedulingType === SchedulingType.COLLECTIVE && t("collective")}
|
||||
</li>
|
||||
) : (
|
||||
<li className="flex whitespace-nowrap">
|
||||
<UserIcon className="inline mt-0.5 mr-1.5 h-4 w-4 text-neutral-400" aria-hidden="true" />
|
||||
<UserIcon className="mt-0.5 mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
|
||||
{t("1_on_1")}
|
||||
</li>
|
||||
)}
|
||||
{eventType.price > 0 && (
|
||||
<li className="flex whitespace-nowrap">
|
||||
<CreditCardIcon className="inline mt-0.5 mr-1.5 h-4 w-4 text-neutral-400" aria-hidden="true" />
|
||||
<CreditCardIcon className="mt-0.5 mr-1.5 inline h-4 w-4 text-neutral-400" aria-hidden="true" />
|
||||
<IntlProvider locale="en">
|
||||
<FormattedNumber
|
||||
value={eventType.price / 100.0}
|
||||
|
|
|
@ -17,7 +17,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(pro
|
|||
{...props}
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
"mt-1 block w-full border border-gray-300 rounded-sm shadow-sm py-2 px-3 focus:outline-none focus:ring-1 focus:ring-neutral-800 focus:border-neutral-800 sm:text-sm",
|
||||
"mt-1 block w-full rounded-sm border border-gray-300 py-2 px-3 shadow-sm focus:border-neutral-800 focus:outline-none focus:ring-1 focus:ring-neutral-800 sm:text-sm",
|
||||
props.className
|
||||
)}
|
||||
/>
|
||||
|
@ -34,7 +34,7 @@ export function Label(props: JSX.IntrinsicElements["label"]) {
|
|||
|
||||
export function InputLeading(props: JSX.IntrinsicElements["div"]) {
|
||||
return (
|
||||
<span className="inline-flex items-center flex-shrink-0 px-3 text-gray-500 border border-r-0 border-gray-300 rounded-l-sm bg-gray-50 sm:text-sm">
|
||||
<span className="inline-flex flex-shrink-0 items-center rounded-l-sm border border-r-0 border-gray-300 bg-gray-50 px-3 text-gray-500 sm:text-sm">
|
||||
{props.children}
|
||||
</span>
|
||||
);
|
||||
|
@ -69,7 +69,7 @@ const InputField = forwardRef<HTMLInputElement, InputFieldProps>(function InputF
|
|||
</Label>
|
||||
)}
|
||||
{addOnLeading ? (
|
||||
<div className="flex mt-1 rounded-md shadow-sm">
|
||||
<div className="mt-1 flex rounded-md shadow-sm">
|
||||
{addOnLeading}
|
||||
<Input
|
||||
id={id}
|
||||
|
@ -136,7 +136,7 @@ export const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(function
|
|||
ref={ref}
|
||||
{...props}
|
||||
className={classNames(
|
||||
"block w-full font-mono border-gray-300 rounded-sm shadow-sm focus:ring-neutral-900 focus:border-neutral-900 sm:text-sm",
|
||||
"font-mono block w-full rounded-sm border-gray-300 shadow-sm focus:border-neutral-900 focus:ring-neutral-900 sm:text-sm",
|
||||
props.className
|
||||
)}
|
||||
/>
|
||||
|
@ -221,7 +221,7 @@ export function InputGroupBox(props: JSX.IntrinsicElements["div"]) {
|
|||
return (
|
||||
<div
|
||||
{...props}
|
||||
className={classNames("p-2 bg-white border border-gray-300 rounded-sm space-y-2", props.className)}>
|
||||
className={classNames("space-y-2 rounded-sm border border-gray-300 bg-white p-2", props.className)}>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -122,7 +122,7 @@ function ConnectedCalendarsList(props: Props) {
|
|||
onOpenChange={props.onChanged}
|
||||
/>
|
||||
}>
|
||||
<ul className="p-4 space-y-2">
|
||||
<ul className="space-y-2 p-4">
|
||||
{item.calendars.map((cal) => (
|
||||
<CalendarSwitch
|
||||
key={cal.externalId}
|
||||
|
|
|
@ -14,9 +14,9 @@ function IntegrationListItem(props: {
|
|||
}): JSX.Element {
|
||||
return (
|
||||
<ListItem expanded={!!props.children} className={classNames("flex-col")}>
|
||||
<div className={classNames("flex flex-1 rtl:space-x-reverse space-x-2 w-full p-3 items-center")}>
|
||||
<div className={classNames("flex w-full flex-1 items-center space-x-2 p-3 rtl:space-x-reverse")}>
|
||||
<Image width={40} height={40} src={`/${props.imageSrc}`} alt={props.title} />
|
||||
<div className="flex-grow pl-2 truncate">
|
||||
<div className="flex-grow truncate pl-2">
|
||||
<ListItemTitle component="h3">{props.title}</ListItemTitle>
|
||||
<ListItemText component="p">{props.description}</ListItemText>
|
||||
</div>
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
import { EventTypeCustomInput, EventTypeCustomInputType } from "@prisma/client";
|
||||
import React, { FC } from "react";
|
||||
import { Controller, SubmitHandler, useForm, useWatch } from "react-hook-form";
|
||||
import Select, { OptionTypeBase } from "react-select";
|
||||
import Select from "react-select";
|
||||
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
|
||||
import Button from "@components/ui/Button";
|
||||
|
||||
interface OptionTypeBase {
|
||||
label: string;
|
||||
value: EventTypeCustomInputType;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
onSubmit: SubmitHandler<IFormInput>;
|
||||
onCancel: () => void;
|
||||
|
@ -50,8 +55,8 @@ const CustomInputTypeForm: FC<Props> = (props) => {
|
|||
defaultValue={selectedInputOption}
|
||||
options={inputOptions}
|
||||
isSearchable={false}
|
||||
className="flex-1 block w-full min-w-0 mt-1 mb-2 border-gray-300 rounded-none focus:ring-primary-500 focus:border-primary-500 rounded-r-md sm:text-sm"
|
||||
onChange={(option) => field.onChange(option.value)}
|
||||
className="mt-1 mb-2 block w-full min-w-0 flex-1 rounded-none rounded-r-md border-gray-300 focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
|
||||
onChange={(option) => option && field.onChange(option.value)}
|
||||
value={selectedInputOption}
|
||||
onBlur={field.onBlur}
|
||||
name={field.name}
|
||||
|
@ -68,7 +73,7 @@ const CustomInputTypeForm: FC<Props> = (props) => {
|
|||
type="text"
|
||||
id="label"
|
||||
required
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
|
||||
defaultValue={selectedCustomInput?.label}
|
||||
{...register("label", { required: true })}
|
||||
/>
|
||||
|
@ -84,18 +89,18 @@ const CustomInputTypeForm: FC<Props> = (props) => {
|
|||
<input
|
||||
type="text"
|
||||
id="placeholder"
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
|
||||
defaultValue={selectedCustomInput?.placeholder}
|
||||
{...register("placeholder")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center h-5">
|
||||
<div className="flex h-5 items-center">
|
||||
<input
|
||||
id="required"
|
||||
type="checkbox"
|
||||
className="w-4 h-4 ltr:mr-2 rtl:ml-2 border-gray-300 rounded focus:ring-primary-500 text-primary-600"
|
||||
className="h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-500 ltr:mr-2 rtl:ml-2"
|
||||
defaultChecked={selectedCustomInput?.required ?? true}
|
||||
{...register("required")}
|
||||
/>
|
||||
|
|
|
@ -57,7 +57,7 @@ const ChangePasswordSection = () => {
|
|||
return (
|
||||
<>
|
||||
<div className="mt-6">
|
||||
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal">{t("change_password")}</h2>
|
||||
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">{t("change_password")}</h2>
|
||||
</div>
|
||||
<form className="divide-y divide-gray-200 lg:col-span-9" onSubmit={changePasswordHandler}>
|
||||
<div className="py-6 lg:pb-8">
|
||||
|
@ -74,12 +74,12 @@ const ChangePasswordSection = () => {
|
|||
name="current_password"
|
||||
id="current_password"
|
||||
required
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-brand focus:ring-black sm:text-sm"
|
||||
placeholder={t("your_old_password")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-1/2 ml-2">
|
||||
<div className="ml-2 w-1/2">
|
||||
<label htmlFor="new_password" className="block text-sm font-medium text-gray-700">
|
||||
{t("new_password")}
|
||||
</label>
|
||||
|
@ -91,7 +91,7 @@ const ChangePasswordSection = () => {
|
|||
value={newPassword}
|
||||
required
|
||||
onInput={(e) => setNewPassword(e.currentTarget.value)}
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-brand focus:ring-black sm:text-sm"
|
||||
placeholder={t("super_secure_new_password")}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -70,7 +70,7 @@ const DisableTwoFactorAuthModal = ({ onDisable, onCancel }: DisableTwoFactorAuth
|
|||
required
|
||||
value={password}
|
||||
onInput={(e) => setPassword(e.currentTarget.value)}
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm focus:ring-neutral-900 focus:border-neutral-900 sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-neutral-900 focus:ring-neutral-900 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
|
|||
required
|
||||
value={password}
|
||||
onInput={(e) => setPassword(e.currentTarget.value)}
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm focus:ring-neutral-900 focus:border-neutral-900 sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-neutral-900 focus:ring-neutral-900 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
@ -152,7 +152,7 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
|
|||
<div className="flex justify-center">
|
||||
<img src={dataUri} />
|
||||
</div>
|
||||
<p className="text-center text-xs font-mono">{secret}</p>
|
||||
<p className="font-mono text-center text-xs">{secret}</p>
|
||||
</>
|
||||
</WithStep>
|
||||
<WithStep step={SetupStep.EnterTotpCode} current={step}>
|
||||
|
@ -172,7 +172,7 @@ const EnableTwoFactorModal = ({ onEnable, onCancel }: EnableTwoFactorModalProps)
|
|||
minLength={6}
|
||||
inputMode="numeric"
|
||||
onInput={(e) => setTotpCode(e.currentTarget.value)}
|
||||
className="block w-full border-gray-300 rounded-sm shadow-sm focus:ring-neutral-900 focus:border-neutral-900 sm:text-sm"
|
||||
className="block w-full rounded-sm border-gray-300 shadow-sm focus:border-neutral-900 focus:ring-neutral-900 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -17,8 +17,8 @@ const TwoFactorAuthSection = ({ twoFactorEnabled }: { twoFactorEnabled: boolean
|
|||
return (
|
||||
<>
|
||||
<div className="flex flex-row items-center">
|
||||
<h2 className="font-cal text-lg leading-6 font-medium text-gray-900">{t("2fa")}</h2>
|
||||
<Badge className="text-xs ml-2" variant={enabled ? "success" : "gray"}>
|
||||
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">{t("2fa")}</h2>
|
||||
<Badge className="ml-2 text-xs" variant={enabled ? "success" : "gray"}>
|
||||
{enabled ? t("enabled") : t("disabled")}
|
||||
</Badge>
|
||||
</div>
|
||||
|
|
|
@ -4,11 +4,11 @@ import React from "react";
|
|||
const TwoFactorModalHeader = ({ title, description }: { title: string; description: string }) => {
|
||||
return (
|
||||
<div className="mb-4 sm:flex sm:items-start">
|
||||
<div className="flex items-center justify-center flex-shrink-0 w-12 h-12 mx-auto rounded-full bg-brand text-brandcontrast bg-opacity-5 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<ShieldCheckIcon className="w-6 h-6 text-black" />
|
||||
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-brand bg-opacity-5 text-brandcontrast sm:mx-0 sm:h-10 sm:w-10">
|
||||
<ShieldCheckIcon className="h-6 w-6 text-black" />
|
||||
</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 font-cal" id="modal-title">
|
||||
<h3 className="font-cal text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
||||
{title}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-400">{description}</p>
|
||||
|
|
|
@ -51,14 +51,14 @@ export default function MemberChangeRoleModal(props: {
|
|||
</div>
|
||||
<form onSubmit={changeRole}>
|
||||
<div className="mb-4">
|
||||
<label className="block mb-2 text-sm font-medium tracking-wide text-gray-700" htmlFor="role">
|
||||
<label className="mb-2 block text-sm font-medium tracking-wide text-gray-700" htmlFor="role">
|
||||
{t("role")}
|
||||
</label>
|
||||
<select
|
||||
value={role}
|
||||
onChange={(e) => setRole(e.target.value as MembershipRole)}
|
||||
id="role"
|
||||
className="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-black focus:border-brand sm:text-sm">
|
||||
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-brand focus:ring-black sm:text-sm">
|
||||
<option value="MEMBER">{t("member")}</option>
|
||||
<option value="ADMIN">{t("admin")}</option>
|
||||
{/*<option value="OWNER">{t("owner")}</option> - needs dialog to confirm change of ownership */}
|
||||
|
|
|
@ -53,19 +53,19 @@ export default function MemberInvitationModal(props: { team: TeamWithMembers | n
|
|||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true">
|
||||
<div className="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div
|
||||
className="fixed inset-0 z-0 transition-opacity bg-gray-500 bg-opacity-75"
|
||||
className="fixed inset-0 z-0 bg-gray-500 bg-opacity-75 transition-opacity"
|
||||
aria-hidden="true"></div>
|
||||
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||
<span className="hidden sm:inline-block sm:h-screen sm:align-middle" aria-hidden="true">
|
||||
​
|
||||
</span>
|
||||
|
||||
<div className="inline-block px-4 pt-5 pb-4 text-left align-bottom transition-all transform bg-white rounded-lg shadow-xl sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
|
||||
<div className="inline-block transform rounded-lg 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="mb-4 sm:flex sm:items-start">
|
||||
<div className="flex items-center justify-center flex-shrink-0 w-12 h-12 mx-auto rounded-full bg-brand text-brandcontrast bg-opacity-5 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<UserIcon className="w-6 h-6 text-brandcontrast" />
|
||||
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-brand bg-opacity-5 text-brandcontrast sm:mx-0 sm:h-10 sm:w-10">
|
||||
<UserIcon className="h-6 w-6 text-brandcontrast" />
|
||||
</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">
|
||||
|
@ -86,34 +86,34 @@ export default function MemberInvitationModal(props: { team: TeamWithMembers | n
|
|||
required
|
||||
/>
|
||||
<div>
|
||||
<label className="block mb-1 text-sm font-medium tracking-wide text-gray-700" htmlFor="role">
|
||||
<label className="mb-1 block text-sm font-medium tracking-wide text-gray-700" htmlFor="role">
|
||||
{t("role")}
|
||||
</label>
|
||||
<select
|
||||
id="role"
|
||||
className="block w-full mt-1 border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-brand sm:text-sm">
|
||||
className="mt-1 block w-full rounded-sm border-gray-300 shadow-sm focus:border-brand focus:ring-black sm:text-sm">
|
||||
<option value="MEMBER">{t("member")}</option>
|
||||
<option value="ADMIN">{t("admin")}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="relative flex items-start">
|
||||
<div className="flex items-center h-5">
|
||||
<div className="flex h-5 items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="sendInviteEmail"
|
||||
defaultChecked
|
||||
id="sendInviteEmail"
|
||||
className="text-black border-gray-300 rounded-sm shadow-sm focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="rounded-sm border-gray-300 text-black shadow-sm focus:border-brand focus:ring-black sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="ltr:ml-2 rtl:mr-2text-sm">
|
||||
<div className="rtl:mr-2text-sm ltr:ml-2">
|
||||
<label htmlFor="sendInviteEmail" className="font-medium text-gray-700">
|
||||
{t("send_invite_email")}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row px-3 py-2 rounded-sm bg-gray-50">
|
||||
<InformationCircleIcon className="flex-shrink-0 w-5 h-5 fill-gray-400" aria-hidden="true" />
|
||||
<div className="flex flex-row rounded-sm bg-gray-50 px-3 py-2">
|
||||
<InformationCircleIcon className="h-5 w-5 flex-shrink-0 fill-gray-400" aria-hidden="true" />
|
||||
<span className="ml-2 text-sm leading-tight text-gray-500">
|
||||
Note: This will cost an extra seat ($12/m) on your subscription if this invitee does not
|
||||
have a pro account.{" "}
|
||||
|
|
|
@ -12,7 +12,7 @@ export default function MemberList(props: Props) {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<ul className="px-4 mb-2 -mx-4 bg-white border divide-y divide-gray-200 rounded sm:px-4 sm:mx-0">
|
||||
<ul className="-mx-4 mb-2 divide-y divide-gray-200 rounded border bg-white px-4 sm:mx-0 sm:px-4">
|
||||
{props.members?.map((member) => (
|
||||
<MemberListItem key={member.id} member={member} team={props.team} />
|
||||
))}
|
||||
|
|
|
@ -61,25 +61,25 @@ export default function MemberListItem(props: Props) {
|
|||
|
||||
return (
|
||||
<li className="divide-y">
|
||||
<div className="flex justify-between my-4">
|
||||
<div className="flex flex-col justify-between w-full sm:flex-row">
|
||||
<div className="my-4 flex justify-between">
|
||||
<div className="flex w-full flex-col justify-between sm:flex-row">
|
||||
<div className="flex">
|
||||
<Avatar
|
||||
imageSrc={getPlaceholderAvatar(props.member?.avatar, name)}
|
||||
alt={name || ""}
|
||||
className="rounded-full w-9 h-9"
|
||||
className="h-9 w-9 rounded-full"
|
||||
/>
|
||||
<div className="inline-block ml-3">
|
||||
<div className="ml-3 inline-block">
|
||||
<span className="text-sm font-bold text-neutral-700">{name}</span>
|
||||
<span
|
||||
className="block -mt-1 text-xs text-gray-400"
|
||||
className="-mt-1 block text-xs text-gray-400"
|
||||
data-testid="member-email"
|
||||
data-email={props.member.email}>
|
||||
{props.member.email}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex mt-2 ltr:mr-2 rtl:ml-2 sm:mt-0 sm:justify-center">
|
||||
<div className="mt-2 flex ltr:mr-2 rtl:ml-2 sm:mt-0 sm:justify-center">
|
||||
{/* Tooltip doesn't show... WHY????? */}
|
||||
{props.member.isMissingSeat && (
|
||||
<Tooltip content={t("hidden_team_member_message")}>
|
||||
|
@ -102,13 +102,13 @@ export default function MemberListItem(props: Props) {
|
|||
disabled={!props.member.accepted}
|
||||
onClick={() => (props.member.accepted ? setShowTeamAvailabilityModal(true) : null)}
|
||||
color="minimal"
|
||||
className="items-center justify-center hidden w-10 h-10 px-0 py-0 border border-transparent group text-neutral-400 hover:border-gray-200 hover:bg-white sm:flex">
|
||||
<ClockIcon className="w-5 h-5 group-hover:text-gray-800" />
|
||||
className="group hidden h-10 w-10 items-center justify-center border border-transparent px-0 py-0 text-neutral-400 hover:border-gray-200 hover:bg-white sm:flex">
|
||||
<ClockIcon className="h-5 w-5 group-hover:text-gray-800" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Dropdown>
|
||||
<DropdownMenuTrigger className="w-10 h-10 p-0 border border-transparent group text-neutral-400 hover:border-gray-200 hover:bg-white">
|
||||
<DotsHorizontalIcon className="w-5 h-5 group-hover:text-gray-800" />
|
||||
<DropdownMenuTrigger className="group h-10 w-10 border border-transparent p-0 text-neutral-400 hover:border-gray-200 hover:bg-white">
|
||||
<DotsHorizontalIcon className="h-5 w-5 group-hover:text-gray-800" />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem>
|
||||
|
@ -129,7 +129,7 @@ export default function MemberListItem(props: Props) {
|
|||
onClick={() => setShowChangeMemberRoleModal(true)}
|
||||
color="minimal"
|
||||
StartIcon={PencilIcon}
|
||||
className="flex-shrink-0 w-full font-normal">
|
||||
className="w-full flex-shrink-0 font-normal">
|
||||
{t("edit_role")}
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
|
@ -173,7 +173,7 @@ export default function MemberListItem(props: Props) {
|
|||
{showTeamAvailabilityModal && (
|
||||
<ModalContainer wide noPadding>
|
||||
<TeamAvailabilityModal team={props.team} member={props.member} />
|
||||
<div className="p-5 space-x-2 border-t rtl:space-x-reverse">
|
||||
<div className="space-x-2 border-t p-5 rtl:space-x-reverse">
|
||||
<Button onClick={() => setShowTeamAvailabilityModal(false)}>{t("done")}</Button>
|
||||
{props.team.membership.role !== MembershipRole.MEMBER && (
|
||||
<Link href={`/settings/teams/${props.team.id}/availability`}>
|
||||
|
|
|
@ -37,19 +37,19 @@ export default function TeamCreate(props: Props) {
|
|||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true">
|
||||
<div className="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div
|
||||
className="fixed inset-0 z-0 transition-opacity bg-gray-500 bg-opacity-75"
|
||||
className="fixed inset-0 z-0 bg-gray-500 bg-opacity-75 transition-opacity"
|
||||
aria-hidden="true"></div>
|
||||
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||
<span className="hidden sm:inline-block sm:h-screen sm:align-middle" aria-hidden="true">
|
||||
​
|
||||
</span>
|
||||
|
||||
<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:align-middle sm:max-w-lg sm:w-full sm:p-6">
|
||||
<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="mb-4 sm:flex sm:items-start">
|
||||
<div className="flex items-center justify-center flex-shrink-0 w-12 h-12 mx-auto rounded-full bg-neutral-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<UsersIcon className="w-6 h-6 text-neutral-900" />
|
||||
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-neutral-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<UsersIcon className="h-6 w-6 text-neutral-900" />
|
||||
</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">
|
||||
|
@ -72,7 +72,7 @@ export default function TeamCreate(props: Props) {
|
|||
id="name"
|
||||
placeholder="Acme Inc."
|
||||
required
|
||||
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-sm shadow-sm focus:outline-none focus:ring-neutral-500 focus:border-neutral-500 sm:text-sm"
|
||||
className="mt-1 block w-full rounded-sm border border-gray-300 px-3 py-2 shadow-sm focus:border-neutral-500 focus:outline-none focus:ring-neutral-500 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
{errorMessage && <Alert severity="error" title={errorMessage} />}
|
||||
|
@ -80,7 +80,7 @@ export default function TeamCreate(props: Props) {
|
|||
<button type="submit" className="btn btn-primary">
|
||||
{t("create_team")}
|
||||
</button>
|
||||
<button onClick={props.onClose} type="button" className="ltr:mr-2 btn btn-white">
|
||||
<button onClick={props.onClose} type="button" className="btn btn-white ltr:mr-2">
|
||||
{t("cancel")}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -33,7 +33,7 @@ export default function TeamList(props: Props) {
|
|||
|
||||
return (
|
||||
<div>
|
||||
<ul className="mb-2 bg-white border divide-y rounded divide-neutral-200">
|
||||
<ul className="mb-2 divide-y divide-neutral-200 rounded border bg-white">
|
||||
{props.teams.map((team) => (
|
||||
<TeamListItem
|
||||
key={team?.id as number}
|
||||
|
|
|
@ -60,9 +60,9 @@ export default function TeamListItem(props: Props) {
|
|||
size={9}
|
||||
imageSrc={getPlaceholderAvatar(team?.logo, team?.name as string)}
|
||||
alt="Team Logo"
|
||||
className="rounded-full w-9 h-9 min-w-9 min-h-9"
|
||||
className="h-9 min-h-9 w-9 min-w-9 rounded-full"
|
||||
/>
|
||||
<div className="inline-block ml-3">
|
||||
<div className="ml-3 inline-block">
|
||||
<span className="text-sm font-bold text-neutral-700">{team.name}</span>
|
||||
<span className="block text-xs text-gray-400">
|
||||
{process.env.NEXT_PUBLIC_APP_URL}/team/{team.slug}
|
||||
|
@ -75,12 +75,12 @@ export default function TeamListItem(props: Props) {
|
|||
<li className="divide-y">
|
||||
<div
|
||||
className={classNames(
|
||||
"flex justify-between items-center",
|
||||
"flex items-center justify-between",
|
||||
!isInvitee && "group hover:bg-neutral-50"
|
||||
)}>
|
||||
{!isInvitee ? (
|
||||
<Link href={"/settings/teams/" + team.id}>
|
||||
<a className="flex-grow text-sm truncate cursor-pointer" title={`${team.name}`}>
|
||||
<a className="flex-grow cursor-pointer truncate text-sm" title={`${team.name}`}>
|
||||
{teamInfo}
|
||||
</a>
|
||||
</Link>
|
||||
|
@ -108,16 +108,16 @@ export default function TeamListItem(props: Props) {
|
|||
navigator.clipboard.writeText(process.env.NEXT_PUBLIC_APP_URL + "/team/" + team.slug);
|
||||
showToast(t("link_copied"), "success");
|
||||
}}
|
||||
className="w-10 h-10 transition-none"
|
||||
className="h-10 w-10 transition-none"
|
||||
size="icon"
|
||||
color="minimal"
|
||||
type="button">
|
||||
<LinkIcon className="w-5 h-5 group-hover:text-gray-600" />
|
||||
<LinkIcon className="h-5 w-5 group-hover:text-gray-600" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Dropdown>
|
||||
<DropdownMenuTrigger className="w-10 h-10 p-0 border border-transparent group text-neutral-400 hover:border-gray-200 ">
|
||||
<DotsHorizontalIcon className="w-5 h-5 group-hover:text-gray-800" />
|
||||
<DropdownMenuTrigger className="group h-10 w-10 border border-transparent p-0 text-neutral-400 hover:border-gray-200 ">
|
||||
<DotsHorizontalIcon className="h-5 w-5 group-hover:text-gray-800" />
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
{isAdmin && (
|
||||
|
|
|
@ -13,12 +13,12 @@ interface Props {
|
|||
export default function TeamPill(props: Props) {
|
||||
return (
|
||||
<div
|
||||
className={classNames("self-center px-3 py-1 ltr:mr-2 rtl:ml-2 text-xs capitalize border rounded-md", {
|
||||
"bg-gray-50 border-gray-200 text-gray-700": !props.color,
|
||||
"bg-blue-50 border-blue-200 text-blue-700": props.color === "blue",
|
||||
"bg-red-50 border-red-200 text-red-700": props.color === "red",
|
||||
"bg-yellow-50 border-yellow-200 text-yellow-700": props.color === "yellow",
|
||||
"bg-green-50 border-green-200 text-green-600": props.color === "green",
|
||||
className={classNames("self-center rounded-md border px-3 py-1 text-xs capitalize ltr:mr-2 rtl:ml-2", {
|
||||
"border-gray-200 bg-gray-50 text-gray-700": !props.color,
|
||||
"border-blue-200 bg-blue-50 text-blue-700": props.color === "blue",
|
||||
"border-red-200 bg-red-50 text-red-700": props.color === "red",
|
||||
"border-yellow-200 bg-yellow-50 text-yellow-700": props.color === "yellow",
|
||||
"border-green-200 bg-green-50 text-green-600": props.color === "green",
|
||||
})}>
|
||||
{props.text}
|
||||
</div>
|
||||
|
|
|
@ -90,7 +90,7 @@ export default function TeamSettings(props: Props) {
|
|||
name="" // typescript requires name but we don't want component to render name label
|
||||
id="team-url"
|
||||
addOnLeading={
|
||||
<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">
|
||||
<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">
|
||||
{process.env.NEXT_PUBLIC_APP_URL}/{"team/"}
|
||||
</span>
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ export default function TeamSettings(props: Props) {
|
|||
id="name"
|
||||
placeholder={t("your_team_name")}
|
||||
required
|
||||
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-sm shadow-sm focus:outline-none focus:ring-neutral-800 focus:border-neutral-800 sm:text-sm"
|
||||
className="mt-1 block w-full rounded-sm border border-gray-300 px-3 py-2 shadow-sm focus:border-neutral-800 focus:outline-none focus:ring-neutral-800 sm:text-sm"
|
||||
defaultValue={team?.name as string}
|
||||
/>
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ export default function TeamSettings(props: Props) {
|
|||
name="about"
|
||||
rows={3}
|
||||
defaultValue={team?.bio as string}
|
||||
className="block w-full mt-1 border-gray-300 rounded-sm shadow-sm focus:ring-neutral-800 focus:border-neutral-800 sm:text-sm"></textarea>
|
||||
className="mt-1 block w-full rounded-sm border-gray-300 shadow-sm focus:border-neutral-800 focus:ring-neutral-800 sm:text-sm"></textarea>
|
||||
<p className="mt-2 text-sm text-gray-500">{t("team_description")}</p>
|
||||
</>
|
||||
}
|
||||
|
@ -143,14 +143,14 @@ export default function TeamSettings(props: Props) {
|
|||
htmlFor="avatar"
|
||||
Input={
|
||||
<>
|
||||
<div className="flex mt-1">
|
||||
<div className="mt-1 flex">
|
||||
<input
|
||||
ref={logoRef}
|
||||
type="hidden"
|
||||
name="avatar"
|
||||
id="avatar"
|
||||
placeholder="URL"
|
||||
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-sm shadow-sm focus:outline-none focus:ring-neutral-800 focus:border-neutral-800 sm:text-sm"
|
||||
className="mt-1 block w-full rounded-sm border border-gray-300 px-3 py-2 shadow-sm focus:border-neutral-800 focus:outline-none focus:ring-neutral-800 sm:text-sm"
|
||||
defaultValue={team?.logo ?? undefined}
|
||||
/>
|
||||
<ImageUploader
|
||||
|
@ -165,7 +165,7 @@ export default function TeamSettings(props: Props) {
|
|||
onClick={removeLogo}
|
||||
color="secondary"
|
||||
type="button"
|
||||
className="py-1 ml-1 text-xs">
|
||||
className="ml-1 py-1 text-xs">
|
||||
{t("remove_logo")}
|
||||
</Button>
|
||||
)}
|
||||
|
@ -178,14 +178,14 @@ export default function TeamSettings(props: Props) {
|
|||
</div>
|
||||
|
||||
<div className="relative flex items-start">
|
||||
<div className="flex items-center h-5">
|
||||
<div className="flex h-5 items-center">
|
||||
<input
|
||||
id="hide-branding"
|
||||
name="hide-branding"
|
||||
type="checkbox"
|
||||
ref={hideBrandingRef}
|
||||
defaultChecked={team?.hideBranding}
|
||||
className="w-4 h-4 border-gray-300 rounded-sm focus:ring-neutral-500 text-neutral-900"
|
||||
className="h-4 w-4 rounded-sm border-gray-300 text-neutral-900 focus:ring-neutral-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="text-sm ltr:ml-3 rtl:mr-3">
|
||||
|
|
|
@ -48,7 +48,7 @@ export default function TeamSettingsRightSidebar(props: { team: TeamWithMembers;
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="px-2 space-y-6">
|
||||
<div className="space-y-6 px-2">
|
||||
{(props.role === MembershipRole.OWNER || props.role === MembershipRole.ADMIN) && (
|
||||
<CreateEventTypeButton
|
||||
isIndividualTeam
|
||||
|
@ -119,7 +119,7 @@ export default function TeamSettingsRightSidebar(props: { team: TeamWithMembers;
|
|||
</div>
|
||||
{props.team?.id && props.role !== MembershipRole.MEMBER && (
|
||||
<Link href={`/settings/teams/${props.team.id}/availability`}>
|
||||
<div className="hidden mt-5 space-y-1 sm:block">
|
||||
<div className="mt-5 hidden space-y-1 sm:block">
|
||||
<LinkIconButton Icon={ClockIcon}>{"View Availability"}</LinkIconButton>
|
||||
<p className="mt-2 text-sm text-gray-500">See your team members availability at a glance.</p>
|
||||
</div>
|
||||
|
|
|
@ -50,7 +50,7 @@ export function UpgradeToFlexibleProModal(props: Props) {
|
|||
setErrorMessage(null);
|
||||
}}>
|
||||
<DialogTrigger asChild>
|
||||
<a className="underline cursor-pointer">{"Upgrade Now"}</a>
|
||||
<a className="cursor-pointer underline">{"Upgrade Now"}</a>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader title={t("Purchase missing seats")} />
|
||||
|
|
|
@ -44,7 +44,7 @@ const Team = ({ team }: TeamPageProps) => {
|
|||
"absolute top-4 right-4",
|
||||
"h-4 w-4",
|
||||
"transition-opacity",
|
||||
"opacity-0 group-hover:opacity-100 group-hover:block"
|
||||
"opacity-0 group-hover:block group-hover:opacity-100"
|
||||
)}
|
||||
/>
|
||||
|
||||
|
@ -52,9 +52,9 @@ const Team = ({ team }: TeamPageProps) => {
|
|||
<Avatar
|
||||
alt={member.name || ""}
|
||||
imageSrc={getPlaceholderAvatar(member.avatar, member.username)}
|
||||
className="w-12 h-12 -mt-4"
|
||||
className="-mt-4 h-12 w-12"
|
||||
/>
|
||||
<section className="w-full mt-2 space-y-1">
|
||||
<section className="mt-2 w-full space-y-1">
|
||||
<Text variant="title">{member.name}</Text>
|
||||
<Text variant="subtitle" className="">
|
||||
{member.bio || t("user_from_team", { user: member.name, team: team.name })}
|
||||
|
@ -72,7 +72,7 @@ const Team = ({ team }: TeamPageProps) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<section className="flex flex-wrap justify-center max-w-5xl min-w-full mx-auto lg:min-w-lg gap-x-6 gap-y-6">
|
||||
<section className="lg:min-w-lg mx-auto flex min-w-full max-w-5xl flex-wrap justify-center gap-x-6 gap-y-6">
|
||||
{members.map((member) => {
|
||||
return member.username !== null && <Member key={member.id} member={member} />;
|
||||
})}
|
||||
|
|
|
@ -15,10 +15,10 @@ export function Alert(props: AlertProps) {
|
|||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
"rounded-sm p-3 border border-opacity-20",
|
||||
"rounded-sm border border-opacity-20 p-3",
|
||||
props.className,
|
||||
severity === "error" && "bg-red-50 text-red-800 border-red-900",
|
||||
severity === "warning" && "bg-yellow-50 text-yellow-700 border-yellow-700",
|
||||
severity === "error" && "border-red-900 bg-red-50 text-red-800",
|
||||
severity === "warning" && "border-yellow-700 bg-yellow-50 text-yellow-700",
|
||||
severity === "success" && "bg-gray-900 text-white"
|
||||
)}>
|
||||
<div className="flex">
|
||||
|
@ -33,7 +33,7 @@ export function Alert(props: AlertProps) {
|
|||
<CheckCircleIcon className={classNames("h-5 w-5 text-gray-400")} aria-hidden="true" />
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-grow ml-3">
|
||||
<div className="ml-3 flex-grow">
|
||||
<h3 className="text-sm font-medium">{props.title}</h3>
|
||||
<div className="text-sm">{props.message}</div>
|
||||
</div>
|
||||
|
|
|
@ -14,26 +14,26 @@ interface Props {
|
|||
|
||||
export default function AuthContainer(props: React.PropsWithChildren<Props>) {
|
||||
return (
|
||||
<div className="flex flex-col justify-center min-h-screen py-12 bg-neutral-50 sm:px-6 lg:px-8">
|
||||
<div className="flex min-h-screen flex-col justify-center bg-neutral-50 py-12 sm:px-6 lg:px-8">
|
||||
<HeadSeo title={props.title} description={props.description} />
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
{props.showLogo && (
|
||||
<img className="h-6 mx-auto" src="/calendso-logo-white-word.svg" alt="Cal.com Logo" />
|
||||
<img className="mx-auto h-6" src="/calendso-logo-white-word.svg" alt="Cal.com Logo" />
|
||||
)}
|
||||
{props.heading && (
|
||||
<h2 className="mt-6 text-3xl font-bold text-center font-cal text-neutral-900">{props.heading}</h2>
|
||||
<h2 className="mt-6 text-center font-cal text-3xl font-bold text-neutral-900">{props.heading}</h2>
|
||||
)}
|
||||
</div>
|
||||
{props.loading && (
|
||||
<div className="absolute z-50 flex items-center w-full h-screen bg-gray-50">
|
||||
<div className="absolute z-50 flex h-screen w-full items-center bg-gray-50">
|
||||
<Loader />
|
||||
</div>
|
||||
)}
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="px-4 py-8 mx-2 bg-white border rounded-sm sm:px-10 border-neutral-200">
|
||||
<div className="mx-2 rounded-sm border border-neutral-200 bg-white px-4 py-8 sm:px-10">
|
||||
{props.children}
|
||||
</div>
|
||||
<div className="mt-4 text-sm text-center text-neutral-600">{props.footerText}</div>
|
||||
<div className="mt-4 text-center text-sm text-neutral-600">{props.footerText}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -36,7 +36,7 @@ export default function Avatar(props: AvatarProps) {
|
|||
return title ? (
|
||||
<Tooltip.Tooltip delayDuration={300}>
|
||||
<Tooltip.TooltipTrigger className="cursor-default">{avatar}</Tooltip.TooltipTrigger>
|
||||
<Tooltip.Content className="p-2 text-sm rounded-sm shadow-sm bg-brand text-brandcontrast">
|
||||
<Tooltip.Content className="rounded-sm bg-brand p-2 text-sm text-brandcontrast shadow-sm">
|
||||
<Tooltip.Arrow />
|
||||
{title}
|
||||
</Tooltip.Content>
|
||||
|
|
|
@ -27,7 +27,7 @@ export const AvatarGroup = function AvatarGroup(props: AvatarGroupProps) {
|
|||
: [];*/
|
||||
|
||||
return (
|
||||
<ul className={classNames("flex -rtl:space-x-reverse space-x-2 overflow-hidden", props.className)}>
|
||||
<ul className={classNames("-rtl:space-x-reverse flex space-x-2 overflow-hidden", props.className)}>
|
||||
{props.items.slice(0, props.truncateAfter).map((item, idx) => {
|
||||
if (item.image != null) {
|
||||
return (
|
||||
|
|
|
@ -13,7 +13,7 @@ export const Badge = function Badge(props: BadgeProps) {
|
|||
<span
|
||||
{...passThroughProps}
|
||||
className={classNames(
|
||||
"font-bold px-2 py-0.5 inline-block rounded-sm text-xs",
|
||||
"inline-block rounded-sm px-2 py-0.5 text-xs font-bold",
|
||||
variant === "default" && "bg-yellow-100 text-yellow-800",
|
||||
variant === "success" && "bg-green-100 text-green-800",
|
||||
variant === "gray" && "bg-gray-200 text-gray-800",
|
||||
|
|
|
@ -93,17 +93,17 @@ export const Button = forwardRef<HTMLAnchorElement | HTMLButtonElement, ButtonPr
|
|||
<StartIcon
|
||||
className={classNames(
|
||||
"inline",
|
||||
size === "icon" ? "w-5 h-5 " : "w-5 h-5 ltr:mr-2 rtl:ml-2 rtl:ml-2 rtl:-mr-1 -ml-1"
|
||||
size === "icon" ? "h-5 w-5 " : "-ml-1 h-5 w-5 ltr:mr-2 rtl:ml-2 rtl:ml-2 rtl:-mr-1"
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{props.children}
|
||||
{loading && (
|
||||
<div className="absolute transform -translate-x-1/2 -translate-y-1/2 top-1/2 left-1/2">
|
||||
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform">
|
||||
<svg
|
||||
className={classNames(
|
||||
"w-5 h-5 mx-4 animate-spin",
|
||||
color === "primary" ? "dark:text-black text-white" : "text-black"
|
||||
"mx-4 h-5 w-5 animate-spin",
|
||||
color === "primary" ? "text-white dark:text-black" : "text-black"
|
||||
)}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
|
@ -122,7 +122,7 @@ export const Button = forwardRef<HTMLAnchorElement | HTMLButtonElement, ButtonPr
|
|||
</svg>
|
||||
</div>
|
||||
)}
|
||||
{EndIcon && <EndIcon className="inline w-5 h-5 ltr:ml-2 rtl:mr-2 -mr-1" />}
|
||||
{EndIcon && <EndIcon className="-mr-1 inline h-5 w-5 ltr:ml-2 rtl:mr-2" />}
|
||||
</>
|
||||
);
|
||||
return props.href ? (
|
||||
|
|
|
@ -12,7 +12,7 @@ export const DropdownMenuTrigger = forwardRef<HTMLButtonElement, DropdownMenuTri
|
|||
className={
|
||||
props.asChild
|
||||
? className
|
||||
: `relative inline-flex items-center px-3 py-2 ltr:ml-2 rtl:mr-2 text-sm font-medium text-gray-700 bg-transparent rounded-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-1 focus:bg-gray-100 focus:ring-neutral-500 group-hover:text-black ${className}`
|
||||
: `relative inline-flex items-center rounded-sm bg-transparent px-3 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-neutral-500 focus:ring-offset-1 group-hover:text-black ltr:ml-2 rtl:mr-2 ${className}`
|
||||
}
|
||||
ref={forwardedRef}
|
||||
/>
|
||||
|
@ -26,7 +26,7 @@ export const DropdownMenuContent = forwardRef<HTMLDivElement, DropdownMenuConten
|
|||
return (
|
||||
<DropdownMenuPrimitive.Content
|
||||
{...props}
|
||||
className="z-10 w-48 mt-1 text-sm origin-top-right bg-white rounded-sm shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
|
||||
className="z-10 mt-1 w-48 origin-top-right rounded-sm bg-white text-sm shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
|
||||
ref={forwardedRef}>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.Content>
|
||||
|
|
|
@ -7,7 +7,7 @@ export default function InfoBadge({ content }: { content: string }) {
|
|||
<>
|
||||
<Tooltip content={content}>
|
||||
<span title={content}>
|
||||
<InformationCircleIcon className="relative w-4 h-4 mt-px text-gray-500 top-px left-1 right-1" />
|
||||
<InformationCircleIcon className="relative top-px left-1 right-1 mt-px h-4 w-4 text-gray-500" />
|
||||
</span>
|
||||
</Tooltip>
|
||||
</>
|
||||
|
|
|
@ -12,8 +12,8 @@ export default function LinkIconButton(props: LinkIconButtonProps) {
|
|||
<button
|
||||
type="button"
|
||||
{...props}
|
||||
className="flex items-center px-2 py-1 text-sm font-medium text-gray-700 rounded-sm text-md hover:text-gray-900 hover:bg-gray-200">
|
||||
<props.Icon className="w-4 h-4 ltr:mr-2 rtl:ml-2 text-neutral-500" />
|
||||
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">
|
||||
<props.Icon className="h-4 w-4 text-neutral-500 ltr:mr-2 rtl:ml-2" />
|
||||
{props.children}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -14,19 +14,19 @@ export default function ModalContainer(props: Props) {
|
|||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true">
|
||||
<div className="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div
|
||||
className="fixed inset-0 z-0 transition-opacity bg-gray-500 bg-opacity-75"
|
||||
className="fixed inset-0 z-0 bg-gray-500 bg-opacity-75 transition-opacity"
|
||||
aria-hidden="true"></div>
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||
<span className="hidden sm:inline-block sm:h-screen sm:align-middle" aria-hidden="true">
|
||||
​
|
||||
</span>
|
||||
<div
|
||||
className={classNames(
|
||||
"inline-block min-w-96 px-4 pt-5 pb-4 text-left align-bottom transition-all transform bg-white rounded-lg shadow-xl sm:my-8 sm:align-middle sm:p-6",
|
||||
"inline-block min-w-96 transform rounded-lg bg-white px-4 pt-5 pb-4 text-left align-bottom shadow-xl transition-all sm:my-8 sm:p-6 sm:align-middle",
|
||||
{
|
||||
"sm:max-w-lg sm:w-full ": !props.wide,
|
||||
"sm:max-w-4xl sm:w-4xl": props.wide,
|
||||
"sm:w-full sm:max-w-lg ": !props.wide,
|
||||
"sm:w-4xl sm:max-w-4xl": props.wide,
|
||||
"overflow-scroll": props.scroll,
|
||||
"!p-0": props.noPadding,
|
||||
}
|
||||
|
|
|
@ -5,17 +5,17 @@ import { useLocale } from "@lib/hooks/useLocale";
|
|||
const PoweredByCal = () => {
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<div className="text-xs text-center sm:text-right p-1">
|
||||
<div className="p-1 text-center text-xs sm:text-right">
|
||||
<Link href={`https://cal.com?utm_source=embed&utm_medium=powered-by-button`}>
|
||||
<a target="_blank" className="dark:text-white text-gray-500 opacity-50 hover:opacity-100">
|
||||
<a target="_blank" className="text-gray-500 opacity-50 hover:opacity-100 dark:text-white">
|
||||
{t("powered_by")}{" "}
|
||||
<img
|
||||
className="dark:hidden w-auto inline h-[10px] relative -mt-px"
|
||||
className="relative -mt-px inline h-[10px] w-auto dark:hidden"
|
||||
src="https://cal.com/logo.svg"
|
||||
alt="Cal.com Logo"
|
||||
/>
|
||||
<img
|
||||
className="hidden dark:inline w-auto h-[10px] relativ -mt-px"
|
||||
className="relativ -mt-px hidden h-[10px] w-auto dark:inline"
|
||||
src="https://cal.com/logo-white.svg"
|
||||
alt="Cal.com Logo"
|
||||
/>
|
||||
|
|
|
@ -66,11 +66,11 @@ export const Scheduler = ({ availability, setAvailability, timeZone, setTimeZone
|
|||
};
|
||||
|
||||
const OpeningHours = ({ idx, item }: { idx: number; item: Availability }) => (
|
||||
<li className="flex justify-between py-2 border-b">
|
||||
<li className="flex justify-between border-b py-2">
|
||||
<div className="flex flex-col space-y-4 lg:inline-flex">
|
||||
<WeekdaySelect defaultValue={item.days} onSelect={(selected: number[]) => (item.days = selected)} />
|
||||
<button
|
||||
className="px-3 py-2 text-sm rounded-sm bg-neutral-100"
|
||||
className="rounded-sm bg-neutral-100 px-3 py-2 text-sm"
|
||||
type="button"
|
||||
onClick={() => setEditSchedule(idx)}>
|
||||
{item.startTime.toLocaleTimeString(i18n.language, {
|
||||
|
@ -89,8 +89,8 @@ export const Scheduler = ({ availability, setAvailability, timeZone, setTimeZone
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => removeScheduleAt(idx)}
|
||||
className="px-2 py-1 ml-1 bg-transparent btn-sm">
|
||||
<TrashIcon className="inline w-5 h-5 -mt-1 text-gray-400" />
|
||||
className="btn-sm ml-1 bg-transparent px-2 py-1">
|
||||
<TrashIcon className="-mt-1 inline h-5 w-5 text-gray-400" />
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
|
@ -108,7 +108,7 @@ export const Scheduler = ({ availability, setAvailability, timeZone, setTimeZone
|
|||
id="timeZone"
|
||||
value={timeZone}
|
||||
onChange={(tz: ITimezoneOption) => setTimeZone(tz.value)}
|
||||
className="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-brand focus:ring-black sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -13,12 +13,12 @@ export default function SettingInputContainer({
|
|||
<div className="space-y-3">
|
||||
<div className="block sm:flex">
|
||||
<div className="mb-4 min-w-48 sm:mb-0">
|
||||
<label htmlFor={htmlFor} className="flex mt-1 text-sm font-medium text-neutral-700">
|
||||
<Icon className="w-4 h-4 ltr:mr-2 rtl:ml-2 mt-0.5 text-neutral-500" />
|
||||
<label htmlFor={htmlFor} className="mt-1 flex text-sm font-medium text-neutral-700">
|
||||
<Icon className="mt-0.5 h-4 w-4 text-neutral-500 ltr:mr-2 rtl:ml-2" />
|
||||
{label}
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex-grow w-full">{Input}</div>
|
||||
<div className="w-full flex-grow">{Input}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -20,16 +20,16 @@ export default function Switch(props: SwitchProps) {
|
|||
};
|
||||
const id = useId();
|
||||
return (
|
||||
<div className="flex items-center h-[20px]">
|
||||
<div className="flex h-[20px] items-center">
|
||||
<PrimitiveSwitch.Root
|
||||
className={classNames(checked ? "bg-gray-900" : "bg-gray-400", "rounded-sm w-[36px] p-0.5 h-[20px]")}
|
||||
className={classNames(checked ? "bg-gray-900" : "bg-gray-400", "h-[20px] w-[36px] rounded-sm p-0.5")}
|
||||
checked={checked}
|
||||
onCheckedChange={onPrimitiveCheckedChange}
|
||||
{...primitiveProps}>
|
||||
<PrimitiveSwitch.Thumb
|
||||
id={id}
|
||||
className={classNames(
|
||||
"bg-white w-[16px] h-[16px] block transition-transform",
|
||||
"block h-[16px] w-[16px] bg-white transition-transform",
|
||||
checked ? "translate-x-[16px]" : "translate-x-0"
|
||||
)}
|
||||
/>
|
||||
|
@ -37,7 +37,7 @@ export default function Switch(props: SwitchProps) {
|
|||
{label && (
|
||||
<Label.Root
|
||||
htmlFor={id}
|
||||
className="text-sm font-medium align-text-top cursor-pointer text-neutral-700 ltr:ml-3 rtl:mr-3">
|
||||
className="cursor-pointer align-text-top text-sm font-medium text-neutral-700 ltr:ml-3 rtl:mr-3">
|
||||
{label}
|
||||
</Label.Root>
|
||||
)}
|
||||
|
|
|
@ -24,7 +24,7 @@ const TableActions: FC<Props> = ({ actions }) => {
|
|||
const { t } = useLocale();
|
||||
return (
|
||||
<>
|
||||
<div className="rtl:space-x-reverse space-x-2 hidden lg:block">
|
||||
<div className="hidden space-x-2 rtl:space-x-reverse lg:block">
|
||||
{actions.map((action) => (
|
||||
<Button
|
||||
key={action.id}
|
||||
|
@ -38,11 +38,11 @@ const TableActions: FC<Props> = ({ actions }) => {
|
|||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<Menu as="div" className="inline-block lg:hidden text-left ">
|
||||
<Menu as="div" className="inline-block text-left lg:hidden ">
|
||||
{({ open }) => (
|
||||
<>
|
||||
<div>
|
||||
<Menu.Button className="text-neutral-400 mt-1 p-2 border border-transparent hover:border-gray-200">
|
||||
<Menu.Button className="mt-1 border border-transparent p-2 text-neutral-400 hover:border-gray-200">
|
||||
<span className="sr-only">{t("open_options")}</span>
|
||||
<DotsHorizontalIcon className="h-5 w-5" aria-hidden="true" />
|
||||
</Menu.Button>
|
||||
|
@ -59,7 +59,7 @@ const TableActions: FC<Props> = ({ actions }) => {
|
|||
leaveTo="transform opacity-0 scale-95">
|
||||
<Menu.Items
|
||||
static
|
||||
className="origin-top-right absolute right-0 mt-2 w-56 rounded-sm shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none divide-y divide-neutral-100">
|
||||
className="absolute right-0 mt-2 w-56 origin-top-right divide-y divide-neutral-100 rounded-sm bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
|
||||
<div className="py-1">
|
||||
{actions.map((action) => {
|
||||
const Element = typeof action.onClick === "function" ? "span" : "a";
|
||||
|
@ -74,7 +74,7 @@ const TableActions: FC<Props> = ({ actions }) => {
|
|||
"group flex items-center px-4 py-2 text-sm font-medium"
|
||||
)}>
|
||||
<action.icon
|
||||
className="ltr:mr-3 h-5 w-5 text-neutral-400 group-hover:text-neutral-500"
|
||||
className="h-5 w-5 text-neutral-400 group-hover:text-neutral-500 ltr:mr-3"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
{action.label}
|
||||
|
|
|
@ -33,8 +33,8 @@ export const WeekdaySelect = (props: WeekdaySelectProps) => {
|
|||
toggleDay(idx);
|
||||
}}
|
||||
className={`
|
||||
w-10 h-10
|
||||
bg-brand text-brandcontrast focus:outline-none px-3 py-1 rounded
|
||||
h-10 w-10
|
||||
rounded bg-brand px-3 py-1 text-brandcontrast focus:outline-none
|
||||
${activeDays[idx + 1] ? "rounded-r-none" : ""}
|
||||
${activeDays[idx - 1] ? "rounded-l-none" : ""}
|
||||
${idx === 0 ? "rounded-l" : ""}
|
||||
|
@ -50,7 +50,7 @@ export const WeekdaySelect = (props: WeekdaySelectProps) => {
|
|||
toggleDay(idx);
|
||||
}}
|
||||
style={{ marginTop: "1px", marginBottom: "1px" }}
|
||||
className={`w-10 h-10 bg-gray-50 focus:outline-none px-3 py-1 rounded-none ${
|
||||
className={`h-10 w-10 rounded-none bg-gray-50 px-3 py-1 focus:outline-none ${
|
||||
idx === 0 ? "rounded-l" : "border-l-0"
|
||||
} ${idx === days.length - 1 ? "rounded-r" : ""}`}>
|
||||
{day}
|
||||
|
|
|
@ -69,13 +69,13 @@ const ColorPicker = (props: ColorPickerProps) => {
|
|||
const close = useCallback(() => toggle(false), []);
|
||||
useOnClickOutside(popover, close);
|
||||
return (
|
||||
<div className="relative flex items-center justify-center mt-1">
|
||||
<div className="relative mt-1 flex items-center justify-center">
|
||||
<Swatch size="sm" backgroundColor={color} onClick={() => toggle(!isOpen)} />
|
||||
|
||||
{isOpen && (
|
||||
<div className="popover" ref={popover}>
|
||||
<HexColorPicker
|
||||
className="!w-32 !h-32 !absolute !top-10 !left-0 !z-10"
|
||||
className="!absolute !top-10 !left-0 !z-10 !h-32 !w-32"
|
||||
color={color}
|
||||
onChange={(val) => {
|
||||
setColor(val);
|
||||
|
@ -85,7 +85,7 @@ const ColorPicker = (props: ColorPickerProps) => {
|
|||
</div>
|
||||
)}
|
||||
<HexColorInput
|
||||
className="block w-full px-3 py-2 ml-1 border border-gray-300 rounded-sm shadow-sm focus:outline-none focus:ring-neutral-800 focus:border-neutral-800 sm:text-sm"
|
||||
className="ml-1 block w-full rounded-sm border border-gray-300 px-3 py-2 shadow-sm focus:border-neutral-800 focus:outline-none focus:ring-neutral-800 sm:text-sm"
|
||||
color={color}
|
||||
onChange={(val) => {
|
||||
setColor(val);
|
||||
|
|
|
@ -7,7 +7,7 @@ type Props = InputHTMLAttributes<HTMLInputElement> & {
|
|||
|
||||
const CheckboxField = forwardRef<HTMLInputElement, Props>(({ label, description, ...rest }, ref) => {
|
||||
return (
|
||||
<div className="items-center block sm:flex">
|
||||
<div className="block items-center sm:flex">
|
||||
<div className="mb-4 min-w-48 sm:mb-0">
|
||||
<label htmlFor={rest.id} className="flex text-sm font-medium text-neutral-700">
|
||||
{label}
|
||||
|
@ -15,15 +15,15 @@ const CheckboxField = forwardRef<HTMLInputElement, Props>(({ label, description,
|
|||
</div>
|
||||
<div className="w-full">
|
||||
<div className="relative flex items-start">
|
||||
<div className="flex items-center h-5">
|
||||
<div className="flex h-5 items-center">
|
||||
<input
|
||||
{...rest}
|
||||
ref={ref}
|
||||
type="checkbox"
|
||||
className="w-4 h-4 border-gray-300 rounded focus:ring-primary-500 text-primary-600"
|
||||
className="h-4 w-4 rounded border-gray-300 text-primary-600 focus:ring-primary-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="ltr:ml-3 rtl:mr-3 text-sm">
|
||||
<div className="text-sm ltr:ml-3 rtl:mr-3">
|
||||
<p className="text-neutral-900">{description}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import { CheckIcon, XIcon } from "@heroicons/react/outline";
|
||||
import React, { ForwardedRef, useEffect, useState } from "react";
|
||||
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
|
||||
import Avatar from "@components/ui/Avatar";
|
||||
import Select from "@components/ui/form/Select";
|
||||
import { CheckIcon, XIcon } from "@heroicons/react/outline";
|
||||
import { useLocale } from "@lib/hooks/useLocale";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { MultiValue } from "react-select";
|
||||
|
||||
type CheckedSelectValue = {
|
||||
avatar: string;
|
||||
label: string;
|
||||
value: string;
|
||||
disabled?: boolean;
|
||||
}[];
|
||||
|
||||
export type CheckedSelectProps = {
|
||||
|
@ -21,7 +21,7 @@ export type CheckedSelectProps = {
|
|||
disabled: boolean;
|
||||
};
|
||||
|
||||
export const CheckedSelect = React.forwardRef((props: CheckedSelectProps, ref: ForwardedRef<unknown>) => {
|
||||
export const CheckedSelect = (props: CheckedSelectProps) => {
|
||||
const [selectedOptions, setSelectedOptions] = useState<CheckedSelectValue>(props.defaultValue || []);
|
||||
const { t } = useLocale();
|
||||
|
||||
|
@ -29,18 +29,6 @@ export const CheckedSelect = React.forwardRef((props: CheckedSelectProps, ref: F
|
|||
props.onChange(selectedOptions);
|
||||
}, [selectedOptions]);
|
||||
|
||||
const formatOptionLabel = ({ label, avatar, disabled }) => (
|
||||
<div className="flex">
|
||||
<Avatar className="h-6 w-6 rounded-full mr-3" displayName={label} imageSrc={avatar} />
|
||||
{label}
|
||||
{disabled && (
|
||||
<div className="flex-grow">
|
||||
<CheckIcon className="text-neutral-500 w-6 h-6 float-right" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
const options = props.options.map((option) => ({
|
||||
...option,
|
||||
disabled: !!selectedOptions.find((selectedOption) => selectedOption.value === option.value),
|
||||
|
@ -49,7 +37,7 @@ export const CheckedSelect = React.forwardRef((props: CheckedSelectProps, ref: F
|
|||
const removeOption = (value: string) =>
|
||||
setSelectedOptions(selectedOptions.filter((option) => option.value !== value));
|
||||
|
||||
const changeHandler = (selections) =>
|
||||
const changeHandler = (selections: MultiValue<CheckedSelectValue[number]>) =>
|
||||
selections.forEach((selected) => {
|
||||
if (selectedOptions.find((option) => option.value === selected.value)) {
|
||||
removeOption(selected.value);
|
||||
|
@ -60,8 +48,7 @@ export const CheckedSelect = React.forwardRef((props: CheckedSelectProps, ref: F
|
|||
|
||||
return (
|
||||
<>
|
||||
<Select
|
||||
ref={ref}
|
||||
<Select<CheckedSelectValue[number], true>
|
||||
styles={{
|
||||
option: (styles, { isDisabled }) => ({
|
||||
...styles,
|
||||
|
@ -71,29 +58,39 @@ export const CheckedSelect = React.forwardRef((props: CheckedSelectProps, ref: F
|
|||
name={props.name}
|
||||
placeholder={props.placeholder || t("select")}
|
||||
isSearchable={false}
|
||||
formatOptionLabel={formatOptionLabel}
|
||||
formatOptionLabel={({ label, avatar, disabled }) => (
|
||||
<div className="flex">
|
||||
<Avatar className="mr-3 h-6 w-6 rounded-full" alt={label} imageSrc={avatar} />
|
||||
{label}
|
||||
{disabled && (
|
||||
<div className="flex-grow">
|
||||
<CheckIcon className="float-right h-6 w-6 text-neutral-500" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
options={options}
|
||||
isMulti
|
||||
value={props.placeholder || t("select")}
|
||||
// value={props.placeholder || t("select")}
|
||||
onChange={changeHandler}
|
||||
/>
|
||||
{selectedOptions.map((option) => (
|
||||
<div key={option.value} className="border border-1 p-2 font-medium">
|
||||
<div key={option.value} className="border-1 border p-2 font-medium">
|
||||
<Avatar
|
||||
className="w-6 h-6 rounded-full inline ltr:mr-2 rtl:ml-2"
|
||||
className="inline h-6 w-6 rounded-full ltr:mr-2 rtl:ml-2"
|
||||
imageSrc={option.avatar}
|
||||
displayName={option.label}
|
||||
alt={option.label}
|
||||
/>
|
||||
{option.label}
|
||||
<XIcon
|
||||
onClick={() => changeHandler([option])}
|
||||
className="cursor-pointer h-5 w-5 mt-0.5 text-neutral-500 float-right"
|
||||
className="float-right mt-0.5 h-5 w-5 cursor-pointer text-neutral-500"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
CheckedSelect.displayName = "CheckedSelect";
|
||||
|
||||
|
|
|
@ -16,11 +16,11 @@ export const DatePicker = ({ date, onDatesChange, className }: Props) => {
|
|||
return (
|
||||
<PrimitiveDatePicker
|
||||
className={classNames(
|
||||
"p-1 pl-2 border border-gray-300 rounded-sm shadow-sm focus:ring-primary-500 focus:border-primary-500 sm:text-sm",
|
||||
"rounded-sm border border-gray-300 p-1 pl-2 shadow-sm focus:border-primary-500 focus:ring-primary-500 sm:text-sm",
|
||||
className
|
||||
)}
|
||||
clearIcon={null}
|
||||
calendarIcon={<CalendarIcon className="w-5 h-5 text-gray-500" />}
|
||||
calendarIcon={<CalendarIcon className="h-5 w-5 text-gray-500" />}
|
||||
value={date}
|
||||
onChange={onDatesChange}
|
||||
/>
|
||||
|
|
|
@ -14,13 +14,13 @@ type Props = {
|
|||
export const DateRangePicker = ({ startDate, endDate, onDatesChange }: Props) => {
|
||||
return (
|
||||
<PrimitiveDateRangePicker
|
||||
className="border-gray-300 rounded-sm focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
|
||||
className="rounded-sm border-gray-300 focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
|
||||
clearIcon={null}
|
||||
calendarIcon={<CalendarIcon className="h-5 w-5 text-gray-500" />}
|
||||
rangeDivider={<ArrowRightIcon className="h-4 w-4 text-gray-400 ltr:mr-2 rtl:ml-2" />}
|
||||
value={[startDate, endDate]}
|
||||
onChange={([startDate, endDate]) => {
|
||||
onDatesChange({ startDate, endDate });
|
||||
if (typeof onDatesChange === "function") onDatesChange({ startDate, endDate });
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -10,7 +10,7 @@ const MinutesField = forwardRef<HTMLInputElement, Props>(({ label, ...rest }, re
|
|||
<div className="block sm:flex">
|
||||
{!!label && (
|
||||
<div className="mb-4 min-w-48 sm:mb-0">
|
||||
<label htmlFor={rest.id} className="flex items-center h-full text-sm font-medium text-neutral-700">
|
||||
<label htmlFor={rest.id} className="flex h-full items-center text-sm font-medium text-neutral-700">
|
||||
{label}
|
||||
</label>
|
||||
</div>
|
||||
|
@ -22,11 +22,11 @@ const MinutesField = forwardRef<HTMLInputElement, Props>(({ label, ...rest }, re
|
|||
ref={ref}
|
||||
type="number"
|
||||
className={classNames(
|
||||
"block w-full pl-2 pr-12 border-gray-300 rounded-sm focus:ring-primary-500 focus:border-primary-500 sm:text-sm",
|
||||
"block w-full rounded-sm border-gray-300 pl-2 pr-12 focus:border-primary-500 focus:ring-primary-500 sm:text-sm",
|
||||
rest.className
|
||||
)}
|
||||
/>
|
||||
<div className="absolute inset-y-0 right-0 flex items-center pr-3 pointer-events-none">
|
||||
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
|
||||
<span className="text-gray-500 sm:text-sm" id="duration">
|
||||
mins
|
||||
</span>
|
||||
|
|
|
@ -9,7 +9,7 @@ export const PhoneInput = (props: Optional<PhoneInputProps, "onChange">) => (
|
|||
<BasePhoneInput
|
||||
{...props}
|
||||
className={classNames(
|
||||
"shadow-sm rounded-sm block w-full py-px px-3 border border-1 border-gray-300 ring-black focus-within:ring-1 focus-within:border-brand dark:border-black dark:text-white dark:bg-black",
|
||||
"border-1 block w-full rounded-sm border border-gray-300 py-px px-3 shadow-sm ring-black focus-within:border-brand focus-within:ring-1 dark:border-black dark:bg-black dark:text-white",
|
||||
props.className
|
||||
)}
|
||||
onChange={() => {
|
||||
|
|
|
@ -139,21 +139,21 @@ const ScheduleBlock = ({ name, day, weekday }: ScheduleBlockProps) => {
|
|||
};
|
||||
|
||||
return (
|
||||
<fieldset className="flex flex-col space-y-2 sm:space-y-0 sm:flex-row justify-between py-5 min-h-[86px]">
|
||||
<fieldset className="flex min-h-[86px] flex-col justify-between space-y-2 py-5 sm:flex-row sm:space-y-0">
|
||||
<div className="w-1/3">
|
||||
<label className="flex items-center space-x-2 rtl:space-x-reverse">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={fields.length > 0}
|
||||
onChange={(e) => (e.target.checked ? replace([defaultDayRange]) : replace([]))}
|
||||
className="inline-block border-gray-300 rounded-sm focus:ring-neutral-500 text-neutral-900"
|
||||
className="inline-block rounded-sm border-gray-300 text-neutral-900 focus:ring-neutral-500"
|
||||
/>
|
||||
<span className="inline-block text-sm capitalize">{weekday}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex-grow">
|
||||
{fields.map((field, index) => (
|
||||
<div key={field.id} className="flex justify-between mb-1">
|
||||
<div key={field.id} className="mb-1 flex justify-between">
|
||||
<div className="flex items-center space-x-2 rtl:space-x-reverse">
|
||||
<TimeRangeField name={`${name}.${day}.${index}`} />
|
||||
</div>
|
||||
|
|
|
@ -11,7 +11,7 @@ const RadioArea = (props: RadioAreaProps) => {
|
|||
return (
|
||||
<label
|
||||
className={classNames(
|
||||
"block border border-1 p-4 focus:outline-none focus:ring focus:ring-neutral-500",
|
||||
"border-1 block border p-4 focus:outline-none focus:ring focus:ring-neutral-500",
|
||||
props.checked && "border-brand",
|
||||
props.className
|
||||
)}>
|
||||
|
|
|
@ -7,13 +7,15 @@ import { useLocale } from "@lib/hooks/useLocale";
|
|||
|
||||
import { RadioArea, RadioAreaGroup } from "@components/ui/form/radio-area/RadioAreaGroup";
|
||||
|
||||
type OptionProps = React.OptionHTMLAttributes<HTMLOptionElement> & {
|
||||
interface OptionProps
|
||||
extends Pick<React.OptionHTMLAttributes<HTMLOptionElement>, "value" | "label" | "className"> {
|
||||
description?: string;
|
||||
};
|
||||
}
|
||||
|
||||
type RadioAreaSelectProps = React.SelectHTMLAttributes<HTMLSelectElement> & {
|
||||
interface RadioAreaSelectProps extends Omit<React.SelectHTMLAttributes<HTMLSelectElement>, "onChange"> {
|
||||
options: OptionProps[]; // allow options to be passed programmatically, like options={}
|
||||
};
|
||||
onChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
export const Select = function RadioAreaSelect(props: RadioAreaSelectProps) {
|
||||
const { t } = useLocale();
|
||||
|
@ -23,7 +25,7 @@ export const Select = function RadioAreaSelect(props: RadioAreaSelectProps) {
|
|||
placeholder = t("select"),
|
||||
} = props;
|
||||
|
||||
const getLabel = (value: string | ReadonlyArray<string> | number) =>
|
||||
const getLabel = (value: string | ReadonlyArray<string> | number | undefined) =>
|
||||
options.find((option: OptionProps) => option.value === value)?.label;
|
||||
|
||||
return (
|
||||
|
@ -32,8 +34,8 @@ export const Select = function RadioAreaSelect(props: RadioAreaSelectProps) {
|
|||
type="button"
|
||||
disabled={disabled}
|
||||
className={classNames(
|
||||
"mb-1 cursor-pointer focus:ring-primary-500 text-left border border-1 bg-white p-2 shadow-sm block w-full sm:text-sm border-gray-300 rounded-sm",
|
||||
disabled && "focus:ring-0 cursor-default bg-gray-200 "
|
||||
"border-1 mb-1 block w-full cursor-pointer rounded-sm border border-gray-300 bg-white p-2 text-left shadow-sm focus:ring-primary-500 sm:text-sm",
|
||||
disabled && "cursor-default bg-gray-200 focus:ring-0 "
|
||||
)}>
|
||||
{getLabel(props.value) ?? placeholder}
|
||||
<ChevronDownIcon className="float-right h-5 w-5 text-neutral-500" />
|
||||
|
@ -41,8 +43,11 @@ export const Select = function RadioAreaSelect(props: RadioAreaSelectProps) {
|
|||
<CollapsibleContent>
|
||||
<RadioAreaGroup className="space-y-2 text-sm" name={props.name} onChange={props.onChange}>
|
||||
{options.map((option) => (
|
||||
<RadioArea {...option} key={option.value} defaultChecked={props.value === option.value}>
|
||||
<strong className="block mb-1">{option.label}</strong>
|
||||
<RadioArea
|
||||
{...option}
|
||||
key={Array.isArray(option.value) ? option.value.join(",") : `${option.value}`}
|
||||
defaultChecked={props.value === option.value}>
|
||||
<strong className="mb-1 block">{option.label}</strong>
|
||||
<p>{option.description}</p>
|
||||
</RadioArea>
|
||||
))}
|
||||
|
|
|
@ -5,31 +5,21 @@ import { useLocale } from "@lib/hooks/useLocale";
|
|||
|
||||
import Button from "@components/ui/Button";
|
||||
|
||||
export default function SetTimesModal(props) {
|
||||
interface SetTimesModalProps {
|
||||
startTime: number;
|
||||
endTime: number;
|
||||
onChange: (times: { startTime: number; endTime: number }) => void;
|
||||
onExit: (...p: unknown[]) => void;
|
||||
}
|
||||
|
||||
export default function SetTimesModal(props: SetTimesModalProps) {
|
||||
const { t } = useLocale();
|
||||
const [startHours, startMinutes] = [Math.floor(props.startTime / 60), props.startTime % 60];
|
||||
const [endHours, endMinutes] = [Math.floor(props.endTime / 60), props.endTime % 60];
|
||||
|
||||
const startHoursRef = useRef<HTMLInputElement>();
|
||||
const startMinsRef = useRef<HTMLInputElement>();
|
||||
const endHoursRef = useRef<HTMLInputElement>();
|
||||
const endMinsRef = useRef<HTMLInputElement>();
|
||||
|
||||
function updateStartEndTimesHandler(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const enteredStartHours = parseInt(startHoursRef.current.value);
|
||||
const enteredStartMins = parseInt(startMinsRef.current.value);
|
||||
const enteredEndHours = parseInt(endHoursRef.current.value);
|
||||
const enteredEndMins = parseInt(endMinsRef.current.value);
|
||||
|
||||
props.onChange({
|
||||
startTime: enteredStartHours * 60 + enteredStartMins,
|
||||
endTime: enteredEndHours * 60 + enteredEndMins,
|
||||
});
|
||||
|
||||
props.onExit(0);
|
||||
}
|
||||
const startHoursRef = useRef<HTMLInputElement>(null!);
|
||||
const startMinsRef = useRef<HTMLInputElement>(null!);
|
||||
const endHoursRef = useRef<HTMLInputElement>(null!);
|
||||
const endMinsRef = useRef<HTMLInputElement>(null!);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -37,19 +27,19 @@ export default function SetTimesModal(props) {
|
|||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true">
|
||||
<div className="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div
|
||||
className="fixed inset-0 z-0 transition-opacity bg-gray-500 bg-opacity-75"
|
||||
className="fixed inset-0 z-0 bg-gray-500 bg-opacity-75 transition-opacity"
|
||||
aria-hidden="true"></div>
|
||||
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||
<span className="hidden sm:inline-block sm:h-screen sm:align-middle" aria-hidden="true">
|
||||
​
|
||||
</span>
|
||||
|
||||
<div className="inline-block px-4 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white rounded-lg shadow-xl sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6">
|
||||
<div className="inline-block transform overflow-hidden rounded-lg 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="mb-4 sm:flex sm:items-start">
|
||||
<div className="flex items-center justify-center flex-shrink-0 w-12 h-12 mx-auto bg-blue-100 rounded-full sm:mx-0 sm:h-10 sm:w-10">
|
||||
<ClockIcon className="w-6 h-6 text-black" />
|
||||
<div className="mx-auto flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<ClockIcon className="h-6 w-6 text-black" />
|
||||
</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">
|
||||
|
@ -60,7 +50,7 @@ export default function SetTimesModal(props) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex mb-4">
|
||||
<div className="mb-4 flex">
|
||||
<label className="block w-1/4 pt-2 text-sm font-medium text-gray-700">{t("start_time")}</label>
|
||||
<div>
|
||||
<label htmlFor="startHours" className="sr-only">
|
||||
|
@ -71,15 +61,15 @@ export default function SetTimesModal(props) {
|
|||
type="number"
|
||||
min="0"
|
||||
max="23"
|
||||
maxLength="2"
|
||||
maxLength={2}
|
||||
name="hours"
|
||||
id="startHours"
|
||||
className="block w-full border-gray-300 rounded-md shadow-sm focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-brand focus:ring-black sm:text-sm"
|
||||
placeholder="9"
|
||||
defaultValue={startHours}
|
||||
/>
|
||||
</div>
|
||||
<span className="pt-1 mx-2">:</span>
|
||||
<span className="mx-2 pt-1">:</span>
|
||||
<div>
|
||||
<label htmlFor="startMinutes" className="sr-only">
|
||||
{t("minutes")}
|
||||
|
@ -90,10 +80,10 @@ export default function SetTimesModal(props) {
|
|||
min="0"
|
||||
max="59"
|
||||
step="15"
|
||||
maxLength="2"
|
||||
maxLength={2}
|
||||
name="minutes"
|
||||
id="startMinutes"
|
||||
className="block w-full border-gray-300 rounded-md shadow-sm focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-brand focus:ring-black sm:text-sm"
|
||||
placeholder="30"
|
||||
defaultValue={startMinutes}
|
||||
/>
|
||||
|
@ -110,15 +100,15 @@ export default function SetTimesModal(props) {
|
|||
type="number"
|
||||
min="0"
|
||||
max="24"
|
||||
maxLength="2"
|
||||
maxLength={2}
|
||||
name="hours"
|
||||
id="endHours"
|
||||
className="block w-full border-gray-300 rounded-md shadow-sm focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-brand focus:ring-black sm:text-sm"
|
||||
placeholder="17"
|
||||
defaultValue={endHours}
|
||||
/>
|
||||
</div>
|
||||
<span className="pt-1 mx-2">:</span>
|
||||
<span className="mx-2 pt-1">:</span>
|
||||
<div>
|
||||
<label htmlFor="endMinutes" className="sr-only">
|
||||
{t("minutes")}
|
||||
|
@ -128,18 +118,34 @@ export default function SetTimesModal(props) {
|
|||
type="number"
|
||||
min="0"
|
||||
max="59"
|
||||
maxLength="2"
|
||||
maxLength={2}
|
||||
step="15"
|
||||
name="minutes"
|
||||
id="endMinutes"
|
||||
className="block w-full border-gray-300 rounded-md shadow-sm focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-brand focus:ring-black sm:text-sm"
|
||||
placeholder="30"
|
||||
defaultValue={endMinutes}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-4 sm:flex sm:flex-row-reverse">
|
||||
<Button onClick={updateStartEndTimesHandler} type="submit">
|
||||
<Button
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const enteredStartHours = parseInt(startHoursRef.current.value);
|
||||
const enteredStartMins = parseInt(startMinsRef.current.value);
|
||||
const enteredEndHours = parseInt(endHoursRef.current.value);
|
||||
const enteredEndMins = parseInt(endMinsRef.current.value);
|
||||
|
||||
props.onChange({
|
||||
startTime: enteredStartHours * 60 + enteredStartMins,
|
||||
endTime: enteredEndHours * 60 + enteredEndMins,
|
||||
});
|
||||
|
||||
props.onExit(0);
|
||||
}}
|
||||
type="submit">
|
||||
{t("save")}
|
||||
</Button>
|
||||
<Button onClick={props.onExit} type="button" color="secondary" className="ltr:mr-2">
|
||||
|
|
|
@ -3,7 +3,7 @@ import React from "react";
|
|||
function UserCalendarIllustration() {
|
||||
return (
|
||||
<svg
|
||||
className="w-1/2 md:w-32 mx-auto block mb-4"
|
||||
className="mx-auto mb-4 block w-1/2 md:w-32"
|
||||
viewBox="0 0 132 132"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
|
|
|
@ -24,40 +24,40 @@ export default function LicenseBanner() {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-x-0 bottom-0 left-0 pb-2 md:left-56 sm:pb-5">
|
||||
<div className="px-2 mx-auto max-w-7xl sm:px-8">
|
||||
<div className="p-2 bg-green-600 rounded-sm shadow-lg sm:p-3">
|
||||
<div className="fixed inset-x-0 bottom-0 left-0 pb-2 sm:pb-5 md:left-56">
|
||||
<div className="mx-auto max-w-7xl px-2 sm:px-8">
|
||||
<div className="rounded-sm bg-green-600 p-2 shadow-lg sm:p-3">
|
||||
<div className="flex flex-wrap items-center justify-between">
|
||||
<div className="flex items-center flex-1 w-0">
|
||||
<span className="flex p-2 bg-green-800 rounded-sm">
|
||||
<BadgeCheckIcon className="w-6 h-6 text-white" aria-hidden="true" />
|
||||
<div className="flex w-0 flex-1 items-center">
|
||||
<span className="flex rounded-sm bg-green-800 p-2">
|
||||
<BadgeCheckIcon className="h-6 w-6 text-white" aria-hidden="true" />
|
||||
</span>
|
||||
<p className="ml-3 font-medium text-white truncate">
|
||||
<p className="ml-3 truncate font-medium text-white">
|
||||
<span className="inline">
|
||||
<Trans i18nKey="accept_our_license" values={{ agree: "agree" }}>
|
||||
Accept our license by changing the .env variable
|
||||
<span className="px-1 bg-gray-50 bg-opacity-20">NEXT_PUBLIC_LICENSE_CONSENT</span> to
|
||||
<span className="bg-gray-50 bg-opacity-20 px-1">NEXT_PUBLIC_LICENSE_CONSENT</span> to
|
||||
'agree'.
|
||||
</Trans>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex-shrink-0 order-3 w-full mt-2 sm:order-2 sm:mt-0 sm:w-auto">
|
||||
<div className="order-3 mt-2 w-full flex-shrink-0 sm:order-2 sm:mt-0 sm:w-auto">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<button className="flex items-center justify-center w-full px-4 py-2 text-sm font-medium text-green-600 bg-white border border-transparent rounded-sm shadow-sm hover:bg-green-50">
|
||||
<button className="flex w-full items-center justify-center rounded-sm border border-transparent bg-white px-4 py-2 text-sm font-medium text-green-600 shadow-sm hover:bg-green-50">
|
||||
{t("accept_license")}
|
||||
</button>
|
||||
</DialogTrigger>
|
||||
<DialogContent />
|
||||
</Dialog>
|
||||
</div>
|
||||
<div className="flex-shrink-0 order-2 sm:order-3 sm:ml-2">
|
||||
<div className="order-2 flex-shrink-0 sm:order-3 sm:ml-2">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<button className="flex p-2 -mr-1 rounded-sm hover:bg-green-500 focus:outline-none focus:ring-2 focus:ring-white">
|
||||
<button className="-mr-1 flex rounded-sm p-2 hover:bg-green-500 focus:outline-none focus:ring-2 focus:ring-white">
|
||||
<span className="sr-only">{t("dismiss")}</span>
|
||||
<XIcon className="w-6 h-6 text-white" aria-hidden="true" />
|
||||
<XIcon className="h-6 w-6 text-white" aria-hidden="true" />
|
||||
</button>
|
||||
</DialogTrigger>
|
||||
<DialogContent />
|
||||
|
@ -78,12 +78,12 @@ export default function LicenseBanner() {
|
|||
cancelBtnText={t("cancel")}>
|
||||
<Trans i18nKey="remove_banner_instructions" values={{ agree: "agree" }}>
|
||||
To remove this banner, please open your .env file and change the
|
||||
<span className="bg-green-400 text-green-500 bg-opacity-20 p-[2px]">
|
||||
<span className="bg-green-400 bg-opacity-20 p-[2px] text-green-500">
|
||||
NEXT_PUBLIC_LICENSE_CONSENT
|
||||
</span>{" "}
|
||||
</span>
|
||||
variable to 'agreeapos;.
|
||||
</Trans>
|
||||
<h2 className="mt-8 mb-2 text-black font-cal">{t("terms_summary")}:</h2>
|
||||
<h2 className="mt-8 mb-2 font-cal text-black">{t("terms_summary")}:</h2>
|
||||
<ul className="ml-5 list-disc">
|
||||
<li>{t("codebase_has_to_stay_opensource")}</li>
|
||||
<li>{t("cannot_repackage_codebase")}</li>
|
||||
|
|
|
@ -19,13 +19,13 @@ const TrialBanner = () => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="hidden p-4 m-4 text-sm font-medium text-center text-gray-600 bg-yellow-200 rounded-md sm:block"
|
||||
className="m-4 hidden rounded-md bg-yellow-200 p-4 text-center text-sm font-medium text-gray-600 sm:block"
|
||||
data-testid="trial-banner">
|
||||
<div className="mb-2 text-left">{t("trial_days_left", { days: trialDaysLeft })}</div>
|
||||
<Button
|
||||
href="/api/upgrade"
|
||||
color="minimal"
|
||||
className="justify-center w-full border-2 border-gray-600 hover:bg-yellow-100">
|
||||
className="w-full justify-center border-2 border-gray-600 hover:bg-yellow-100">
|
||||
{t("upgrade_now")}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
@ -94,7 +94,7 @@ export default function SAMLConfiguration({
|
|||
<>
|
||||
<hr className="mt-8" />
|
||||
<div className="mt-6">
|
||||
<h2 className="text-lg font-medium leading-6 text-gray-900 font-cal">
|
||||
<h2 className="font-cal text-lg font-medium leading-6 text-gray-900">
|
||||
{t("saml_configuration")}
|
||||
<Badge className="ml-2 text-xs" variant={samlConfig ? "success" : "gray"}>
|
||||
{samlConfig ? t("enabled") : t("disabled")}
|
||||
|
@ -110,7 +110,7 @@ export default function SAMLConfiguration({
|
|||
</div>
|
||||
|
||||
{samlConfig ? (
|
||||
<div className="flex mt-2">
|
||||
<div className="mt-2 flex">
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
|
|
|
@ -106,7 +106,7 @@ export default function PaymentComponent(props: Props) {
|
|||
return (
|
||||
<form id="payment-form" className="mt-4" onSubmit={handleSubmit}>
|
||||
<CardElement id="card-element" options={CARD_OPTIONS} onChange={handleChange} />
|
||||
<div className="flex justify-center mt-2">
|
||||
<div className="mt-2 flex justify-center">
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={["processing", "error"].includes(state.status)}
|
||||
|
|
|
@ -40,25 +40,25 @@ const PaymentPage: FC<PaymentPageProps> = (props) => {
|
|||
</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
<main className="max-w-3xl py-24 mx-auto">
|
||||
<main className="mx-auto max-w-3xl py-24">
|
||||
<div className="fixed inset-0 z-50 overflow-y-auto">
|
||||
<div className="flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="flex min-h-screen items-end justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div className="fixed inset-0 my-4 transition-opacity sm:my-0" aria-hidden="true">
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||
<span className="hidden sm:inline-block sm:h-screen sm:align-middle" aria-hidden="true">
|
||||
​
|
||||
</span>
|
||||
<div
|
||||
className="inline-block px-8 pt-5 pb-4 overflow-hidden text-left align-bottom transition-all transform bg-white border rounded-sm dark:bg-gray-800 border-neutral-200 dark:border-neutral-700 sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:py-6"
|
||||
className="inline-block transform overflow-hidden rounded-sm border border-neutral-200 bg-white px-8 pt-5 pb-4 text-left align-bottom transition-all dark:border-neutral-700 dark:bg-gray-800 sm:my-8 sm:w-full sm:max-w-lg sm:py-6 sm:align-middle"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline">
|
||||
<div>
|
||||
<div className="flex items-center justify-center w-12 h-12 mx-auto bg-green-100 rounded-full">
|
||||
<CreditCardIcon className="w-8 h-8 text-green-600" />
|
||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
|
||||
<CreditCardIcon className="h-8 w-8 text-green-600" />
|
||||
</div>
|
||||
<div className="mt-3 text-center sm:mt-5">
|
||||
<h3
|
||||
className="text-2xl font-semibold leading-6 dark:text-white text-neutral-900"
|
||||
className="text-2xl font-semibold leading-6 text-neutral-900 dark:text-white"
|
||||
id="modal-headline">
|
||||
{t("payment")}
|
||||
</h3>
|
||||
|
@ -67,7 +67,7 @@ const PaymentPage: FC<PaymentPageProps> = (props) => {
|
|||
{t("pay_later_instructions")}
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-3 py-4 mt-4 text-left text-gray-700 border-t border-b dark:text-gray-300 dark:border-gray-900">
|
||||
<div className="mt-4 grid grid-cols-3 border-t border-b py-4 text-left text-gray-700 dark:border-gray-900 dark:text-gray-300">
|
||||
<div className="font-medium">{t("what")}</div>
|
||||
<div className="col-span-2 mb-6">{eventName}</div>
|
||||
<div className="font-medium">{t("when")}</div>
|
||||
|
@ -117,7 +117,7 @@ const PaymentPage: FC<PaymentPageProps> = (props) => {
|
|||
)}
|
||||
</div>
|
||||
{!props.profile.hideBranding && (
|
||||
<div className="pt-4 mt-4 text-xs text-center text-gray-400 border-t dark:border-gray-900 dark:text-white">
|
||||
<div className="mt-4 border-t pt-4 text-center text-xs text-gray-400 dark:border-gray-900 dark:text-white">
|
||||
<a href="https://cal.com/signup">{t("create_booking_link_with_calcom")}</a>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -32,17 +32,17 @@ export default function TeamAvailabilityModal(props: Props) {
|
|||
}, [utils, selectedTimeZone, selectedDate]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-row max-h-[500px] min-h-[500px] rtl:space-x-reverse space-x-8">
|
||||
<div className="w-64 p-5 pr-0 space-y-5 min-w-64">
|
||||
<div className="flex max-h-[500px] min-h-[500px] flex-row space-x-8 rtl:space-x-reverse">
|
||||
<div className="w-64 min-w-64 space-y-5 p-5 pr-0">
|
||||
<div className="flex">
|
||||
<Avatar
|
||||
imageSrc={getPlaceholderAvatar(props.member?.avatar, props.member?.name as string)}
|
||||
alt={props.member?.name || ""}
|
||||
className="rounded-full w-14 h-14"
|
||||
className="h-14 w-14 rounded-full"
|
||||
/>
|
||||
<div className="inline-block pt-1 ml-3">
|
||||
<div className="ml-3 inline-block pt-1">
|
||||
<span className="text-lg font-bold text-neutral-700">{props.member?.name}</span>
|
||||
<span className="block -mt-1 text-sm text-gray-400">{props.member?.email}</span>
|
||||
<span className="-mt-1 block text-sm text-gray-400">{props.member?.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
|
@ -61,7 +61,7 @@ export default function TeamAvailabilityModal(props: Props) {
|
|||
value={selectedTimeZone}
|
||||
onChange={(timezone) => setSelectedTimeZone(timezone.value)}
|
||||
classNamePrefix="react-select"
|
||||
className="block w-full mt-1 border border-gray-300 rounded-sm shadow-sm react-select-container focus:ring-neutral-800 focus:border-neutral-800 sm:text-sm"
|
||||
className="react-select-container mt-1 block w-full rounded-sm border border-gray-300 shadow-sm focus:border-neutral-800 focus:ring-neutral-800 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -74,7 +74,7 @@ export default function TeamAvailabilityModal(props: Props) {
|
|||
]}
|
||||
isSearchable={false}
|
||||
classNamePrefix="react-select"
|
||||
className="flex-1 block w-full min-w-0 border border-gray-300 rounded-sm react-select-container focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
|
||||
className="react-select-container block w-full min-w-0 flex-1 rounded-sm border border-gray-300 focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
|
||||
value={{ value: frequency, label: `${frequency} minutes` }}
|
||||
onChange={(newFrequency) => setFrequency(newFrequency?.value ?? 30)}
|
||||
/>
|
||||
|
|
|
@ -35,7 +35,7 @@ export default function TeamAvailabilityScreen(props: Props) {
|
|||
if (!member) return <></>;
|
||||
|
||||
return (
|
||||
<div key={member.id} style={style} className="flex pl-4 border-r border-gray-200 ">
|
||||
<div key={member.id} style={style} className="flex border-r border-gray-200 pl-4 ">
|
||||
<TeamAvailabilityTimes
|
||||
teamId={props.team?.id as number}
|
||||
memberId={member.id}
|
||||
|
@ -43,15 +43,15 @@ export default function TeamAvailabilityScreen(props: Props) {
|
|||
selectedDate={selectedDate}
|
||||
selectedTimeZone={selectedTimeZone}
|
||||
HeaderComponent={
|
||||
<div className="flex items-center mb-6">
|
||||
<div className="mb-6 flex items-center">
|
||||
<Avatar
|
||||
imageSrc={getPlaceholderAvatar(member?.avatar, member?.name as string)}
|
||||
alt={member?.name || ""}
|
||||
className="w-10 h-10 mt-1 rounded-full min-w-10 min-h-10"
|
||||
className="mt-1 h-10 min-h-10 w-10 min-w-10 rounded-full"
|
||||
/>
|
||||
<div className="inline-block pt-1 ml-3 overflow-hidden">
|
||||
<span className="text-lg font-bold truncate text-neutral-700">{member?.name}</span>
|
||||
<span className="block -mt-1 text-sm text-gray-400 truncate">{member?.email}</span>
|
||||
<div className="ml-3 inline-block overflow-hidden pt-1">
|
||||
<span className="truncate text-lg font-bold text-neutral-700">{member?.name}</span>
|
||||
<span className="-mt-1 block truncate text-sm text-gray-400">{member?.email}</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
@ -61,8 +61,8 @@ export default function TeamAvailabilityScreen(props: Props) {
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col flex-1 bg-white border rounded-sm border-neutral-200">
|
||||
<div className="flex w-full p-4 rtl:space-x-reverse space-x-5 border-b border-gray-200">
|
||||
<div className="flex flex-1 flex-col rounded-sm border border-neutral-200 bg-white">
|
||||
<div className="flex w-full space-x-5 border-b border-gray-200 p-4 rtl:space-x-reverse">
|
||||
<div className="flex flex-col">
|
||||
<span className="text-sm font-medium text-neutral-700">Date</span>
|
||||
<DatePicker
|
||||
|
@ -80,7 +80,7 @@ export default function TeamAvailabilityScreen(props: Props) {
|
|||
value={selectedTimeZone}
|
||||
onChange={(timezone) => setSelectedTimeZone(timezone.value)}
|
||||
classNamePrefix="react-select"
|
||||
className="w-full border border-gray-300 rounded-sm shadow-sm react-select-container focus:ring-neutral-800 focus:border-neutral-800 sm:text-sm"
|
||||
className="react-select-container w-full rounded-sm border border-gray-300 shadow-sm focus:border-neutral-800 focus:ring-neutral-800 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="hidden sm:block">
|
||||
|
@ -93,13 +93,13 @@ export default function TeamAvailabilityScreen(props: Props) {
|
|||
]}
|
||||
isSearchable={false}
|
||||
classNamePrefix="react-select"
|
||||
className="flex-1 block w-full min-w-0 border border-gray-300 rounded-sm react-select-container focus:ring-primary-500 focus:border-primary-500 sm:text-sm"
|
||||
className="react-select-container block w-full min-w-0 flex-1 rounded-sm border border-gray-300 focus:border-primary-500 focus:ring-primary-500 sm:text-sm"
|
||||
value={{ value: frequency, label: `${frequency} minutes` }}
|
||||
onChange={(newFrequency) => setFrequency(newFrequency?.value ?? 30)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-1 h-full">
|
||||
<div className="flex h-full flex-1">
|
||||
<AutoSizer>
|
||||
{({ height, width }) => (
|
||||
<List
|
||||
|
|
|
@ -48,7 +48,7 @@ export default function TeamAvailabilityTimes(props: Props) {
|
|||
: [];
|
||||
|
||||
return (
|
||||
<div className={classNames("flex-grow p-5 pl-0 min-w-60", props.className)}>
|
||||
<div className={classNames("min-w-60 flex-grow p-5 pl-0", props.className)}>
|
||||
{props.HeaderComponent}
|
||||
{isLoading && times.length === 0 && <Loader />}
|
||||
{!isLoading && times.length === 0 && (
|
||||
|
@ -59,7 +59,7 @@ export default function TeamAvailabilityTimes(props: Props) {
|
|||
{times.map((time) => (
|
||||
<div key={time.format()} className="flex flex-row items-center">
|
||||
<a
|
||||
className="flex-grow block py-2 mb-2 mr-3 font-medium text-center bg-white border rounded-sm min-w-48 dark:bg-gray-600 text-primary-500 dark:text-neutral-200 border-brand dark:border-transparent hover:bg-brand hover:text-brandcontrast dark:hover:border-black dark:hover:text-white dark:hover:bg-black"
|
||||
className="mb-2 mr-3 block min-w-48 flex-grow rounded-sm border border-brand bg-white py-2 text-center font-medium text-primary-500 hover:bg-brand hover:text-brandcontrast dark:border-transparent dark:bg-gray-600 dark:text-neutral-200 dark:hover:border-black dark:hover:bg-black dark:hover:text-white"
|
||||
data-testid="time">
|
||||
{time.format("HH:mm")}
|
||||
</a>
|
||||
|
|
|
@ -96,7 +96,7 @@ const CryptoSection = (props: CryptoSectionProps) => {
|
|||
const verifyButton = useMemo(() => {
|
||||
return (
|
||||
<Button color="secondary" onClick={verifyWallet} type="button" id="hasToken" name="hasToken">
|
||||
<img className="h-5 mr-1" src="/integrations/metamask.svg" />
|
||||
<img className="mr-1 h-5" src="/integrations/metamask.svg" />
|
||||
{t("verify_wallet")}
|
||||
</Button>
|
||||
);
|
||||
|
@ -105,7 +105,7 @@ const CryptoSection = (props: CryptoSectionProps) => {
|
|||
const connectButton = useMemo(() => {
|
||||
return (
|
||||
<Button color="secondary" onClick={connectMetamask} type="button">
|
||||
<img className="h-5 mr-1" src="/integrations/metamask.svg" />
|
||||
<img className="mr-1 h-5" src="/integrations/metamask.svg" />
|
||||
{t("connect_metamask")}
|
||||
</Button>
|
||||
);
|
||||
|
@ -120,7 +120,7 @@ const CryptoSection = (props: CryptoSectionProps) => {
|
|||
await connectMetamask();
|
||||
await verifyWallet();
|
||||
}}>
|
||||
<img className="h-5 mr-1" src="/integrations/metamask.svg" />
|
||||
<img className="mr-1 h-5" src="/integrations/metamask.svg" />
|
||||
{t("verify_wallet")}
|
||||
</Button>
|
||||
);
|
||||
|
@ -141,7 +141,7 @@ const CryptoSection = (props: CryptoSectionProps) => {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="absolute transition-opacity transform -translate-x-1/2 -translate-y-1/2 opacity-0 dark:bg-gray-900 top-1/2 left-1/2 group-hover:opacity-100"
|
||||
className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform opacity-0 transition-opacity group-hover:opacity-100 dark:bg-gray-900"
|
||||
id={`crypto-${props.id}`}>
|
||||
{determineButton()}
|
||||
</div>
|
||||
|
|
|
@ -20,7 +20,7 @@ const HelpMenuItem = () => {
|
|||
<ChatAltIcon
|
||||
className={classNames(
|
||||
"text-neutral-400 group-hover:text-neutral-500",
|
||||
"ltr:mr-2 flex-shrink-0 h-5 w-5"
|
||||
"h-5 w-5 flex-shrink-0 ltr:mr-2"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
export class HttpError<TCode extends number = number> extends Error {
|
||||
public readonly cause: unknown;
|
||||
public readonly cause?: Error;
|
||||
public readonly statusCode: TCode;
|
||||
public readonly message: string;
|
||||
public readonly url: string | undefined;
|
||||
public readonly method: string | undefined;
|
||||
|
||||
constructor(opts: { url?: string; method?: string; message?: string; statusCode: TCode; cause?: unknown }) {
|
||||
constructor(opts: { url?: string; method?: string; message?: string; statusCode: TCode; cause?: Error }) {
|
||||
super(opts.message ?? `HTTP Error ${opts.statusCode} `);
|
||||
|
||||
Object.setPrototypeOf(this, HttpError.prototype);
|
||||
|
|
|
@ -123,14 +123,14 @@ const AddCalDavIntegration = React.forwardRef<HTMLFormElement, Props>((props, re
|
|||
<label htmlFor="url" className="block text-sm font-medium text-gray-700">
|
||||
Calendar URL
|
||||
</label>
|
||||
<div className="flex mt-1 rounded-md shadow-sm">
|
||||
<div className="mt-1 flex rounded-md shadow-sm">
|
||||
<input
|
||||
required
|
||||
type="text"
|
||||
name="url"
|
||||
id="url"
|
||||
placeholder="https://example.com/calendar"
|
||||
className="flex-grow block w-full min-w-0 lowercase border-gray-300 rounded-none rounded-r-sm focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full min-w-0 flex-grow rounded-none rounded-r-sm border-gray-300 lowercase focus:border-brand focus:ring-black sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -144,7 +144,7 @@ const AddCalDavIntegration = React.forwardRef<HTMLFormElement, Props>((props, re
|
|||
name="username"
|
||||
id="username"
|
||||
placeholder="rickroll"
|
||||
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-sm shadow-sm focus:outline-none focus:ring-neutral-500 focus:border-neutral-500 sm:text-sm"
|
||||
className="mt-1 block w-full rounded-sm border border-gray-300 px-3 py-2 shadow-sm focus:border-neutral-500 focus:outline-none focus:ring-neutral-500 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-2">
|
||||
|
@ -157,7 +157,7 @@ const AddCalDavIntegration = React.forwardRef<HTMLFormElement, Props>((props, re
|
|||
name="password"
|
||||
id="password"
|
||||
placeholder="•••••••••••••"
|
||||
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-sm shadow-sm focus:outline-none focus:ring-neutral-500 focus:border-neutral-500 sm:text-sm"
|
||||
className="mt-1 block w-full rounded-sm border border-gray-300 px-3 py-2 shadow-sm focus:border-neutral-500 focus:outline-none focus:ring-neutral-500 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -152,6 +152,7 @@
|
|||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.4.4",
|
||||
"prettier": "^2.3.2",
|
||||
"prettier-plugin-tailwindcss": "^0.1.6",
|
||||
"prisma": "3.0.2",
|
||||
"tailwindcss": "^3.0.0",
|
||||
"ts-jest": "^26.0.0",
|
||||
|
|
112
pages/404.tsx
112
pages/404.tsx
|
@ -43,36 +43,36 @@ export default function Custom404() {
|
|||
noindex: true,
|
||||
}}
|
||||
/>
|
||||
<div className="min-h-screen px-4 bg-white">
|
||||
<main className="max-w-xl pt-16 pb-6 mx-auto sm:pt-24">
|
||||
<div className="min-h-screen bg-white px-4">
|
||||
<main className="mx-auto max-w-xl pt-16 pb-6 sm:pt-24">
|
||||
{isSignup && process.env.NEXT_PUBLIC_BASE_URL !== "https://app.cal.com" ? (
|
||||
<div>
|
||||
<div>
|
||||
<p className="text-sm font-semibold tracking-wide text-black uppercase">
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-black">
|
||||
{t("missing_license")}
|
||||
</p>
|
||||
<h1 className="mt-2 text-3xl font-extrabold text-gray-900 font-cal">
|
||||
<h1 className="mt-2 font-cal text-3xl font-extrabold text-gray-900">
|
||||
{t("signup_requires")}
|
||||
</h1>
|
||||
<p className="mt-4">{t("signup_requires_description")}</p>
|
||||
</div>
|
||||
<div className="mt-12">
|
||||
<h2 className="text-sm font-semibold tracking-wide text-gray-500 uppercase">
|
||||
<h2 className="text-sm font-semibold uppercase tracking-wide text-gray-500">
|
||||
{t("next_steps")}
|
||||
</h2>
|
||||
<ul role="list" className="mt-4">
|
||||
<li className="px-4 py-2 border-2 border-green-500">
|
||||
<li className="border-2 border-green-500 px-4 py-2">
|
||||
<a
|
||||
href="https://cal.com/pricing?infra"
|
||||
className="relative flex items-start py-6 space-x-4 rtl:space-x-reverse">
|
||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="flex items-center justify-center w-12 h-12 rounded-lg bg-green-50">
|
||||
<CheckIcon className="w-6 h-6 text-green-500" aria-hidden="true" />
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-green-50">
|
||||
<CheckIcon className="h-6 w-6 text-green-500" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-gray-500">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
||||
<span className="focus:outline-none">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
{t("acquire_commercial_license")}
|
||||
|
@ -81,33 +81,33 @@ export default function Custom404() {
|
|||
</h3>
|
||||
<p className="text-base text-gray-500">{t("the_infrastructure_plan")}</p>
|
||||
</div>
|
||||
<div className="self-center flex-shrink-0">
|
||||
<ChevronRightIcon className="w-5 h-5 text-gray-400" aria-hidden="true" />
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<ChevronRightIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul role="list" className="border-gray-200 divide-y divide-gray-200">
|
||||
<ul role="list" className="divide-y divide-gray-200 border-gray-200">
|
||||
<li className="px-4 py-2">
|
||||
<Link href="https://docs.cal.com/self-hosting/install#setting-up-your-first-user">
|
||||
<a className="relative flex items-start py-6 space-x-4 rtl:space-x-reverse">
|
||||
<a className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="flex items-center justify-center w-12 h-12 rounded-lg bg-gray-50">
|
||||
<DocumentTextIcon className="w-6 h-6 text-gray-700" aria-hidden="true" />
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
||||
<DocumentTextIcon className="h-6 w-6 text-gray-700" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-gray-500">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
{t("prisma_studio_tip")}
|
||||
</span>
|
||||
</h3>
|
||||
<p className="text-base text-gray-500">{t("prisma_studio_tip_description")}</p>
|
||||
</div>
|
||||
<div className="self-center flex-shrink-0">
|
||||
<ChevronRightIcon className="w-5 h-5 text-gray-400" aria-hidden="true" />
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<ChevronRightIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
|
@ -115,12 +115,12 @@ export default function Custom404() {
|
|||
<li className="px-4 py-2">
|
||||
<a
|
||||
href="https://cal.com/slack"
|
||||
className="relative flex items-start py-6 space-x-4 rtl:space-x-reverse">
|
||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="flex items-center justify-center w-12 h-12 rounded-lg bg-gray-50">
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
||||
<svg
|
||||
viewBox="0 0 2447.6 2452.5"
|
||||
className="w-6 h-6"
|
||||
className="h-6 w-6"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g clipRule="evenodd" fillRule="evenodd">
|
||||
<path
|
||||
|
@ -139,17 +139,17 @@ export default function Custom404() {
|
|||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-gray-500">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
Slack
|
||||
</span>
|
||||
</h3>
|
||||
<p className="text-base text-gray-500">{t("join_our_community")}</p>
|
||||
</div>
|
||||
<div className="self-center flex-shrink-0">
|
||||
<ChevronRightIcon className="w-5 h-5 text-gray-400" aria-hidden="true" />
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<ChevronRightIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
@ -167,18 +167,18 @@ export default function Custom404() {
|
|||
) : (
|
||||
<>
|
||||
<div className="text-center">
|
||||
<p className="text-sm font-semibold tracking-wide text-black uppercase">{t("error_404")}</p>
|
||||
<h1 className="mt-2 text-4xl font-extrabold text-gray-900 font-cal sm:text-5xl">
|
||||
<p className="text-sm font-semibold uppercase tracking-wide text-black">{t("error_404")}</p>
|
||||
<h1 className="mt-2 font-cal text-4xl font-extrabold text-gray-900 sm:text-5xl">
|
||||
{t("page_doesnt_exist")}
|
||||
</h1>
|
||||
{isSubpage ? (
|
||||
<span className="inline-block mt-2 text-lg ">
|
||||
<span className="mt-2 inline-block text-lg ">
|
||||
{t("check_spelling_mistakes_or_go_back")}
|
||||
</span>
|
||||
) : process.env.NEXT_PUBLIC_BASE_URL === "https://app.cal.com" ? (
|
||||
<a
|
||||
href={"https://cal.com/signup?username=" + username.replace("/", "")}
|
||||
className="inline-block mt-2 text-lg ">
|
||||
className="mt-2 inline-block text-lg ">
|
||||
{t("the_username")} <strong className="text-blue-500">cal.com{username}</strong>{" "}
|
||||
{t("is_still_available")} <span className="text-blue-500">{t("register_now")}</span>.
|
||||
</a>
|
||||
|
@ -194,23 +194,23 @@ export default function Custom404() {
|
|||
)}
|
||||
</div>
|
||||
<div className="mt-12">
|
||||
<h2 className="text-sm font-semibold tracking-wide text-gray-500 uppercase">
|
||||
<h2 className="text-sm font-semibold uppercase tracking-wide text-gray-500">
|
||||
{t("popular_pages")}
|
||||
</h2>
|
||||
{!isSubpage && process.env.NEXT_PUBLIC_BASE_URL === "https://app.cal.com" && (
|
||||
<ul role="list" className="mt-4">
|
||||
<li className="px-4 py-2 border-2 border-green-500">
|
||||
<li className="border-2 border-green-500 px-4 py-2">
|
||||
<a
|
||||
href={"https://cal.com/signup?username=" + username.replace("/", "")}
|
||||
className="relative flex items-start py-6 space-x-4 rtl:space-x-reverse">
|
||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="flex items-center justify-center w-12 h-12 rounded-lg bg-green-50">
|
||||
<CheckIcon className="w-6 h-6 text-green-500" aria-hidden="true" />
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-green-50">
|
||||
<CheckIcon className="h-6 w-6 text-green-500" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-gray-500">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
||||
<span className="focus:outline-none">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
{t("register")} <strong className="text-green-500">{username}</strong>
|
||||
|
@ -219,35 +219,35 @@ export default function Custom404() {
|
|||
</h3>
|
||||
<p className="text-base text-gray-500">{t("claim_username_and_schedule_events")}</p>
|
||||
</div>
|
||||
<div className="self-center flex-shrink-0">
|
||||
<ChevronRightIcon className="w-5 h-5 text-gray-400" aria-hidden="true" />
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<ChevronRightIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
|
||||
<ul role="list" className="mt-4 border-gray-200 divide-y divide-gray-200">
|
||||
<ul role="list" className="mt-4 divide-y divide-gray-200 border-gray-200">
|
||||
{links.map((link, linkIdx) => (
|
||||
<li key={linkIdx} className="px-4 py-2">
|
||||
<Link href={link.href}>
|
||||
<a className="relative flex items-start py-6 space-x-4 rtl:space-x-reverse">
|
||||
<a className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="flex items-center justify-center w-12 h-12 rounded-lg bg-gray-50">
|
||||
<link.icon className="w-6 h-6 text-gray-700" aria-hidden="true" />
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
||||
<link.icon className="h-6 w-6 text-gray-700" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-gray-500">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
{link.title}
|
||||
</span>
|
||||
</h3>
|
||||
<p className="text-base text-gray-500">{link.description}</p>
|
||||
</div>
|
||||
<div className="self-center flex-shrink-0">
|
||||
<ChevronRightIcon className="w-5 h-5 text-gray-400" aria-hidden="true" />
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<ChevronRightIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
|
@ -256,12 +256,12 @@ export default function Custom404() {
|
|||
<li className="px-4 py-2">
|
||||
<a
|
||||
href="https://cal.com/slack"
|
||||
className="relative flex items-start py-6 space-x-4 rtl:space-x-reverse">
|
||||
className="relative flex items-start space-x-4 py-6 rtl:space-x-reverse">
|
||||
<div className="flex-shrink-0">
|
||||
<span className="flex items-center justify-center w-12 h-12 rounded-lg bg-gray-50">
|
||||
<span className="flex h-12 w-12 items-center justify-center rounded-lg bg-gray-50">
|
||||
<svg
|
||||
viewBox="0 0 2447.6 2452.5"
|
||||
className="w-6 h-6"
|
||||
className="h-6 w-6"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<g clipRule="evenodd" fillRule="evenodd">
|
||||
<path
|
||||
|
@ -280,17 +280,17 @@ export default function Custom404() {
|
|||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-base font-medium text-gray-900">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-gray-500">
|
||||
<span className="rounded-sm focus-within:ring-2 focus-within:ring-gray-500 focus-within:ring-offset-2">
|
||||
<span className="absolute inset-0" aria-hidden="true" />
|
||||
Slack
|
||||
</span>
|
||||
</h3>
|
||||
<p className="text-base text-gray-500">{t("join_our_community")}</p>
|
||||
</div>
|
||||
<div className="self-center flex-shrink-0">
|
||||
<ChevronRightIcon className="w-5 h-5 text-gray-400" aria-hidden="true" />
|
||||
<div className="flex-shrink-0 self-center">
|
||||
<ChevronRightIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
|
|
@ -47,17 +47,17 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
/>
|
||||
{isReady && (
|
||||
<div className="h-screen dark:bg-black">
|
||||
<main className="max-w-3xl px-4 py-24 mx-auto">
|
||||
<main className="mx-auto max-w-3xl px-4 py-24">
|
||||
<div className="mb-8 text-center">
|
||||
<Avatar
|
||||
imageSrc={user.avatar}
|
||||
className="w-24 h-24 mx-auto mb-4 rounded-full"
|
||||
className="mx-auto mb-4 h-24 w-24 rounded-full"
|
||||
alt={nameOrUsername}
|
||||
/>
|
||||
<h1 className="mb-1 text-3xl font-bold font-cal text-neutral-900 dark:text-white">
|
||||
<h1 className="mb-1 font-cal text-3xl font-bold text-neutral-900 dark:text-white">
|
||||
{nameOrUsername}
|
||||
{user.verified && (
|
||||
<BadgeCheckIcon className="inline w-6 h-6 -mt-1 text-blue-500 dark:text-white" />
|
||||
<BadgeCheckIcon className="-mt-1 inline h-6 w-6 text-blue-500 dark:text-white" />
|
||||
)}
|
||||
</h1>
|
||||
<p className="text-neutral-500 dark:text-white">{user.bio}</p>
|
||||
|
@ -68,8 +68,8 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
<div
|
||||
key={type.id}
|
||||
style={{ display: "flex" }}
|
||||
className="relative bg-white border rounded-sm group dark:bg-neutral-900 dark:border-0 dark:hover:border-neutral-600 hover:bg-gray-50 border-neutral-200 hover:border-brand">
|
||||
<ArrowRightIcon className="absolute w-4 h-4 text-black transition-opacity opacity-0 right-3 top-3 dark:text-white group-hover:opacity-100" />
|
||||
className="group relative rounded-sm border border-neutral-200 bg-white hover:border-brand hover:bg-gray-50 dark:border-0 dark:bg-neutral-900 dark:hover:border-neutral-600">
|
||||
<ArrowRightIcon className="absolute right-3 top-3 h-4 w-4 text-black opacity-0 transition-opacity group-hover:opacity-100 dark:text-white" />
|
||||
<Link
|
||||
href={{
|
||||
pathname: `/${user.username}/${type.slug}`,
|
||||
|
@ -88,7 +88,7 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
}}
|
||||
className="block w-full px-6 py-4"
|
||||
data-testid="event-type-link">
|
||||
<h2 className="font-semibold grow text-neutral-900 dark:text-white">{type.title}</h2>
|
||||
<h2 className="grow font-semibold text-neutral-900 dark:text-white">{type.title}</h2>
|
||||
<EventTypeDescription eventType={type} />
|
||||
</a>
|
||||
</Link>
|
||||
|
@ -108,10 +108,10 @@ export default function User(props: inferSSRProps<typeof getServerSideProps>) {
|
|||
{eventTypes.length === 0 && (
|
||||
<div className="overflow-hidden rounded-sm shadow">
|
||||
<div className="p-8 text-center text-gray-400 dark:text-white">
|
||||
<h2 className="text-3xl font-semibold text-gray-600 font-cal dark:text-white">
|
||||
<h2 className="font-cal text-3xl font-semibold text-gray-600 dark:text-white">
|
||||
{t("uh_oh")}
|
||||
</h2>
|
||||
<p className="max-w-md mx-auto">{t("no_event_types_have_been_setup")}</p>
|
||||
<p className="mx-auto max-w-md">{t("no_event_types_have_been_setup")}</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -18,11 +18,11 @@ export default function Error() {
|
|||
return (
|
||||
<AuthContainer title="" description="">
|
||||
<div>
|
||||
<div className="mx-auto flex items-center justify-center h-12 w-12 rounded-full bg-red-100">
|
||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-red-100">
|
||||
<XIcon className="h-6 w-6 text-red-600" />
|
||||
</div>
|
||||
<div className="mt-3 text-center sm:mt-5">
|
||||
<h3 className="text-lg leading-6 font-medium text-gray-900" id="modal-title">
|
||||
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
||||
{error}
|
||||
</h3>
|
||||
<div className="mt-2">
|
||||
|
@ -32,7 +32,7 @@ export default function Error() {
|
|||
</div>
|
||||
<div className="mt-5 sm:mt-6">
|
||||
<Link href="/auth/login">
|
||||
<Button className="w-full flex justify-center">{t("go_back_login")}</Button>
|
||||
<Button className="flex w-full justify-center">{t("go_back_login")}</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</AuthContainer>
|
||||
|
|
|
@ -58,7 +58,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
<>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="mt-6 text-3xl font-extrabold text-center text-gray-900 font-cal">
|
||||
<h2 className="mt-6 text-center font-cal text-3xl font-extrabold text-gray-900">
|
||||
{t("success")}
|
||||
</h2>
|
||||
</div>
|
||||
|
@ -66,7 +66,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
<Link href="/auth/login">
|
||||
<button
|
||||
type="button"
|
||||
className="flex justify-center w-full px-4 py-2 text-sm font-medium text-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black">
|
||||
className="flex w-full justify-center px-4 py-2 text-sm font-medium text-blue-600 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2">
|
||||
{t("login")}
|
||||
</button>
|
||||
</Link>
|
||||
|
@ -80,14 +80,14 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
<>
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="mt-6 text-3xl font-extrabold text-center text-gray-900 font-cal">{t("whoops")}</h2>
|
||||
<h2 className="text-3xl font-extrabold text-center text-gray-900">{t("request_is_expired")}</h2>
|
||||
<h2 className="mt-6 text-center font-cal text-3xl font-extrabold text-gray-900">{t("whoops")}</h2>
|
||||
<h2 className="text-center text-3xl font-extrabold text-gray-900">{t("request_is_expired")}</h2>
|
||||
</div>
|
||||
<p>{t("request_is_expired_instructions")}</p>
|
||||
<Link href="/auth/forgot-password">
|
||||
<button
|
||||
type="button"
|
||||
className="flex justify-center w-full px-4 py-2 text-sm font-medium text-blue-600 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black">
|
||||
className="flex w-full justify-center px-4 py-2 text-sm font-medium text-blue-600 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2">
|
||||
{t("try_again")}
|
||||
</button>
|
||||
</Link>
|
||||
|
@ -102,15 +102,15 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
}, [resetPasswordRequest]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col justify-center min-h-screen py-12 bg-gray-50 sm:px-6 lg:px-8">
|
||||
<div className="flex min-h-screen flex-col justify-center bg-gray-50 py-12 sm:px-6 lg:px-8">
|
||||
<HeadSeo title={t("reset_password")} description={t("change_your_password")} />
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="px-4 py-8 mx-2 space-y-6 bg-white rounded-lg shadow sm:px-10">
|
||||
<div className="mx-2 space-y-6 rounded-lg bg-white px-4 py-8 shadow sm:px-10">
|
||||
{isRequestExpired && <Expired />}
|
||||
{!isRequestExpired && !success && (
|
||||
<>
|
||||
<div className="space-y-6">
|
||||
<h2 className="mt-6 text-3xl font-extrabold text-center text-gray-900 font-cal">
|
||||
<h2 className="mt-6 text-center font-cal text-3xl font-extrabold text-gray-900">
|
||||
{t("reset_password")}
|
||||
</h2>
|
||||
<p>{t("enter_new_password")}</p>
|
||||
|
@ -151,7 +151,7 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
type="password"
|
||||
autoComplete="password"
|
||||
required
|
||||
className="block w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm appearance-none focus:outline-none focus:ring-black focus:border-brand sm:text-sm"
|
||||
className="block w-full appearance-none rounded-md border border-gray-300 px-3 py-2 placeholder-gray-400 shadow-sm focus:border-brand focus:outline-none focus:ring-black sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -160,12 +160,12 @@ export default function Page({ resetPasswordRequest, csrfToken }: Props) {
|
|||
<button
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
className={`w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-black ${
|
||||
className={`flex w-full justify-center rounded-md border border-transparent bg-blue-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-black focus:ring-offset-2 ${
|
||||
loading ? "cursor-not-allowed" : ""
|
||||
}`}>
|
||||
{loading && (
|
||||
<svg
|
||||
className="w-5 h-5 mr-3 -ml-1 text-white animate-spin"
|
||||
className="mr-3 -ml-1 h-5 w-5 animate-spin text-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24">
|
||||
|
|
|
@ -111,7 +111,7 @@ export default function ForgotPassword({ csrfToken }: { csrfToken: string }) {
|
|||
/>
|
||||
<div className="space-y-2">
|
||||
<Button
|
||||
className="justify-center w-full"
|
||||
className="w-full justify-center"
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
aria-label={t("request_password_reset")}
|
||||
|
|
|
@ -139,7 +139,7 @@ export default function Login({
|
|||
{errorMessage && <Alert severity="error" title={errorMessage} />}
|
||||
<div className="flex space-y-2">
|
||||
<Button
|
||||
className="flex justify-center w-full"
|
||||
className="flex w-full justify-center"
|
||||
type="submit"
|
||||
disabled={form.formState.isSubmitting}>
|
||||
{twoFactorRequired ? t("submit") : t("sign_in")}
|
||||
|
@ -153,7 +153,7 @@ export default function Login({
|
|||
<div className="mt-5">
|
||||
<Button
|
||||
color="secondary"
|
||||
className="flex justify-center w-full"
|
||||
className="flex w-full justify-center"
|
||||
data-testid={"google"}
|
||||
onClick={async (e) => {
|
||||
e.preventDefault();
|
||||
|
|
|
@ -26,8 +26,8 @@ export default function Logout(props: Props) {
|
|||
return (
|
||||
<AuthContainer title={t("logged_out")} description={t("youve_been_logged_out")}>
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center justify-center w-12 h-12 mx-auto bg-green-100 rounded-full">
|
||||
<CheckIcon className="w-6 h-6 text-green-600" />
|
||||
<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
|
||||
<CheckIcon className="h-6 w-6 text-green-600" />
|
||||
</div>
|
||||
<div className="mt-3 text-center sm:mt-5">
|
||||
<h3 className="text-lg font-medium leading-6 text-gray-900" id="modal-title">
|
||||
|
@ -39,7 +39,7 @@ export default function Logout(props: Props) {
|
|||
</div>
|
||||
</div>
|
||||
<Link href="/auth/login">
|
||||
<Button className="flex justify-center w-full"> {t("go_back_login")}</Button>
|
||||
<Button className="flex w-full justify-center"> {t("go_back_login")}</Button>
|
||||
</Link>
|
||||
</AuthContainer>
|
||||
);
|
||||
|
|
|
@ -64,18 +64,18 @@ export default function Signup({ email }: Props) {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="flex flex-col justify-center min-h-screen py-12 bg-gray-50 sm:px-6 lg:px-8"
|
||||
className="flex min-h-screen flex-col justify-center bg-gray-50 py-12 sm:px-6 lg:px-8"
|
||||
aria-labelledby="modal-title"
|
||||
role="dialog"
|
||||
aria-modal="true">
|
||||
<HeadSeo title={t("sign_up")} description={t("sign_up")} />
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<h2 className="text-3xl font-extrabold text-center text-gray-900 font-cal">
|
||||
<h2 className="text-center font-cal text-3xl font-extrabold text-gray-900">
|
||||
{t("create_your_account")}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
|
||||
<div className="px-4 py-8 mx-2 bg-white shadow sm:rounded-lg sm:px-10">
|
||||
<div className="mx-2 bg-white px-4 py-8 shadow sm:rounded-lg sm:px-10">
|
||||
{/* TODO: Refactor as soon as /availability is live */}
|
||||
<FormProvider {...methods}>
|
||||
<form onSubmit={methods.handleSubmit(signUp)} className="space-y-6 bg-white">
|
||||
|
@ -83,25 +83,25 @@ export default function Signup({ email }: Props) {
|
|||
<div className="space-y-2">
|
||||
<TextField
|
||||
addOnLeading={
|
||||
<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">
|
||||
<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">
|
||||
{process.env.NEXT_PUBLIC_APP_URL}/
|
||||
</span>
|
||||
}
|
||||
labelProps={{ className: "block text-sm font-medium text-gray-700" }}
|
||||
className="flex-grow block w-full min-w-0 lowercase border-gray-300 rounded-none rounded-r-sm focus:ring-black focus:border-black sm:text-sm"
|
||||
className="block w-full min-w-0 flex-grow rounded-none rounded-r-sm border-gray-300 lowercase focus:border-black focus:ring-black sm:text-sm"
|
||||
{...register("username")}
|
||||
required
|
||||
/>
|
||||
<EmailField
|
||||
{...register("email")}
|
||||
className="block w-full px-3 py-2 mt-1 bg-gray-100 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-black focus:border-black sm:text-sm"
|
||||
className="mt-1 block w-full rounded-md border border-gray-300 bg-gray-100 px-3 py-2 shadow-sm focus:border-black focus:outline-none focus:ring-black sm:text-sm"
|
||||
/>
|
||||
<PasswordField
|
||||
labelProps={{
|
||||
className: "block text-sm font-medium text-gray-700",
|
||||
}}
|
||||
{...register("password")}
|
||||
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-black focus:border-black sm:text-sm"
|
||||
className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-black focus:outline-none focus:ring-black sm:text-sm"
|
||||
/>
|
||||
<PasswordField
|
||||
label={t("confirm_password")}
|
||||
|
@ -112,16 +112,16 @@ export default function Signup({ email }: Props) {
|
|||
validate: (value) =>
|
||||
value === methods.watch("password") || (t("error_password_mismatch") as string),
|
||||
})}
|
||||
className="block w-full px-3 py-2 mt-1 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-black focus:border-black sm:text-sm"
|
||||
className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-black focus:outline-none focus:ring-black sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex rtl:space-x-reverse space-x-2">
|
||||
<Button loading={isSubmitting} className="justify-center w-7/12">
|
||||
<div className="flex space-x-2 rtl:space-x-reverse">
|
||||
<Button loading={isSubmitting} className="w-7/12 justify-center">
|
||||
{t("create_account")}
|
||||
</Button>
|
||||
<Button
|
||||
color="secondary"
|
||||
className="justify-center w-5/12"
|
||||
className="w-5/12 justify-center"
|
||||
onClick={() =>
|
||||
signIn("Cal.com", { callbackUrl: (router.query.callbackUrl || "") as string })
|
||||
}>
|
||||
|
|
|
@ -90,7 +90,7 @@ export function AvailabilityForm(props: inferQueryOutput<"viewer.availability">)
|
|||
await createSchedule(values);
|
||||
}}
|
||||
className="col-span-3 space-y-2 lg:col-span-2">
|
||||
<div className="px-4 py-5 bg-white border border-gray-200 divide-y rounded-sm sm:p-6">
|
||||
<div className="divide-y rounded-sm border border-gray-200 bg-white px-4 py-5 sm:p-6">
|
||||
<h3 className="mb-5 text-base font-medium leading-6 text-gray-900">{t("change_start_end")}</h3>
|
||||
<Schedule name="schedule" />
|
||||
</div>
|
||||
|
@ -107,12 +107,12 @@ export function AvailabilityForm(props: inferQueryOutput<"viewer.availability">)
|
|||
<Button>{t("save")}</Button>
|
||||
</div>
|
||||
</Form>
|
||||
<div className="col-span-3 ltr:ml-2 rtl:mr-2 lg:col-span-1 min-w-40">
|
||||
<div className="px-4 py-5 border border-gray-200 rounded-sm sm:p-6 ">
|
||||
<div className="col-span-3 min-w-40 ltr:ml-2 rtl:mr-2 lg:col-span-1">
|
||||
<div className="rounded-sm border border-gray-200 px-4 py-5 sm:p-6 ">
|
||||
<h3 className="text-base font-medium leading-6 text-gray-900">
|
||||
{t("something_doesnt_look_right")}
|
||||
</h3>
|
||||
<div className="max-w-xl mt-2 text-sm text-gray-500">
|
||||
<div className="mt-2 max-w-xl text-sm text-gray-500">
|
||||
<p>{t("troubleshoot_availability")}</p>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
|
|
|
@ -16,14 +16,14 @@ type User = inferQueryOutput<"viewer.me">;
|
|||
const AvailabilityView = ({ user }: { user: User }) => {
|
||||
const { t } = useLocale();
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [availability, setAvailability] = useState([]);
|
||||
const [availability, setAvailability] = useState<{ end: string; start: string }[]>([]);
|
||||
const [selectedDate, setSelectedDate] = useState(dayjs());
|
||||
|
||||
function convertMinsToHrsMins(mins: number) {
|
||||
let h = Math.floor(mins / 60);
|
||||
let m = mins % 60;
|
||||
h = h < 10 ? "0" + h : h;
|
||||
m = m < 10 ? "0" + m : m;
|
||||
h = h < 10 ? 0 + h : h;
|
||||
m = m < 10 ? 0 + m : m;
|
||||
return `${h}:${m}`;
|
||||
}
|
||||
|
||||
|
@ -51,12 +51,12 @@ const AvailabilityView = ({ user }: { user: User }) => {
|
|||
}, [selectedDate]);
|
||||
|
||||
return (
|
||||
<div className="max-w-xl overflow-hidden bg-white rounded-sm shadow">
|
||||
<div className="max-w-xl overflow-hidden rounded-sm bg-white shadow">
|
||||
<div className="px-4 py-5 sm:p-6">
|
||||
{t("overview_of_day")}{" "}
|
||||
<input
|
||||
type="date"
|
||||
className="inline h-8 p-0 border-none"
|
||||
className="inline h-8 border-none p-0"
|
||||
defaultValue={selectedDate.format("YYYY-MM-DD")}
|
||||
onChange={(e) => {
|
||||
setSelectedDate(dayjs(e.target.value));
|
||||
|
@ -65,7 +65,7 @@ const AvailabilityView = ({ user }: { user: User }) => {
|
|||
<small className="block text-neutral-400">{t("hover_over_bold_times_tip")}</small>
|
||||
<div className="mt-4 space-y-4">
|
||||
<div className="overflow-hidden rounded-sm bg-brand">
|
||||
<div className="px-4 py-2 sm:px-6 text-brandcontrast">
|
||||
<div className="px-4 py-2 text-brandcontrast sm:px-6">
|
||||
{t("your_day_starts_at")} {convertMinsToHrsMins(user.startTime)}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -95,7 +95,7 @@ const AvailabilityView = ({ user }: { user: User }) => {
|
|||
)}
|
||||
|
||||
<div className="overflow-hidden rounded-sm bg-brand">
|
||||
<div className="px-4 py-2 sm:px-6 text-brandcontrast">
|
||||
<div className="px-4 py-2 text-brandcontrast sm:px-6">
|
||||
{t("your_day_ends_at")} {convertMinsToHrsMins(user.endTime)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -45,7 +45,7 @@ export default function Bookings() {
|
|||
return (
|
||||
<Shell heading={t("bookings")} subtitle={t("bookings_description")}>
|
||||
<BookingsShell>
|
||||
<div className="flex flex-col -mx-4 sm:mx-auto">
|
||||
<div className="-mx-4 flex flex-col sm:mx-auto">
|
||||
<div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
|
||||
<div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
|
||||
{query.status === "error" && (
|
||||
|
@ -54,9 +54,9 @@ export default function Bookings() {
|
|||
{(query.status === "loading" || query.status === "idle") && <Loader />}
|
||||
{query.status === "success" && !isEmpty && (
|
||||
<>
|
||||
<div className="mt-6 overflow-hidden border border-b border-gray-200 rounded-sm">
|
||||
<div className="mt-6 overflow-hidden rounded-sm border border-b border-gray-200">
|
||||
<table className="min-w-full divide-y divide-gray-200">
|
||||
<tbody className="bg-white divide-y divide-gray-200" data-testid="bookings">
|
||||
<tbody className="divide-y divide-gray-200 bg-white" data-testid="bookings">
|
||||
{query.data.pages.map((page, index) => (
|
||||
<Fragment key={index}>
|
||||
{page.bookings.map((booking) => (
|
||||
|
@ -67,7 +67,7 @@ export default function Bookings() {
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="text-center p-4" ref={buttonInView.ref}>
|
||||
<div className="p-4 text-center" ref={buttonInView.ref}>
|
||||
<Button
|
||||
loading={query.isFetchingNextPage}
|
||||
disabled={!query.hasNextPage}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue