refine nginx caching strategy and add service worker update prompt with periodic checks
This commit is contained in:
@@ -4,6 +4,7 @@ import { DeliveryForm } from './components/delivery/DeliveryForm';
|
||||
import { LoginForm } from './components/auth/LoginForm';
|
||||
import { ToastContainer } from './components/ui/Toast';
|
||||
import { Button } from './components/ui/Button';
|
||||
import { UpdatePrompt } from './components/ui/UpdatePrompt';
|
||||
import { useDeliveryStore } from './stores/deliveryStore';
|
||||
import { useAuthStore } from './stores/authStore';
|
||||
|
||||
@@ -89,6 +90,7 @@ function App() {
|
||||
if (!isAuthenticated) {
|
||||
return (
|
||||
<>
|
||||
<UpdatePrompt />
|
||||
<LoginForm />
|
||||
<ToastContainer />
|
||||
</>
|
||||
@@ -97,6 +99,7 @@ function App() {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-[#fbf8fb]">
|
||||
<UpdatePrompt />
|
||||
<header className="sticky top-0 z-40 bg-[#1B263B] text-white shadow-md">
|
||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex items-center justify-between h-14">
|
||||
|
||||
55
frontend/src/components/ui/UpdatePrompt.tsx
Normal file
55
frontend/src/components/ui/UpdatePrompt.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { useRegisterSW } from 'virtual:pwa-register/react';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
import { Button } from './Button';
|
||||
|
||||
// Check for SW updates every hour and on tab focus/visibility change
|
||||
const UPDATE_INTERVAL_MS = 60 * 60 * 1000;
|
||||
|
||||
export function UpdatePrompt() {
|
||||
const {
|
||||
needRefresh: [needRefresh],
|
||||
updateServiceWorker,
|
||||
} = useRegisterSW({
|
||||
onRegisteredSW(_swUrl, registration) {
|
||||
if (!registration) return;
|
||||
|
||||
const checkForUpdate = async () => {
|
||||
if (registration.installing || !navigator) return;
|
||||
if ('connection' in navigator && !navigator.onLine) return;
|
||||
try {
|
||||
await registration.update();
|
||||
} catch {
|
||||
// network error — ignore, will retry
|
||||
}
|
||||
};
|
||||
|
||||
setInterval(checkForUpdate, UPDATE_INTERVAL_MS);
|
||||
|
||||
const onVisible = () => {
|
||||
if (document.visibilityState === 'visible') checkForUpdate();
|
||||
};
|
||||
document.addEventListener('visibilitychange', onVisible);
|
||||
window.addEventListener('focus', checkForUpdate);
|
||||
},
|
||||
});
|
||||
|
||||
if (!needRefresh) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed top-0 inset-x-0 z-[60] bg-[#1B263B] text-white shadow-lg">
|
||||
<div className="max-w-7xl mx-auto px-4 py-2 flex items-center justify-between gap-3">
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<RefreshCw size={16} className="shrink-0" />
|
||||
<span>Доступна новая версия приложения</span>
|
||||
</div>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={() => updateServiceWorker(true)}
|
||||
className="bg-white text-[#1B263B] hover:bg-white/90"
|
||||
>
|
||||
Обновить
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -3,18 +3,6 @@ import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/sw.js', { scope: '/' })
|
||||
.then((registration) => {
|
||||
console.log('SW registered:', registration)
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('SW registration failed:', error)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
|
||||
Reference in New Issue
Block a user