diff --git a/src/components/VersionUpdateBanner/index.tsx b/src/components/VersionUpdateBanner/index.tsx new file mode 100644 index 0000000..cd752ba --- /dev/null +++ b/src/components/VersionUpdateBanner/index.tsx @@ -0,0 +1,144 @@ +import { Button } from '@/components/ui/button' +import { RefreshCw, X } from 'lucide-react' +import { useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' + +export default function VersionUpdateBanner() { + const { t } = useTranslation() + const [updateAvailable, setUpdateAvailable] = useState(false) + const [isDismissed, setIsDismissed] = useState(false) + const [isUpdating, setIsUpdating] = useState(false) + + useEffect(() => { + if (typeof window === 'undefined' || !('serviceWorker' in navigator)) { + return + } + + let registration: ServiceWorkerRegistration | null = null + + const checkForUpdates = async () => { + try { + registration = await navigator.serviceWorker.ready + if (!registration) return + + // Check if there's a waiting service worker (new version ready) + if (registration.waiting) { + // There's already a new version waiting + setUpdateAvailable(true) + } + + // Listen for updates + const handleUpdateFound = () => { + const newWorker = registration?.installing + if (!newWorker) return + + const handleStateChange = () => { + if (newWorker.state === 'installed') { + // New version installed + if (navigator.serviceWorker.controller) { + // There's a new version ready (not the first install) + setUpdateAvailable(true) + } + } + } + + newWorker.addEventListener('statechange', handleStateChange) + } + + registration.addEventListener('updatefound', handleUpdateFound) + + // Check for updates periodically + const checkInterval = setInterval(() => { + if (registration) { + registration.update() + } + }, 60000) // Check every minute + + // Initial update check + registration.update() + + return () => { + clearInterval(checkInterval) + if (registration) { + registration.removeEventListener('updatefound', handleUpdateFound as EventListener) + } + } + } catch (error) { + console.error('Error checking for updates:', error) + } + } + + checkForUpdates() + }, []) + + const handleUpdate = () => { + setIsUpdating(true) + // Reload the page to activate the new service worker + window.location.reload() + } + + const handleDismiss = () => { + setIsDismissed(true) + // Store dismissal in localStorage to avoid showing it again this session + sessionStorage.setItem('versionUpdateDismissed', 'true') + } + + // Check if user already dismissed this session + useEffect(() => { + const dismissed = sessionStorage.getItem('versionUpdateDismissed') + if (dismissed === 'true') { + setIsDismissed(true) + } + }, []) + + if (!updateAvailable || isDismissed) { + return null + } + + return ( +
+ {t('A new version is available')} +
++ {t('Click update to get the latest features and improvements')} +
+