Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ yarn-error.log*
next-env.d.ts

# PWA files
**/public/sw.js
**/public/workbox-*.js
**/public/worker-*.js
**/public/sw.js.map
Expand Down
14 changes: 14 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,20 @@ export default function RootLayout({
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta name="apple-mobile-web-app-title" content="QueCode" />

{/* PushAlert Unified Code */}
<script
type="text/javascript"
dangerouslySetInnerHTML={{
__html: `(function(d, t) {
var g = d.createElement(t),
s = d.getElementsByTagName(t)[0];
g.src = "https://cdn.pushalert.co/unified_0fe68d0326f325e63c546b3d13037915.js";
s.parentNode.insertBefore(g, s);
}(document, "script"));`,
}}
/>
{/* End PushAlert Unified Code */}
</head>
<body
className={`${poppins.className} ${geistSans.variable} ${geistMono.variable} antialiased`}
Expand Down
2 changes: 0 additions & 2 deletions components/ActionPage/QRObjectValidator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -358,8 +358,6 @@ export default function QRObjectValidator({ isOpen, onClose, organizationId }: Q

if (welcomeIndex !== -1 && pathParts[welcomeIndex + 1]) {
const userId = pathParts[welcomeIndex + 1];
console.log("Welcome URL detected, navigating to /action/" + userId);

toast({
title: "User Profile Scanned",
description: "Navigating to user's QR objects...",
Expand Down
161 changes: 118 additions & 43 deletions hooks/use-push-notifications.ts
Original file line number Diff line number Diff line change
@@ -1,96 +1,171 @@
'use client';

import { useEffect, useState } from 'react';
import { requestNotificationPermission, onMessageListener } from '@/lib/firebase';
import { useEffect, useState, useCallback } from 'react';
import {
initializePushAlerts,
requestNotificationPermission,
onMessageListener
} from '@/lib/pushalerts';
import { useAuthToken } from './use-auth-token';
import axios from 'axios';

export function usePushNotifications() {
const [isSupported, setIsSupported] = useState(false);
const [permission, setPermission] = useState<NotificationPermission>('default');
const [swReady, setSwReady] = useState(false);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const { getToken } = useAuthToken();

// Initialize service worker and check support
useEffect(() => {
if (typeof window !== 'undefined' && 'Notification' in window) {
setIsSupported(true);
setPermission(Notification.permission);
}
}, []);
const initializeNotifications = async () => {
try {
if (typeof window !== 'undefined' && 'Notification' in window) {
setIsSupported(true);
setPermission(Notification.permission);

// Check if service worker can be registered
if ('serviceWorker' in navigator) {
try {
const registrations = await navigator.serviceWorker.getRegistrations();
const hasPushAlertsSW = registrations.some(r => r.active?.scriptURL.includes('sw.js'));
console.log('[usePushNotifications] Service Worker status:', {
registered: registrations.length > 0,
hasPushAlertsSW
});
setSwReady(registrations.length > 0);
} catch (swError) {
console.warn('[usePushNotifications] Service Worker check failed:', swError);
}
}
}
} catch (initError) {
console.error('[usePushNotifications] Initialization error:', initError);
setError('Failed to initialize notifications');
}
};

const requestPermission = async () => {
if (!isSupported) return false;
initializeNotifications();
}, []);

try {
const fcmToken = await requestNotificationPermission();
if (fcmToken) {
setPermission('granted');
await registerToken(fcmToken);
return true;
}
return false;
} catch (error) {
console.error('Error requesting notification permission:', error);
const registerSubscriberId = useCallback(async (subscriberId: string) => {
const authToken = getToken();
if (!authToken) {
console.warn('[usePushNotifications] No auth token available');
return false;
}
};

const registerToken = async (fcmToken: string) => {
const authToken = getToken();
if (!authToken) return;

try {
await axios.put(
`${process.env.NEXT_PUBLIC_API_URL}/fcm/token`,
{ fcmToken },
console.log('[usePushNotifications] Registering PushAlerts subscriber ID...');
const response = await axios.put(
`${process.env.NEXT_PUBLIC_API_URL}/fcm/subscriber`,
{ subscriberId },
{
headers: {
Authorization: `Bearer ${authToken}`,
},
}
);
console.log('[usePushNotifications] PushAlerts subscriber ID registered successfully');
return true;
} catch (error) {
console.error('[usePushNotifications] Error registering PushAlerts subscriber ID:', error);
setError('Failed to register device for notifications');
return false;
}
}, [getToken]);

const requestPermission = useCallback(async () => {
if (!isSupported) {
setError('Notifications not supported on this browser');
return false;
}

setLoading(true);
setError(null);

try {
console.log('[usePushNotifications] Initializing PushAlerts and requesting permission...');
await initializePushAlerts();
const subscriberId = await requestNotificationPermission();
if (subscriberId) {
console.log('[usePushNotifications] Permission granted, registering subscriber...');
setPermission('granted');
const registered = await registerSubscriberId(subscriberId);
setLoading(false);
return registered;
}
console.warn('[usePushNotifications] No PushAlerts subscriber ID obtained');
setPermission(Notification.permission);
setLoading(false);
return false;
} catch (error) {
console.error('Error registering FCM token:', error);
console.error('[usePushNotifications] Error requesting notification permission:', error);
setError('Failed to request notification permission');
setLoading(false);
return false;
}
};
}, [isSupported, registerSubscriberId]);

const unregisterToken = async () => {
const unregisterSubscriber = useCallback(async () => {
const authToken = getToken();
if (!authToken) return;
if (!authToken) return false;

try {
await axios.delete(`${process.env.NEXT_PUBLIC_API_URL}/fcm/token`, {
await axios.delete(`${process.env.NEXT_PUBLIC_API_URL}/fcm/subscriber`, {
headers: {
Authorization: `Bearer ${authToken}`,
},
});
console.log('[usePushNotifications] PushAlerts subscriber unregistered');
return true;
} catch (error) {
console.error('Error unregistering FCM token:', error);
console.error('[usePushNotifications] Error unregistering PushAlerts subscriber:', error);
return false;
}
};
}, [getToken]);

// Listen for foreground messages
useEffect(() => {
if (permission === 'granted') {
if (permission === 'granted' && swReady) {
console.log('[usePushNotifications] Setting up foreground message listener...');

const unsubscribe = onMessageListener().then((payload: any) => {
console.log('Foreground message received:', payload);
console.log('[usePushNotifications] Foreground message received:', {
title: payload.notification?.title,
body: payload.notification?.body
});

if (payload.notification) {
new Notification(payload.notification.title, {
body: payload.notification.body,
icon: '/icon-192x192.png',
});
// Show notification even when app is in foreground
try {
new Notification(payload.notification.title, {
body: payload.notification.body,
icon: '/icon-192x192.png',
data: payload.data
});
} catch (notifErr: any) {
console.error('[usePushNotifications] Error showing foreground notification:', notifErr);
}
}
}).catch((err: any) => {
console.error('[usePushNotifications] Foreground listener error:', err);
});

return () => {
unsubscribe.catch(console.error);
unsubscribe?.catch(console.error);
};
}
}, [permission]);
}, [permission, swReady]);

return {
isSupported,
permission,
loading,
error,
swReady,
requestPermission,
unregisterToken,
unregisterSubscriber,
};
}
46 changes: 0 additions & 46 deletions lib/firebase.ts

This file was deleted.

Loading