// api.js — shared fetch helpers and utilities used by every page const API = { async _fetch(url, options = {}) { const token = localStorage.getItem('token'); const headers = { 'Content-Type': 'application/json' }; if (token) headers['Authorization'] = `Bearer ${token}`; const res = await fetch(url, { headers, ...options, }); if (res.status === 401) { localStorage.removeItem('token'); window.location.href = '/login'; return; } if (!res.ok) { const err = await res.json().catch(() => ({ detail: res.statusText })); throw new Error(err.detail || `Request failed (${res.status})`); } if (res.status === 204) return null; // DELETE returns No Content return res.json(); }, get: (url) => API._fetch(url), post: (url, data) => API._fetch(url, { method: 'POST', body: JSON.stringify(data) }), put: (url, data) => API._fetch(url, { method: 'PUT', body: JSON.stringify(data) }), del: (url) => API._fetch(url, { method: 'DELETE' }), }; // Show a timed success or error message inside a .message element function showMessage(el, text, type = 'success') { el.textContent = text; el.className = `message ${type} visible`; setTimeout(() => { el.className = 'message'; }, 4000); } // Set an input[type=date] to today's date in the user's configured timezone function setToday(inputEl) { const tz = (typeof Auth !== 'undefined' && Auth.getUser()?.timezone) || Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC'; // en-CA locale produces YYYY-MM-DD which is what date inputs expect inputEl.value = new Date().toLocaleDateString('en-CA', { timeZone: tz }); } // Format YYYY-MM-DD → MM/DD/YYYY for display function fmtDate(str) { if (!str) return '—'; const [y, m, d] = str.split('-'); return `${m}/${d}/${y}`; } // Format a number as a dollar amount function fmtMoney(val) { if (val == null || val === '' || isNaN(Number(val))) return '—'; return '$' + Number(val).toFixed(2); } // Format a small decimal (cost per egg) with 4 decimal places function fmtMoneyFull(val) { if (val == null || val === '' || isNaN(Number(val))) return '—'; return '$' + Number(val).toFixed(4); } // Highlight the nav link that matches the current page function highlightNav() { const path = window.location.pathname.replace(/\.html$/, '').replace(/\/$/, '') || '/'; document.querySelectorAll('.nav-links a').forEach(a => { const href = a.getAttribute('href').replace(/\/$/, '') || '/'; if (href === path) a.classList.add('active'); }); } document.addEventListener('DOMContentLoaded', highlightNav);