335 lines
11 KiB
JavaScript
335 lines
11 KiB
JavaScript
// Load Firebase SDK immediately
|
|
const script1 = document.createElement('script');
|
|
script1.src = 'https://www.gstatic.com/firebasejs/10.7.1/firebase-app-compat.js';
|
|
script1.onload = () => {
|
|
const script2 = document.createElement('script');
|
|
script2.src = 'https://www.gstatic.com/firebasejs/10.7.1/firebase-messaging-compat.js';
|
|
script2.onload = () => {
|
|
// Initialize Firebase immediately
|
|
initializeFirebase();
|
|
console.log('Firebase SDK and initialization complete');
|
|
|
|
// Now that Firebase is ready, set up the app
|
|
setupApp();
|
|
};
|
|
document.head.appendChild(script2);
|
|
};
|
|
document.head.appendChild(script1);
|
|
|
|
// Global variables
|
|
let currentUser = null;
|
|
let fcmToken = null;
|
|
let messaging = null;
|
|
let swRegistration = null;
|
|
let initPromise = null;
|
|
let foregroundHandlerSetup = false;
|
|
|
|
const VAPID_KEY = 'BE6hPKkbf-h0lUQ1tYo249pBOdZFFcWQn9suwg3NDwSE8C_hv8hk1dUY9zxHBQEChO_IAqyFZplF_SUb5c4Ofrw';
|
|
|
|
// Simple user authentication
|
|
const users = {
|
|
'pwau1': { password: 'test123', name: 'Desktop User' },
|
|
'pwau2': { password: 'test123', name: 'Mobile User 1' },
|
|
'pwau3': { password: 'test123', name: 'Mobile User 2' }
|
|
};
|
|
|
|
// Initialize Firebase — returns a promise that resolves when messaging is ready
|
|
function initializeFirebase() {
|
|
if (initPromise) return initPromise;
|
|
|
|
const firebaseConfig = {
|
|
apiKey: "AIzaSyAw1v4COZ68Po8CuwVKrQq0ygf7zFd2QCA",
|
|
authDomain: "fcmtest-push.firebaseapp.com",
|
|
projectId: "fcmtest-push",
|
|
storageBucket: "fcmtest-push.firebasestorage.app",
|
|
messagingSenderId: "439263996034",
|
|
appId: "1:439263996034:web:9b3d52af2c402e65fdec9b"
|
|
};
|
|
|
|
if (firebase.apps.length === 0) {
|
|
firebase.initializeApp(firebaseConfig);
|
|
console.log('Firebase app initialized');
|
|
}
|
|
|
|
initPromise = navigator.serviceWorker.register('/sw.js')
|
|
.then((registration) => {
|
|
console.log('Service Worker registered:', registration);
|
|
swRegistration = registration;
|
|
messaging = firebase.messaging();
|
|
console.log('Firebase messaging initialized successfully');
|
|
})
|
|
.catch((error) => {
|
|
console.error('Service Worker registration failed:', error);
|
|
initPromise = null;
|
|
throw error;
|
|
});
|
|
|
|
return initPromise;
|
|
}
|
|
|
|
// Show user info panel and hide login form
|
|
function showUserInfo() {
|
|
document.getElementById('loginForm').style.display = 'none';
|
|
document.getElementById('userInfo').style.display = 'block';
|
|
document.getElementById('currentUser').textContent = users[currentUser]?.name || currentUser;
|
|
}
|
|
|
|
// Setup app after Firebase is ready
|
|
function setupApp() {
|
|
// Set up event listeners
|
|
document.getElementById('loginForm').addEventListener('submit', login);
|
|
document.getElementById('sendNotificationBtn').addEventListener('click', sendNotification);
|
|
document.getElementById('logoutBtn').addEventListener('click', logout);
|
|
|
|
// Restore session and re-register FCM token if notifications were already granted
|
|
const savedUser = localStorage.getItem('currentUser');
|
|
if (savedUser) {
|
|
currentUser = savedUser;
|
|
showUserInfo();
|
|
if (Notification.permission === 'granted') {
|
|
initializeFirebase()
|
|
.then(() => messaging.getToken({ vapidKey: VAPID_KEY, serviceWorkerRegistration: swRegistration }))
|
|
.then(token => { if (token) return registerToken(currentUser, token); })
|
|
.catch(err => console.error('Token refresh on session restore failed:', err));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Request notification permission and get FCM token
|
|
async function requestNotificationPermission() {
|
|
try {
|
|
console.log('Requesting notification permission...');
|
|
const permission = await Notification.requestPermission();
|
|
console.log('Permission result:', permission);
|
|
|
|
if (permission === 'granted') {
|
|
console.log('Notification permission granted.');
|
|
showStatus('Getting FCM token...', 'info');
|
|
|
|
try {
|
|
const token = await messaging.getToken({ vapidKey: VAPID_KEY, serviceWorkerRegistration: swRegistration });
|
|
console.log('FCM Token generated:', token);
|
|
|
|
if (!token) {
|
|
throw new Error('getToken() returned empty — check VAPID key and service worker');
|
|
}
|
|
|
|
fcmToken = token;
|
|
|
|
// Send token to server
|
|
await registerToken(currentUser, token);
|
|
showStatus('Notifications enabled successfully!', 'success');
|
|
} catch (tokenError) {
|
|
console.error('Error getting FCM token:', tokenError);
|
|
showStatus('Failed to get FCM token: ' + tokenError.message, 'error');
|
|
}
|
|
} else {
|
|
console.log('Notification permission denied.');
|
|
showStatus('Notification permission denied.', 'error');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error requesting notification permission:', error);
|
|
showStatus('Failed to enable notifications: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
// Register FCM token with server
|
|
async function registerToken(username, token) {
|
|
try {
|
|
console.log('Attempting to register token:', { username, token: token.substring(0, 20) + '...' });
|
|
|
|
const response = await fetch('/register-token', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ username, token })
|
|
});
|
|
|
|
console.log('Registration response status:', response.status);
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
throw new Error(`Server returned ${response.status}: ${errorText}`);
|
|
}
|
|
|
|
const result = await response.json();
|
|
console.log('Token registered successfully:', result);
|
|
showStatus(`Token registered for ${username}`, 'success');
|
|
} catch (error) {
|
|
console.error('Error registering token:', error);
|
|
showStatus('Failed to register token with server: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
// Handle foreground messages (guard against duplicate registration)
|
|
function handleForegroundMessages() {
|
|
if (foregroundHandlerSetup) return;
|
|
foregroundHandlerSetup = true;
|
|
messaging.onMessage(function(payload) {
|
|
console.log('Received foreground message: ', payload);
|
|
|
|
// Show notification in foreground
|
|
const notificationTitle = payload.notification.title;
|
|
const notificationOptions = {
|
|
body: payload.notification.body,
|
|
icon: '/icon-192.png',
|
|
badge: '/icon-192.png'
|
|
};
|
|
|
|
new Notification(notificationTitle, notificationOptions);
|
|
showStatus(`New notification: ${payload.notification.body}`, 'info');
|
|
});
|
|
}
|
|
|
|
// Login function
|
|
async function login(event) {
|
|
if (event) event.preventDefault();
|
|
|
|
const username = document.getElementById('username').value;
|
|
const password = document.getElementById('password').value;
|
|
|
|
if (!users[username] || users[username].password !== password) {
|
|
showStatus('Invalid username or password', 'error');
|
|
return;
|
|
}
|
|
|
|
currentUser = username;
|
|
localStorage.setItem('currentUser', username);
|
|
showUserInfo();
|
|
|
|
showStatus(`Logged in as ${users[username].name}`, 'success');
|
|
|
|
// Initialize Firebase and request notifications
|
|
if (typeof firebase !== 'undefined') {
|
|
await initializeFirebase();
|
|
await requestNotificationPermission();
|
|
handleForegroundMessages();
|
|
} else {
|
|
showStatus('Firebase not loaded. Please check your connection.', 'error');
|
|
}
|
|
}
|
|
|
|
// Logout function
|
|
function logout() {
|
|
currentUser = null;
|
|
fcmToken = null;
|
|
localStorage.removeItem('currentUser');
|
|
document.getElementById('loginForm').style.display = 'block';
|
|
document.getElementById('userInfo').style.display = 'none';
|
|
document.getElementById('username').value = '';
|
|
document.getElementById('password').value = '';
|
|
showStatus('Logged out successfully.', 'info');
|
|
}
|
|
|
|
// Send notification function
|
|
async function sendNotification() {
|
|
if (!currentUser) {
|
|
showStatus('Please login first.', 'error');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// First check registered users
|
|
const usersResponse = await fetch('/users');
|
|
const users = await usersResponse.json();
|
|
console.log('Registered users:', users);
|
|
|
|
const response = await fetch('/send-notification', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
fromUser: currentUser,
|
|
title: 'Test Notification',
|
|
body: `Notification sent from ${currentUser} at ${new Date().toLocaleTimeString()}`
|
|
})
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to send notification');
|
|
}
|
|
|
|
const result = await response.json();
|
|
console.log('Send result:', result);
|
|
|
|
if (result.recipients === 0) {
|
|
showStatus('No other users have registered tokens. Open the app on other devices and enable notifications.', 'error');
|
|
} else {
|
|
showStatus(`Notification sent to ${result.recipients} user(s)!`, 'success');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error sending notification:', error);
|
|
showStatus('Failed to send notification.', 'error');
|
|
}
|
|
}
|
|
|
|
// Show status message
|
|
function showStatus(message, type) {
|
|
const statusEl = document.getElementById('status');
|
|
statusEl.textContent = message;
|
|
statusEl.className = `status ${type}`;
|
|
statusEl.style.display = 'block';
|
|
|
|
setTimeout(() => {
|
|
statusEl.style.display = 'none';
|
|
}, 5000);
|
|
}
|
|
|
|
// Register service worker and handle PWA installation
|
|
if ('serviceWorker' in navigator) {
|
|
window.addEventListener('load', function() {
|
|
navigator.serviceWorker.register('/sw.js')
|
|
.then(function(registration) {
|
|
console.log('ServiceWorker registration successful with scope: ', registration.scope);
|
|
|
|
// Handle PWA installation
|
|
let deferredPrompt;
|
|
|
|
window.addEventListener('beforeinstallprompt', (e) => {
|
|
console.log('beforeinstallprompt fired');
|
|
e.preventDefault();
|
|
deferredPrompt = e;
|
|
|
|
// Show install button or banner
|
|
showInstallButton();
|
|
});
|
|
|
|
function showInstallButton() {
|
|
const installBtn = document.createElement('button');
|
|
installBtn.textContent = 'Install App';
|
|
installBtn.style.cssText = `
|
|
position: fixed;
|
|
bottom: 20px;
|
|
right: 20px;
|
|
background: #2196F3;
|
|
color: white;
|
|
border: none;
|
|
padding: 12px 20px;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
z-index: 1000;
|
|
font-size: 14px;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
`;
|
|
|
|
installBtn.addEventListener('click', async () => {
|
|
if (deferredPrompt) {
|
|
deferredPrompt.prompt();
|
|
const { outcome } = await deferredPrompt.userChoice;
|
|
console.log(`User response to the install prompt: ${outcome}`);
|
|
deferredPrompt = null;
|
|
installBtn.remove();
|
|
}
|
|
});
|
|
|
|
document.body.appendChild(installBtn);
|
|
}
|
|
})
|
|
.catch(function(error) {
|
|
console.log('ServiceWorker registration failed: ', error);
|
|
});
|
|
});
|
|
}
|