From 8bed920de1895acb3985008f3a37a4ec51e97fe8 Mon Sep 17 00:00:00 2001 From: BOHA Date: Mon, 8 Jun 2026 13:00:09 +0200 Subject: [PATCH] =?UTF-8?q?feat(dashboard):=20show=20every=20active=20empl?= =?UTF-8?q?oyee=20in=20"Doch=C3=A1zka=20dnes"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The attendance card listed only employees with a record today (present / break / clocked-out / on-leave). Now every active employee appears; those with no record today show as "absent" (Nepřítomen), so the card reflects the whole team. Loads active users (was a bare count) and appends the unrecorded ones. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/admin/utils/dashboardHelpers.ts | 1 + src/routes/admin/dashboard.ts | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/admin/utils/dashboardHelpers.ts b/src/admin/utils/dashboardHelpers.ts index f544019..13dcead 100644 --- a/src/admin/utils/dashboardHelpers.ts +++ b/src/admin/utils/dashboardHelpers.ts @@ -16,6 +16,7 @@ export const STATUS_LABELS: Record = { away: "Přestávka", out: "Nepřihlášen", leave: "Nepřítomen", + absent: "Nepřítomen", }; // Re-exported from the single source of truth so the dashboard activity feed diff --git a/src/routes/admin/dashboard.ts b/src/routes/admin/dashboard.ts index 3f3d9da..4c5003b 100644 --- a/src/routes/admin/dashboard.ts +++ b/src/routes/admin/dashboard.ts @@ -69,7 +69,7 @@ export default async function dashboardRoutes( // Attendance admin — only for attendance.manage if (has("attendance.manage")) { - const [todayAttendance, onLeaveToday, usersCount] = await Promise.all([ + const [todayAttendance, onLeaveToday, activeUsers] = await Promise.all([ prisma.attendance.findMany({ where: { shift_date: { gte: todayStart, lt: todayEnd }, @@ -89,8 +89,13 @@ export default async function dashboardRoutes( users: { select: { id: true, first_name: true, last_name: true } }, }, }), - prisma.users.count({ where: { is_active: true } }), + prisma.users.findMany({ + where: { is_active: true }, + select: { id: true, first_name: true, last_name: true }, + orderBy: [{ last_name: "asc" }, { first_name: "asc" }], + }), ]); + const usersCount = activeUsers.length; const userAttendanceMap = new Map(); for (const a of todayAttendance) { @@ -153,6 +158,25 @@ export default async function dashboardRoutes( }); } + // Show every active employee — those with no attendance record today + // appear as "absent" so the card reflects the whole team, not just those + // who clocked in or are on leave. + const recordedUserIds = new Set([ + ...userAttendanceMap.keys(), + ...leaveUserIds, + ]); + for (const user of activeUsers) { + if (recordedUserIds.has(user.id)) continue; + attendanceUsers.push({ + user_id: user.id, + name: `${user.first_name} ${user.last_name}`, + initials: + `${user.first_name?.charAt(0) ?? ""}${user.last_name?.charAt(0) ?? ""}`.toUpperCase(), + status: "absent", + arrived_at: null, + }); + } + result.attendance = { present_today: presentCount, total_active: usersCount,