u
This commit is contained in:
@@ -35,6 +35,14 @@ export {
|
||||
selectActiveHelpId,
|
||||
} from './helpAutomat';
|
||||
|
||||
export {
|
||||
default as pwaAutomat,
|
||||
initPwa,
|
||||
openPwaDialog,
|
||||
closePwaDialog,
|
||||
applyPwaUpdate,
|
||||
} from './pwaAutomat';
|
||||
|
||||
export { default as supplierAutomat } from './supplierAutomat';
|
||||
export { default as warehouseAutomat } from './warehouseAutomat';
|
||||
|
||||
|
||||
125
src/automats/pwaAutomat.js
Normal file
125
src/automats/pwaAutomat.js
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* @file pwaAutomat.js
|
||||
* @description Manages PWA update lifecycle, service worker registration,
|
||||
* and user prompt dialog state.
|
||||
*/
|
||||
|
||||
import { Automat } from 'react-automat';
|
||||
|
||||
/**
|
||||
* @typedef {Object} PwaState
|
||||
* @property {boolean} needRefresh Whether a new SW update is available and waiting
|
||||
* @property {boolean} dialogOpen Whether the update dialog is currently visible
|
||||
* @property {boolean} offlineReady Whether content is cached for offline use
|
||||
* @property {boolean} updating Whether an update is currently being applied
|
||||
*/
|
||||
|
||||
/** @type {PwaState} */
|
||||
const initialState = {
|
||||
needRefresh: false,
|
||||
dialogOpen: false,
|
||||
offlineReady: false,
|
||||
updating: false,
|
||||
};
|
||||
|
||||
let swUpdater = null;
|
||||
|
||||
/**
|
||||
* State store for PWA lifecycle & update notifications.
|
||||
* Registered on window.__AUTOMATS__ as 'pwa'.
|
||||
*
|
||||
* @type {Automat<PwaState>}
|
||||
*/
|
||||
const pwaAutomat = new Automat(
|
||||
initialState,
|
||||
{
|
||||
setRegistration(updater) {
|
||||
swUpdater = updater;
|
||||
},
|
||||
setNeedRefresh() {
|
||||
pwaAutomat.setState({
|
||||
needRefresh: true,
|
||||
dialogOpen: true,
|
||||
});
|
||||
},
|
||||
setOfflineReady() {
|
||||
pwaAutomat.setState({
|
||||
offlineReady: true,
|
||||
});
|
||||
},
|
||||
openDialog() {
|
||||
pwaAutomat.setState({ dialogOpen: true });
|
||||
},
|
||||
closeDialog() {
|
||||
pwaAutomat.setState({ dialogOpen: false });
|
||||
},
|
||||
async applyUpdate() {
|
||||
pwaAutomat.setState({ updating: true });
|
||||
if (typeof swUpdater === 'function') {
|
||||
try {
|
||||
await swUpdater(true);
|
||||
} catch (err) {
|
||||
console.error('[PWA] Error activating update:', err);
|
||||
window.location.reload();
|
||||
}
|
||||
} else {
|
||||
window.location.reload();
|
||||
}
|
||||
},
|
||||
// Allows testing the dialog in dev mode or in browser console:
|
||||
// window.__AUTOMATS__.pwa.actions.simulateUpdateAvailable()
|
||||
simulateUpdateAvailable() {
|
||||
pwaAutomat.setState({
|
||||
needRefresh: true,
|
||||
dialogOpen: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
{ name: 'pwa' },
|
||||
);
|
||||
|
||||
/**
|
||||
* Initializes PWA service worker registration in production.
|
||||
*/
|
||||
export function initPwa() {
|
||||
if (!import.meta.env.PROD || !('serviceWorker' in navigator)) return;
|
||||
|
||||
import('virtual:pwa-register')
|
||||
.then(({ registerSW }) => {
|
||||
const updateSW = registerSW({
|
||||
immediate: true,
|
||||
onNeedRefresh() {
|
||||
pwaAutomat.actions.setNeedRefresh();
|
||||
},
|
||||
onOfflineReady() {
|
||||
pwaAutomat.actions.setOfflineReady();
|
||||
},
|
||||
onRegistered(registration) {
|
||||
if (!registration) return;
|
||||
|
||||
// Check for new updates periodically (every 30 minutes)
|
||||
setInterval(() => {
|
||||
registration.update().catch(() => {});
|
||||
}, 30 * 60 * 1000);
|
||||
|
||||
// Check for updates when tab or PWA returns to foreground
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
registration.update().catch(() => {});
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
pwaAutomat.actions.setRegistration(updateSW);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn('[PWA] Service worker registration failed or omitted:', err);
|
||||
});
|
||||
}
|
||||
|
||||
export const openPwaDialog = () => pwaAutomat.actions.openDialog();
|
||||
export const closePwaDialog = () => pwaAutomat.actions.closeDialog();
|
||||
export const applyPwaUpdate = () => pwaAutomat.actions.applyUpdate();
|
||||
|
||||
export default pwaAutomat;
|
||||
Reference in New Issue
Block a user