feat(pwa): Add update prompt for new versions
- Change registerType from 'autoUpdate' to 'prompt' - Add UpdatePrompt component that shows when new version available - Users see banner with "Update" or "Later" buttons - Service worker checks for updates every hour 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -54,10 +54,12 @@ import { SeoOrchestrator } from './pages/admin/seo/SeoOrchestrator';
|
|||||||
import { StatePage } from './pages/public/StatePage';
|
import { StatePage } from './pages/public/StatePage';
|
||||||
import { SeoPage } from './pages/public/SeoPage';
|
import { SeoPage } from './pages/public/SeoPage';
|
||||||
import { PrivateRoute } from './components/PrivateRoute';
|
import { PrivateRoute } from './components/PrivateRoute';
|
||||||
|
import { UpdatePrompt } from './components/UpdatePrompt';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
|
<UpdatePrompt />
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
<Route path="/login" element={<Login />} />
|
<Route path="/login" element={<Login />} />
|
||||||
|
|||||||
45
cannaiq/src/components/UpdatePrompt.tsx
Normal file
45
cannaiq/src/components/UpdatePrompt.tsx
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* PWA Update Prompt
|
||||||
|
*
|
||||||
|
* Shows a banner when a new version of the app is available.
|
||||||
|
* Uses the virtual:pwa-register/react hook from vite-plugin-pwa.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { useRegisterSW } from 'virtual:pwa-register/react';
|
||||||
|
|
||||||
|
export function UpdatePrompt() {
|
||||||
|
const {
|
||||||
|
needRefresh: [needRefresh, setNeedRefresh],
|
||||||
|
updateServiceWorker,
|
||||||
|
} = useRegisterSW({
|
||||||
|
onRegistered(r) {
|
||||||
|
// Check for updates every hour
|
||||||
|
r && setInterval(() => r.update(), 60 * 60 * 1000);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!needRefresh) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="fixed bottom-4 right-4 z-50 bg-emerald-600 text-white px-4 py-3 rounded-lg shadow-lg flex items-center gap-3 max-w-sm">
|
||||||
|
<div className="flex-1">
|
||||||
|
<p className="font-medium">New version available</p>
|
||||||
|
<p className="text-sm text-emerald-100">Refresh to update CannaIQ</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<button
|
||||||
|
onClick={() => setNeedRefresh(false)}
|
||||||
|
className="px-3 py-1 text-sm text-emerald-200 hover:text-white"
|
||||||
|
>
|
||||||
|
Later
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => updateServiceWorker(true)}
|
||||||
|
className="px-3 py-1 text-sm bg-white text-emerald-600 rounded font-medium hover:bg-emerald-50"
|
||||||
|
>
|
||||||
|
Update
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
1
cannaiq/src/vite-env.d.ts
vendored
1
cannaiq/src/vite-env.d.ts
vendored
@@ -1,4 +1,5 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
/// <reference types="vite-plugin-pwa/react" />
|
||||||
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
readonly VITE_API_URL?: string;
|
readonly VITE_API_URL?: string;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ export default defineConfig({
|
|||||||
plugins: [
|
plugins: [
|
||||||
react(),
|
react(),
|
||||||
VitePWA({
|
VitePWA({
|
||||||
registerType: 'autoUpdate',
|
registerType: 'prompt',
|
||||||
includeAssets: ['favicon.svg'],
|
includeAssets: ['favicon.svg'],
|
||||||
manifest: {
|
manifest: {
|
||||||
name: 'CannaIQ',
|
name: 'CannaIQ',
|
||||||
|
|||||||
Reference in New Issue
Block a user