@spotsdev/sdk 1.0.0 → 1.2.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 (74) hide show
  1. package/dist/api/client.d.ts +1 -1
  2. package/dist/api/client.js +7 -3
  3. package/dist/api/entities.d.ts +318 -0
  4. package/dist/api/entities.js +9 -0
  5. package/dist/api/mutations/clubs.d.ts +6 -6
  6. package/dist/api/mutations/clubs.js +12 -10
  7. package/dist/api/mutations/conversations.d.ts +7 -7
  8. package/dist/api/mutations/conversations.js +17 -13
  9. package/dist/api/mutations/index.js +1 -1
  10. package/dist/api/mutations/notifications.d.ts +4 -4
  11. package/dist/api/mutations/notifications.js +7 -7
  12. package/dist/api/mutations/orders.d.ts +7 -7
  13. package/dist/api/mutations/orders.js +11 -13
  14. package/dist/api/mutations/posts.d.ts +13 -13
  15. package/dist/api/mutations/posts.js +41 -29
  16. package/dist/api/mutations/products.d.ts +5 -5
  17. package/dist/api/mutations/products.js +9 -13
  18. package/dist/api/mutations/spots.d.ts +42 -8
  19. package/dist/api/mutations/spots.js +51 -13
  20. package/dist/api/mutations/users.d.ts +12 -10
  21. package/dist/api/mutations/users.js +20 -18
  22. package/dist/api/queries/auth.d.ts +5 -5
  23. package/dist/api/queries/auth.js +7 -7
  24. package/dist/api/queries/clubs.d.ts +7 -7
  25. package/dist/api/queries/clubs.js +11 -11
  26. package/dist/api/queries/conversations.d.ts +5 -5
  27. package/dist/api/queries/conversations.js +7 -7
  28. package/dist/api/queries/index.js +1 -1
  29. package/dist/api/queries/misc.d.ts +8 -32
  30. package/dist/api/queries/misc.js +28 -66
  31. package/dist/api/queries/notifications.d.ts +4 -4
  32. package/dist/api/queries/notifications.js +5 -5
  33. package/dist/api/queries/orders.d.ts +4 -4
  34. package/dist/api/queries/orders.js +7 -7
  35. package/dist/api/queries/posts.d.ts +44 -7
  36. package/dist/api/queries/posts.js +118 -15
  37. package/dist/api/queries/products.d.ts +6 -10
  38. package/dist/api/queries/products.js +7 -9
  39. package/dist/api/queries/spots.d.ts +31 -16
  40. package/dist/api/queries/spots.js +113 -31
  41. package/dist/api/queries/templates.d.ts +6 -9
  42. package/dist/api/queries/templates.js +8 -13
  43. package/dist/api/queries/users.d.ts +25 -11
  44. package/dist/api/queries/users.js +75 -27
  45. package/dist/api/types.d.ts +36 -33
  46. package/dist/api/types.js +6 -7
  47. package/dist/index.d.ts +1 -2
  48. package/dist/index.js +1 -8
  49. package/package.json +6 -21
  50. package/src/api/client.ts +45 -30
  51. package/src/api/entities.ts +424 -0
  52. package/src/api/mutations/clubs.ts +73 -40
  53. package/src/api/mutations/conversations.ts +91 -47
  54. package/src/api/mutations/index.ts +8 -8
  55. package/src/api/mutations/notifications.ts +48 -25
  56. package/src/api/mutations/orders.ts +101 -70
  57. package/src/api/mutations/posts.ts +229 -118
  58. package/src/api/mutations/products.ts +120 -81
  59. package/src/api/mutations/spots.ts +167 -55
  60. package/src/api/mutations/users.ts +109 -76
  61. package/src/api/queries/auth.ts +49 -24
  62. package/src/api/queries/clubs.ts +53 -38
  63. package/src/api/queries/conversations.ts +48 -30
  64. package/src/api/queries/index.ts +21 -21
  65. package/src/api/queries/misc.ts +53 -82
  66. package/src/api/queries/notifications.ts +32 -21
  67. package/src/api/queries/orders.ts +59 -42
  68. package/src/api/queries/posts.ts +203 -48
  69. package/src/api/queries/products.ts +51 -44
  70. package/src/api/queries/spots.ts +216 -85
  71. package/src/api/queries/templates.ts +39 -32
  72. package/src/api/queries/users.ts +157 -64
  73. package/src/api/types.ts +72 -118
  74. package/src/index.ts +5 -11
@@ -4,9 +4,70 @@
4
4
  * TanStack Query hooks for post/board operations.
5
5
  */
6
6
 
7
- import { useQuery, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
8
- import { getApiClient } from '../client';
9
- import type { Post, PostResponse, ApiResponse, PostStatusDto } from '../types';
7
+ import {
8
+ useQuery,
9
+ type UseQueryOptions,
10
+ type UseQueryResult,
11
+ } from '@tanstack/react-query'
12
+
13
+ import {getApiClient} from '../client'
14
+ import {
15
+ type ApiResponse,
16
+ type Post,
17
+ type PostResponse,
18
+ type PostStatusDto,
19
+ type PostUpvotesResponse,
20
+ } from '../types'
21
+
22
+ // ============================================================================
23
+ // HELPER FUNCTIONS
24
+ // ============================================================================
25
+
26
+ /**
27
+ * Extract array data from API response
28
+ * API returns { success, data: { data: [...], meta: {...} } } or { success, data: [...] }
29
+ */
30
+ function extractArrayData<T>(data: unknown): T[] {
31
+ // If already an array, return it
32
+ if (Array.isArray(data)) {
33
+ return data
34
+ }
35
+ // If it's an object with nested data property, extract it
36
+ if (data && typeof data === 'object' && 'data' in data) {
37
+ const nested = (data as {data: unknown}).data
38
+ if (Array.isArray(nested)) {
39
+ return nested
40
+ }
41
+ }
42
+ return []
43
+ }
44
+
45
+ /**
46
+ * Extract single object data from API response
47
+ * API returns { success, data: { data: {...} } } or { success, data: {...} }
48
+ */
49
+ function extractObjectData<T>(data: unknown): T {
50
+ // If it's an object with nested data property (not an array), extract it
51
+ if (
52
+ data &&
53
+ typeof data === 'object' &&
54
+ 'data' in data &&
55
+ !Array.isArray(data)
56
+ ) {
57
+ const nested = (data as {data: unknown}).data
58
+ // Check if nested also has a data property (double-wrapped)
59
+ if (
60
+ nested &&
61
+ typeof nested === 'object' &&
62
+ 'data' in nested &&
63
+ !Array.isArray(nested)
64
+ ) {
65
+ return (nested as {data: T}).data
66
+ }
67
+ return nested as T
68
+ }
69
+ return data as T
70
+ }
10
71
 
11
72
  // ============================================================================
12
73
  // QUERY KEYS
@@ -15,13 +76,18 @@ import type { Post, PostResponse, ApiResponse, PostStatusDto } from '../types';
15
76
  export const postKeys = {
16
77
  all: ['posts'] as const,
17
78
  lists: () => [...postKeys.all, 'list'] as const,
18
- list: (filters?: Record<string, unknown>) => [...postKeys.lists(), filters] as const,
19
- bySpot: (spotId: string, filters?: Record<string, unknown>) => [...postKeys.all, 'spot', spotId, filters] as const,
79
+ list: (filters?: Record<string, unknown>) =>
80
+ [...postKeys.lists(), filters] as const,
81
+ bySpot: (spotId: string, filters?: Record<string, unknown>) =>
82
+ [...postKeys.all, 'spot', spotId, filters] as const,
20
83
  details: () => [...postKeys.all, 'detail'] as const,
21
84
  detail: (id: string) => [...postKeys.details(), id] as const,
22
- responses: (postId: string) => [...postKeys.detail(postId), 'responses'] as const,
85
+ responses: (postId: string) =>
86
+ [...postKeys.detail(postId), 'responses'] as const,
23
87
  status: (postId: string) => [...postKeys.detail(postId), 'status'] as const,
24
- };
88
+ upvotes: (postId: string, filters?: {limit?: number; offset?: number}) =>
89
+ [...postKeys.detail(postId), 'upvotes', filters] as const,
90
+ }
25
91
 
26
92
  // ============================================================================
27
93
  // QUERY HOOKS
@@ -30,113 +96,202 @@ export const postKeys = {
30
96
  /**
31
97
  * Get posts for a spot
32
98
  *
33
- * @endpoint GET /api/v1/spots/{spotId}/posts
99
+ * @endpoint GET /spots/{spotId}/posts
34
100
  */
35
101
  export function useSpotPosts(
36
102
  spotId: string,
37
- params?: { postType?: string; status?: string; page?: number; limit?: number },
38
- options?: Omit<UseQueryOptions<Post[]>, 'queryKey' | 'queryFn'>
103
+ params?: {postType?: string; status?: string; page?: number; limit?: number},
104
+ options?: Omit<UseQueryOptions<Post[]>, 'queryKey' | 'queryFn'>,
39
105
  ): UseQueryResult<Post[]> {
40
106
  return useQuery({
41
107
  queryKey: postKeys.bySpot(spotId, params),
42
108
  queryFn: async (): Promise<Post[]> => {
43
- const client = getApiClient();
44
- const queryParams = new URLSearchParams();
45
- if (params?.postType) queryParams.set('postType', params.postType);
46
- if (params?.status) queryParams.set('status', params.status);
47
- if (params?.page) queryParams.set('page', String(params.page));
48
- if (params?.limit) queryParams.set('limit', String(params.limit));
49
- const response = await client.get<ApiResponse<Post[]>>(`/api/v1/spots/${spotId}/posts?${queryParams}`);
50
- return response.data.data;
109
+ const client = getApiClient()
110
+ const queryParams = new URLSearchParams()
111
+ if (params?.postType) queryParams.set('postType', params.postType)
112
+ if (params?.status) queryParams.set('status', params.status)
113
+ if (params?.page) queryParams.set('page', String(params.page))
114
+ if (params?.limit) queryParams.set('limit', String(params.limit))
115
+ const response = await client.get<ApiResponse<unknown>>(
116
+ `/spots/${spotId}/posts?${queryParams}`,
117
+ )
118
+ return extractArrayData<Post>(response.data.data)
51
119
  },
52
120
  enabled: !!spotId,
53
121
  ...options,
54
- });
122
+ })
55
123
  }
56
124
 
57
125
  /**
58
126
  * Get a single post by ID
59
127
  *
60
- * @endpoint GET /api/v1/posts/{postId}
128
+ * @endpoint GET /posts/{postId}
61
129
  */
62
130
  export function usePost(
63
131
  postId: string,
64
- options?: Omit<UseQueryOptions<Post>, 'queryKey' | 'queryFn'>
132
+ options?: Omit<UseQueryOptions<Post>, 'queryKey' | 'queryFn'>,
65
133
  ): UseQueryResult<Post> {
66
134
  return useQuery({
67
135
  queryKey: postKeys.detail(postId),
68
136
  queryFn: async (): Promise<Post> => {
69
- const client = getApiClient();
70
- const response = await client.get<ApiResponse<Post>>(`/api/v1/posts/${postId}`);
71
- return response.data.data;
137
+ const client = getApiClient()
138
+ const response = await client.get<ApiResponse<unknown>>(
139
+ `/posts/${postId}`,
140
+ )
141
+ return extractObjectData<Post>(response.data.data)
72
142
  },
73
143
  enabled: !!postId,
74
144
  ...options,
75
- });
145
+ })
76
146
  }
77
147
 
78
148
  /**
79
149
  * Get responses for a post
80
150
  *
81
- * @endpoint GET /api/v1/posts/{postId}/responses
151
+ * @endpoint GET /posts/{postId}/responses
82
152
  */
83
153
  export function usePostResponses(
84
154
  postId: string,
85
- options?: Omit<UseQueryOptions<PostResponse[]>, 'queryKey' | 'queryFn'>
155
+ options?: Omit<UseQueryOptions<PostResponse[]>, 'queryKey' | 'queryFn'>,
86
156
  ): UseQueryResult<PostResponse[]> {
87
157
  return useQuery({
88
158
  queryKey: postKeys.responses(postId),
89
159
  queryFn: async (): Promise<PostResponse[]> => {
90
- const client = getApiClient();
91
- const response = await client.get<ApiResponse<PostResponse[]>>(`/api/v1/posts/${postId}/responses`);
92
- return response.data.data;
160
+ const client = getApiClient()
161
+ const response = await client.get<ApiResponse<unknown>>(
162
+ `/posts/${postId}/responses`,
163
+ )
164
+ return extractArrayData<PostResponse>(response.data.data)
93
165
  },
94
166
  enabled: !!postId,
95
167
  ...options,
96
- });
168
+ })
97
169
  }
98
170
 
99
171
  /**
100
172
  * Get all posts (with filters)
101
173
  *
102
- * @endpoint GET /api/v1/posts
174
+ * @endpoint GET /posts
103
175
  */
104
176
  export function usePosts(
105
- params?: { postType?: string; limit?: number },
106
- options?: Omit<UseQueryOptions<Post[]>, 'queryKey' | 'queryFn'>
177
+ params?: {postType?: string; limit?: number},
178
+ options?: Omit<UseQueryOptions<Post[]>, 'queryKey' | 'queryFn'>,
107
179
  ): UseQueryResult<Post[]> {
108
180
  return useQuery({
109
181
  queryKey: postKeys.list(params),
110
182
  queryFn: async (): Promise<Post[]> => {
111
- const client = getApiClient();
112
- const queryParams = new URLSearchParams();
113
- if (params?.postType) queryParams.set('postType', params.postType);
114
- if (params?.limit) queryParams.set('limit', String(params.limit));
115
- const response = await client.get<ApiResponse<Post[]>>(`/api/v1/posts?${queryParams}`);
116
- return response.data.data;
183
+ const client = getApiClient()
184
+ const queryParams = new URLSearchParams()
185
+ if (params?.postType) queryParams.set('postType', params.postType)
186
+ if (params?.limit) queryParams.set('limit', String(params.limit))
187
+ const response = await client.get<ApiResponse<unknown>>(
188
+ `/posts?${queryParams}`,
189
+ )
190
+ return extractArrayData<Post>(response.data.data)
117
191
  },
118
192
  ...options,
119
- });
193
+ })
120
194
  }
121
195
 
122
-
123
196
  /**
124
197
  * Get user's status for a post (read/hidden/pinned)
125
198
  *
126
- * @endpoint GET /api/v1/posts/{postId}/status
199
+ * @endpoint GET /posts/{postId}/status
127
200
  */
128
201
  export function usePostStatus(
129
202
  postId: string,
130
- options?: Omit<UseQueryOptions<PostStatusDto>, 'queryKey' | 'queryFn'>
203
+ options?: Omit<UseQueryOptions<PostStatusDto>, 'queryKey' | 'queryFn'>,
131
204
  ): UseQueryResult<PostStatusDto> {
132
205
  return useQuery({
133
206
  queryKey: postKeys.status(postId),
134
207
  queryFn: async (): Promise<PostStatusDto> => {
135
- const client = getApiClient();
136
- const response = await client.get<ApiResponse<PostStatusDto>>(`/api/v1/posts/${postId}/status`);
137
- return response.data.data;
208
+ const client = getApiClient()
209
+ const response = await client.get<ApiResponse<unknown>>(
210
+ `/posts/${postId}/status`,
211
+ )
212
+ return extractObjectData<PostStatusDto>(response.data.data)
213
+ },
214
+ enabled: !!postId,
215
+ ...options,
216
+ })
217
+ }
218
+
219
+ /**
220
+ * Get upvotes for a post (list of users who upvoted)
221
+ *
222
+ * @endpoint GET /posts/{postId}/upvotes
223
+ */
224
+ export function usePostUpvotes(
225
+ postId: string,
226
+ params?: {limit?: number; offset?: number},
227
+ options?: Omit<UseQueryOptions<PostUpvotesResponse>, 'queryKey' | 'queryFn'>,
228
+ ): UseQueryResult<PostUpvotesResponse> {
229
+ return useQuery({
230
+ queryKey: postKeys.upvotes(postId, params),
231
+ queryFn: async (): Promise<PostUpvotesResponse> => {
232
+ const client = getApiClient()
233
+ const queryParams = new URLSearchParams()
234
+ if (params?.limit) queryParams.set('limit', String(params.limit))
235
+ if (params?.offset) queryParams.set('offset', String(params.offset))
236
+ const queryString = queryParams.toString()
237
+ const response = await client.get<ApiResponse<PostUpvotesResponse>>(
238
+ `/posts/${postId}/upvotes${queryString ? `?${queryString}` : ''}`,
239
+ )
240
+ // Response structure: { success, data: { data: [...], meta: {...} } }
241
+ return response.data.data
138
242
  },
139
243
  enabled: !!postId,
140
244
  ...options,
141
- });
245
+ })
246
+ }
247
+
248
+ /**
249
+ * Get nearby posts feed
250
+ *
251
+ * @endpoint GET /posts/feed
252
+ */
253
+ export function usePostsFeed(
254
+ params: {
255
+ lat: number
256
+ lng: number
257
+ radius?: number
258
+ postType?: string
259
+ cursor?: string
260
+ limit?: number
261
+ },
262
+ options?: Omit<
263
+ UseQueryOptions<{posts: Post[]; hasMore: boolean; nextCursor?: string}>,
264
+ 'queryKey' | 'queryFn'
265
+ >,
266
+ ): UseQueryResult<{posts: Post[]; hasMore: boolean; nextCursor?: string}> {
267
+ return useQuery({
268
+ queryKey: [...postKeys.lists(), 'feed', params] as const,
269
+ queryFn: async (): Promise<{
270
+ posts: Post[]
271
+ hasMore: boolean
272
+ nextCursor?: string
273
+ }> => {
274
+ const client = getApiClient()
275
+ const queryParams = new URLSearchParams()
276
+ queryParams.set('lat', String(params.lat))
277
+ queryParams.set('lng', String(params.lng))
278
+ if (params.radius) queryParams.set('radius', String(params.radius))
279
+ if (params.postType) queryParams.set('postType', params.postType)
280
+ if (params.cursor) queryParams.set('cursor', params.cursor)
281
+ if (params.limit) queryParams.set('limit', String(params.limit))
282
+
283
+ const response = await client.get<
284
+ ApiResponse<{posts: Post[]; hasMore: boolean; nextCursor?: string}>
285
+ >(`/posts/feed?${queryParams}`)
286
+
287
+ const data = response.data.data
288
+ return {
289
+ posts: data.posts ?? extractArrayData<Post>(data),
290
+ hasMore: data.hasMore ?? false,
291
+ nextCursor: data.nextCursor,
292
+ }
293
+ },
294
+ enabled: params.lat !== 0 && params.lng !== 0,
295
+ ...options,
296
+ })
142
297
  }
@@ -4,9 +4,16 @@
4
4
  * TanStack Query hooks for product-related operations.
5
5
  */
6
6
 
7
- import { useQuery, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
8
- import { getApiClient } from '../client';
9
- import type { Product, ApiResponse, PaginatedResponse, ProductType, ProductStatus } from '../types';
7
+ import {useQuery, type UseQueryOptions, type UseQueryResult} from '@tanstack/react-query'
8
+ import {getApiClient} from '../client'
9
+ import type {
10
+ Product,
11
+ ApiResponse,
12
+ PaginatedResponse,
13
+ ProductType,
14
+ ProductStatus,
15
+ Spot,
16
+ } from '../types'
10
17
 
11
18
  // ============================================================================
12
19
  // QUERY KEYS
@@ -15,31 +22,29 @@ import type { Product, ApiResponse, PaginatedResponse, ProductType, ProductStatu
15
22
  export const productKeys = {
16
23
  all: ['products'] as const,
17
24
  lists: () => [...productKeys.all, 'list'] as const,
18
- list: (filters?: Record<string, unknown>) => [...productKeys.lists(), filters] as const,
25
+ list: (filters?: Record<string, unknown>) =>
26
+ [...productKeys.lists(), filters] as const,
19
27
  details: () => [...productKeys.all, 'detail'] as const,
20
28
  detail: (id: string) => [...productKeys.details(), id] as const,
21
- bySlug: (spotId: string, slug: string) => [...productKeys.all, 'slug', spotId, slug] as const,
29
+ bySlug: (spotId: string, slug: string) =>
30
+ [...productKeys.all, 'slug', spotId, slug] as const,
22
31
  bySpot: (spotId: string) => [...productKeys.all, 'spot', spotId] as const,
23
- };
32
+ }
24
33
 
25
34
  // ============================================================================
26
35
  // TYPES
27
36
  // ============================================================================
28
37
 
29
38
  export interface ProductFilters {
30
- spotId?: string;
31
- type?: ProductType;
32
- status?: ProductStatus;
33
- limit?: number;
34
- page?: number;
39
+ spotId?: string
40
+ type?: ProductType
41
+ status?: ProductStatus
42
+ limit?: number
43
+ page?: number
35
44
  }
36
45
 
37
46
  export interface ProductWithSpot extends Product {
38
- spot: {
39
- id: string;
40
- name: string;
41
- slug: string;
42
- };
47
+ spot: Pick<Spot, 'id' | 'name' | 'slug'>
43
48
  }
44
49
 
45
50
  // ============================================================================
@@ -49,75 +54,77 @@ export interface ProductWithSpot extends Product {
49
54
  /**
50
55
  * Get products for a spot (public browse)
51
56
  *
52
- * @endpoint GET /api/v1/spots/{spotId}/products
57
+ * @endpoint GET /spots/{spotId}/products
53
58
  */
54
59
  export function useSpotProducts(
55
60
  spotId: string,
56
- params?: { type?: ProductType; limit?: number; page?: number },
57
- options?: Omit<UseQueryOptions<PaginatedResponse<Product>>, 'queryKey' | 'queryFn'>
61
+ params?: {type?: ProductType; limit?: number; page?: number},
62
+ options?: Omit<
63
+ UseQueryOptions<PaginatedResponse<Product>>,
64
+ 'queryKey' | 'queryFn'
65
+ >,
58
66
  ): UseQueryResult<PaginatedResponse<Product>> {
59
67
  return useQuery({
60
68
  queryKey: productKeys.bySpot(spotId),
61
69
  queryFn: async (): Promise<PaginatedResponse<Product>> => {
62
- const client = getApiClient();
63
- const queryParams = new URLSearchParams();
64
- if (params?.limit) queryParams.set('limit', String(params.limit));
65
- if (params?.page) queryParams.set('page', String(params.page));
66
- if (params?.type) queryParams.set('type', params.type);
70
+ const client = getApiClient()
71
+ const queryParams = new URLSearchParams()
72
+ if (params?.limit) queryParams.set('limit', String(params.limit))
73
+ if (params?.page) queryParams.set('page', String(params.page))
74
+ if (params?.type) queryParams.set('type', params.type)
67
75
  const response = await client.get<ApiResponse<PaginatedResponse<Product>>>(
68
- `/api/v1/spots/${spotId}/products?${queryParams}`
69
- );
70
- return response.data.data;
76
+ `/spots/${spotId}/products?${queryParams}`,
77
+ )
78
+ return response.data.data
71
79
  },
72
80
  enabled: !!spotId,
73
81
  ...options,
74
- });
82
+ })
75
83
  }
76
84
 
77
85
  /**
78
86
  * Get a product by ID
79
87
  *
80
- * @endpoint GET /api/v1/products/{productId}
88
+ * @endpoint GET /products/{productId}
81
89
  */
82
90
  export function useProduct(
83
91
  productId: string,
84
- options?: Omit<UseQueryOptions<ProductWithSpot>, 'queryKey' | 'queryFn'>
92
+ options?: Omit<UseQueryOptions<ProductWithSpot>, 'queryKey' | 'queryFn'>,
85
93
  ): UseQueryResult<ProductWithSpot> {
86
94
  return useQuery({
87
95
  queryKey: productKeys.detail(productId),
88
96
  queryFn: async (): Promise<ProductWithSpot> => {
89
- const client = getApiClient();
90
- const response = await client.get<ApiResponse<ProductWithSpot>>(`/api/v1/products/${productId}`);
91
- return response.data.data;
97
+ const client = getApiClient()
98
+ const response = await client.get<ApiResponse<ProductWithSpot>>(
99
+ `/products/${productId}`,
100
+ )
101
+ return response.data.data
92
102
  },
93
103
  enabled: !!productId,
94
104
  ...options,
95
- });
105
+ })
96
106
  }
97
107
 
98
108
  /**
99
109
  * Get a product by slug (within a spot)
100
110
  *
101
- * @endpoint GET /api/v1/spots/{spotId}/products/slug/{slug}
111
+ * @endpoint GET /spots/{spotId}/products/slug/{slug}
102
112
  */
103
113
  export function useProductBySlug(
104
114
  spotId: string,
105
115
  slug: string,
106
- options?: Omit<UseQueryOptions<ProductWithSpot>, 'queryKey' | 'queryFn'>
116
+ options?: Omit<UseQueryOptions<ProductWithSpot>, 'queryKey' | 'queryFn'>,
107
117
  ): UseQueryResult<ProductWithSpot> {
108
118
  return useQuery({
109
119
  queryKey: productKeys.bySlug(spotId, slug),
110
120
  queryFn: async (): Promise<ProductWithSpot> => {
111
- const client = getApiClient();
121
+ const client = getApiClient()
112
122
  const response = await client.get<ApiResponse<ProductWithSpot>>(
113
- `/api/v1/spots/${spotId}/products/slug/${slug}`
114
- );
115
- return response.data.data;
123
+ `/spots/${spotId}/products/slug/${slug}`,
124
+ )
125
+ return response.data.data
116
126
  },
117
127
  enabled: !!spotId && !!slug,
118
128
  ...options,
119
- });
129
+ })
120
130
  }
121
-
122
- // Note: To list products as a seller, use useSpotProducts with your spot ID.
123
- // There is no cross-spot product listing endpoint currently.