This commit is contained in:
2025-11-08 13:42:43 +01:00
commit 7567d3eb05
125 changed files with 16866 additions and 0 deletions

View File

@@ -0,0 +1,69 @@
"use server";
const apiUrl = process.env.NEXT_SERVER_API_URL;
export async function getTableData() {
try {
const res = await fetch(
`${apiUrl}/VorlageRollenDruck/getAllRollendruckVorlagen`
);
if (!res.ok) {
console.error("Response status:", res.status);
}
const data: {
id: number;
height: number;
width: number;
printer: string;
articleTypes: string;
}[] = await res.json();
return data;
} catch (error) {
console.error("Error fetching vorlagen:", error);
throw new Error("An error occurred while fetching vorlagen.");
}
}
export async function deleteVorlageRollendruck(id: number) {
const res = await fetch(`${apiUrl}/VorlageRollenDruck/delete/${id}`, {
method: "DELETE",
});
if (!res.ok) {
throw new Error("Failed to delete item");
}
return;
}
export async function getTableDataDupli() {
try {
const res = await fetch(
`${apiUrl}/VorlageRollenDruck/getAllDupliArtikel`
);
if (!res.ok) {
console.error("Response status:", res.status);
}
const data: {
id: number;
product_type: string;
}[] = await res.json();
return data;
} catch (error) {
console.error("Error fetching vorlagen:", error);
throw new Error("An error occurred while fetching vorlagen.");
}
}
export async function deleteDupliEntry(id: number) {
const res = await fetch(`${apiUrl}/VorlageRollenDruck/deleteDupli/${id}`, {
method: "DELETE",
});
if (!res.ok) {
throw new Error("Failed to delete item");
}
return;
}

View File

@@ -0,0 +1,107 @@
"use server";
const apiUrl = process.env.NEXT_SERVER_API_URL;
export async function createVorlage(formData: FormData) {
const printer = formData.get("printer") as string;
const height = Number(formData.get("height"));
const width = Number(formData.get("width"));
const articleTypes = formData.get("articleTypes") as string;
const payload = {
printer,
height,
width,
articleTypes
};
try {
const response = await fetch(
`${apiUrl}/VorlageRollenDruck/createRollenDruckVorlage`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
cache: "no-store",
}
);
if (!response.ok) {
console.error("Response status:", response.status);
throw new Error("Failed to submit form");
}
} catch (error) {
console.error("Error submitting form:", error);
throw new Error("An error occurred while submitting the form.");
}
}
export async function alterVorlage(formData: FormData) {
const id = Number(formData.get("id"));
const printer = formData.get("printer") as string;
const height = Number(formData.get("height"));
const width = Number(formData.get("width"));
const articleTypes = formData.get("articleTypes") as string;
const payload = {
id,
printer,
height,
width,
articleTypes
};
try {
const response = await fetch(
`${apiUrl}/VorlageRollenDruck/alterVorlage`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
cache: "no-store",
}
);
if (!response.ok) {
console.error("Response status:", response.status);
throw new Error("Failed to submit form");
}
} catch (error) {
console.error("Error submitting form:", error);
throw new Error("An error occurred while submitting the form.");
}
}
export async function addDupliArtikel(fromData: FormData) {
const artikelTyp = fromData.get("ArtikelTyp") as string;
const payload = {
product_type: artikelTyp,
};
try {
const response = await fetch(
`${apiUrl}/VorlageRollenDruck/addDupliArtikel`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
cache: "no-store",
}
);
if (!response.ok) {
console.error("Response status:", response.status);
throw new Error("Failed to submit form");
}
} catch (error) {
console.error("Error submitting form:", error);
throw new Error("An error occurred while submitting the form.");
}
}

View File

@@ -0,0 +1,177 @@
"use Client";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { createVorlage } from "./action";
import { useState } from "react";
export default function AddDialog({ onNewEntry }: { onNewEntry: () => void }) {
const [open, setOpen] = useState(false)
const formSchema = z.object({
Drucker: z.string().min(1, {
message: "Druckername muss mindestens 2 Zeichen lang sein.",
}),
Höhe: z.preprocess(
(value) => (typeof value === "string" ? parseFloat(value) : value),
z.number({
invalid_type_error: "Höhe muss eine gültige Zahl sein. Bspw. 1.5 .",
}).min(1, {
message: "Höhe muss mindestens 1 sein.",
})
),
Breite: z.preprocess(
(value) => (typeof value === "string" ? parseFloat(value) : value),
z.number({
invalid_type_error: "Breite muss eine gültige Zahl sein. Bspw. 1.5 .",
}).min(1, {
message: "Breite muss mindestens 1 sein.",
})
),
ArtikelTypen: z
.string()
.regex(/^(\s*\w+\s*)(,\s*\w+\s*)*$/, {
message: "Bitte geben Sie eine durch Kommas getrennte Liste ein (z.B. te, bs, s, s, s)",
}),
});
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
Drucker: "",
Höhe: 0,
Breite: 0,
ArtikelTypen: "",
},
});
async function onSubmit(values: z.infer<typeof formSchema>) {
const formData = new FormData();
formData.append("printer", values.Drucker);
formData.append("height", values.Höhe.toString());
formData.append("width", values.Breite.toString());
formData.append("articleTypes", values.ArtikelTypen);
try {
await createVorlage(formData);
setOpen(false);
form.reset();
onNewEntry();
}
catch (error) {
console.error("Error submitting form:", error);
throw new Error("An error occurred while submitting the form.");
}
}
return (
<div>
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="outline" className="mt-2 mb-2 border-green-700 text-green-700">
Vorlage hinzufügen
</Button>
</DialogTrigger>
<DialogContent className="max-w-screen-lg max-h-screen overflow-y-auto">
<DialogHeader>
<DialogTitle className="mb-8">Vorlage hinzufügen</DialogTitle>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="Drucker"
render={({ field }) => (
<FormItem>
<FormLabel>Drucker Name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<DialogDescription>
Der Name des Druckers, auf dem die Vorlage gedruckt wird.
</DialogDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="Höhe"
render={({ field }) => (
<FormItem>
<FormLabel>Höhe</FormLabel>
<FormControl>
<Input type="number" step="any" {...field} />
</FormControl>
<FormDescription>
Die Höhe der Vorlage in Millimeter.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="Breite"
render={({ field }) => (
<FormItem>
<FormLabel>Breite</FormLabel>
<FormControl>
<Input type="number" step="any" {...field} />
</FormControl>
<FormDescription>
Die Breite der Vorlage in Millimeter.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="ArtikelTypen"
render={({ field }) => (
<FormItem>
<FormLabel>Artikel Typen</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormDescription>
Geben Sie die Artikeltypen als durch Kommas getrennte Liste ein (z.B. te, bs, s, s, s).
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">
Hinzufügen
</Button>
</form>
</Form>
</DialogHeader>
</DialogContent>
</Dialog>
</div>
);
}

View File

@@ -0,0 +1,99 @@
"use Client";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import {addDupliArtikel} from "./action";
import { useState } from "react";
import {Plus} from "lucide-react";
export default function AddDialog({ onNewEntry }: { onNewEntry: () => void }) {
const [open, setOpen] = useState(false)
const formSchema = z.object({
ArtikelTyp: z.string().min(1, {
message: "Druckername muss mindestens 2 Zeichen lang sein.",
}),
});
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
ArtikelTyp: "",
},
});
async function onSubmit(values: z.infer<typeof formSchema>) {
const formData = new FormData();
formData.append("ArtikelTyp", values.ArtikelTyp);
try {
await addDupliArtikel(formData);
setOpen(false);
form.reset();
onNewEntry();
}
catch (error) {
console.error("Error submitting form:", error);
throw new Error("An error occurred while submitting the form.");
}
}
return (
<div>
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant={"outline"} className="border-green-700 text-green-700 mt-2 mb-2" ><Plus /></Button>
</DialogTrigger>
<DialogContent className="max-w-screen-lg max-h-screen overflow-y-auto">
<DialogHeader>
<DialogTitle className="mb-8">ArtikelTyp hinzufügen</DialogTitle>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="ArtikelTyp"
render={({ field }) => (
<FormItem>
<FormLabel>ArtikelTyp</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<DialogDescription>
Der Typ des Artikels, der dupliziert gedruckt werden soll.
</DialogDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">
Hinzufügen
</Button>
</form>
</Form>
</DialogHeader>
</DialogContent>
</Dialog>
</div>
);
}

View File

@@ -0,0 +1,190 @@
"use Client";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import { z } from "zod"
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { alterVorlage } from "./action";
import { useState } from "react";
type TableData = {
id: number;
printer: string;
height: number;
width: number;
articleTypes: string;
};
type AlterDialogProps = {
onNewEntry: () => void;
data: TableData;
};
export default function AlterDialog({ onNewEntry, data }: AlterDialogProps) {
const [open, setOpen] = useState(false)
const formSchema = z.object({
Drucker: z.string().min(1, {
message: "Druckername muss mindestens 2 Zeichen lang sein.",
}),
Höhe: z.preprocess(
(value) => (typeof value === "string" ? parseFloat(value) : value),
z.number({
invalid_type_error: "Höhe muss eine gültige Zahl sein. Bspw. 1.5 .",
}).min(1, {
message: "Höhe muss mindestens 1 sein.",
})
),
Breite: z.preprocess(
(value) => (typeof value === "string" ? parseFloat(value) : value),
z.number({
invalid_type_error: "Breite muss eine gültige Zahl sein. Bspw. 1.5 .",
}).min(1, {
message: "Breite muss mindestens 1 sein.",
})
),
ArtikelTypen: z
.string()
.regex(/^(\s*\w+\s*)(,\s*\w+\s*)*$/, {
message: "Bitte geben Sie eine durch Kommas getrennte Liste ein (z.B. te, bs, s, s, s)",
}),
});
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
Drucker: data.printer,
Höhe: data.height,
Breite: data.width,
ArtikelTypen: data.articleTypes,
},
});
async function onSubmit(values: z.infer<typeof formSchema>) {
const formData = new FormData();
formData.append("id", data.id.toString());
formData.append("printer", values.Drucker);
formData.append("height", values.Höhe.toString());
formData.append("width", values.Breite.toString());
formData.append("articleTypes", values.ArtikelTypen);
try {
await alterVorlage(formData);
setOpen(false);
form.reset();
onNewEntry();
}
catch (error) {
console.error("Error submitting form:", error);
throw new Error("An error occurred while submitting the form.");
}
}
return (
<div>
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button variant="ghost" className="font-normal pl-2">
Vorlage bearbeiten
</Button>
</DialogTrigger>
<DialogContent className="max-w-screen-lg max-h-screen overflow-y-auto">
<DialogHeader>
<DialogTitle className="mb-8">Vorlage bearbeiten</DialogTitle>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="Drucker"
render={({ field }) => (
<FormItem>
<FormLabel>Drucker Name</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<DialogDescription>
Der Name des Druckers, auf dem die Vorlage gedruckt wird.
</DialogDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="Höhe"
render={({ field }) => (
<FormItem>
<FormLabel>Höhe</FormLabel>
<FormControl>
<Input type="number" step="any" {...field} />
</FormControl>
<FormDescription>
Die Höhe der Vorlage in Millimeter.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="Breite"
render={({ field }) => (
<FormItem>
<FormLabel>Breite</FormLabel>
<FormControl>
<Input type="number" step="any" {...field} />
</FormControl>
<FormDescription>
Die Breite der Vorlage in Millimeter.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="ArtikelTypen"
render={({ field }) => (
<FormItem>
<FormLabel>Artikel Typen</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormDescription>
Geben Sie eine durch Kommas getrennte Liste von Artikeltypen ein (z.B. te, bs, s, s, s).
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">
Änderungen speichern
</Button>
</form>
</Form>
</DialogHeader>
</DialogContent>
</Dialog>
</div>
);
}

View File

@@ -0,0 +1,227 @@
"use client";
import { useEffect, useState } from "react";
import { Ellipsis } from "lucide-react"
import { getTableData, deleteVorlageRollendruck, getTableDataDupli, deleteDupliEntry } from "./action";
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import AddDialog from "./components/addDialog";
import AlterDialog from "./components/alterDialog";
import AddDialogDupli from "./components/addDialogDupli";
type TableData = {
id: number;
printer: string;
height: number;
width: number;
articleTypes: string;
};
export default function Page() {
const [data, setData] = useState<TableData[]>([]);
const [dupliData, setDupliData] = useState<{ id: number; product_type: string }[]>([]);
useEffect(() => {
async function fetchData() {
try {
const result = await getTableData();
setData(result || []);
const dupliResult = await getTableDataDupli();
setDupliData(Array.isArray(dupliResult) ? dupliResult : []);
} catch (error) {
console.error("Fehler beim Laden der Daten:", error);
}
}
fetchData();
}, []);
const handleNewEntry = async () => {
try {
const result = await getTableData(); // Daten erneut abrufen
setData(result); // Tabelle aktualisieren
} catch (error) {
console.error("Fehler beim Aktualisieren der Daten:", error);
}
};
const handleNewEntry2 = async () => {
try {
const result = await getTableDataDupli(); // Daten erneut abrufen
setDupliData(result) // Tabelle aktualisieren
} catch (error) {
console.error("Fehler beim Aktualisieren der Daten:", error);
}
};
const deleteEntry = async (id: number) => {
try {
await deleteVorlageRollendruck(id);
await handleNewEntry();
}
catch (error) {
console.error("Fehler beim Löschen der Daten:", error);
}
};
const deleteEntryDupli = async (id: number) => {
try {
await deleteDupliEntry(id);
await handleNewEntry2();
}
catch (error) {
console.error("Fehler beim Löschen der Daten:", error);
}
}
return (
<div className="min-h-screen bg-gray-50 p-6">
<div className="flex w-full max-w-6xl mx-auto gap-2">
<div className="w-1/3 flex-shrink-0">
<Table className="bg-white shadow-md border border-gray-300">
<TableCaption>Artikel für Duplizierung</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Artikel Typ</TableHead>
<TableHead className="text-right">
<AddDialogDupli onNewEntry={handleNewEntry2} />
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{dupliData.map((item) => (
<TableRow key={item.id}>
<TableCell>{item.product_type}</TableCell>
<TableCell className="text-right">
<Button onClick={() => {
deleteEntryDupli(item.id); // Eintrag löschen
}} variant={"outline"} className="border-red-700 text-red-700 h-6">Entfernen</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
<div className="flex-1">
<Table className="bg-white shadow-md border border-gray-300">
<TableCaption>Vorlagen Rollendruck</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Drucker</TableHead>
<TableHead>Höhe</TableHead>
<TableHead>Breite</TableHead>
<TableHead>Artikel Typen</TableHead>
<TableHead className="text-right">
<AddDialog onNewEntry={handleNewEntry} />
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.map((item) => (
<TableRow key={item.id}>
<TableCell>{item.printer}</TableCell>
<TableCell>{item.height}</TableCell>
<TableCell>{item.width}</TableCell>
<TableCell>
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Anzeigen</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Artikel Typen</DialogTitle>
<DialogDescription>
Hier sind die Artikel Typen gelistet, die von der Vorlage unterstützt werden.
</DialogDescription>
</DialogHeader>
{item.articleTypes}
</DialogContent>
</Dialog>
</TableCell>
<TableCell className="text-right">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon">
<Ellipsis />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<AlterDialog onNewEntry={handleNewEntry} data={item} />
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">
<AlertDialog>
<AlertDialogTrigger
onClick={(event) => {
event.stopPropagation(); // Verhindert das Schließen des Dropdown-Menüs
}}
>
Eintrag Löschen
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Sind Sie sich sicher?</AlertDialogTitle>
<AlertDialogDescription>
Diese Aktion ist permanent und kann nicht rückgängig gemacht werden.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Abbrechen</AlertDialogCancel>
<AlertDialogAction
onClick={() => {
deleteEntry(item.id); // Eintrag löschen
}}
>
Löschen
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
</div>
);
}