refactor: dialog auto swap platform primitives (#14186)

* refactor: dialog auto swap platform primities

* fixup! refactor: dialog auto swap platform primities

* fixup! fixup! refactor: dialog auto swap platform primities
This commit is contained in:
Morgan
2024-03-22 13:48:17 +02:00
committed by GitHub
parent d08c3fdc71
commit 896ba104fd
3 changed files with 68 additions and 100 deletions
@@ -13,15 +13,15 @@ import { useLocale } from "@calcom/lib/hooks/useLocale";
import type { TimeRange, WorkingHours } from "@calcom/types/schedule";
import {
Button,
ConfirmationDialogContent as WebConfirmationDialogContent,
Dialog as WebDialog,
DialogTrigger as WebDialogTrigger,
ConfirmationDialogContent,
EditableHeading,
Form,
SkeletonText,
Dialog,
DialogTrigger,
Label,
SelectSkeletonLoader,
Skeleton,
SkeletonText,
Switch,
TimezoneSelect as WebTimezoneSelect,
Tooltip,
@@ -29,11 +29,6 @@ import {
} from "@calcom/ui";
import { ArrowLeft, Info, MoreVertical, Plus, Trash } from "@calcom/ui/components/icon";
import { ConfirmationDialogContent as PlatformConfirmationDialogContent } from "../src/components/ui/confirmation-dialog-content";
import {
Dialog as PlatformDialog,
DialogTrigger as PlatformDialogTrigger,
} from "../src/components/ui/dialog";
import { Shell as PlatformShell } from "../src/components/ui/shell";
import { cn } from "../src/lib/utils";
import { Timezone as PlatformTimzoneSelect } from "../timezone/index";
@@ -96,22 +91,14 @@ const DeleteDialogButton = ({
buttonClassName,
isPending,
onDeleteConfirmed,
isPlatform,
handleDelete,
}: {
disabled?: boolean;
onDeleteConfirmed?: () => void;
buttonClassName: string;
isPlatform: boolean;
handleDelete: () => void;
isPending: boolean;
}) => {
const [Dialog, DialogTrigger, ConfirmationDialogContent] = useMemo(() => {
return isPlatform
? [PlatformDialog, PlatformDialogTrigger, PlatformConfirmationDialogContent]
: [WebDialog, WebDialogTrigger, WebConfirmationDialogContent];
}, [isPlatform]);
const { t } = useLocale();
return (
@@ -318,7 +305,6 @@ export function AvailabilitySettings({
disabled={schedule.isLastSchedule}
isPending={isDeleting}
handleDelete={handleDelete}
isPlatform={isPlatform}
/>
<VerticalDivider className="hidden sm:inline" />
<SmallScreenSideBar open={openSidebar}>
@@ -342,7 +328,6 @@ export function AvailabilitySettings({
disabled={schedule.isLastSchedule}
isPending={isDeleting}
handleDelete={handleDelete}
isPlatform={isPlatform}
onDeleteConfirmed={() => {
setOpenSidebar(false);
}}
@@ -1,69 +0,0 @@
import type { PropsWithChildren } from "react";
import type { ConfirmationDialogContentProps } from "@calcom/ui";
import { Button } from "@calcom/ui";
import { AlertCircle, Check } from "@calcom/ui/components/icon";
import { DialogContent, DialogClose, DialogTitle, DialogDescription, DialogHeader } from "./dialog";
export function ConfirmationDialogContent(props: PropsWithChildren<ConfirmationDialogContentProps>) {
const {
title,
variety,
confirmBtn = null,
confirmBtnText = "Confirm",
cancelBtnText = "Cancel",
loadingText = "Loading",
isPending = false,
onConfirm,
children,
} = props;
return (
<DialogContent>
<>
<div className="flex items-center">
{variety && (
<div className="mt-0.5 ltr:mr-3">
{variety === "danger" && (
<div className="bg-error mx-auto rounded-full p-2 text-center">
<AlertCircle className="h-5 w-5 text-red-600 dark:text-red-100" />
</div>
)}
{variety === "warning" && (
<div className="bg-attention mx-auto rounded-full p-2 text-center">
<AlertCircle className="h-5 w-5 text-orange-600" />
</div>
)}
{variety === "success" && (
<div className="bg-success mx-auto rounded-full p-2 text-center">
<Check className="h-5 w-5 text-green-600" />
</div>
)}
</div>
)}
<DialogHeader>
<DialogTitle className="font-cal text-emphasis mt-2 text-xl">{title}</DialogTitle>
<DialogDescription className="text-subtle text-sm">{children}</DialogDescription>
</DialogHeader>
</div>
<div className="my-5 flex flex-row-reverse gap-x-2 sm:my-8">
{confirmBtn ? (
confirmBtn
) : (
<DialogClose asChild>
<Button
color="primary"
onClick={(e) => onConfirm && onConfirm(e)}
data-testid="dialog-confirmation">
{isPending ? loadingText : confirmBtnText}
</Button>
</DialogClose>
)}
<DialogClose asChild>
<Button disabled={isPending}>{cancelBtnText}</Button>
</DialogClose>
</div>
</>
</DialogContent>
);
}
+64 -12
View File
@@ -1,8 +1,10 @@
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { usePathname, useRouter } from "next/navigation";
import type { ReactNode } from "react";
import { useMemo } from "react";
import type { ReactNode, ForwardRefExoticComponent, ReactElement } from "react";
import React, { useState } from "react";
import { useIsPlatform, Dialog as PlatformDialogPrimitives } from "@calcom/atoms/monorepo";
import classNames from "@calcom/lib/classNames";
import { useCompatSearchParams } from "@calcom/lib/hooks/useCompatSearchParams";
import { useLocale } from "@calcom/lib/hooks/useLocale";
@@ -26,6 +28,11 @@ const enum DIALOG_STATE {
}
export function Dialog(props: DialogProps) {
const isPlatform = useIsPlatform();
return !isPlatform ? <WebDialog {...props} /> : <PlatformDialogPrimitives.Dialog {...props} />;
}
function WebDialog(props: DialogProps) {
const router = useRouter();
const pathname = usePathname();
const searchParams = useCompatSearchParams();
@@ -70,6 +77,7 @@ export function Dialog(props: DialogProps) {
return <DialogPrimitive.Root {...dialogProps}>{children}</DialogPrimitive.Root>;
}
type DialogContentProps = React.ComponentProps<(typeof DialogPrimitive)["Content"]> & {
size?: "xl" | "lg" | "md";
type?: "creation" | "confirmation";
@@ -84,10 +92,22 @@ type DialogContentProps = React.ComponentProps<(typeof DialogPrimitive)["Content
// enableOverflow:- use this prop whenever content inside DialogContent could overflow and require scrollbar
export const DialogContent = React.forwardRef<HTMLDivElement, DialogContentProps>(
({ children, title, Icon, enableOverflow, type = "creation", ...props }, forwardedRef) => {
const isPlatform = useIsPlatform();
const [Portal, Overlay, Content] = useMemo(
() =>
isPlatform
? [
({ children }: { children: ReactElement | ReactElement[] }) => <>{children}</>,
PlatformDialogPrimitives.DialogOverlay,
PlatformDialogPrimitives.DialogContent,
]
: [DialogPrimitive.Portal, DialogPrimitive.Overlay, DialogPrimitive.Content],
[isPlatform]
);
return (
<DialogPrimitive.Portal>
<DialogPrimitive.Overlay className="fadeIn fixed inset-0 z-50 bg-neutral-800 bg-opacity-70 transition-opacity dark:bg-opacity-70 " />
<DialogPrimitive.Content
<Portal>
<Overlay className="fadeIn fixed inset-0 z-50 bg-neutral-800 bg-opacity-70 transition-opacity dark:bg-opacity-70 " />
<Content
{...props}
className={classNames(
"fadeIn bg-default scroll-bar fixed left-1/2 top-1/2 z-50 w-full max-w-[22rem] -translate-x-1/2 -translate-y-1/2 rounded-md text-left shadow-xl focus-visible:outline-none sm:align-middle",
@@ -125,8 +145,8 @@ export const DialogContent = React.forwardRef<HTMLDivElement, DialogContentProps
</div>
)}
{!type && children}
</DialogPrimitive.Content>
</DialogPrimitive.Portal>
</Content>
</Portal>
);
}
);
@@ -134,7 +154,7 @@ export const DialogContent = React.forwardRef<HTMLDivElement, DialogContentProps
type DialogHeaderProps = {
title: React.ReactNode;
subtitle?: React.ReactNode;
};
} & React.HTMLAttributes<HTMLDivElement>;
export function DialogHeader(props: DialogHeaderProps) {
if (!props.title) return null;
@@ -152,7 +172,12 @@ export function DialogHeader(props: DialogHeaderProps) {
);
}
export function DialogFooter(props: { children: ReactNode; className?: string; showDivider?: boolean }) {
type DialogFooterProps = {
children: React.ReactNode;
showDivider?: boolean;
} & React.HTMLAttributes<HTMLDivElement>;
export function DialogFooter(props: DialogFooterProps) {
return (
<div className={classNames("bg-default sticky bottom-0", props.className)}>
{props.showDivider && (
@@ -172,8 +197,27 @@ export function DialogFooter(props: { children: ReactNode; className?: string; s
DialogContent.displayName = "DialogContent";
export const DialogTrigger = DialogPrimitive.Trigger;
// export const DialogClose = DialogPrimitive.Close;
export const DialogTrigger: ForwardRefExoticComponent<
DialogPrimitive.DialogTriggerProps & React.RefAttributes<HTMLButtonElement>
> = React.forwardRef((props, ref) => {
const isPlatform = useIsPlatform();
return !isPlatform ? (
<DialogPrimitive.Trigger {...props} ref={ref} />
) : (
<PlatformDialogPrimitives.DialogTrigger {...props} ref={ref} />
);
});
DialogTrigger.displayName = "DialogTrigger";
type DialogCloseProps = {
"data-testid"?: string;
dialogCloseProps?: React.ComponentProps<(typeof DialogPrimitive)["Close"]>;
children?: ReactNode;
onClick?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
disabled?: boolean;
color?: ButtonProps["color"];
} & React.ComponentProps<typeof Button>;
export function DialogClose(
props: {
@@ -186,8 +230,14 @@ export function DialogClose(
} & React.ComponentProps<typeof Button>
) {
const { t } = useLocale();
const isPlatform = useIsPlatform();
const Close = useMemo(
() => (isPlatform ? PlatformDialogPrimitives.DialogClose : DialogPrimitive.Close),
[isPlatform]
);
return (
<DialogPrimitive.Close asChild {...props.dialogCloseProps}>
<Close asChild {...props.dialogCloseProps}>
{/* This will require the i18n string passed in */}
<Button
data-testid={props["data-testid"] || "dialog-rejection"}
@@ -195,6 +245,8 @@ export function DialogClose(
{...props}>
{props.children ? props.children : t("Close")}
</Button>
</DialogPrimitive.Close>
</Close>
);
}
DialogClose.displayName = "WebDialogClose";