@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,146 @@
1
+ /**
2
+ * Spots Mutation Hooks
3
+ *
4
+ * TanStack Query hooks for spot mutation operations.
5
+ */
6
+
7
+ import { useMutation, useQueryClient, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
8
+ import { getApiClient } from '../client';
9
+ import { spotKeys } from '../queries/spots';
10
+ import { userKeys } from '../queries/users';
11
+ import type { Spot, ClaimSpotRequest, ApiResponse } from '../types';
12
+
13
+ // ============================================================================
14
+ // MUTATION HOOKS
15
+ // ============================================================================
16
+
17
+ /**
18
+ * Create a new spot
19
+ *
20
+ * @endpoint POST /api/v1/spots
21
+ */
22
+ export function useCreateSpot(
23
+ options?: Omit<UseMutationOptions<Spot, Error, Partial<Spot>>, 'mutationFn'>
24
+ ): UseMutationResult<Spot, Error, Partial<Spot>> {
25
+ const queryClient = useQueryClient();
26
+
27
+ return useMutation({
28
+ mutationFn: async (data: Partial<Spot>): Promise<Spot> => {
29
+ const client = getApiClient();
30
+ const response = await client.post<ApiResponse<Spot>>('/api/v1/spots', data);
31
+ return response.data.data;
32
+ },
33
+ onSuccess: () => {
34
+ queryClient.invalidateQueries({ queryKey: spotKeys.lists() });
35
+ },
36
+ ...options,
37
+ });
38
+ }
39
+
40
+ /**
41
+ * Update a spot
42
+ *
43
+ * @endpoint PUT /api/v1/spots/{spotId}
44
+ */
45
+ export function useUpdateSpot(
46
+ options?: Omit<UseMutationOptions<Spot, Error, { spotId: string } & Partial<Spot>>, 'mutationFn'>
47
+ ): UseMutationResult<Spot, Error, { spotId: string } & Partial<Spot>> {
48
+ const queryClient = useQueryClient();
49
+
50
+ return useMutation({
51
+ mutationFn: async ({ spotId, ...data }): Promise<Spot> => {
52
+ const client = getApiClient();
53
+ const response = await client.put<ApiResponse<Spot>>(`/api/v1/spots/${spotId}`, data);
54
+ return response.data.data;
55
+ },
56
+ onSuccess: (data, variables) => {
57
+ queryClient.setQueryData(spotKeys.detail(variables.spotId), data);
58
+ },
59
+ ...options,
60
+ });
61
+ }
62
+
63
+ /**
64
+ * Claim a spot (for business owners)
65
+ *
66
+ * @endpoint POST /api/v1/spots/{spotId}/claim
67
+ */
68
+ export function useClaimSpot(
69
+ options?: Omit<UseMutationOptions<{ claimId: string }, Error, { spotId: string } & ClaimSpotRequest>, 'mutationFn'>
70
+ ): UseMutationResult<{ claimId: string }, Error, { spotId: string } & ClaimSpotRequest> {
71
+ return useMutation({
72
+ mutationFn: async ({ spotId, ...data }): Promise<{ claimId: string }> => {
73
+ const client = getApiClient();
74
+ const response = await client.post<ApiResponse<{ claimId: string }>>(`/api/v1/spots/${spotId}/claim`, data);
75
+ return response.data.data;
76
+ },
77
+ ...options,
78
+ });
79
+ }
80
+
81
+ /**
82
+ * Subscribe to a spot
83
+ *
84
+ * @endpoint POST /api/v1/spots/{spotId}/subscribe
85
+ */
86
+ export function useSubscribeToSpot(
87
+ options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>
88
+ ): UseMutationResult<void, Error, string> {
89
+ const queryClient = useQueryClient();
90
+
91
+ return useMutation({
92
+ mutationFn: async (spotId: string): Promise<void> => {
93
+ const client = getApiClient();
94
+ await client.post(`/api/v1/spots/${spotId}/subscribe`);
95
+ },
96
+ onSuccess: () => {
97
+ queryClient.invalidateQueries({ queryKey: userKeys.subscriptions() });
98
+ },
99
+ ...options,
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Unsubscribe from a spot
105
+ *
106
+ * @endpoint DELETE /api/v1/spots/{spotId}/subscribe
107
+ */
108
+ export function useUnsubscribeFromSpot(
109
+ options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>
110
+ ): UseMutationResult<void, Error, string> {
111
+ const queryClient = useQueryClient();
112
+
113
+ return useMutation({
114
+ mutationFn: async (spotId: string): Promise<void> => {
115
+ const client = getApiClient();
116
+ await client.delete(`/api/v1/spots/${spotId}/subscribe`);
117
+ },
118
+ onSuccess: () => {
119
+ queryClient.invalidateQueries({ queryKey: userKeys.subscriptions() });
120
+ },
121
+ ...options,
122
+ });
123
+ }
124
+
125
+ /**
126
+ * Toggle favorite status on a spot
127
+ *
128
+ * @endpoint POST /api/v1/spots/{spotId}/favorite
129
+ */
130
+ export function useFavoriteSpot(
131
+ options?: Omit<UseMutationOptions<{ isFavorite: boolean }, Error, string>, 'mutationFn'>
132
+ ): UseMutationResult<{ isFavorite: boolean }, Error, string> {
133
+ const queryClient = useQueryClient();
134
+
135
+ return useMutation({
136
+ mutationFn: async (spotId: string): Promise<{ isFavorite: boolean }> => {
137
+ const client = getApiClient();
138
+ const response = await client.post<ApiResponse<{ isFavorite: boolean }>>(`/api/v1/spots/${spotId}/favorite`);
139
+ return response.data.data;
140
+ },
141
+ onSuccess: () => {
142
+ queryClient.invalidateQueries({ queryKey: userKeys.favorites() });
143
+ },
144
+ ...options,
145
+ });
146
+ }
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Users Mutation Hooks
3
+ *
4
+ * TanStack Query hooks for user mutation operations.
5
+ */
6
+
7
+ import { useMutation, useQueryClient, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
8
+ import { getApiClient } from '../client';
9
+ import { userKeys } from '../queries/users';
10
+ import type { User, UpdateProfileRequest, ApiResponse } from '../types';
11
+
12
+ // ============================================================================
13
+ // MUTATION HOOKS
14
+ // ============================================================================
15
+
16
+ /**
17
+ * Update current user's profile
18
+ *
19
+ * @endpoint PUT /api/v1/users/me
20
+ */
21
+ export function useUpdateProfile(
22
+ options?: Omit<UseMutationOptions<User, Error, UpdateProfileRequest>, 'mutationFn'>
23
+ ): UseMutationResult<User, Error, UpdateProfileRequest> {
24
+ const queryClient = useQueryClient();
25
+
26
+ return useMutation({
27
+ mutationFn: async (data: UpdateProfileRequest): Promise<User> => {
28
+ const client = getApiClient();
29
+ const response = await client.put<ApiResponse<User>>('/api/v1/users/me', data);
30
+ return response.data.data;
31
+ },
32
+ onSuccess: (data) => {
33
+ queryClient.setQueryData(userKeys.me(), data);
34
+ },
35
+ ...options,
36
+ });
37
+ }
38
+
39
+ /**
40
+ * Upload avatar
41
+ *
42
+ * @endpoint POST /api/v1/users/me/avatar
43
+ */
44
+ export function useUploadAvatar(
45
+ options?: Omit<UseMutationOptions<{ avatarUrl: string }, Error, FormData>, 'mutationFn'>
46
+ ): UseMutationResult<{ avatarUrl: string }, Error, FormData> {
47
+ const queryClient = useQueryClient();
48
+
49
+ return useMutation({
50
+ mutationFn: async (formData: FormData): Promise<{ avatarUrl: string }> => {
51
+ const client = getApiClient();
52
+ const response = await client.post<ApiResponse<{ avatarUrl: string }>>('/api/v1/users/me/avatar', formData, {
53
+ headers: { 'Content-Type': 'multipart/form-data' },
54
+ });
55
+ return response.data.data;
56
+ },
57
+ onSuccess: () => {
58
+ queryClient.invalidateQueries({ queryKey: userKeys.me() });
59
+ },
60
+ ...options,
61
+ });
62
+ }
63
+
64
+ /**
65
+ * Delete current user's account
66
+ *
67
+ * @endpoint DELETE /api/v1/users/me
68
+ */
69
+ export function useDeleteAccount(
70
+ options?: Omit<UseMutationOptions<void, Error, void>, 'mutationFn'>
71
+ ): UseMutationResult<void, Error, void> {
72
+ const queryClient = useQueryClient();
73
+
74
+ return useMutation({
75
+ mutationFn: async (): Promise<void> => {
76
+ const client = getApiClient();
77
+ await client.delete('/api/v1/users/me');
78
+ },
79
+ onSuccess: () => {
80
+ queryClient.clear();
81
+ },
82
+ ...options,
83
+ });
84
+ }
85
+
86
+ /**
87
+ * Update user vibes
88
+ *
89
+ * @endpoint PUT /api/v1/user/me/vibes
90
+ */
91
+ export function useUpdateVibes(
92
+ options?: Omit<UseMutationOptions<User, Error, { vibes: string[] }>, 'mutationFn'>
93
+ ): UseMutationResult<User, Error, { vibes: string[] }> {
94
+ const queryClient = useQueryClient();
95
+
96
+ return useMutation({
97
+ mutationFn: async (data: { vibes: string[] }): Promise<User> => {
98
+ const client = getApiClient();
99
+ const response = await client.put<ApiResponse<User>>('/api/v1/user/me/vibes', data);
100
+ return response.data.data;
101
+ },
102
+ onSuccess: () => {
103
+ queryClient.invalidateQueries({ queryKey: userKeys.me() });
104
+ },
105
+ ...options,
106
+ });
107
+ }
108
+
109
+ /**
110
+ * Update user interests
111
+ *
112
+ * @endpoint PUT /api/v1/user/me/interests
113
+ */
114
+ export function useUpdateInterests(
115
+ options?: Omit<UseMutationOptions<User, Error, { interests: string[] }>, 'mutationFn'>
116
+ ): UseMutationResult<User, Error, { interests: string[] }> {
117
+ const queryClient = useQueryClient();
118
+
119
+ return useMutation({
120
+ mutationFn: async (data: { interests: string[] }): Promise<User> => {
121
+ const client = getApiClient();
122
+ const response = await client.put<ApiResponse<User>>('/api/v1/user/me/interests', data);
123
+ return response.data.data;
124
+ },
125
+ onSuccess: () => {
126
+ queryClient.invalidateQueries({ queryKey: userKeys.me() });
127
+ },
128
+ ...options,
129
+ });
130
+ }
131
+
132
+ /**
133
+ * Complete onboarding step
134
+ *
135
+ * @endpoint POST /api/v1/user/me/onboarding-step
136
+ */
137
+ export function useCompleteOnboardingStep(
138
+ options?: Omit<UseMutationOptions<User, Error, { step: number }>, 'mutationFn'>
139
+ ): UseMutationResult<User, Error, { step: number }> {
140
+ const queryClient = useQueryClient();
141
+
142
+ return useMutation({
143
+ mutationFn: async (data: { step: number }): Promise<User> => {
144
+ const client = getApiClient();
145
+ const response = await client.post<ApiResponse<User>>('/api/v1/user/me/onboarding-step', data);
146
+ return response.data.data;
147
+ },
148
+ onSuccess: () => {
149
+ queryClient.invalidateQueries({ queryKey: userKeys.me() });
150
+ },
151
+ ...options,
152
+ });
153
+ }
154
+
155
+ /**
156
+ * Block a user
157
+ *
158
+ * @endpoint POST /api/v1/users/{id}/block
159
+ */
160
+ export function useBlockUser(
161
+ options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>
162
+ ): UseMutationResult<void, Error, string> {
163
+ const queryClient = useQueryClient();
164
+
165
+ return useMutation({
166
+ mutationFn: async (userId: string): Promise<void> => {
167
+ const client = getApiClient();
168
+ await client.post(`/api/v1/users/${userId}/block`);
169
+ },
170
+ onSuccess: () => {
171
+ queryClient.invalidateQueries({ queryKey: userKeys.blocked() });
172
+ },
173
+ ...options,
174
+ });
175
+ }
176
+
177
+ /**
178
+ * Unblock a user
179
+ *
180
+ * @endpoint DELETE /api/v1/users/{id}/block
181
+ */
182
+ export function useUnblockUser(
183
+ options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>
184
+ ): UseMutationResult<void, Error, string> {
185
+ const queryClient = useQueryClient();
186
+
187
+ return useMutation({
188
+ mutationFn: async (userId: string): Promise<void> => {
189
+ const client = getApiClient();
190
+ await client.delete(`/api/v1/users/${userId}/block`);
191
+ },
192
+ onSuccess: () => {
193
+ queryClient.invalidateQueries({ queryKey: userKeys.blocked() });
194
+ },
195
+ ...options,
196
+ });
197
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Auth Mutation Hooks
3
+ *
4
+ * TanStack Query hooks for authentication operations.
5
+ */
6
+
7
+ import { useMutation, UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
8
+ import { getApiClient } from '../client';
9
+ import type { SendOtpRequest, VerifyOtpRequest, AuthResponse, ApiResponse } from '../types';
10
+
11
+ // ============================================================================
12
+ // MUTATION HOOKS
13
+ // ============================================================================
14
+
15
+ /**
16
+ * Send OTP to phone number
17
+ *
18
+ * @endpoint POST /api/v1/auth/send-otp
19
+ */
20
+ export function useSendOtp(
21
+ options?: Omit<UseMutationOptions<ApiResponse<{ sent: boolean }>, Error, SendOtpRequest>, 'mutationFn'>
22
+ ): UseMutationResult<ApiResponse<{ sent: boolean }>, Error, SendOtpRequest> {
23
+ return useMutation({
24
+ mutationFn: async (data: SendOtpRequest) => {
25
+ const client = getApiClient();
26
+ const response = await client.post<ApiResponse<{ sent: boolean }>>('/api/v1/auth/send-otp', data);
27
+ return response.data;
28
+ },
29
+ ...options,
30
+ });
31
+ }
32
+
33
+ /**
34
+ * Verify OTP and authenticate
35
+ *
36
+ * @endpoint POST /api/v1/auth/verify-otp
37
+ */
38
+ export function useVerifyOtp(
39
+ options?: Omit<UseMutationOptions<AuthResponse, Error, VerifyOtpRequest>, 'mutationFn'>
40
+ ): UseMutationResult<AuthResponse, Error, VerifyOtpRequest> {
41
+ return useMutation({
42
+ mutationFn: async (data: VerifyOtpRequest) => {
43
+ const client = getApiClient();
44
+ const response = await client.post<AuthResponse>('/api/v1/auth/verify-otp', data);
45
+ return response.data;
46
+ },
47
+ ...options,
48
+ });
49
+ }
50
+
51
+ /**
52
+ * Refresh access token
53
+ *
54
+ * @endpoint POST /api/v1/auth/refresh
55
+ */
56
+ export function useRefreshToken(
57
+ options?: Omit<UseMutationOptions<{ accessToken: string }, Error, { refreshToken: string }>, 'mutationFn'>
58
+ ): UseMutationResult<{ accessToken: string }, Error, { refreshToken: string }> {
59
+ return useMutation({
60
+ mutationFn: async (data: { refreshToken: string }) => {
61
+ const client = getApiClient();
62
+ const response = await client.post<{ accessToken: string }>('/api/v1/auth/refresh', data);
63
+ return response.data;
64
+ },
65
+ ...options,
66
+ });
67
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Clubs Query Hooks
3
+ *
4
+ * TanStack Query hooks for club operations.
5
+ */
6
+
7
+ import { useQuery, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
8
+ import { getApiClient } from '../client';
9
+ import type { Club, ApiResponse } from '../types';
10
+
11
+ // ============================================================================
12
+ // QUERY KEYS
13
+ // ============================================================================
14
+
15
+ export const clubKeys = {
16
+ all: ['clubs'] as const,
17
+ bySpot: (spotId: string) => [...clubKeys.all, 'spot', spotId] as const,
18
+ details: () => [...clubKeys.all, 'detail'] as const,
19
+ detail: (id: string) => [...clubKeys.details(), id] as const,
20
+ bySlug: (slug: string) => [...clubKeys.all, 'slug', slug] as const,
21
+ byUser: (userId: string) => [...clubKeys.all, 'user', userId] as const,
22
+ membership: (clubId: string, userId: string) => [...clubKeys.detail(clubId), 'membership', userId] as const,
23
+ };
24
+
25
+ // ============================================================================
26
+ // QUERY HOOKS
27
+ // ============================================================================
28
+
29
+ /**
30
+ * Get clubs for a spot
31
+ *
32
+ * @endpoint GET /api/v1/clubs/spot/{spotId}
33
+ */
34
+ export function useClubsBySpot(
35
+ spotId: string,
36
+ options?: Omit<UseQueryOptions<Club[]>, 'queryKey' | 'queryFn'>
37
+ ): UseQueryResult<Club[]> {
38
+ return useQuery({
39
+ queryKey: clubKeys.bySpot(spotId),
40
+ queryFn: async (): Promise<Club[]> => {
41
+ const client = getApiClient();
42
+ const response = await client.get<ApiResponse<Club[]>>(`/api/v1/clubs/spot/${spotId}`);
43
+ return response.data.data;
44
+ },
45
+ enabled: !!spotId,
46
+ ...options,
47
+ });
48
+ }
49
+
50
+ /**
51
+ * Get a club by ID
52
+ *
53
+ * @endpoint GET /api/v1/clubs/{id}
54
+ */
55
+ export function useClub(
56
+ clubId: string,
57
+ options?: Omit<UseQueryOptions<Club>, 'queryKey' | 'queryFn'>
58
+ ): UseQueryResult<Club> {
59
+ return useQuery({
60
+ queryKey: clubKeys.detail(clubId),
61
+ queryFn: async (): Promise<Club> => {
62
+ const client = getApiClient();
63
+ const response = await client.get<ApiResponse<Club>>(`/api/v1/clubs/${clubId}`);
64
+ return response.data.data;
65
+ },
66
+ enabled: !!clubId,
67
+ ...options,
68
+ });
69
+ }
70
+
71
+ /**
72
+ * Get a club by slug
73
+ *
74
+ * @endpoint GET /api/v1/clubs/slug/{slug}
75
+ */
76
+ export function useClubBySlug(
77
+ slug: string,
78
+ options?: Omit<UseQueryOptions<Club>, 'queryKey' | 'queryFn'>
79
+ ): UseQueryResult<Club> {
80
+ return useQuery({
81
+ queryKey: clubKeys.bySlug(slug),
82
+ queryFn: async (): Promise<Club> => {
83
+ const client = getApiClient();
84
+ const response = await client.get<ApiResponse<Club>>(`/api/v1/clubs/slug/${slug}`);
85
+ return response.data.data;
86
+ },
87
+ enabled: !!slug,
88
+ ...options,
89
+ });
90
+ }
91
+
92
+ /**
93
+ * Get clubs for a user
94
+ *
95
+ * @endpoint GET /api/v1/clubs/user/{userId}
96
+ */
97
+ export function useClubsByUser(
98
+ userId: string,
99
+ options?: Omit<UseQueryOptions<Club[]>, 'queryKey' | 'queryFn'>
100
+ ): UseQueryResult<Club[]> {
101
+ return useQuery({
102
+ queryKey: clubKeys.byUser(userId),
103
+ queryFn: async (): Promise<Club[]> => {
104
+ const client = getApiClient();
105
+ const response = await client.get<ApiResponse<Club[]>>(`/api/v1/clubs/user/${userId}`);
106
+ return response.data.data;
107
+ },
108
+ enabled: !!userId,
109
+ ...options,
110
+ });
111
+ }
112
+
113
+ /**
114
+ * Get membership status for a user in a club
115
+ *
116
+ * @endpoint GET /api/v1/clubs/{id}/membership/{userId}
117
+ */
118
+ export function useClubMembership(
119
+ clubId: string,
120
+ userId: string,
121
+ options?: Omit<UseQueryOptions<{ isMember: boolean; role?: string }>, 'queryKey' | 'queryFn'>
122
+ ): UseQueryResult<{ isMember: boolean; role?: string }> {
123
+ return useQuery({
124
+ queryKey: clubKeys.membership(clubId, userId),
125
+ queryFn: async () => {
126
+ const client = getApiClient();
127
+ const response = await client.get<ApiResponse<{ isMember: boolean; role?: string }>>(
128
+ `/api/v1/clubs/${clubId}/membership/${userId}`
129
+ );
130
+ return response.data.data;
131
+ },
132
+ enabled: !!clubId && !!userId,
133
+ ...options,
134
+ });
135
+ }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Conversations Query Hooks
3
+ *
4
+ * TanStack Query hooks for conversation/messaging operations.
5
+ */
6
+
7
+ import { useQuery, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
8
+ import { getApiClient } from '../client';
9
+ import type { Conversation, Message, ApiResponse } from '../types';
10
+
11
+ // ============================================================================
12
+ // QUERY KEYS
13
+ // ============================================================================
14
+
15
+ export const conversationKeys = {
16
+ all: ['conversations'] as const,
17
+ lists: () => [...conversationKeys.all, 'list'] as const,
18
+ list: () => [...conversationKeys.lists()] as const,
19
+ details: () => [...conversationKeys.all, 'detail'] as const,
20
+ detail: (id: string) => [...conversationKeys.details(), id] as const,
21
+ messages: (conversationId: string, params?: { before?: string }) =>
22
+ [...conversationKeys.detail(conversationId), 'messages', params] as const,
23
+ };
24
+
25
+ // ============================================================================
26
+ // QUERY HOOKS
27
+ // ============================================================================
28
+
29
+ /**
30
+ * Get all conversations for current user
31
+ *
32
+ * @endpoint GET /api/v1/conversations
33
+ */
34
+ export function useConversations(
35
+ options?: Omit<UseQueryOptions<Conversation[]>, 'queryKey' | 'queryFn'>
36
+ ): UseQueryResult<Conversation[]> {
37
+ return useQuery({
38
+ queryKey: conversationKeys.list(),
39
+ queryFn: async (): Promise<Conversation[]> => {
40
+ const client = getApiClient();
41
+ const response = await client.get<ApiResponse<Conversation[]>>('/api/v1/conversations');
42
+ return response.data.data;
43
+ },
44
+ ...options,
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Get a single conversation with details
50
+ *
51
+ * @endpoint GET /api/v1/conversations/{id}
52
+ */
53
+ export function useConversation(
54
+ conversationId: string,
55
+ options?: Omit<UseQueryOptions<Conversation>, 'queryKey' | 'queryFn'>
56
+ ): UseQueryResult<Conversation> {
57
+ return useQuery({
58
+ queryKey: conversationKeys.detail(conversationId),
59
+ queryFn: async (): Promise<Conversation> => {
60
+ const client = getApiClient();
61
+ const response = await client.get<ApiResponse<Conversation>>(`/api/v1/conversations/${conversationId}`);
62
+ return response.data.data;
63
+ },
64
+ enabled: !!conversationId,
65
+ ...options,
66
+ });
67
+ }
68
+
69
+ /**
70
+ * Get messages for a conversation
71
+ *
72
+ * @endpoint GET /api/v1/conversations/{id}/messages
73
+ */
74
+ export function useConversationMessages(
75
+ conversationId: string,
76
+ params?: { limit?: number; before?: string },
77
+ options?: Omit<UseQueryOptions<{ data: Message[]; meta: { hasMore: boolean; oldestMessageAt: string | null } }>, 'queryKey' | 'queryFn'>
78
+ ): UseQueryResult<{ data: Message[]; meta: { hasMore: boolean; oldestMessageAt: string | null } }> {
79
+ return useQuery({
80
+ queryKey: conversationKeys.messages(conversationId, params),
81
+ queryFn: async () => {
82
+ const client = getApiClient();
83
+ const queryParams = new URLSearchParams();
84
+ if (params?.limit) queryParams.set('limit', String(params.limit));
85
+ if (params?.before) queryParams.set('before', params.before);
86
+ const response = await client.get<{ data: Message[]; meta: { hasMore: boolean; oldestMessageAt: string | null } }>(
87
+ `/api/v1/conversations/${conversationId}/messages?${queryParams}`
88
+ );
89
+ return response.data;
90
+ },
91
+ enabled: !!conversationId,
92
+ ...options,
93
+ });
94
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Spots SDK Query Hooks Index
3
+ *
4
+ * Re-exports all query hooks and keys.
5
+ */
6
+
7
+ // Auth (mutations, but grouped with queries for convenience)
8
+ export * from './auth';
9
+
10
+ // Users
11
+ export * from './users';
12
+ export { userKeys } from './users';
13
+
14
+ // Spots
15
+ export * from './spots';
16
+ export { spotKeys } from './spots';
17
+
18
+ // Posts
19
+ export * from './posts';
20
+ export { postKeys } from './posts';
21
+
22
+ // Conversations
23
+ export * from './conversations';
24
+ export { conversationKeys } from './conversations';
25
+
26
+ // Clubs
27
+ export * from './clubs';
28
+ export { clubKeys } from './clubs';
29
+
30
+ // Templates
31
+ export * from './templates';
32
+ export { templateKeys } from './templates';
33
+
34
+ // Notifications
35
+ export * from './notifications';
36
+ export { notificationKeys } from './notifications';
37
+
38
+ // Misc (cities, vibes, events)
39
+ export * from './misc';
40
+ export { miscKeys } from './misc';
41
+
42
+ // Products (marketplace)
43
+ export * from './products';
44
+ export { productKeys } from './products';
45
+
46
+ // Orders (marketplace)
47
+ export * from './orders';
48
+ export { orderKeys } from './orders';