action-button

Next

A button that displays a popup when clicked

Docs
shadix-uicomponent

Preview

Loading preview…
registry/new-york/components/action-button.tsx
"use client";
import { useTransition } from "react";
import type React from "react";

import { Loader2Icon } from "lucide-react";
import { toast } from "sonner";

import {
    AlertDialog,
    AlertDialogAction,
    AlertDialogCancel,
    AlertDialogContent,
    AlertDialogDescription,
    AlertDialogFooter,
    AlertDialogHeader,
    AlertDialogTitle,
    AlertDialogTrigger,
} from "@/shadcn/components/ui/alert-dialog";
import { Button } from "@/shadcn/components/ui/button";

const ActionButton: React.FC<ActionButtonProps> = ({
    children,
    popupContent,
    title,
    onConfirm,
    ...props
}) => {
    const [isLoading, startLoading] = useTransition();

    const handleConfirm = () => {
        startLoading(async () => {
            const data = await onConfirm();
            if (data.error) toast.error(data.message ?? "Something went wrong");
            else toast.success(data.message ?? "Action successful");
        });
    };

    return (
        <AlertDialog open={isLoading ? true : undefined}>
            <AlertDialogTrigger asChild>
                <Button {...props}>{children}</Button>
            </AlertDialogTrigger>

            <AlertDialogContent>
                <AlertDialogHeader>
                    <AlertDialogTitle>{title}</AlertDialogTitle>

                    <AlertDialogDescription asChild>
                        {popupContent}
                    </AlertDialogDescription>
                </AlertDialogHeader>

                <AlertDialogFooter>
                    <AlertDialogCancel>Cancel</AlertDialogCancel>

                    <AlertDialogAction
                        disabled={isLoading}
                        onClick={handleConfirm}
                    >
                        {isLoading ? (
                            <Loader2Icon className="size-4 animate-spin" />
                        ) : (
                            "Confirm"
                        )}
                    </AlertDialogAction>
                </AlertDialogFooter>
            </AlertDialogContent>
        </AlertDialog>
    );
};

export interface ActionButtonProps extends React.ComponentProps<typeof Button> {
    /** @public Button content */
    children: React.ReactNode;
    /** @public Content to show in popup */
    popupContent: React.ReactNode;
    /** @public Additional CSS class names */
    className?: string;
    /** @public Variant of the button */
    variant?:
        | "default"
        | "destructive"
        | "outline"
        | "secondary"
        | "ghost"
        | "link";
    /** @public Size of the button */
    size?: "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg";
    /** @public Whether the button is disabled */
    disabled?: boolean;
    /** @public Function to execute on confirmation */
    onConfirm: () => Promise<{
        message?: string;
        error?: boolean;
    }>;
}

export default ActionButton;

Installation

npx shadcn@latest add @shadix-ui/action-button

Usage

import { ActionButton } from "@/components/action-button"
<ActionButton />