import dayjs from "dayjs"; type ValueResolver = ( oldVal: any, newVal: any, ctx?: Record ) => { oldVal: any; newVal: any }; const TOKEN_TRANSLATIONS: Record = { account: "Konto", active: "Aktiv", address: "Adresse", amount: "Betrag", archived: "Archiviert", article: "Artikel", bank: "Bank", barcode: "Barcode", birthday: "Geburtstag", category: "Kategorie", city: "Ort", color: "Farbe", comment: "Kommentar", company: "Firma", contact: "Kontakt", contract: "Vertrag", cost: "Kosten", country: "Land", created: "Erstellt", customer: "Kunde", date: "Datum", default: "Standard", deleted: "Gelöscht", delivery: "Lieferung", description: "Beschreibung", document: "Dokument", driver: "Fahrer", due: "Fällig", duration: "Dauer", email: "E-Mail", employee: "Mitarbeiter", enabled: "Aktiviert", end: "Ende", event: "Ereignis", file: "Datei", first: "Vorname", fixed: "Festgeschrieben", group: "Gruppe", hour: "Stunde", iban: "IBAN", id: "ID", incoming: "Eingang", invoice: "Rechnung", item: "Eintrag", language: "Sprache", last: "Nachname", license: "Kennzeichen", link: "Link", list: "Liste", location: "Standort", manufacturer: "Hersteller", markup: "Verkaufsaufschlag", message: "Nachricht", mobile: "Mobil", name: "Name", note: "Notiz", notes: "Notizen", number: "Nummer", order: "Bestellung", own: "Eigen", payment: "Zahlung", phone: "Telefon", plant: "Objekt", postal: "Post", price: "Preis", percentage: "%", product: "Produkt", profile: "Profil", project: "Projekt", purchase: "Kauf", quantity: "Menge", rate: "Satz", reference: "Referenz", requisition: "Anfrage", resource: "Ressource", role: "Rolle", serial: "Serien", service: "Leistung", selling: "Verkauf", sellign: "Verkauf", space: "Lagerplatz", start: "Start", statement: "Buchung", status: "Status", street: "Straße", surcharge: "Aufschlag", tax: "Steuer", tel: "Telefon", tenant: "Mandant", time: "Zeit", title: "Titel", total: "Gesamt", type: "Typ", unit: "Einheit", updated: "Aktualisiert", user: "Benutzer", ustid: "USt-ID", value: "Wert", vendor: "Lieferant", vehicle: "Fahrzeug", weekly: "Wöchentlich", working: "Arbeits", zip: "Postleitzahl", composed: "Zusammensetzung", material: "Material", worker: "Arbeit", }; function tokenizeKey(key: string): string[] { return key .replace(/([a-z0-9])([A-Z])/g, "$1_$2") .replace(/[^a-zA-Z0-9]+/g, "_") .split("_") .filter(Boolean) .map((p) => p.toLowerCase()); } function capitalize(word: string) { if (!word) return word; return word.charAt(0).toUpperCase() + word.slice(1); } function fallbackLabelFromKey(key: string): string { const parts = tokenizeKey(key); if (!parts.length) return key; if (parts.length > 1 && parts[parts.length - 1] === "id") { const base = parts.slice(0, -1).map((p) => TOKEN_TRANSLATIONS[p] || capitalize(p)).join(" "); return `${base} ID`.trim(); } return parts .map((p) => TOKEN_TRANSLATIONS[p] || capitalize(p)) .join(" ") .replace(/\s+/g, " ") .trim(); } export function getDiffLabel(key: string): string { return diffTranslations[key]?.label || fallbackLabelFromKey(key); } export const diffTranslations: Record< string, { label: string; resolve?: ValueResolver } > = { project: { label: "Projekt", resolve: (o, n, ctx) => ({ oldVal: o ? ctx?.projects?.find((i: any) => i.id === o)?.name ?? "-" : "-", newVal: n ? ctx?.projects?.find((i: any) => i.id === n)?.name ?? "-" : "-", }), }, title: { label: "Titel" }, type: { label: "Typ" }, notes: { label: "Notizen" }, link: { label: "Link" }, start: { label: "Start", resolve: (o, n) => ({ oldVal: o ? dayjs(o).format("DD.MM.YYYY HH:mm") : "-", newVal: n ? dayjs(n).format("DD.MM.YYYY HH:mm") : "-", }), }, end: { label: "Ende", resolve: (o, n) => ({ oldVal: o ? dayjs(o).format("DD.MM.YYYY HH:mm") : "-", newVal: n ? dayjs(n).format("DD.MM.YYYY HH:mm") : "-", }), }, birthday: { label: "Geburtstag", resolve: (o, n) => ({ oldVal: o ? dayjs(o).format("DD.MM.YYYY") : "-", newVal: n ? dayjs(n).format("DD.MM.YYYY") : "-", }), }, resources: { label: "Ressourcen", resolve: (o, n) => ({ oldVal: Array.isArray(o) ? o.map((i: any) => i.title).join(", ") : "-", newVal: Array.isArray(n) ? n.map((i: any) => i.title).join(", ") : "-", }), }, customerNumber: { label: "Kundennummer" }, active: { label: "Aktiv", resolve: (o, n) => ({ oldVal: o === true ? "Aktiv" : "Gesperrt", newVal: n === true ? "Aktiv" : "Gesperrt", }), }, isCompany: { label: "Firmenkunde", resolve: (o, n) => ({ oldVal: o === true ? "Firma" : "Privatkunde", newVal: n === true ? "Firma" : "Privatkunde", }), }, special: { label: "Adresszusatz" }, street: { label: "Straße & Hausnummer" }, city: { label: "Ort" }, zip: { label: "Postleitzahl" }, country: { label: "Land" }, web: { label: "Webseite" }, email: { label: "E-Mail" }, tel: { label: "Telefon" }, ustid: { label: "USt-ID" }, role: { label: "Rolle" }, phoneHome: { label: "Festnetz" }, phoneMobile: { label: "Mobiltelefon" }, salutation: { label: "Anrede" }, firstName: { label: "Vorname" }, lastName: { label: "Nachname" }, name: { label: "Name" }, nameAddition: { label: "Name Zusatz" }, approved: { label: "Genehmigt" }, manufacturer: { label: "Hersteller" }, purchasePrice: { label: "Kaufpreis" }, markupPercentage: { label: "Verkaufsaufschlag in %" }, markup_percentage: { label: "Verkaufsaufschlag in %" }, sellingPrice: { label: "Verkaufspreis" }, selling_price: { label: "Verkaufspreis" }, sellingPriceComposed: { label: "Verkaufspreis Zusammensetzung" }, purchaseDate: { label: "Kaufdatum" }, serialNumber: { label: "Seriennummer" }, customerInventoryId: { label: "Kundeninventar-ID" }, customerinventoryitems: { label: "Kundeninventar" }, usePlanning: { label: "In Plantafel verwenden" }, currentSpace: { label: "Lagerplatz" }, customerspace: { label: "Kundenlagerplatz" }, customer: { label: "Kunde", resolve: (o, n, ctx) => ({ oldVal: o ? ctx?.customers?.find((i: any) => i.id === o)?.name ?? "-" : "-", newVal: n ? ctx?.customers?.find((i: any) => i.id === n)?.name ?? "-" : "-", }), }, vendor: { label: "Lieferant", resolve: (o, n, ctx) => ({ oldVal: o ? ctx?.vendors?.find((i: any) => i.id === o)?.name ?? "-" : "-", newVal: n ? ctx?.vendors?.find((i: any) => i.id === n)?.name ?? "-" : "-", }), }, description: { label: "Beschreibung" }, categorie: { label: "Kategorie" }, category: { label: "Kategorie" }, profile: { label: "Mitarbeiter", resolve: (o, n, ctx) => ({ oldVal: o ? ctx?.profiles?.find((i: any) => i.id === o)?.fullName ?? "-" : "-", newVal: n ? ctx?.profiles?.find((i: any) => i.id === n)?.fullName ?? "-" : "-", }), }, plant: { label: "Objekt", resolve: (o, n, ctx) => ({ oldVal: o ? ctx?.plants?.find((i: any) => i.id === o)?.name ?? "-" : "-", newVal: n ? ctx?.plants?.find((i: any) => i.id === n)?.name ?? "-" : "-", }), }, annualPaidLeaveDays: { label: "Urlaubstage" }, employeeNumber: { label: "Mitarbeiternummer" }, weeklyWorkingDays: { label: "Wöchentliche Arbeitstage" }, weeklyWorkingHours: { label: "Wöchentliche Arbeitszeit" }, customerRef: { label: "Referenz des Kunden" }, licensePlate: { label: "Kennzeichen" }, tankSize: { label: "Tankvolumen" }, towingCapacity: { label: "Anhängelast" }, color: { label: "Farbe" }, customPaymentDays: { label: "Zahlungsziel in Tagen" }, customSurchargePercentage: { label: "Individueller Aufschlag" }, powerInKW: { label: "Leistung" }, driver: { label: "Fahrer", resolve: (o, n, ctx) => ({ oldVal: o ? ctx?.profiles?.find((i: any) => i.id === o)?.fullName ?? "-" : "-", newVal: n ? ctx?.profiles?.find((i: any) => i.id === n)?.fullName ?? "-" : "-", }), }, projecttype: { label: "Projekttyp" }, contracttype: { label: "Vertragstyp" }, billingInterval: { label: "Abrechnungsintervall" }, fixed: { label: "Festgeschrieben", resolve: (o, n) => ({ oldVal: o === true ? "Ja" : "Nein", newVal: n === true ? "Ja" : "Nein", }), }, archived: { label: "Archiviert", resolve: (o, n) => ({ oldVal: o === true ? "Ja" : "Nein", newVal: n === true ? "Ja" : "Nein", }), }, };