From 8e4f07dcf84ac7d9b385626962691defd5576651 Mon Sep 17 00:00:00 2001 From: mboehmlaender Date: Wed, 5 Aug 2026 15:34:47 +0200 Subject: [PATCH] Refine statistics Teamspace display --- frontend/src/views/MonthlyClosePage.tsx | 6 +- frontend/src/views/StatisticsPage.tsx | 178 ++++++++---------------- 2 files changed, 57 insertions(+), 127 deletions(-) diff --git a/frontend/src/views/MonthlyClosePage.tsx b/frontend/src/views/MonthlyClosePage.tsx index fd1e7fe..6a45253 100644 --- a/frontend/src/views/MonthlyClosePage.tsx +++ b/frontend/src/views/MonthlyClosePage.tsx @@ -39,11 +39,7 @@ function formatSignedMinutes(minutes: number) { } function formatTeamspaceDelta(minutes: number) { - if (minutes === 0) { - return "ausgeglichen"; - } - - return `TS ${formatSignedMinutes(minutes)}`; + return formatSignedMinutes(minutes); } function StatusCard({ label, value, detail, tone }: { label: string; value: string | number; detail: string; tone?: "ok" | "warn" | "neutral" }) { diff --git a/frontend/src/views/StatisticsPage.tsx b/frontend/src/views/StatisticsPage.tsx index e49cc9f..24d9303 100644 --- a/frontend/src/views/StatisticsPage.tsx +++ b/frontend/src/views/StatisticsPage.tsx @@ -1,7 +1,4 @@ import { - ArrowDownRight, - ArrowUpRight, - Building2, ChevronLeft, ChevronRight, CircleAlert, @@ -97,16 +94,16 @@ function formatSignedMinutes(minutes: number) { } function formatTeamspaceDelta(minutes: number) { - if (minutes === 0) { - return "ausgeglichen"; - } + return formatSignedMinutes(minutes); +} - return `TS ${formatSignedMinutes(minutes)}`; +function deltaTextClass(minutes: number) { + return minutes < 0 ? "text-red-700 dark:text-red-300" : "text-emerald-700 dark:text-emerald-300"; } function DeltaBadge({ minutes }: { minutes: number }) { return ( - + {formatTeamspaceDelta(minutes)} ); @@ -134,40 +131,35 @@ function TimeComparison({ trackedMinutes, crmMinutes, sessions }: { trackedMinut ); } -function teamspaceTrend(buckets: StatisticsDailyBucket[]) { - const activeBuckets = buckets - .filter((bucket) => bucket.total_minutes > 0 || bucket.crm_billed_minutes > 0) - .map((bucket) => ({ - day: bucket.day, - deltaMinutes: bucket.crm_billed_minutes - bucket.total_minutes - })); - - if (activeBuckets.length < 2) { - return { - label: "Trend noch offen", - detail: "Zu wenige Tageswerte", - changeMinutes: 0, - firstAverage: 0, - secondAverage: 0 - }; - } - - const splitIndex = Math.ceil(activeBuckets.length / 2); - const first = activeBuckets.slice(0, splitIndex); - const second = activeBuckets.slice(splitIndex); - const average = (items: typeof activeBuckets) => Math.round(items.reduce((sum, item) => sum + item.deltaMinutes, 0) / Math.max(items.length, 1)); - const firstAverage = average(first); - const secondAverage = average(second.length > 0 ? second : first); - const changeMinutes = secondAverage - firstAverage; - const label = Math.abs(changeMinutes) < 15 ? "Trend stabil" : changeMinutes > 0 ? "Teamspace steigt relativ" : "Teamspace faellt relativ"; - - return { - label, - detail: `${formatTeamspaceDelta(firstAverage)} zu ${formatTeamspaceDelta(secondAverage)}`, - changeMinutes, - firstAverage, - secondAverage - }; +function ColorLegend() { + return ( +
+ + + Sessions + + + + Teamspace + + + + Differenz plus oder ausgeglichen + + + + Differenz minus + + + + bewertet + + + + offen + +
+ ); } function formatAxisMinutes(value: number) { @@ -375,7 +367,7 @@ function TicketHotspot({ ticket, month, onNavigate }: { ticket: StatisticsTicket Teamspace {formatMinutes(ticket.crm_billed_minutes)} {ticket.sessions} Session(s) {ticket.active_days} Tag(e) - {formatTeamspaceDelta(ticket.crm_delta_minutes)} + {formatTeamspaceDelta(ticket.crm_delta_minutes)}