Files
tickettracker/frontend/src/zammad-meta.tsx
2026-09-16 08:29:58 +00:00

155 lines
4.8 KiB
TypeScript

import { AlertTriangle, ArrowDown, ArrowUp, CheckCircle2, CircleDot, CirclePause, Flag, Minus } from "lucide-react";
import { Badge } from "@/components/ui/badge";
import { cn } from "@/lib/utils";
export type ZammadStateFilter = "all" | "none" | "2" | "3" | "4" | "7";
export type ZammadPriorityFilter = "all" | "none" | "1" | "2" | "3";
export const zammadStateFilterOptions: Array<{ value: ZammadStateFilter; label: string }> = [
{ value: "all", label: "Alle Zammad-Status" },
{ value: "2", label: "Offen" },
{ value: "3", label: "Wartend" },
{ value: "4", label: "Geschlossen" },
{ value: "7", label: "Abschluss" },
{ value: "none", label: "Ohne Zammad-Status" }
];
export const zammadPriorityFilterOptions: Array<{ value: ZammadPriorityFilter; label: string }> = [
{ value: "all", label: "Alle Prioritäten" },
{ value: "1", label: "Niedrig" },
{ value: "2", label: "Normal" },
{ value: "3", label: "Hoch" },
{ value: "none", label: "Ohne Priorität" }
];
const zammadStateMeta = {
"2": {
label: "Offen",
order: 10,
className: "border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
Icon: CircleDot
},
"3": {
label: "Wartend",
order: 20,
className: "border-blue-500/30 bg-blue-500/10 text-blue-700 dark:text-blue-300",
Icon: CirclePause
},
"7": {
label: "Abschluss",
order: 30,
className: "border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300",
Icon: Flag
},
"4": {
label: "Geschlossen",
order: 40,
className: "border-slate-500/30 bg-slate-500/10 text-slate-700 dark:text-slate-300",
Icon: CheckCircle2
}
};
const zammadPriorityMeta = {
"1": {
label: "Niedrig",
order: 10,
className: "border-blue-500/30 bg-blue-500/10 text-blue-700 dark:text-blue-300",
Icon: ArrowDown
},
"2": {
label: "Normal",
order: 20,
className: "border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300",
Icon: Minus
},
"3": {
label: "Hoch",
order: 30,
className: "border-red-500/30 bg-red-500/10 text-red-700 dark:text-red-300",
Icon: ArrowUp
}
};
export function zammadId(value: unknown) {
if (value === null || value === undefined || value === "") {
return null;
}
const normalized = String(value).trim();
return /^\d+$/.test(normalized) ? normalized.replace(/^0+(?=\d)/, "") : normalized || null;
}
export function zammadStateId(value: unknown) {
const id = zammadId(value);
return id === "1" ? "2" : id;
}
export function zammadStateLabel(value: unknown) {
const id = zammadStateId(value);
return id ? zammadStateMeta[id as keyof typeof zammadStateMeta]?.label ?? `Status ${id}` : "-";
}
export function zammadPriorityLabel(value: unknown) {
const id = zammadId(value);
return id ? zammadPriorityMeta[id as keyof typeof zammadPriorityMeta]?.label ?? `Priorität ${id}` : "-";
}
export function zammadStateSortRank(value: unknown) {
const id = zammadStateId(value);
const fallback = id ? Number(id) : Number.NaN;
return id ? zammadStateMeta[id as keyof typeof zammadStateMeta]?.order ?? (Number.isFinite(fallback) ? 900 + fallback : 999) : 999;
}
export function zammadPrioritySortRank(value: unknown) {
const id = zammadId(value);
const fallback = id ? Number(id) : Number.NaN;
return id ? zammadPriorityMeta[id as keyof typeof zammadPriorityMeta]?.order ?? (Number.isFinite(fallback) ? 900 + fallback : 999) : 999;
}
export function matchesZammadStateFilter(value: unknown, filter: ZammadStateFilter) {
const id = zammadStateId(value);
return filter === "all" || (filter === "none" ? !id : id === filter);
}
export function matchesZammadPriorityFilter(value: unknown, filter: ZammadPriorityFilter) {
const id = zammadId(value);
return filter === "all" || (filter === "none" ? !id : id === filter);
}
export function ZammadStateBadge({ stateId, className }: { stateId: unknown; className?: string }) {
const id = zammadStateId(stateId);
if (!id) {
return null;
}
const meta = zammadStateMeta[id as keyof typeof zammadStateMeta];
const Icon = meta?.Icon ?? AlertTriangle;
return (
<Badge variant="outline" className={cn(meta?.className ?? "border-border bg-muted/40 text-muted-foreground", className)}>
<Icon className="size-3" />
{meta?.label ?? `Status ${id}`}
</Badge>
);
}
export function ZammadPriorityBadge({ priorityId, className }: { priorityId: unknown; className?: string }) {
const id = zammadId(priorityId);
if (!id) {
return null;
}
const meta = zammadPriorityMeta[id as keyof typeof zammadPriorityMeta];
const Icon = meta?.Icon ?? AlertTriangle;
return (
<Badge variant="outline" className={cn(meta?.className ?? "border-border bg-muted/40 text-muted-foreground", className)}>
<Icon className="size-3" />
{meta?.label ?? `Priorität ${id}`}
</Badge>
);
}