"use client"; import { invoke } from "@tauri-apps/api/core"; import { useCallback, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; import { Badge } from "@/components/ui/badge"; import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { isCrossOsProfile } from "@/lib/browser-utils"; import { showErrorToast } from "@/lib/toast-utils"; import type { BrowserProfile, SyncSessionInfo, WayfernFingerprintConfig, } from "@/types"; import { RippleButton } from "./ui/ripple"; function getScreenSize( profile: BrowserProfile, ): { w: number; h: number } | null { const fp = profile.wayfern_config?.fingerprint; if (!fp) return null; try { const parsed: WayfernFingerprintConfig = JSON.parse(fp); const w = parsed.screenWidth ?? parsed.windowInnerWidth; const h = parsed.screenHeight ?? parsed.windowInnerHeight; if (w && h) return { w, h }; } catch { // ignore } return null; } interface SyncFollowerDialogProps { isOpen: boolean; onClose: () => void; leaderProfile: BrowserProfile | null; allProfiles: BrowserProfile[]; runningProfiles: Set; } export function SyncFollowerDialog({ isOpen, onClose, leaderProfile, allProfiles, runningProfiles, }: SyncFollowerDialogProps) { const { t } = useTranslation(); const [selectedIds, setSelectedIds] = useState>(new Set()); const eligibleProfiles = allProfiles.filter( (p) => p.id !== leaderProfile?.id && p.browser === "wayfern" && !runningProfiles.has(p.id) && !isCrossOsProfile(p), ); const leaderScreenSize = useMemo( () => (leaderProfile ? getScreenSize(leaderProfile) : null), [leaderProfile], ); const handleToggle = useCallback((id: string, checked: boolean) => { setSelectedIds((prev) => { const next = new Set(prev); if (checked) { next.add(id); } else { next.delete(id); } return next; }); }, []); const handleStart = useCallback(() => { if (!leaderProfile || selectedIds.size === 0) return; const ids = Array.from(selectedIds); const leaderId = leaderProfile.id; setSelectedIds(new Set()); onClose(); invoke("start_sync_session", { leaderProfileId: leaderId, followerProfileIds: ids, }).catch((err) => { console.error("Failed to start sync session:", err); showErrorToast(err instanceof Error ? err.message : String(err)); }); }, [leaderProfile, selectedIds, onClose]); const handleOpenChange = useCallback( (open: boolean) => { if (!open) { setSelectedIds(new Set()); onClose(); } }, [onClose], ); return ( {t("profiles.synchronizer.selectFollowers")} {t("profiles.synchronizer.selectFollowersDesc")} {leaderProfile && (
{t("profiles.synchronizer.leader")} {leaderProfile.name}
{eligibleProfiles.length === 0 ? (

{t("profiles.synchronizer.wayfernOnly")}

) : ( eligibleProfiles.map((profile) => { const followerSize = getScreenSize(profile); const isFlaky = leaderScreenSize && followerSize && (leaderScreenSize.w !== followerSize.w || leaderScreenSize.h !== followerSize.h); return (
handleToggle( profile.id, !selectedIds.has(profile.id), ) } onKeyDown={() => {}} role="button" tabIndex={0} > handleToggle(profile.id, checked === true) } /> {profile.name} {isFlaky && ( {t("profiles.synchronizer.flakyBadge")} {t("profiles.synchronizer.flakyTooltip")} )}
); }) )}
)} handleOpenChange(false)} > {t("common.buttons.cancel")} {t("profiles.synchronizer.startSession")}
); }