Skip to content

Commit 17ea55e

Browse files
garyoclaude
andcommitted
Fix all-items page refreshing entire list on item edit
Use createResource's mutate() for surgical local updates instead of refetching the full item list, preserving scroll position and context. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0acbde0 commit 17ea55e

3 files changed

Lines changed: 39 additions & 12 deletions

File tree

src/components/all-items/AllItemsPage.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ export function AllItemsPage() {
3030
});
3131

3232
// Fetch all items
33-
const [items, { refetch: refetchItems }] = createResource<MasterItemWithCategory[]>(async () => {
33+
const [items, { refetch: refetchItems, mutate: mutateItems }] = createResource<
34+
MasterItemWithCategory[]
35+
>(async () => {
3436
return fetchWithErrorHandling(
3537
() => api.get<MasterItemWithCategory[]>(endpoints.masterItems),
3638
'Failed to load items'
@@ -77,12 +79,21 @@ export function AllItemsPage() {
7779
const response = await api.delete(endpoints.masterItem(id));
7880
if (response.success) {
7981
showToast('success', 'Item deleted successfully');
80-
refetchItems();
82+
mutateItems((prev) => prev?.filter((item) => item.id !== id));
8183
} else {
8284
showToast('error', response.error || 'Failed to delete item');
8385
}
8486
};
8587

88+
const handleItemUpdated = (updatedItem: MasterItemWithCategory) => {
89+
mutateItems((prev) => prev?.map((item) => (item.id === updatedItem.id ? updatedItem : item)));
90+
};
91+
92+
const handleItemAdded = () => {
93+
// New items need a full refetch since we don't have the server-generated id/category data
94+
refetchItems();
95+
};
96+
8697
const handleDataChanged = () => {
8798
refetchCategories();
8899
refetchItems();
@@ -184,7 +195,8 @@ export function AllItemsPage() {
184195
categories={categories}
185196
bagTemplates={bagTemplates}
186197
onDeleteItem={handleDeleteItem}
187-
onItemSaved={refetchItems}
198+
onItemUpdated={handleItemUpdated}
199+
onItemAdded={handleItemAdded}
188200
onCategoriesSaved={handleDataChanged}
189201
onBagTemplatesSaved={handleBagTemplatesChanged}
190202
/>

src/components/all-items/AllItemsPageTabs.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ interface AllItemsPageTabsProps {
1010
categories: Accessor<Category[] | undefined>;
1111
bagTemplates: Accessor<BagTemplate[] | undefined>;
1212
onDeleteItem: (id: string) => void;
13-
onItemSaved: () => void;
13+
onItemUpdated: (item: MasterItemWithCategory) => void;
14+
onItemAdded: () => void;
1415
onCategoriesSaved: () => void;
1516
onBagTemplatesSaved: () => void;
1617
}
@@ -50,7 +51,8 @@ export function AllItemsPageTabs(props: AllItemsPageTabsProps) {
5051
items={props.items}
5152
categories={props.categories}
5253
onDeleteItem={props.onDeleteItem}
53-
onItemSaved={props.onItemSaved}
54+
onItemUpdated={props.onItemUpdated}
55+
onItemAdded={props.onItemAdded}
5456
/>
5557
</TabPanel>
5658

src/components/all-items/ItemsList.tsx

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Extracted from AllItemsPage for better separation of concerns
66
*/
77

8-
import { createSignal, createResource, createMemo, For, Show, type Accessor } from 'solid-js';
8+
import { createSignal, createMemo, For, Show, type Accessor } from 'solid-js';
99
import { Input } from '../ui/Input';
1010
import { Button } from '../ui/Button';
1111
import { Combobox, type ComboboxItem } from '../ui/Combobox';
@@ -20,7 +20,8 @@ interface ItemsListProps {
2020
items: Accessor<MasterItemWithCategory[] | undefined>;
2121
categories: Accessor<Category[] | undefined>;
2222
onDeleteItem: (id: string) => void;
23-
onItemSaved?: () => void;
23+
onItemUpdated: (item: MasterItemWithCategory) => void;
24+
onItemAdded: () => void;
2425
}
2526

2627
export function ItemsList(props: ItemsListProps) {
@@ -113,7 +114,7 @@ export function ItemsList(props: ItemsListProps) {
113114
setNewCategoryId('');
114115
setNewQuantity(1);
115116
setNewIsContainer(false);
116-
props.onItemSaved?.();
117+
props.onItemAdded();
117118
} else {
118119
showToast('error', response.error || 'Failed to add item');
119120
}
@@ -145,22 +146,34 @@ export function ItemsList(props: ItemsListProps) {
145146
return;
146147
}
147148

148-
setUpdating(true);
149+
const itemId = editingItemId()!;
150+
const originalItem = props.items()?.find((i) => i.id === itemId);
151+
if (!originalItem) return;
149152

150-
const response = await api.put(endpoints.masterItem(editingItemId()!), {
153+
const patchData = {
151154
name: editName().trim(),
152155
description: editDescription().trim() || null,
153156
category_id: editCategoryId() || null,
154157
default_quantity: editQuantity(),
155158
is_container: editIsContainer(),
156-
});
159+
};
160+
161+
setUpdating(true);
162+
163+
const response = await api.put(endpoints.masterItem(itemId), patchData);
157164

158165
setUpdating(false);
159166

160167
if (response.success) {
161168
showToast('success', 'Item updated');
169+
const category = props.categories()?.find((c) => c.id === patchData.category_id);
170+
const updatedItem: MasterItemWithCategory = {
171+
...originalItem,
172+
...patchData,
173+
category_name: category?.name || null,
174+
};
162175
cancelEdit();
163-
props.onItemSaved?.();
176+
props.onItemUpdated(updatedItem);
164177
} else {
165178
showToast('error', response.error || 'Failed to update item');
166179
}

0 commit comments

Comments
 (0)