import { useState, useCallback } from "preact/hooks"; import { useT } from "@shared/i18n/context"; import type { TranslationKey } from "@shared/i18n/translations"; import type { ProxiesState } from "@shared/hooks/use-proxies"; const PROTOCOLS = ["http", "https", "socks5", "socks5h"] as const; const statusStyles: Record = { active: [ "bg-green-100 text-green-700 border-green-200 dark:bg-[#11281d] dark:text-primary dark:border-[#1a442e]", "proxyActive", ], unreachable: [ "bg-red-100 text-red-600 border-red-200 dark:bg-red-900/20 dark:text-red-400 dark:border-red-800/30", "proxyUnreachable", ], disabled: [ "bg-slate-100 text-slate-500 border-slate-200 dark:bg-slate-800/30 dark:text-slate-400 dark:border-slate-700/30", "proxyDisabled", ], }; const inputCls = "px-3 py-2 text-sm border border-gray-200 dark:border-border-dark rounded-lg bg-white dark:bg-bg-dark text-slate-700 dark:text-text-main focus:outline-none focus:ring-1 focus:ring-primary"; interface ProxyPoolProps { proxies: ProxiesState; } export function ProxyPool({ proxies }: ProxyPoolProps) { const t = useT(); const [showAdd, setShowAdd] = useState(false); const [newName, setNewName] = useState(""); const [newProtocol, setNewProtocol] = useState("http"); const [newHost, setNewHost] = useState(""); const [newPort, setNewPort] = useState(""); const [newUsername, setNewUsername] = useState(""); const [newPassword, setNewPassword] = useState(""); const [addError, setAddError] = useState(""); const [checking, setChecking] = useState(null); const [checkingAll, setCheckingAll] = useState(false); const resetForm = useCallback(() => { setNewName(""); setNewProtocol("http"); setNewHost(""); setNewPort(""); setNewUsername(""); setNewPassword(""); setAddError(""); }, []); const handleAdd = useCallback(async () => { setAddError(""); if (!newHost.trim()) { setAddError(t("proxyHost") + " is required"); return; } const err = await proxies.addProxy({ name: newName, protocol: newProtocol, host: newHost, port: newPort, username: newUsername, password: newPassword, }); if (err) { setAddError(err); } else { resetForm(); setShowAdd(false); } }, [newName, newProtocol, newHost, newPort, newUsername, newPassword, proxies, resetForm, t]); const handleCheck = useCallback( async (id: string) => { setChecking(id); await proxies.checkProxy(id); setChecking(null); }, [proxies], ); const handleCheckAll = useCallback(async () => { setCheckingAll(true); await proxies.checkAll(); setCheckingAll(false); }, [proxies]); const handleDelete = useCallback( async (id: string) => { if (!confirm(t("removeProxyConfirm"))) return; await proxies.removeProxy(id); }, [proxies, t], ); return (
{/* Header */}

{t("proxyPool")}

{t("proxyPoolDesc")}

{proxies.proxies.length > 0 && ( )}
{/* Add form */} {showAdd && (
{/* Row 1: Protocol + Host + Port */} setNewHost((e.target as HTMLInputElement).value)} class={`${inputCls} font-mono`} /> setNewPort((e.target as HTMLInputElement).value)} class={`${inputCls} font-mono`} />
{/* Row 2: Name + Username + Password */} setNewName((e.target as HTMLInputElement).value)} class={inputCls} /> setNewUsername((e.target as HTMLInputElement).value)} class={inputCls} /> setNewPassword((e.target as HTMLInputElement).value)} class={`${inputCls} col-span-2 sm:col-span-1`} />
{addError && (

{addError}

)}
)} {/* Empty state */} {proxies.proxies.length === 0 && !showAdd && (
{t("noProxies")}
)} {/* Proxy list */} {proxies.proxies.length > 0 && (
{proxies.proxies.map((proxy) => { const [statusCls, statusKey] = statusStyles[proxy.status] || statusStyles.disabled; const isChecking = checking === proxy.id; return (
{/* Left: name + url + status */}
{proxy.name} {t(statusKey)}

{proxy.url}

{/* Center: health info */} {proxy.health && ( )} {/* Right: actions */}
{proxy.status === "disabled" ? ( ) : ( )}
{/* Mobile health info */} {proxy.health && (
{proxy.health.exitIp && ( IP: {proxy.health.exitIp} )} {proxy.health.latencyMs}ms
)}
); })}
)}
); }