Implement reliability improvements across frontend

- api.js: add exponential backoff retry (3 attempts, 500/1000/2000ms) for
  GET requests on network errors and 5xx responses; mutating methods are
  not retried since they are not idempotent
- api.js: add offline indicator — fixed pill banner appears at bottom of
  page when navigator goes offline, disappears when back online
- style.css: add styles for offline banner and session expiry warning
- auth.js: show amber warning banner below nav when session expires within
  24 hours (with exact hours remaining); dismissible with X button
- auth.js: fix password min-length client-side check from 6 to 10 to
  match the backend
- log.js, flock.js, budget.js: disable submit button during async request
  and re-enable in finally block to prevent double-submits and make loading
  state visible
- dashboard.js: fix chart date labels to use user's configured timezone
  instead of the browser's local timezone

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-18 00:09:36 -07:00
parent 60fed6d464
commit ce1e9c5134
7 changed files with 122 additions and 17 deletions

View File

@@ -1,7 +1,7 @@
let eggChart = null;
function buildChart(eggs) {
const today = new Date();
const tz = (typeof Auth !== 'undefined' && Auth.getUser()?.timezone) || 'UTC';
const labels = [];
const data = [];
@@ -9,14 +9,12 @@ function buildChart(eggs) {
const eggMap = {};
eggs.forEach(e => { eggMap[e.date] = e.eggs; });
// Generate the last 30 days in chronological order
// Generate the last 30 days in the user's configured timezone
for (let i = 29; i >= 0; i--) {
const d = new Date(today);
const d = new Date();
d.setDate(d.getDate() - i);
const y = d.getFullYear();
const mo = String(d.getMonth() + 1).padStart(2, '0');
const dy = String(d.getDate()).padStart(2, '0');
const dateStr = `${y}-${mo}-${dy}`;
const dateStr = d.toLocaleDateString('en-CA', { timeZone: tz });
const [, mo, dy] = dateStr.split('-');
labels.push(`${mo}/${dy}`);
data.push(eggMap[dateStr] ?? 0);
}