diff --git a/frontend/src/views/AnalysisPage.tsx b/frontend/src/views/AnalysisPage.tsx index ad1cd80..7dad444 100644 --- a/frontend/src/views/AnalysisPage.tsx +++ b/frontend/src/views/AnalysisPage.tsx @@ -444,7 +444,6 @@ export function AnalysisPage({ onNavigate }: AnalysisPageProps) { { label: "Sessions", value: totals?.sessions ?? 0, icon: Users }, { label: "Abgerechnet", value: formatMinutes(totals?.minutes ?? 0), detail: `Teamspace ${formatMinutes(totals?.crmBilledMinutes ?? 0)}`, icon: Clock3 }, { label: "Abrechenbar", value: formatMinutes(totals?.billableMinutes ?? 0), icon: UserCheck }, - { label: "Nicht abrechenbar", value: formatMinutes(totals?.nonBillableMinutes ?? 0), icon: UserCheck }, { label: "Offen", value: totals?.openSessions ?? 0, detail: formatMinutes(totals?.openMinutes ?? 0), icon: UserCheck } ]; const tickets = overview?.tickets ?? []; diff --git a/frontend/src/views/TicketDetailPage.tsx b/frontend/src/views/TicketDetailPage.tsx index 54244b1..4ed4c5a 100644 --- a/frontend/src/views/TicketDetailPage.tsx +++ b/frontend/src/views/TicketDetailPage.tsx @@ -395,7 +395,7 @@ function BillingButtons({ const status = session.billing_status; return ( -
+
) : null} + {ticket?.ticket_number ? ( + + ) : null} {ticket?.ticket_number ? ( @@ -2124,76 +2090,6 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
- - -
- - - Zammad-Mails importieren - - Eigene eMail-Artikel übernehmen. Rückblick: {mailDaysBack} Tag(e). -
-
- {mailPreview?.items.length ? ( - - ) : null} - -
-
- {!canPreviewMailSessions || mailPreview ? ( - - {!canPreviewMailSessions ? ( - - - Mail-Sync nicht bereit - Dieses Ticket braucht eine Support/Consulting-Art und dein Profil einen gültigen Zammad-Token. - - ) : null} - - {mailPreview ? ( -
-
- - {mailPreview.skipped > 0 || mailPreview.errors.length > 0 ? ( - - {mailPreview.skipped} ohne Transfer, {mailPreview.errors.length} Fehler - - ) : null} -
- - {mailPreview.items.length === 0 ? ( -

Keine importierbaren Mails für dieses Ticket gefunden.

- ) : ( -
- {mailPreview.items.map((item: TicketZammadMailSessionItem) => ( - - ))} -
- )} -
- ) : null} -
- ) : null} -
-
@@ -2213,6 +2109,56 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
+ {isGlobalTicket ? ( +
+
+ + +
+
+ + +
+
+ + +
+
+ ) : null} + {data?.sessions.length ? (
{teamspaceTabs.length > 0 ? ( @@ -2253,29 +2199,43 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
{sessionGroups.map((group) => (
-
+

{group.label}

{group.sessions.length} Session(s)

-
- + +
+ + + {formatMinutes(group.billableMinutes)} + + + + {formatMinutes(group.totalMinutes)} + + + + {formatMinutes(group.nonBillableMinutes)} + +
+
-
+
{group.sessions.map((session) => { const expanded = expandedSessionIds.includes(session.id); const zammadSent = session.zammad_article_status === "sent"; @@ -2325,8 +2285,8 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS const sendingZammad = sendingZammadSessionId === session.id; return ( -
-
+
+
+ ) : null} + +
+ + {!canPreviewMailSessions ? ( + + + Mail-Sync nicht bereit + Dieses Ticket braucht eine Support/Consulting-Art und dein Profil einen gültigen Zammad-Token. + + ) : null} + + {mailPreview ? ( +
+
+ + {mailPreview.skipped > 0 || mailPreview.errors.length > 0 ? ( + + {mailPreview.skipped} ohne Transfer, {mailPreview.errors.length} Fehler + + ) : null} +
+ + {mailPreview.items.length === 0 ? ( +

Keine importierbaren Mails für dieses Ticket gefunden.

+ ) : ( +
+ {mailPreview.items.map((item: TicketZammadMailSessionItem) => ( + + ))} +
+ )} +
+ ) : canPreviewMailSessions ? ( +

Lade zuerst die Vorschau, um importierbare Mails auszuwählen.

+ ) : null} +
+ + + !open && void keepEmptyProject()}> @@ -2751,7 +2766,6 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS />
- - -
-
- - - setManualSession({ - ...manualSession, - ticketNumber: event.currentTarget.value, - organizationId: "", - organizationName: null, - projectTeamspaceEntryId: "", - workType: "support" - }) - } - required - /> - {manualSession.ticketNumber.length > 0 && !isManualTicketValid ?

Format: Ticket#XXXXXX

: null} - {manualLookupStatus === "loading" ?

Prüfe vorhandenes Ticket...

: null} - {manualLookupStatus === "found" && manualTicketDefaultsLocked ? ( -

- {manualLookupTicket?.is_project ? "Projekt gefunden. Organisation und Consulting wurden übernommen." : "Ticket gefunden. Organisation und Art wurden übernommen."} -

- ) : null} - {manualLookupStatus === "found" && !manualTicketDefaultsLocked ? ( -

Ticket gefunden, aber Stammdaten sind unvollständig. Bitte ergänzen.

- ) : null} - {manualTicketIsRecurringBilling ? ( -

Fixe Abrechnung: Sessions kommen ausschließlich aus der Definition.

- ) : null} - {manualLookupStatus === "not-found" ? ( -
-

Neues Ticket. Organisation und Art bitte wählen oder aus Zammad übernehmen.

- -
- ) : null} -
-
- - - setManualSession({ - ...manualSession, - organizationId: organization.id, - organizationName: organization.name - }) - } - required - /> -
-
- - + +
+
+
+ + + setManualSession({ + ...manualSession, + ticketNumber: event.currentTarget.value, + organizationId: "", + organizationName: null, + projectTeamspaceEntryId: "", + workType: "support" + }) + } + required + /> + {manualSession.ticketNumber.length > 0 && !isManualTicketValid ?

Format: Ticket#XXXXXX

: null} + {manualLookupStatus === "loading" ?

Prüfe vorhandenes Ticket...

: null} + {manualLookupStatus === "found" && manualTicketDefaultsLocked ? ( +

+ {manualLookupTicket?.is_project ? "Projekt gefunden. Organisation und Consulting wurden übernommen." : "Ticket gefunden. Organisation und Art wurden übernommen."} +

+ ) : null} + {manualLookupStatus === "found" && !manualTicketDefaultsLocked ? ( +

Ticket gefunden, aber Stammdaten sind unvollständig. Bitte ergänzen.

+ ) : null} + {manualTicketIsRecurringBilling ? ( +

Fixe Abrechnung: Sessions kommen ausschließlich aus der Definition.

+ ) : null} + {manualLookupStatus === "not-found" ? ( +
+

Neues Ticket. Organisation und Art bitte wählen oder aus Zammad übernehmen.

+ +
+ ) : null} +
+
+ + + setManualSession({ + ...manualSession, + organizationId: organization.id, + organizationName: organization.name + }) + } + required + /> +
+
+ + +
+ {requiresTeamspaceEntry(manualLookupTicket) ? ( -
+
setManualSession({ ...manualSession, day: event.currentTarget.value })} - required - /> +
+
+ + setManualSession({ ...manualSession, startTime: event.currentTarget.value })} + required + /> +
+
+ + setManualSession({ ...manualSession, endTime: event.currentTarget.value })} + required + /> +
+
+ + setManualSession({ ...manualSession, day: event.currentTarget.value })} + required + /> +
+
+ + setManualSession({ ...manualSession, billingStatus })} + /> +
-
- - setManualSession({ ...manualSession, startTime: event.currentTarget.value })} - required - /> -
-
- - setManualSession({ ...manualSession, endTime: event.currentTarget.value })} - required - /> -
-
- - setManualSession({ ...manualSession, billingStatus })} - /> -
-
- - setManualSession((current) => ({ ...current, activity, zammadArticleBody }))} - /> -
-