@spotsdev/sdk 1.0.0

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 (79) hide show
  1. package/dist/api/client.d.ts +12 -0
  2. package/dist/api/client.js +68 -0
  3. package/dist/api/mutations/clubs.d.ts +47 -0
  4. package/dist/api/mutations/clubs.js +95 -0
  5. package/dist/api/mutations/conversations.d.ts +45 -0
  6. package/dist/api/mutations/conversations.js +110 -0
  7. package/dist/api/mutations/index.d.ts +13 -0
  8. package/dist/api/mutations/index.js +38 -0
  9. package/dist/api/mutations/notifications.d.ts +38 -0
  10. package/dist/api/mutations/notifications.js +64 -0
  11. package/dist/api/mutations/orders.d.ts +73 -0
  12. package/dist/api/mutations/orders.js +116 -0
  13. package/dist/api/mutations/posts.d.ts +123 -0
  14. package/dist/api/mutations/posts.js +229 -0
  15. package/dist/api/mutations/products.d.ts +81 -0
  16. package/dist/api/mutations/products.js +102 -0
  17. package/dist/api/mutations/spots.d.ts +59 -0
  18. package/dist/api/mutations/spots.js +129 -0
  19. package/dist/api/mutations/users.d.ts +71 -0
  20. package/dist/api/mutations/users.js +173 -0
  21. package/dist/api/queries/auth.d.ts +37 -0
  22. package/dist/api/queries/auth.js +61 -0
  23. package/dist/api/queries/clubs.d.ts +52 -0
  24. package/dist/api/queries/clubs.js +116 -0
  25. package/dist/api/queries/conversations.d.ts +52 -0
  26. package/dist/api/queries/conversations.js +83 -0
  27. package/dist/api/queries/index.d.ts +26 -0
  28. package/dist/api/queries/index.js +65 -0
  29. package/dist/api/queries/misc.d.ts +54 -0
  30. package/dist/api/queries/misc.js +129 -0
  31. package/dist/api/queries/notifications.d.ts +34 -0
  32. package/dist/api/queries/notifications.js +62 -0
  33. package/dist/api/queries/orders.d.ts +45 -0
  34. package/dist/api/queries/orders.js +93 -0
  35. package/dist/api/queries/posts.d.ts +55 -0
  36. package/dist/api/queries/posts.js +130 -0
  37. package/dist/api/queries/products.d.ts +52 -0
  38. package/dist/api/queries/products.js +89 -0
  39. package/dist/api/queries/spots.d.ts +78 -0
  40. package/dist/api/queries/spots.js +168 -0
  41. package/dist/api/queries/templates.d.ts +42 -0
  42. package/dist/api/queries/templates.js +86 -0
  43. package/dist/api/queries/users.d.ts +90 -0
  44. package/dist/api/queries/users.js +187 -0
  45. package/dist/api/services/index.d.ts +2 -0
  46. package/dist/api/services/index.js +8 -0
  47. package/dist/api/services/marketplace.d.ts +129 -0
  48. package/dist/api/services/marketplace.js +168 -0
  49. package/dist/api/types.d.ts +54 -0
  50. package/dist/api/types.js +34 -0
  51. package/dist/index.d.ts +38 -0
  52. package/dist/index.js +73 -0
  53. package/package.json +57 -0
  54. package/src/api/client.ts +78 -0
  55. package/src/api/mutations/clubs.ts +107 -0
  56. package/src/api/mutations/conversations.ts +124 -0
  57. package/src/api/mutations/index.ts +29 -0
  58. package/src/api/mutations/notifications.ts +70 -0
  59. package/src/api/mutations/orders.ts +174 -0
  60. package/src/api/mutations/posts.ts +278 -0
  61. package/src/api/mutations/products.ts +160 -0
  62. package/src/api/mutations/spots.ts +146 -0
  63. package/src/api/mutations/users.ts +197 -0
  64. package/src/api/queries/auth.ts +67 -0
  65. package/src/api/queries/clubs.ts +135 -0
  66. package/src/api/queries/conversations.ts +94 -0
  67. package/src/api/queries/index.ts +48 -0
  68. package/src/api/queries/misc.ts +140 -0
  69. package/src/api/queries/notifications.ts +66 -0
  70. package/src/api/queries/orders.ts +119 -0
  71. package/src/api/queries/posts.ts +142 -0
  72. package/src/api/queries/products.ts +123 -0
  73. package/src/api/queries/spots.ts +201 -0
  74. package/src/api/queries/templates.ts +95 -0
  75. package/src/api/queries/users.ts +206 -0
  76. package/src/api/services/index.ts +6 -0
  77. package/src/api/services/marketplace.ts +265 -0
  78. package/src/api/types.ts +144 -0
  79. package/src/index.ts +63 -0
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Notifications Mutation Hooks
3
+ *
4
+ * TanStack Query hooks for notification mutation operations.
5
+ */
6
+
7
+ import { useMutation, useQueryClient, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
8
+ import { getApiClient } from '../client';
9
+ import { notificationKeys } from '../queries/notifications';
10
+
11
+ // ============================================================================
12
+ // MUTATION HOOKS
13
+ // ============================================================================
14
+
15
+ /**
16
+ * Mark notifications as read
17
+ *
18
+ * @endpoint PUT /api/v1/notifications/read
19
+ */
20
+ export function useMarkNotificationsRead(
21
+ options?: Omit<UseMutationOptions<void, Error, { notificationIds?: string[] }>, 'mutationFn'>
22
+ ): UseMutationResult<void, Error, { notificationIds?: string[] }> {
23
+ const queryClient = useQueryClient();
24
+
25
+ return useMutation({
26
+ mutationFn: async (data: { notificationIds?: string[] }): Promise<void> => {
27
+ const client = getApiClient();
28
+ await client.put('/api/v1/notifications/read', data);
29
+ },
30
+ onSuccess: () => {
31
+ queryClient.invalidateQueries({ queryKey: notificationKeys.lists() });
32
+ queryClient.invalidateQueries({ queryKey: notificationKeys.unreadCount() });
33
+ },
34
+ ...options,
35
+ });
36
+ }
37
+
38
+ /**
39
+ * Register device token for push notifications
40
+ *
41
+ * @endpoint POST /api/v1/device-tokens
42
+ */
43
+ export function useRegisterDeviceToken(
44
+ options?: Omit<UseMutationOptions<void, Error, { token: string; platform: 'ios' | 'android' | 'web' }>, 'mutationFn'>
45
+ ): UseMutationResult<void, Error, { token: string; platform: 'ios' | 'android' | 'web' }> {
46
+ return useMutation({
47
+ mutationFn: async (data): Promise<void> => {
48
+ const client = getApiClient();
49
+ await client.post('/api/v1/device-tokens', data);
50
+ },
51
+ ...options,
52
+ });
53
+ }
54
+
55
+ /**
56
+ * Remove device token
57
+ *
58
+ * @endpoint DELETE /api/v1/device-tokens
59
+ */
60
+ export function useRemoveDeviceToken(
61
+ options?: Omit<UseMutationOptions<void, Error, { token: string }>, 'mutationFn'>
62
+ ): UseMutationResult<void, Error, { token: string }> {
63
+ return useMutation({
64
+ mutationFn: async (data): Promise<void> => {
65
+ const client = getApiClient();
66
+ await client.delete('/api/v1/device-tokens', { data });
67
+ },
68
+ ...options,
69
+ });
70
+ }
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Orders Mutation Hooks
3
+ *
4
+ * TanStack Query hooks for order mutation operations.
5
+ */
6
+
7
+ import { useMutation, useQueryClient, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
8
+ import { getApiClient } from '../client';
9
+ import { orderKeys, OrderWithDetails } from '../queries/orders';
10
+ import { productKeys } from '../queries/products';
11
+ import type { Order, OrderStatus, ApiResponse } from '../types';
12
+
13
+ // ============================================================================
14
+ // TYPES
15
+ // ============================================================================
16
+
17
+ export interface CartItem {
18
+ productId: string;
19
+ quantity: number;
20
+ }
21
+
22
+ export interface CreateOrderRequest {
23
+ spotId: string;
24
+ items: CartItem[];
25
+ notes?: string;
26
+ deliveryAddress?: string;
27
+ }
28
+
29
+ export interface CreateOrderResponse extends Order {
30
+ items: Array<{
31
+ id: string;
32
+ productId: string;
33
+ productName: string;
34
+ quantity: number;
35
+ unitPrice: number;
36
+ totalPrice: number;
37
+ }>;
38
+ }
39
+
40
+ export interface PaymentIntentResponse {
41
+ clientSecret: string;
42
+ paymentIntentId: string;
43
+ }
44
+
45
+ export interface CoinbaseChargeResponse {
46
+ chargeId: string;
47
+ chargeCode: string;
48
+ hostedUrl: string;
49
+ }
50
+
51
+ // ============================================================================
52
+ // MUTATION HOOKS
53
+ // ============================================================================
54
+
55
+ /**
56
+ * Create a new order
57
+ *
58
+ * @endpoint POST /api/v1/orders
59
+ */
60
+ export function useCreateOrder(
61
+ options?: Omit<UseMutationOptions<CreateOrderResponse, Error, CreateOrderRequest>, 'mutationFn'>
62
+ ): UseMutationResult<CreateOrderResponse, Error, CreateOrderRequest> {
63
+ const queryClient = useQueryClient();
64
+
65
+ return useMutation({
66
+ mutationFn: async (data: CreateOrderRequest): Promise<CreateOrderResponse> => {
67
+ const client = getApiClient();
68
+ const response = await client.post<ApiResponse<CreateOrderResponse>>('/api/v1/orders', data);
69
+ return response.data.data;
70
+ },
71
+ onSuccess: (_, variables) => {
72
+ // Invalidate products to reflect updated stock
73
+ queryClient.invalidateQueries({ queryKey: productKeys.bySpot(variables.spotId) });
74
+ // Invalidate my orders list
75
+ queryClient.invalidateQueries({ queryKey: orderKeys.list({ my: true }) });
76
+ },
77
+ ...options,
78
+ });
79
+ }
80
+
81
+ /**
82
+ * Create Stripe PaymentIntent for an order
83
+ *
84
+ * @endpoint POST /api/v1/payments/stripe/intent/{orderId}
85
+ */
86
+ export function useCreateStripeIntent(
87
+ options?: Omit<UseMutationOptions<PaymentIntentResponse, Error, string>, 'mutationFn'>
88
+ ): UseMutationResult<PaymentIntentResponse, Error, string> {
89
+ return useMutation({
90
+ mutationFn: async (orderId: string): Promise<PaymentIntentResponse> => {
91
+ const client = getApiClient();
92
+ const response = await client.post<ApiResponse<PaymentIntentResponse>>(
93
+ `/api/v1/payments/stripe/intent/${orderId}`
94
+ );
95
+ return response.data.data;
96
+ },
97
+ ...options,
98
+ });
99
+ }
100
+
101
+ /**
102
+ * Create Coinbase Commerce charge for an order
103
+ *
104
+ * @endpoint POST /api/v1/payments/coinbase/charge/{orderId}
105
+ */
106
+ export function useCreateCoinbaseCharge(
107
+ options?: Omit<UseMutationOptions<CoinbaseChargeResponse, Error, string>, 'mutationFn'>
108
+ ): UseMutationResult<CoinbaseChargeResponse, Error, string> {
109
+ return useMutation({
110
+ mutationFn: async (orderId: string): Promise<CoinbaseChargeResponse> => {
111
+ const client = getApiClient();
112
+ const response = await client.post<ApiResponse<CoinbaseChargeResponse>>(
113
+ `/api/v1/payments/coinbase/charge/${orderId}`
114
+ );
115
+ return response.data.data;
116
+ },
117
+ ...options,
118
+ });
119
+ }
120
+
121
+ /**
122
+ * Update order status (seller action)
123
+ *
124
+ * @endpoint PUT /api/v1/orders/{orderId}/status
125
+ */
126
+ export function useUpdateOrderStatus(
127
+ options?: Omit<
128
+ UseMutationOptions<OrderWithDetails, Error, { orderId: string; status: OrderStatus }>,
129
+ 'mutationFn'
130
+ >
131
+ ): UseMutationResult<OrderWithDetails, Error, { orderId: string; status: OrderStatus }> {
132
+ const queryClient = useQueryClient();
133
+
134
+ return useMutation({
135
+ mutationFn: async ({ orderId, status }): Promise<OrderWithDetails> => {
136
+ const client = getApiClient();
137
+ const response = await client.put<ApiResponse<OrderWithDetails>>(`/api/v1/orders/${orderId}/status`, {
138
+ status,
139
+ });
140
+ return response.data.data;
141
+ },
142
+ onSuccess: (data) => {
143
+ queryClient.setQueryData(orderKeys.detail(data.id), data);
144
+ queryClient.invalidateQueries({ queryKey: orderKeys.spotOrders(data.spotId) });
145
+ },
146
+ ...options,
147
+ });
148
+ }
149
+
150
+ /**
151
+ * Cancel an order (buyer action, only for pending orders)
152
+ *
153
+ * @endpoint POST /api/v1/orders/{orderId}/cancel
154
+ */
155
+ export function useCancelOrder(
156
+ options?: Omit<UseMutationOptions<OrderWithDetails, Error, string>, 'mutationFn'>
157
+ ): UseMutationResult<OrderWithDetails, Error, string> {
158
+ const queryClient = useQueryClient();
159
+
160
+ return useMutation({
161
+ mutationFn: async (orderId: string): Promise<OrderWithDetails> => {
162
+ const client = getApiClient();
163
+ const response = await client.post<ApiResponse<OrderWithDetails>>(`/api/v1/orders/${orderId}/cancel`);
164
+ return response.data.data;
165
+ },
166
+ onSuccess: (data) => {
167
+ queryClient.setQueryData(orderKeys.detail(data.id), data);
168
+ queryClient.invalidateQueries({ queryKey: orderKeys.list({ my: true }) });
169
+ // Restore stock
170
+ queryClient.invalidateQueries({ queryKey: productKeys.bySpot(data.spotId) });
171
+ },
172
+ ...options,
173
+ });
174
+ }
@@ -0,0 +1,278 @@
1
+ /**
2
+ * Posts Mutation Hooks
3
+ *
4
+ * TanStack Query hooks for post/board mutation operations.
5
+ */
6
+
7
+ import { useMutation, useQueryClient, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
8
+ import { getApiClient } from '../client';
9
+ import { postKeys } from '../queries/posts';
10
+ import type {
11
+ Post,
12
+ PostResponse,
13
+ CreatePostRequest,
14
+ CreateReplyRequest,
15
+ RespondToPostRequest,
16
+ UpdateResponseRequest,
17
+ ApiResponse,
18
+ UpvoteResponse,
19
+ PostStatusDto,
20
+ } from '../types';
21
+
22
+ // ============================================================================
23
+ // MUTATION HOOKS
24
+ // ============================================================================
25
+
26
+ /**
27
+ * Create a new post
28
+ *
29
+ * @endpoint POST /api/v1/spots/{spotId}/posts
30
+ */
31
+ export function useCreatePost(
32
+ options?: Omit<UseMutationOptions<Post, Error, { spotId: string } & CreatePostRequest>, 'mutationFn'>
33
+ ): UseMutationResult<Post, Error, { spotId: string } & CreatePostRequest> {
34
+ const queryClient = useQueryClient();
35
+
36
+ return useMutation({
37
+ mutationFn: async ({ spotId, ...data }): Promise<Post> => {
38
+ const client = getApiClient();
39
+ const response = await client.post<ApiResponse<Post>>(`/api/v1/spots/${spotId}/posts`, data);
40
+ return response.data.data;
41
+ },
42
+ onSuccess: (_, variables) => {
43
+ queryClient.invalidateQueries({ queryKey: postKeys.bySpot(variables.spotId) });
44
+ },
45
+ ...options,
46
+ });
47
+ }
48
+
49
+ /**
50
+ * Update a post
51
+ *
52
+ * @endpoint PUT /api/v1/posts/{postId}
53
+ */
54
+ export function useUpdatePost(
55
+ options?: Omit<UseMutationOptions<Post, Error, { postId: string; title?: string; content?: string }>, 'mutationFn'>
56
+ ): UseMutationResult<Post, Error, { postId: string; title?: string; content?: string }> {
57
+ const queryClient = useQueryClient();
58
+
59
+ return useMutation({
60
+ mutationFn: async ({ postId, ...data }): Promise<Post> => {
61
+ const client = getApiClient();
62
+ const response = await client.put<ApiResponse<Post>>(`/api/v1/posts/${postId}`, data);
63
+ return response.data.data;
64
+ },
65
+ onSuccess: (data, variables) => {
66
+ queryClient.setQueryData(postKeys.detail(variables.postId), data);
67
+ },
68
+ ...options,
69
+ });
70
+ }
71
+
72
+ /**
73
+ * Delete a post
74
+ *
75
+ * @endpoint DELETE /api/v1/posts/{postId}
76
+ */
77
+ export function useDeletePost(
78
+ options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>
79
+ ): UseMutationResult<void, Error, string> {
80
+ const queryClient = useQueryClient();
81
+
82
+ return useMutation({
83
+ mutationFn: async (postId: string): Promise<void> => {
84
+ const client = getApiClient();
85
+ await client.delete(`/api/v1/posts/${postId}`);
86
+ },
87
+ onSuccess: (_, postId) => {
88
+ queryClient.invalidateQueries({ queryKey: postKeys.detail(postId) });
89
+ queryClient.invalidateQueries({ queryKey: postKeys.lists() });
90
+ },
91
+ ...options,
92
+ });
93
+ }
94
+
95
+ /**
96
+ * Fulfill a post (mark as fulfilled)
97
+ *
98
+ * @endpoint PUT /api/v1/posts/{postId}/fulfill
99
+ */
100
+ export function useFulfillPost(
101
+ options?: Omit<UseMutationOptions<Post, Error, string>, 'mutationFn'>
102
+ ): UseMutationResult<Post, Error, string> {
103
+ const queryClient = useQueryClient();
104
+
105
+ return useMutation({
106
+ mutationFn: async (postId: string): Promise<Post> => {
107
+ const client = getApiClient();
108
+ const response = await client.put<ApiResponse<Post>>(`/api/v1/posts/${postId}/fulfill`);
109
+ return response.data.data;
110
+ },
111
+ onSuccess: (data, postId) => {
112
+ queryClient.setQueryData(postKeys.detail(postId), data);
113
+ },
114
+ ...options,
115
+ });
116
+ }
117
+
118
+ /**
119
+ * Upvote/unupvote a post
120
+ *
121
+ * @endpoint POST /api/v1/posts/{postId}/upvote
122
+ */
123
+ export function useUpvotePost(
124
+ options?: Omit<UseMutationOptions<UpvoteResponse, Error, string>, 'mutationFn'>
125
+ ): UseMutationResult<UpvoteResponse, Error, string> {
126
+ const queryClient = useQueryClient();
127
+
128
+ return useMutation({
129
+ mutationFn: async (postId: string): Promise<UpvoteResponse> => {
130
+ const client = getApiClient();
131
+ const response = await client.post<ApiResponse<UpvoteResponse>>(`/api/v1/posts/${postId}/upvote`);
132
+ return response.data.data;
133
+ },
134
+ onSuccess: (_, postId) => {
135
+ queryClient.invalidateQueries({ queryKey: postKeys.detail(postId) });
136
+ },
137
+ ...options,
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Create a reply to a post
143
+ *
144
+ * @endpoint POST /api/v1/posts/{postId}/reply
145
+ */
146
+ export function useCreateReply(
147
+ options?: Omit<UseMutationOptions<unknown, Error, { postId: string } & CreateReplyRequest>, 'mutationFn'>
148
+ ): UseMutationResult<unknown, Error, { postId: string } & CreateReplyRequest> {
149
+ const queryClient = useQueryClient();
150
+
151
+ return useMutation({
152
+ mutationFn: async ({ postId, ...data }) => {
153
+ const client = getApiClient();
154
+ const response = await client.post<ApiResponse<unknown>>(`/api/v1/posts/${postId}/reply`, data);
155
+ return response.data.data;
156
+ },
157
+ onSuccess: (_, variables) => {
158
+ queryClient.invalidateQueries({ queryKey: postKeys.detail(variables.postId) });
159
+ },
160
+ ...options,
161
+ });
162
+ }
163
+
164
+ /**
165
+ * Delete a reply
166
+ *
167
+ * @endpoint DELETE /api/v1/replies/{replyId}
168
+ */
169
+ export function useDeleteReply(
170
+ options?: Omit<UseMutationOptions<void, Error, { replyId: string; postId: string }>, 'mutationFn'>
171
+ ): UseMutationResult<void, Error, { replyId: string; postId: string }> {
172
+ const queryClient = useQueryClient();
173
+
174
+ return useMutation({
175
+ mutationFn: async ({ replyId }): Promise<void> => {
176
+ const client = getApiClient();
177
+ await client.delete(`/api/v1/replies/${replyId}`);
178
+ },
179
+ onSuccess: (_, variables) => {
180
+ queryClient.invalidateQueries({ queryKey: postKeys.detail(variables.postId) });
181
+ },
182
+ ...options,
183
+ });
184
+ }
185
+
186
+ /**
187
+ * Respond to a post (express interest)
188
+ *
189
+ * @endpoint POST /api/v1/posts/{postId}/respond
190
+ */
191
+ export function useRespondToPost(
192
+ options?: Omit<UseMutationOptions<PostResponse, Error, { postId: string } & RespondToPostRequest>, 'mutationFn'>
193
+ ): UseMutationResult<PostResponse, Error, { postId: string } & RespondToPostRequest> {
194
+ const queryClient = useQueryClient();
195
+
196
+ return useMutation({
197
+ mutationFn: async ({ postId, ...data }): Promise<PostResponse> => {
198
+ const client = getApiClient();
199
+ const response = await client.post<ApiResponse<PostResponse>>(`/api/v1/posts/${postId}/respond`, data);
200
+ return response.data.data;
201
+ },
202
+ onSuccess: (_, variables) => {
203
+ queryClient.invalidateQueries({ queryKey: postKeys.detail(variables.postId) });
204
+ queryClient.invalidateQueries({ queryKey: postKeys.responses(variables.postId) });
205
+ },
206
+ ...options,
207
+ });
208
+ }
209
+
210
+ /**
211
+ * Accept or decline a response
212
+ *
213
+ * @endpoint PUT /api/v1/responses/{responseId}
214
+ */
215
+ export function useUpdateResponse(
216
+ options?: Omit<UseMutationOptions<PostResponse, Error, { responseId: string; postId: string } & UpdateResponseRequest>, 'mutationFn'>
217
+ ): UseMutationResult<PostResponse, Error, { responseId: string; postId: string } & UpdateResponseRequest> {
218
+ const queryClient = useQueryClient();
219
+
220
+ return useMutation({
221
+ mutationFn: async ({ responseId, postId: _, ...data }): Promise<PostResponse> => {
222
+ const client = getApiClient();
223
+ const response = await client.put<ApiResponse<PostResponse>>(`/api/v1/responses/${responseId}`, data);
224
+ return response.data.data;
225
+ },
226
+ onSuccess: (_, variables) => {
227
+ queryClient.invalidateQueries({ queryKey: postKeys.responses(variables.postId) });
228
+ },
229
+ ...options,
230
+ });
231
+ }
232
+
233
+ /**
234
+ * Report a post
235
+ *
236
+ * @endpoint POST /api/v1/posts/{postId}/report
237
+ */
238
+ export function useReportPost(
239
+ options?: Omit<UseMutationOptions<void, Error, { postId: string; reason: string; details?: string }>, 'mutationFn'>
240
+ ): UseMutationResult<void, Error, { postId: string; reason: string; details?: string }> {
241
+ return useMutation({
242
+ mutationFn: async ({ postId, ...data }): Promise<void> => {
243
+ const client = getApiClient();
244
+ await client.post(`/api/v1/posts/${postId}/report`, data);
245
+ },
246
+ ...options,
247
+ });
248
+ }
249
+
250
+ // PostStatusUpdate matches partial PostStatusDto for updates
251
+ interface PostStatusUpdate {
252
+ isRead?: boolean;
253
+ isHidden?: boolean;
254
+ isPinned?: boolean;
255
+ }
256
+
257
+ /**
258
+ * Update user's status for a post (read/hidden/pinned)
259
+ *
260
+ * @endpoint PUT /api/v1/posts/{postId}/status
261
+ */
262
+ export function useUpdatePostStatus(
263
+ options?: Omit<UseMutationOptions<PostStatusDto, Error, { postId: string } & PostStatusUpdate>, 'mutationFn'>
264
+ ): UseMutationResult<PostStatusDto, Error, { postId: string } & PostStatusUpdate> {
265
+ const queryClient = useQueryClient();
266
+
267
+ return useMutation({
268
+ mutationFn: async ({ postId, ...data }): Promise<PostStatusDto> => {
269
+ const client = getApiClient();
270
+ const response = await client.put<ApiResponse<PostStatusDto>>(`/api/v1/posts/${postId}/status`, data);
271
+ return response.data.data;
272
+ },
273
+ onSuccess: (data, variables) => {
274
+ queryClient.setQueryData(postKeys.status(variables.postId), data);
275
+ },
276
+ ...options,
277
+ });
278
+ }
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Products Mutation Hooks
3
+ *
4
+ * TanStack Query hooks for product mutation operations.
5
+ */
6
+
7
+ import { useMutation, useQueryClient, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
8
+ import { getApiClient } from '../client';
9
+ import { productKeys } from '../queries/products';
10
+ import type { Product, ProductType, ProductStatus, ApiResponse } from '../types';
11
+
12
+ // ============================================================================
13
+ // TYPES
14
+ // ============================================================================
15
+
16
+ export interface CreateProductRequest {
17
+ spotId: string;
18
+ name: string;
19
+ description?: string;
20
+ type: ProductType;
21
+ price: number;
22
+ currency?: string;
23
+ stockQuantity?: number;
24
+ lowStockThreshold?: number;
25
+ validFrom?: string;
26
+ validUntil?: string;
27
+ deliveryRadiusKm?: number;
28
+ prepTimeMinutes?: number;
29
+ maxCapacity?: number;
30
+ eventDate?: string;
31
+ imageUrl?: string;
32
+ metadata?: Record<string, unknown>;
33
+ }
34
+
35
+ export interface UpdateProductRequest {
36
+ name?: string;
37
+ description?: string;
38
+ price?: number;
39
+ stockQuantity?: number;
40
+ lowStockThreshold?: number;
41
+ status?: ProductStatus;
42
+ validFrom?: string;
43
+ validUntil?: string;
44
+ deliveryRadiusKm?: number;
45
+ prepTimeMinutes?: number;
46
+ maxCapacity?: number;
47
+ eventDate?: string;
48
+ imageUrl?: string;
49
+ metadata?: Record<string, unknown>;
50
+ }
51
+
52
+ // ============================================================================
53
+ // MUTATION HOOKS
54
+ // ============================================================================
55
+
56
+ /**
57
+ * Create a new product
58
+ *
59
+ * @endpoint POST /api/v1/spots/{spotId}/products
60
+ */
61
+ export function useCreateProduct(
62
+ options?: Omit<UseMutationOptions<Product, Error, CreateProductRequest>, 'mutationFn'>
63
+ ): UseMutationResult<Product, Error, CreateProductRequest> {
64
+ const queryClient = useQueryClient();
65
+
66
+ return useMutation({
67
+ mutationFn: async (data: CreateProductRequest): Promise<Product> => {
68
+ const client = getApiClient();
69
+ const { spotId, ...productData } = data;
70
+ const response = await client.post<ApiResponse<Product>>(
71
+ `/api/v1/spots/${spotId}/products`,
72
+ productData
73
+ );
74
+ return response.data.data;
75
+ },
76
+ onSuccess: (_, variables) => {
77
+ queryClient.invalidateQueries({ queryKey: productKeys.bySpot(variables.spotId) });
78
+ queryClient.invalidateQueries({ queryKey: productKeys.list({ my: true }) });
79
+ },
80
+ ...options,
81
+ });
82
+ }
83
+
84
+ /**
85
+ * Update a product
86
+ *
87
+ * @endpoint PUT /api/v1/products/{productId}
88
+ */
89
+ export function useUpdateProduct(
90
+ options?: Omit<UseMutationOptions<Product, Error, { productId: string; data: UpdateProductRequest }>, 'mutationFn'>
91
+ ): UseMutationResult<Product, Error, { productId: string; data: UpdateProductRequest }> {
92
+ const queryClient = useQueryClient();
93
+
94
+ return useMutation({
95
+ mutationFn: async ({ productId, data }): Promise<Product> => {
96
+ const client = getApiClient();
97
+ const response = await client.put<ApiResponse<Product>>(`/api/v1/products/${productId}`, data);
98
+ return response.data.data;
99
+ },
100
+ onSuccess: (data) => {
101
+ queryClient.setQueryData(productKeys.detail(data.id), data);
102
+ queryClient.invalidateQueries({ queryKey: productKeys.bySpot(data.spotId) });
103
+ queryClient.invalidateQueries({ queryKey: productKeys.list({ my: true }) });
104
+ },
105
+ ...options,
106
+ });
107
+ }
108
+
109
+ /**
110
+ * Delete a product
111
+ *
112
+ * @endpoint DELETE /api/v1/products/{productId}
113
+ */
114
+ export function useDeleteProduct(
115
+ options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>
116
+ ): UseMutationResult<void, Error, string> {
117
+ const queryClient = useQueryClient();
118
+
119
+ return useMutation({
120
+ mutationFn: async (productId: string): Promise<void> => {
121
+ const client = getApiClient();
122
+ await client.delete(`/api/v1/products/${productId}`);
123
+ },
124
+ onSuccess: () => {
125
+ queryClient.invalidateQueries({ queryKey: productKeys.all });
126
+ },
127
+ ...options,
128
+ });
129
+ }
130
+
131
+ /**
132
+ * Adjust product stock
133
+ *
134
+ * @endpoint POST /api/v1/products/{productId}/stock
135
+ */
136
+ export function useAdjustStock(
137
+ options?: Omit<
138
+ UseMutationOptions<Product, Error, { productId: string; quantity: number; reason: 'RESTOCK' | 'ADJUSTMENT'; notes?: string }>,
139
+ 'mutationFn'
140
+ >
141
+ ): UseMutationResult<Product, Error, { productId: string; quantity: number; reason: 'RESTOCK' | 'ADJUSTMENT'; notes?: string }> {
142
+ const queryClient = useQueryClient();
143
+
144
+ return useMutation({
145
+ mutationFn: async ({ productId, quantity, reason, notes }): Promise<Product> => {
146
+ const client = getApiClient();
147
+ const response = await client.post<ApiResponse<Product>>(`/api/v1/products/${productId}/stock`, {
148
+ quantity,
149
+ reason,
150
+ notes,
151
+ });
152
+ return response.data.data;
153
+ },
154
+ onSuccess: (data) => {
155
+ queryClient.setQueryData(productKeys.detail(data.id), data);
156
+ queryClient.invalidateQueries({ queryKey: productKeys.bySpot(data.spotId) });
157
+ },
158
+ ...options,
159
+ });
160
+ }