feat: implement push notification subscription handling and improve service worker configuration

This commit is contained in:
Yoga Pangestu 2026-08-16 13:42:37 +07:00
parent cc3cd03e41
commit c415493ee1
2 changed files with 56 additions and 32 deletions

View File

@ -33,6 +33,38 @@ function getIsSupported(): boolean {
);
}
async function sendSubscriptionToServer(
subscription: PushSubscription,
): Promise<boolean> {
const { endpoint } = subscription;
const key = subscription.getKey('p256dh');
const auth = subscription.getKey('auth');
const response = await fetch('/api/push/subscribe', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-XSRF-TOKEN': decodeURIComponent(
document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ?? '',
),
},
credentials: 'same-origin',
body: JSON.stringify({
endpoint,
public_key: key
? btoa(String.fromCharCode(...new Uint8Array(key)))
: null,
auth_token: auth
? btoa(String.fromCharCode(...new Uint8Array(auth)))
: null,
content_encoding: 'aes128gcm',
}),
});
return response.ok;
}
export function usePushNotification() {
const [permission, setPermission] =
useState<PermissionStatus>(getInitialPermission);
@ -54,40 +86,29 @@ export function usePushNotification() {
async (vapidPublicKey: string): Promise<boolean> => {
try {
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
vapidPublicKey,
) as BufferSource,
});
const { endpoint } = subscription;
const key = subscription.getKey('p256dh');
const auth = subscription.getKey('auth');
const existingSubscription =
await registration.pushManager.getSubscription();
const response = await fetch('/api/push/subscribe', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-XSRF-TOKEN': decodeURIComponent(
document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ??
'',
),
},
body: JSON.stringify({
endpoint,
public_key: key
? btoa(String.fromCharCode(...new Uint8Array(key)))
: null,
auth_token: auth
? btoa(String.fromCharCode(...new Uint8Array(auth)))
: null,
content_encoding: 'aes128gcm',
}),
});
if (existingSubscription) {
const synced = await sendSubscriptionToServer(
existingSubscription,
);
return response.ok;
return synced;
}
const subscription =
await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: urlBase64ToUint8Array(
vapidPublicKey,
) as BufferSource,
});
const saved = await sendSubscriptionToServer(subscription);
return saved;
} catch (error) {
console.error(
'Failed to subscribe to push notifications:',
@ -119,6 +140,7 @@ export function usePushNotification() {
document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ?? '',
),
},
credentials: 'same-origin',
body: JSON.stringify({
endpoint: subscription.endpoint,
}),

View File

@ -37,7 +37,9 @@ export default defineConfig({
manifest: false,
srcDir: 'resources/js',
filename: 'sw.ts',
workbox: {
scope: '/',
strategies: 'injectManifest',
injectManifest: {
globPatterns: ['**/*.{js,css,html,ico,png,svg,woff,woff2}'],
},
devOptions: {