Multiple minor changes and improvements

This commit is contained in:
2026-10-08 21:14:54 +02:00
parent 163424f6f1
commit 5cf19bb8ac
30 changed files with 500 additions and 174 deletions

View File

@@ -24,13 +24,13 @@ import { DAY, HOUR, localDateKey } from './time.js';
/**
* One stretch of the day. `endTs === null` marks the single running entry; every
* other entry's `endTs` equals the next entry's `startTs`.
* other entry has a finite end; imported histories may contain gaps.
*
* @typedef {object} EntryRecord
* @property {number} [id]
* @property {string} date
* @property {number} seq position within the day, dense from 0
* @property {'travel'|'work'|'lunch'} kind
* @property {'travel'|'work'|'lunch'|'break'} kind
* @property {string} task
* @property {string|null} client
* @property {number} startTs
@@ -120,15 +120,30 @@ export function closeDay(date, ts, stale = false) {
});
}
/** Undo a premature close; no new entry or unaccounted interval is introduced. */
export function reopenDay(date, now) {
/** Confirmed same-day reopening; status and all resumed slots commit together. */
export function reopenDay(date, now, mode = 'continue') {
return db.transaction('rw', db.days, db.entries, async () => {
const day = await getDay(date);
if (!day || day.status !== 'closed' || await getActiveDay()) return false;
if (!['continue', 'break'].includes(mode)) throw new Error('Choix de reprise invalide.');
if (!day || date !== localDateKey(now) || day.status !== 'closed' || await getActiveDay()) return false;
const entries = await getEntries(date);
const last = entries.at(-1);
if (!last) return false;
await db.entries.update(last.id, { endTs: null });
const boundary = day.endedTs;
if (!Number.isFinite(boundary) || now < boundary) return false;
if (mode === 'continue' && ['work', 'travel'].includes(last.kind)) {
await db.entries.update(last.id, { endTs: null, automatic: false });
} else {
let seq = last.seq + 1;
if (now > boundary) {
if (mode === 'continue') await db.entries.update(last.id, { endTs: now, automatic: false });
else await db.entries.add({ date, seq: seq++, kind: 'break', task: 'Pause', client: null, startTs: boundary, endTs: now });
}
const history = await db.entries.toArray();
const work = history.filter((e) => e.kind === 'work' && e.date <= date)
.sort((a, b) => b.date.localeCompare(a.date) || b.seq - a.seq)[0];
await db.entries.add({ date, seq, kind: 'work', task: work?.task || 'Travaux sur site', client: work?.client ?? null, startTs: now, endTs: null });
}
await patchDay(date, {
status: 'active', endedTs: null, closePromptedTs: null,
plannedEndTs: Math.max(day.plannedEndTs, now + HOUR),
@@ -230,13 +245,13 @@ export function setEntryStart(id, ts, now = Date.now()) {
const list = await db.entries.where('date').equals(entry.date).sortBy('seq');
const prev = list[list.findIndex((e) => e.id === id) - 1];
const lower = prev ? prev.startTs : Number.NEGATIVE_INFINITY;
const lower = prev ? (prev.endTs === entry.startTs ? prev.startTs : prev.endTs) : Number.NEGATIVE_INFINITY;
const upper = entry.endTs ?? now;
const stored = Math.min(Math.max(ts, lower), upper);
await db.entries.update(entry.id, { startTs: stored, ...(entry.automatic ? { automatic: false } : {}) });
if (prev) await db.entries.update(prev.id, { endTs: stored, ...(prev.automatic ? { automatic: false } : {}) });
else await db.days.update(entry.date, { startedTs: stored });
if (prev && prev.endTs === entry.startTs) await db.entries.update(prev.id, { endTs: stored, ...(prev.automatic ? { automatic: false } : {}) });
else if (!prev) await db.days.update(entry.date, { startedTs: stored });
return stored;
});
@@ -257,11 +272,11 @@ export function deleteEntry(id) {
const next = list[i + 1];
await db.entries.delete(id);
if (prev) {
if (prev && prev.endTs === victim.startTs && (!next || victim.endTs === next.startTs)) {
// Extend the previous entry over the hole; if nothing follows, it inherits
// the victim's end (including `null`, i.e. it becomes the running entry).
await db.entries.update(prev.id, { endTs: next ? next.startTs : victim.endTs });
} else if (next) {
} else if (!prev && next && victim.endTs === next.startTs) {
await db.entries.update(next.id, { startTs: victim.startTs });
}
// Re-number so `seq` stays dense.