import { useEffect, useState } from 'react' import { useUIStore } from '../../stores/uiStore' type UpdateInfo = { version: string downloading: boolean progress: number } let isTauri = false try { isTauri = '__TAURI_INTERNALS__' in window } catch { // not in Tauri } export function UpdateChecker() { const [update, setUpdate] = useState(null) const addToast = useUIStore((s) => s.addToast) useEffect(() => { if (!isTauri) return const checkForUpdate = async () => { try { const { check } = await import('@tauri-apps/plugin-updater') const available = await check() if (available) { setUpdate({ version: available.version, downloading: false, progress: 0 }) addToast({ type: 'info', message: `New version v${available.version} available`, duration: 0, // persist until dismissed }) } } catch { // Updater not configured or no network — silently ignore } } // Check after a short delay so UI loads first const timer = setTimeout(checkForUpdate, 5000) return () => clearTimeout(timer) }, [addToast]) if (!update || !isTauri) return null const handleUpdate = async () => { try { const { check } = await import('@tauri-apps/plugin-updater') const { relaunch } = await import('@tauri-apps/plugin-process') const available = await check() if (!available) return setUpdate((u) => u && { ...u, downloading: true }) await available.downloadAndInstall((event) => { if (event.event === 'Started' && event.data.contentLength) { setUpdate((u) => u && { ...u, progress: 0 }) } else if (event.event === 'Progress') { setUpdate((u) => { if (!u) return u return { ...u, progress: Math.min(u.progress + (event.data.chunkLength ?? 0), 100) } }) } else if (event.event === 'Finished') { setUpdate((u) => u && { ...u, progress: 100 }) } }) await relaunch() } catch (err) { addToast({ type: 'error', message: `Update failed: ${err instanceof Error ? err.message : String(err)}`, }) setUpdate((u) => u && { ...u, downloading: false }) } } return (

v{update.version} available

{update.downloading ? (

Downloading...

) : (
)}
) }