This commit is contained in:
michael committed 2026-09-23 11:09:10 +00:00
1 parent 9be6c6e36a
commit fa6db04370
16 files changed
+1123 -118

No files matched your search

+14 -9
View File
@@ -1536,7 +1536,7 @@ function WidgetContent(props: WidgetContentProps) {
return (
<MetricGrid
items={[
{ label: "Bewertet heute", value: formatMinutes(stats.dayTotals?.minutes ?? 0), icon: Timer },
{ label: "Abgerechnet heute", value: formatMinutes(stats.dayTotals?.minutes ?? 0), icon: Timer },
{ label: "Offene Bewertungen", value: stats.dayTotals?.openSessions ?? 0, icon: ClipboardCheck }
]}
/>
@@ -1547,7 +1547,7 @@ function WidgetContent(props: WidgetContentProps) {
return (
<MetricGrid
items={[
{ label: "Bewertet Monat", value: formatMinutes(stats.monthTotals?.minutes ?? 0), icon: CheckCircle2 },
{ label: "Abgerechnet Monat", value: formatMinutes(stats.monthTotals?.minutes ?? 0), icon: CheckCircle2 },
{ label: "Offene Bewertungen", value: stats.monthTotals?.openSessions ?? 0, icon: ClipboardCheck }
]}
/>
@@ -1560,7 +1560,7 @@ function WidgetContent(props: WidgetContentProps) {
<MetricGrid
items={[
{ label: "TS-Zeit Monat", value: formatMinutes(stats.monthTotals?.crmBilledMinutes ?? 0), icon: LayoutDashboard },
{ label: "Bewertet - TS", value: `${delta >= 0 ? "+" : "-"}${formatMinutes(Math.abs(delta))}`, icon: ArrowUp, tone: delta === 0 ? "normal" : delta > 0 ? "warning" : "good" }
{ label: "Abgerechnet - TS", value: `${delta >= 0 ? "+" : "-"}${formatMinutes(Math.abs(delta))}`, icon: ArrowUp, tone: delta === 0 ? "normal" : delta > 0 ? "warning" : "good" }
]}
/>
);
@@ -1697,7 +1697,7 @@ function DayControlWidget({ stats, projects, todos, onNavigate }: WidgetContentP
const todayTickets = stableSort(stats.todayTickets, (left, right) => compareText(left.ticket_number, right.ticket_number));
const todayOpenRatings = stableSort(stats.todayOpenRatings, (left, right) => compareOptionalDate(left.started_at, right.started_at, "asc") || compareText(left.ticket_number, right.ticket_number));
const teamspaceReviewTickets = todayTickets.filter((ticket) => ticket.open_count === 0 && teamspaceDeltaMinutes(ticket) > 0);
const afterworkTickets = todayTickets.filter((ticket) => ticket.open_count > 0 || teamspaceDeltaMinutes(ticket) > 0 || (ticket.total_minutes === 0 && ticket.non_billable_count > 0));
const afterworkTickets = todayTickets.filter((ticket) => ticket.open_count > 0 || teamspaceDeltaMinutes(ticket) > 0 || (ticket.total_minutes === 0 && (ticket.billable_count > 0 || ticket.non_billable_count > 0)));
const budgetAttention = stableSort(
projects.filter((project) => {
const percent = projectConsumptionPercent(project);
@@ -1779,7 +1779,7 @@ function DayControlWidget({ stats, projects, todos, onNavigate }: WidgetContentP
tone: "warning" as const,
title: session.ticket_number,
detail: `${formatMinutes(session.rounded_minutes)} offen · ${session.organization_name ?? "Keine Organisation"}`,
note: "Bewertung setzen: Abgerechnet oder Nicht abrechenbar.",
note: "Bewertung setzen: Abrechenbar oder Nicht abrechenbar.",
onClick: () => onNavigate(`/tickets/${session.ticket_id}?month=${currentMonth()}&status=open`)
})),
...teamspaceReviewTickets.slice(0, 4).map((ticket) => ({
@@ -1831,7 +1831,7 @@ function DayControlWidget({ stats, projects, todos, onNavigate }: WidgetContentP
items={afterworkTickets.slice(0, 4).map((ticket) => ({
key: `today-ticket-${ticket.id}`,
title: ticket.title || ticket.ticket_number,
detail: `${ticket.ticket_number} · ${formatMinutes(ticket.total_minutes + ticket.non_billable_minutes + ticket.open_minutes)} · ${ticket.session_count} Session(s)`,
detail: `${ticket.ticket_number} · ${formatMinutes(ticket.total_minutes + ticket.billable_minutes + ticket.non_billable_minutes + ticket.open_minutes)} · ${ticket.session_count} Session(s)`,
note: dayControlTodaySessionReason(ticket),
onClick: () => onNavigate(`/tickets/${ticket.id}?month=${currentMonth()}`)
}))}
@@ -1896,6 +1896,10 @@ function dayControlTodaySessionReason(ticket: PeriodOverview["tickets"][number])
return `Teamspace ok: ${formatMinutes(crmMinutes)} erfasst.`;
}
if (ticket.billable_count > 0) {
return `Abrechenbar gesetzt: später abrechnen oder Status finalisieren.`;
}
if (ticket.non_billable_count > 0) {
return `Nicht abrechenbar gesetzt: Zammad-Dokumentation kontrollieren.`;
}
@@ -2504,7 +2508,7 @@ function StatisticWidget({ widget, editing, stats, onNavigate, onUpdateConfig }:
{settings}
<MetricGrid
items={[
{ label: "Bewertet", value: formatMinutes(statistics.totals.minutes), icon: CheckCircle2 },
{ label: "Abgerechnet", value: formatMinutes(statistics.totals.minutes), icon: CheckCircle2 },
{ label: "Offen", value: statistics.totals.openSessions, icon: ClipboardCheck },
{ label: "Ø Session", value: formatMinutes(statistics.totals.averageSessionMinutes), icon: Timer },
{ label: "Aktive Tage", value: statistics.totals.activeDays, icon: LayoutDashboard }
@@ -2520,7 +2524,8 @@ function StatisticWidget({ widget, editing, stats, onNavigate, onUpdateConfig }:
{settings}
<BarList
items={[
{ key: "billed", title: "Bewertet", value: statistics.totals.billedMinutes, detail: `${statistics.totals.billedSessions} Session(s)` },
{ key: "billed", title: "Abgerechnet", value: statistics.totals.billedMinutes, detail: `${statistics.totals.billedSessions} Session(s)` },
{ key: "billable", title: "Abrechenbar", value: statistics.totals.billableMinutes, detail: `${statistics.totals.billableSessions} Session(s)` },
{ key: "non", title: "Nicht abrechenbar", value: statistics.totals.nonBillableMinutes, detail: `${statistics.totals.nonBillableSessions} Session(s)` },
{ key: "open", title: "Offen", value: statistics.totals.openMinutes, detail: `${statistics.totals.openSessions} Session(s)` }
]}
@@ -2616,7 +2621,7 @@ function StatisticWidget({ widget, editing, stats, onNavigate, onUpdateConfig }:
key: day.day,
title: formatDate(`${day.day}T00:00:00`),
value: view === "teamspaceDaily" ? day.crm_billed_minutes : day.total_minutes,
detail: view === "teamspaceDaily" ? `Bewertet ${formatMinutes(day.total_minutes)}` : `${day.sessions} Session(s)`
detail: view === "teamspaceDaily" ? `Abgerechnet ${formatMinutes(day.total_minutes)}` : `${day.sessions} Session(s)`
}));
return (