complete project using prettier!
This commit is contained in:
@@ -14,36 +14,51 @@ const useShoppingListsHook = () => {
|
||||
const { userProfile } = useAuth();
|
||||
// We get the lists and the global setter from the DataContext.
|
||||
const { shoppingLists, setShoppingLists } = useUserData();
|
||||
|
||||
|
||||
const [activeListId, setActiveListId] = useState<number | null>(null);
|
||||
|
||||
// API hooks for shopping list operations
|
||||
const { execute: createListApi, error: createError, loading: isCreatingList } = useApi<ShoppingList, [string]>(
|
||||
(name) => apiClient.createShoppingList(name)
|
||||
const {
|
||||
execute: createListApi,
|
||||
error: createError,
|
||||
loading: isCreatingList,
|
||||
} = useApi<ShoppingList, [string]>((name) => apiClient.createShoppingList(name));
|
||||
const {
|
||||
execute: deleteListApi,
|
||||
error: deleteError,
|
||||
loading: isDeletingList,
|
||||
} = useApi<null, [number]>((listId) => apiClient.deleteShoppingList(listId));
|
||||
const {
|
||||
execute: addItemApi,
|
||||
error: addItemError,
|
||||
loading: isAddingItem,
|
||||
} = useApi<ShoppingListItem, [number, { masterItemId?: number; customItemName?: string }]>(
|
||||
(listId, item) => apiClient.addShoppingListItem(listId, item),
|
||||
);
|
||||
const { execute: deleteListApi, error: deleteError, loading: isDeletingList } = useApi<null, [number]>(
|
||||
(listId) => apiClient.deleteShoppingList(listId)
|
||||
);
|
||||
const { execute: addItemApi, error: addItemError, loading: isAddingItem } = useApi<ShoppingListItem, [number, { masterItemId?: number, customItemName?: string }]>(
|
||||
(listId, item) => apiClient.addShoppingListItem(listId, item)
|
||||
);
|
||||
const { execute: updateItemApi, error: updateItemError, loading: isUpdatingItem } = useApi<ShoppingListItem, [number, Partial<ShoppingListItem>]>(
|
||||
(itemId, updates) => apiClient.updateShoppingListItem(itemId, updates)
|
||||
);
|
||||
const { execute: removeItemApi, error: removeItemError, loading: isRemovingItem } = useApi<null, [number]>(
|
||||
(itemId) => apiClient.removeShoppingListItem(itemId)
|
||||
const {
|
||||
execute: updateItemApi,
|
||||
error: updateItemError,
|
||||
loading: isUpdatingItem,
|
||||
} = useApi<ShoppingListItem, [number, Partial<ShoppingListItem>]>((itemId, updates) =>
|
||||
apiClient.updateShoppingListItem(itemId, updates),
|
||||
);
|
||||
const {
|
||||
execute: removeItemApi,
|
||||
error: removeItemError,
|
||||
loading: isRemovingItem,
|
||||
} = useApi<null, [number]>((itemId) => apiClient.removeShoppingListItem(itemId));
|
||||
|
||||
// Consolidate errors from all API hooks into a single displayable error.
|
||||
const error = useMemo(() => {
|
||||
const firstError = createError || deleteError || addItemError || updateItemError || removeItemError;
|
||||
const firstError =
|
||||
createError || deleteError || addItemError || updateItemError || removeItemError;
|
||||
return firstError ? firstError.message : null;
|
||||
}, [createError, deleteError, addItemError, updateItemError, removeItemError]);
|
||||
|
||||
// Effect to select the first list as active when lists are loaded or the user changes.
|
||||
useEffect(() => {
|
||||
// Check if the currently active list still exists in the shoppingLists array.
|
||||
const activeListExists = shoppingLists.some(l => l.shopping_list_id === activeListId);
|
||||
const activeListExists = shoppingLists.some((l) => l.shopping_list_id === activeListId);
|
||||
|
||||
// If the user is logged in and there are lists...
|
||||
if (userProfile && shoppingLists.length > 0) {
|
||||
@@ -57,103 +72,133 @@ const useShoppingListsHook = () => {
|
||||
}
|
||||
}, [shoppingLists, userProfile]); // This effect should NOT depend on activeListId to prevent re-selection loops.
|
||||
|
||||
const createList = useCallback(async (name: string) => {
|
||||
if (!userProfile) return;
|
||||
try {
|
||||
const newList = await createListApi(name);
|
||||
if (newList) {
|
||||
setShoppingLists(prev => [...prev, newList]);
|
||||
const createList = useCallback(
|
||||
async (name: string) => {
|
||||
if (!userProfile) return;
|
||||
try {
|
||||
const newList = await createListApi(name);
|
||||
if (newList) {
|
||||
setShoppingLists((prev) => [...prev, newList]);
|
||||
}
|
||||
} catch (e) {
|
||||
// The useApi hook handles setting the error state.
|
||||
// We catch the error here to prevent unhandled promise rejections and add logging.
|
||||
console.error('useShoppingLists: Failed to create list.', e);
|
||||
}
|
||||
} catch (e) {
|
||||
// The useApi hook handles setting the error state.
|
||||
// We catch the error here to prevent unhandled promise rejections and add logging.
|
||||
console.error('useShoppingLists: Failed to create list.', e);
|
||||
}
|
||||
}, [userProfile, setShoppingLists, createListApi]);
|
||||
},
|
||||
[userProfile, setShoppingLists, createListApi],
|
||||
);
|
||||
|
||||
const deleteList = useCallback(async (listId: number) => {
|
||||
if (!userProfile) return;
|
||||
try {
|
||||
const result = await deleteListApi(listId);
|
||||
// A successful DELETE will have a null result from useApi (for 204 No Content)
|
||||
if (result === null) {
|
||||
setShoppingLists(prevLists => prevLists.filter(l => l.shopping_list_id !== listId));
|
||||
const deleteList = useCallback(
|
||||
async (listId: number) => {
|
||||
if (!userProfile) return;
|
||||
try {
|
||||
const result = await deleteListApi(listId);
|
||||
// A successful DELETE will have a null result from useApi (for 204 No Content)
|
||||
if (result === null) {
|
||||
setShoppingLists((prevLists) => prevLists.filter((l) => l.shopping_list_id !== listId));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('useShoppingLists: Failed to delete list.', e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('useShoppingLists: Failed to delete list.', e);
|
||||
}
|
||||
}, [userProfile, setShoppingLists, deleteListApi]);
|
||||
},
|
||||
[userProfile, setShoppingLists, deleteListApi],
|
||||
);
|
||||
|
||||
const addItemToList = useCallback(async (listId: number, item: { masterItemId?: number, customItemName?: string }) => {
|
||||
if (!userProfile) return;
|
||||
const addItemToList = useCallback(
|
||||
async (listId: number, item: { masterItemId?: number; customItemName?: string }) => {
|
||||
if (!userProfile) return;
|
||||
|
||||
// Find the target list first to check for duplicates *before* the API call.
|
||||
const targetList = shoppingLists.find(l => l.shopping_list_id === listId);
|
||||
if (!targetList) {
|
||||
console.error(`useShoppingLists: List with ID ${listId} not found.`);
|
||||
return; // Or throw an error
|
||||
}
|
||||
|
||||
// Prevent adding a duplicate master item.
|
||||
if (item.masterItemId) {
|
||||
const itemExists = targetList.items.some(i => i.master_item_id === item.masterItemId);
|
||||
if (itemExists) {
|
||||
// Optionally, we could show a toast notification here.
|
||||
console.log(`useShoppingLists: Item with master ID ${item.masterItemId} already in list.`);
|
||||
return; // Exit without calling the API.
|
||||
// Find the target list first to check for duplicates *before* the API call.
|
||||
const targetList = shoppingLists.find((l) => l.shopping_list_id === listId);
|
||||
if (!targetList) {
|
||||
console.error(`useShoppingLists: List with ID ${listId} not found.`);
|
||||
return; // Or throw an error
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const newItem = await addItemApi(listId, item);
|
||||
if (newItem) {
|
||||
setShoppingLists(prevLists =>
|
||||
prevLists.map(list => {
|
||||
if (list.shopping_list_id === listId) {
|
||||
// The duplicate check is now handled above, so we can just add the item.
|
||||
return { ...list, items: [...list.items, newItem] };
|
||||
}
|
||||
return list;
|
||||
}));
|
||||
// Prevent adding a duplicate master item.
|
||||
if (item.masterItemId) {
|
||||
const itemExists = targetList.items.some((i) => i.master_item_id === item.masterItemId);
|
||||
if (itemExists) {
|
||||
// Optionally, we could show a toast notification here.
|
||||
console.log(
|
||||
`useShoppingLists: Item with master ID ${item.masterItemId} already in list.`,
|
||||
);
|
||||
return; // Exit without calling the API.
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('useShoppingLists: Failed to add item.', e);
|
||||
}
|
||||
}, [userProfile, shoppingLists, setShoppingLists, addItemApi]);
|
||||
|
||||
const updateItemInList = useCallback(async (itemId: number, updates: Partial<ShoppingListItem>) => {
|
||||
if (!userProfile || !activeListId) return;
|
||||
try {
|
||||
const updatedItem = await updateItemApi(itemId, updates);
|
||||
if (updatedItem) {
|
||||
setShoppingLists(prevLists => prevLists.map(list => {
|
||||
if (list.shopping_list_id === activeListId) {
|
||||
return { ...list, items: list.items.map(i => i.shopping_list_item_id === itemId ? updatedItem : i) };
|
||||
}
|
||||
return list;
|
||||
}));
|
||||
try {
|
||||
const newItem = await addItemApi(listId, item);
|
||||
if (newItem) {
|
||||
setShoppingLists((prevLists) =>
|
||||
prevLists.map((list) => {
|
||||
if (list.shopping_list_id === listId) {
|
||||
// The duplicate check is now handled above, so we can just add the item.
|
||||
return { ...list, items: [...list.items, newItem] };
|
||||
}
|
||||
return list;
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('useShoppingLists: Failed to add item.', e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('useShoppingLists: Failed to update item.', e);
|
||||
}
|
||||
}, [userProfile, activeListId, setShoppingLists, updateItemApi]);
|
||||
},
|
||||
[userProfile, shoppingLists, setShoppingLists, addItemApi],
|
||||
);
|
||||
|
||||
const removeItemFromList = useCallback(async (itemId: number) => {
|
||||
if (!userProfile || !activeListId) return;
|
||||
try {
|
||||
const result = await removeItemApi(itemId);
|
||||
if (result === null) {
|
||||
setShoppingLists(prevLists => prevLists.map(list => {
|
||||
if (list.shopping_list_id === activeListId) {
|
||||
return { ...list, items: list.items.filter(i => i.shopping_list_item_id !== itemId) };
|
||||
}
|
||||
return list;
|
||||
}));
|
||||
const updateItemInList = useCallback(
|
||||
async (itemId: number, updates: Partial<ShoppingListItem>) => {
|
||||
if (!userProfile || !activeListId) return;
|
||||
try {
|
||||
const updatedItem = await updateItemApi(itemId, updates);
|
||||
if (updatedItem) {
|
||||
setShoppingLists((prevLists) =>
|
||||
prevLists.map((list) => {
|
||||
if (list.shopping_list_id === activeListId) {
|
||||
return {
|
||||
...list,
|
||||
items: list.items.map((i) =>
|
||||
i.shopping_list_item_id === itemId ? updatedItem : i,
|
||||
),
|
||||
};
|
||||
}
|
||||
return list;
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('useShoppingLists: Failed to update item.', e);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('useShoppingLists: Failed to remove item.', e);
|
||||
}
|
||||
}, [userProfile, activeListId, setShoppingLists, removeItemApi]);
|
||||
},
|
||||
[userProfile, activeListId, setShoppingLists, updateItemApi],
|
||||
);
|
||||
|
||||
const removeItemFromList = useCallback(
|
||||
async (itemId: number) => {
|
||||
if (!userProfile || !activeListId) return;
|
||||
try {
|
||||
const result = await removeItemApi(itemId);
|
||||
if (result === null) {
|
||||
setShoppingLists((prevLists) =>
|
||||
prevLists.map((list) => {
|
||||
if (list.shopping_list_id === activeListId) {
|
||||
return {
|
||||
...list,
|
||||
items: list.items.filter((i) => i.shopping_list_item_id !== itemId),
|
||||
};
|
||||
}
|
||||
return list;
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('useShoppingLists: Failed to remove item.', e);
|
||||
}
|
||||
},
|
||||
[userProfile, activeListId, setShoppingLists, removeItemApi],
|
||||
);
|
||||
|
||||
return {
|
||||
shoppingLists,
|
||||
@@ -173,4 +218,4 @@ const useShoppingListsHook = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export { useShoppingListsHook as useShoppingLists };
|
||||
export { useShoppingListsHook as useShoppingLists };
|
||||
|
||||
Reference in New Issue
Block a user