Update
This commit is contained in:
1 parent
c89d4825e2
commit
62794f72f1
8 files changed
+402
-78
No files matched your search
@@ -12,7 +12,7 @@ import { Textarea } from "@/components/ui/textarea";
|
||||
import { CopyTicketButton } from "@/components/CopyTicketButton";
|
||||
import { HelpLink } from "@/components/HelpLink";
|
||||
import { OrganizationSelect } from "@/components/OrganizationSelect";
|
||||
import { RichActivityEditor } from "@/components/RichActivityEditor";
|
||||
import { readRichActivityEditorValue, RichActivityEditor } from "@/components/RichActivityEditor";
|
||||
import { TodoPanel } from "@/components/TodoPanel";
|
||||
import {
|
||||
createSession,
|
||||
@@ -240,14 +240,18 @@ 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";
|
||||
function teamspaceEntryDisplayLabel(entry: { teamspace_project: string | null; teamspace_description?: string | null; is_default: boolean }) {
|
||||
return entry.teamspace_description?.trim() || entry.teamspace_project || "Ohne Teamspace-ID";
|
||||
}
|
||||
|
||||
function teamspaceEntryOptionLabel(entry: { teamspace_project: string | null; teamspace_description?: string | null; is_default: boolean }) {
|
||||
const label = teamspaceEntryDisplayLabel(entry);
|
||||
|
||||
return entry.is_default ? `${label} (Standard)` : label;
|
||||
}
|
||||
|
||||
function teamspaceEntryDescription(entry: { teamspace_description?: string | null } | null | undefined) {
|
||||
return entry?.teamspace_description?.trim() || "";
|
||||
function teamspaceEntryDescription(entry: { teamspace_project?: string | null; teamspace_description?: string | null } | null | undefined) {
|
||||
return entry?.teamspace_description?.trim() ? entry.teamspace_project?.trim() || "" : "";
|
||||
}
|
||||
|
||||
function teamspaceBillingKey(day: string, projectTeamspaceEntryId: string | null | undefined) {
|
||||
@@ -495,6 +499,19 @@ function teamspacePreparationText(ticket: TicketPeriod["ticket"] | null | undefi
|
||||
return [`${ticketNumber} - ${customerName}`, "", activities, "", "Tickethandling und Dokumentation"].join("\n");
|
||||
}
|
||||
|
||||
function SessionActivityBody({ session }: { session: SessionEntry }) {
|
||||
if (session.zammad_article_body) {
|
||||
return (
|
||||
<div
|
||||
className="break-words text-sm font-medium [&_blockquote]:border-l-2 [&_blockquote]:pl-3 [&_br]:block [&_code]:rounded-sm [&_code]:bg-muted [&_code]:px-1 [&_h1]:text-xl [&_h1]:font-semibold [&_h2]:text-lg [&_h2]:font-semibold [&_h3]:text-base [&_h3]:font-semibold [&_img]:my-2 [&_img]:max-h-80 [&_img]:max-w-full [&_img]:rounded-md [&_ol]:ml-5 [&_ol]:list-decimal [&_p]:my-1 [&_pre]:whitespace-pre-wrap [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-2 [&_strike]:line-through [&_ul]:ml-5 [&_ul]:list-disc"
|
||||
dangerouslySetInnerHTML={{ __html: session.zammad_article_body }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <p className="whitespace-pre-wrap break-words text-sm font-medium">{session.activity || "Keine Tätigkeit erfasst."}</p>;
|
||||
}
|
||||
|
||||
function toDateLocalValue(value: string) {
|
||||
const date = new Date(value);
|
||||
const offsetMs = date.getTimezoneOffset() * 60_000;
|
||||
@@ -921,7 +938,7 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
|
||||
return [
|
||||
...projectEntries.map((entry) => ({
|
||||
id: entry.id,
|
||||
label: entry.teamspace_project || (entry.is_default ? "Standard" : "Ohne Teamspace-ID"),
|
||||
label: teamspaceEntryDisplayLabel(entry),
|
||||
description: teamspaceEntryDescription(entry),
|
||||
entry
|
||||
})),
|
||||
@@ -1446,18 +1463,22 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
|
||||
setSavingTicketSession(true);
|
||||
|
||||
try {
|
||||
const activityValue = readRichActivityEditorValue("ticket-session-activity") ?? {
|
||||
activity: ticketSession.activity,
|
||||
zammadArticleBody: ticketSession.zammadArticleBody
|
||||
};
|
||||
const result = await createSession({
|
||||
ticketNumber: ticket.ticket_number,
|
||||
organizationId: effectiveOrganizationId,
|
||||
activity: ticketSession.activity,
|
||||
zammadArticleBody: ticketSession.zammadArticleBody || null,
|
||||
activity: activityValue.activity,
|
||||
zammadArticleBody: activityValue.zammadArticleBody || null,
|
||||
workType: effectiveWorkType,
|
||||
startedAt: startedAt.toISOString(),
|
||||
endedAt: endedAt.toISOString(),
|
||||
durationSeconds,
|
||||
projectTeamspaceEntryId: effectiveWorkType === "consulting" && requiresProjectTeamspaceEntry ? ticketSession.projectTeamspaceEntryId : null,
|
||||
billingStatus: ticketSession.billingStatus,
|
||||
createZammadArticle: ticketSession.createZammadArticle,
|
||||
createZammadArticle: ticketSession.createZammadArticle && (activityValue.activity.trim().length > 0 || Boolean(activityValue.zammadArticleBody)),
|
||||
zammadArticleTypeId: ticketSession.zammadArticleTypeId
|
||||
});
|
||||
toast.success("Session nachgetragen", {
|
||||
@@ -1563,10 +1584,14 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
|
||||
|
||||
setSavingSessionDetails(true);
|
||||
try {
|
||||
const activityValue = readRichActivityEditorValue("session-activity") ?? {
|
||||
activity: editSessionActivity,
|
||||
zammadArticleBody: editSessionZammadArticleBody
|
||||
};
|
||||
await updateSessionDetails(editingSession.id, {
|
||||
organizationId: editSessionOrganizationId,
|
||||
activity: editSessionActivity,
|
||||
zammadArticleBody: editSessionZammadArticleBody || null,
|
||||
activity: activityValue.activity,
|
||||
zammadArticleBody: activityValue.zammadArticleBody || null,
|
||||
workType: editSessionWorkType,
|
||||
removeProjectData,
|
||||
projectTeamspaceEntryId: editSessionWorkType === "consulting" && requiresProjectTeamspaceEntry ? editSessionProjectTeamspaceEntryId : null,
|
||||
@@ -1855,7 +1880,7 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
|
||||
? `Eigentümer: ${project.owner_display_name}`
|
||||
: showBudgetedProjectEntries
|
||||
? `${budgetedProjectEntries.length} budgetierte Teamspace-Einträge`
|
||||
: budgetedProjectEntries[0]?.teamspace_project || project.teamspace_project || "Kein Teamspace-Projekt hinterlegt"}
|
||||
: budgetedProjectEntries[0] ? teamspaceEntryDisplayLabel(budgetedProjectEntries[0]) : project.teamspace_project || "Kein Teamspace-Projekt hinterlegt"}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
@@ -1927,7 +1952,7 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
|
||||
{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");
|
||||
const label = teamspaceEntryDisplayLabel(entry);
|
||||
|
||||
return (
|
||||
<div key={entry.id} className="rounded-md border bg-background/50 px-2 py-1">
|
||||
@@ -2371,7 +2396,7 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
|
||||
</div>
|
||||
{expanded ? (
|
||||
<div className="border-t px-3 pb-3 pt-2">
|
||||
<p className="whitespace-pre-wrap break-words text-sm font-medium">{session.activity || "Keine Tätigkeit erfasst."}</p>
|
||||
<SessionActivityBody session={session} />
|
||||
<div className="mt-2 flex flex-wrap gap-x-3 gap-y-1 text-xs text-muted-foreground">
|
||||
<span>{session.organization_name ?? session.customer_name}</span>
|
||||
<span>{session.work_type === "support" ? "Support" : "Consulting"}</span>
|
||||
@@ -2566,6 +2591,7 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
|
||||
Tätigkeit
|
||||
</label>
|
||||
<RichActivityEditor
|
||||
key={`ticket-session-${ticketId}`}
|
||||
id="ticket-session-activity"
|
||||
value={ticketSession.activity}
|
||||
htmlValue={ticketSession.zammadArticleBody}
|
||||
@@ -2727,6 +2753,7 @@ export function TicketDetailPage({ periodType, period, ticketId, onNavigate, onS
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium" htmlFor="session-activity">Tätigkeit</label>
|
||||
<RichActivityEditor
|
||||
key={editingSession?.id ?? "session-activity-empty"}
|
||||
id="session-activity"
|
||||
value={editSessionActivity}
|
||||
htmlValue={editSessionZammadArticleBody}
|
||||
|
||||
Reference in new issue
Block a user