Remove non-billable fragments from statistics

This commit is contained in:
2026-08-05 22:46:39 +02:00
parent ac71eb88c0
commit e527576ed6
2 changed files with 15 additions and 60 deletions
+11 -30
View File
@@ -218,7 +218,7 @@ export const helpSections: HelpSection[] = [
{ {
id: "statistiken", id: "statistiken",
title: "Statistiken", title: "Statistiken",
description: "Statistiken vergleichen abgerechnete Session-Zeit, nicht abrechenbare Arbeit, offene Bewertungen und Teamspace-Werte.", description: "Statistiken vergleichen abgerechnete Session-Zeit, offene Bewertungen und Teamspace-Werte.",
quickItems: [ quickItems: [
"Abgerechnet und Teamspace haben getrennte Farben.", "Abgerechnet und Teamspace haben getrennte Farben.",
"Positive oder gleiche Differenz ist grün.", "Positive oder gleiche Differenz ist grün.",
@@ -226,13 +226,12 @@ export const helpSections: HelpSection[] = [
], ],
details: [ details: [
"Die Statistikseite betrachtet immer einen Monat.", "Die Statistikseite betrachtet immer einen Monat.",
"Abgerechnet zeigt nur Sessions mit der Bewertung Abgerechnet. Nicht abrechenbare und offene Zeiten sind dort nicht enthalten.", "Abgerechnet zeigt nur Sessions mit der Bewertung Abgerechnet. Offene Zeiten sind dort nicht enthalten.",
"Alle Statistik- und Vergleichswerte nutzen nur abgerechnete Zeiten.", "Alle Statistik- und Vergleichswerte nutzen nur abgerechnete Zeiten.",
"Teamspace zeigt, wie viel Zeit für dieselben abrechenbaren Ticket-Tage im CRM eingetragen wurde.", "Teamspace zeigt, wie viel Zeit für dieselben abrechenbaren Ticket-Tage im CRM eingetragen wurde.",
"Eine positive Differenz bedeutet: In Teamspace steht mehr Zeit als abgerechnet wurde.", "Eine positive Differenz bedeutet: In Teamspace steht mehr Zeit als abgerechnet wurde.",
"Eine negative Differenz bedeutet: In Teamspace steht weniger Zeit als abgerechnet wurde.", "Eine negative Differenz bedeutet: In Teamspace steht weniger Zeit als abgerechnet wurde.",
"Nicht abrechenbar und Offen werden jeweils als eigene Statuswerte ausgewiesen.", "Offene Sessions werden nicht in Relationen, Graphen, Teamspace-Differenzen, Hotspots, Manuell/Fix-Werte oder Durchschnittswerte eingerechnet.",
"Sie werden nicht in Relationen, Graphen, Teamspace-Differenzen, Hotspots, Manuell/Fix-Werte oder Durchschnittswerte eingerechnet.",
"Der Monatsverlauf zeigt abgerechnete Session-Zeit als Balken und Teamspace als Linie.", "Der Monatsverlauf zeigt abgerechnete Session-Zeit als Balken und Teamspace als Linie.",
"Organisationen, Typen und Ticket-Hotspots helfen dabei, Auffälligkeiten im Monat schnell zu finden." "Organisationen, Typen und Ticket-Hotspots helfen dabei, Auffälligkeiten im Monat schnell zu finden."
] ]
@@ -248,9 +247,9 @@ export const helpSections: HelpSection[] = [
], ],
details: [ details: [
"Abgerechnet umfasst nur Sessions des angemeldeten Benutzers, die aktiv als Abgerechnet markiert wurden.", "Abgerechnet umfasst nur Sessions des angemeldeten Benutzers, die aktiv als Abgerechnet markiert wurden.",
"Nicht abrechenbare Sessions und offene Sessions werden aus diesem Wert herausgehalten.", "Offene Sessions werden aus diesem Wert herausgehalten.",
"Auch automatisch erzeugte Sessions aus fixen Abrechnungen zählen hier mit, sobald sie als Abgerechnet markiert wurden.", "Auch automatisch erzeugte Sessions aus fixen Abrechnungen zählen hier mit, sobald sie als Abgerechnet markiert wurden.",
"Es werden keine offenen oder nicht abrechenbaren Zeiten in diesen Wert eingerechnet.", "Es werden keine offenen Zeiten in diesen Wert eingerechnet.",
"Dieser Wert ist die Ausgangsbasis für Teamspace-Differenzen: Teamspace minus abgerechnete Session-Zeit ergibt die Differenz." "Dieser Wert ist die Ausgangsbasis für Teamspace-Differenzen: Teamspace minus abgerechnete Session-Zeit ergibt die Differenz."
] ]
}, },
@@ -268,39 +267,22 @@ export const helpSections: HelpSection[] = [
"Die Statistik summiert alle Teamspace-Werte des Monats für den angemeldeten Benutzer.", "Die Statistik summiert alle Teamspace-Werte des Monats für den angemeldeten Benutzer.",
"Eine positive Differenz bedeutet, dass in Teamspace mehr Zeit steht als abgerechnet wurde.", "Eine positive Differenz bedeutet, dass in Teamspace mehr Zeit steht als abgerechnet wurde.",
"Eine negative Differenz bedeutet, dass in Teamspace weniger Zeit steht als abgerechnet wurde.", "Eine negative Differenz bedeutet, dass in Teamspace weniger Zeit steht als abgerechnet wurde.",
"Nicht abrechenbare und offene Sessions fließen nicht in diese Differenz ein.", "Offene Sessions fließen nicht in diese Differenz ein.",
"Fehlende Teamspace-Werte können im Monatsabschluss geprüft und bei Bedarf zur Kenntnis genommen werden." "Fehlende Teamspace-Werte können im Monatsabschluss geprüft und bei Bedarf zur Kenntnis genommen werden."
] ]
}, },
{
id: "statistik-bewertet",
title: "Statistik: Nicht abrechenbar",
description: "Diese Kennzahl zeigt Arbeit, die bewusst nicht abgerechnet wird.",
quickItems: [
"Nur Sessions mit Bewertung Nicht abrechenbar.",
"Wird nur separat ausgewiesen.",
"Nicht abrechenbare Sessions blockieren den Monatsabschluss nicht."
],
details: [
"Nicht abrechenbar ist getrennt von Abgerechnet, damit interne, Kulanz- oder nicht fakturierbare Arbeit sichtbar bleibt.",
"Diese Sessions werden nicht mit Teamspace verglichen.",
"Die Statistik zeigt die Anzahl der nicht abrechenbaren Sessions, aber keinen Stundenwert.",
"Es werden daraus keine Anteile, Differenzen oder Vergleichswerte berechnet.",
"Wenn eine Bewertung zurückgenommen wird, wandert die Session wieder in Offen."
]
},
{ {
id: "statistik-offen", id: "statistik-offen",
title: "Statistik: Offen", title: "Statistik: Offen",
description: "Diese Kennzahl zeigt Sessions, die noch keine Bewertung haben.", description: "Diese Kennzahl zeigt Sessions, die noch keine Bewertung haben.",
quickItems: [ quickItems: [
"Offen bedeutet: weder Abgerechnet noch Nicht abrechenbar.", "Offen bedeutet: noch keine Bewertung.",
"Offene Sessions blockieren den Monatsabschluss.", "Offene Sessions blockieren den Monatsabschluss.",
"Die Klärung erfolgt in der Ticketdetailansicht." "Die Klärung erfolgt in der Ticketdetailansicht."
], ],
details: [ details: [
"Offen umfasst alle Sessions des Monats ohne Bewertung.", "Offen umfasst alle Sessions des Monats ohne Bewertung.",
"Diese Sessions müssen vor dem Monatsabschluss entweder als Abgerechnet oder Nicht abrechenbar markiert werden.", "Diese Sessions müssen vor dem Monatsabschluss bewertet werden.",
"Die offene Zeit zeigt, wie viele Minuten noch bewertet werden müssen.", "Die offene Zeit zeigt, wie viele Minuten noch bewertet werden müssen.",
"Der Monatsabschluss listet offene Bewertungen gruppiert nach Ticket, damit du direkt in die passende Ticketdetailansicht springen kannst.", "Der Monatsabschluss listet offene Bewertungen gruppiert nach Ticket, damit du direkt in die passende Ticketdetailansicht springen kannst.",
"Wird eine Bewertung zurückgenommen, steigt die offene Anzahl wieder." "Wird eine Bewertung zurückgenommen, steigt die offene Anzahl wieder."
@@ -319,7 +301,7 @@ export const helpSections: HelpSection[] = [
"Der Monatsverlauf zeigt jeden Tag des Monats. Tage ohne Sessions bleiben leer, damit die Monatsstruktur sichtbar bleibt.", "Der Monatsverlauf zeigt jeden Tag des Monats. Tage ohne Sessions bleiben leer, damit die Monatsstruktur sichtbar bleibt.",
"Die blauen Balken stehen für abgerechnete Session-Zeit.", "Die blauen Balken stehen für abgerechnete Session-Zeit.",
"Die fuchsiafarbene Linie steht für Teamspace-Zeit, sofern für den Tag Werte gepflegt wurden.", "Die fuchsiafarbene Linie steht für Teamspace-Zeit, sofern für den Tag Werte gepflegt wurden.",
"Der Bewertungsstand weist Abgerechnet, Nicht abrechenbar und Offen nur als getrennte Werte aus.", "Der Bewertungsstand weist Abgerechnet und Offen getrennt aus.",
"Der Teamspace-Abgleich zeigt die Gesamtdifferenz zwischen CRM-Werten und abgerechneter Session-Zeit.", "Der Teamspace-Abgleich zeigt die Gesamtdifferenz zwischen CRM-Werten und abgerechneter Session-Zeit.",
"Manuell und Fix trennen selbst erfasste abrechenbare Sessions von automatisch erzeugten abrechenbaren Sessions aus fixen Abrechnungen." "Manuell und Fix trennen selbst erfasste abrechenbare Sessions von automatisch erzeugten abrechenbaren Sessions aus fixen Abrechnungen."
] ]
@@ -338,7 +320,6 @@ export const helpSections: HelpSection[] = [
"Sessions zeigt die Anzahl der einzelnen Arbeitseinträge.", "Sessions zeigt die Anzahl der einzelnen Arbeitseinträge.",
"Zeiten vergleicht abgerechnete Session-Zeit mit Teamspace-Zeit.", "Zeiten vergleicht abgerechnete Session-Zeit mit Teamspace-Zeit.",
"Die Differenz wird als Teamspace minus abgerechnete Zeit berechnet.", "Die Differenz wird als Teamspace minus abgerechnete Zeit berechnet.",
"Nicht abrechenbare Sessions werden separat ausgewiesen und nicht in die Differenz gerechnet.",
"Der Anteil am Monat zeigt, wie groß die abgerechnete Zeit dieser Organisation im Verhältnis zur größten Organisation im Monat ist.", "Der Anteil am Monat zeigt, wie groß die abgerechnete Zeit dieser Organisation im Verhältnis zur größten Organisation im Monat ist.",
"Bei vielen Organisationen wird die Liste paginiert, damit die Seite kompakt bleibt." "Bei vielen Organisationen wird die Liste paginiert, damit die Seite kompakt bleibt."
] ]
@@ -357,7 +338,7 @@ export const helpSections: HelpSection[] = [
"Support und Consulting werden getrennt summiert.", "Support und Consulting werden getrennt summiert.",
"Die Zeitwerte zeigen abgerechnete Sessions und Teamspace für den jeweiligen Typ.", "Die Zeitwerte zeigen abgerechnete Sessions und Teamspace für den jeweiligen Typ.",
"Die Differenz folgt derselben Logik wie überall: Teamspace minus abgerechnete Session-Zeit.", "Die Differenz folgt derselben Logik wie überall: Teamspace minus abgerechnete Session-Zeit.",
"Die Zeile Abr., Nicht und Offen zeigt, wie viele Sessions dieses Typs bereits bewertet oder noch offen sind." "Die Zeile Abr. und Offen zeigt, wie viele Sessions dieses Typs bereits abgerechnet oder noch offen sind."
] ]
}, },
{ {
@@ -372,7 +353,7 @@ export const helpSections: HelpSection[] = [
details: [ details: [
"Ticket-Hotspots helfen, die größten Aufwandstreiber im Monat schnell zu erkennen.", "Ticket-Hotspots helfen, die größten Aufwandstreiber im Monat schnell zu erkennen.",
"Die Liste zeigt die wichtigsten Tickets nach abgerechneter Zeit.", "Die Liste zeigt die wichtigsten Tickets nach abgerechneter Zeit.",
"Pro Ticket siehst du Organisation, Sessionanzahl, aktive abrechenbare Tage, abgerechnete Zeit, nicht abrechenbare Sessions, Teamspace-Zeit und Differenz.", "Pro Ticket siehst du Organisation, Sessionanzahl, aktive abrechenbare Tage, abgerechnete Zeit, Teamspace-Zeit und Differenz.",
"Offene Tickets werden mit einem Warnstatus angezeigt, damit Bewertungen nachgezogen werden können.", "Offene Tickets werden mit einem Warnstatus angezeigt, damit Bewertungen nachgezogen werden können.",
"Über Öffnen gelangst du direkt in die Ticketdetailansicht des Monats." "Über Öffnen gelangst du direkt in die Ticketdetailansicht des Monats."
] ]
+4 -30
View File
@@ -4,7 +4,6 @@ import {
CircleAlert, CircleAlert,
Clock3, Clock3,
ExternalLink, ExternalLink,
ListChecks,
RotateCcw, RotateCcw,
Ticket, Ticket,
TrendingUp, TrendingUp,
@@ -36,7 +35,6 @@ const trackedFillClass = "fill-sky-500/70 dark:fill-sky-400/65";
const teamspaceStrokeClass = "text-fuchsia-600 dark:text-fuchsia-300"; const teamspaceStrokeClass = "text-fuchsia-600 dark:text-fuchsia-300";
const trackedDotClass = "bg-sky-500 dark:bg-sky-400"; const trackedDotClass = "bg-sky-500 dark:bg-sky-400";
const teamspaceDotClass = "bg-fuchsia-500 dark:bg-fuchsia-400"; const teamspaceDotClass = "bg-fuchsia-500 dark:bg-fuchsia-400";
const nonBillableTextClass = "text-indigo-700 dark:text-indigo-300";
const openTextClass = "text-amber-700 dark:text-amber-300"; const openTextClass = "text-amber-700 dark:text-amber-300";
const organizationPageSize = 8; const organizationPageSize = 8;
@@ -125,10 +123,6 @@ function ColorLegend() {
<span className="size-2 rounded-full bg-red-500 dark:bg-red-400" /> <span className="size-2 rounded-full bg-red-500 dark:bg-red-400" />
<span className="text-red-700 dark:text-red-300">Differenz minus</span> <span className="text-red-700 dark:text-red-300">Differenz minus</span>
</span> </span>
<span className="inline-flex items-center gap-1.5">
<span className="size-2 rounded-full bg-indigo-500 dark:bg-indigo-400" />
<span className={nonBillableTextClass}>nicht abrechenbar</span>
</span>
<span className="inline-flex items-center gap-1.5"> <span className="inline-flex items-center gap-1.5">
<span className="size-2 rounded-full bg-amber-500 dark:bg-amber-400" /> <span className="size-2 rounded-full bg-amber-500 dark:bg-amber-400" />
<span className={openTextClass}>offen</span> <span className={openTextClass}>offen</span>
@@ -197,7 +191,6 @@ function buildMonthSeries(month: string, buckets: StatisticsDailyBucket[]) {
billedMinutes: bucket?.billed_minutes ?? 0, billedMinutes: bucket?.billed_minutes ?? 0,
openMinutes: bucket?.open_minutes ?? 0, openMinutes: bucket?.open_minutes ?? 0,
billedSessions: bucket?.billed_sessions ?? 0, billedSessions: bucket?.billed_sessions ?? 0,
nonBillableSessions: bucket?.non_billable_sessions ?? 0,
openSessions: bucket?.open_sessions ?? 0, openSessions: bucket?.open_sessions ?? 0,
crmBilledMinutes: bucket?.crm_billed_minutes ?? 0 crmBilledMinutes: bucket?.crm_billed_minutes ?? 0
}; };
@@ -344,7 +337,6 @@ function TicketHotspot({ ticket, month, onNavigate }: { ticket: StatisticsTicket
<div className="mt-1 flex flex-wrap gap-x-3 gap-y-1 text-xs"> <div className="mt-1 flex flex-wrap gap-x-3 gap-y-1 text-xs">
<span className={trackedTextClass}>Abgerechnet {formatMinutes(ticket.total_minutes)}</span> <span className={trackedTextClass}>Abgerechnet {formatMinutes(ticket.total_minutes)}</span>
<span className={teamspaceTextClass}>Teamspace {formatMinutes(ticket.crm_billed_minutes)}</span> <span className={teamspaceTextClass}>Teamspace {formatMinutes(ticket.crm_billed_minutes)}</span>
<span className={nonBillableTextClass}>Nicht {ticket.non_billable_sessions} Session(s)</span>
<span className="text-muted-foreground">{ticket.billed_sessions} abgerechnet</span> <span className="text-muted-foreground">{ticket.billed_sessions} abgerechnet</span>
<span>{ticket.active_days} Tag(e)</span> <span>{ticket.active_days} Tag(e)</span>
<span className={deltaTextClass(ticket.crm_delta_minutes)}>{formatTeamspaceDelta(ticket.crm_delta_minutes)}</span> <span className={deltaTextClass(ticket.crm_delta_minutes)}>{formatTeamspaceDelta(ticket.crm_delta_minutes)}</span>
@@ -421,7 +413,6 @@ export function StatisticsPage({ onNavigate }: StatisticsPageProps) {
const totals = stats?.totals; const totals = stats?.totals;
const billedSessions = totals?.billedSessions ?? 0; const billedSessions = totals?.billedSessions ?? 0;
const billedMinutes = totals?.billedMinutes ?? 0; const billedMinutes = totals?.billedMinutes ?? 0;
const nonBillableSessions = totals?.nonBillableSessions ?? 0;
const openSessions = totals?.openSessions ?? 0; const openSessions = totals?.openSessions ?? 0;
const openMinutes = totals?.openMinutes ?? 0; const openMinutes = totals?.openMinutes ?? 0;
const crmCoverage = percentage(totals?.crmBilledMinutes ?? 0, totals?.minutes ?? 0); const crmCoverage = percentage(totals?.crmBilledMinutes ?? 0, totals?.minutes ?? 0);
@@ -469,7 +460,7 @@ export function StatisticsPage({ onNavigate }: StatisticsPageProps) {
</div> </div>
</div> </div>
<div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-4"> <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
<MetricCard <MetricCard
label="Abgerechnet" label="Abgerechnet"
value={formatMinutes(totals?.minutes ?? 0)} value={formatMinutes(totals?.minutes ?? 0)}
@@ -488,19 +479,6 @@ export function StatisticsPage({ onNavigate }: StatisticsPageProps) {
helpAnchor="statistik-teamspace" helpAnchor="statistik-teamspace"
helpLabel="Hilfe zur Kennzahl Teamspace" helpLabel="Hilfe zur Kennzahl Teamspace"
/> />
<MetricCard
label="Nicht abrechenbar"
value={`${nonBillableSessions} Session(s)`}
detail={
<div className="space-y-0.5">
<div>wird nicht kalkuliert</div>
</div>
}
icon={ListChecks}
valueClassName={nonBillableTextClass}
helpAnchor="statistik-bewertet"
helpLabel="Hilfe zur Kennzahl Nicht abrechenbar"
/>
<MetricCard <MetricCard
label="Offen" label="Offen"
value={formatMinutes(openMinutes)} value={formatMinutes(openMinutes)}
@@ -541,9 +519,8 @@ export function StatisticsPage({ onNavigate }: StatisticsPageProps) {
<span className="text-muted-foreground">Bewertungsstand</span> <span className="text-muted-foreground">Bewertungsstand</span>
<span className="font-medium">{billedSessions} abrechenbar</span> <span className="font-medium">{billedSessions} abrechenbar</span>
</div> </div>
<div className="grid gap-2 text-xs sm:grid-cols-3 xl:grid-cols-1 2xl:grid-cols-3"> <div className="grid gap-2 text-xs sm:grid-cols-2 xl:grid-cols-1 2xl:grid-cols-2">
<div className={trackedTextClass}>Abgerechnet: {billedSessions} Session(s), {formatMinutes(billedMinutes)}</div> <div className={trackedTextClass}>Abgerechnet: {billedSessions} Session(s), {formatMinutes(billedMinutes)}</div>
<div className={nonBillableTextClass}>Nicht: {nonBillableSessions} Session(s)</div>
<div className={openTextClass}>Offen: {openSessions} Session(s), {formatMinutes(openMinutes)}</div> <div className={openTextClass}>Offen: {openSessions} Session(s), {formatMinutes(openMinutes)}</div>
</div> </div>
</div> </div>
@@ -587,7 +564,6 @@ export function StatisticsPage({ onNavigate }: StatisticsPageProps) {
<p className="flex flex-wrap gap-x-3 gap-y-1 text-xs"> <p className="flex flex-wrap gap-x-3 gap-y-1 text-xs">
<span className={trackedTextClass}>Abgerechnet {formatMinutes(topOrganization.total_minutes)}</span> <span className={trackedTextClass}>Abgerechnet {formatMinutes(topOrganization.total_minutes)}</span>
<span className={teamspaceTextClass}>Teamspace {formatMinutes(topOrganization.crm_billed_minutes)}</span> <span className={teamspaceTextClass}>Teamspace {formatMinutes(topOrganization.crm_billed_minutes)}</span>
<span className={nonBillableTextClass}>Nicht {topOrganization.non_billable_sessions} Session(s)</span>
</p> </p>
</div> </div>
) : null} ) : null}
@@ -647,7 +623,6 @@ export function StatisticsPage({ onNavigate }: StatisticsPageProps) {
<div className="flex flex-wrap gap-x-3 gap-y-1 text-xs"> <div className="flex flex-wrap gap-x-3 gap-y-1 text-xs">
<span className={trackedTextClass}>Abgerechnet {formatMinutes(organization.total_minutes)}</span> <span className={trackedTextClass}>Abgerechnet {formatMinutes(organization.total_minutes)}</span>
<span className={teamspaceTextClass}>Teamspace {formatMinutes(organization.crm_billed_minutes)}</span> <span className={teamspaceTextClass}>Teamspace {formatMinutes(organization.crm_billed_minutes)}</span>
<span className={nonBillableTextClass}>Nicht {organization.non_billable_sessions} Session(s)</span>
<span className="text-muted-foreground">{percentage(organization.total_minutes, totals?.minutes ?? 0)}% vom Monat</span> <span className="text-muted-foreground">{percentage(organization.total_minutes, totals?.minutes ?? 0)}% vom Monat</span>
<span className={deltaTextClass(organization.crm_delta_minutes)}>{formatTeamspaceDelta(organization.crm_delta_minutes)}</span> <span className={deltaTextClass(organization.crm_delta_minutes)}>{formatTeamspaceDelta(organization.crm_delta_minutes)}</span>
</div> </div>
@@ -718,9 +693,8 @@ export function StatisticsPage({ onNavigate }: StatisticsPageProps) {
<span className={trackedTextClass}>Abgerechnet {formatMinutes(group.total_minutes)}</span> <span className={trackedTextClass}>Abgerechnet {formatMinutes(group.total_minutes)}</span>
<span className={teamspaceTextClass}>Teamspace {formatMinutes(group.crm_billed_minutes)}</span> <span className={teamspaceTextClass}>Teamspace {formatMinutes(group.crm_billed_minutes)}</span>
</div> </div>
<div className="grid grid-cols-3 gap-2 text-xs text-muted-foreground"> <div className="grid grid-cols-2 gap-2 text-xs text-muted-foreground">
<span>Abr. {group.billed_sessions} / {formatMinutes(group.billed_minutes)}</span> <span>Abr. {group.billed_sessions} / {formatMinutes(group.billed_minutes)}</span>
<span>Nicht {group.non_billable_sessions}</span>
<span>Offen {group.open_sessions} / {formatMinutes(group.open_minutes)}</span> <span>Offen {group.open_sessions} / {formatMinutes(group.open_minutes)}</span>
</div> </div>
</div> </div>
@@ -758,7 +732,7 @@ export function StatisticsPage({ onNavigate }: StatisticsPageProps) {
<Ticket className="size-8 text-muted-foreground" /> <Ticket className="size-8 text-muted-foreground" />
<div> <div>
<p className="font-medium">Keine abgerechneten Sessions in diesem Monat</p> <p className="font-medium">Keine abgerechneten Sessions in diesem Monat</p>
<p className="text-sm text-muted-foreground">Offene oder nicht abrechenbare Sessions werden separat gezeigt und fließen nicht in Statistiken oder Vergleiche ein.</p> <p className="text-sm text-muted-foreground">Offene Sessions werden separat gezeigt und fließen nicht in Statistiken oder Vergleiche ein.</p>
</div> </div>
<Button variant="secondary" size="sm" onClick={() => setMonth(currentMonth())}> <Button variant="secondary" size="sm" onClick={() => setMonth(currentMonth())}>
<RotateCcw className="size-4" /> <RotateCcw className="size-4" />