Compare commits

...

4 Commits

Author SHA1 Message Date
BOHA
92252382ac chore(release): v2.0.8 — show all employees in dashboard attendance
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 13:07:59 +02:00
BOHA
8bed920de1 feat(dashboard): show every active employee in "Docházka dnes"
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) <noreply@anthropic.com>
2026-06-08 13:00:09 +02:00
BOHA
9d2992b722 chore(release): v2.0.7 — always show notes in multi-record plan cells
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 12:54:47 +02:00
BOHA
1ddc0feccd fix(plan): always show notes for every record in a multi-record cell
Previously notes were hidden when a cell held 2-3 records (a density
choice). Show each record's note regardless of count — drop the
now-unused showNote prop on PlanRangeChips.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 12:53:45 +02:00
5 changed files with 29 additions and 9 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "app-ts",
"version": "2.0.6",
"version": "2.0.8",
"description": "",
"main": "dist/server.js",
"scripts": {

View File

@@ -620,7 +620,6 @@ export default function PlanGrid({
c.category,
catMap,
)}
showNote={cellArr.length === 1}
/>
</Box>
))}

View File

@@ -6,7 +6,6 @@ interface Props {
project: Project | null;
readonly?: boolean;
categoryLabel: string;
showNote?: boolean;
}
export default function PlanRangeChips({
@@ -14,7 +13,6 @@ export default function PlanRangeChips({
project,
readonly,
categoryLabel,
showNote = true,
}: Props) {
void readonly;
if (!cell) return null;
@@ -38,9 +36,7 @@ export default function PlanRangeChips({
</span>
)}
</div>
{showNote && cell.note && (
<div className="plan-cell-note">{cell.note}</div>
)}
{cell.note && <div className="plan-cell-note">{cell.note}</div>}
</div>
);
}

View File

@@ -16,6 +16,7 @@ export const STATUS_LABELS: Record<string, string> = {
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

View File

@@ -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<number, (typeof todayAttendance)[0]>();
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<number>([
...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,