fix: hide close-week button when a tracked day is still open

Fetch entries for the week alongside days/weeks in the week view.
canCloseWeek now mirrors the server rule: every past workday that
has at least one entry must have a closed_days record. Days with
no entries are still skipped (they count as 0h implicitly).
This commit is contained in:
2026-04-30 18:10:44 +02:00
parent 563784d5fb
commit 3fd1455704

View File

@@ -1,14 +1,15 @@
<script lang="ts">
import { onMount } from 'svelte';
import { days, weeks, settings, type ClosedDay, type ClosedWeek, type Settings, ApiError } from '$lib/api/client';
import { entries, days, weeks, settings, type Entry, type ClosedDay, type ClosedWeek, type Settings, ApiError } from '$lib/api/client';
import {
currentWeekKey, weekDayKeys, formatDurationShort, formatDelta, todayKey, isWorkday
} from '$lib/utils';
let weekKey = $state(currentWeekKey());
let dayKeys = $derived(weekDayKeys(weekKey));
let closedDaysMap: Record<string, ClosedDay> = $state({});
let closedWeek: ClosedWeek | null = $state(null);
let closedDaysMap = $state<Record<string, ClosedDay>>({});
let daysWithEntries = $state<Set<string>>(new Set());
let closedWeek = $state<ClosedWeek | null>(null);
let currentSettings = $state<Settings | null>(null);
let error = $state('');
@@ -17,14 +18,19 @@
const from = dayKeys[0];
const to = dayKeys[6];
try {
const [ds, ws, s] = await Promise.all([
const [ds, ws, s, es] = await Promise.all([
days.list(from, to),
weeks.list(weekKey, weekKey),
settings.current()
settings.current(),
entries.list(from, to)
]);
closedDaysMap = Object.fromEntries((ds ?? []).map((d) => [d.day_key, d]));
closedWeek = (ws ?? []).find((w) => w.week_key === weekKey) ?? null;
currentSettings = s;
// Track which day_keys have at least one entry (for close-week guard).
const set = new Set<string>();
for (const e of (es ?? [])) set.add(e.day_key);
daysWithEntries = set;
} catch (e) {
error = e instanceof ApiError ? e.message : String(e);
}
@@ -61,10 +67,16 @@
currentSettings ? currentSettings.hours_per_week * 3_600_000 : 0
);
// Week can be closed if it's not already closed and the week has started
// (i.e. Monday ≤ today). The server enforces the detailed per-day rules.
// Week can be closed if it's not already closed, the week has started,
// and every past workday that has entries is also closed.
const canCloseWeek = $derived(
!closedWeek && dayKeys[0] <= todayKey()
!closedWeek &&
dayKeys[0] <= todayKey() &&
dayKeys.every((dk) => {
if (dk > todayKey()) return true; // future day — skip
if (!daysWithEntries.has(dk)) return true; // no entries — skip
return !!closedDaysMap[dk]; // has entries → must be closed
})
);
function prevWeek() { weekKey = offsetWeek(weekKey, -1); }