// Utility functions export function escapeHtml(text) { if (text === null || text === undefined) { return ''; } const div = document.createElement('div'); div.textContent = String(text); return div.innerHTML; } export function parseGeoLocation(value) { if (!value) return null; // Try semicolon separator first let parts = value.split(';'); if (parts.length !== 2) { // Try comma separator parts = value.split(','); } if (parts.length === 2) { const lat = parseFloat(parts[0].trim()); const lng = parseFloat(parts[1].trim()); if (!isNaN(lat) && !isNaN(lng)) { return { lat, lng }; } } return null; } export function showStatus(message, type = 'info') { const container = document.getElementById('status-container'); const messageDiv = document.createElement('div'); messageDiv.className = `status-message ${type}`; messageDiv.textContent = message; container.appendChild(messageDiv); // Auto-remove after 5 seconds setTimeout(() => { messageDiv.remove(); }, 5000); } export function hideLoading() { const loading = document.getElementById('loading'); if (loading) { loading.classList.add('hidden'); } } export function updateLoadingMessage(message) { const loadingElement = document.querySelector('#loading p'); if (loadingElement) { loadingElement.textContent = message; } } export function updateLocationCount(count) { const countElement = document.getElementById('location-count'); const mobileCountElement = document.getElementById('mobile-location-count'); const countText = `${count} location${count !== 1 ? 's' : ''}`; if (countElement) { countElement.textContent = countText; } if (mobileCountElement) { mobileCountElement.textContent = countText; } } /** * Sets a CSS custom property `--app-height` to the window's inner height. * This helps create a reliable "full height" value across all browsers, * especially on mobile where `100vh` can be inconsistent. */ export function setAppHeight() { const doc = document.documentElement; doc.style.setProperty('--app-height', `${window.innerHeight}px`); } /** * Sets viewport dimensions and handles safe area insets for better mobile support * Also detects if we're on a scrollable page and adjusts accordingly */ export function setViewportDimensions() { const doc = document.documentElement; // Set height doc.style.setProperty('--app-height', `${window.innerHeight}px`); // Set width (useful for avoiding overflow issues) doc.style.setProperty('--app-width', `${window.innerWidth}px`); // Handle safe area insets for devices with notches or home indicators if (CSS.supports('padding: env(safe-area-inset-top)')) { doc.style.setProperty('--safe-area-top', 'env(safe-area-inset-top)'); doc.style.setProperty('--safe-area-bottom', 'env(safe-area-inset-bottom)'); doc.style.setProperty('--safe-area-left', 'env(safe-area-inset-left)'); doc.style.setProperty('--safe-area-right', 'env(safe-area-inset-right)'); } else { doc.style.setProperty('--safe-area-top', '0px'); doc.style.setProperty('--safe-area-bottom', '0px'); doc.style.setProperty('--safe-area-left', '0px'); doc.style.setProperty('--safe-area-right', '0px'); } // For pages that need scrolling (like shifts, user), don't restrict height const isScrollablePage = window.location.pathname.includes('shifts') || window.location.pathname.includes('user') || window.location.pathname.includes('admin'); if (isScrollablePage) { // Allow the body and app to grow beyond viewport height document.body.style.height = 'auto'; document.body.style.minHeight = `${window.innerHeight}px`; const app = document.getElementById('app'); if (app) { app.style.height = 'auto'; app.style.minHeight = `${window.innerHeight}px`; } } }