push notification
fix implemented
This commit is contained in:
1 parent
0bbf2ab56f
commit
57864e00da
15 files changed
+5126
-26
No files matched your search
@@ -0,0 +1 @@
|
||||
if('serviceWorker' in navigator) navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' })
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright 2018 Google Inc. All Rights Reserved.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// If the loader is already loaded, just stop.
|
||||
if (!self.define) {
|
||||
let registry = {};
|
||||
|
||||
// Used for `eval` and `importScripts` where we can't get script URL by other means.
|
||||
// In both cases, it's safe to use a global var because those functions are synchronous.
|
||||
let nextDefineUri;
|
||||
|
||||
const singleRequire = (uri, parentUri) => {
|
||||
uri = new URL(uri + ".js", parentUri).href;
|
||||
return registry[uri] || (
|
||||
|
||||
new Promise(resolve => {
|
||||
if ("document" in self) {
|
||||
const script = document.createElement("script");
|
||||
script.src = uri;
|
||||
script.onload = resolve;
|
||||
document.head.appendChild(script);
|
||||
} else {
|
||||
nextDefineUri = uri;
|
||||
importScripts(uri);
|
||||
resolve();
|
||||
}
|
||||
})
|
||||
|
||||
.then(() => {
|
||||
let promise = registry[uri];
|
||||
if (!promise) {
|
||||
throw new Error(`Module ${uri} didn’t register its module`);
|
||||
}
|
||||
return promise;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
self.define = (depsNames, factory) => {
|
||||
const uri = nextDefineUri || ("document" in self ? document.currentScript.src : "") || location.href;
|
||||
if (registry[uri]) {
|
||||
// Module is already loading or loaded.
|
||||
return;
|
||||
}
|
||||
let exports = {};
|
||||
const require = depUri => singleRequire(depUri, uri);
|
||||
const specialDeps = {
|
||||
module: { uri },
|
||||
exports,
|
||||
require
|
||||
};
|
||||
registry[uri] = Promise.all(depsNames.map(
|
||||
depName => specialDeps[depName] || require(depName)
|
||||
)).then(deps => {
|
||||
factory(...deps);
|
||||
return exports;
|
||||
});
|
||||
};
|
||||
}
|
||||
define(['./workbox-d975e299'], (function (workbox) { 'use strict';
|
||||
|
||||
self.skipWaiting();
|
||||
workbox.clientsClaim();
|
||||
|
||||
/**
|
||||
* The precacheAndRoute() method efficiently caches and responds to
|
||||
* requests for URLs in the manifest.
|
||||
* See https://goo.gl/S9QRab
|
||||
*/
|
||||
workbox.precacheAndRoute([{
|
||||
"url": "registerSW.js",
|
||||
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||
}, {
|
||||
"url": "index.html",
|
||||
"revision": "0.ek3n41mv3u8"
|
||||
}], {});
|
||||
workbox.cleanupOutdatedCaches();
|
||||
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||
allowlist: [/^\/$/]
|
||||
}));
|
||||
workbox.registerRoute(/^https?:\/\/.*\/api\/.*/i, new workbox.StaleWhileRevalidate({
|
||||
"cacheName": "api-cache",
|
||||
plugins: [new workbox.ExpirationPlugin({
|
||||
maxEntries: 100,
|
||||
maxAgeSeconds: 86400
|
||||
}), new workbox.CacheableResponsePlugin({
|
||||
statuses: [0, 200]
|
||||
})]
|
||||
}), 'GET');
|
||||
|
||||
}));
|
||||
File diff suppressed because it is too large.
Load diff
@@ -32,9 +32,18 @@ export function NotificationBanner() {
|
||||
};
|
||||
|
||||
const handleSubscribe = async () => {
|
||||
const success = await subscribe();
|
||||
if (success) {
|
||||
setIsVisible(false);
|
||||
console.log('handleSubscribe called');
|
||||
console.log('isSupported:', isSupported);
|
||||
console.log('isSubscribed:', isSubscribed);
|
||||
|
||||
try {
|
||||
const success = await subscribe();
|
||||
console.log('subscribe() returned:', success);
|
||||
if (success) {
|
||||
setIsVisible(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('handleSubscribe error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -40,13 +40,20 @@ export function usePushNotifications(): UsePushNotificationsReturn {
|
||||
const [permissionState, setPermissionState] = useState(getInitialPermission);
|
||||
const hasCheckedRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('usePushNotifications - isSupported:', checkPushSupport());
|
||||
console.log('usePushNotifications - permissionState:', getInitialPermission());
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isSupported || hasCheckedRef.current) return;
|
||||
hasCheckedRef.current = true;
|
||||
|
||||
console.log('Checking existing push subscription...');
|
||||
navigator.serviceWorker.ready
|
||||
.then((registration) => registration.pushManager.getSubscription())
|
||||
.then((subscription) => {
|
||||
console.log('Existing subscription:', subscription);
|
||||
setIsSubscribed(!!subscription);
|
||||
})
|
||||
.catch((error) => {
|
||||
@@ -71,6 +78,7 @@ export function usePushNotifications(): UsePushNotificationsReturn {
|
||||
try {
|
||||
const permission = await requestPermission();
|
||||
if (permission !== 'granted') {
|
||||
console.log('Push permission denied');
|
||||
setIsLoading(false);
|
||||
return false;
|
||||
}
|
||||
@@ -82,19 +90,58 @@ export function usePushNotifications(): UsePushNotificationsReturn {
|
||||
return false;
|
||||
}
|
||||
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
console.log('Got VAPID public key, subscribing...');
|
||||
|
||||
// Check if service worker is already ready
|
||||
console.log('Checking service worker status...');
|
||||
const swController = navigator.serviceWorker.controller;
|
||||
console.log('Service worker controller:', swController);
|
||||
|
||||
// Wait for service worker to be ready with timeout
|
||||
const registration = await Promise.race([
|
||||
navigator.serviceWorker.ready,
|
||||
new Promise<ServiceWorkerRegistration>((_, reject) => {
|
||||
setTimeout(() => {
|
||||
reject(new Error('Service worker ready timeout after 10s'));
|
||||
}, 10000);
|
||||
}),
|
||||
]);
|
||||
console.log('Service worker ready:', registration);
|
||||
|
||||
if (!registration.pushManager) {
|
||||
console.error('PushManager not available in service worker registration');
|
||||
setIsLoading(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
let subscription = await registration.pushManager.getSubscription();
|
||||
|
||||
if (!subscription) {
|
||||
console.log('Creating new push subscription...');
|
||||
subscription = await registration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: urlBase64ToUint8Array(publicKey),
|
||||
});
|
||||
console.log('Push subscription created');
|
||||
} else {
|
||||
console.log('Existing push subscription found');
|
||||
}
|
||||
|
||||
const subJson = subscription.toJSON() as PushSubscriptionData;
|
||||
const success = await subscribeToPush(subJson);
|
||||
const subJson = subscription.toJSON();
|
||||
console.log('Subscription JSON:', subJson);
|
||||
|
||||
if (
|
||||
!subJson.endpoint ||
|
||||
!subJson.keys?.p256dh ||
|
||||
!subJson.keys?.auth
|
||||
) {
|
||||
console.error('Invalid subscription data:', subJson);
|
||||
setIsLoading(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
const success = await subscribeToPush(subJson as PushSubscriptionData);
|
||||
console.log('Subscribe to push result:', success);
|
||||
|
||||
if (success) {
|
||||
setIsSubscribed(true);
|
||||
|
||||
+25
-6
@@ -30,18 +30,37 @@ export async function subscribeToPush(
|
||||
subscription: PushSubscriptionData,
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
console.log('Sending subscription to server:', {
|
||||
endpoint: subscription.endpoint,
|
||||
hasKeys: !!subscription.keys,
|
||||
});
|
||||
|
||||
const payload = {
|
||||
endpoint: subscription.endpoint,
|
||||
p256dh: subscription.keys.p256dh,
|
||||
auth: subscription.keys.auth,
|
||||
};
|
||||
|
||||
console.log('Payload:', payload);
|
||||
console.log('API URL:', `${API_BASE_URL}/push/subscribe`);
|
||||
|
||||
const response = await fetch(`${API_BASE_URL}/push/subscribe`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
endpoint: subscription.endpoint,
|
||||
p256dh: subscription.keys.p256dh,
|
||||
auth: subscription.keys.auth,
|
||||
}),
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
return response.ok;
|
||||
|
||||
console.log('Subscribe response status:', response.status);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
console.error('Subscribe failed:', errorText);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Error subscribing to push:', error);
|
||||
return false;
|
||||
|
||||
+19
-1
@@ -5,12 +5,30 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { router } from './routes'
|
||||
import { AuthProvider } from './contexts/AuthContext'
|
||||
import { initializeTheme } from './lib/theme'
|
||||
import 'virtual:pwa-register'
|
||||
import { registerSW } from 'virtual:pwa-register'
|
||||
|
||||
initializeTheme()
|
||||
|
||||
const queryClient = new QueryClient()
|
||||
|
||||
// Register service worker
|
||||
const updateSW = registerSW({
|
||||
onNeedRefresh() {
|
||||
if (confirm('New content available. Reload?')) {
|
||||
updateSW(true)
|
||||
}
|
||||
},
|
||||
onOfflineReady() {
|
||||
console.log('App ready to work offline')
|
||||
},
|
||||
onRegistered(registration) {
|
||||
console.log('SW Registered:', registration?.scope)
|
||||
},
|
||||
onRegisterError(error) {
|
||||
console.error('SW registration error:', error)
|
||||
},
|
||||
})
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
|
||||
@@ -44,6 +44,7 @@ export default defineConfig({
|
||||
},
|
||||
devOptions: {
|
||||
enabled: true,
|
||||
type: 'module',
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user