File size: 2,382 Bytes
cd8bd0a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
"use client";

import { useState, useCallback, useRef, useEffect } from "react";

type ButtonState = "idle" | "distributing" | "complete";

interface DistributeProxiesButtonProps {
  /** Async callback that performs the actual proxy distribution */
  onDistribute: () => Promise<void>;
  /** Whether the button should be disabled (e.g., during batch testing) */
  disabled?: boolean;
  /** Button label override */
  label?: string;
  /** Size variant */
  size?: "sm" | "md";
}

export default function DistributeProxiesButton({
  onDistribute,
  disabled = false,
  label = "Distribute Proxies",
  size = "md",
}: DistributeProxiesButtonProps) {
  const [state, setState] = useState<ButtonState>("idle");
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  useEffect(() => {
    return () => {
      if (timerRef.current) clearTimeout(timerRef.current);
    };
  }, []);

  const handleClick = useCallback(async () => {
    if (disabled || state === "distributing") return;
    setState("distributing");
    try {
      await onDistribute();
      setState("complete");
      timerRef.current = setTimeout(() => setState("idle"), 1500);
    } catch {
      setState("idle");
    }
  }, [onDistribute, disabled, state]);

  const isDisabled = disabled || state === "distributing";

  const sizeClasses =
    size === "sm" ? "px-2 py-1 text-[11px]" : "px-3 py-1.5 text-xs";

  const stateClasses =
    state === "distributing"
      ? "bg-primary/20 border-primary/40 text-primary animate-pulse"
      : state === "complete"
        ? "bg-green-500/15 border-green-500/40 text-green-500"
        : "bg-bg-subtle border-border text-text-muted hover:text-text-primary hover:border-primary/40";

  const icon = state === "distributing" ? "sync" : state === "complete" ? "check" : "swap_horiz";
  const displayLabel = state === "distributing" ? "Distributing..." : state === "complete" ? "Complete" : label;

  return (
    <button
      onClick={handleClick}
      disabled={isDisabled}
      className={`flex items-center gap-1.5 rounded-lg font-medium border transition-colors ${sizeClasses} ${stateClasses}`}
      title={displayLabel}
      aria-label={displayLabel}
    >
      <span className={`material-symbols-outlined text-[14px] ${state === "distributing" ? "animate-spin" : ""}`}>
        {icon}
      </span>
      {displayLabel}
    </button>
  );
}