Files
OmniRoute/src/shared/components/DistributeProxiesButton.tsx
PizzaV f42e8fa751 feat(mimocode): per-account proxy support for multi-account round-robin (#3837)
Integrated into release/v3.8.25 — feat(mimocode): per-account proxy for multi-account round-robin (runWithProxyContext per account, keyed by fingerprint). Orphan test relocated to a collected vitest path (14/14 green).
2026-06-14 21:30:02 -03:00

75 lines
2.3 KiB
TypeScript

"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>
);
}