This commit is contained in:
michael committed 2026-09-15 11:49:47 +00:00
1 parent 235c19e51b
commit 227644cfeb
8 files changed
+1041 -309

No files matched your search

+20 -8
View File
@@ -124,6 +124,16 @@ function projectTeamspaceEntries(project: ProjectSummary): ProjectTeamspaceEntry
];
}
function budgetedProjectTeamspaceEntries(project: ProjectSummary) {
return projectTeamspaceEntries(project).filter((entry) => Number(entry.hour_budget_minutes ?? 0) > 0);
}
function teamspaceEntryOptionLabel(entry: { teamspace_project: string | null; is_default: boolean }) {
const label = entry.teamspace_project || "Ohne Teamspace-ID";
return entry.is_default ? `${label} (Standard)` : label;
}
function projectEditForm(project: ProjectSummary): ProjectEditFormState {
const entries = projectTeamspaceEntries(project).map((entry, index) => ({
clientId: entry.id || projectEntryId(),
@@ -503,7 +513,9 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onO
const isRecurringBillingTicket = ticketHasRecurringBilling(ticket);
const projectDescription = project ? combinedProjectDescription(project) : "";
const projectEntries = useMemo(() => (project ? projectTeamspaceEntries(project) : []), [project]);
const budgetedProjectEntries = useMemo(() => (project ? budgetedProjectTeamspaceEntries(project) : []), [project]);
const hasMultipleProjectTeamspaceEntries = projectEntries.length > 1;
const showBudgetedProjectEntries = budgetedProjectEntries.length > 1;
const requiresProjectTeamspaceEntry = Boolean(project && hasMultipleProjectTeamspaceEntries);
const projectConsumptionMinutes = project?.consumption_minutes ?? 0;
const projectBudgetMinutes = project?.hour_budget_minutes ?? null;
@@ -1284,9 +1296,9 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onO
<CardDescription>
{!canEditProject && project.owner_display_name
? `Eigentümer: ${project.owner_display_name}`
: hasMultipleProjectTeamspaceEntries
? `${projectEntries.length} Teamspace-Einträge`
: project.teamspace_project || "Kein Teamspace-Projekt hinterlegt"}
: showBudgetedProjectEntries
? `${budgetedProjectEntries.length} budgetierte Teamspace-Einträge`
: budgetedProjectEntries[0]?.teamspace_project || project.teamspace_project || "Kein Teamspace-Projekt hinterlegt"}
</CardDescription>
</div>
<div className="flex shrink-0 items-center gap-1">
@@ -1329,9 +1341,9 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onO
<Badge variant="secondary">Zeitraum {project.starts_on || "offen"} - {project.ends_on || "offen"}</Badge>
<Badge variant="secondary">Kontingent {projectBudgetMinutes ? formatMinutes(projectBudgetMinutes) : "offen"}</Badge>
<Badge variant="secondary">Verbrauch {formatMinutes(projectConsumptionMinutes)}</Badge>
{hasMultipleProjectTeamspaceEntries ? <Badge variant="outline">{projectEntries.length} Teamspace</Badge> : null}
{showBudgetedProjectEntries ? <Badge variant="outline">{budgetedProjectEntries.length} Budgets</Badge> : null}
</div>
{hasMultipleProjectTeamspaceEntries ? (
{showBudgetedProjectEntries ? (
<div className="space-y-2">
<div>
<div className="mb-1 flex items-center justify-between gap-2 text-xs text-muted-foreground">
@@ -1346,7 +1358,7 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onO
</div>
</div>
<div className="grid gap-1.5 md:grid-cols-2">
{projectEntries.map((entry) => {
{budgetedProjectEntries.map((entry) => {
const consumption = Number(entry.consumption_minutes ?? 0);
const percent = projectConsumptionPercent(consumption, entry.hour_budget_minutes);
const label = entry.teamspace_project || (entry.is_default ? "Standard" : "Ohne Teamspace-ID");
@@ -1762,7 +1774,7 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onO
<option value="">Bitte wählen</option>
{projectEntries.map((entry) => (
<option key={entry.id} value={entry.id}>
{entry.teamspace_project || (entry.is_default ? "Standard" : "Ohne Teamspace-ID")}
{teamspaceEntryOptionLabel(entry)}
</option>
))}
</select>
@@ -1943,7 +1955,7 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onO
<option value="">Bitte wählen</option>
{projectEntries.map((entry) => (
<option key={entry.id} value={entry.id}>
{entry.teamspace_project || (entry.is_default ? "Standard" : "Ohne Teamspace-ID")}
{teamspaceEntryOptionLabel(entry)}
</option>
))}
</select>