From fc27f11ab8b6e66375529b2c24f0f422f723edce Mon Sep 17 00:00:00 2001 From: Z8MB1E Date: Sun, 2 Aug 2026 19:00:05 -0400 Subject: [PATCH] fix(locker): revert to onClick and add error feedback to slot picker - Revert onPointerDown back to onClick for item selection - Add error state to display server action failures to user - Add pending state to disable buttons during submission - Update onPick to return ActionResult for error handling --- .../frontend/locker/WardrobePanel.tsx | 3 +- .../frontend/locker/WardrobeSlotPicker.tsx | 51 +++++++++++-------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/components/frontend/locker/WardrobePanel.tsx b/src/components/frontend/locker/WardrobePanel.tsx index b1aaa71..43efc81 100644 --- a/src/components/frontend/locker/WardrobePanel.tsx +++ b/src/components/frontend/locker/WardrobePanel.tsx @@ -62,7 +62,7 @@ export function WardrobePanel({ userName, loadouts, equippedLoadout, items }: Wa } async function handlePick(slotName: string, assetId: number | null) { - if (!equippedLoadout) return; + if (!equippedLoadout) return { success: false, error: "No loadout equipped." }; setBusy(true); const res = await setLoadoutSlot(equippedLoadout.id, slotName, assetId); setBusy(false); @@ -70,6 +70,7 @@ export function WardrobePanel({ userName, loadouts, equippedLoadout, items }: Wa setPickerSlot(null); router.refresh(); } + return res; } const pickerLayout = pickerSlot ? getWardrobeSlot(pickerSlot) : null; diff --git a/src/components/frontend/locker/WardrobeSlotPicker.tsx b/src/components/frontend/locker/WardrobeSlotPicker.tsx index 3ebe7e8..e5e47da 100644 --- a/src/components/frontend/locker/WardrobeSlotPicker.tsx +++ b/src/components/frontend/locker/WardrobeSlotPicker.tsx @@ -1,6 +1,6 @@ "use client"; -import { useMemo } from "react"; +import { useMemo, useState } from "react"; import type { Asset } from "@/payload-types"; import { Button } from "@/components/ui/button"; import { @@ -22,7 +22,7 @@ interface WardrobeSlotPickerProps { items: LockerGridItem[]; currentValue: number | Asset | null; busy: boolean; - onPick: (assetId: number | null) => void; + onPick: (assetId: number | null) => Promise<{ success: boolean; error?: string }>; } function resolveCurrentId(value: number | Asset | null): number | null { @@ -40,6 +40,9 @@ export function WardrobeSlotPicker({ busy, onPick, }: WardrobeSlotPickerProps) { + const [error, setError] = useState(null); + const [pending, setPending] = useState(false); + const options = useMemo(() => { const types = new Set(slot.assetTypes); const seen = new Set(); @@ -53,6 +56,21 @@ export function WardrobeSlotPicker({ const currentId = resolveCurrentId(currentValue); + async function handlePick(assetId: number | null) { + setError(null); + setPending(true); + try { + const res = await onPick(assetId); + if (!res.success) { + setError(res.error ?? "Failed to equip item."); + } + } catch (e) { + setError(e instanceof Error ? e.message : "An unexpected error occurred."); + } finally { + setPending(false); + } + } + return ( @@ -63,6 +81,12 @@ export function WardrobeSlotPicker({ + {error && ( +
+ {error} +
+ )} +
{options.length === 0 && (

@@ -75,11 +99,8 @@ export function WardrobeSlotPicker({ {currentId != null && ( - )}