Files
buzz/components/action-button.tsx
T
dmgnr f7bd43087d
Build and Push Image / build-backend (push) Successful in 1m4s
Build and Push Image / build-frontend (push) Successful in 2m52s
Build and Push Image / push (push) Successful in 1m16s
feat: add mobile upload
2026-08-29 15:32:47 +07:00

61 lines
1.3 KiB
TypeScript

"use client";
import type { MaybePromise } from "bun";
import { Check } from "lucide-react";
import type { ComponentProps, ReactNode } from "react";
import { useEffect, useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/spinner";
export function ActionButton({
action,
children,
onClick,
text,
...props
}: ComponentProps<typeof Button> & {
action: () => MaybePromise<void>;
text?: string;
}) {
const [state, setState] = useState<0 | 1 | 2>(0);
useEffect(() => {
if (state !== 2) return;
const tm = setTimeout(() => setState(0), 2000);
return () => clearTimeout(tm);
});
return (
<Button
disabled={state > 0}
{...props}
onClick={async (ev) => {
onClick?.(ev);
setState(1);
try {
await action();
setState(2);
} catch (e) {
toast.error("An error occured!");
console.error(e);
setState(0);
}
}}
>
{state === 0 ? children : state === 1 ? <Spinner /> : <Check />} {text}
</Button>
);
}
export function MaybeWrap({
wrap,
wrapper,
children,
}: {
wrap: boolean;
wrapper: (props: { children?: ReactNode }) => ReactNode;
children?: ReactNode;
}) {
return wrap ? wrapper({ children }) : children;
}