"use client"; import { useCallback, useState } from "react"; import { useRouter } from "next/navigation"; import { GameStructure, Resource, Structure } from "@/payload-types"; import { InventoryGrid } from "./InventoryGrid"; import { GridToolbar } from "./GridToolbar"; import { ResourceList } from "./ResourceList"; import { type GridItem } from "@/lib/logistics"; import { pluralize } from "@/lib/utils"; import { Item, ItemContent, ItemDescription, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, } from "@/components/ui/item"; import { AlertTriangleIcon, BrainIcon, DropletIcon, PackageOpenIcon, ZapIcon } from "lucide-react"; import { EventLedger } from "./EventLedger"; import { autoArrangeGrid, mergeGridStacks, moveGridItem, removeGridItem, removeResource, retrieveFromVoid, rotateGridItem, splitGridStack, } from "@/app/(frontend)/logistics/structures/actions"; function getResourceIcon(type: Resource["type"]) { switch (type) { case "fluid": return ; case "energy": return ; case "abstract": return ; default: return ; } } interface StructureStorageViewProps { structure: GameStructure & { type: Structure }; /** Rearranging/rotating/splitting conserves quantities — logistics personnel or superuser. */ canArrange?: boolean; /** Removing grid items / withdrawing destroys stored stock — superuser only. */ canMutate?: boolean; } export function StructureStorageView({ structure, canArrange = false, canMutate = false, }: StructureStorageViewProps) { const router = useRouter(); const [viewMode, setViewMode] = useState<"grid" | "list">("grid"); const [selectedItem, setSelectedItem] = useState(null); const [eventLogKey, setEventLogKey] = useState(0); const storedRaw = structure.storedResources ?? []; const gridWidth = structure.type.xSize ?? 0; const gridHeight = structure.type.ySize ?? 0; const hasGrid = gridWidth > 0 && gridHeight > 0; const storedResources: GridItem[] = storedRaw .filter((entry) => { const res = entry.resource as Resource; return res && typeof res === "object" && "id" in res; }) .map((entry) => ({ id: entry.id ?? `${(entry.resource as Resource).id}-${entry.gridX}-${entry.gridY}`, resourceId: (entry.resource as Resource).id, amount: entry.amount, gridX: entry.gridX ?? 0, gridY: entry.gridY ?? 0, rotated: entry.rotated ?? false, resource: entry.resource as Resource, })); const refresh = useCallback(() => { router.refresh(); setEventLogKey((k) => k + 1); }, [router]); const handleMoveItem = useCallback( async (entryId: string, gridX: number, gridY: number, rotated?: boolean) => { if (!canArrange) return; const result = await moveGridItem(structure.id, entryId, gridX, gridY, rotated); if (result.success) refresh(); }, [structure.id, refresh, canArrange], ); const handleMergeStacks = useCallback( async (sourceId: string, targetId: string) => { if (!canArrange) return; const result = await mergeGridStacks(structure.id, sourceId, targetId); if (result.success) refresh(); }, [structure.id, refresh, canArrange], ); const handleRotateItem = useCallback( async (entryId: string) => { if (!canArrange) return; const result = await rotateGridItem(structure.id, entryId); if (result.success) refresh(); }, [structure.id, refresh, canArrange], ); const handleRemoveItem = useCallback( async (entryId: string) => { if (!canMutate) return; const result = await removeGridItem(structure.id, entryId); if (result.success) { setSelectedItem(null); refresh(); } }, [structure.id, refresh, canMutate], ); const handleSplitStack = useCallback( async (entryId: string, amount: number) => { if (!canArrange) return; const result = await splitGridStack(structure.id, entryId, amount); if (result.success) refresh(); }, [structure.id, refresh, canArrange], ); const handleAutoArrange = useCallback(async () => { if (!canArrange) return; const result = await autoArrangeGrid(structure.id); if (result.success) refresh(); }, [structure.id, refresh, canArrange]); const handleWithdrawFromVoid = useCallback( async (resourceId: number, amount: number) => { if (!canMutate) return; const result = await removeResource(structure.id, resourceId, amount); if (result.success) refresh(); }, [structure.id, refresh, canMutate], ); const handleRetrieveFromVoid = useCallback(async () => { if (!canArrange) return; const result = await retrieveFromVoid(structure.id); if (result.success) refresh(); }, [structure.id, refresh, canArrange]); if (!hasGrid) { return ( ); } const voidStorageRaw = (structure as any).voidStorage ?? []; const voidStorageItems = voidStorageRaw .filter((entry: any) => { const res = entry.resource as Resource; return res && typeof res === "object" && "id" in res; }) .map((entry: any) => ({ id: entry.id ?? `${(entry.resource as Resource).id}-void`, resourceId: (entry.resource as Resource).id, amount: entry.amount, gridX: entry.gridX ?? 0, gridY: entry.gridY ?? 0, rotated: entry.rotated ?? false, resource: entry.resource as Resource, })); const hasVoidStorage = voidStorageItems.length > 0; return (
{viewMode === "grid" ? ( ) : ( )} {hasVoidStorage && ( Void Storage {voidStorageItems.length} item{voidStorageItems.length !== 1 ? "s" : ""}: these no longer fit in the grid. {canArrange && ( )}
{voidStorageItems.map((entry: any, index: number) => { const resource = entry.resource as Resource; if (!resource || typeof resource === "number") return null; const mass = (resource.massPerUnit ?? 0) * entry.amount; return (
{resource.icon ? ( {resource.name} ) : ( getResourceIcon(resource.type) )} {resource.name}
{entry.amount.toLocaleString()}{" "} {pluralize(entry.amount, resource.unitOfMeasure)}
{mass > 0 && `${mass.toLocaleString()} kg`}
{canMutate && ( )}
{index < voidStorageItems.length - 1 && }
); })}
)}
); }