mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Adding new version of the ButtonWithConfirm component.
This commit is contained in:
@@ -35,6 +35,8 @@ const buttonVariants = cva(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
export type ButtonVariantsProps = VariantProps<typeof buttonVariants>;
|
||||||
|
|
||||||
function Button({
|
function Button({
|
||||||
className,
|
className,
|
||||||
variant,
|
variant,
|
||||||
|
|||||||
@@ -1,45 +1,161 @@
|
|||||||
"use client";
|
// "use client";
|
||||||
|
//
|
||||||
import { Button } from "@/components/ui/button";
|
// import { Button } from "@/components/ui/button";
|
||||||
|
// import { useState } from "react";
|
||||||
|
// import { Loader2 } from "lucide-react";
|
||||||
|
//
|
||||||
|
// export type VariantButton = {
|
||||||
|
// secondary: string;
|
||||||
|
// default: string;
|
||||||
|
// outline: string;
|
||||||
|
// ghost: string;
|
||||||
|
// link: string;
|
||||||
|
// destructive: string;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// export type ButtonWithConfirmProps = {
|
||||||
|
// icon?: any;
|
||||||
|
// text: string;
|
||||||
|
// variant?: keyof VariantButton;
|
||||||
|
// className?: string;
|
||||||
|
// onClick?: () => void;
|
||||||
|
// isPending?: boolean;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// export const ButtonWithConfirm = (props: ButtonWithConfirmProps) => {
|
||||||
|
// const [isConfirming, setIsConfirming] = useState(false);
|
||||||
|
//
|
||||||
|
// return (
|
||||||
|
// <Button
|
||||||
|
// onClick={() => {
|
||||||
|
// if (isConfirming && props.onClick) {
|
||||||
|
// props.onClick();
|
||||||
|
// } else {
|
||||||
|
// setIsConfirming(true);
|
||||||
|
// }
|
||||||
|
// }}
|
||||||
|
// variant={props.variant ? props.variant : "default"}
|
||||||
|
// className={props.className}
|
||||||
|
// >
|
||||||
|
// {props.isPending && <Loader2 className="animate-spin mr-4" size={16} />}
|
||||||
|
// {isConfirming ? "Are you sure ?" : `${props.text}`}
|
||||||
|
// <>{props.icon ? props.icon : null}</>
|
||||||
|
// </Button>
|
||||||
|
// );
|
||||||
|
// };
|
||||||
|
"use client"
|
||||||
|
import {Button, ButtonVariantsProps} from "@/components/ui/button";
|
||||||
import {useState} from "react";
|
import {useState} from "react";
|
||||||
import {Loader2} from "lucide-react";
|
import {Loader2} from "lucide-react";
|
||||||
|
import {Popover, PopoverContent, PopoverTrigger} from "@/components/ui/popover";
|
||||||
export type VariantButton = {
|
import {cn} from "@/lib/utils";
|
||||||
secondary: string;
|
import {Tooltip, TooltipContent, TooltipTrigger} from "@/components/ui/tooltip";
|
||||||
default: string;
|
|
||||||
outline: string;
|
|
||||||
ghost: string;
|
|
||||||
link: string;
|
|
||||||
destructive: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ButtonWithConfirmProps = {
|
export type ButtonWithConfirmProps = {
|
||||||
icon?: any;
|
title: string;
|
||||||
text: string;
|
description: string;
|
||||||
variant?: keyof VariantButton;
|
button: {
|
||||||
|
main: {
|
||||||
className?: string;
|
className?: string;
|
||||||
|
text?: string;
|
||||||
|
icon?: any;
|
||||||
|
variant?: ButtonVariantsProps["variant"];
|
||||||
|
size?: ButtonVariantsProps["size"];
|
||||||
|
disabled?: boolean;
|
||||||
|
tooltipText?: string;
|
||||||
|
};
|
||||||
|
confirm: {
|
||||||
|
className?: string;
|
||||||
|
text: string;
|
||||||
|
icon?: any;
|
||||||
|
variant?: ButtonVariantsProps["variant"];
|
||||||
|
size?: ButtonVariantsProps["size"];
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
|
};
|
||||||
|
cancel: {
|
||||||
|
className?: string;
|
||||||
|
text: string;
|
||||||
|
icon?: any;
|
||||||
|
variant?: ButtonVariantsProps["variant"];
|
||||||
|
size?: ButtonVariantsProps["size"];
|
||||||
|
onClick?: () => void;
|
||||||
|
};
|
||||||
|
};
|
||||||
isPending?: boolean;
|
isPending?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export const ButtonWithConfirm = (props: ButtonWithConfirmProps) => {
|
export const ButtonWithConfirm = (props: ButtonWithConfirmProps) => {
|
||||||
const [isConfirming, setIsConfirming] = useState(false);
|
const [isConfirming, setIsConfirming] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<Popover open={isConfirming} onOpenChange={!props.button.main.disabled ? setIsConfirming : undefined}>
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
"inline-flex",
|
||||||
|
props.button.main.disabled ? "cursor-not-allowed" : ""
|
||||||
|
)}
|
||||||
|
role="button">
|
||||||
|
<Button
|
||||||
|
disabled={!!props.button.main.disabled}
|
||||||
|
variant={props.button.main.variant ?? "default"}
|
||||||
|
size={props.button.main.size ?? "default"}
|
||||||
|
className={props.button.main.className}
|
||||||
|
onClick={() => {
|
||||||
|
if (!props.button.main.disabled) setIsConfirming(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.button.main.icon}
|
||||||
|
{props.button.main.text && <span>{props.button.main.text}</span>}
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
|
</PopoverTrigger>
|
||||||
|
</TooltipTrigger>
|
||||||
|
{props.button.main.tooltipText && props.button.main.disabled && (
|
||||||
|
<TooltipContent>
|
||||||
|
<p>{props.button.main.tooltipText}</p>
|
||||||
|
</TooltipContent>
|
||||||
|
)}
|
||||||
|
</Tooltip>
|
||||||
|
<PopoverContent className="w-80">
|
||||||
|
<div className="grid gap-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<h4 className="font-medium leading-none">{props.title}</h4>
|
||||||
|
<p className="text-sm text-muted-foreground">{props.description}</p>
|
||||||
|
</div>
|
||||||
|
<div className="grid gap-2">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (isConfirming && props.onClick) {
|
if (isConfirming && props.button.confirm.onClick) {
|
||||||
props.onClick();
|
props.button.confirm.onClick();
|
||||||
|
setIsConfirming(false);
|
||||||
} else {
|
} else {
|
||||||
setIsConfirming(true);
|
setIsConfirming(true);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
variant={props.variant ? props.variant : "default"}
|
variant={props.button.confirm.variant ? props.button.confirm.variant : "default"}
|
||||||
className={props.className}
|
size={props.button.main.size ?? "default"}
|
||||||
|
className={cn(props.button.main.className, "w-full")}
|
||||||
>
|
>
|
||||||
{props.isPending && <Loader2 className="animate-spin mr-4" size={16}/>}
|
{props.isPending && <Loader2 className="animate-spin mr-4" size={16}/>}
|
||||||
{isConfirming ? "Are you sure ?" : `${props.text}`}
|
{props.button.confirm.icon ? props.button.confirm.icon : null}
|
||||||
<>{props.icon ? props.icon : null}</>
|
<span>{props.button.confirm.text}</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={props.button.cancel.variant ? props.button.cancel.variant : "default"}
|
||||||
|
onClick={props.button.cancel.onClick ? () => props.button.cancel.onClick!() : () => setIsConfirming(false)}
|
||||||
|
className={cn(props.button.main.className, "w-full")}
|
||||||
|
size={props.button.main.size ?? "default"}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+22
-5
@@ -29,14 +29,31 @@ export const ButtonDeleteAgent = (props: ButtonDeleteAgentProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonWithConfirm
|
<ButtonWithConfirm
|
||||||
text={props.text ? props.text : ""}
|
title={props.text ? props.text : ""}
|
||||||
onClick={() => {
|
description="Are you sure you want to remove this agent? This action cannot be undone."
|
||||||
|
button={{
|
||||||
|
main: {
|
||||||
|
text: props.text ? props.text : "",
|
||||||
|
variant: "outline",
|
||||||
|
icon: <Trash2 color="red"/>,
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
className: "w-full",
|
||||||
|
text: "Delete",
|
||||||
|
icon: <Trash2/>,
|
||||||
|
variant: "destructive",
|
||||||
|
onClick: () => {
|
||||||
mutation.mutate();
|
mutation.mutate();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cancel: {
|
||||||
|
className: "w-full",
|
||||||
|
text: "Cancel",
|
||||||
|
icon: <Trash2/>,
|
||||||
|
variant: "outline",
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
variant={"destructive"}
|
|
||||||
isPending={mutation.isPending}
|
isPending={mutation.isPending}
|
||||||
className="gap-2"
|
|
||||||
icon={<Trash2 />}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+26
-3
@@ -6,6 +6,7 @@ import { setCurrentOrganizationSlug } from "@/features/dashboard/organization-co
|
|||||||
import {useRouter} from "next/navigation";
|
import {useRouter} from "next/navigation";
|
||||||
import {toast} from "sonner";
|
import {toast} from "sonner";
|
||||||
import {authClient} from "@/lib/auth/auth-client";
|
import {authClient} from "@/lib/auth/auth-client";
|
||||||
|
import {Trash2} from "lucide-react";
|
||||||
|
|
||||||
export type DeleteOrganizationButtonProps = {
|
export type DeleteOrganizationButtonProps = {
|
||||||
organizationSlug: string;
|
organizationSlug: string;
|
||||||
@@ -38,13 +39,35 @@ export const DeleteOrganizationButton = (props: DeleteOrganizationButtonProps) =
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<ButtonWithConfirm
|
<ButtonWithConfirm
|
||||||
onClick={() => {
|
title="Delete Organization"
|
||||||
|
description="Are you sure you want to remove this organization? This action cannot be undone."
|
||||||
|
button={{
|
||||||
|
main: {
|
||||||
|
text: "Delete Organization",
|
||||||
|
variant: "outline",
|
||||||
|
icon: <Trash2 color="red"/>,
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
className: "w-full",
|
||||||
|
text: "Delete",
|
||||||
|
icon: <Trash2/>,
|
||||||
|
variant: "destructive",
|
||||||
|
onClick: () => {
|
||||||
mutation.mutate();
|
mutation.mutate();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cancel: {
|
||||||
|
className: "w-full",
|
||||||
|
text: "Cancel",
|
||||||
|
icon: <Trash2/>,
|
||||||
|
variant: "outline",
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
isPending={mutation.isPending}
|
isPending={mutation.isPending}
|
||||||
text="Delete Organization"
|
|
||||||
variant="destructive"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+24
-5
@@ -29,14 +29,33 @@ export const ButtonDeleteAccount = (props: ButtonDeleteAccountProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ButtonWithConfirm
|
<ButtonWithConfirm
|
||||||
text={props.text ? props.text : ""}
|
title={props.text ? props.text : ""}
|
||||||
onClick={() => {
|
description="Are you sure you want to delete your account ? This action cannot be undone."
|
||||||
|
button={{
|
||||||
|
main: {
|
||||||
|
text: props.text ? props.text : "",
|
||||||
|
variant: "outline",
|
||||||
|
icon: <Trash2 color="red"/>,
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
className: "w-full",
|
||||||
|
text: "Delete",
|
||||||
|
icon: <Trash2/>,
|
||||||
|
variant: "destructive",
|
||||||
|
onClick: () => {
|
||||||
mutation.mutate();
|
mutation.mutate();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cancel: {
|
||||||
|
className: "w-full",
|
||||||
|
text: "Cancel",
|
||||||
|
icon: <Trash2/>,
|
||||||
|
variant: "outline",
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
variant={"destructive"}
|
|
||||||
isPending={mutation.isPending}
|
isPending={mutation.isPending}
|
||||||
className="gap-2"
|
|
||||||
icon={<Trash2 />}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+26
-6
@@ -3,7 +3,9 @@
|
|||||||
import {Trash2} from "lucide-react";
|
import {Trash2} from "lucide-react";
|
||||||
import {ButtonWithConfirm} from "@/components/wrappers/common/button/button-with-confirm";
|
import {ButtonWithConfirm} from "@/components/wrappers/common/button/button-with-confirm";
|
||||||
import {useMutation} from "@tanstack/react-query";
|
import {useMutation} from "@tanstack/react-query";
|
||||||
import { deleteProjectAction } from "@/components/wrappers/dashboard/projects/button-delete-project/delete-project.action";
|
import {
|
||||||
|
deleteProjectAction
|
||||||
|
} from "@/components/wrappers/dashboard/projects/button-delete-project/delete-project.action";
|
||||||
import {useRouter} from "next/navigation";
|
import {useRouter} from "next/navigation";
|
||||||
import {toast} from "sonner";
|
import {toast} from "sonner";
|
||||||
|
|
||||||
@@ -27,15 +29,33 @@ export const ButtonDeleteProject = (props: ButtonDeleteProjectProps) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<ButtonWithConfirm
|
<ButtonWithConfirm
|
||||||
text={props.text ? props.text : ""}
|
title={props.text ? props.text : ""}
|
||||||
onClick={() => {
|
description="Are you sure you want to delete this project ? This action cannot be undone."
|
||||||
|
button={{
|
||||||
|
main: {
|
||||||
|
text: props.text ? props.text : "",
|
||||||
|
variant: "outline",
|
||||||
|
icon: <Trash2 color="red"/>,
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
className: "w-full",
|
||||||
|
text: "Delete",
|
||||||
|
icon: <Trash2/>,
|
||||||
|
variant: "destructive",
|
||||||
|
onClick: () => {
|
||||||
mutation.mutate();
|
mutation.mutate();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cancel: {
|
||||||
|
className: "w-full",
|
||||||
|
text: "Cancel",
|
||||||
|
icon: <Trash2/>,
|
||||||
|
variant: "outline",
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
variant={"destructive"}
|
|
||||||
isPending={mutation.isPending}
|
isPending={mutation.isPending}
|
||||||
className="gap-2"
|
|
||||||
icon={<Trash2 />}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user