"use client"; import { invoke } from "@tauri-apps/api/core"; import { useCallback, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { FiWifi } from "react-icons/fi"; import { LuLayers, LuPuzzle, LuShield, LuUsers } from "react-icons/lu"; import { LoadingButton } from "@/components/loading-button"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { showErrorToast, showSuccessToast } from "@/lib/toast-utils"; interface UnsyncedEntityCounts { proxies: number; groups: number; vpns: number; extensions: number; extension_groups: number; } interface SyncAllDialogProps { isOpen: boolean; onClose: () => void; } export function SyncAllDialog({ isOpen, onClose }: SyncAllDialogProps) { const { t } = useTranslation(); const [counts, setCounts] = useState(null); const [isLoading, setIsLoading] = useState(false); const [isEnabling, setIsEnabling] = useState(false); const loadCounts = useCallback(async () => { setIsLoading(true); try { const result = await invoke( "get_unsynced_entity_counts", ); setCounts(result); } catch (error) { console.error("Failed to get unsynced entity counts:", error); setCounts(null); } finally { setIsLoading(false); } }, []); useEffect(() => { if (isOpen) { void loadCounts(); } }, [isOpen, loadCounts]); const handleEnableAll = useCallback(async () => { setIsEnabling(true); try { await invoke("enable_sync_for_all_entities"); showSuccessToast(t("syncAll.success")); onClose(); } catch (error) { console.error("Failed to enable sync for all entities:", error); showErrorToast(String(error)); } finally { setIsEnabling(false); } }, [onClose, t]); const items = useMemo(() => { if (!counts) return []; return [ { key: "proxies", count: counts.proxies, label: t("syncAll.labels.proxies"), Icon: FiWifi, }, { key: "vpns", count: counts.vpns, label: t("syncAll.labels.vpns"), Icon: LuShield, }, { key: "groups", count: counts.groups, label: t("syncAll.labels.groups"), Icon: LuUsers, }, { key: "extensions", count: counts.extensions, label: t("syncAll.labels.extensions"), Icon: LuPuzzle, }, { key: "extensionGroups", count: counts.extension_groups, label: t("syncAll.labels.extensionGroups"), Icon: LuLayers, }, ].filter((item) => item.count > 0); }, [counts, t]); const totalCount = items.reduce((sum, item) => sum + item.count, 0); // Don't render anything when there's nothing to sync — the parent // mounts this dialog eagerly after login, so silent-close is correct. if (!isLoading && totalCount === 0) { return null; } return ( 0)} onOpenChange={onClose} > {t("syncAll.title")} {t("syncAll.description")} {isLoading ? (
) : (
{items.map(({ key, count, label, Icon }) => (
{label}
{count}
))}
)} {t("syncAll.enableAll")}
); }