diff --git a/src/app/page.tsx b/src/app/page.tsx index ccda8d0..03755ce 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -44,7 +44,12 @@ import { showSuccessToast, showToast, } from "@/lib/toast-utils"; -import type { BrowserProfile, CamoufoxConfig, WayfernConfig } from "@/types"; +import type { + BrowserProfile, + CamoufoxConfig, + SyncSettings, + WayfernConfig, +} from "@/types"; type BrowserTypeString = | "firefox" @@ -105,6 +110,23 @@ export default function Home() { (cloudUser?.subscriptionStatus === "active" || cloudUser?.planPeriod === "lifetime"); + const [selfHostedSyncConfigured, setSelfHostedSyncConfigured] = + useState(false); + + const checkSelfHostedSync = useCallback(async () => { + try { + const settings = await invoke("get_sync_settings"); + const hasConfig = Boolean( + settings.sync_server_url && settings.sync_token, + ); + setSelfHostedSyncConfigured(hasConfig && !cloudUser); + } catch { + setSelfHostedSyncConfigured(false); + } + }, [cloudUser]); + + const syncUnlocked = crossOsUnlocked || selfHostedSyncConfigured; + const [createProfileDialogOpen, setCreateProfileDialogOpen] = useState(false); const [settingsDialogOpen, setSettingsDialogOpen] = useState(false); const [integrationsDialogOpen, setIntegrationsDialogOpen] = useState(false); @@ -895,6 +917,11 @@ export default function Home() { } }, [isInitialized, checkAllPermissions]); + // Check self-hosted sync config on mount and when cloud user changes + useEffect(() => { + void checkSelfHostedSync(); + }, [checkSelfHostedSync]); + // Filter data by selected group and search query const filteredProfiles = useMemo(() => { let filtered = profiles; @@ -978,6 +1005,7 @@ export default function Home() { onOpenProfileSyncDialog={handleOpenProfileSyncDialog} onToggleProfileSync={handleToggleProfileSync} crossOsUnlocked={crossOsUnlocked} + syncUnlocked={syncUnlocked} /> @@ -1122,6 +1150,7 @@ export default function Home() { isOpen={syncConfigDialogOpen} onClose={(loginOccurred) => { setSyncConfigDialogOpen(false); + void checkSelfHostedSync(); if (loginOccurred) { setSyncAllDialogOpen(true); } diff --git a/src/components/profile-data-table.tsx b/src/components/profile-data-table.tsx index bfb0e1e..a1ca3d9 100644 --- a/src/components/profile-data-table.tsx +++ b/src/components/profile-data-table.tsx @@ -186,6 +186,7 @@ type TableMeta = { onOpenProfileSyncDialog?: (profile: BrowserProfile) => void; onToggleProfileSync?: (profile: BrowserProfile) => void; crossOsUnlocked?: boolean; + syncUnlocked?: boolean; // Country proxy creation (inline in proxy dropdown) countries: LocationItem[]; @@ -764,6 +765,7 @@ interface ProfilesDataTableProps { onOpenProfileSyncDialog?: (profile: BrowserProfile) => void; onToggleProfileSync?: (profile: BrowserProfile) => void; crossOsUnlocked?: boolean; + syncUnlocked?: boolean; } export function ProfilesDataTable({ @@ -787,6 +789,7 @@ export function ProfilesDataTable({ onOpenProfileSyncDialog, onToggleProfileSync, crossOsUnlocked = false, + syncUnlocked = false, }: ProfilesDataTableProps) { const { getTableSorting, updateSorting, isLoaded } = useTableSorting(); const [sorting, setSorting] = React.useState([]); @@ -1472,6 +1475,7 @@ export function ProfilesDataTable({ onOpenProfileSyncDialog, onToggleProfileSync, crossOsUnlocked, + syncUnlocked, // Country proxy creation countries, @@ -1523,6 +1527,7 @@ export function ProfilesDataTable({ onOpenProfileSyncDialog, onToggleProfileSync, crossOsUnlocked, + syncUnlocked, countries, canCreateLocationProxy, loadCountries, @@ -2332,15 +2337,15 @@ export function ProfilesDataTable({ { - if (meta.crossOsUnlocked) { + if (meta.syncUnlocked) { meta.onToggleProfileSync?.(profile); } }} - disabled={!meta.crossOsUnlocked || isCrossOs} + disabled={!meta.syncUnlocked || isCrossOs} > {profile.sync_enabled ? "Disable Sync" : "Enable Sync"} - {!meta.crossOsUnlocked && ( + {!meta.syncUnlocked && ( )}