Anwesenheit auch in "Zeit im Team heute" anzeigen
ci / quality (push) Failing after 30s
ci / build (push) Has been skipped
deploy / deploy (push) Successful in 53s

teamToday liefert pro Person checkedInAt/checkedOutAt aus dem heutigen
day_entry mit; die Team-Karte zeigt daneben "Anwesend: …" (live, bzw.
eingefroren nach Feierabend). Reine Anzeige, kein Eingriff ins Tracking.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Fable 5 committed 2026-06-11 19:28:29 +02:00
1 parent 687325ad0d
commit e0fbc386fa
2 files changed
+41 -7

No files matched your search

+23 -7
View File
@@ -341,14 +341,30 @@ export const timeRouter = router({
perUser.set(r.userId, bucket);
}
// Anwesenheit (Lock-in → Feierabend) pro Person — reine Anzeige neben dem Tracking.
const dayRows = await ctx.db
.select({
userId: dayEntry.userId,
checkedInAt: dayEntry.checkedInAt,
checkedOutAt: dayEntry.checkedOutAt,
})
.from(dayEntry)
.where(eq(dayEntry.date, today));
const presenceByUser = new Map(dayRows.map((d) => [d.userId, d]));
// „Gesamt" pro Person = Wall-Clock (Vereinigung der Intervalle).
return Array.from(perUser.values()).map((b) => ({
userId: b.userId,
totalSeconds: unionSeconds(b.intervals),
trackedSeconds: b.trackedSeconds,
byCategory: b.byCategory,
active: b.active,
}));
return Array.from(perUser.values()).map((b) => {
const p = presenceByUser.get(b.userId);
return {
userId: b.userId,
totalSeconds: unionSeconds(b.intervals),
trackedSeconds: b.trackedSeconds,
byCategory: b.byCategory,
active: b.active,
checkedInAt: p?.checkedInAt ? p.checkedInAt.toISOString() : null,
checkedOutAt: p?.checkedOutAt ? p.checkedOutAt.toISOString() : null,
};
});
}),
/**
@@ -28,6 +28,16 @@ function initials(name: string) {
.join('');
}
/** Anwesenheit (Lock-in → Feierabend bzw. jetzt) — reine Anzeige, kein Tracking. */
function presenceSecondsOf(it: {
checkedInAt: string | null;
checkedOutAt: string | null;
}): number | null {
if (!it.checkedInAt) return null;
const endMs = it.checkedOutAt ? new Date(it.checkedOutAt).getTime() : Date.now();
return Math.max(0, Math.round((endMs - new Date(it.checkedInAt).getTime()) / 1000));
}
export function TeamTimeSection() {
const team = trpc.time.teamToday.useQuery(undefined, { refetchInterval: 30_000 });
const users = trpc.user.list.useQuery();
@@ -90,6 +100,14 @@ export function TeamTimeSection() {
</span>
</span>
)}
{presenceSecondsOf(it) !== null && (
<span title="Anwesenheit: Lock-in bis Feierabend (bzw. jetzt) — unabhängig vom Tracking.">
{' · Anwesend: '}
<span className="font-mono">
{formatDurationCompact(presenceSecondsOf(it)!)}
</span>
</span>
)}
</p>
</div>
</div>