import React, { useState, useEffect, useRef } from "react"; import { Button } from "@/components/button.tsx"; import { Input } from "@/components/input.tsx"; import { Label } from "@/components/label.tsx"; import { Alert, AlertTitle, AlertDescription } from "@/components/alert.tsx"; import { Switch } from "@/components/switch.tsx"; import { useTranslation } from "react-i18next"; import { ChevronDown, X } from "lucide-react"; const SAVED_URLS_KEY = "termix_saved_server_urls"; const MAX_SAVED_URLS = 5; function getSavedUrls(): string[] { try { const raw = localStorage.getItem(SAVED_URLS_KEY); if (!raw) return []; return JSON.parse(raw); } catch { return []; } } function addSavedUrl(url: string) { const urls = getSavedUrls().filter((u) => u !== url); urls.unshift(url); localStorage.setItem( SAVED_URLS_KEY, JSON.stringify(urls.slice(0, MAX_SAVED_URLS)), ); } function removeSavedUrl(url: string) { const urls = getSavedUrls().filter((u) => u !== url); localStorage.setItem(SAVED_URLS_KEY, JSON.stringify(urls)); } interface RemoteSyncServerPickerProps { onServerConfigured: (serverUrl: string) => void; onCancel: () => void; } export function RemoteSyncServerPicker({ onServerConfigured, onCancel, }: RemoteSyncServerPickerProps) { const { t } = useTranslation(); const [serverUrl, setServerUrl] = useState(""); const [allowInvalidCertificate, setAllowInvalidCertificate] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [savedUrls, setSavedUrls] = useState([]); const [dropdownOpen, setDropdownOpen] = useState(false); const dropdownRef = useRef(null); useEffect(() => { setSavedUrls(getSavedUrls()); }, []); useEffect(() => { function handleClickOutside(e: MouseEvent) { if ( dropdownRef.current && !dropdownRef.current.contains(e.target as Node) ) { setDropdownOpen(false); } } if (dropdownOpen) { document.addEventListener("mousedown", handleClickOutside); } return () => document.removeEventListener("mousedown", handleClickOutside); }, [dropdownOpen]); const handleSaveConfig = async () => { if (!serverUrl.trim()) { setError(t("remoteSync.enterServerUrl")); return; } setLoading(true); setError(null); try { const normalizedUrl = serverUrl.trim(); if ( !normalizedUrl.startsWith("http://") && !normalizedUrl.startsWith("https://") ) { setError(t("remoteSync.mustIncludeProtocol")); setLoading(false); return; } const result = await window.electronAPI?.invoke?.( "save-remote-sync-config", { serverUrl: normalizedUrl, allowInvalidCertificate: normalizedUrl.startsWith("https://") && allowInvalidCertificate, connectedAt: new Date().toISOString(), }, ); if ((result as { success?: boolean })?.success) { addSavedUrl(normalizedUrl); setSavedUrls(getSavedUrls()); onServerConfigured(normalizedUrl); } else { setError(t("serverConfig.saveFailed")); } } catch { setError(t("serverConfig.saveError")); } finally { setLoading(false); } }; const handleUrlChange = (value: string) => { setServerUrl(value); setError(null); }; return (

{t("remoteSync.title")}

{t("remoteSync.description")}

handleUrlChange(e.target.value)} disabled={loading} className={savedUrls.length > 0 ? "pr-9" : ""} onFocus={() => { if (savedUrls.length > 0) setDropdownOpen(true); }} /> {savedUrls.length > 0 && ( )} {dropdownOpen && savedUrls.length > 0 && (

{t("remoteSync.savedServers")}

{savedUrls.map((url) => (
))}
)}
{serverUrl.trim().startsWith("https://") && (

{t("remoteSync.allowInvalidCertificateDesc")}

)} {error && ( {t("common.error")} {error} )}
); }