108 lines
3.9 KiB
TypeScript
108 lines
3.9 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
import { useRegisterSW } from 'virtual:pwa-register/react';
|
|
import { Button } from './ui/button';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle
|
|
} from './ui/dialog';
|
|
|
|
export const ReloadPrompt: React.FC = () => {
|
|
// Skip SW in dev mode
|
|
if (import.meta.env.DEV) {
|
|
useEffect(() => {
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.getRegistrations().then((registrations) => {
|
|
registrations.forEach((registration) => registration.unregister());
|
|
});
|
|
}
|
|
// Clear workbox caches
|
|
if (typeof caches !== 'undefined') {
|
|
caches.keys().then((keys) => {
|
|
keys.forEach((key) => {
|
|
if (key.toLowerCase().includes('workbox') || key.toLowerCase().includes('cognitive-clarity')) {
|
|
caches.delete(key);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}, []);
|
|
return null;
|
|
}
|
|
|
|
const {
|
|
offlineReady: [offlineReady, setOfflineReady],
|
|
needRefresh: [needRefresh, setNeedRefresh],
|
|
updateServiceWorker,
|
|
} = useRegisterSW({
|
|
onRegisteredSW(swUrl, r) {
|
|
if (r) {
|
|
// Check for updates every 60 minutes
|
|
setInterval(() => {
|
|
console.log('[PWA] Periodic update check...');
|
|
r.update();
|
|
}, 60 * 60 * 1000);
|
|
|
|
// Check for updates when coming back online
|
|
const handleOnline = () => {
|
|
console.log('[PWA] Back online, checking for updates...');
|
|
r.update();
|
|
};
|
|
window.addEventListener('online', handleOnline);
|
|
}
|
|
|
|
// Auto-reload when a new service worker takes control
|
|
if ('serviceWorker' in navigator) {
|
|
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
|
console.log('[PWA] Controller changed, reloading...');
|
|
window.location.reload();
|
|
});
|
|
}
|
|
},
|
|
});
|
|
|
|
const close = () => {
|
|
setOfflineReady(false);
|
|
setNeedRefresh(false);
|
|
};
|
|
|
|
return (
|
|
<Dialog open={needRefresh || offlineReady} onOpenChange={close}>
|
|
<DialogContent className="sm:max-w-md bg-slate-900 border-slate-800 text-slate-100">
|
|
<DialogHeader>
|
|
<DialogTitle>
|
|
{needRefresh ? 'Update Available' : 'Offline Ready'}
|
|
</DialogTitle>
|
|
<DialogDescription className="text-slate-400">
|
|
{needRefresh
|
|
? 'A new version of Cognitive Clarity is available. Click reload to update immediately.'
|
|
: 'The application is ready to work offline.'}
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
<DialogFooter className="sm:justify-start gap-2">
|
|
{needRefresh && (
|
|
<Button
|
|
type="button"
|
|
onClick={() => updateServiceWorker(true)}
|
|
className="bg-blue-600 hover:bg-blue-500 text-white"
|
|
>
|
|
Reload and Update
|
|
</Button>
|
|
)}
|
|
<Button
|
|
type="button"
|
|
variant="secondary"
|
|
onClick={close}
|
|
className="bg-slate-800 hover:bg-slate-700 text-slate-300 border-none"
|
|
>
|
|
Close
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
};
|