diff --git a/frontend/src/components/inventory/InventoryFiltersPanel.tsx b/frontend/src/components/inventory/InventoryFiltersPanel.tsx index a26a325..b5ab4f2 100644 --- a/frontend/src/components/inventory/InventoryFiltersPanel.tsx +++ b/frontend/src/components/inventory/InventoryFiltersPanel.tsx @@ -57,6 +57,7 @@ interface FiltersPanelProps { showAddButton: boolean; totalCount: number; itemCount: number; + autoFocusSearch?: boolean; } export const InventoryFiltersPanel = ({ @@ -84,6 +85,7 @@ export const InventoryFiltersPanel = ({ showAddButton, totalCount, itemCount, + autoFocusSearch = false, }: FiltersPanelProps) => { return ( <> @@ -94,6 +96,7 @@ export const InventoryFiltersPanel = ({ label="Search by name, note, or location" placeholder="Prospector, Lorville, armors..." value={filters.search} + autoFocus={autoFocusSearch} onChange={(e) => setFilters((prev) => ({ ...prev, search: e.target.value }))} /> diff --git a/frontend/src/components/inventory/InventoryInlineRow.tsx b/frontend/src/components/inventory/InventoryInlineRow.tsx index adc2af1..d62d845 100644 --- a/frontend/src/components/inventory/InventoryInlineRow.tsx +++ b/frontend/src/components/inventory/InventoryInlineRow.tsx @@ -30,6 +30,7 @@ interface InventoryInlineRowProps { inlineLocationInput: string; locationEditing: boolean; inlineSaving: boolean; + inlineSaved?: boolean; inlineError?: string | null; isDirty: boolean; focusController: FocusController; @@ -54,6 +55,7 @@ export const InventoryInlineRow = ({ inlineLocationInput, locationEditing, inlineSaving, + inlineSaved, inlineError, isDirty, focusController, @@ -279,11 +281,6 @@ export const InventoryInlineRow = ({ Large quantity entered - verify value. )} - {inlineError && ( - - {inlineError} - - )} + + {inlineError && ( + + {inlineError} + + )} + {!inlineError && inlineSaved && ( + + )} + {density === 'compact' && isDirty && ( { Record >({}); const [inlineSaving, setInlineSaving] = useState>(new Set()); + const [inlineSaved, setInlineSaved] = useState>(new Set()); const [inlineError, setInlineError] = useState>({}); const [allLocations, setAllLocations] = useState<{ id: number; name: string }[]>([]); const [inlineLocationInputs, setInlineLocationInputs] = useState>({}); @@ -150,14 +151,6 @@ const InventoryPage = () => { api?: string | null; }>({}); const [newRowSaving, setNewRowSaving] = useState(false); - const itemGridTemplate = useMemo( - () => - density === 'compact' - ? { xs: '1fr', md: '2fr 1fr 0.8fr 0.8fr auto' } - : { xs: '1fr', md: '2fr 1fr 1fr 1fr auto' }, - [density], - ); - const debouncedSearch = useDebounce(filters.search, 350); const debouncedCatalogSearch = useDebounce(catalogSearch, 350); const debouncedNewItemSearch = useDebounce(newRowItemInput, 300); @@ -962,6 +955,21 @@ const InventoryPage = () => { const nextSaving = new Set(inlineSaving); nextSaving.add(item.id); setInlineSaving(nextSaving); + const prevItem = + items.find((entry) => entry.id === item.id) ?? + ({ + ...item, + } as InventoryRecord); + const updatedItem: InventoryRecord = { + ...item, + locationId: parsedLocationId, + quantity: parsedQuantity, + locationName: + allLocations.find((loc) => loc.id === parsedLocationId)?.name || item.locationName, + }; + setItems((prev) => + prev.map((entry) => (entry.id === item.id ? updatedItem : entry)), + ); try { if (viewMode === 'org' && selectedOrgId) { @@ -975,10 +983,24 @@ const InventoryPage = () => { quantity: parsedQuantity, }); } - await fetchInventory(); + setInlineSaved((prev) => { + const next = new Set(prev); + next.add(item.id.toString()); + setTimeout(() => { + setInlineSaved((current) => { + const copy = new Set(current); + copy.delete(item.id.toString()); + return copy; + }); + }, 1200); + return next; + }); return true; } catch (err) { console.error('Inline save failed', err); + setItems((prev) => + prev.map((entry) => (entry.id === item.id ? prevItem : entry)), + ); setInlineError((prev) => ({ ...prev, [item.id]: 'Unable to save. Please try again.', @@ -1461,6 +1483,7 @@ const InventoryPage = () => { ''); const saving = inlineSaving.has(item.id); const errorText = inlineError[item.id]; + const saved = inlineSaved.has(item.id.toString()); return ( { inlineLocationInput={inlineLocationValue} locationEditing={Boolean(locationEditing[rowKey])} inlineSaving={saving} + inlineSaved={saved} inlineError={errorText} isDirty={isDirty} focusController={focusController} @@ -1596,6 +1620,7 @@ const InventoryPage = () => { showAddButton={viewMode === 'personal'} totalCount={totalCount} itemCount={items.length} + autoFocusSearch /> @@ -1650,7 +1675,13 @@ const InventoryPage = () => {