shelflife-react-hooks 1.0.18 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/index.cjs.js +23 -0
  2. package/dist/index.cjs.js.map +1 -1
  3. package/dist/index.d.cts +2 -0
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.esm.js +23 -0
  6. package/dist/index.esm.js.map +1 -1
  7. package/package.json +36 -36
  8. package/src/context/AuthContext.tsx +161 -161
  9. package/src/context/InviteContext.tsx +74 -74
  10. package/src/context/ProductContext.tsx +131 -121
  11. package/src/context/RunningLowContext.tsx +100 -100
  12. package/src/context/ShoppingListContext.tsx +76 -76
  13. package/src/context/StorageContext.tsx +105 -105
  14. package/src/context/StorageItemContext.tsx +157 -157
  15. package/src/context/StorageMemberContext.tsx +84 -84
  16. package/src/context/UserContext.tsx +109 -109
  17. package/src/context/__tests__/contexts.test.tsx +370 -370
  18. package/src/context/api/authApi.ts +155 -155
  19. package/src/context/api/inviteApi.ts +65 -65
  20. package/src/context/api/productApi.ts +223 -201
  21. package/src/context/api/requestState.ts +24 -24
  22. package/src/context/api/runningLowApi.ts +141 -141
  23. package/src/context/api/shoppingListApi.ts +161 -159
  24. package/src/context/api/storageApi.ts +166 -166
  25. package/src/context/api/storageItemApi.ts +260 -260
  26. package/src/context/api/storageMemberApi.ts +84 -84
  27. package/src/context/api/userApi.ts +161 -161
  28. package/src/context/http.ts +22 -22
  29. package/src/index.ts +21 -21
  30. package/src/type/PaginatedResponse.ts +8 -8
  31. package/src/type/auth.ts +79 -79
  32. package/src/type/base.ts +21 -21
  33. package/src/type/item.ts +12 -12
  34. package/src/type/member.ts +6 -6
  35. package/src/type/models.ts +56 -56
  36. package/src/type/product.ts +11 -11
  37. package/src/type/requests.ts +60 -60
  38. package/src/type/runninglow.ts +13 -13
  39. package/src/type/shoppingList.ts +13 -13
  40. package/src/type/storage.ts +7 -7
  41. package/src/type/user.ts +11 -11
  42. package/tsconfig.json +46 -46
  43. package/tsup.config.ts +10 -10
  44. package/vitest.config.ts +8 -8
@@ -1,141 +1,141 @@
1
- import type { RunningLowSetting } from '../../type/models.js';
2
- import type { CreateSettingRequest, EditSettingRequest } from '../../type/requests.js';
3
- import type { CreateRunningLowSettingError, EditRunningLowSettingError } from '../../type/runninglow.js';
4
- import { buildAuthHeaders, normalizeBaseUrl, readJson } from '../http.js';
5
- import { runWithRequestState, type RequestStateHandlers } from './requestState.js';
6
-
7
- type RunningLowApiConfig = RequestStateHandlers & {
8
- baseUrl: string;
9
- token: string | null;
10
- setSettings: (value: RunningLowSetting[] | ((items: RunningLowSetting[]) => RunningLowSetting[])) => void;
11
- };
12
-
13
- const updateById = (items: RunningLowSetting[], updated: RunningLowSetting): RunningLowSetting[] => {
14
- const index = items.findIndex((item) => item.id === updated.id);
15
- if (index === -1) {
16
- return [updated, ...items];
17
- }
18
-
19
- const next = [...items];
20
- next[index] = updated;
21
- return next;
22
- };
23
-
24
- export const fetchSettingsRequest = async (
25
- config: RunningLowApiConfig,
26
- storageId: number
27
- ): Promise<RunningLowSetting[]> => runWithRequestState(config, async () => {
28
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
29
- const response = await fetch(
30
- `${normalizedBaseUrl}/api/storages/${storageId}/runninglowsettings`,
31
- {
32
- headers: buildAuthHeaders(config.token)
33
- }
34
- );
35
-
36
- if (!response.ok) {
37
- throw new Error('Failed to fetch running low settings');
38
- }
39
-
40
- const payload = await readJson<RunningLowSetting[]>(response);
41
- if (payload) {
42
- config.setSettings(payload);
43
- return payload;
44
- }
45
-
46
- return [];
47
- });
48
-
49
- export const createSettingRequest = async (
50
- config: RunningLowApiConfig,
51
- storageId: number,
52
- dto: CreateSettingRequest
53
- ): Promise<RunningLowSetting> => runWithRequestState(config, async () => {
54
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
55
- const response = await fetch(
56
- `${normalizedBaseUrl}/api/storages/${storageId}/runninglowsettings`,
57
- {
58
- method: 'POST',
59
- headers: {
60
- ...buildAuthHeaders(config.token),
61
- 'Content-Type': 'application/json'
62
- },
63
- body: JSON.stringify(dto)
64
- }
65
- );
66
-
67
- if (!response.ok) {
68
- const err = await readJson<CreateRunningLowSettingError>(response);
69
-
70
- if (err?.productId || err?.runningLow)
71
- throw err;
72
-
73
- throw new Error('Failed to create running low setting');
74
- }
75
-
76
- const payload = await readJson<RunningLowSetting>(response);
77
- if (!payload) {
78
- throw new Error('Create running low response missing data');
79
- }
80
-
81
- config.setSettings((previous) => [payload, ...previous]);
82
- return payload;
83
- });
84
-
85
- export const editSettingRequest = async (
86
- config: RunningLowApiConfig,
87
- storageId: number,
88
- id: number,
89
- dto: EditSettingRequest
90
- ): Promise<RunningLowSetting> => runWithRequestState(config, async () => {
91
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
92
- const response = await fetch(
93
- `${normalizedBaseUrl}/api/storages/${storageId}/runninglowsettings/${id}`,
94
- {
95
- method: 'PUT',
96
- headers: {
97
- ...buildAuthHeaders(config.token),
98
- 'Content-Type': 'application/json'
99
- },
100
- body: JSON.stringify(dto)
101
- }
102
- );
103
-
104
- if (!response.ok) {
105
- const err = await readJson<EditRunningLowSettingError>(response);
106
-
107
- if (err?.runningLow)
108
- throw err;
109
-
110
- throw new Error('Failed to edit running low setting');
111
- }
112
-
113
- const payload = await readJson<RunningLowSetting>(response);
114
- if (!payload) {
115
- throw new Error('Edit running low response missing data');
116
- }
117
-
118
- config.setSettings((previous) => updateById(previous, payload));
119
- return payload;
120
- });
121
-
122
- export const deleteSettingRequest = async (
123
- config: RunningLowApiConfig,
124
- storageId: number,
125
- id: number
126
- ): Promise<void> => runWithRequestState(config, async () => {
127
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
128
- const response = await fetch(
129
- `${normalizedBaseUrl}/api/storages/${storageId}/runninglowsettings/${id}`,
130
- {
131
- method: 'DELETE',
132
- headers: buildAuthHeaders(config.token)
133
- }
134
- );
135
-
136
- if (!response.ok) {
137
- throw new Error('Failed to delete running low setting');
138
- }
139
-
140
- config.setSettings((previous) => previous.filter((item) => item.id !== id));
141
- });
1
+ import type { RunningLowSetting } from '../../type/models.js';
2
+ import type { CreateSettingRequest, EditSettingRequest } from '../../type/requests.js';
3
+ import type { CreateRunningLowSettingError, EditRunningLowSettingError } from '../../type/runninglow.js';
4
+ import { buildAuthHeaders, normalizeBaseUrl, readJson } from '../http.js';
5
+ import { runWithRequestState, type RequestStateHandlers } from './requestState.js';
6
+
7
+ type RunningLowApiConfig = RequestStateHandlers & {
8
+ baseUrl: string;
9
+ token: string | null;
10
+ setSettings: (value: RunningLowSetting[] | ((items: RunningLowSetting[]) => RunningLowSetting[])) => void;
11
+ };
12
+
13
+ const updateById = (items: RunningLowSetting[], updated: RunningLowSetting): RunningLowSetting[] => {
14
+ const index = items.findIndex((item) => item.id === updated.id);
15
+ if (index === -1) {
16
+ return [updated, ...items];
17
+ }
18
+
19
+ const next = [...items];
20
+ next[index] = updated;
21
+ return next;
22
+ };
23
+
24
+ export const fetchSettingsRequest = async (
25
+ config: RunningLowApiConfig,
26
+ storageId: number
27
+ ): Promise<RunningLowSetting[]> => runWithRequestState(config, async () => {
28
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
29
+ const response = await fetch(
30
+ `${normalizedBaseUrl}/api/storages/${storageId}/runninglowsettings`,
31
+ {
32
+ headers: buildAuthHeaders(config.token)
33
+ }
34
+ );
35
+
36
+ if (!response.ok) {
37
+ throw new Error('Failed to fetch running low settings');
38
+ }
39
+
40
+ const payload = await readJson<RunningLowSetting[]>(response);
41
+ if (payload) {
42
+ config.setSettings(payload);
43
+ return payload;
44
+ }
45
+
46
+ return [];
47
+ });
48
+
49
+ export const createSettingRequest = async (
50
+ config: RunningLowApiConfig,
51
+ storageId: number,
52
+ dto: CreateSettingRequest
53
+ ): Promise<RunningLowSetting> => runWithRequestState(config, async () => {
54
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
55
+ const response = await fetch(
56
+ `${normalizedBaseUrl}/api/storages/${storageId}/runninglowsettings`,
57
+ {
58
+ method: 'POST',
59
+ headers: {
60
+ ...buildAuthHeaders(config.token),
61
+ 'Content-Type': 'application/json'
62
+ },
63
+ body: JSON.stringify(dto)
64
+ }
65
+ );
66
+
67
+ if (!response.ok) {
68
+ const err = await readJson<CreateRunningLowSettingError>(response);
69
+
70
+ if (err?.productId || err?.runningLow)
71
+ throw err;
72
+
73
+ throw new Error('Failed to create running low setting');
74
+ }
75
+
76
+ const payload = await readJson<RunningLowSetting>(response);
77
+ if (!payload) {
78
+ throw new Error('Create running low response missing data');
79
+ }
80
+
81
+ config.setSettings((previous) => [payload, ...previous]);
82
+ return payload;
83
+ });
84
+
85
+ export const editSettingRequest = async (
86
+ config: RunningLowApiConfig,
87
+ storageId: number,
88
+ id: number,
89
+ dto: EditSettingRequest
90
+ ): Promise<RunningLowSetting> => runWithRequestState(config, async () => {
91
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
92
+ const response = await fetch(
93
+ `${normalizedBaseUrl}/api/storages/${storageId}/runninglowsettings/${id}`,
94
+ {
95
+ method: 'PUT',
96
+ headers: {
97
+ ...buildAuthHeaders(config.token),
98
+ 'Content-Type': 'application/json'
99
+ },
100
+ body: JSON.stringify(dto)
101
+ }
102
+ );
103
+
104
+ if (!response.ok) {
105
+ const err = await readJson<EditRunningLowSettingError>(response);
106
+
107
+ if (err?.runningLow)
108
+ throw err;
109
+
110
+ throw new Error('Failed to edit running low setting');
111
+ }
112
+
113
+ const payload = await readJson<RunningLowSetting>(response);
114
+ if (!payload) {
115
+ throw new Error('Edit running low response missing data');
116
+ }
117
+
118
+ config.setSettings((previous) => updateById(previous, payload));
119
+ return payload;
120
+ });
121
+
122
+ export const deleteSettingRequest = async (
123
+ config: RunningLowApiConfig,
124
+ storageId: number,
125
+ id: number
126
+ ): Promise<void> => runWithRequestState(config, async () => {
127
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
128
+ const response = await fetch(
129
+ `${normalizedBaseUrl}/api/storages/${storageId}/runninglowsettings/${id}`,
130
+ {
131
+ method: 'DELETE',
132
+ headers: buildAuthHeaders(config.token)
133
+ }
134
+ );
135
+
136
+ if (!response.ok) {
137
+ throw new Error('Failed to delete running low setting');
138
+ }
139
+
140
+ config.setSettings((previous) => previous.filter((item) => item.id !== id));
141
+ });
@@ -1,159 +1,161 @@
1
- import type { ShoppingListItem } from '../../type/models.js';
2
- import type { CreateShoppingItemRequest, EditShoppingItemRequest } from '../../type/requests.js';
3
- import type { CreateShoppingItemError, EditShoppingItemError } from '../../type/shoppingList.js';
4
- import { buildAuthHeaders, normalizeBaseUrl, readJson } from '../http.js';
5
- import { runWithRequestState, type RequestStateHandlers } from './requestState.js';
6
-
7
- type ShoppingListApiConfig = RequestStateHandlers & {
8
- baseUrl: string;
9
- token: string | null;
10
- setItems: (value: ShoppingListItem[] | ((items: ShoppingListItem[]) => ShoppingListItem[])) => void;
11
- };
12
-
13
- const updateById = (items: ShoppingListItem[], updated: ShoppingListItem): ShoppingListItem[] => {
14
- const index = items.findIndex((i) => i.id === updated.id);
15
- if (index === -1) return [updated, ...items];
16
- const next = [...items];
17
- next[index] = updated;
18
- return next;
19
- };
20
-
21
- export const fetchShoppingListRequest = async (
22
- config: ShoppingListApiConfig,
23
- storageId: number
24
- ): Promise<ShoppingListItem[]> => runWithRequestState(config, async () => {
25
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
26
- const response = await fetch(`${normalizedBaseUrl}/api/storages/${storageId}/shoppinglist`, {
27
- headers: buildAuthHeaders(config.token)
28
- });
29
-
30
- if (!response.ok) {
31
- throw new Error('Failed to fetch shopping list items');
32
- }
33
-
34
- const payload = await readJson<ShoppingListItem[]>(response);
35
- if (payload) {
36
- config.setItems(payload);
37
- return payload;
38
- }
39
-
40
- return [];
41
- });
42
-
43
- export const fetchAggregatedShoppingListRequest = async (
44
- config: ShoppingListApiConfig
45
- ): Promise<ShoppingListItem[]> => runWithRequestState(config, async () => {
46
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
47
- const response = await fetch(`${normalizedBaseUrl}/api/shoppinglist`, {
48
- headers: buildAuthHeaders(config.token)
49
- });
50
-
51
- if (!response.ok) {
52
- throw new Error('Failed to fetch aggregated shopping list');
53
- }
54
-
55
- const payload = await readJson<ShoppingListItem[]>(response);
56
- if (payload) {
57
- config.setItems(payload);
58
- return payload;
59
- }
60
-
61
- return [];
62
- });
63
-
64
- export const createStorageItemsWithShoppingListItemRequest = async (
65
- config: ShoppingListApiConfig,
66
- storageId: number,
67
- itemId: number
68
- ) => runWithRequestState(config, async () => {
69
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
70
- const response = await fetch(`${normalizedBaseUrl}/api/storages/${storageId}/shoppinglist/${itemId}`, {
71
- method: 'POST',
72
- headers: buildAuthHeaders(config.token)
73
- });
74
-
75
- if (!response.ok) {
76
- throw new Error('Failed to add items');
77
- }
78
- });
79
-
80
- export const createShoppingItemRequest = async (
81
- config: ShoppingListApiConfig,
82
- storageId: number,
83
- dto: CreateShoppingItemRequest
84
- ): Promise<ShoppingListItem> => runWithRequestState(config, async () => {
85
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
86
- const response = await fetch(`${normalizedBaseUrl}/api/storages/${storageId}/shoppinglist`, {
87
- method: 'POST',
88
- headers: {
89
- ...buildAuthHeaders(config.token),
90
- 'Content-Type': 'application/json'
91
- },
92
- body: JSON.stringify(dto)
93
- });
94
-
95
- if (!response.ok) {
96
- const err = await readJson<CreateShoppingItemError>(response);
97
-
98
- if (err?.productId || err?.amountToBuy)
99
- throw err;
100
-
101
- throw new Error('Failed to create shopping list item');
102
- }
103
-
104
- const payload = await readJson<ShoppingListItem>(response);
105
- if (!payload) throw new Error('Create shopping item response missing data');
106
-
107
- config.setItems((previous) => [payload, ...previous]);
108
- return payload;
109
- });
110
-
111
- export const editShoppingItemRequest = async (
112
- config: ShoppingListApiConfig,
113
- storageId: number,
114
- itemId: number,
115
- dto: EditShoppingItemRequest
116
- ): Promise<ShoppingListItem> => runWithRequestState(config, async () => {
117
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
118
- const response = await fetch(`${normalizedBaseUrl}/api/storages/${storageId}/shoppinglist/${itemId}`, {
119
- method: 'PUT',
120
- headers: {
121
- ...buildAuthHeaders(config.token),
122
- 'Content-Type': 'application/json'
123
- },
124
- body: JSON.stringify(dto)
125
- });
126
-
127
- if (!response.ok) {
128
- const err = await readJson<EditShoppingItemError>(response);
129
-
130
- if (err?.productId || err?.amountToBuy)
131
- throw err;
132
-
133
- throw new Error('Failed to edit shopping list item');
134
- }
135
-
136
- const payload = await readJson<ShoppingListItem>(response);
137
- if (!payload) throw new Error('Edit shopping item response missing data');
138
-
139
- config.setItems((previous) => updateById(previous, payload));
140
- return payload;
141
- });
142
-
143
- export const deleteShoppingItemRequest = async (
144
- config: ShoppingListApiConfig,
145
- storageId: number,
146
- itemId: number
147
- ): Promise<void> => runWithRequestState(config, async () => {
148
- const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
149
- const response = await fetch(`${normalizedBaseUrl}/api/storages/${storageId}/shoppinglist/${itemId}`, {
150
- method: 'DELETE',
151
- headers: buildAuthHeaders(config.token)
152
- });
153
-
154
- if (!response.ok) {
155
- throw new Error('Failed to delete shopping list item');
156
- }
157
-
158
- config.setItems((previous) => previous.filter((i) => i.id !== itemId));
159
- });
1
+ import type { ShoppingListItem } from '../../type/models.js';
2
+ import type { CreateShoppingItemRequest, EditShoppingItemRequest } from '../../type/requests.js';
3
+ import type { CreateShoppingItemError, EditShoppingItemError } from '../../type/shoppingList.js';
4
+ import { buildAuthHeaders, normalizeBaseUrl, readJson } from '../http.js';
5
+ import { runWithRequestState, type RequestStateHandlers } from './requestState.js';
6
+
7
+ type ShoppingListApiConfig = RequestStateHandlers & {
8
+ baseUrl: string;
9
+ token: string | null;
10
+ setItems: (value: ShoppingListItem[] | ((items: ShoppingListItem[]) => ShoppingListItem[])) => void;
11
+ };
12
+
13
+ const updateById = (items: ShoppingListItem[], updated: ShoppingListItem): ShoppingListItem[] => {
14
+ const index = items.findIndex((i) => i.id === updated.id);
15
+ if (index === -1) return [updated, ...items];
16
+ const next = [...items];
17
+ next[index] = updated;
18
+ return next;
19
+ };
20
+
21
+ export const fetchShoppingListRequest = async (
22
+ config: ShoppingListApiConfig,
23
+ storageId: number
24
+ ): Promise<ShoppingListItem[]> => runWithRequestState(config, async () => {
25
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
26
+ const response = await fetch(`${normalizedBaseUrl}/api/storages/${storageId}/shoppinglist`, {
27
+ headers: buildAuthHeaders(config.token)
28
+ });
29
+
30
+ if (!response.ok) {
31
+ throw new Error('Failed to fetch shopping list items');
32
+ }
33
+
34
+ const payload = await readJson<ShoppingListItem[]>(response);
35
+ if (payload) {
36
+ config.setItems(payload);
37
+ return payload;
38
+ }
39
+
40
+ return [];
41
+ });
42
+
43
+ export const fetchAggregatedShoppingListRequest = async (
44
+ config: ShoppingListApiConfig
45
+ ): Promise<ShoppingListItem[]> => runWithRequestState(config, async () => {
46
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
47
+ const response = await fetch(`${normalizedBaseUrl}/api/shoppinglist`, {
48
+ headers: buildAuthHeaders(config.token)
49
+ });
50
+
51
+ if (!response.ok) {
52
+ throw new Error('Failed to fetch aggregated shopping list');
53
+ }
54
+
55
+ const payload = await readJson<ShoppingListItem[]>(response);
56
+ if (payload) {
57
+ config.setItems(payload);
58
+ return payload;
59
+ }
60
+
61
+ return [];
62
+ });
63
+
64
+ export const createStorageItemsWithShoppingListItemRequest = async (
65
+ config: ShoppingListApiConfig,
66
+ storageId: number,
67
+ itemId: number
68
+ ) => runWithRequestState(config, async () => {
69
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
70
+ const response = await fetch(`${normalizedBaseUrl}/api/storages/${storageId}/shoppinglist/${itemId}`, {
71
+ method: 'POST',
72
+ headers: buildAuthHeaders(config.token)
73
+ });
74
+
75
+ if (!response.ok) {
76
+ throw new Error('Failed to add items');
77
+ }
78
+
79
+ config.setItems((previous) => previous.filter((i) => i.id !== itemId));
80
+ });
81
+
82
+ export const createShoppingItemRequest = async (
83
+ config: ShoppingListApiConfig,
84
+ storageId: number,
85
+ dto: CreateShoppingItemRequest
86
+ ): Promise<ShoppingListItem> => runWithRequestState(config, async () => {
87
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
88
+ const response = await fetch(`${normalizedBaseUrl}/api/storages/${storageId}/shoppinglist`, {
89
+ method: 'POST',
90
+ headers: {
91
+ ...buildAuthHeaders(config.token),
92
+ 'Content-Type': 'application/json'
93
+ },
94
+ body: JSON.stringify(dto)
95
+ });
96
+
97
+ if (!response.ok) {
98
+ const err = await readJson<CreateShoppingItemError>(response);
99
+
100
+ if (err?.productId || err?.amountToBuy)
101
+ throw err;
102
+
103
+ throw new Error('Failed to create shopping list item');
104
+ }
105
+
106
+ const payload = await readJson<ShoppingListItem>(response);
107
+ if (!payload) throw new Error('Create shopping item response missing data');
108
+
109
+ config.setItems((previous) => [payload, ...previous]);
110
+ return payload;
111
+ });
112
+
113
+ export const editShoppingItemRequest = async (
114
+ config: ShoppingListApiConfig,
115
+ storageId: number,
116
+ itemId: number,
117
+ dto: EditShoppingItemRequest
118
+ ): Promise<ShoppingListItem> => runWithRequestState(config, async () => {
119
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
120
+ const response = await fetch(`${normalizedBaseUrl}/api/storages/${storageId}/shoppinglist/${itemId}`, {
121
+ method: 'PUT',
122
+ headers: {
123
+ ...buildAuthHeaders(config.token),
124
+ 'Content-Type': 'application/json'
125
+ },
126
+ body: JSON.stringify(dto)
127
+ });
128
+
129
+ if (!response.ok) {
130
+ const err = await readJson<EditShoppingItemError>(response);
131
+
132
+ if (err?.productId || err?.amountToBuy)
133
+ throw err;
134
+
135
+ throw new Error('Failed to edit shopping list item');
136
+ }
137
+
138
+ const payload = await readJson<ShoppingListItem>(response);
139
+ if (!payload) throw new Error('Edit shopping item response missing data');
140
+
141
+ config.setItems((previous) => updateById(previous, payload));
142
+ return payload;
143
+ });
144
+
145
+ export const deleteShoppingItemRequest = async (
146
+ config: ShoppingListApiConfig,
147
+ storageId: number,
148
+ itemId: number
149
+ ): Promise<void> => runWithRequestState(config, async () => {
150
+ const normalizedBaseUrl = normalizeBaseUrl(config.baseUrl);
151
+ const response = await fetch(`${normalizedBaseUrl}/api/storages/${storageId}/shoppinglist/${itemId}`, {
152
+ method: 'DELETE',
153
+ headers: buildAuthHeaders(config.token)
154
+ });
155
+
156
+ if (!response.ok) {
157
+ throw new Error('Failed to delete shopping list item');
158
+ }
159
+
160
+ config.setItems((previous) => previous.filter((i) => i.id !== itemId));
161
+ });