1
0
Fork 0

fix(grid): prevent split collision by including source in overlap check

Server action: remove 'other.id === entryId' exclusion from the
split overlap scan so the source item's own footprint is treated
as occupied, forcing the split to find a different position.

UI: disable the split button via findEmptySpot check when no room
exists for the split stack, preventing a failed action.
This commit is contained in:
Jason Fraley 2026-07-28 14:51:56 -04:00
parent 256e5bd68a
commit d88fe04b56
3 changed files with 7 additions and 3 deletions

View file

@ -737,7 +737,7 @@ export async function splitGridStack(
let overlaps = false; let overlaps = false;
for (const other of existing) { for (const other of existing) {
if (other.id === entryId || other.id == null) continue; if (other.id == null) continue;
const otherRes = other.resource as Resource; const otherRes = other.resource as Resource;
if (!otherRes || typeof otherRes === "number") continue; if (!otherRes || typeof otherRes === "number") continue;
const otherRotated = other.rotated ?? false; const otherRotated = other.rotated ?? false;

View file

@ -9,7 +9,7 @@ import {
LayoutGridIcon, LayoutGridIcon,
ListIcon, ListIcon,
} from "lucide-react"; } from "lucide-react";
import { GridItem, getItemFootprint, getGridOccupancy } from "@/lib/logistics"; import { GridItem, getItemFootprint, getGridOccupancy, findEmptySpot } from "@/lib/logistics";
import { Resource } from "@/payload-types"; import { Resource } from "@/payload-types";
import { cn, pluralize } from "@/lib/utils"; import { cn, pluralize } from "@/lib/utils";
@ -41,6 +41,9 @@ export function GridToolbar({
const occupancy = getGridOccupancy(storedResources, gridWidth, gridHeight); const occupancy = getGridOccupancy(storedResources, gridWidth, gridHeight);
const res = selectedItem ? (selectedItem.resource as Resource) : null; const res = selectedItem ? (selectedItem.resource as Resource) : null;
const fp = res ? getItemFootprint(res, selectedItem!.rotated) : null; const fp = res ? getItemFootprint(res, selectedItem!.rotated) : null;
const canSplit = selectedItem && res && fp
? findEmptySpot(storedResources, fp.width, fp.height, gridWidth, gridHeight) !== null
: false;
return ( return (
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3">
@ -94,6 +97,7 @@ export function GridToolbar({
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
disabled={!canSplit}
onClick={() => onSplit(selectedItem.id, Math.floor(selectedItem.amount / 2))} onClick={() => onSplit(selectedItem.id, Math.floor(selectedItem.amount / 2))}
> >
<ScissorsIcon className="size-3.5" /> <ScissorsIcon className="size-3.5" />

View file

@ -46,7 +46,7 @@ export function StructureCard({ structure }: StructureCardProps) {
return ( return (
<Link href={`/logistics/structures/${structure.id}`}> <Link href={`/logistics/structures/${structure.id}`}>
<Item variant="outline" className="cursor-pointer group transition-all duration-200 hover:scale-[1.01] hover:[box-shadow:inset_0_2px_8px_rgba(255,255,255,0.12)]"> <Item variant="outline" className="cursor-pointer group transition-all duration-200 hover:scale-[1.01] hover:[box-shadow:inset_0_2px_8px_rgba(255,255,255,0.33)]">
<ItemHeader> <ItemHeader>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<ItemMedia variant="icon"> <ItemMedia variant="icon">