You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
110 lines
3.1 KiB
110 lines
3.1 KiB
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { useI18n } from "@/translations/provider";
|
|
import { LoadingSkeleton } from "./loading-skeleton";
|
|
import { LoadingBorderSpinner } from "@/components/ui/loading-border-spinner";
|
|
|
|
type SwipeButtonProps = {
|
|
onSuccess: () => void | Promise<void>;
|
|
onCancel?: () => void;
|
|
text: string;
|
|
cancelText?: string;
|
|
disabled?: boolean;
|
|
isLoading?: boolean;
|
|
isSubmitting?: boolean;
|
|
theme?: "default" | "green" | "pink";
|
|
};
|
|
|
|
export function SwipeButton({
|
|
onSuccess,
|
|
onCancel,
|
|
text,
|
|
cancelText,
|
|
disabled = false,
|
|
isLoading = false,
|
|
isSubmitting = false,
|
|
theme = "default",
|
|
}: SwipeButtonProps) {
|
|
const { dictionary: t } = useI18n();
|
|
const [internalSubmitting, setInternalSubmitting] = useState(false);
|
|
|
|
if (isLoading) {
|
|
if (onCancel) {
|
|
return (
|
|
<div className="flex w-full items-center gap-3">
|
|
<LoadingSkeleton className="flex-1 h-[52px] rounded-[11px]" />
|
|
<LoadingSkeleton className="flex-1 h-[52px] rounded-[11px]" />
|
|
</div>
|
|
);
|
|
}
|
|
return (
|
|
<div className="w-full flex">
|
|
<LoadingSkeleton className="w-full h-[52px] rounded-[11px]" />
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const busy = isSubmitting || internalSubmitting;
|
|
|
|
const handleClick = async () => {
|
|
if (disabled || busy) return;
|
|
setInternalSubmitting(true);
|
|
try {
|
|
await onSuccess();
|
|
} finally {
|
|
setInternalSubmitting(false);
|
|
}
|
|
};
|
|
|
|
const cancelLabel = cancelText || t?.["Cancel"] || "Cancel";
|
|
const buttonBg =
|
|
theme === "green"
|
|
? "bg-[#00AC78]"
|
|
: theme === "pink"
|
|
? "bg-gradient-to-r from-[#FF6687] to-[#FF456C] shadow-[0_8px_16px_rgba(255,69,108,0.25)]"
|
|
: "bg-[#F0445B]";
|
|
|
|
const actionButton = (
|
|
<button
|
|
type="button"
|
|
disabled={disabled || busy}
|
|
onClick={handleClick}
|
|
className={`flex-1 min-w-0 h-[52px] rounded-[11px] px-3 ${buttonBg} text-white font-semibold group-16 flex items-center justify-center cursor-pointer transition-all active:scale-[0.98] hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed`}
|
|
>
|
|
{busy ? (
|
|
<LoadingBorderSpinner size="sm" variant="white" />
|
|
) : (
|
|
<span className="block w-full min-w-0 max-w-full truncate text-center">
|
|
{text}
|
|
</span>
|
|
)}
|
|
</button>
|
|
);
|
|
|
|
if (onCancel) {
|
|
return (
|
|
<div className="flex w-full items-center gap-3">
|
|
{/* Cancel Button */}
|
|
<button
|
|
type="button"
|
|
disabled={busy}
|
|
onClick={onCancel}
|
|
className="flex-1 min-w-0 h-[52px] rounded-[11px] px-3 border border-[#8B8B8B] bg-transparent text-[#8B8B8B] font-semibold group-16 flex items-center justify-center cursor-pointer transition-all active:scale-[0.98] hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
>
|
|
<span className="block w-full min-w-0 max-w-full truncate text-center">
|
|
{cancelLabel}
|
|
</span>
|
|
</button>
|
|
|
|
{/* Action Button */}
|
|
{actionButton}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
// Single Button full width
|
|
return <div className="w-full flex">{actionButton}</div>;
|
|
}
|
|
|
|
export default SwipeButton;
|