feat(ui): raw material lots and production inputs

- Pages for raw material lots (beeswax, propolis): list, create in grams
  with optional apiary, detail with stock card (harvested / used in
  production / withdrawn / remaining) and "used in" batches.
- Production batch form takes the raw material used (lot + grams) and the
  batch page shows what it was made from - traceability both ways.
- Sidebar entry "Rohstoffe".
- Removes backend files that were committed into ApiCore-Frontend/src by
  mistake in e52a605 (copies of ApiCore-Backend/src/raw-materials).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
Nick SzaunigandClaude Opus 5.5 committed 2026-10-06 06:31:07 +02:00
1 parent f9899d5621
commit 569a43d247
22 files changed
+803 -412

No files matched your search

+25 -4
View File
@@ -9,6 +9,7 @@ import {
Database,
Droplet,
Factory,
Boxes,
FileClock,
FlaskConical,
Hexagon,
@@ -82,6 +83,12 @@ const NAV_GROUPS: NavGroup[] = [
{ label: "Schleuderungen", href: "/extractions", icon: FlaskConical },
{ label: "Honigchargen", href: "/honey-batches", icon: Droplet },
{ label: "Abfüllungen", href: "/bottling", icon: Package },
{
label: "Rohstoffe",
href: "/raw-materials",
icon: Boxes,
permission: "raw-material:read",
},
{
label: "Herstellungschargen",
href: "/production-batches",
@@ -128,7 +135,12 @@ const ADMIN_GROUP: NavGroup = {
icon: Database,
permission: ["backup:export", "backup:import", "import:execute"],
},
{ label: "Audit-Log", href: "/settings/audit-log", icon: History, permission: "audit:read" },
{
label: "Audit-Log",
href: "/settings/audit-log",
icon: History,
permission: "audit:read",
},
],
};
@@ -157,7 +169,10 @@ function SidebarLink({ item, pathname }: { item: NavItem; pathname: string }) {
);
}
function hasNavPermission(user: AuthUser, permission: NavItem["permission"]): boolean {
function hasNavPermission(
user: AuthUser,
permission: NavItem["permission"],
): boolean {
if (!permission) {
return true;
}
@@ -185,13 +200,19 @@ export function Sidebar({ user }: { user: AuthUser }) {
className="flex size-8 items-center justify-center rounded-xl shadow-[var(--shadow-soft)]"
style={{ background: "var(--gradient-honey)" }}
>
<Hexagon className="size-4.5 fill-white/25 text-white" strokeWidth={2.25} />
<Hexagon
className="size-4.5 fill-white/25 text-white"
strokeWidth={2.25}
/>
</span>
ApiCore
</Link>
<nav className="flex flex-1 flex-col gap-5">
{groups.map((group, index) => (
<div key={group.label ?? `group-${index}`} className="flex flex-col gap-0.5">
<div
key={group.label ?? `group-${index}`}
className="flex flex-col gap-0.5"
>
{group.label ? (
<p className="px-3 pb-1 text-xs font-semibold tracking-wide text-muted-foreground/80 uppercase">
{group.label}