Skip to content

Commit

Permalink
Add new Sheet component
Browse files Browse the repository at this point in the history
  • Loading branch information
TWilson023 committed Nov 1, 2024
1 parent c3acad1 commit 798cb3c
Show file tree
Hide file tree
Showing 2 changed files with 119 additions and 149 deletions.
109 changes: 62 additions & 47 deletions apps/web/ui/webhooks/webhook-events.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
"use client";

import { WebhookEventProps } from "@/lib/types";
import {
Sheet,
SheetContent,
SheetTrigger,
useCopyToClipboard,
useMediaQuery,
} from "@dub/ui";
import { Button, Sheet, useCopyToClipboard, useMediaQuery } from "@dub/ui";
import { CircleCheck, CircleHalfDottedClock, Copy } from "@dub/ui/src/icons";
import { ButtonTooltip, Tooltip } from "@dub/ui/src/tooltip";
import { PropsWithChildren, useEffect, useState } from "react";
import { Highlighter } from "shiki";
import { toast } from "sonner";
import { X } from "../shared/icons";

export type EventListProps = PropsWithChildren<{
events: WebhookEventProps[];
Expand Down Expand Up @@ -58,48 +53,68 @@ const WebhookEvent = ({ event }: { event: WebhookEventProps }) => {
const isSuccess = event.http_status >= 200 && event.http_status < 300;
const { isMobile } = useMediaQuery();

const [isOpen, setIsOpen] = useState(false);

return (
<Sheet>
<SheetTrigger asChild>
<button className="flex items-center justify-between gap-5 px-3.5 py-3 hover:bg-gray-50 focus:outline-none">
<div className="flex items-center gap-5">
<div className="flex items-center gap-2.5">
<Tooltip
content={
isSuccess
? "This webhook was successfully delivered."
: "This webhook failed to deliver – it will be retried."
}
>
<div>
{isSuccess ? (
<CircleCheck className="size-4 text-green-500" />
) : (
<CircleHalfDottedClock className="size-4 text-amber-500" />
)}
</div>
</Tooltip>
<div className="text-sm text-gray-500">{event.http_status}</div>
</div>
<div className="text-sm text-gray-500">{event.event}</div>
<>
<button
type="button"
onClick={() => setIsOpen(true)}
className="flex items-center justify-between gap-5 px-3.5 py-3 hover:bg-gray-50 focus:outline-none"
>
<div className="flex items-center gap-5">
<div className="flex items-center gap-2.5">
<Tooltip
content={
isSuccess
? "This webhook was successfully delivered."
: "This webhook failed to deliver – it will be retried."
}
>
<div>
{isSuccess ? (
<CircleCheck className="size-4 text-green-500" />
) : (
<CircleHalfDottedClock className="size-4 text-amber-500" />
)}
</div>
</Tooltip>
<div className="text-sm text-gray-500">{event.http_status}</div>
</div>
<div className="text-sm text-gray-500">{event.event}</div>
</div>

<div className="text-xs text-gray-400">
{(() => {
const date = new Date(event.timestamp);
const localDate = new Date(
date.getTime() - date.getTimezoneOffset() * 60000,
);
return isMobile
? localDate.toLocaleTimeString()
: localDate.toLocaleString();
})()}
</div>
</button>
</SheetTrigger>
<SheetContent className="w-full overflow-y-scroll p-0 sm:w-auto sm:max-w-screen-sm">
<div className="text-xs text-gray-400">
{(() => {
const date = new Date(event.timestamp);
const localDate = new Date(
date.getTime() - date.getTimezoneOffset() * 60000,
);
return isMobile
? localDate.toLocaleTimeString()
: localDate.toLocaleString();
})()}
</div>
</button>
<Sheet
open={isOpen}
onOpenChange={setIsOpen}
contentProps={{ className: "md:w-[650px]" }}
handleOnly
>
<div className="p-6">
<h3 className="text-lg font-semibold">{event.event}</h3>
<div className="flex items-start justify-between">
<Sheet.Title className="text-lg font-semibold">
{event.event}
</Sheet.Title>
<Sheet.Close asChild>
<Button
variant="outline"
icon={<X className="size-5" />}
className="h-auto w-fit p-1"
/>
</Sheet.Close>
</div>
<div className="group flex items-center gap-2">
<p className="font-mono text-sm text-gray-500">{event.event_id}</p>
<ButtonTooltip
Expand Down Expand Up @@ -134,8 +149,8 @@ const WebhookEvent = ({ event }: { event: WebhookEventProps }) => {
dangerouslySetInnerHTML={{ __html: requestBody }}
/>
</div>
</SheetContent>
</Sheet>
</Sheet>
</>
);
};

Expand Down
159 changes: 57 additions & 102 deletions packages/ui/src/sheet.tsx
Original file line number Diff line number Diff line change
@@ -1,105 +1,60 @@
"use client";

import { cn } from "@dub/utils";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react";
import * as React from "react";

const Sheet = SheetPrimitive.Root;

const SheetTrigger = SheetPrimitive.Trigger;

const SheetClose = SheetPrimitive.Close;

const SheetPortal = SheetPrimitive.Portal;

interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content> {}

const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ className, children, ...props }, ref) => (
<SheetPortal>
<SheetPrimitive.Content
ref={ref}
className={cn(
"fixed inset-y-0 right-0 z-50 h-full w-3/4 gap-4 border-l border-gray-200 bg-white p-6 shadow-xl transition ease-in-out sm:max-w-sm",
"data-[state=closed]:animate-slide-out-to-right data-[state=open]:animate-slide-in-from-right data-[state=closed]:duration-300 data-[state=open]:duration-500",
className,
)}
{...props}
>
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-md p-1 transition-colors hover:bg-gray-100 focus:outline-none focus:ring-0 disabled:pointer-events-none data-[state=open]:bg-gray-100">
<X className="size-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
{children}
</SheetPrimitive.Content>
</SheetPortal>
));
SheetContent.displayName = SheetPrimitive.Content.displayName;

const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";

const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";

const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-foreground text-lg font-semibold", className)}
{...props}
/>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;

const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;

export {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetPortal,
SheetTitle,
SheetTrigger,
};
import { ComponentProps } from "react";
import { ContentProps, Drawer } from "vaul";

function SheetRoot({
children,
contentProps,
...rest
}: { contentProps?: ContentProps } & ComponentProps<typeof Drawer.Root>) {
return (
<Drawer.Root direction="right" {...rest}>
<Drawer.Portal>
<Drawer.Overlay className="fixed inset-0 bg-black/20" />
<Drawer.Content
{...contentProps}
className={cn(
"fixed bottom-2 right-2 top-2 z-10 flex w-[calc(100%-16px)] outline-none md:w-[540px]",
contentProps?.className,
)}
style={
// 8px between edge of screen and drawer
{
"--initial-transform": "calc(100% + 8px)",
...contentProps?.style,
} as React.CSSProperties
}
>
<div className="scrollbar-hide flex size-full grow flex-col overflow-y-auto rounded-lg bg-white">
{children}
</div>
</Drawer.Content>
</Drawer.Portal>
</Drawer.Root>
);
}

function Title({ className, ...rest }: ComponentProps<typeof Drawer.Title>) {
return (
<Drawer.Title
className={cn("text-xl font-medium text-zinc-900", className)}
{...rest}
/>
);
}

function Description(props: ComponentProps<typeof Drawer.Description>) {
return <Drawer.Description {...props} />;
}

function Close(props: ComponentProps<typeof Drawer.Close>) {
return <Drawer.Close {...props} />;
}

export const Sheet = Object.assign(SheetRoot, {
Title,
Description,
Close,
});

0 comments on commit 798cb3c

Please sign in to comment.