@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.
- package/dist/api/client.d.ts +12 -0
- package/dist/api/client.js +68 -0
- package/dist/api/mutations/clubs.d.ts +47 -0
- package/dist/api/mutations/clubs.js +95 -0
- package/dist/api/mutations/conversations.d.ts +45 -0
- package/dist/api/mutations/conversations.js +110 -0
- package/dist/api/mutations/index.d.ts +13 -0
- package/dist/api/mutations/index.js +38 -0
- package/dist/api/mutations/notifications.d.ts +38 -0
- package/dist/api/mutations/notifications.js +64 -0
- package/dist/api/mutations/orders.d.ts +73 -0
- package/dist/api/mutations/orders.js +116 -0
- package/dist/api/mutations/posts.d.ts +123 -0
- package/dist/api/mutations/posts.js +229 -0
- package/dist/api/mutations/products.d.ts +81 -0
- package/dist/api/mutations/products.js +102 -0
- package/dist/api/mutations/spots.d.ts +59 -0
- package/dist/api/mutations/spots.js +129 -0
- package/dist/api/mutations/users.d.ts +71 -0
- package/dist/api/mutations/users.js +173 -0
- package/dist/api/queries/auth.d.ts +37 -0
- package/dist/api/queries/auth.js +61 -0
- package/dist/api/queries/clubs.d.ts +52 -0
- package/dist/api/queries/clubs.js +116 -0
- package/dist/api/queries/conversations.d.ts +52 -0
- package/dist/api/queries/conversations.js +83 -0
- package/dist/api/queries/index.d.ts +26 -0
- package/dist/api/queries/index.js +65 -0
- package/dist/api/queries/misc.d.ts +54 -0
- package/dist/api/queries/misc.js +129 -0
- package/dist/api/queries/notifications.d.ts +34 -0
- package/dist/api/queries/notifications.js +62 -0
- package/dist/api/queries/orders.d.ts +45 -0
- package/dist/api/queries/orders.js +93 -0
- package/dist/api/queries/posts.d.ts +55 -0
- package/dist/api/queries/posts.js +130 -0
- package/dist/api/queries/products.d.ts +52 -0
- package/dist/api/queries/products.js +89 -0
- package/dist/api/queries/spots.d.ts +78 -0
- package/dist/api/queries/spots.js +168 -0
- package/dist/api/queries/templates.d.ts +42 -0
- package/dist/api/queries/templates.js +86 -0
- package/dist/api/queries/users.d.ts +90 -0
- package/dist/api/queries/users.js +187 -0
- package/dist/api/services/index.d.ts +2 -0
- package/dist/api/services/index.js +8 -0
- package/dist/api/services/marketplace.d.ts +129 -0
- package/dist/api/services/marketplace.js +168 -0
- package/dist/api/types.d.ts +54 -0
- package/dist/api/types.js +34 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +73 -0
- package/package.json +57 -0
- package/src/api/client.ts +78 -0
- package/src/api/mutations/clubs.ts +107 -0
- package/src/api/mutations/conversations.ts +124 -0
- package/src/api/mutations/index.ts +29 -0
- package/src/api/mutations/notifications.ts +70 -0
- package/src/api/mutations/orders.ts +174 -0
- package/src/api/mutations/posts.ts +278 -0
- package/src/api/mutations/products.ts +160 -0
- package/src/api/mutations/spots.ts +146 -0
- package/src/api/mutations/users.ts +197 -0
- package/src/api/queries/auth.ts +67 -0
- package/src/api/queries/clubs.ts +135 -0
- package/src/api/queries/conversations.ts +94 -0
- package/src/api/queries/index.ts +48 -0
- package/src/api/queries/misc.ts +140 -0
- package/src/api/queries/notifications.ts +66 -0
- package/src/api/queries/orders.ts +119 -0
- package/src/api/queries/posts.ts +142 -0
- package/src/api/queries/products.ts +123 -0
- package/src/api/queries/spots.ts +201 -0
- package/src/api/queries/templates.ts +95 -0
- package/src/api/queries/users.ts +206 -0
- package/src/api/services/index.ts +6 -0
- package/src/api/services/marketplace.ts +265 -0
- package/src/api/types.ts +144 -0
- 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
|
+
}
|