cf64a2dc50
- EPA Agility & Speed: add Max Speed and Max Weighted Speed (mph), decimal record-tracked metrics, per session. - Logged sessions are editable: tapping a category or a logged entry opens it pre-filled; saving updates that entry (PUT /api/entries/:id) instead of creating a duplicate. Record auto-update runs on edit too. - Every value field is now a tap-to-type number input (decimal keypad for speeds) while keeping the +/- stepper buttons; native spinners removed. New decimal metric kind; seed + idempotent migration add the EPA speed metrics. - Bump StartOS package to 0.1.5:0; service worker cache to v5.
49 lines
2.0 KiB
JavaScript
49 lines
2.0 KiB
JavaScript
// Thin fetch wrapper. Redirects to login on 401.
|
|
async function req(method, url, body) {
|
|
const opts = { method, headers: {} };
|
|
if (body !== undefined) {
|
|
opts.headers['Content-Type'] = 'application/json';
|
|
opts.body = JSON.stringify(body);
|
|
}
|
|
const res = await fetch(url, opts);
|
|
if (res.status === 401 && !url.endsWith('/api/login')) {
|
|
location.href = '/login.html';
|
|
throw new Error('Not authenticated');
|
|
}
|
|
const data = res.headers.get('content-type')?.includes('application/json')
|
|
? await res.json() : null;
|
|
if (!res.ok) throw new Error((data && data.error) || `Request failed (${res.status})`);
|
|
return data;
|
|
}
|
|
|
|
export const api = {
|
|
login: (password) => req('POST', '/api/login', { password }),
|
|
logout: () => req('POST', '/api/logout'),
|
|
me: () => req('GET', '/api/me'),
|
|
setPassword: (current, next) => req('POST', '/api/password', { current, next }),
|
|
|
|
categories: (all = false) => req('GET', `/api/categories${all ? '?all=1' : ''}`),
|
|
addCategory: (c) => req('POST', '/api/categories', c),
|
|
updateCategory: (id, c) => req('PUT', `/api/categories/${id}`, c),
|
|
addMetric: (catId, m) => req('POST', `/api/categories/${catId}/metrics`, m),
|
|
updateMetric: (id, m) => req('PUT', `/api/metrics/${id}`, m),
|
|
deleteMetric: (id) => req('DELETE', `/api/metrics/${id}`),
|
|
|
|
day: (day) => req('GET', `/api/day/${day}`),
|
|
logEntry: (e) => req('POST', '/api/entries', e),
|
|
updateEntry: (id, e) => req('PUT', `/api/entries/${id}`, e),
|
|
deleteEntry: (id) => req('DELETE', `/api/entries/${id}`),
|
|
saveNotes: (day, notes) => req('PUT', `/api/day/${day}/notes`, { notes }),
|
|
|
|
plans: (from, to) => req('GET', `/api/plans?from=${from}&to=${to}`),
|
|
addPlan: (p) => req('POST', '/api/plans', p),
|
|
deletePlan: (id) => req('DELETE', `/api/plans/${id}`),
|
|
|
|
goals: () => req('GET', '/api/goals'),
|
|
addGoal: (g) => req('POST', '/api/goals', g),
|
|
updateGoal: (id, g) => req('PUT', `/api/goals/${id}`, g),
|
|
deleteGoal: (id) => req('DELETE', `/api/goals/${id}`),
|
|
|
|
stats: () => req('GET', '/api/stats'),
|
|
};
|