feat: Profilseite, Etikettendruck mit QR-Code, mehr Automatisierungen und Entra-ID-SSO
Backend Image / build-and-push (push) Successful in 2m28s
Frontend Image / build-and-push (push) Successful in 2m10s

- Profilseite mit MFA-Einrichtung, Passwort/E-Mail/Name aendern, Konto deaktivieren
- Bearbeiten-Buttons fuer Bienenstaende/Voelker/Koeniginnen/Aufgaben-Datensaetze
- Restliche englische Enum-Werte durch deutsche Labels ersetzt (SelectValue-Fix)
- Sidebar-Eintraege fuer Ernten/Schleuderungen ergaenzt
- Automatisierungen von 3 auf 6 Regeln erweitert (Schwarmstimmung, kritischer Gesundheitsstatus, Lagerbestand)
- Responsive Grid-Layout fuer Volk-/Koeniginnen-/Honigchargen-/Bienenstand-Detailseiten
- Etikettenvorlagen mit Platzhaltern inkl. QR-Code (verweist auf Herkunftsseite) und PDF-Druck
- Entra-ID-SSO (Authorization Code + PKCE, kein Auto-Provisioning, Secrets nur ueber Environment-Variablen)
This commit is contained in:
Nick Szaunig committed 2026-08-31 18:56:08 +02:00
1 parent 0a52b29c57
commit 8432313fa9
83 files changed
+2684 -289

No files matched your search

@@ -0,0 +1,36 @@
import { apiFetch, apiFetchBlob } from "@/lib/auth/api-client";
import { downloadBlob } from "@/lib/export/api";
import { CreateLabelTemplateInput, LabelTemplate, UpdateLabelTemplateInput } from "./types";
export function fetchLabelTemplates(): Promise<LabelTemplate[]> {
return apiFetch<LabelTemplate[]>("/label-templates");
}
export function createLabelTemplate(input: CreateLabelTemplateInput): Promise<LabelTemplate> {
return apiFetch<LabelTemplate>("/label-templates", {
method: "POST",
body: JSON.stringify(input),
});
}
export function updateLabelTemplate(
id: string,
input: UpdateLabelTemplateInput,
): Promise<LabelTemplate> {
return apiFetch<LabelTemplate>(`/label-templates/${id}`, {
method: "PATCH",
body: JSON.stringify(input),
});
}
export function deactivateLabelTemplate(id: string): Promise<LabelTemplate> {
return apiFetch<LabelTemplate>(`/label-templates/${id}`, { method: "DELETE" });
}
export async function printLabels(templateId: string, bottlingBatchId: string): Promise<void> {
const { blob, filename } = await apiFetchBlob(
`/label-templates/${templateId}/print/${bottlingBatchId}`,
"etiketten.pdf",
);
downloadBlob(blob, filename);
}
@@ -0,0 +1,41 @@
export interface LabelTemplate {
id: string;
name: string;
content: string;
widthMm: number;
heightMm: number;
isDefault: boolean;
active: boolean;
createdAt: string;
updatedAt: string;
}
export interface CreateLabelTemplateInput {
name: string;
content: string;
widthMm?: number;
heightMm?: number;
isDefault?: boolean;
}
export interface UpdateLabelTemplateInput {
name?: string;
content?: string;
widthMm?: number;
heightMm?: number;
isDefault?: boolean;
}
export const LABEL_PLACEHOLDERS: { key: string; description: string }[] = [
{ key: "batchNumber", description: "Chargennummer der Honigcharge" },
{ key: "honeyType", description: "Honigsorte" },
{ key: "lotNumber", description: "Los-/Chargennummer der Abfüllung" },
{ key: "bottlingDate", description: "Abfülldatum" },
{ key: "bestBeforeDate", description: "Mindesthaltbarkeitsdatum (MHD)" },
{ key: "jarSize", description: "Glasgröße" },
{ key: "productName", description: "Produktname" },
{
key: "qrCode",
description: "QR-Code zur öffentlichen Herkunftsseite der Charge (Honigsorte, Daten, Rückverfolgbarkeit)",
},
];