Add goals.js module
This commit is contained in:
parent
7f92cc32b7
commit
fa68017d49
1 changed files with 93 additions and 0 deletions
93
public/js/goals.js
Normal file
93
public/js/goals.js
Normal 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) + '%';
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue