Add goals.js module

This commit is contained in:
Simon Kühn 2026-05-08 11:39:47 +02:00
parent 7f92cc32b7
commit fa68017d49

93
public/js/goals.js Normal file
View file

@ -0,0 +1,93 @@
import { state } from './state.js';
import { ldoc } from './i18n.js';
export function tOff(g) {
return Math.round((state.TODAY - new Date(g.start)) / 86400000);
}
export function o2d(g, i) {
const d = new Date(new Date(g.start).getTime() + i * 86400000);
d.setHours(0,0,0,0);
return d;
}
export function dTot(g, o) {
return (g.sets[String(o)] || []).reduce((a, b) => a + b.amount, 0);
}
export function fd(d) {
return d.toLocaleDateString(ldoc(), { weekday: 'short', day: 'numeric', month: 'short' });
}
export function fs(d) {
return d.toLocaleDateString(ldoc(), { day: 'numeric', month: 'short' });
}
export function editable(g, o) {
const t = tOff(g);
return o === t || o === t - 1;
}
export function now() {
const n = new Date();
return String(n.getHours()).padStart(2, '0') + ':' + String(n.getMinutes()).padStart(2, '0');
}
export function heuteColor(tdone, daily) {
if (tdone === 0) return 'var(--red)';
if (tdone >= daily * 1.1) return 'var(--blue)';
if (tdone >= daily) return 'var(--green)';
return 'var(--amber)';
}
export function isCollapsed(id) {
return state.collapsed[id] !== false;
}
export function toggleCollapse(id) {
const wasCollapsed = isCollapsed(id);
state.collapsed[id] = !wasCollapsed;
if (wasCollapsed) {
const g = state.goals.find(x => x.id === id);
if (g) state.selDay[id] = tOff(g);
}
}
export function calc(g) {
const t = tOff(g), tot = g.daily * g.days;
const dr = Math.max(0, g.days - t - 1);
const sd = new Date(g.start); sd.setHours(0,0,0,0);
const end = new Date(sd.getTime() + g.days * 86400000);
let past = 0;
for (let i = 0; i < Math.min(t, g.days); i++) past += dTot(g, i);
const tdone = dTot(g, t), tot2 = past + tdone;
const dl = dr + 1;
const remaining = Math.max(0, tot - past);
const pd = Math.ceil(remaining / Math.max(1, dl));
const st = Math.max(0, pd - tdone);
const expectedPast = Math.min(t, g.days) * g.daily;
const buf = Math.floor((past - expectedPast) + Math.max(0, tdone - g.daily));
const deficit = Math.min(0, buf);
const surplus = Math.max(0, buf);
const dailyDelta = pd - g.daily;
const pct = Math.min(100, Math.round((tot2 / tot) * 100));
return { tot, tOff: t, end, dr, done: tot2, tdone, pd, st, buf, deficit, surplus, dailyDelta, net: tdone - pd, pct, ok: tdone >= pd };
}
export function dcls(g, i) {
const t = tOff(g);
if (i > t) return 'dot df';
const v = dTot(g, i);
const c = v === 0 ? 'dot dm' : v >= g.daily * 1.1 ? 'dot db' : v >= g.daily ? 'dot dd' : 'dot dp';
return c + (editable(g, i) ? ' de' : ' dl');
}
export function dlbl(g, i) {
const t = tOff(g);
if (i > t) return String(i + 1);
const v = dTot(g, i);
if (v === 0) return '✕';
if (v >= g.daily * 1.1) return '+';
if (v >= g.daily) return '✓';
return Math.round(v / g.daily * 100) + '%';
}