142 lines
4.5 KiB
JavaScript

// 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`;
}
}
}
// Add session expiry detection
function handleAuthError(error) {
if (error.status === 401) {
// Stop all intervals
if (typeof autoRefreshInterval !== 'undefined') {
clearInterval(autoRefreshInterval);
}
// Redirect to login with expiry message
window.location.href = '/login.html?expired=true';
}
}