diff --git a/ApiCore-Frontend/src/app/(app)/equipment/[id]/equipment-edit-dialog.tsx b/ApiCore-Frontend/src/app/(app)/equipment/[id]/equipment-edit-dialog.tsx new file mode 100644 index 0000000..19a062e --- /dev/null +++ b/ApiCore-Frontend/src/app/(app)/equipment/[id]/equipment-edit-dialog.tsx @@ -0,0 +1,211 @@ +"use client"; + +import { FormEvent, useState } from "react"; +import { Pencil } from "lucide-react"; +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { toast } from "sonner"; +import { updateEquipment } from "@/lib/equipment/api"; +import { Equipment, EquipmentCondition } from "@/lib/equipment/types"; +import { + EQUIPMENT_CONDITIONS, + EQUIPMENT_CONDITION_LABELS, +} from "@/lib/equipment/labels"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; + +/** + * Corrects every field of an inventory item. Only the condition used to be + * changeable, so a mistyped inventory number or a wrong purchase date stayed + * wrong for the life of the record. + */ +function EquipmentEditForm({ + equipment, + onSaved, +}: { + equipment: Equipment; + onSaved: () => void; +}) { + const queryClient = useQueryClient(); + const [inventoryNumber, setInventoryNumber] = useState( + equipment.inventoryNumber, + ); + const [name, setName] = useState(equipment.name); + const [manufacturer, setManufacturer] = useState(equipment.manufacturer ?? ""); + const [location, setLocation] = useState(equipment.location ?? ""); + const [purchaseDate, setPurchaseDate] = useState( + equipment.purchaseDate?.slice(0, 10) ?? "", + ); + const [maintenanceDate, setMaintenanceDate] = useState( + equipment.maintenanceDate?.slice(0, 10) ?? "", + ); + const [condition, setCondition] = useState( + equipment.condition, + ); + const [error, setError] = useState(null); + + const mutation = useMutation({ + mutationFn: () => + updateEquipment(equipment.id, { + inventoryNumber, + name, + manufacturer: manufacturer || undefined, + location: location || undefined, + purchaseDate: purchaseDate + ? new Date(purchaseDate).toISOString() + : undefined, + maintenanceDate: maintenanceDate + ? new Date(maintenanceDate).toISOString() + : undefined, + condition, + }), + onSuccess: () => { + void queryClient.invalidateQueries({ + queryKey: ["equipment", equipment.id], + }); + void queryClient.invalidateQueries({ queryKey: ["equipment"] }); + onSaved(); + }, + onError: (mutationError: Error) => { + const message = + mutationError.message || "Gegenstand konnte nicht gespeichert werden"; + setError(message); + toast.error(message); + }, + }); + + function handleSubmit(event: FormEvent) { + event.preventDefault(); + setError(null); + mutation.mutate(); + } + + return ( +
+
+ + setInventoryNumber(event.target.value)} + /> +
+
+ + setName(event.target.value)} + /> +
+
+ + setManufacturer(event.target.value)} + /> +
+
+ + setLocation(event.target.value)} + /> +
+
+
+ + setPurchaseDate(event.target.value)} + /> +
+
+ + setMaintenanceDate(event.target.value)} + /> +
+
+
+ + +
+ {error ? ( +

+ {error} +

+ ) : null} + +
+ ); +} + +export function EquipmentEditDialog({ equipment }: { equipment: Equipment }) { + const [open, setOpen] = useState(false); + + return ( + + + + Bearbeiten + + } + /> + + + Gegenstand bearbeiten + + {open ? ( + setOpen(false)} + /> + ) : null} + + + ); +} diff --git a/ApiCore-Frontend/src/app/(app)/equipment/[id]/page.tsx b/ApiCore-Frontend/src/app/(app)/equipment/[id]/page.tsx index 1f291bb..8fec8bb 100644 --- a/ApiCore-Frontend/src/app/(app)/equipment/[id]/page.tsx +++ b/ApiCore-Frontend/src/app/(app)/equipment/[id]/page.tsx @@ -5,6 +5,7 @@ import { Wrench } from "lucide-react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { toast } from "sonner"; import { fetchEquipment, updateEquipment } from "@/lib/equipment/api"; +import { EquipmentEditDialog } from "./equipment-edit-dialog"; import { EquipmentCondition } from "@/lib/equipment/types"; import { EQUIPMENT_CONDITIONS, EQUIPMENT_CONDITION_LABELS } from "@/lib/equipment/labels"; import { statusTone } from "@/lib/status-tone"; @@ -60,9 +61,12 @@ export default function EquipmentDetailPage() { {equipment.name} - - {EQUIPMENT_CONDITION_LABELS[equipment.condition]} - +
+ + {EQUIPMENT_CONDITION_LABELS[equipment.condition]} + + +

diff --git a/ApiCore-Frontend/src/app/(app)/products/edit-product-dialog.tsx b/ApiCore-Frontend/src/app/(app)/products/edit-product-dialog.tsx index 03e0827..36af6c4 100644 --- a/ApiCore-Frontend/src/app/(app)/products/edit-product-dialog.tsx +++ b/ApiCore-Frontend/src/app/(app)/products/edit-product-dialog.tsx @@ -5,11 +5,19 @@ import { Pencil } from "lucide-react"; import { useMutation, useQueryClient } from "@tanstack/react-query"; import { toast } from "sonner"; import { updateProduct } from "@/lib/products/api"; -import { Product } from "@/lib/products/types"; +import { Product, ProductStatus } from "@/lib/products/types"; +import { PRODUCT_STATUS_LABELS } from "@/lib/products/labels"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Textarea } from "@/components/ui/textarea"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { Dialog, DialogContent, @@ -28,6 +36,7 @@ export function EditProductDialog({ product }: { product: Product }) { const [packagingSize, setPackagingSize] = useState(product.packagingSize?.toString() ?? ""); const [weight, setWeight] = useState(product.weight?.toString() ?? ""); const [salesUnit, setSalesUnit] = useState(product.salesUnit ?? ""); + const [status, setStatus] = useState(product.status); const mutation = useMutation({ mutationFn: () => @@ -38,6 +47,7 @@ export function EditProductDialog({ product }: { product: Product }) { packagingSize: packagingSize ? Number(packagingSize) : undefined, weight: weight ? Number(weight) : undefined, salesUnit: salesUnit || undefined, + status, }), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: ["products"] }); @@ -111,6 +121,28 @@ export function EditProductDialog({ product }: { product: Product }) { onChange={(event) => setWeight(event.target.value)} /> +

+ + +
(null); + const { data: colonies } = useQuery({ + queryKey: ["colonies"], + queryFn: () => fetchColonies(), + }); + const mutation = useMutation({ mutationFn: () => updateQueenEvaluation(evaluation.id, { @@ -70,6 +90,8 @@ function EditEvaluationDialog({ swarmingTendency: Number(scores.swarmingTendency), broodPattern: Number(scores.broodPattern), honeyYield: Number(scores.honeyYield), + colonyId: colonyId === NO_COLONY ? undefined : colonyId, + notes: notes || undefined, }), onSuccess: () => { void queryClient.invalidateQueries({ @@ -136,6 +158,38 @@ function EditEvaluationDialog({ />
))} +
+ + +
+
+ +