progress enforcing adr-0005
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 46s
Some checks failed
Deploy to Test Environment / deploy-to-test (push) Failing after 46s
This commit is contained in:
23
src/hooks/mutations/index.ts
Normal file
23
src/hooks/mutations/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// src/hooks/mutations/index.ts
|
||||
/**
|
||||
* Barrel export for all TanStack Query mutation hooks.
|
||||
*
|
||||
* These mutations follow ADR-0005 and provide:
|
||||
* - Automatic cache invalidation
|
||||
* - Optimistic updates (where applicable)
|
||||
* - Success/error notifications
|
||||
* - Proper TypeScript types
|
||||
*
|
||||
* @see docs/adr/0005-frontend-state-management-and-server-cache-strategy.md
|
||||
*/
|
||||
|
||||
// Watched Items mutations
|
||||
export { useAddWatchedItemMutation } from './useAddWatchedItemMutation';
|
||||
export { useRemoveWatchedItemMutation } from './useRemoveWatchedItemMutation';
|
||||
|
||||
// Shopping List mutations
|
||||
export { useCreateShoppingListMutation } from './useCreateShoppingListMutation';
|
||||
export { useDeleteShoppingListMutation } from './useDeleteShoppingListMutation';
|
||||
export { useAddShoppingListItemMutation } from './useAddShoppingListItemMutation';
|
||||
export { useUpdateShoppingListItemMutation } from './useUpdateShoppingListItemMutation';
|
||||
export { useRemoveShoppingListItemMutation } from './useRemoveShoppingListItemMutation';
|
||||
71
src/hooks/mutations/useAddShoppingListItemMutation.ts
Normal file
71
src/hooks/mutations/useAddShoppingListItemMutation.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
// src/hooks/mutations/useAddShoppingListItemMutation.ts
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import * as apiClient from '../../services/apiClient';
|
||||
import { notifySuccess, notifyError } from '../../services/notificationService';
|
||||
|
||||
interface AddShoppingListItemParams {
|
||||
listId: number;
|
||||
item: {
|
||||
masterItemId?: number;
|
||||
customItemName?: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutation hook for adding an item to a shopping list.
|
||||
*
|
||||
* This hook provides automatic cache invalidation. When the mutation succeeds,
|
||||
* it invalidates the shopping-lists query to trigger a refetch of the updated list.
|
||||
*
|
||||
* Items can be added by either masterItemId (for master grocery items) or
|
||||
* customItemName (for custom items not in the master list).
|
||||
*
|
||||
* @returns Mutation object with mutate function and state
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const addShoppingListItem = useAddShoppingListItemMutation();
|
||||
*
|
||||
* // Add master item
|
||||
* const handleAddMasterItem = () => {
|
||||
* addShoppingListItem.mutate({
|
||||
* listId: 1,
|
||||
* item: { masterItemId: 42 }
|
||||
* });
|
||||
* };
|
||||
*
|
||||
* // Add custom item
|
||||
* const handleAddCustomItem = () => {
|
||||
* addShoppingListItem.mutate({
|
||||
* listId: 1,
|
||||
* item: { customItemName: 'Special Brand Milk' }
|
||||
* });
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export const useAddShoppingListItemMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ listId, item }: AddShoppingListItemParams) => {
|
||||
const response = await apiClient.addShoppingListItem(listId, item);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({
|
||||
message: `Request failed with status ${response.status}`,
|
||||
}));
|
||||
throw new Error(error.message || 'Failed to add item to shopping list');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Invalidate and refetch shopping lists to get the updated list
|
||||
queryClient.invalidateQueries({ queryKey: ['shopping-lists'] });
|
||||
notifySuccess('Item added to shopping list');
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
notifyError(error.message || 'Failed to add item to shopping list');
|
||||
},
|
||||
});
|
||||
};
|
||||
58
src/hooks/mutations/useCreateShoppingListMutation.ts
Normal file
58
src/hooks/mutations/useCreateShoppingListMutation.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
// src/hooks/mutations/useCreateShoppingListMutation.ts
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import * as apiClient from '../../services/apiClient';
|
||||
import { notifySuccess, notifyError } from '../../services/notificationService';
|
||||
|
||||
interface CreateShoppingListParams {
|
||||
name: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutation hook for creating a new shopping list.
|
||||
*
|
||||
* This hook provides automatic cache invalidation. When the mutation succeeds,
|
||||
* it invalidates the shopping-lists query to trigger a refetch of the updated list.
|
||||
*
|
||||
* @returns Mutation object with mutate function and state
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const createShoppingList = useCreateShoppingListMutation();
|
||||
*
|
||||
* const handleCreate = () => {
|
||||
* createShoppingList.mutate(
|
||||
* { name: 'Weekly Groceries' },
|
||||
* {
|
||||
* onSuccess: (newList) => console.log('Created:', newList),
|
||||
* onError: (error) => console.error(error),
|
||||
* }
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export const useCreateShoppingListMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ name }: CreateShoppingListParams) => {
|
||||
const response = await apiClient.createShoppingList(name);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({
|
||||
message: `Request failed with status ${response.status}`,
|
||||
}));
|
||||
throw new Error(error.message || 'Failed to create shopping list');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Invalidate and refetch shopping lists to get the updated list
|
||||
queryClient.invalidateQueries({ queryKey: ['shopping-lists'] });
|
||||
notifySuccess('Shopping list created');
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
notifyError(error.message || 'Failed to create shopping list');
|
||||
},
|
||||
});
|
||||
};
|
||||
58
src/hooks/mutations/useDeleteShoppingListMutation.ts
Normal file
58
src/hooks/mutations/useDeleteShoppingListMutation.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
// src/hooks/mutations/useDeleteShoppingListMutation.ts
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import * as apiClient from '../../services/apiClient';
|
||||
import { notifySuccess, notifyError } from '../../services/notificationService';
|
||||
|
||||
interface DeleteShoppingListParams {
|
||||
listId: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutation hook for deleting a shopping list.
|
||||
*
|
||||
* This hook provides automatic cache invalidation. When the mutation succeeds,
|
||||
* it invalidates the shopping-lists query to trigger a refetch of the updated list.
|
||||
*
|
||||
* @returns Mutation object with mutate function and state
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const deleteShoppingList = useDeleteShoppingListMutation();
|
||||
*
|
||||
* const handleDelete = (listId: number) => {
|
||||
* deleteShoppingList.mutate(
|
||||
* { listId },
|
||||
* {
|
||||
* onSuccess: () => console.log('Deleted!'),
|
||||
* onError: (error) => console.error(error),
|
||||
* }
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export const useDeleteShoppingListMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ listId }: DeleteShoppingListParams) => {
|
||||
const response = await apiClient.deleteShoppingList(listId);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({
|
||||
message: `Request failed with status ${response.status}`,
|
||||
}));
|
||||
throw new Error(error.message || 'Failed to delete shopping list');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Invalidate and refetch shopping lists to get the updated list
|
||||
queryClient.invalidateQueries({ queryKey: ['shopping-lists'] });
|
||||
notifySuccess('Shopping list deleted');
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
notifyError(error.message || 'Failed to delete shopping list');
|
||||
},
|
||||
});
|
||||
};
|
||||
58
src/hooks/mutations/useRemoveShoppingListItemMutation.ts
Normal file
58
src/hooks/mutations/useRemoveShoppingListItemMutation.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
// src/hooks/mutations/useRemoveShoppingListItemMutation.ts
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import * as apiClient from '../../services/apiClient';
|
||||
import { notifySuccess, notifyError } from '../../services/notificationService';
|
||||
|
||||
interface RemoveShoppingListItemParams {
|
||||
itemId: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutation hook for removing an item from a shopping list.
|
||||
*
|
||||
* This hook provides automatic cache invalidation. When the mutation succeeds,
|
||||
* it invalidates the shopping-lists query to trigger a refetch of the updated list.
|
||||
*
|
||||
* @returns Mutation object with mutate function and state
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const removeShoppingListItem = useRemoveShoppingListItemMutation();
|
||||
*
|
||||
* const handleRemove = (itemId: number) => {
|
||||
* removeShoppingListItem.mutate(
|
||||
* { itemId },
|
||||
* {
|
||||
* onSuccess: () => console.log('Removed!'),
|
||||
* onError: (error) => console.error(error),
|
||||
* }
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export const useRemoveShoppingListItemMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ itemId }: RemoveShoppingListItemParams) => {
|
||||
const response = await apiClient.removeShoppingListItem(itemId);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({
|
||||
message: `Request failed with status ${response.status}`,
|
||||
}));
|
||||
throw new Error(error.message || 'Failed to remove shopping list item');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Invalidate and refetch shopping lists to get the updated list
|
||||
queryClient.invalidateQueries({ queryKey: ['shopping-lists'] });
|
||||
notifySuccess('Item removed from shopping list');
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
notifyError(error.message || 'Failed to remove shopping list item');
|
||||
},
|
||||
});
|
||||
};
|
||||
58
src/hooks/mutations/useRemoveWatchedItemMutation.ts
Normal file
58
src/hooks/mutations/useRemoveWatchedItemMutation.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
// src/hooks/mutations/useRemoveWatchedItemMutation.ts
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import * as apiClient from '../../services/apiClient';
|
||||
import { notifySuccess, notifyError } from '../../services/notificationService';
|
||||
|
||||
interface RemoveWatchedItemParams {
|
||||
masterItemId: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutation hook for removing an item from the user's watched items list.
|
||||
*
|
||||
* This hook provides automatic cache invalidation. When the mutation succeeds,
|
||||
* it invalidates the watched-items query to trigger a refetch of the updated list.
|
||||
*
|
||||
* @returns Mutation object with mutate function and state
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const removeWatchedItem = useRemoveWatchedItemMutation();
|
||||
*
|
||||
* const handleRemove = (itemId: number) => {
|
||||
* removeWatchedItem.mutate(
|
||||
* { masterItemId: itemId },
|
||||
* {
|
||||
* onSuccess: () => console.log('Removed!'),
|
||||
* onError: (error) => console.error(error),
|
||||
* }
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export const useRemoveWatchedItemMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ masterItemId }: RemoveWatchedItemParams) => {
|
||||
const response = await apiClient.removeWatchedItem(masterItemId);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({
|
||||
message: `Request failed with status ${response.status}`,
|
||||
}));
|
||||
throw new Error(error.message || 'Failed to remove watched item');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Invalidate and refetch watched items to get the updated list
|
||||
queryClient.invalidateQueries({ queryKey: ['watched-items'] });
|
||||
notifySuccess('Item removed from watched list');
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
notifyError(error.message || 'Failed to remove item from watched list');
|
||||
},
|
||||
});
|
||||
};
|
||||
68
src/hooks/mutations/useUpdateShoppingListItemMutation.ts
Normal file
68
src/hooks/mutations/useUpdateShoppingListItemMutation.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
// src/hooks/mutations/useUpdateShoppingListItemMutation.ts
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import * as apiClient from '../../services/apiClient';
|
||||
import { notifySuccess, notifyError } from '../../services/notificationService';
|
||||
import type { ShoppingListItem } from '../../types';
|
||||
|
||||
interface UpdateShoppingListItemParams {
|
||||
itemId: number;
|
||||
updates: Partial<Pick<ShoppingListItem, 'custom_item_name' | 'quantity' | 'is_purchased' | 'notes'>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutation hook for updating a shopping list item.
|
||||
*
|
||||
* This hook provides automatic cache invalidation. When the mutation succeeds,
|
||||
* it invalidates the shopping-lists query to trigger a refetch of the updated list.
|
||||
*
|
||||
* You can update: custom_item_name, quantity, is_purchased, notes.
|
||||
*
|
||||
* @returns Mutation object with mutate function and state
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const updateShoppingListItem = useUpdateShoppingListItemMutation();
|
||||
*
|
||||
* // Mark item as purchased
|
||||
* const handlePurchase = () => {
|
||||
* updateShoppingListItem.mutate({
|
||||
* itemId: 42,
|
||||
* updates: { is_purchased: true }
|
||||
* });
|
||||
* };
|
||||
*
|
||||
* // Update quantity
|
||||
* const handleQuantityChange = () => {
|
||||
* updateShoppingListItem.mutate({
|
||||
* itemId: 42,
|
||||
* updates: { quantity: 3 }
|
||||
* });
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
export const useUpdateShoppingListItemMutation = () => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ itemId, updates }: UpdateShoppingListItemParams) => {
|
||||
const response = await apiClient.updateShoppingListItem(itemId, updates);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({
|
||||
message: `Request failed with status ${response.status}`,
|
||||
}));
|
||||
throw new Error(error.message || 'Failed to update shopping list item');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
},
|
||||
onSuccess: () => {
|
||||
// Invalidate and refetch shopping lists to get the updated list
|
||||
queryClient.invalidateQueries({ queryKey: ['shopping-lists'] });
|
||||
notifySuccess('Shopping list item updated');
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
notifyError(error.message || 'Failed to update shopping list item');
|
||||
},
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user