@growsober/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 (129) hide show
  1. package/README.md +276 -0
  2. package/dist/__tests__/e2e.test.d.ts +7 -0
  3. package/dist/__tests__/e2e.test.js +472 -0
  4. package/dist/api/client.d.ts +11 -0
  5. package/dist/api/client.js +61 -0
  6. package/dist/api/mutations/admin.d.ts +167 -0
  7. package/dist/api/mutations/admin.js +326 -0
  8. package/dist/api/mutations/ambassadors.d.ts +52 -0
  9. package/dist/api/mutations/ambassadors.js +148 -0
  10. package/dist/api/mutations/auth.d.ts +267 -0
  11. package/dist/api/mutations/auth.js +332 -0
  12. package/dist/api/mutations/bookings.d.ts +59 -0
  13. package/dist/api/mutations/bookings.js +143 -0
  14. package/dist/api/mutations/event-chat.d.ts +35 -0
  15. package/dist/api/mutations/event-chat.js +147 -0
  16. package/dist/api/mutations/events.d.ts +87 -0
  17. package/dist/api/mutations/events.js +205 -0
  18. package/dist/api/mutations/grow90.d.ts +36 -0
  19. package/dist/api/mutations/grow90.js +132 -0
  20. package/dist/api/mutations/hubs.d.ts +111 -0
  21. package/dist/api/mutations/hubs.js +240 -0
  22. package/dist/api/mutations/index.d.ts +22 -0
  23. package/dist/api/mutations/index.js +39 -0
  24. package/dist/api/mutations/jack.d.ts +61 -0
  25. package/dist/api/mutations/jack.js +104 -0
  26. package/dist/api/mutations/library.d.ts +67 -0
  27. package/dist/api/mutations/library.js +168 -0
  28. package/dist/api/mutations/map.d.ts +153 -0
  29. package/dist/api/mutations/map.js +181 -0
  30. package/dist/api/mutations/matching.d.ts +130 -0
  31. package/dist/api/mutations/matching.js +204 -0
  32. package/dist/api/mutations/notifications.d.ts +63 -0
  33. package/dist/api/mutations/notifications.js +106 -0
  34. package/dist/api/mutations/offers.d.ts +26 -0
  35. package/dist/api/mutations/offers.js +47 -0
  36. package/dist/api/mutations/subscriptions.d.ts +127 -0
  37. package/dist/api/mutations/subscriptions.js +140 -0
  38. package/dist/api/mutations/support.d.ts +165 -0
  39. package/dist/api/mutations/support.js +307 -0
  40. package/dist/api/mutations/users.d.ts +211 -0
  41. package/dist/api/mutations/users.js +261 -0
  42. package/dist/api/queries/admin.d.ts +257 -0
  43. package/dist/api/queries/admin.js +320 -0
  44. package/dist/api/queries/ambassadors.d.ts +53 -0
  45. package/dist/api/queries/ambassadors.js +98 -0
  46. package/dist/api/queries/auth.d.ts +16 -0
  47. package/dist/api/queries/auth.js +25 -0
  48. package/dist/api/queries/bookings.d.ts +91 -0
  49. package/dist/api/queries/bookings.js +102 -0
  50. package/dist/api/queries/businesses.d.ts +212 -0
  51. package/dist/api/queries/businesses.js +154 -0
  52. package/dist/api/queries/event-chat.d.ts +19 -0
  53. package/dist/api/queries/event-chat.js +75 -0
  54. package/dist/api/queries/events.d.ts +322 -0
  55. package/dist/api/queries/events.js +221 -0
  56. package/dist/api/queries/grow90.d.ts +26 -0
  57. package/dist/api/queries/grow90.js +85 -0
  58. package/dist/api/queries/hubs.d.ts +165 -0
  59. package/dist/api/queries/hubs.js +143 -0
  60. package/dist/api/queries/index.d.ts +23 -0
  61. package/dist/api/queries/index.js +40 -0
  62. package/dist/api/queries/jack.d.ts +63 -0
  63. package/dist/api/queries/jack.js +92 -0
  64. package/dist/api/queries/library.d.ts +132 -0
  65. package/dist/api/queries/library.js +120 -0
  66. package/dist/api/queries/map.d.ts +216 -0
  67. package/dist/api/queries/map.js +278 -0
  68. package/dist/api/queries/matching.d.ts +136 -0
  69. package/dist/api/queries/matching.js +161 -0
  70. package/dist/api/queries/notifications.d.ts +78 -0
  71. package/dist/api/queries/notifications.js +88 -0
  72. package/dist/api/queries/offers.d.ts +91 -0
  73. package/dist/api/queries/offers.js +103 -0
  74. package/dist/api/queries/subscriptions.d.ts +56 -0
  75. package/dist/api/queries/subscriptions.js +73 -0
  76. package/dist/api/queries/support.d.ts +106 -0
  77. package/dist/api/queries/support.js +202 -0
  78. package/dist/api/queries/users.d.ts +293 -0
  79. package/dist/api/queries/users.js +370 -0
  80. package/dist/api/types.d.ts +464 -0
  81. package/dist/api/types.js +9 -0
  82. package/dist/hooks/useAuth.d.ts +5 -0
  83. package/dist/hooks/useAuth.js +39 -0
  84. package/dist/hooks/useUser.d.ts +43 -0
  85. package/dist/hooks/useUser.js +44 -0
  86. package/dist/index.d.ts +36 -0
  87. package/dist/index.js +67 -0
  88. package/package.json +62 -0
  89. package/src/__tests__/e2e.test.ts +502 -0
  90. package/src/api/client.ts +71 -0
  91. package/src/api/mutations/admin.ts +531 -0
  92. package/src/api/mutations/ambassadors.ts +185 -0
  93. package/src/api/mutations/auth.ts +350 -0
  94. package/src/api/mutations/bookings.ts +190 -0
  95. package/src/api/mutations/event-chat.ts +177 -0
  96. package/src/api/mutations/events.ts +273 -0
  97. package/src/api/mutations/grow90.ts +169 -0
  98. package/src/api/mutations/hubs.ts +385 -0
  99. package/src/api/mutations/index.ts +23 -0
  100. package/src/api/mutations/jack.ts +130 -0
  101. package/src/api/mutations/library.ts +212 -0
  102. package/src/api/mutations/map.ts +230 -0
  103. package/src/api/mutations/matching.ts +271 -0
  104. package/src/api/mutations/notifications.ts +114 -0
  105. package/src/api/mutations/offers.ts +73 -0
  106. package/src/api/mutations/subscriptions.ts +162 -0
  107. package/src/api/mutations/support.ts +390 -0
  108. package/src/api/mutations/users.ts +271 -0
  109. package/src/api/queries/admin.ts +480 -0
  110. package/src/api/queries/ambassadors.ts +139 -0
  111. package/src/api/queries/auth.ts +24 -0
  112. package/src/api/queries/bookings.ts +135 -0
  113. package/src/api/queries/businesses.ts +203 -0
  114. package/src/api/queries/event-chat.ts +78 -0
  115. package/src/api/queries/events.ts +272 -0
  116. package/src/api/queries/grow90.ts +98 -0
  117. package/src/api/queries/hubs.ts +211 -0
  118. package/src/api/queries/index.ts +24 -0
  119. package/src/api/queries/jack.ts +127 -0
  120. package/src/api/queries/library.ts +166 -0
  121. package/src/api/queries/map.ts +331 -0
  122. package/src/api/queries/matching.ts +238 -0
  123. package/src/api/queries/notifications.ts +103 -0
  124. package/src/api/queries/offers.ts +136 -0
  125. package/src/api/queries/subscriptions.ts +91 -0
  126. package/src/api/queries/support.ts +235 -0
  127. package/src/api/queries/users.ts +393 -0
  128. package/src/api/types.ts +596 -0
  129. package/src/index.ts +57 -0
@@ -0,0 +1,190 @@
1
+ import {
2
+ useMutation,
3
+ useQueryClient,
4
+ UseMutationOptions,
5
+ UseMutationResult,
6
+ } from '@tanstack/react-query';
7
+ import { getApiClient } from '../client';
8
+ import type { BookingResponse } from '../types';
9
+ import { bookingKeys } from '../queries/bookings';
10
+ import { eventKeys } from '../queries/events';
11
+
12
+ // ============================================================================
13
+ // MUTATION HOOKS
14
+ // ============================================================================
15
+
16
+ /**
17
+ * Create a new booking for an event
18
+ *
19
+ * @param options - TanStack Query mutation options
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * const { mutate, isPending } = useCreateBooking();
24
+ *
25
+ * // Simple usage - just pass eventId
26
+ * mutate({ eventId: 'event-123' });
27
+ *
28
+ * // With optional data
29
+ * mutate({
30
+ * eventId: 'event-123',
31
+ * ticketCount: 2,
32
+ * notes: 'Vegetarian meal preferred'
33
+ * });
34
+ * ```
35
+ */
36
+ export function useCreateBooking(
37
+ options?: Omit<
38
+ UseMutationOptions<
39
+ BookingResponse,
40
+ Error,
41
+ { eventId: string; ticketCount?: number; notes?: string }
42
+ >,
43
+ 'mutationFn'
44
+ >
45
+ ): UseMutationResult<
46
+ BookingResponse,
47
+ Error,
48
+ { eventId: string; ticketCount?: number; notes?: string }
49
+ > {
50
+ const queryClient = useQueryClient();
51
+
52
+ return useMutation({
53
+ mutationFn: async ({
54
+ eventId,
55
+ ticketCount,
56
+ notes,
57
+ }: {
58
+ eventId: string;
59
+ ticketCount?: number;
60
+ notes?: string;
61
+ }): Promise<BookingResponse> => {
62
+ const client = getApiClient();
63
+ const data: any = {};
64
+ if (ticketCount) data.ticketCount = ticketCount;
65
+ if (notes) data.notes = notes;
66
+ const response = await client.post(`/api/v1/events/${eventId}/book`, data);
67
+ return response.data;
68
+ },
69
+ onSuccess: (newBooking, variables, context) => {
70
+ // Invalidate user's bookings list
71
+ queryClient.invalidateQueries({ queryKey: bookingKeys.mine() });
72
+
73
+ // Invalidate all booking lists
74
+ queryClient.invalidateQueries({ queryKey: bookingKeys.lists() });
75
+
76
+ // Invalidate the event to reflect updated booking count
77
+ queryClient.invalidateQueries({
78
+ queryKey: eventKeys.detail(variables.eventId)
79
+ });
80
+
81
+ // Invalidate event bookings if applicable
82
+ queryClient.invalidateQueries({
83
+ queryKey: eventKeys.bookings(variables.eventId)
84
+ });
85
+
86
+ // Invalidate ambient events
87
+ queryClient.invalidateQueries({ queryKey: eventKeys.ambient() });
88
+
89
+ // Call user's onSuccess if provided
90
+ },
91
+ ...options,
92
+ });
93
+ }
94
+
95
+ /**
96
+ * Cancel a booking
97
+ *
98
+ * @param options - TanStack Query mutation options
99
+ *
100
+ * @example
101
+ * ```tsx
102
+ * const { mutate, isPending } = useCancelBooking();
103
+ *
104
+ * mutate('booking-123');
105
+ * ```
106
+ */
107
+ export function useCancelBooking(
108
+ options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>
109
+ ): UseMutationResult<void, Error, string> {
110
+ const queryClient = useQueryClient();
111
+
112
+ return useMutation({
113
+ mutationFn: async (id: string): Promise<void> => {
114
+ const client = getApiClient();
115
+ await client.delete(`/api/v1/bookings/${id}`);
116
+ },
117
+ onSuccess: (data, bookingId, context) => {
118
+ // Remove the booking from cache
119
+ queryClient.removeQueries({ queryKey: bookingKeys.detail(bookingId) });
120
+
121
+ // Invalidate user's bookings list
122
+ queryClient.invalidateQueries({ queryKey: bookingKeys.mine() });
123
+
124
+ // Invalidate all booking lists
125
+ queryClient.invalidateQueries({ queryKey: bookingKeys.lists() });
126
+
127
+ // Invalidate QR code cache
128
+ queryClient.removeQueries({ queryKey: bookingKeys.qrCode(bookingId) });
129
+
130
+ // Invalidate events to reflect updated booking counts
131
+ queryClient.invalidateQueries({ queryKey: eventKeys.lists() });
132
+ queryClient.invalidateQueries({ queryKey: eventKeys.upcoming() });
133
+ queryClient.invalidateQueries({ queryKey: eventKeys.ambient() });
134
+
135
+ // Call user's onSuccess if provided
136
+ },
137
+ ...options,
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Check in a booking
143
+ *
144
+ * Note: This is typically used by event hosts/ambassadors to check in attendees
145
+ *
146
+ * @param options - TanStack Query mutation options
147
+ *
148
+ * @example
149
+ * ```tsx
150
+ * const { mutate, isPending } = useCheckInBooking();
151
+ *
152
+ * mutate('booking-123');
153
+ * ```
154
+ */
155
+ export function useCheckInBooking(
156
+ options?: Omit<UseMutationOptions<BookingResponse, Error, string>, 'mutationFn'>
157
+ ): UseMutationResult<BookingResponse, Error, string> {
158
+ const queryClient = useQueryClient();
159
+
160
+ return useMutation({
161
+ mutationFn: async (id: string): Promise<BookingResponse> => {
162
+ const client = getApiClient();
163
+ const response = await client.post(`/api/v1/bookings/${id}/check-in`);
164
+ return response.data;
165
+ },
166
+ onSuccess: (checkedInBooking, bookingId, context) => {
167
+ // Update the booking in cache
168
+ queryClient.setQueryData(
169
+ bookingKeys.detail(bookingId),
170
+ checkedInBooking
171
+ );
172
+
173
+ // Invalidate user's bookings list to reflect check-in status
174
+ queryClient.invalidateQueries({ queryKey: bookingKeys.mine() });
175
+
176
+ // Invalidate all booking lists
177
+ queryClient.invalidateQueries({ queryKey: bookingKeys.lists() });
178
+
179
+ // Invalidate event bookings if applicable
180
+ if (checkedInBooking.eventId) {
181
+ queryClient.invalidateQueries({
182
+ queryKey: eventKeys.bookings(checkedInBooking.eventId)
183
+ });
184
+ }
185
+
186
+ // Call user's onSuccess if provided
187
+ },
188
+ ...options,
189
+ });
190
+ }
@@ -0,0 +1,177 @@
1
+ import { useMutation, useQueryClient } from '@tanstack/react-query';
2
+ import { getApiClient } from '../client';
3
+ import { eventChatKeys } from '../queries/event-chat';
4
+ import type {
5
+ ChatMemberResponse,
6
+ MessageResponse,
7
+ EventChatResponse,
8
+ SendMessageRequest,
9
+ UpdateMessageRequest,
10
+ UpdateChatSettingsRequest,
11
+ UpdateMemberSettingsRequest,
12
+ } from '../types';
13
+
14
+ // ============================================================================
15
+ // CHAT MANAGEMENT
16
+ // ============================================================================
17
+
18
+ /**
19
+ * Update chat settings (hosts only)
20
+ */
21
+ export function useUpdateChatSettings(eventId: string) {
22
+ const queryClient = useQueryClient();
23
+
24
+ return useMutation({
25
+ mutationFn: async (data: UpdateChatSettingsRequest) => {
26
+ const client = getApiClient();
27
+ const response = await client.put<EventChatResponse>(
28
+ `/events/${eventId}/chat/settings`,
29
+ data
30
+ );
31
+ return response.data;
32
+ },
33
+ onSuccess: () => {
34
+ queryClient.invalidateQueries({ queryKey: eventChatKeys.chat(eventId) });
35
+ },
36
+ });
37
+ }
38
+
39
+ // ============================================================================
40
+ // MEMBER MANAGEMENT
41
+ // ============================================================================
42
+
43
+ /**
44
+ * Join event chat
45
+ */
46
+ export function useJoinEventChat(eventId: string) {
47
+ const queryClient = useQueryClient();
48
+
49
+ return useMutation({
50
+ mutationFn: async () => {
51
+ const client = getApiClient();
52
+ const response = await client.post<ChatMemberResponse>(
53
+ `/events/${eventId}/chat/join`
54
+ );
55
+ return response.data;
56
+ },
57
+ onSuccess: () => {
58
+ queryClient.invalidateQueries({ queryKey: eventChatKeys.chat(eventId) });
59
+ queryClient.invalidateQueries({ queryKey: eventChatKeys.members(eventId) });
60
+ },
61
+ });
62
+ }
63
+
64
+ /**
65
+ * Leave event chat
66
+ */
67
+ export function useLeaveEventChat(eventId: string) {
68
+ const queryClient = useQueryClient();
69
+
70
+ return useMutation({
71
+ mutationFn: async () => {
72
+ const client = getApiClient();
73
+ await client.post(`/events/${eventId}/chat/leave`);
74
+ },
75
+ onSuccess: () => {
76
+ queryClient.invalidateQueries({ queryKey: eventChatKeys.chat(eventId) });
77
+ queryClient.invalidateQueries({ queryKey: eventChatKeys.members(eventId) });
78
+ },
79
+ });
80
+ }
81
+
82
+ /**
83
+ * Update member settings (mute, nickname)
84
+ */
85
+ export function useUpdateMemberSettings(eventId: string) {
86
+ const queryClient = useQueryClient();
87
+
88
+ return useMutation({
89
+ mutationFn: async (data: UpdateMemberSettingsRequest) => {
90
+ const client = getApiClient();
91
+ const response = await client.put<ChatMemberResponse>(
92
+ `/events/${eventId}/chat/settings/me`,
93
+ data
94
+ );
95
+ return response.data;
96
+ },
97
+ onSuccess: () => {
98
+ queryClient.invalidateQueries({ queryKey: eventChatKeys.members(eventId) });
99
+ },
100
+ });
101
+ }
102
+
103
+ /**
104
+ * Mark messages as read
105
+ */
106
+ export function useMarkMessagesAsRead(eventId: string) {
107
+ return useMutation({
108
+ mutationFn: async () => {
109
+ const client = getApiClient();
110
+ await client.post(`/events/${eventId}/chat/read`);
111
+ },
112
+ });
113
+ }
114
+
115
+ // ============================================================================
116
+ // MESSAGES
117
+ // ============================================================================
118
+
119
+ /**
120
+ * Send a message
121
+ */
122
+ export function useSendEventChatMessage(eventId: string) {
123
+ const queryClient = useQueryClient();
124
+
125
+ return useMutation({
126
+ mutationFn: async (data: SendMessageRequest) => {
127
+ const client = getApiClient();
128
+ const response = await client.post<MessageResponse>(
129
+ `/events/${eventId}/chat/messages`,
130
+ data
131
+ );
132
+ return response.data;
133
+ },
134
+ onSuccess: () => {
135
+ queryClient.invalidateQueries({ queryKey: eventChatKeys.messages(eventId) });
136
+ queryClient.invalidateQueries({ queryKey: eventChatKeys.chat(eventId) });
137
+ },
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Update a message
143
+ */
144
+ export function useUpdateEventChatMessage(eventId: string) {
145
+ const queryClient = useQueryClient();
146
+
147
+ return useMutation({
148
+ mutationFn: async ({ messageId, content }: { messageId: string } & UpdateMessageRequest) => {
149
+ const client = getApiClient();
150
+ const response = await client.put<MessageResponse>(
151
+ `/events/${eventId}/chat/messages/${messageId}`,
152
+ { content }
153
+ );
154
+ return response.data;
155
+ },
156
+ onSuccess: () => {
157
+ queryClient.invalidateQueries({ queryKey: eventChatKeys.messages(eventId) });
158
+ },
159
+ });
160
+ }
161
+
162
+ /**
163
+ * Delete a message
164
+ */
165
+ export function useDeleteEventChatMessage(eventId: string) {
166
+ const queryClient = useQueryClient();
167
+
168
+ return useMutation({
169
+ mutationFn: async (messageId: string) => {
170
+ const client = getApiClient();
171
+ await client.delete(`/events/${eventId}/chat/messages/${messageId}`);
172
+ },
173
+ onSuccess: () => {
174
+ queryClient.invalidateQueries({ queryKey: eventChatKeys.messages(eventId) });
175
+ },
176
+ });
177
+ }
@@ -0,0 +1,273 @@
1
+ import {
2
+ useMutation,
3
+ useQueryClient,
4
+ UseMutationOptions,
5
+ UseMutationResult,
6
+ } from '@tanstack/react-query';
7
+ import { getApiClient } from '../client';
8
+ import type { EventResponse, CreateEventRequest, UpdateEventRequest } from '../types';
9
+ import { eventKeys } from '../queries/events';
10
+
11
+ // ============================================================================
12
+ // MUTATION HOOKS
13
+ // ============================================================================
14
+
15
+ /**
16
+ * Create a new event
17
+ *
18
+ * @param options - TanStack Query mutation options
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * const { mutate, isPending } = useCreateEvent();
23
+ *
24
+ * mutate({
25
+ * title: 'Yoga in the Park',
26
+ * description: 'Join us for morning yoga',
27
+ * startDate: new Date('2025-01-15T10:00:00Z'),
28
+ * // ... other fields
29
+ * });
30
+ * ```
31
+ */
32
+ export function useCreateEvent(
33
+ options?: Omit<
34
+ UseMutationOptions<EventResponse, Error, CreateEventRequest>,
35
+ 'mutationFn'
36
+ >
37
+ ): UseMutationResult<EventResponse, Error, CreateEventRequest> {
38
+ const queryClient = useQueryClient();
39
+
40
+ return useMutation({
41
+ mutationFn: async (data: CreateEventRequest): Promise<EventResponse> => {
42
+ const client = getApiClient();
43
+ const response = await client.post('/api/v1/events', data);
44
+ return response.data;
45
+ },
46
+ onSuccess: (newEvent, variables, context) => {
47
+ // Invalidate all event lists to include the new event
48
+ queryClient.invalidateQueries({ queryKey: eventKeys.lists() });
49
+ queryClient.invalidateQueries({ queryKey: eventKeys.upcoming() });
50
+
51
+ // If the event is featured, invalidate featured events
52
+ if (newEvent.isFeatured) {
53
+ queryClient.invalidateQueries({ queryKey: eventKeys.featured() });
54
+ }
55
+
56
+ // Call user's onSuccess if provided
57
+ },
58
+ ...options,
59
+ });
60
+ }
61
+
62
+ /**
63
+ * Update an existing event
64
+ *
65
+ * @param options - TanStack Query mutation options
66
+ *
67
+ * @example
68
+ * ```tsx
69
+ * const { mutate, isPending } = useUpdateEvent();
70
+ *
71
+ * mutate({
72
+ * id: 'event-123',
73
+ * data: {
74
+ * title: 'Updated Event Title',
75
+ * isFeatured: true,
76
+ * }
77
+ * });
78
+ * ```
79
+ */
80
+ export function useUpdateEvent(
81
+ options?: Omit<
82
+ UseMutationOptions<
83
+ EventResponse,
84
+ Error,
85
+ { id: string; data: UpdateEventRequest }
86
+ >,
87
+ 'mutationFn'
88
+ >
89
+ ): UseMutationResult<EventResponse, Error, { id: string; data: UpdateEventRequest }> {
90
+ const queryClient = useQueryClient();
91
+
92
+ return useMutation({
93
+ mutationFn: async ({
94
+ id,
95
+ data,
96
+ }: {
97
+ id: string;
98
+ data: UpdateEventRequest;
99
+ }): Promise<EventResponse> => {
100
+ const client = getApiClient();
101
+ const response = await client.put(`/api/v1/events/${id}`, data);
102
+ return response.data;
103
+ },
104
+ onSuccess: (updatedEvent, variables, context) => {
105
+ // Update the specific event in cache
106
+ queryClient.setQueryData(
107
+ eventKeys.detail(variables.id),
108
+ updatedEvent
109
+ );
110
+
111
+ // If the event has a slug, update the slug-based query too
112
+ if (updatedEvent.slug && typeof updatedEvent.slug === 'string') {
113
+ queryClient.setQueryData(
114
+ eventKeys.detailBySlug(updatedEvent.slug),
115
+ updatedEvent
116
+ );
117
+ }
118
+
119
+ // Invalidate lists to reflect changes in ordering/filtering
120
+ queryClient.invalidateQueries({ queryKey: eventKeys.lists() });
121
+ queryClient.invalidateQueries({ queryKey: eventKeys.upcoming() });
122
+ queryClient.invalidateQueries({ queryKey: eventKeys.featured() });
123
+
124
+ // Call user's onSuccess if provided
125
+ },
126
+ ...options,
127
+ });
128
+ }
129
+
130
+ /**
131
+ * Delete an event
132
+ *
133
+ * @param options - TanStack Query mutation options
134
+ *
135
+ * @example
136
+ * ```tsx
137
+ * const { mutate, isPending } = useDeleteEvent();
138
+ *
139
+ * mutate('event-123');
140
+ * ```
141
+ */
142
+ export function useDeleteEvent(
143
+ options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>
144
+ ): UseMutationResult<void, Error, string> {
145
+ const queryClient = useQueryClient();
146
+
147
+ return useMutation({
148
+ mutationFn: async (id: string): Promise<void> => {
149
+ const client = getApiClient();
150
+ await client.delete(`/api/v1/events/${id}`);
151
+ },
152
+ onSuccess: (data, eventId, context) => {
153
+ // Remove the event from cache
154
+ queryClient.removeQueries({ queryKey: eventKeys.detail(eventId) });
155
+
156
+ // Invalidate all lists
157
+ queryClient.invalidateQueries({ queryKey: eventKeys.lists() });
158
+ queryClient.invalidateQueries({ queryKey: eventKeys.upcoming() });
159
+ queryClient.invalidateQueries({ queryKey: eventKeys.featured() });
160
+
161
+ // Call user's onSuccess if provided
162
+ },
163
+ ...options,
164
+ });
165
+ }
166
+
167
+ /**
168
+ * Cancel an event
169
+ *
170
+ * @param options - TanStack Query mutation options
171
+ *
172
+ * @example
173
+ * ```tsx
174
+ * const { mutate, isPending } = useCancelEvent();
175
+ *
176
+ * mutate('event-123');
177
+ * ```
178
+ */
179
+ export function useCancelEvent(
180
+ options?: Omit<UseMutationOptions<EventResponse, Error, string>, 'mutationFn'>
181
+ ): UseMutationResult<EventResponse, Error, string> {
182
+ const queryClient = useQueryClient();
183
+
184
+ return useMutation({
185
+ mutationFn: async (id: string): Promise<EventResponse> => {
186
+ const client = getApiClient();
187
+ const response = await client.post(`/api/v1/events/${id}/cancel`);
188
+ return response.data;
189
+ },
190
+ onSuccess: (cancelledEvent, eventId, context) => {
191
+ // Update the specific event in cache
192
+ queryClient.setQueryData(
193
+ eventKeys.detail(eventId),
194
+ cancelledEvent
195
+ );
196
+
197
+ // If the event has a slug, update the slug-based query too
198
+ if (cancelledEvent.slug && typeof cancelledEvent.slug === 'string') {
199
+ queryClient.setQueryData(
200
+ eventKeys.detailBySlug(cancelledEvent.slug),
201
+ cancelledEvent
202
+ );
203
+ }
204
+
205
+ // Invalidate lists to reflect the cancelled status
206
+ queryClient.invalidateQueries({ queryKey: eventKeys.lists() });
207
+ queryClient.invalidateQueries({ queryKey: eventKeys.upcoming() });
208
+ queryClient.invalidateQueries({ queryKey: eventKeys.featured() });
209
+
210
+ // Invalidate bookings for this event
211
+ queryClient.invalidateQueries({ queryKey: eventKeys.bookings(eventId) });
212
+
213
+ // Call user's onSuccess if provided
214
+ },
215
+ ...options,
216
+ });
217
+ }
218
+
219
+ /**
220
+ * Publish an event
221
+ *
222
+ * Note: This mutation is provided for future compatibility.
223
+ * The API endpoint exists but may require specific permissions.
224
+ *
225
+ * @param options - TanStack Query mutation options
226
+ *
227
+ * @example
228
+ * ```tsx
229
+ * const { mutate, isPending } = usePublishEvent();
230
+ *
231
+ * mutate('event-123');
232
+ * ```
233
+ */
234
+ export function usePublishEvent(
235
+ options?: Omit<UseMutationOptions<EventResponse, Error, string>, 'mutationFn'>
236
+ ): UseMutationResult<EventResponse, Error, string> {
237
+ const queryClient = useQueryClient();
238
+
239
+ return useMutation({
240
+ mutationFn: async (id: string): Promise<EventResponse> => {
241
+ const client = getApiClient();
242
+ const response = await client.post(`/api/v1/events/${id}/publish`);
243
+ return response.data;
244
+ },
245
+ onSuccess: (publishedEvent, eventId, context) => {
246
+ // Update the specific event in cache
247
+ queryClient.setQueryData(
248
+ eventKeys.detail(eventId),
249
+ publishedEvent
250
+ );
251
+
252
+ // If the event has a slug, update the slug-based query too
253
+ if (publishedEvent.slug && typeof publishedEvent.slug === 'string') {
254
+ queryClient.setQueryData(
255
+ eventKeys.detailBySlug(publishedEvent.slug),
256
+ publishedEvent
257
+ );
258
+ }
259
+
260
+ // Invalidate lists to reflect the published status
261
+ queryClient.invalidateQueries({ queryKey: eventKeys.lists() });
262
+ queryClient.invalidateQueries({ queryKey: eventKeys.upcoming() });
263
+
264
+ // If the event is featured, invalidate featured events
265
+ if (publishedEvent.isFeatured) {
266
+ queryClient.invalidateQueries({ queryKey: eventKeys.featured() });
267
+ }
268
+
269
+ // Call user's onSuccess if provided
270
+ },
271
+ ...options,
272
+ });
273
+ }