feat(frontend): Abfuellungen und Produkte (Modul 23)

/products, /products/new, /bottling/new, /bottling/:id. Verbindung
von der Honigcharge-Detailseite zur Abfuellung, Nav-Dropdown "Mehr"
fuer alle Rollen mit Produkte/Abfuellungen erweitert.
This commit is contained in:
Nick Szaunig committed 2026-08-22 22:21:22 +02:00
1 parent e82cae257b
commit f4df719df7
11 files changed
+568 -18

No files matched your search

+24
View File
@@ -0,0 +1,24 @@
import { apiFetch } from "@/lib/auth/api-client";
import { BottlingBatch, BottlingBatchFilter, CreateBottlingBatchInput } from "./types";
export function fetchBottlingBatches(
filter: BottlingBatchFilter = {},
): Promise<BottlingBatch[]> {
const params = new URLSearchParams();
if (filter.honeyBatchId) params.set("honeyBatchId", filter.honeyBatchId);
const query = params.toString();
return apiFetch<BottlingBatch[]>(`/bottling-batches${query ? `?${query}` : ""}`);
}
export function fetchBottlingBatch(id: string): Promise<BottlingBatch> {
return apiFetch<BottlingBatch>(`/bottling-batches/${id}`);
}
export function createBottlingBatch(
input: CreateBottlingBatchInput,
): Promise<BottlingBatch> {
return apiFetch<BottlingBatch>("/bottling-batches", {
method: "POST",
body: JSON.stringify(input),
});
}
@@ -0,0 +1,28 @@
export interface BottlingBatch {
id: string;
honeyBatchId: string;
productId: string | null;
date: string;
jarSize: number;
jarCount: number;
totalAmount: number;
bestBeforeDate: string;
lotNumber: string;
createdAt: string;
honeyBatch: { id: string; batchNumber: string };
product: { id: string; name: string } | null;
}
export interface CreateBottlingBatchInput {
honeyBatchId: string;
productId?: string;
date: string;
jarSize: number;
jarCount: number;
bestBeforeDate: string;
lotNumber: string;
}
export interface BottlingBatchFilter {
honeyBatchId?: string;
}
+32
View File
@@ -0,0 +1,32 @@
import { apiFetch } from "@/lib/auth/api-client";
import {
CreateProductInput,
Product,
ProductFilter,
UpdateProductInput,
} from "./types";
export function fetchProducts(filter: ProductFilter = {}): Promise<Product[]> {
const params = new URLSearchParams();
if (filter.status) params.set("status", filter.status);
const query = params.toString();
return apiFetch<Product[]>(`/products${query ? `?${query}` : ""}`);
}
export function fetchProduct(id: string): Promise<Product> {
return apiFetch<Product>(`/products/${id}`);
}
export function createProduct(input: CreateProductInput): Promise<Product> {
return apiFetch<Product>("/products", {
method: "POST",
body: JSON.stringify(input),
});
}
export function updateProduct(id: string, input: UpdateProductInput): Promise<Product> {
return apiFetch<Product>(`/products/${id}`, {
method: "PATCH",
body: JSON.stringify(input),
});
}
@@ -0,0 +1,31 @@
export type ProductStatus = "ACTIVE" | "DISCONTINUED";
export interface Product {
id: string;
name: string;
description: string | null;
sku: string | null;
packagingSize: number | null;
weight: number | null;
salesUnit: string | null;
status: ProductStatus;
createdAt: string;
updatedAt: string;
}
export interface CreateProductInput {
name: string;
description?: string;
sku?: string;
packagingSize?: number;
weight?: number;
salesUnit?: string;
}
export interface UpdateProductInput extends Partial<CreateProductInput> {
status?: ProductStatus;
}
export interface ProductFilter {
status?: ProductStatus;
}