"use client"; import Link from "next/link"; import { type ButtonHTMLAttributes, type ReactNode, useEffect, useId, useState, } from "react"; import { GoArrowRight } from "react-icons/go"; import { localizePath } from "@/translations/config"; import { useI18n } from "@/translations/provider"; import { LoadingThreeDot } from "./loading-three-dot"; type ButtonVariant = | "default" | "secondary" | "countdown" | "outlined" | "dark"; type ArrowDirection = "left" | "right"; export type ButtonProps = Omit< ButtonHTMLAttributes, "children" > & { children: ReactNode; description?: string; variant?: ButtonVariant; arrowDirection?: ArrowDirection; countdownSeconds?: number; href?: string; isLoading?: boolean; }; const FILLED_STROKE = "#FFFFFF"; const EMPTY_STROKE = "rgba(255, 255, 255, 0.5)"; const RADIUS = 18; const CIRCUMFERENCE = 2 * Math.PI * RADIUS; export function Button({ children, description, variant = "default", arrowDirection, countdownSeconds = 0, disabled, isLoading = false, href, className, type = "button", ...props }: ButtonProps) { const { locale } = useI18n(); const countdownId = useId(); const isCountdown = variant === "countdown"; const isOutlined = variant === "outlined"; const initialCountdown = Math.max(0, Math.ceil(countdownSeconds)); const [remainingSeconds, setRemainingSeconds] = useState(initialCountdown); const [animatedProgress, setAnimatedProgress] = useState( isCountdown && initialCountdown > 0 ? 0 : 1, ); useEffect(() => { setRemainingSeconds(initialCountdown); }, [initialCountdown]); useEffect(() => { if (!isCountdown || remainingSeconds <= 0) { return; } const timeoutId = window.setTimeout(() => { setRemainingSeconds((current) => Math.max(0, current - 1)); }, 1000); return () => window.clearTimeout(timeoutId); }, [isCountdown, remainingSeconds]); useEffect(() => { if (!isCountdown || initialCountdown <= 0) { setAnimatedProgress(1); return; } let animationFrameId = 0; const startedAt = window.performance.now(); const duration = initialCountdown * 1000; setAnimatedProgress(0); const updateProgress = (currentTime: number) => { const elapsed = currentTime - startedAt; const nextProgress = Math.min(1, elapsed / duration); setAnimatedProgress(nextProgress); if (nextProgress < 1) { animationFrameId = window.requestAnimationFrame(updateProgress); } }; animationFrameId = window.requestAnimationFrame(updateProgress); return () => window.cancelAnimationFrame(animationFrameId); }, [initialCountdown, isCountdown]); const countdownLocked = isCountdown && remainingSeconds > 0; const isDisabled = disabled || countdownLocked || isLoading; const progress = isCountdown ? animatedProgress : 1; const widthClass = variant === "secondary" ? "w-1/2" : "w-full"; const baseClassName = [ "inline-flex", widthClass, "items-center", "justify-center", "h-[52px]", variant === "dark" ? "rounded-[9px]" : "rounded-[11px]", "px-4", "text-center", "transition-opacity", variant === "outlined" ? "border border-[#8B8B8B] bg-transparent text-[#8B8B8B]" : variant === "dark" ? "border-none bg-[#2B2C31] text-white shadow-none hover:opacity-90" : "bg-linear-to-tl from-[#FE6F82] to-[#E03950] text-white", isDisabled ? "cursor-not-allowed opacity-50" : "cursor-pointer", className, ] .filter(Boolean) .join(" "); const renderArrow = (direction: ArrowDirection) => { if (arrowDirection !== direction) { return null; } return (