155 lines
5.1 KiB
TypeScript
155 lines
5.1 KiB
TypeScript
import { useEffect } from "preact/hooks";
|
|
|
|
// Simple safe storage functions to avoid errorHandling.ts dependency
|
|
function safeLocalStorage() {
|
|
try {
|
|
if (typeof localStorage === "undefined") {
|
|
return null;
|
|
}
|
|
// Test if localStorage is accessible
|
|
const testKey = "__test__";
|
|
localStorage.setItem(testKey, "test");
|
|
localStorage.removeItem(testKey);
|
|
return localStorage;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function safeSessionStorage() {
|
|
try {
|
|
if (typeof sessionStorage === "undefined") {
|
|
return null;
|
|
}
|
|
// Test if sessionStorage is accessible
|
|
const testKey = "__test__";
|
|
sessionStorage.setItem(testKey, "test");
|
|
sessionStorage.removeItem(testKey);
|
|
return sessionStorage;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Custom hook to manage Service Worker registration
|
|
* Handles registration, unregistration, and session-based updates
|
|
* Includes robust error handling for network issues and broken pipes
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* function MyComponent() {
|
|
* useServiceWorker();
|
|
* return <div>Component content</div>;
|
|
* }
|
|
* ```
|
|
*/
|
|
export function useServiceWorker() {
|
|
useEffect(() => {
|
|
if ("serviceWorker" in navigator) {
|
|
// Check if this is a new user experience (session start)
|
|
const storage = safeSessionStorage();
|
|
const isNewSession = !storage?.getItem("sw_registered");
|
|
|
|
// Add timeout for service worker operations
|
|
// const registrationTimeout = setTimeout(() => {
|
|
// console.warn("Service Worker registration taking longer than expected");
|
|
// }, 10000);
|
|
|
|
navigator.serviceWorker.getRegistrations().then((registrations) => {
|
|
const activeSW = registrations.find((reg) =>
|
|
reg.active?.scriptURL.includes("fetch_sw.js")
|
|
);
|
|
|
|
if (activeSW && !isNewSession) {
|
|
// Service worker already active and not a new session - skip registration
|
|
// console.log("Service Worker already active.");
|
|
// clearTimeout(registrationTimeout);
|
|
return;
|
|
}
|
|
|
|
// New session or no active SW - unregister old versions and register new
|
|
const unregisterPromises = registrations.map((registration) =>
|
|
registration.unregister().catch((err) => {
|
|
// Log but don't fail if unregistration fails
|
|
// console.warn("Failed to unregister old service worker:", err);
|
|
return Promise.resolve();
|
|
})
|
|
);
|
|
|
|
return Promise.all(unregisterPromises).then(() => {
|
|
// Register the new service worker after unregistering old ones
|
|
return navigator.serviceWorker.register("/fetch_sw.js");
|
|
}).then(() => {
|
|
// console.log("Service Worker registered.");
|
|
const swStorage = safeSessionStorage();
|
|
swStorage?.setItem("sw_registered", "true");
|
|
// clearTimeout(registrationTimeout);
|
|
}).catch((regError) => {
|
|
// Handle registration errors gracefully
|
|
// console.error("Service Worker registration failed:", regError);
|
|
// clearTimeout(registrationTimeout);
|
|
// Don't throw - allow app to continue without service worker
|
|
});
|
|
}).catch((error) => {
|
|
//clearTimeout(registrationTimeout);
|
|
|
|
// Handle different error types
|
|
// const errorMessage = error instanceof Error ? error.message : String(error);
|
|
// if (error instanceof TypeError || errorMessage.includes("network")) {
|
|
// console.error("Network error during service worker setup:", error);
|
|
// } else if (errorMessage.includes("broken pipe")) {
|
|
// console.error("Connection broken during service worker setup:", error);
|
|
// } else {
|
|
// console.error("Service Worker registration failed:", error);
|
|
// }
|
|
// App should continue functioning without service worker
|
|
});
|
|
}
|
|
// else {
|
|
// console.log("Service Worker not supported in this browser.");
|
|
// }
|
|
|
|
// Cleanup function
|
|
return () => {
|
|
// No cleanup needed for service worker registration
|
|
};
|
|
}, []);
|
|
}
|
|
|
|
/**
|
|
* Custom hook to manage logout button state
|
|
* Handles post-logout redirect cleanup
|
|
* Includes error handling for localStorage access issues
|
|
*/
|
|
export function useLogoutCleanup() {
|
|
useEffect(() => {
|
|
try {
|
|
// Use safe localStorage access
|
|
const storage = safeLocalStorage();
|
|
if (!storage) {
|
|
console.warn("localStorage not available");
|
|
return;
|
|
}
|
|
|
|
const lastClickedButton = storage.getItem("lastClickedButton");
|
|
if (lastClickedButton === "logout") {
|
|
storage.removeItem("lastClickedButton");
|
|
|
|
// Add try-catch for URL manipulation and redirect
|
|
try {
|
|
const url = new URL(globalThis.location.href);
|
|
globalThis.location.href = url.origin + "?popstate=true";
|
|
} catch (urlError) {
|
|
console.error("Error during logout redirect:", urlError);
|
|
// Fallback to simple redirect
|
|
globalThis.location.href = "/";
|
|
}
|
|
}
|
|
} catch (error) {
|
|
// Handle localStorage access errors (quota exceeded, privacy mode, etc.)
|
|
console.error("Error during logout cleanup:", error);
|
|
}
|
|
}, []);
|
|
}
|