/ components / UpdateBanner.tsx
UpdateBanner.tsx
1 import { useState, useEffect } from 'react'; 2 import { X } from 'lucide-react'; 3 import type { UpdateInfo } from '../lib/types'; 4 5 const supportsAutoUpdate = window.electronAPI.platform !== 'linux' && window.electronAPI.isPackaged; 6 7 export function UpdateBanner() { 8 const [update, setUpdate] = useState<UpdateInfo | null>(null); 9 const [readyVersion, setReadyVersion] = useState<string | null>(null); 10 11 useEffect(() => { 12 window.electronAPI.onUpdateAvailable((info) => setUpdate(info)); 13 window.electronAPI.onUpdateReady((version) => setReadyVersion(version)); 14 return () => { 15 window.electronAPI.offUpdateAvailable(); 16 window.electronAPI.offUpdateReady(); 17 }; 18 }, []); 19 20 // macOS/Windows: show banner when update has been downloaded and is ready to install 21 if (supportsAutoUpdate && readyVersion !== null) { 22 return ( 23 <div className="updateBanner flex items-center justify-between gap-3 px-6 py-1.5 text-xs"> 24 <span> 25 Gnosis <strong className="font-semibold">v{readyVersion}</strong> will install on next restart 26 </span> 27 <button onClick={() => setReadyVersion(null)} className="shrink-0 transition-opacity hover:opacity-80" aria-label="Dismiss"> 28 <X className="h-3 w-3" /> 29 </button> 30 </div> 31 ); 32 } 33 34 // Linux: show banner when a new version is available for manual download 35 if (!update || supportsAutoUpdate) return null; 36 37 const { version, releaseUrl } = update; 38 39 function handleDismiss() { 40 void window.electronAPI.dismissUpdate(version); 41 setUpdate(null); 42 } 43 44 return ( 45 <div className="updateBanner flex items-center justify-between gap-3 px-6 py-1.5 text-xs"> 46 <div className="flex items-center gap-3"> 47 <span> 48 Gnosis <strong className="font-semibold">v{version}</strong> is available 49 </span> 50 <button 51 onClick={() => void window.electronAPI.openExternal(releaseUrl)} 52 className="updateBanner-btn px-2 py-0.5 rounded-sm text-xs transition-colors" 53 > 54 Download 55 </button> 56 </div> 57 <button onClick={handleDismiss} className="shrink-0 transition-opacity hover:opacity-80" aria-label="Dismiss"> 58 <X className="h-3 w-3" /> 59 </button> 60 </div> 61 ); 62 }