tried fixing infinite loop
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import { API_ENDPOINTS } from "~/constants";
|
||||
import useSubscribeNotification from "~/composables/api/notifications/useSubscribeNotification";
|
||||
import { useToast } from "~/composables/global/useToast";
|
||||
|
||||
interface VapidKeys {
|
||||
publicKey: string;
|
||||
}
|
||||
|
||||
export const usePushNotifications = () => {
|
||||
const isSupported = ref(false);
|
||||
const permission = usePermission("notifications");
|
||||
const subscription = useLocalStorage<PushSubscriptionJSON | null>(
|
||||
"push-subscription",
|
||||
null
|
||||
);
|
||||
const vapid = ref<VapidKeys | null>(null);
|
||||
|
||||
const { mutateAsync: subscribeNotification } = useSubscribeNotification();
|
||||
const { addToast } = useToast();
|
||||
|
||||
const unsubscribe = async () => {
|
||||
const swRegistration = await navigator.serviceWorker.ready;
|
||||
const existingSubscription =
|
||||
await swRegistration.pushManager.getSubscription();
|
||||
if (existingSubscription) {
|
||||
await existingSubscription.unsubscribe();
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
if (typeof window !== "undefined" && "serviceWorker" in navigator) {
|
||||
isSupported.value = true;
|
||||
vapid.value = await $fetch("/api/vapid");
|
||||
}
|
||||
});
|
||||
|
||||
const subscribe = async () => {
|
||||
if (!isSupported.value || !vapid.value?.publicKey) {
|
||||
throw new Error("Push notifications not supported");
|
||||
}
|
||||
|
||||
const swRegistration = await navigator.serviceWorker.ready;
|
||||
|
||||
await unsubscribe();
|
||||
|
||||
const applicationServerKey = vapid.value.publicKey
|
||||
.replace(/-/g, "+")
|
||||
.replace(/_/g, "/");
|
||||
|
||||
const convertedKey = Uint8Array.from(atob(applicationServerKey), (c) =>
|
||||
c.charCodeAt(0)
|
||||
);
|
||||
|
||||
const pushSubscription = await swRegistration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: convertedKey,
|
||||
});
|
||||
|
||||
const subscriptionJson = pushSubscription.toJSON();
|
||||
|
||||
subscribeNotification(
|
||||
{
|
||||
body: subscriptionJson,
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
addToast({
|
||||
message: "اعلانات برای دستگاه شما فعال شد",
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
addToast({
|
||||
message: "خطایی در فعال شدن اعلانات رخ داد",
|
||||
options: {
|
||||
status: "error",
|
||||
},
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
subscription.value = subscriptionJson;
|
||||
};
|
||||
|
||||
return {
|
||||
isSupported,
|
||||
permission,
|
||||
subscribe,
|
||||
unsubscribe,
|
||||
subscription,
|
||||
};
|
||||
};
|
||||
+31
-26
@@ -6,45 +6,45 @@ export default defineNuxtConfig({
|
||||
css: [
|
||||
"~/assets/css/tailwind.css",
|
||||
"swiper/css",
|
||||
"animate.css/animate.min.css"
|
||||
"animate.css/animate.min.css",
|
||||
],
|
||||
|
||||
routeRules: {
|
||||
"/products": { prerender: false, ssr: false }
|
||||
"/products": { prerender: false, ssr: false },
|
||||
},
|
||||
|
||||
app: {
|
||||
head: {
|
||||
title: "فروشگاه هی ملز"
|
||||
title: "فروشگاه هی ملز",
|
||||
},
|
||||
pageTransition: {
|
||||
enterActiveClass:
|
||||
"animate__animated animate__fadeIn animate__faster",
|
||||
leaveActiveClass:
|
||||
"animate__animated animate__fadeOut animate__faster",
|
||||
mode: "out-in"
|
||||
mode: "out-in",
|
||||
},
|
||||
layoutTransition: {
|
||||
enterActiveClass:
|
||||
"animate__animated animate__fadeIn animate__faster",
|
||||
leaveActiveClass:
|
||||
"animate__animated animate__fadeOut animate__faster",
|
||||
mode: "out-in"
|
||||
}
|
||||
mode: "out-in",
|
||||
},
|
||||
},
|
||||
|
||||
postcss: {
|
||||
plugins: {
|
||||
"@tailwindcss/postcss": {},
|
||||
autoprefixer: {}
|
||||
}
|
||||
autoprefixer: {},
|
||||
},
|
||||
},
|
||||
|
||||
components: [
|
||||
{
|
||||
path: "~/components",
|
||||
pathPrefix: false
|
||||
}
|
||||
pathPrefix: false,
|
||||
},
|
||||
],
|
||||
|
||||
icon: {
|
||||
@@ -52,9 +52,9 @@ export default defineNuxtConfig({
|
||||
customCollections: [
|
||||
{
|
||||
prefix: "ci",
|
||||
dir: "./public/icons"
|
||||
}
|
||||
]
|
||||
dir: "./public/icons",
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
modules: [
|
||||
@@ -65,21 +65,23 @@ export default defineNuxtConfig({
|
||||
"DM Sans": "100..900",
|
||||
Inter: "100..900",
|
||||
download: true,
|
||||
inject: false
|
||||
}
|
||||
}
|
||||
inject: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
"@nuxt/icon",
|
||||
"reka-ui/nuxt",
|
||||
"@vueuse/nuxt",
|
||||
"@formkit/auto-animate/nuxt",
|
||||
"@vite-pwa/nuxt"
|
||||
"@vite-pwa/nuxt",
|
||||
],
|
||||
|
||||
pwa: {
|
||||
strategies: "injectManifest",
|
||||
srcDir: "public",
|
||||
filename: "sw.js",
|
||||
registerType:
|
||||
process.env.NODE_ENV === "production" ? "autoUpdate" : "prompt",
|
||||
manifest: {
|
||||
name: "Heymlz",
|
||||
short_name: "Heymlz",
|
||||
@@ -88,27 +90,30 @@ export default defineNuxtConfig({
|
||||
{
|
||||
src: "/logo/logo-192x192.png",
|
||||
sizes: "192x192",
|
||||
type: "image/png"
|
||||
type: "image/png",
|
||||
},
|
||||
{
|
||||
src: "/logo/logo-512x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png"
|
||||
}
|
||||
]
|
||||
type: "image/png",
|
||||
},
|
||||
],
|
||||
},
|
||||
workbox: {
|
||||
navigateFallback: "/",
|
||||
clientsClaim: true,
|
||||
skipWaiting: true
|
||||
skipWaiting: true,
|
||||
},
|
||||
devOptions: {
|
||||
enabled: process.env.NODE_ENV === "production",
|
||||
type: "module",
|
||||
},
|
||||
devOptions: { enabled: true, type: "module" }
|
||||
},
|
||||
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
API_BASE_URL: process.env.API_BASE_URL,
|
||||
DEBUG: process.env.DEBUG
|
||||
}
|
||||
}
|
||||
DEBUG: process.env.DEBUG,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -8,29 +8,73 @@ export default defineNuxtPlugin(() => {
|
||||
const { isInstalledAsPWA } = usePWA();
|
||||
|
||||
if ("serviceWorker" in navigator && isInstalledAsPWA.value) {
|
||||
// Initialize Workbox
|
||||
wb = new Workbox("/sw.js");
|
||||
|
||||
wb.addEventListener("waiting", () => {
|
||||
navigator.serviceWorker
|
||||
.register("/sw.js")
|
||||
.then((registration) => {
|
||||
// Native Service Worker API for update detection
|
||||
registration.addEventListener("updatefound", () => {
|
||||
const newWorker = registration.installing;
|
||||
if (newWorker) {
|
||||
newWorker.addEventListener("statechange", () => {
|
||||
if (newWorker.state === "installed") {
|
||||
// Only show prompt if there's a controller (not first install)
|
||||
if (navigator.serviceWorker.controller) {
|
||||
checkForUpdate();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Workbox events for consistency
|
||||
wb?.addEventListener("waiting", () => {
|
||||
checkForUpdate();
|
||||
});
|
||||
|
||||
wb.register()
|
||||
.then((registration: any) => {
|
||||
// Check if there's already a waiting worker
|
||||
if (registration.waiting) {
|
||||
checkForUpdate();
|
||||
}
|
||||
|
||||
// Periodic update checks (optional)
|
||||
setInterval(() => {
|
||||
registration.update().catch((err) => {
|
||||
console.debug(
|
||||
"Service worker update check failed:",
|
||||
err
|
||||
);
|
||||
});
|
||||
}, 60 * 60 * 1000); // Check every hour
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Service worker registration failed:", error);
|
||||
.catch((err) => {
|
||||
console.error("Service worker registration failed:", err);
|
||||
});
|
||||
|
||||
// Register Workbox
|
||||
wb.register().catch((error) => {
|
||||
console.error("Workbox registration failed:", error);
|
||||
});
|
||||
}
|
||||
|
||||
const checkForUpdate = () => {
|
||||
if (!updateAvailable.value) {
|
||||
updateAvailable.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdate = () => {
|
||||
if (wb) {
|
||||
// Send skip waiting message
|
||||
wb.messageSW({ type: "SKIP_WAITING" }).then(() => {
|
||||
// Notify all tabs to reload
|
||||
if (navigator.serviceWorker.controller) {
|
||||
navigator.serviceWorker.controller.postMessage({
|
||||
type: "CLIENT_RELOAD",
|
||||
});
|
||||
}
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
+12
-10
@@ -3,33 +3,36 @@ import { precacheAndRoute } from "workbox-precaching";
|
||||
// Precaching configuration for PWA assets
|
||||
precacheAndRoute(self.__WB_MANIFEST);
|
||||
|
||||
// Version
|
||||
|
||||
const VERSION = "1.0.4";
|
||||
|
||||
// Service Worker Installation
|
||||
// Only enable skipWaiting and claim in production
|
||||
const isProduction = process.env.NODE_ENV === "production";
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
if (isProduction) {
|
||||
self.skipWaiting();
|
||||
}
|
||||
});
|
||||
|
||||
// Service Worker Activation
|
||||
self.addEventListener("activate", (event) => {
|
||||
event.waitUntil(
|
||||
(async () => {
|
||||
if (isProduction) {
|
||||
const clients = await self.clients.matchAll({ type: "window" });
|
||||
|
||||
// Notify all open clients about the version
|
||||
clients.forEach((client) =>
|
||||
client.postMessage({ type: "VERSION_CHECK", version: VERSION })
|
||||
client.postMessage({
|
||||
type: "VERSION_CHECK",
|
||||
version: VERSION,
|
||||
})
|
||||
);
|
||||
|
||||
self.clients.claim();
|
||||
}
|
||||
console.log("Service Worker Activated (Version: " + VERSION + ")");
|
||||
})()
|
||||
);
|
||||
});
|
||||
|
||||
// Push Notification Handler for Django Web Push
|
||||
// Rest of your existing handlers remain the same...
|
||||
self.addEventListener("push", (event) => {
|
||||
try {
|
||||
const payload = event.data?.json() || {
|
||||
@@ -51,7 +54,6 @@ self.addEventListener("push", (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Notification Click Handler
|
||||
self.addEventListener("notificationclick", (event) => {
|
||||
event.notification.close();
|
||||
event.waitUntil(clients.openWindow(event.notification.data?.url || "/"));
|
||||
|
||||
Reference in New Issue
Block a user