Initial commit

This commit is contained in:
iulian 2025-12-26 00:52:56 +00:00
commit 983cee0320
322 changed files with 57174 additions and 0 deletions

View file

@ -0,0 +1,187 @@
// PWA Service Worker Registration
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/static/js/service-worker.js')
.then(registration => {
console.log('[PWA] Service Worker registered successfully:', registration.scope);
// Check for updates
registration.addEventListener('updatefound', () => {
const newWorker = registration.installing;
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
console.log('[PWA] New version available! Refresh to update.');
// Optionally show a notification to the user
if (confirm('A new version of FINA is available. Reload to update?')) {
newWorker.postMessage({ type: 'SKIP_WAITING' });
window.location.reload();
}
}
});
});
})
.catch(error => {
console.log('[PWA] Service Worker registration failed:', error);
});
});
}
// PWA Install Prompt
let deferredPrompt;
const installPrompt = document.getElementById('pwa-install-prompt');
const installBtn = document.getElementById('pwa-install-btn');
const dismissBtn = document.getElementById('pwa-dismiss-btn');
// Check if already installed (standalone mode)
const isInstalled = () => {
return window.matchMedia('(display-mode: standalone)').matches ||
window.navigator.standalone === true ||
document.referrer.includes('android-app://');
};
// Detect iOS
const isIOS = () => {
return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
};
// Show iOS install instructions
function showIOSInstallPrompt() {
if (installPrompt) {
const promptText = installPrompt.querySelector('.pwa-prompt-text p');
if (promptText && isIOS() && !window.navigator.standalone) {
promptText.textContent = 'Tap Share button and then "Add to Home Screen"';
installBtn.style.display = 'none'; // Hide install button on iOS
}
}
}
window.addEventListener('beforeinstallprompt', (e) => {
// Prevent the default mini-infobar
e.preventDefault();
// Store the event for later use
deferredPrompt = e;
// Don't show if already installed
if (isInstalled()) {
return;
}
// Show custom install prompt if not dismissed
const dismissed = localStorage.getItem('pwa-install-dismissed');
const dismissedUntil = parseInt(dismissed || '0');
if (Date.now() > dismissedUntil && installPrompt) {
installPrompt.style.display = 'block';
}
});
// Handle iOS separately
if (isIOS() && !isInstalled()) {
const dismissed = localStorage.getItem('pwa-install-dismissed');
const dismissedUntil = parseInt(dismissed || '0');
if (Date.now() > dismissedUntil && installPrompt) {
setTimeout(() => {
installPrompt.style.display = 'block';
showIOSInstallPrompt();
}, 2000); // Show after 2 seconds
}
}
if (installBtn) {
installBtn.addEventListener('click', async () => {
if (!deferredPrompt) {
return;
}
// Show the install prompt
deferredPrompt.prompt();
// Wait for the user's response
const { outcome } = await deferredPrompt.userChoice;
console.log(`[PWA] User response: ${outcome}`);
// Clear the saved prompt since it can't be used again
deferredPrompt = null;
// Hide the prompt
installPrompt.style.display = 'none';
});
}
if (dismissBtn) {
dismissBtn.addEventListener('click', () => {
installPrompt.style.display = 'none';
// Remember dismissal for 7 days
localStorage.setItem('pwa-install-dismissed', Date.now() + (7 * 24 * 60 * 60 * 1000));
});
}
// Check if app is installed
window.addEventListener('appinstalled', () => {
console.log('[PWA] App installed successfully');
if (installPrompt) {
installPrompt.style.display = 'none';
}
localStorage.removeItem('pwa-install-dismissed');
});
// Online/Offline status
window.addEventListener('online', () => {
console.log('[PWA] Back online');
// Show notification or update UI
showToast('Connection restored', 'success');
});
window.addEventListener('offline', () => {
console.log('[PWA] Gone offline');
showToast('You are offline. Some features may be limited.', 'info');
});
// Toast notification function
function showToast(message, type = 'info') {
const toast = document.createElement('div');
toast.className = `alert alert-${type} glass-card`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => {
toast.classList.add('hiding');
setTimeout(() => toast.remove(), 300);
}, 3000);
}
// Language menu toggle
function toggleLanguageMenu() {
const menu = document.getElementById('language-menu');
menu.classList.toggle('show');
}
// Close language menu when clicking outside
document.addEventListener('click', function(event) {
const switcher = document.querySelector('.language-switcher');
const menu = document.getElementById('language-menu');
if (menu && switcher && !switcher.contains(event.target)) {
menu.classList.remove('show');
}
});
document.addEventListener('DOMContentLoaded', function() {
console.log('Finance Tracker loaded');
// Auto-hide flash messages after 2 seconds
const alerts = document.querySelectorAll('.alert');
alerts.forEach(function(alert) {
// Add hiding animation after 2 seconds
setTimeout(function() {
alert.classList.add('hiding');
// Remove from DOM after animation completes
setTimeout(function() {
alert.remove();
}, 300); // Wait for animation to finish
}, 2000); // Show for 2 seconds
});
});