"use client"; import { invoke } from "@tauri-apps/api/core"; import { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; 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 { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { useCloudAuth } from "@/hooks/use-cloud-auth"; import { showErrorToast, showSuccessToast } from "@/lib/toast-utils"; import type { BrowserProfile, SyncMode, SyncSettings } from "@/types"; import { isSyncEnabled } from "@/types"; interface ProfileSyncDialogProps { isOpen: boolean; onClose: () => void; profile: BrowserProfile | null; onSyncConfigOpen: () => void; } export function ProfileSyncDialog({ isOpen, onClose, profile, onSyncConfigOpen, }: ProfileSyncDialogProps) { const { t } = useTranslation(); const { user: cloudUser } = useCloudAuth(); const isCloudSyncEligible = cloudUser != null && cloudUser.plan !== "free" && (cloudUser.subscriptionStatus === "active" || cloudUser.planPeriod === "lifetime"); const canUseEncryption = isCloudSyncEligible && cloudUser != null && (cloudUser.plan !== "team" || cloudUser.teamRole === "owner"); const [isSaving, setIsSaving] = useState(false); const [isSyncing, setIsSyncing] = useState(false); const [syncMode, setSyncMode] = useState( profile?.sync_mode ?? "Disabled", ); const [hasSelfHostedConfig, setHasSelfHostedConfig] = useState(false); const [hasE2ePassword, setHasE2ePassword] = useState(false); const [isCheckingConfig, setIsCheckingConfig] = useState(false); const [userChangedMode, setUserChangedMode] = useState(false); const hasConfig = isCloudSyncEligible || hasSelfHostedConfig; const checkSyncConfig = useCallback(async () => { setIsCheckingConfig(true); try { const settings = await invoke("get_sync_settings"); setHasSelfHostedConfig( Boolean(settings.sync_server_url && settings.sync_token), ); const hasPassword = await invoke("check_has_e2e_password"); setHasE2ePassword(hasPassword); } catch { setHasSelfHostedConfig(false); } finally { setIsCheckingConfig(false); } }, []); useEffect(() => { if (isOpen && profile) { setSyncMode(profile.sync_mode ?? "Disabled"); setUserChangedMode(false); void checkSyncConfig(); } }, [isOpen, profile, checkSyncConfig]); const handleOpenChange = useCallback( (open: boolean) => { if (!open) { onClose(); } }, [onClose], ); const handleModeChange = useCallback( async (newMode: string) => { if (!profile) return; if (!hasConfig) { showErrorToast(t("sync.mode.noPasswordWarning")); onSyncConfigOpen(); onClose(); return; } if (newMode === "Encrypted" && !canUseEncryption) { showErrorToast(t("settings.encryption.requiresProOrOwner")); return; } if (newMode === "Encrypted" && !hasE2ePassword) { showErrorToast(t("sync.mode.passwordRequired")); return; } setIsSaving(true); try { await invoke("set_profile_sync_mode", { profileId: profile.id, syncMode: newMode, }); setSyncMode(newMode as SyncMode); setUserChangedMode(true); showSuccessToast( newMode !== "Disabled" ? t("sync.mode.enabledToast") : t("sync.mode.disabledToast"), ); } catch (error) { console.error("Failed to set sync mode:", error); showErrorToast(String(error)); } finally { setIsSaving(false); } }, [ profile, hasConfig, hasE2ePassword, canUseEncryption, onSyncConfigOpen, onClose, t, ], ); const handleSyncNow = useCallback(async () => { if (!profile) return; if (!hasConfig) { showErrorToast(t("sync.mode.noPasswordWarning")); onSyncConfigOpen(); onClose(); return; } setIsSyncing(true); try { await invoke("request_profile_sync", { profileId: profile.id }); showSuccessToast(t("sync.mode.syncQueued")); } catch (error) { console.error("Failed to queue sync:", error); showErrorToast(String(error)); } finally { setIsSyncing(false); } }, [profile, hasConfig, onSyncConfigOpen, onClose, t]); const formatLastSync = (timestamp?: number) => { if (!timestamp) return t("common.labels.never", "Never"); const date = new Date(timestamp * 1000); return date.toLocaleString(); }; if (!profile) return null; return ( {t("sync.mode.title", "Profile Sync")} {t("sync.mode.description", { name: profile.name, defaultValue: `Manage sync settings for "${profile.name}"`, })} {isCheckingConfig ? (
) : (
{!hasConfig && (

{t("sync.mode.notConfigured", "Sync service not configured.")}

)} {hasConfig && ( <>
{syncMode === "Encrypted" && !hasE2ePassword && userChangedMode && (
{t( "sync.mode.noPasswordWarning", "E2E password not set. Please set a password in Settings.", )}
)}
{formatLastSync(profile.last_sync)} {isSyncEnabled(profile) && ( {profile.last_sync ? t("common.status.synced") : t("common.status.pending")} )}
)}
)} {hasConfig && isSyncEnabled(profile) && ( {t("sync.mode.syncNow", "Sync Now")} )}
); }