init
This commit is contained in:
44
frontend/app/dashboard/generateFlaechendruck/action.ts
Normal file
44
frontend/app/dashboard/generateFlaechendruck/action.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
"use server";
|
||||
//import { promises as fs } from "fs";
|
||||
const apiUrl = process.env.NEXT_SERVER_API_URL;
|
||||
//const sharedFolder = process.env.SHARED_FOLDER;
|
||||
|
||||
export async function getVorlagen() {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${apiUrl}/vorlageFlaechendruck/getAllFlaechendruckVorlagen`
|
||||
);
|
||||
if (!response.ok) {
|
||||
console.error("Response status:", response.status);
|
||||
throw new Error("Failed to fetch vorlagen");
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error fetching vorlagen:", error);
|
||||
throw new Error("An error occurred while fetching vorlagen.");
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateFlaechendruck(formData: FormData) {
|
||||
const vorlageIds = formData.getAll("vorlageIds") as string[];
|
||||
const requestBody = {
|
||||
rootDirectory: "Orders",
|
||||
vorlageIds: vorlageIds,
|
||||
};
|
||||
|
||||
const response = await fetch(`${apiUrl}/vorlageFlaechendruck/generate`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
cache: "no-store",
|
||||
});
|
||||
if (!response.ok) {
|
||||
const body = await response.text().catch(() => null);
|
||||
const msg = body ? body : `HTTP ${response.status}`;
|
||||
return { message: msg, status: false };
|
||||
} else {
|
||||
return { message: "Erfolgreiche Flächendruckgenerierung!", status: true };
|
||||
}
|
||||
}
|
||||
173
frontend/app/dashboard/generateFlaechendruck/page.tsx
Normal file
173
frontend/app/dashboard/generateFlaechendruck/page.tsx
Normal file
@@ -0,0 +1,173 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { getVorlagen, generateFlaechendruck } from "./action";
|
||||
import { toast, Bounce } from "react-toastify";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Label } from "@/components/ui/label";
|
||||
|
||||
export default function Page() {
|
||||
const [vorlagen, setVorlagen] = useState<
|
||||
{ id: number; name: string; printer: string }[]
|
||||
>([]);
|
||||
const [selectedVorlagen, setSelectedVorlagen] = useState<number[]>([]);
|
||||
const [isUploading, setIsUploading] = useState(false); // Zustand für den Upload
|
||||
|
||||
// API-Aufruf, um Vorlagen zu laden
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
try {
|
||||
const data = await getVorlagen(); // Server-Action aufrufen
|
||||
setVorlagen(
|
||||
data.map(
|
||||
(item: { id: number; product_type: string; printer: string }) => ({
|
||||
id: item.id,
|
||||
name: item.product_type,
|
||||
printer: item.printer,
|
||||
})
|
||||
)
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (selectedVorlagen.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
selectedVorlagen.forEach((id) => {
|
||||
formData.append("vorlageIds", id.toString());
|
||||
});
|
||||
setIsUploading(true);
|
||||
const res = await generateFlaechendruck(formData);
|
||||
if (res.status) {
|
||||
toast.success(res.message, {
|
||||
position: "bottom-right",
|
||||
autoClose: 5000,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: false,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
theme: "light",
|
||||
transition: Bounce,
|
||||
});
|
||||
} else {
|
||||
toast.error(res.message, {
|
||||
position: "bottom-right",
|
||||
autoClose: 5000,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: false,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
theme: "light",
|
||||
transition: Bounce,
|
||||
});
|
||||
}
|
||||
|
||||
setIsUploading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 flex items-center justify-center">
|
||||
<>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>Generierung Flächendruck</CardTitle>
|
||||
<CardDescription>
|
||||
Wählen sie Vorlagen zur Generierung aus.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
{!isUploading ? (
|
||||
<div className="grid w-full items-center gap-4">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<Label htmlFor="framework" className="mb-4">
|
||||
Vorlagen
|
||||
</Label>
|
||||
<div className="flex flex-col space-y-2">
|
||||
{vorlagen.map((vorlage) => (
|
||||
<div
|
||||
key={vorlage.id}
|
||||
className="flex items-start space-x-2"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`vorlage-${vorlage.id}`}
|
||||
value={vorlage.id}
|
||||
onChange={(e) => {
|
||||
const id = parseInt(e.target.value, 10);
|
||||
if (e.target.checked) {
|
||||
setSelectedVorlagen((prev) => [...prev, id]);
|
||||
} else {
|
||||
setSelectedVorlagen((prev) =>
|
||||
prev.filter((v) => v !== id)
|
||||
);
|
||||
}
|
||||
}}
|
||||
className="mt-1"
|
||||
/>
|
||||
<label
|
||||
htmlFor={`vorlage-${vorlage.id}`}
|
||||
className="text-gray-700"
|
||||
>
|
||||
Printer: {vorlage.printer} - {vorlage.name}
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center w-full h-32">
|
||||
<div role="status">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="w-20 h-20 text-gray-200 animate-spin dark:text-gray-600 fill-black"
|
||||
viewBox="0 0 100 101"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
<CardFooter className="flex justify-between">
|
||||
{!isUploading ? <Button type="submit">Start</Button> : null}
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</form>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
45
frontend/app/dashboard/generateRollendruck/action.ts
Normal file
45
frontend/app/dashboard/generateRollendruck/action.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
"use server";
|
||||
//import { promises as fs } from "fs";
|
||||
const apiUrl = process.env.NEXT_SERVER_API_URL;
|
||||
//const sharedFolder = process.env.SHARED_FOLDER;
|
||||
|
||||
export async function getVorlagen() {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${apiUrl}/VorlageRollenDruck/getAllRollendruckVorlagen`
|
||||
);
|
||||
if (!response.ok) {
|
||||
console.error("Response status:", response.status);
|
||||
throw new Error("Failed to fetch vorlagen");
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error("Error fetching vorlagen:", error);
|
||||
throw new Error("An error occurred while fetching vorlagen.");
|
||||
}
|
||||
}
|
||||
|
||||
export async function uploadFiles(formData: FormData) {
|
||||
const vorlageIds = formData.getAll("vorlageIds") as string[];
|
||||
|
||||
// JSON-Daten erstellen
|
||||
const requestBody = {
|
||||
rootDirectory: "Rollendruck",
|
||||
vorlageIds: vorlageIds,
|
||||
};
|
||||
const response = await fetch(`${apiUrl}/VorlageRollenDruck/generate`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(requestBody),
|
||||
cache: "no-store",
|
||||
});
|
||||
if (!response.ok) {
|
||||
const body = await response.text().catch(() => null);
|
||||
const msg = body ? body : `HTTP ${response.status}`;
|
||||
return { message: msg, status: false };
|
||||
} else {
|
||||
return { message: "Erfolgreiche Rollendruckgenerierung!", status: true };
|
||||
}
|
||||
}
|
||||
180
frontend/app/dashboard/generateRollendruck/page.tsx
Normal file
180
frontend/app/dashboard/generateRollendruck/page.tsx
Normal file
@@ -0,0 +1,180 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { getVorlagen, uploadFiles } from "./action";
|
||||
import { toast, Bounce } from "react-toastify";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Label } from "@/components/ui/label";
|
||||
|
||||
export default function Page() {
|
||||
const [vorlagen, setVorlagen] = useState<
|
||||
{ id: number; printer: string; height: number; width: number }[]
|
||||
>([]);
|
||||
const [selectedVorlagen, setSelectedVorlagen] = useState<number[]>([]);
|
||||
const [isUploading, setIsUploading] = useState(false); // Zustand für den Upload
|
||||
|
||||
// API-Aufruf, um Vorlagen zu laden
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
try {
|
||||
const data = await getVorlagen(); // Server-Action aufrufen
|
||||
setVorlagen(
|
||||
data.map(
|
||||
(item: {
|
||||
id: number;
|
||||
printer: string;
|
||||
height: number;
|
||||
width: number;
|
||||
}) => ({
|
||||
id: item.id,
|
||||
printer: item.printer,
|
||||
height: item.height,
|
||||
width: item.width,
|
||||
})
|
||||
)
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("Error fetching vorlagen:", err);
|
||||
}
|
||||
}
|
||||
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (selectedVorlagen.length === 0) {
|
||||
alert("Please select at least one Vorlage before submitting.");
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
selectedVorlagen.forEach((id) => {
|
||||
formData.append("vorlageIds", id.toString()); // Fügt die ausgewählten Vorlagen-IDs hinzu
|
||||
});
|
||||
setIsUploading(true);
|
||||
const res = await uploadFiles(formData);
|
||||
if (res.status) {
|
||||
toast.success(res.message, {
|
||||
position: "bottom-right",
|
||||
autoClose: 5000,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: false,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
theme: "light",
|
||||
transition: Bounce,
|
||||
});
|
||||
} else {
|
||||
toast.error(res.message, {
|
||||
position: "bottom-right",
|
||||
autoClose: 5000,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: false,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
theme: "light",
|
||||
transition: Bounce,
|
||||
});
|
||||
}
|
||||
setIsUploading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-100 flex items-center justify-center">
|
||||
<>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<Card className="w-[350px]">
|
||||
<CardHeader>
|
||||
<CardTitle>Generierung Rollendruck</CardTitle>
|
||||
<CardDescription>
|
||||
Wählen sie Vorlagen zur Generierung aus.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
{!isUploading ? (
|
||||
<div className="grid w-full items-center gap-4">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<Label htmlFor="framework" className="mb-4">
|
||||
Vorlagen
|
||||
</Label>
|
||||
<div className="flex flex-col space-y-2">
|
||||
{vorlagen.map((vorlage) => (
|
||||
<div
|
||||
key={vorlage.id}
|
||||
className="flex items-start space-x-2"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`vorlage-${vorlage.id}`}
|
||||
value={vorlage.id}
|
||||
onChange={(e) => {
|
||||
const id = parseInt(e.target.value, 10);
|
||||
if (e.target.checked) {
|
||||
setSelectedVorlagen((prev) => [...prev, id]);
|
||||
} else {
|
||||
setSelectedVorlagen((prev) =>
|
||||
prev.filter((v) => v !== id)
|
||||
);
|
||||
}
|
||||
}}
|
||||
className="mt-1"
|
||||
/>
|
||||
<label
|
||||
htmlFor={`vorlage-${vorlage.id}`}
|
||||
className="text-gray-700"
|
||||
>
|
||||
Printer: {vorlage.printer} - {vorlage.height}mm x{" "}
|
||||
{vorlage.width}mm
|
||||
</label>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center w-full h-32">
|
||||
<div role="status">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="w-20 h-20 text-gray-200 animate-spin dark:text-gray-600 fill-black"
|
||||
viewBox="0 0 100 101"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
<CardFooter className="flex justify-between">
|
||||
{!isUploading ? <Button type="submit">Start</Button> : null}
|
||||
</CardFooter>
|
||||
</Card>
|
||||
</form>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
13
frontend/app/dashboard/layout.tsx
Normal file
13
frontend/app/dashboard/layout.tsx
Normal file
@@ -0,0 +1,13 @@
|
||||
import AdminPanelLayout from "@/components/admin-panel/admin-panel-layout";
|
||||
|
||||
export default function DashboardLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<AdminPanelLayout>
|
||||
<main>{children}</main>
|
||||
</AdminPanelLayout>
|
||||
);
|
||||
}
|
||||
14
frontend/app/dashboard/page.tsx
Normal file
14
frontend/app/dashboard/page.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
export default function Page() {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100 text-gray-800">
|
||||
<div className="bg-white shadow-md rounded-lg p-8 max-w-lg text-center">
|
||||
<h1 className="text-2xl font-bold mb-4 text-gray-900">
|
||||
Willkommen im Dashboard
|
||||
</h1>
|
||||
<h2 className="text-lg text-gray-600">
|
||||
Navigieren Sie über das Menü auf der linken Seite zu den Anwendungen.
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
9
frontend/app/dashboard/updateOrders/page.tsx
Normal file
9
frontend/app/dashboard/updateOrders/page.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import UploadForm from "@/components/upload-form/page";
|
||||
|
||||
export default async function Home() {
|
||||
return (
|
||||
<main>
|
||||
<UploadForm />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
42
frontend/app/dashboard/vorlagenFlaechendruck/action.ts
Normal file
42
frontend/app/dashboard/vorlagenFlaechendruck/action.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
"use server";
|
||||
|
||||
const apiUrl = process.env.NEXT_SERVER_API_URL;
|
||||
|
||||
export async function getTableData() {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${apiUrl}/vorlageFlaechendruck/getAllFlaechendruckVorlagen`
|
||||
);
|
||||
if (!res.ok) {
|
||||
console.error("Response status:", res.status);
|
||||
}
|
||||
|
||||
const data: {
|
||||
id: number;
|
||||
product_type: string;
|
||||
height: number;
|
||||
width: number;
|
||||
printer: string;
|
||||
coordinates: {
|
||||
x: number;
|
||||
y: number;
|
||||
rotation: number;
|
||||
}[];
|
||||
}[] = 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 deleteVorlageFlaechendruck(id: number) {
|
||||
const res = await fetch(`${apiUrl}/vorlageFlaechendruck/delete/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error("Failed to delete item");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
"use server";
|
||||
|
||||
const apiUrl = process.env.NEXT_SERVER_API_URL;
|
||||
|
||||
export async function createVorlage(formData: FormData) {
|
||||
const printer = formData.get("printer") as string;
|
||||
const product_type = formData.get("product_type") as string;
|
||||
const height = Number(formData.get("height"));
|
||||
const width = Number(formData.get("width"));
|
||||
const coordinatesJson = formData.get("coordinates") as string;
|
||||
const coordinates = JSON.parse(coordinatesJson);
|
||||
|
||||
const payload = {
|
||||
printer,
|
||||
product_type,
|
||||
height,
|
||||
width,
|
||||
coordinates,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${apiUrl}/vorlageFlaechendruck/createWithCoordinates`,
|
||||
{
|
||||
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 product_type = formData.get("product_type") as string;
|
||||
const height = Number(formData.get("height"));
|
||||
const width = Number(formData.get("width"));
|
||||
const coordinatesJson = formData.get("coordinates") as string;
|
||||
const coordinates = JSON.parse(coordinatesJson);
|
||||
|
||||
const payload = {
|
||||
id,
|
||||
printer,
|
||||
product_type,
|
||||
height,
|
||||
width,
|
||||
coordinates,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
`${apiUrl}/vorlageFlaechendruck/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.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
"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 { Separator } from "@/components/ui/separator";
|
||||
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
|
||||
import { useFieldArray } from "react-hook-form";
|
||||
|
||||
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.",
|
||||
}),
|
||||
Artikeltyp: z.string().min(1, {
|
||||
message: "Artikeltyp 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.",
|
||||
})
|
||||
),
|
||||
Koordinaten: z.array(
|
||||
z.object({
|
||||
x: z.preprocess(
|
||||
(value) => (typeof value === "string" ? parseFloat(value) : value),
|
||||
z.number().min(0, {
|
||||
message: "X-Koordinate muss mindestens 0 sein.",
|
||||
})
|
||||
),
|
||||
y: z.preprocess(
|
||||
(value) => (typeof value === "string" ? parseFloat(value) : value),
|
||||
z.number().min(0, {
|
||||
message: "Y-Koordinate muss mindestens 0 sein.",
|
||||
})
|
||||
),
|
||||
rotation: z.preprocess(
|
||||
(value) => (typeof value === "string" ? parseFloat(value) : value),
|
||||
z.number().min(0, {
|
||||
message: "Rotation muss mindestens 0 sein.",
|
||||
})
|
||||
),
|
||||
})
|
||||
).min(1, {
|
||||
message: "Es muss mindestens eine Koordinate angegeben werden.",
|
||||
}),
|
||||
});
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
Drucker: "",
|
||||
Artikeltyp: "",
|
||||
Höhe: 0,
|
||||
Breite: 0,
|
||||
Koordinaten: [{ x: 0, y: 0, rotation: 0 }],
|
||||
},
|
||||
});
|
||||
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
control: form.control,
|
||||
name: "Koordinaten",
|
||||
});
|
||||
|
||||
async function onSubmit(values: z.infer<typeof formSchema>) {
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append("printer", values.Drucker);
|
||||
formData.append("product_type", values.Artikeltyp);
|
||||
formData.append("height", values.Höhe.toString());
|
||||
formData.append("width", values.Breite.toString());
|
||||
formData.append("coordinates", JSON.stringify(values.Koordinaten));
|
||||
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="Artikeltyp"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Artikel Typ</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<DialogDescription>
|
||||
Der Name des Artikels, der auf der 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>
|
||||
)}
|
||||
/>
|
||||
<div className="max-h-64 overflow-y-auto">
|
||||
<FormLabel className="mb-4">Koordinaten:</FormLabel>
|
||||
<Separator />
|
||||
{fields.map((field, index) => (
|
||||
<div key={field.id} className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`Koordinaten.${index}.x`}
|
||||
|
||||
render={({ field }) => (
|
||||
<FormItem className="mt-4">
|
||||
<FormLabel>X-Koordinate</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" step="any" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`Koordinaten.${index}.y`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Y-Koordinate</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" step="any" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`Koordinaten.${index}.rotation`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Rotation</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" step="any" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
onClick={() => remove(index)}
|
||||
>
|
||||
Entfernen
|
||||
</Button>
|
||||
<Separator className="mt-4" />
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => append({ x: 0, y: 0, rotation: 0 })}
|
||||
className="mt-4"
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="submit">
|
||||
Hinzufügen
|
||||
</Button>
|
||||
|
||||
</form>
|
||||
</Form>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
"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 { Separator } from "@/components/ui/separator";
|
||||
|
||||
import { Plus } from "lucide-react";
|
||||
|
||||
|
||||
import { useFieldArray } from "react-hook-form";
|
||||
|
||||
import { alterVorlage } from "./action";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
type TableData = {
|
||||
id: number;
|
||||
product_type: string;
|
||||
height: number;
|
||||
width: number;
|
||||
printer: string;
|
||||
coordinates: { x: number; y: number; rotation: number }[];
|
||||
};
|
||||
|
||||
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.",
|
||||
}),
|
||||
Artikeltyp: z.string().min(1, {
|
||||
message: "Artikeltyp 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.",
|
||||
})
|
||||
),
|
||||
Koordinaten: z.array(
|
||||
z.object({
|
||||
x: z.preprocess(
|
||||
(value) => (typeof value === "string" ? parseFloat(value) : value),
|
||||
z.number().min(0, {
|
||||
message: "X-Koordinate muss mindestens 0 sein.",
|
||||
})
|
||||
),
|
||||
y: z.preprocess(
|
||||
(value) => (typeof value === "string" ? parseFloat(value) : value),
|
||||
z.number().min(0, {
|
||||
message: "Y-Koordinate muss mindestens 0 sein.",
|
||||
})
|
||||
),
|
||||
rotation: z.preprocess(
|
||||
(value) => (typeof value === "string" ? parseFloat(value) : value),
|
||||
z.number().min(0, {
|
||||
message: "Rotation muss mindestens 0 sein.",
|
||||
})
|
||||
),
|
||||
})
|
||||
).min(1, {
|
||||
message: "Es muss mindestens eine Koordinate angegeben werden.",
|
||||
}),
|
||||
});
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
Drucker: data.printer,
|
||||
Artikeltyp: data.product_type,
|
||||
Höhe: data.height,
|
||||
Breite: data.width,
|
||||
Koordinaten: data.coordinates.map((coord) => ({
|
||||
x: coord.x,
|
||||
y: coord.y,
|
||||
rotation: coord.rotation,
|
||||
})),
|
||||
},
|
||||
});
|
||||
|
||||
const { fields, append, remove } = useFieldArray({
|
||||
control: form.control,
|
||||
name: "Koordinaten",
|
||||
});
|
||||
|
||||
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("product_type", values.Artikeltyp);
|
||||
formData.append("height", values.Höhe.toString());
|
||||
formData.append("width", values.Breite.toString());
|
||||
formData.append("coordinates", JSON.stringify(values.Koordinaten));
|
||||
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="Artikeltyp"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Artikel Typ</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<DialogDescription>
|
||||
Der Name des Artikels, der auf der 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>
|
||||
)}
|
||||
/>
|
||||
<div className="max-h-64 overflow-y-auto">
|
||||
<FormLabel className="mb-4">Koordinaten:</FormLabel>
|
||||
<Separator />
|
||||
{fields.map((field, index) => (
|
||||
<div key={field.id} className="space-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`Koordinaten.${index}.x`}
|
||||
|
||||
render={({ field }) => (
|
||||
<FormItem className="mt-4">
|
||||
<FormLabel>X-Koordinate</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" step="any" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`Koordinaten.${index}.y`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Y-Koordinate</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" step="any" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`Koordinaten.${index}.rotation`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Rotation</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="number" step="any" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
onClick={() => remove(index)}
|
||||
>
|
||||
Entfernen
|
||||
</Button>
|
||||
<Separator className="mt-4" />
|
||||
</div>
|
||||
))}
|
||||
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => append({ x: 0, y: 0, rotation: 0 })}
|
||||
className="mt-4"
|
||||
>
|
||||
<Plus />
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="submit">
|
||||
Änderungen speichern
|
||||
</Button>
|
||||
|
||||
</form>
|
||||
</Form>
|
||||
</DialogHeader>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
199
frontend/app/dashboard/vorlagenFlaechendruck/page.tsx
Normal file
199
frontend/app/dashboard/vorlagenFlaechendruck/page.tsx
Normal file
@@ -0,0 +1,199 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { Ellipsis } from "lucide-react"
|
||||
import { getTableData, deleteVorlageFlaechendruck } from "./action";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCaption,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog"
|
||||
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 AddDialog from "./components/addDialog";
|
||||
import AlterDialog from "./components/alterDialog";
|
||||
|
||||
type TableData = {
|
||||
id: number;
|
||||
product_type: string;
|
||||
height: number;
|
||||
width: number;
|
||||
printer: string;
|
||||
coordinates: { x: number; y: number; rotation: number }[];
|
||||
};
|
||||
export default function Page() {
|
||||
const [data, setData] = useState<TableData[]>([]);
|
||||
useEffect(() => {
|
||||
async function fetchData() {
|
||||
try {
|
||||
const result = await getTableData();
|
||||
setData(result);
|
||||
} 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 deleteEntry = async (id: number) => {
|
||||
try {
|
||||
await deleteVorlageFlaechendruck(id);
|
||||
await handleNewEntry();
|
||||
}
|
||||
catch (error) {
|
||||
console.error("Fehler beim Löschen der Daten:", error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 p-6">
|
||||
<div className="max-w-5xl mx-auto">
|
||||
{/* Table Section */}
|
||||
<Table className="bg-white shadow-md border border-gray-300">
|
||||
<TableCaption>Vorlagen Flächendruck</TableCaption>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead className="w-[100px]">Drucker</TableHead>
|
||||
<TableHead>Artikel Typ</TableHead>
|
||||
<TableHead>Höhe</TableHead>
|
||||
<TableHead>Breite</TableHead>
|
||||
<TableHead>Koordinaten</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.product_type}</TableCell>
|
||||
<TableCell>{item.height}</TableCell>
|
||||
<TableCell >{item.width}</TableCell>
|
||||
<TableCell>
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<Button variant="outline">Anzeigen</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Koordinaten</DialogTitle>
|
||||
<DialogDescription>
|
||||
Hier sind die Koordinaten für die ausgewählte Vorlage. X und Y Werte in Millimetern.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<Table>
|
||||
<TableCaption>Koordinaten Tabelle</TableCaption>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>X</TableHead>
|
||||
<TableHead>Y</TableHead>
|
||||
<TableHead className="text-right">Rotation</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{item.coordinates.map((coordi) => (
|
||||
<TableRow key={crypto.randomUUID()}>
|
||||
<TableCell>{coordi.x}</TableCell>
|
||||
<TableCell>{coordi.y}</TableCell>
|
||||
<TableCell className="text-right">{coordi.rotation}°</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</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>
|
||||
);
|
||||
}
|
||||
69
frontend/app/dashboard/vorlagenRollendruck/action.ts
Normal file
69
frontend/app/dashboard/vorlagenRollendruck/action.ts
Normal 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;
|
||||
}
|
||||
107
frontend/app/dashboard/vorlagenRollendruck/components/action.ts
Normal file
107
frontend/app/dashboard/vorlagenRollendruck/components/action.ts
Normal 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.");
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
227
frontend/app/dashboard/vorlagenRollendruck/page.tsx
Normal file
227
frontend/app/dashboard/vorlagenRollendruck/page.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
BIN
frontend/app/favicon.ico
Normal file
BIN
frontend/app/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 25 KiB |
122
frontend/app/globals.css
Normal file
122
frontend/app/globals.css
Normal file
@@ -0,0 +1,122 @@
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
|
||||
@theme inline {
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--font-sans: var(--font-geist-sans);
|
||||
--font-mono: var(--font-geist-mono);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-ring: var(--ring);
|
||||
--color-input: var(--input);
|
||||
--color-border: var(--border);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-card: var(--card);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius) + 4px);
|
||||
}
|
||||
|
||||
:root {
|
||||
--radius: 0.625rem;
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.147 0.004 49.25);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.147 0.004 49.25);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.147 0.004 49.25);
|
||||
--primary: oklch(0.216 0.006 56.043);
|
||||
--primary-foreground: oklch(0.985 0.001 106.423);
|
||||
--secondary: oklch(0.97 0.001 106.424);
|
||||
--secondary-foreground: oklch(0.216 0.006 56.043);
|
||||
--muted: oklch(0.97 0.001 106.424);
|
||||
--muted-foreground: oklch(0.553 0.013 58.071);
|
||||
--accent: oklch(0.97 0.001 106.424);
|
||||
--accent-foreground: oklch(0.216 0.006 56.043);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.923 0.003 48.717);
|
||||
--input: oklch(0.923 0.003 48.717);
|
||||
--ring: oklch(0.709 0.01 56.259);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.985 0.001 106.423);
|
||||
--sidebar-foreground: oklch(0.147 0.004 49.25);
|
||||
--sidebar-primary: oklch(0.216 0.006 56.043);
|
||||
--sidebar-primary-foreground: oklch(0.985 0.001 106.423);
|
||||
--sidebar-accent: oklch(0.97 0.001 106.424);
|
||||
--sidebar-accent-foreground: oklch(0.216 0.006 56.043);
|
||||
--sidebar-border: oklch(0.923 0.003 48.717);
|
||||
--sidebar-ring: oklch(0.709 0.01 56.259);
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: oklch(0.147 0.004 49.25);
|
||||
--foreground: oklch(0.985 0.001 106.423);
|
||||
--card: oklch(0.216 0.006 56.043);
|
||||
--card-foreground: oklch(0.985 0.001 106.423);
|
||||
--popover: oklch(0.216 0.006 56.043);
|
||||
--popover-foreground: oklch(0.985 0.001 106.423);
|
||||
--primary: oklch(0.923 0.003 48.717);
|
||||
--primary-foreground: oklch(0.216 0.006 56.043);
|
||||
--secondary: oklch(0.268 0.007 34.298);
|
||||
--secondary-foreground: oklch(0.985 0.001 106.423);
|
||||
--muted: oklch(0.268 0.007 34.298);
|
||||
--muted-foreground: oklch(0.709 0.01 56.259);
|
||||
--accent: oklch(0.268 0.007 34.298);
|
||||
--accent-foreground: oklch(0.985 0.001 106.423);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 15%);
|
||||
--ring: oklch(0.553 0.013 58.071);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.216 0.006 56.043);
|
||||
--sidebar-foreground: oklch(0.985 0.001 106.423);
|
||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
||||
--sidebar-primary-foreground: oklch(0.985 0.001 106.423);
|
||||
--sidebar-accent: oklch(0.268 0.007 34.298);
|
||||
--sidebar-accent-foreground: oklch(0.985 0.001 106.423);
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.553 0.013 58.071);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border outline-ring/50;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
}
|
||||
}
|
||||
49
frontend/app/layout.tsx
Normal file
49
frontend/app/layout.tsx
Normal file
@@ -0,0 +1,49 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Geist, Geist_Mono } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
import { ToastContainer, Bounce } from "react-toastify";
|
||||
|
||||
const geistSans = Geist({
|
||||
variable: "--font-geist-sans",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
const geistMono = Geist_Mono({
|
||||
variable: "--font-geist-mono",
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "ERP - Wolga Kreativ",
|
||||
description: "Wolga ERP",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<body
|
||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||
>
|
||||
<ToastContainer
|
||||
position="bottom-right"
|
||||
autoClose={5000}
|
||||
hideProgressBar={false}
|
||||
newestOnTop={false}
|
||||
closeOnClick={false}
|
||||
rtl={false}
|
||||
pauseOnFocusLoss
|
||||
draggable
|
||||
pauseOnHover
|
||||
theme="light"
|
||||
transition={Bounce}
|
||||
/>
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
9
frontend/app/login/page.tsx
Normal file
9
frontend/app/login/page.tsx
Normal file
@@ -0,0 +1,9 @@
|
||||
import SignInPage from "@/components/auth/signin-form";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<>
|
||||
<SignInPage></SignInPage>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user