Initial commit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
67
nginx/html/js/api.js
Normal file
67
nginx/html/js/api.js
Normal file
@@ -0,0 +1,67 @@
|
||||
// api.js — shared fetch helpers and utilities used by every page
|
||||
|
||||
const API = {
|
||||
async _fetch(url, options = {}) {
|
||||
const res = await fetch(url, {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
...options,
|
||||
});
|
||||
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 (using local time, not UTC)
|
||||
function setToday(inputEl) {
|
||||
const now = new Date();
|
||||
const y = now.getFullYear();
|
||||
const m = String(now.getMonth() + 1).padStart(2, '0');
|
||||
const d = String(now.getDate()).padStart(2, '0');
|
||||
inputEl.value = `${y}-${m}-${d}`;
|
||||
}
|
||||
|
||||
// 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);
|
||||
Reference in New Issue
Block a user