@growsober/sdk 1.0.3 → 1.0.4

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.
@@ -62,45 +62,28 @@ export declare function useMarkMessagesAsRead(eventId: string): import("@tanstac
62
62
  */
63
63
  export declare function useSendEventChatMessage(eventId: string): import("@tanstack/react-query").UseMutationResult<{
64
64
  id: string;
65
- chatId: string;
66
- userId: string;
65
+ conversationId: string;
66
+ role: "USER" | "ASSISTANT" | "SYSTEM";
67
67
  content: string;
68
- messageType: "TEXT" | "IMAGE" | "SYSTEM" | "ANNOUNCEMENT";
69
- imageUrl?: string;
70
- replyToId?: string;
71
- isEdited: boolean;
72
- isDeleted: boolean;
68
+ model?: Record<string, never>;
69
+ promptTokens?: Record<string, never>;
70
+ completionTokens?: Record<string, never>;
73
71
  createdAt: string;
74
- updatedAt?: string;
75
- userName?: string;
76
- userImage?: string;
77
- replyToContent?: string;
78
- replyToUserName?: string;
79
72
  }, Error, {
80
73
  content: string;
81
- messageType: "TEXT" | "IMAGE" | "SYSTEM" | "ANNOUNCEMENT";
82
- imageUrl?: string;
83
- replyToId?: string;
84
74
  }, unknown>;
85
75
  /**
86
76
  * Update a message
87
77
  */
88
78
  export declare function useUpdateEventChatMessage(eventId: string): import("@tanstack/react-query").UseMutationResult<{
89
79
  id: string;
90
- chatId: string;
91
- userId: string;
80
+ conversationId: string;
81
+ role: "USER" | "ASSISTANT" | "SYSTEM";
92
82
  content: string;
93
- messageType: "TEXT" | "IMAGE" | "SYSTEM" | "ANNOUNCEMENT";
94
- imageUrl?: string;
95
- replyToId?: string;
96
- isEdited: boolean;
97
- isDeleted: boolean;
83
+ model?: Record<string, never>;
84
+ promptTokens?: Record<string, never>;
85
+ completionTokens?: Record<string, never>;
98
86
  createdAt: string;
99
- updatedAt?: string;
100
- userName?: string;
101
- userImage?: string;
102
- replyToContent?: string;
103
- replyToUserName?: string;
104
87
  }, Error, {
105
88
  messageId: string;
106
89
  } & {
@@ -20,3 +20,4 @@ export * from './ambassadors';
20
20
  export * from './grow90';
21
21
  export * from './matching';
22
22
  export * from './event-chat';
23
+ export * from './user-pins';
@@ -36,4 +36,5 @@ __exportStar(require("./ambassadors"), exports);
36
36
  __exportStar(require("./grow90"), exports);
37
37
  __exportStar(require("./matching"), exports);
38
38
  __exportStar(require("./event-chat"), exports);
39
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL211dGF0aW9ucy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7Ozs7Ozs7Ozs7Ozs7OztBQUVILDBDQUF3QjtBQUN4Qix5Q0FBdUI7QUFDdkIsNkNBQTJCO0FBQzNCLDJDQUF5QjtBQUN6Qix5Q0FBdUI7QUFDdkIsNENBQTBCO0FBQzFCLHdDQUFzQjtBQUN0QixrREFBZ0M7QUFDaEMsMkNBQXlCO0FBQ3pCLGtEQUFnQztBQUNoQyw0Q0FBMEI7QUFDMUIsMENBQXdCO0FBQ3hCLHlDQUF1QjtBQUN2QixnREFBOEI7QUFDOUIsMkNBQXlCO0FBQ3pCLDZDQUEyQjtBQUMzQiwrQ0FBNkIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIE11dGF0aW9uIEhvb2tzXG4gKlxuICogUmUtZXhwb3J0cyBhbGwgbXV0YXRpb24gaG9va3MgZm9yIEFQSSBlbmRwb2ludHMuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9hZG1pbic7XG5leHBvcnQgKiBmcm9tICcuL2F1dGgnO1xuZXhwb3J0ICogZnJvbSAnLi9ib29raW5ncyc7XG5leHBvcnQgKiBmcm9tICcuL2V2ZW50cyc7XG5leHBvcnQgKiBmcm9tICcuL2h1YnMnO1xuZXhwb3J0ICogZnJvbSAnLi9saWJyYXJ5JztcbmV4cG9ydCAqIGZyb20gJy4vbWFwJztcbmV4cG9ydCAqIGZyb20gJy4vbm90aWZpY2F0aW9ucyc7XG5leHBvcnQgKiBmcm9tICcuL29mZmVycyc7XG5leHBvcnQgKiBmcm9tICcuL3N1YnNjcmlwdGlvbnMnO1xuZXhwb3J0ICogZnJvbSAnLi9zdXBwb3J0JztcbmV4cG9ydCAqIGZyb20gJy4vdXNlcnMnO1xuZXhwb3J0ICogZnJvbSAnLi9qYWNrJztcbmV4cG9ydCAqIGZyb20gJy4vYW1iYXNzYWRvcnMnO1xuZXhwb3J0ICogZnJvbSAnLi9ncm93OTAnO1xuZXhwb3J0ICogZnJvbSAnLi9tYXRjaGluZyc7XG5leHBvcnQgKiBmcm9tICcuL2V2ZW50LWNoYXQnO1xuIl19
39
+ __exportStar(require("./user-pins"), exports);
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL211dGF0aW9ucy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7R0FJRzs7Ozs7Ozs7Ozs7Ozs7OztBQUVILDBDQUF3QjtBQUN4Qix5Q0FBdUI7QUFDdkIsNkNBQTJCO0FBQzNCLDJDQUF5QjtBQUN6Qix5Q0FBdUI7QUFDdkIsNENBQTBCO0FBQzFCLHdDQUFzQjtBQUN0QixrREFBZ0M7QUFDaEMsMkNBQXlCO0FBQ3pCLGtEQUFnQztBQUNoQyw0Q0FBMEI7QUFDMUIsMENBQXdCO0FBQ3hCLHlDQUF1QjtBQUN2QixnREFBOEI7QUFDOUIsMkNBQXlCO0FBQ3pCLDZDQUEyQjtBQUMzQiwrQ0FBNkI7QUFDN0IsOENBQTRCIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBNdXRhdGlvbiBIb29rc1xuICpcbiAqIFJlLWV4cG9ydHMgYWxsIG11dGF0aW9uIGhvb2tzIGZvciBBUEkgZW5kcG9pbnRzLlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vYWRtaW4nO1xuZXhwb3J0ICogZnJvbSAnLi9hdXRoJztcbmV4cG9ydCAqIGZyb20gJy4vYm9va2luZ3MnO1xuZXhwb3J0ICogZnJvbSAnLi9ldmVudHMnO1xuZXhwb3J0ICogZnJvbSAnLi9odWJzJztcbmV4cG9ydCAqIGZyb20gJy4vbGlicmFyeSc7XG5leHBvcnQgKiBmcm9tICcuL21hcCc7XG5leHBvcnQgKiBmcm9tICcuL25vdGlmaWNhdGlvbnMnO1xuZXhwb3J0ICogZnJvbSAnLi9vZmZlcnMnO1xuZXhwb3J0ICogZnJvbSAnLi9zdWJzY3JpcHRpb25zJztcbmV4cG9ydCAqIGZyb20gJy4vc3VwcG9ydCc7XG5leHBvcnQgKiBmcm9tICcuL3VzZXJzJztcbmV4cG9ydCAqIGZyb20gJy4vamFjayc7XG5leHBvcnQgKiBmcm9tICcuL2FtYmFzc2Fkb3JzJztcbmV4cG9ydCAqIGZyb20gJy4vZ3JvdzkwJztcbmV4cG9ydCAqIGZyb20gJy4vbWF0Y2hpbmcnO1xuZXhwb3J0ICogZnJvbSAnLi9ldmVudC1jaGF0JztcbmV4cG9ydCAqIGZyb20gJy4vdXNlci1waW5zJztcbiJdfQ==
@@ -0,0 +1,132 @@
1
+ /**
2
+ * User Pins Mutation Hooks
3
+ *
4
+ * TanStack Query mutation hooks for user pin operations.
5
+ * These hooks handle creating and deleting user pins
6
+ * ("I'm here now" / "I'll be there").
7
+ *
8
+ * @module api/mutations/user-pins
9
+ */
10
+ import { UseMutationOptions, UseMutationResult } from '@tanstack/react-query';
11
+ import { UserPinResponse, PinType } from '../queries/user-pins';
12
+ export interface CreatePinRequest {
13
+ type: PinType;
14
+ latitude: number;
15
+ longitude: number;
16
+ locationName?: string;
17
+ activity: string;
18
+ venueId?: string;
19
+ scheduledTime?: string;
20
+ duration?: number;
21
+ }
22
+ /**
23
+ * Create a new user pin
24
+ *
25
+ * @description
26
+ * Creates a new pin showing where the user is or will be.
27
+ * Any existing active pin is automatically deactivated.
28
+ *
29
+ * Two types of pins:
30
+ * - HERE_NOW: User is currently at this location (default 1 hour duration)
31
+ * - SCHEDULED: User will be at this location at a specific time (default 2 hour duration)
32
+ *
33
+ * @endpoint POST /api/v1/user-pins
34
+ *
35
+ * @example
36
+ * Drop a "I'm here now" pin:
37
+ * ```tsx
38
+ * import { useCreateUserPin } from '@growsober/sdk';
39
+ *
40
+ * function DropPinButton({ location }) {
41
+ * const createPin = useCreateUserPin();
42
+ *
43
+ * const handleDropPin = () => {
44
+ * createPin.mutate({
45
+ * type: 'HERE_NOW',
46
+ * latitude: location.lat,
47
+ * longitude: location.lng,
48
+ * locationName: 'Fabrica Coffee',
49
+ * activity: 'Working remotely',
50
+ * duration: 120, // 2 hours
51
+ * });
52
+ * };
53
+ *
54
+ * return (
55
+ * <Button onPress={handleDropPin} loading={createPin.isPending}>
56
+ * Drop Pin
57
+ * </Button>
58
+ * );
59
+ * }
60
+ * ```
61
+ *
62
+ * @example
63
+ * Schedule a pin for later:
64
+ * ```tsx
65
+ * import { useCreateUserPin } from '@growsober/sdk';
66
+ *
67
+ * function SchedulePinForm() {
68
+ * const createPin = useCreateUserPin({
69
+ * onSuccess: () => {
70
+ * toast.show('Pin scheduled!');
71
+ * },
72
+ * });
73
+ *
74
+ * const handleSchedule = (data) => {
75
+ * createPin.mutate({
76
+ * type: 'SCHEDULED',
77
+ * latitude: data.venue.lat,
78
+ * longitude: data.venue.lng,
79
+ * locationName: data.venue.name,
80
+ * venueId: data.venue.id,
81
+ * activity: 'Coffee meetup',
82
+ * scheduledTime: data.time.toISOString(),
83
+ * duration: 90,
84
+ * });
85
+ * };
86
+ *
87
+ * return <ScheduleForm onSubmit={handleSchedule} />;
88
+ * }
89
+ * ```
90
+ *
91
+ * @param options - TanStack Query mutation options
92
+ * @returns TanStack Query mutation result
93
+ */
94
+ export declare function useCreateUserPin(options?: Omit<UseMutationOptions<UserPinResponse, Error, CreatePinRequest>, 'mutationFn'>): UseMutationResult<UserPinResponse, Error, CreatePinRequest>;
95
+ /**
96
+ * Delete a user pin
97
+ *
98
+ * @description
99
+ * Deactivates a user pin. Users can only delete their own pins.
100
+ *
101
+ * @endpoint DELETE /api/v1/user-pins/:id
102
+ *
103
+ * @example
104
+ * ```tsx
105
+ * import { useDeleteUserPin } from '@growsober/sdk';
106
+ *
107
+ * function MyPinCard({ pin }) {
108
+ * const deletePin = useDeleteUserPin({
109
+ * onSuccess: () => {
110
+ * toast.show('Pin removed');
111
+ * },
112
+ * });
113
+ *
114
+ * return (
115
+ * <Card>
116
+ * <Text>{pin.activity}</Text>
117
+ * <Text>At {pin.locationName}</Text>
118
+ * <Button
119
+ * onPress={() => deletePin.mutate(pin.id)}
120
+ * loading={deletePin.isPending}
121
+ * >
122
+ * Remove Pin
123
+ * </Button>
124
+ * </Card>
125
+ * );
126
+ * }
127
+ * ```
128
+ *
129
+ * @param options - TanStack Query mutation options
130
+ * @returns TanStack Query mutation result
131
+ */
132
+ export declare function useDeleteUserPin(options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>): UseMutationResult<void, Error, string>;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ /**
3
+ * User Pins Mutation Hooks
4
+ *
5
+ * TanStack Query mutation hooks for user pin operations.
6
+ * These hooks handle creating and deleting user pins
7
+ * ("I'm here now" / "I'll be there").
8
+ *
9
+ * @module api/mutations/user-pins
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.useCreateUserPin = useCreateUserPin;
13
+ exports.useDeleteUserPin = useDeleteUserPin;
14
+ const react_query_1 = require("@tanstack/react-query");
15
+ const client_1 = require("../client");
16
+ const user_pins_1 = require("../queries/user-pins");
17
+ // ============================================================================
18
+ // MUTATION HOOKS
19
+ // ============================================================================
20
+ /**
21
+ * Create a new user pin
22
+ *
23
+ * @description
24
+ * Creates a new pin showing where the user is or will be.
25
+ * Any existing active pin is automatically deactivated.
26
+ *
27
+ * Two types of pins:
28
+ * - HERE_NOW: User is currently at this location (default 1 hour duration)
29
+ * - SCHEDULED: User will be at this location at a specific time (default 2 hour duration)
30
+ *
31
+ * @endpoint POST /api/v1/user-pins
32
+ *
33
+ * @example
34
+ * Drop a "I'm here now" pin:
35
+ * ```tsx
36
+ * import { useCreateUserPin } from '@growsober/sdk';
37
+ *
38
+ * function DropPinButton({ location }) {
39
+ * const createPin = useCreateUserPin();
40
+ *
41
+ * const handleDropPin = () => {
42
+ * createPin.mutate({
43
+ * type: 'HERE_NOW',
44
+ * latitude: location.lat,
45
+ * longitude: location.lng,
46
+ * locationName: 'Fabrica Coffee',
47
+ * activity: 'Working remotely',
48
+ * duration: 120, // 2 hours
49
+ * });
50
+ * };
51
+ *
52
+ * return (
53
+ * <Button onPress={handleDropPin} loading={createPin.isPending}>
54
+ * Drop Pin
55
+ * </Button>
56
+ * );
57
+ * }
58
+ * ```
59
+ *
60
+ * @example
61
+ * Schedule a pin for later:
62
+ * ```tsx
63
+ * import { useCreateUserPin } from '@growsober/sdk';
64
+ *
65
+ * function SchedulePinForm() {
66
+ * const createPin = useCreateUserPin({
67
+ * onSuccess: () => {
68
+ * toast.show('Pin scheduled!');
69
+ * },
70
+ * });
71
+ *
72
+ * const handleSchedule = (data) => {
73
+ * createPin.mutate({
74
+ * type: 'SCHEDULED',
75
+ * latitude: data.venue.lat,
76
+ * longitude: data.venue.lng,
77
+ * locationName: data.venue.name,
78
+ * venueId: data.venue.id,
79
+ * activity: 'Coffee meetup',
80
+ * scheduledTime: data.time.toISOString(),
81
+ * duration: 90,
82
+ * });
83
+ * };
84
+ *
85
+ * return <ScheduleForm onSubmit={handleSchedule} />;
86
+ * }
87
+ * ```
88
+ *
89
+ * @param options - TanStack Query mutation options
90
+ * @returns TanStack Query mutation result
91
+ */
92
+ function useCreateUserPin(options) {
93
+ const queryClient = (0, react_query_1.useQueryClient)();
94
+ return (0, react_query_1.useMutation)({
95
+ mutationFn: async (data) => {
96
+ const client = (0, client_1.getApiClient)();
97
+ const response = await client.post('/api/v1/user-pins', data);
98
+ return response.data;
99
+ },
100
+ onSuccess: () => {
101
+ // Invalidate pin queries to reflect new pin
102
+ queryClient.invalidateQueries({ queryKey: user_pins_1.userPinKeys.all });
103
+ },
104
+ ...options,
105
+ });
106
+ }
107
+ /**
108
+ * Delete a user pin
109
+ *
110
+ * @description
111
+ * Deactivates a user pin. Users can only delete their own pins.
112
+ *
113
+ * @endpoint DELETE /api/v1/user-pins/:id
114
+ *
115
+ * @example
116
+ * ```tsx
117
+ * import { useDeleteUserPin } from '@growsober/sdk';
118
+ *
119
+ * function MyPinCard({ pin }) {
120
+ * const deletePin = useDeleteUserPin({
121
+ * onSuccess: () => {
122
+ * toast.show('Pin removed');
123
+ * },
124
+ * });
125
+ *
126
+ * return (
127
+ * <Card>
128
+ * <Text>{pin.activity}</Text>
129
+ * <Text>At {pin.locationName}</Text>
130
+ * <Button
131
+ * onPress={() => deletePin.mutate(pin.id)}
132
+ * loading={deletePin.isPending}
133
+ * >
134
+ * Remove Pin
135
+ * </Button>
136
+ * </Card>
137
+ * );
138
+ * }
139
+ * ```
140
+ *
141
+ * @param options - TanStack Query mutation options
142
+ * @returns TanStack Query mutation result
143
+ */
144
+ function useDeleteUserPin(options) {
145
+ const queryClient = (0, react_query_1.useQueryClient)();
146
+ return (0, react_query_1.useMutation)({
147
+ mutationFn: async (pinId) => {
148
+ const client = (0, client_1.getApiClient)();
149
+ await client.delete(`/api/v1/user-pins/${pinId}`);
150
+ },
151
+ onSuccess: () => {
152
+ // Invalidate pin queries to reflect deletion
153
+ queryClient.invalidateQueries({ queryKey: user_pins_1.userPinKeys.all });
154
+ },
155
+ ...options,
156
+ });
157
+ }
158
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlci1waW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS9tdXRhdGlvbnMvdXNlci1waW5zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7R0FRRzs7QUFzR0gsNENBb0JDO0FBdUNELDRDQWdCQztBQS9LRCx1REFLK0I7QUFDL0Isc0NBQXlDO0FBQ3pDLG9EQUE2RTtBQWlCN0UsK0VBQStFO0FBQy9FLGlCQUFpQjtBQUNqQiwrRUFBK0U7QUFFL0U7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBdUVHO0FBQ0gsU0FBZ0IsZ0JBQWdCLENBQzlCLE9BR0M7SUFFRCxNQUFNLFdBQVcsR0FBRyxJQUFBLDRCQUFjLEdBQUUsQ0FBQztJQUVyQyxPQUFPLElBQUEseUJBQVcsRUFBQztRQUNqQixVQUFVLEVBQUUsS0FBSyxFQUFFLElBQXNCLEVBQTRCLEVBQUU7WUFDckUsTUFBTSxNQUFNLEdBQUcsSUFBQSxxQkFBWSxHQUFFLENBQUM7WUFDOUIsTUFBTSxRQUFRLEdBQUcsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFrQixtQkFBbUIsRUFBRSxJQUFJLENBQUMsQ0FBQztZQUMvRSxPQUFPLFFBQVEsQ0FBQyxJQUFJLENBQUM7UUFDdkIsQ0FBQztRQUNELFNBQVMsRUFBRSxHQUFHLEVBQUU7WUFDZCw0Q0FBNEM7WUFDNUMsV0FBVyxDQUFDLGlCQUFpQixDQUFDLEVBQUUsUUFBUSxFQUFFLHVCQUFXLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQztRQUMvRCxDQUFDO1FBQ0QsR0FBRyxPQUFPO0tBQ1gsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQ0c7QUFDSCxTQUFnQixnQkFBZ0IsQ0FDOUIsT0FBcUU7SUFFckUsTUFBTSxXQUFXLEdBQUcsSUFBQSw0QkFBYyxHQUFFLENBQUM7SUFFckMsT0FBTyxJQUFBLHlCQUFXLEVBQUM7UUFDakIsVUFBVSxFQUFFLEtBQUssRUFBRSxLQUFhLEVBQWlCLEVBQUU7WUFDakQsTUFBTSxNQUFNLEdBQUcsSUFBQSxxQkFBWSxHQUFFLENBQUM7WUFDOUIsTUFBTSxNQUFNLENBQUMsTUFBTSxDQUFDLHFCQUFxQixLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFDRCxTQUFTLEVBQUUsR0FBRyxFQUFFO1lBQ2QsNkNBQTZDO1lBQzdDLFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFFLFFBQVEsRUFBRSx1QkFBVyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDL0QsQ0FBQztRQUNELEdBQUcsT0FBTztLQUNYLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFVzZXIgUGlucyBNdXRhdGlvbiBIb29rc1xuICpcbiAqIFRhblN0YWNrIFF1ZXJ5IG11dGF0aW9uIGhvb2tzIGZvciB1c2VyIHBpbiBvcGVyYXRpb25zLlxuICogVGhlc2UgaG9va3MgaGFuZGxlIGNyZWF0aW5nIGFuZCBkZWxldGluZyB1c2VyIHBpbnNcbiAqIChcIkknbSBoZXJlIG5vd1wiIC8gXCJJJ2xsIGJlIHRoZXJlXCIpLlxuICpcbiAqIEBtb2R1bGUgYXBpL211dGF0aW9ucy91c2VyLXBpbnNcbiAqL1xuXG5pbXBvcnQge1xuICB1c2VNdXRhdGlvbixcbiAgVXNlTXV0YXRpb25PcHRpb25zLFxuICBVc2VNdXRhdGlvblJlc3VsdCxcbiAgdXNlUXVlcnlDbGllbnQsXG59IGZyb20gJ0B0YW5zdGFjay9yZWFjdC1xdWVyeSc7XG5pbXBvcnQgeyBnZXRBcGlDbGllbnQgfSBmcm9tICcuLi9jbGllbnQnO1xuaW1wb3J0IHsgdXNlclBpbktleXMsIFVzZXJQaW5SZXNwb25zZSwgUGluVHlwZSB9IGZyb20gJy4uL3F1ZXJpZXMvdXNlci1waW5zJztcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gUkVRVUVTVCBUWVBFU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIENyZWF0ZVBpblJlcXVlc3Qge1xuICB0eXBlOiBQaW5UeXBlO1xuICBsYXRpdHVkZTogbnVtYmVyO1xuICBsb25naXR1ZGU6IG51bWJlcjtcbiAgbG9jYXRpb25OYW1lPzogc3RyaW5nO1xuICBhY3Rpdml0eTogc3RyaW5nO1xuICB2ZW51ZUlkPzogc3RyaW5nO1xuICBzY2hlZHVsZWRUaW1lPzogc3RyaW5nOyAvLyBJU08gZGF0ZSBzdHJpbmcsIHJlcXVpcmVkIGZvciBTQ0hFRFVMRUQgdHlwZVxuICBkdXJhdGlvbj86IG51bWJlcjsgLy8gbWludXRlcywgZGVmYXVsdCA2MCBmb3IgSEVSRV9OT1csIDEyMCBmb3IgU0NIRURVTEVEXG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIE1VVEFUSU9OIEhPT0tTXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogQ3JlYXRlIGEgbmV3IHVzZXIgcGluXG4gKlxuICogQGRlc2NyaXB0aW9uXG4gKiBDcmVhdGVzIGEgbmV3IHBpbiBzaG93aW5nIHdoZXJlIHRoZSB1c2VyIGlzIG9yIHdpbGwgYmUuXG4gKiBBbnkgZXhpc3RpbmcgYWN0aXZlIHBpbiBpcyBhdXRvbWF0aWNhbGx5IGRlYWN0aXZhdGVkLlxuICpcbiAqIFR3byB0eXBlcyBvZiBwaW5zOlxuICogLSBIRVJFX05PVzogVXNlciBpcyBjdXJyZW50bHkgYXQgdGhpcyBsb2NhdGlvbiAoZGVmYXVsdCAxIGhvdXIgZHVyYXRpb24pXG4gKiAtIFNDSEVEVUxFRDogVXNlciB3aWxsIGJlIGF0IHRoaXMgbG9jYXRpb24gYXQgYSBzcGVjaWZpYyB0aW1lIChkZWZhdWx0IDIgaG91ciBkdXJhdGlvbilcbiAqXG4gKiBAZW5kcG9pbnQgUE9TVCAvYXBpL3YxL3VzZXItcGluc1xuICpcbiAqIEBleGFtcGxlXG4gKiBEcm9wIGEgXCJJJ20gaGVyZSBub3dcIiBwaW46XG4gKiBgYGB0c3hcbiAqIGltcG9ydCB7IHVzZUNyZWF0ZVVzZXJQaW4gfSBmcm9tICdAZ3Jvd3NvYmVyL3Nkayc7XG4gKlxuICogZnVuY3Rpb24gRHJvcFBpbkJ1dHRvbih7IGxvY2F0aW9uIH0pIHtcbiAqICAgY29uc3QgY3JlYXRlUGluID0gdXNlQ3JlYXRlVXNlclBpbigpO1xuICpcbiAqICAgY29uc3QgaGFuZGxlRHJvcFBpbiA9ICgpID0+IHtcbiAqICAgICBjcmVhdGVQaW4ubXV0YXRlKHtcbiAqICAgICAgIHR5cGU6ICdIRVJFX05PVycsXG4gKiAgICAgICBsYXRpdHVkZTogbG9jYXRpb24ubGF0LFxuICogICAgICAgbG9uZ2l0dWRlOiBsb2NhdGlvbi5sbmcsXG4gKiAgICAgICBsb2NhdGlvbk5hbWU6ICdGYWJyaWNhIENvZmZlZScsXG4gKiAgICAgICBhY3Rpdml0eTogJ1dvcmtpbmcgcmVtb3RlbHknLFxuICogICAgICAgZHVyYXRpb246IDEyMCwgLy8gMiBob3Vyc1xuICogICAgIH0pO1xuICogICB9O1xuICpcbiAqICAgcmV0dXJuIChcbiAqICAgICA8QnV0dG9uIG9uUHJlc3M9e2hhbmRsZURyb3BQaW59IGxvYWRpbmc9e2NyZWF0ZVBpbi5pc1BlbmRpbmd9PlxuICogICAgICAgRHJvcCBQaW5cbiAqICAgICA8L0J1dHRvbj5cbiAqICAgKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBleGFtcGxlXG4gKiBTY2hlZHVsZSBhIHBpbiBmb3IgbGF0ZXI6XG4gKiBgYGB0c3hcbiAqIGltcG9ydCB7IHVzZUNyZWF0ZVVzZXJQaW4gfSBmcm9tICdAZ3Jvd3NvYmVyL3Nkayc7XG4gKlxuICogZnVuY3Rpb24gU2NoZWR1bGVQaW5Gb3JtKCkge1xuICogICBjb25zdCBjcmVhdGVQaW4gPSB1c2VDcmVhdGVVc2VyUGluKHtcbiAqICAgICBvblN1Y2Nlc3M6ICgpID0+IHtcbiAqICAgICAgIHRvYXN0LnNob3coJ1BpbiBzY2hlZHVsZWQhJyk7XG4gKiAgICAgfSxcbiAqICAgfSk7XG4gKlxuICogICBjb25zdCBoYW5kbGVTY2hlZHVsZSA9IChkYXRhKSA9PiB7XG4gKiAgICAgY3JlYXRlUGluLm11dGF0ZSh7XG4gKiAgICAgICB0eXBlOiAnU0NIRURVTEVEJyxcbiAqICAgICAgIGxhdGl0dWRlOiBkYXRhLnZlbnVlLmxhdCxcbiAqICAgICAgIGxvbmdpdHVkZTogZGF0YS52ZW51ZS5sbmcsXG4gKiAgICAgICBsb2NhdGlvbk5hbWU6IGRhdGEudmVudWUubmFtZSxcbiAqICAgICAgIHZlbnVlSWQ6IGRhdGEudmVudWUuaWQsXG4gKiAgICAgICBhY3Rpdml0eTogJ0NvZmZlZSBtZWV0dXAnLFxuICogICAgICAgc2NoZWR1bGVkVGltZTogZGF0YS50aW1lLnRvSVNPU3RyaW5nKCksXG4gKiAgICAgICBkdXJhdGlvbjogOTAsXG4gKiAgICAgfSk7XG4gKiAgIH07XG4gKlxuICogICByZXR1cm4gPFNjaGVkdWxlRm9ybSBvblN1Ym1pdD17aGFuZGxlU2NoZWR1bGV9IC8+O1xuICogfVxuICogYGBgXG4gKlxuICogQHBhcmFtIG9wdGlvbnMgLSBUYW5TdGFjayBRdWVyeSBtdXRhdGlvbiBvcHRpb25zXG4gKiBAcmV0dXJucyBUYW5TdGFjayBRdWVyeSBtdXRhdGlvbiByZXN1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZUNyZWF0ZVVzZXJQaW4oXG4gIG9wdGlvbnM/OiBPbWl0PFxuICAgIFVzZU11dGF0aW9uT3B0aW9uczxVc2VyUGluUmVzcG9uc2UsIEVycm9yLCBDcmVhdGVQaW5SZXF1ZXN0PixcbiAgICAnbXV0YXRpb25GbidcbiAgPlxuKTogVXNlTXV0YXRpb25SZXN1bHQ8VXNlclBpblJlc3BvbnNlLCBFcnJvciwgQ3JlYXRlUGluUmVxdWVzdD4ge1xuICBjb25zdCBxdWVyeUNsaWVudCA9IHVzZVF1ZXJ5Q2xpZW50KCk7XG5cbiAgcmV0dXJuIHVzZU11dGF0aW9uKHtcbiAgICBtdXRhdGlvbkZuOiBhc3luYyAoZGF0YTogQ3JlYXRlUGluUmVxdWVzdCk6IFByb21pc2U8VXNlclBpblJlc3BvbnNlPiA9PiB7XG4gICAgICBjb25zdCBjbGllbnQgPSBnZXRBcGlDbGllbnQoKTtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LnBvc3Q8VXNlclBpblJlc3BvbnNlPignL2FwaS92MS91c2VyLXBpbnMnLCBkYXRhKTtcbiAgICAgIHJldHVybiByZXNwb25zZS5kYXRhO1xuICAgIH0sXG4gICAgb25TdWNjZXNzOiAoKSA9PiB7XG4gICAgICAvLyBJbnZhbGlkYXRlIHBpbiBxdWVyaWVzIHRvIHJlZmxlY3QgbmV3IHBpblxuICAgICAgcXVlcnlDbGllbnQuaW52YWxpZGF0ZVF1ZXJpZXMoeyBxdWVyeUtleTogdXNlclBpbktleXMuYWxsIH0pO1xuICAgIH0sXG4gICAgLi4ub3B0aW9ucyxcbiAgfSk7XG59XG5cbi8qKlxuICogRGVsZXRlIGEgdXNlciBwaW5cbiAqXG4gKiBAZGVzY3JpcHRpb25cbiAqIERlYWN0aXZhdGVzIGEgdXNlciBwaW4uIFVzZXJzIGNhbiBvbmx5IGRlbGV0ZSB0aGVpciBvd24gcGlucy5cbiAqXG4gKiBAZW5kcG9pbnQgREVMRVRFIC9hcGkvdjEvdXNlci1waW5zLzppZFxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIGltcG9ydCB7IHVzZURlbGV0ZVVzZXJQaW4gfSBmcm9tICdAZ3Jvd3NvYmVyL3Nkayc7XG4gKlxuICogZnVuY3Rpb24gTXlQaW5DYXJkKHsgcGluIH0pIHtcbiAqICAgY29uc3QgZGVsZXRlUGluID0gdXNlRGVsZXRlVXNlclBpbih7XG4gKiAgICAgb25TdWNjZXNzOiAoKSA9PiB7XG4gKiAgICAgICB0b2FzdC5zaG93KCdQaW4gcmVtb3ZlZCcpO1xuICogICAgIH0sXG4gKiAgIH0pO1xuICpcbiAqICAgcmV0dXJuIChcbiAqICAgICA8Q2FyZD5cbiAqICAgICAgIDxUZXh0PntwaW4uYWN0aXZpdHl9PC9UZXh0PlxuICogICAgICAgPFRleHQ+QXQge3Bpbi5sb2NhdGlvbk5hbWV9PC9UZXh0PlxuICogICAgICAgPEJ1dHRvblxuICogICAgICAgICBvblByZXNzPXsoKSA9PiBkZWxldGVQaW4ubXV0YXRlKHBpbi5pZCl9XG4gKiAgICAgICAgIGxvYWRpbmc9e2RlbGV0ZVBpbi5pc1BlbmRpbmd9XG4gKiAgICAgICA+XG4gKiAgICAgICAgIFJlbW92ZSBQaW5cbiAqICAgICAgIDwvQnV0dG9uPlxuICogICAgIDwvQ2FyZD5cbiAqICAgKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBwYXJhbSBvcHRpb25zIC0gVGFuU3RhY2sgUXVlcnkgbXV0YXRpb24gb3B0aW9uc1xuICogQHJldHVybnMgVGFuU3RhY2sgUXVlcnkgbXV0YXRpb24gcmVzdWx0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1c2VEZWxldGVVc2VyUGluKFxuICBvcHRpb25zPzogT21pdDxVc2VNdXRhdGlvbk9wdGlvbnM8dm9pZCwgRXJyb3IsIHN0cmluZz4sICdtdXRhdGlvbkZuJz5cbik6IFVzZU11dGF0aW9uUmVzdWx0PHZvaWQsIEVycm9yLCBzdHJpbmc+IHtcbiAgY29uc3QgcXVlcnlDbGllbnQgPSB1c2VRdWVyeUNsaWVudCgpO1xuXG4gIHJldHVybiB1c2VNdXRhdGlvbih7XG4gICAgbXV0YXRpb25GbjogYXN5bmMgKHBpbklkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgICAgIGNvbnN0IGNsaWVudCA9IGdldEFwaUNsaWVudCgpO1xuICAgICAgYXdhaXQgY2xpZW50LmRlbGV0ZShgL2FwaS92MS91c2VyLXBpbnMvJHtwaW5JZH1gKTtcbiAgICB9LFxuICAgIG9uU3VjY2VzczogKCkgPT4ge1xuICAgICAgLy8gSW52YWxpZGF0ZSBwaW4gcXVlcmllcyB0byByZWZsZWN0IGRlbGV0aW9uXG4gICAgICBxdWVyeUNsaWVudC5pbnZhbGlkYXRlUXVlcmllcyh7IHF1ZXJ5S2V5OiB1c2VyUGluS2V5cy5hbGwgfSk7XG4gICAgfSxcbiAgICAuLi5vcHRpb25zLFxuICB9KTtcbn1cbiJdfQ==
@@ -22,3 +22,4 @@ export * from './ambassadors';
22
22
  export * from './grow90';
23
23
  export * from './matching';
24
24
  export * from './event-chat';
25
+ export * from './user-pins';
@@ -38,4 +38,5 @@ __exportStar(require("./ambassadors"), exports);
38
38
  __exportStar(require("./grow90"), exports);
39
39
  __exportStar(require("./matching"), exports);
40
40
  __exportStar(require("./event-chat"), exports);
41
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3F1ZXJpZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7O0dBSUc7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFSCwwQ0FBd0I7QUFDeEIseUNBQXVCO0FBQ3ZCLDZDQUEyQjtBQUMzQiwrQ0FBNkI7QUFDN0IsMkNBQXlCO0FBQ3pCLDJDQUF5QjtBQUN6Qix5Q0FBdUI7QUFDdkIsNENBQTBCO0FBQzFCLHdDQUFzQjtBQUN0QixrREFBZ0M7QUFDaEMsMkNBQXlCO0FBQ3pCLGtEQUFnQztBQUNoQyw0Q0FBMEI7QUFDMUIsMENBQXdCO0FBQ3hCLHlDQUF1QjtBQUN2QixnREFBOEI7QUFDOUIsMkNBQXlCO0FBQ3pCLDZDQUEyQjtBQUMzQiwrQ0FBNkIiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFF1ZXJ5IEhvb2tzXG4gKlxuICogUmUtZXhwb3J0cyBhbGwgcXVlcnkgaG9va3MgZm9yIEFQSSBlbmRwb2ludHMuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9hZG1pbic7XG5leHBvcnQgKiBmcm9tICcuL2F1dGgnO1xuZXhwb3J0ICogZnJvbSAnLi9ib29raW5ncyc7XG5leHBvcnQgKiBmcm9tICcuL2J1c2luZXNzZXMnO1xuZXhwb3J0ICogZnJvbSAnLi9jaXRpZXMnO1xuZXhwb3J0ICogZnJvbSAnLi9ldmVudHMnO1xuZXhwb3J0ICogZnJvbSAnLi9odWJzJztcbmV4cG9ydCAqIGZyb20gJy4vbGlicmFyeSc7XG5leHBvcnQgKiBmcm9tICcuL21hcCc7XG5leHBvcnQgKiBmcm9tICcuL25vdGlmaWNhdGlvbnMnO1xuZXhwb3J0ICogZnJvbSAnLi9vZmZlcnMnO1xuZXhwb3J0ICogZnJvbSAnLi9zdWJzY3JpcHRpb25zJztcbmV4cG9ydCAqIGZyb20gJy4vc3VwcG9ydCc7XG5leHBvcnQgKiBmcm9tICcuL3VzZXJzJztcbmV4cG9ydCAqIGZyb20gJy4vamFjayc7XG5leHBvcnQgKiBmcm9tICcuL2FtYmFzc2Fkb3JzJztcbmV4cG9ydCAqIGZyb20gJy4vZ3JvdzkwJztcbmV4cG9ydCAqIGZyb20gJy4vbWF0Y2hpbmcnO1xuZXhwb3J0ICogZnJvbSAnLi9ldmVudC1jaGF0JztcbiJdfQ==
41
+ __exportStar(require("./user-pins"), exports);
42
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3F1ZXJpZXMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7O0dBSUc7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFSCwwQ0FBd0I7QUFDeEIseUNBQXVCO0FBQ3ZCLDZDQUEyQjtBQUMzQiwrQ0FBNkI7QUFDN0IsMkNBQXlCO0FBQ3pCLDJDQUF5QjtBQUN6Qix5Q0FBdUI7QUFDdkIsNENBQTBCO0FBQzFCLHdDQUFzQjtBQUN0QixrREFBZ0M7QUFDaEMsMkNBQXlCO0FBQ3pCLGtEQUFnQztBQUNoQyw0Q0FBMEI7QUFDMUIsMENBQXdCO0FBQ3hCLHlDQUF1QjtBQUN2QixnREFBOEI7QUFDOUIsMkNBQXlCO0FBQ3pCLDZDQUEyQjtBQUMzQiwrQ0FBNkI7QUFDN0IsOENBQTRCIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBRdWVyeSBIb29rc1xuICpcbiAqIFJlLWV4cG9ydHMgYWxsIHF1ZXJ5IGhvb2tzIGZvciBBUEkgZW5kcG9pbnRzLlxuICovXG5cbmV4cG9ydCAqIGZyb20gJy4vYWRtaW4nO1xuZXhwb3J0ICogZnJvbSAnLi9hdXRoJztcbmV4cG9ydCAqIGZyb20gJy4vYm9va2luZ3MnO1xuZXhwb3J0ICogZnJvbSAnLi9idXNpbmVzc2VzJztcbmV4cG9ydCAqIGZyb20gJy4vY2l0aWVzJztcbmV4cG9ydCAqIGZyb20gJy4vZXZlbnRzJztcbmV4cG9ydCAqIGZyb20gJy4vaHVicyc7XG5leHBvcnQgKiBmcm9tICcuL2xpYnJhcnknO1xuZXhwb3J0ICogZnJvbSAnLi9tYXAnO1xuZXhwb3J0ICogZnJvbSAnLi9ub3RpZmljYXRpb25zJztcbmV4cG9ydCAqIGZyb20gJy4vb2ZmZXJzJztcbmV4cG9ydCAqIGZyb20gJy4vc3Vic2NyaXB0aW9ucyc7XG5leHBvcnQgKiBmcm9tICcuL3N1cHBvcnQnO1xuZXhwb3J0ICogZnJvbSAnLi91c2Vycyc7XG5leHBvcnQgKiBmcm9tICcuL2phY2snO1xuZXhwb3J0ICogZnJvbSAnLi9hbWJhc3NhZG9ycyc7XG5leHBvcnQgKiBmcm9tICcuL2dyb3c5MCc7XG5leHBvcnQgKiBmcm9tICcuL21hdGNoaW5nJztcbmV4cG9ydCAqIGZyb20gJy4vZXZlbnQtY2hhdCc7XG5leHBvcnQgKiBmcm9tICcuL3VzZXItcGlucyc7XG4iXX0=
@@ -0,0 +1,134 @@
1
+ /**
2
+ * User Pins Query Hooks
3
+ *
4
+ * TanStack Query hooks for user pin read operations.
5
+ * These hooks handle fetching user pins for the map feature
6
+ * ("I'm here now" / "I'll be there").
7
+ *
8
+ * @module api/queries/user-pins
9
+ */
10
+ import { UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
11
+ export type PinType = 'HERE_NOW' | 'SCHEDULED';
12
+ export interface UserPinResponse {
13
+ id: string;
14
+ userId: string;
15
+ type: PinType;
16
+ latitude: number;
17
+ longitude: number;
18
+ locationName: string | null;
19
+ activity: string;
20
+ venueId: string | null;
21
+ scheduledTime: string | null;
22
+ expiresAt: string;
23
+ duration: number | null;
24
+ isActive: boolean;
25
+ createdAt: string;
26
+ user?: {
27
+ id: string;
28
+ name: string | null;
29
+ profileImage: string | null;
30
+ };
31
+ venue?: {
32
+ id: string;
33
+ name: string;
34
+ slug: string | null;
35
+ };
36
+ }
37
+ export interface NearbyPinsResponse {
38
+ pins: UserPinResponse[];
39
+ total: number;
40
+ }
41
+ /**
42
+ * Query key factory for user pin queries
43
+ */
44
+ export declare const userPinKeys: {
45
+ all: readonly ["user-pins"];
46
+ nearby: (params: NearbyPinsParams) => readonly ["user-pins", "nearby", NearbyPinsParams];
47
+ me: () => readonly ["user-pins", "me"];
48
+ };
49
+ export interface NearbyPinsParams {
50
+ lat: number;
51
+ lng: number;
52
+ radius?: number;
53
+ }
54
+ /**
55
+ * Get nearby user pins
56
+ *
57
+ * @description
58
+ * Retrieves active user pins within a radius of a location.
59
+ * Shows where other GrowSober members are or will be.
60
+ *
61
+ * @endpoint GET /api/v1/user-pins/nearby
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * import { useNearbyPins } from '@growsober/sdk';
66
+ *
67
+ * function MapWithPins() {
68
+ * const { data, isLoading } = useNearbyPins({
69
+ * lat: 38.7097,
70
+ * lng: -9.1367,
71
+ * radius: 5, // 5km radius
72
+ * });
73
+ *
74
+ * return (
75
+ * <Map>
76
+ * {data?.pins.map(pin => (
77
+ * <Marker
78
+ * key={pin.id}
79
+ * position={[pin.latitude, pin.longitude]}
80
+ * icon={pin.type === 'HERE_NOW' ? 'here' : 'scheduled'}
81
+ * >
82
+ * <Popup>
83
+ * <p>{pin.user?.name}</p>
84
+ * <p>{pin.activity}</p>
85
+ * </Popup>
86
+ * </Marker>
87
+ * ))}
88
+ * </Map>
89
+ * );
90
+ * }
91
+ * ```
92
+ *
93
+ * @param params - Location and radius parameters
94
+ * @param options - TanStack Query options
95
+ * @returns TanStack Query result with nearby pins
96
+ */
97
+ export declare function useNearbyPins(params: NearbyPinsParams, options?: Omit<UseQueryOptions<NearbyPinsResponse>, 'queryKey' | 'queryFn'>): UseQueryResult<NearbyPinsResponse>;
98
+ /**
99
+ * Get current user's active pins
100
+ *
101
+ * @description
102
+ * Retrieves the authenticated user's active pins.
103
+ * Users can have at most one active pin at a time.
104
+ *
105
+ * @endpoint GET /api/v1/user-pins/me
106
+ *
107
+ * @example
108
+ * ```tsx
109
+ * import { useMyPins } from '@growsober/sdk';
110
+ *
111
+ * function MyPinStatus() {
112
+ * const { data: pins, isLoading } = useMyPins();
113
+ *
114
+ * if (isLoading) return <Spinner />;
115
+ *
116
+ * if (!pins?.length) {
117
+ * return <Text>You haven't dropped a pin yet</Text>;
118
+ * }
119
+ *
120
+ * const pin = pins[0];
121
+ * return (
122
+ * <View>
123
+ * <Text>You're at {pin.locationName}</Text>
124
+ * <Text>Activity: {pin.activity}</Text>
125
+ * <Text>Expires: {formatTime(pin.expiresAt)}</Text>
126
+ * </View>
127
+ * );
128
+ * }
129
+ * ```
130
+ *
131
+ * @param options - TanStack Query options
132
+ * @returns TanStack Query result with user's active pins
133
+ */
134
+ export declare function useMyPins(options?: Omit<UseQueryOptions<UserPinResponse[]>, 'queryKey' | 'queryFn'>): UseQueryResult<UserPinResponse[]>;
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ /**
3
+ * User Pins Query Hooks
4
+ *
5
+ * TanStack Query hooks for user pin read operations.
6
+ * These hooks handle fetching user pins for the map feature
7
+ * ("I'm here now" / "I'll be there").
8
+ *
9
+ * @module api/queries/user-pins
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.userPinKeys = void 0;
13
+ exports.useNearbyPins = useNearbyPins;
14
+ exports.useMyPins = useMyPins;
15
+ const react_query_1 = require("@tanstack/react-query");
16
+ const client_1 = require("../client");
17
+ // ============================================================================
18
+ // QUERY KEYS
19
+ // ============================================================================
20
+ /**
21
+ * Query key factory for user pin queries
22
+ */
23
+ exports.userPinKeys = {
24
+ all: ['user-pins'],
25
+ nearby: (params) => [...exports.userPinKeys.all, 'nearby', params],
26
+ me: () => [...exports.userPinKeys.all, 'me'],
27
+ };
28
+ // ============================================================================
29
+ // QUERY HOOKS
30
+ // ============================================================================
31
+ /**
32
+ * Get nearby user pins
33
+ *
34
+ * @description
35
+ * Retrieves active user pins within a radius of a location.
36
+ * Shows where other GrowSober members are or will be.
37
+ *
38
+ * @endpoint GET /api/v1/user-pins/nearby
39
+ *
40
+ * @example
41
+ * ```tsx
42
+ * import { useNearbyPins } from '@growsober/sdk';
43
+ *
44
+ * function MapWithPins() {
45
+ * const { data, isLoading } = useNearbyPins({
46
+ * lat: 38.7097,
47
+ * lng: -9.1367,
48
+ * radius: 5, // 5km radius
49
+ * });
50
+ *
51
+ * return (
52
+ * <Map>
53
+ * {data?.pins.map(pin => (
54
+ * <Marker
55
+ * key={pin.id}
56
+ * position={[pin.latitude, pin.longitude]}
57
+ * icon={pin.type === 'HERE_NOW' ? 'here' : 'scheduled'}
58
+ * >
59
+ * <Popup>
60
+ * <p>{pin.user?.name}</p>
61
+ * <p>{pin.activity}</p>
62
+ * </Popup>
63
+ * </Marker>
64
+ * ))}
65
+ * </Map>
66
+ * );
67
+ * }
68
+ * ```
69
+ *
70
+ * @param params - Location and radius parameters
71
+ * @param options - TanStack Query options
72
+ * @returns TanStack Query result with nearby pins
73
+ */
74
+ function useNearbyPins(params, options) {
75
+ return (0, react_query_1.useQuery)({
76
+ queryKey: exports.userPinKeys.nearby(params),
77
+ queryFn: async () => {
78
+ const client = (0, client_1.getApiClient)();
79
+ const response = await client.get('/api/v1/user-pins/nearby', {
80
+ params: {
81
+ lat: params.lat,
82
+ lng: params.lng,
83
+ radius: params.radius,
84
+ },
85
+ });
86
+ return response.data;
87
+ },
88
+ enabled: params.lat !== undefined && params.lng !== undefined,
89
+ staleTime: 30 * 1000, // 30 seconds - pins change frequently
90
+ ...options,
91
+ });
92
+ }
93
+ /**
94
+ * Get current user's active pins
95
+ *
96
+ * @description
97
+ * Retrieves the authenticated user's active pins.
98
+ * Users can have at most one active pin at a time.
99
+ *
100
+ * @endpoint GET /api/v1/user-pins/me
101
+ *
102
+ * @example
103
+ * ```tsx
104
+ * import { useMyPins } from '@growsober/sdk';
105
+ *
106
+ * function MyPinStatus() {
107
+ * const { data: pins, isLoading } = useMyPins();
108
+ *
109
+ * if (isLoading) return <Spinner />;
110
+ *
111
+ * if (!pins?.length) {
112
+ * return <Text>You haven't dropped a pin yet</Text>;
113
+ * }
114
+ *
115
+ * const pin = pins[0];
116
+ * return (
117
+ * <View>
118
+ * <Text>You're at {pin.locationName}</Text>
119
+ * <Text>Activity: {pin.activity}</Text>
120
+ * <Text>Expires: {formatTime(pin.expiresAt)}</Text>
121
+ * </View>
122
+ * );
123
+ * }
124
+ * ```
125
+ *
126
+ * @param options - TanStack Query options
127
+ * @returns TanStack Query result with user's active pins
128
+ */
129
+ function useMyPins(options) {
130
+ return (0, react_query_1.useQuery)({
131
+ queryKey: exports.userPinKeys.me(),
132
+ queryFn: async () => {
133
+ const client = (0, client_1.getApiClient)();
134
+ const response = await client.get('/api/v1/user-pins/me');
135
+ return response.data;
136
+ },
137
+ staleTime: 60 * 1000, // 1 minute
138
+ ...options,
139
+ });
140
+ }
141
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlci1waW5zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2FwaS9xdWVyaWVzL3VzZXItcGlucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7O0dBUUc7OztBQWdISCxzQ0FxQkM7QUFzQ0QsOEJBYUM7QUF0TEQsdURBQWtGO0FBQ2xGLHNDQUF5QztBQXVDekMsK0VBQStFO0FBQy9FLGFBQWE7QUFDYiwrRUFBK0U7QUFFL0U7O0dBRUc7QUFDVSxRQUFBLFdBQVcsR0FBRztJQUN6QixHQUFHLEVBQUUsQ0FBQyxXQUFXLENBQVU7SUFDM0IsTUFBTSxFQUFFLENBQUMsTUFBd0IsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLG1CQUFXLENBQUMsR0FBRyxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQVU7SUFDckYsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsR0FBRyxtQkFBVyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQVU7Q0FDOUMsQ0FBQztBQVlGLCtFQUErRTtBQUMvRSxjQUFjO0FBQ2QsK0VBQStFO0FBRS9FOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EwQ0c7QUFDSCxTQUFnQixhQUFhLENBQzNCLE1BQXdCLEVBQ3hCLE9BQTJFO0lBRTNFLE9BQU8sSUFBQSxzQkFBUSxFQUFDO1FBQ2QsUUFBUSxFQUFFLG1CQUFXLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztRQUNwQyxPQUFPLEVBQUUsS0FBSyxJQUFpQyxFQUFFO1lBQy9DLE1BQU0sTUFBTSxHQUFHLElBQUEscUJBQVksR0FBRSxDQUFDO1lBQzlCLE1BQU0sUUFBUSxHQUFHLE1BQU0sTUFBTSxDQUFDLEdBQUcsQ0FBcUIsMEJBQTBCLEVBQUU7Z0JBQ2hGLE1BQU0sRUFBRTtvQkFDTixHQUFHLEVBQUUsTUFBTSxDQUFDLEdBQUc7b0JBQ2YsR0FBRyxFQUFFLE1BQU0sQ0FBQyxHQUFHO29CQUNmLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTTtpQkFDdEI7YUFDRixDQUFDLENBQUM7WUFDSCxPQUFPLFFBQVEsQ0FBQyxJQUFJLENBQUM7UUFDdkIsQ0FBQztRQUNELE9BQU8sRUFBRSxNQUFNLENBQUMsR0FBRyxLQUFLLFNBQVMsSUFBSSxNQUFNLENBQUMsR0FBRyxLQUFLLFNBQVM7UUFDN0QsU0FBUyxFQUFFLEVBQUUsR0FBRyxJQUFJLEVBQUUsc0NBQXNDO1FBQzVELEdBQUcsT0FBTztLQUNYLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FtQ0c7QUFDSCxTQUFnQixTQUFTLENBQ3ZCLE9BQTBFO0lBRTFFLE9BQU8sSUFBQSxzQkFBUSxFQUFDO1FBQ2QsUUFBUSxFQUFFLG1CQUFXLENBQUMsRUFBRSxFQUFFO1FBQzFCLE9BQU8sRUFBRSxLQUFLLElBQWdDLEVBQUU7WUFDOUMsTUFBTSxNQUFNLEdBQUcsSUFBQSxxQkFBWSxHQUFFLENBQUM7WUFDOUIsTUFBTSxRQUFRLEdBQUcsTUFBTSxNQUFNLENBQUMsR0FBRyxDQUFvQixzQkFBc0IsQ0FBQyxDQUFDO1lBQzdFLE9BQU8sUUFBUSxDQUFDLElBQUksQ0FBQztRQUN2QixDQUFDO1FBQ0QsU0FBUyxFQUFFLEVBQUUsR0FBRyxJQUFJLEVBQUUsV0FBVztRQUNqQyxHQUFHLE9BQU87S0FDWCxDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBVc2VyIFBpbnMgUXVlcnkgSG9va3NcbiAqXG4gKiBUYW5TdGFjayBRdWVyeSBob29rcyBmb3IgdXNlciBwaW4gcmVhZCBvcGVyYXRpb25zLlxuICogVGhlc2UgaG9va3MgaGFuZGxlIGZldGNoaW5nIHVzZXIgcGlucyBmb3IgdGhlIG1hcCBmZWF0dXJlXG4gKiAoXCJJJ20gaGVyZSBub3dcIiAvIFwiSSdsbCBiZSB0aGVyZVwiKS5cbiAqXG4gKiBAbW9kdWxlIGFwaS9xdWVyaWVzL3VzZXItcGluc1xuICovXG5cbmltcG9ydCB7IHVzZVF1ZXJ5LCBVc2VRdWVyeU9wdGlvbnMsIFVzZVF1ZXJ5UmVzdWx0IH0gZnJvbSAnQHRhbnN0YWNrL3JlYWN0LXF1ZXJ5JztcbmltcG9ydCB7IGdldEFwaUNsaWVudCB9IGZyb20gJy4uL2NsaWVudCc7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFRZUEVTXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCB0eXBlIFBpblR5cGUgPSAnSEVSRV9OT1cnIHwgJ1NDSEVEVUxFRCc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgVXNlclBpblJlc3BvbnNlIHtcbiAgaWQ6IHN0cmluZztcbiAgdXNlcklkOiBzdHJpbmc7XG4gIHR5cGU6IFBpblR5cGU7XG4gIGxhdGl0dWRlOiBudW1iZXI7XG4gIGxvbmdpdHVkZTogbnVtYmVyO1xuICBsb2NhdGlvbk5hbWU6IHN0cmluZyB8IG51bGw7XG4gIGFjdGl2aXR5OiBzdHJpbmc7XG4gIHZlbnVlSWQ6IHN0cmluZyB8IG51bGw7XG4gIHNjaGVkdWxlZFRpbWU6IHN0cmluZyB8IG51bGw7XG4gIGV4cGlyZXNBdDogc3RyaW5nO1xuICBkdXJhdGlvbjogbnVtYmVyIHwgbnVsbDtcbiAgaXNBY3RpdmU6IGJvb2xlYW47XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xuICB1c2VyPzoge1xuICAgIGlkOiBzdHJpbmc7XG4gICAgbmFtZTogc3RyaW5nIHwgbnVsbDtcbiAgICBwcm9maWxlSW1hZ2U6IHN0cmluZyB8IG51bGw7XG4gIH07XG4gIHZlbnVlPzoge1xuICAgIGlkOiBzdHJpbmc7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIHNsdWc6IHN0cmluZyB8IG51bGw7XG4gIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTmVhcmJ5UGluc1Jlc3BvbnNlIHtcbiAgcGluczogVXNlclBpblJlc3BvbnNlW107XG4gIHRvdGFsOiBudW1iZXI7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFFVRVJZIEtFWVNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBRdWVyeSBrZXkgZmFjdG9yeSBmb3IgdXNlciBwaW4gcXVlcmllc1xuICovXG5leHBvcnQgY29uc3QgdXNlclBpbktleXMgPSB7XG4gIGFsbDogWyd1c2VyLXBpbnMnXSBhcyBjb25zdCxcbiAgbmVhcmJ5OiAocGFyYW1zOiBOZWFyYnlQaW5zUGFyYW1zKSA9PiBbLi4udXNlclBpbktleXMuYWxsLCAnbmVhcmJ5JywgcGFyYW1zXSBhcyBjb25zdCxcbiAgbWU6ICgpID0+IFsuLi51c2VyUGluS2V5cy5hbGwsICdtZSddIGFzIGNvbnN0LFxufTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gUEFSQU0gVFlQRVNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBOZWFyYnlQaW5zUGFyYW1zIHtcbiAgbGF0OiBudW1iZXI7XG4gIGxuZzogbnVtYmVyO1xuICByYWRpdXM/OiBudW1iZXI7IC8vIGttLCBkZWZhdWx0IDVcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gUVVFUlkgSE9PS1Ncbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBHZXQgbmVhcmJ5IHVzZXIgcGluc1xuICpcbiAqIEBkZXNjcmlwdGlvblxuICogUmV0cmlldmVzIGFjdGl2ZSB1c2VyIHBpbnMgd2l0aGluIGEgcmFkaXVzIG9mIGEgbG9jYXRpb24uXG4gKiBTaG93cyB3aGVyZSBvdGhlciBHcm93U29iZXIgbWVtYmVycyBhcmUgb3Igd2lsbCBiZS5cbiAqXG4gKiBAZW5kcG9pbnQgR0VUIC9hcGkvdjEvdXNlci1waW5zL25lYXJieVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIGltcG9ydCB7IHVzZU5lYXJieVBpbnMgfSBmcm9tICdAZ3Jvd3NvYmVyL3Nkayc7XG4gKlxuICogZnVuY3Rpb24gTWFwV2l0aFBpbnMoKSB7XG4gKiAgIGNvbnN0IHsgZGF0YSwgaXNMb2FkaW5nIH0gPSB1c2VOZWFyYnlQaW5zKHtcbiAqICAgICBsYXQ6IDM4LjcwOTcsXG4gKiAgICAgbG5nOiAtOS4xMzY3LFxuICogICAgIHJhZGl1czogNSwgLy8gNWttIHJhZGl1c1xuICogICB9KTtcbiAqXG4gKiAgIHJldHVybiAoXG4gKiAgICAgPE1hcD5cbiAqICAgICAgIHtkYXRhPy5waW5zLm1hcChwaW4gPT4gKFxuICogICAgICAgICA8TWFya2VyXG4gKiAgICAgICAgICAga2V5PXtwaW4uaWR9XG4gKiAgICAgICAgICAgcG9zaXRpb249e1twaW4ubGF0aXR1ZGUsIHBpbi5sb25naXR1ZGVdfVxuICogICAgICAgICAgIGljb249e3Bpbi50eXBlID09PSAnSEVSRV9OT1cnID8gJ2hlcmUnIDogJ3NjaGVkdWxlZCd9XG4gKiAgICAgICAgID5cbiAqICAgICAgICAgICA8UG9wdXA+XG4gKiAgICAgICAgICAgICA8cD57cGluLnVzZXI/Lm5hbWV9PC9wPlxuICogICAgICAgICAgICAgPHA+e3Bpbi5hY3Rpdml0eX08L3A+XG4gKiAgICAgICAgICAgPC9Qb3B1cD5cbiAqICAgICAgICAgPC9NYXJrZXI+XG4gKiAgICAgICApKX1cbiAqICAgICA8L01hcD5cbiAqICAgKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBwYXJhbSBwYXJhbXMgLSBMb2NhdGlvbiBhbmQgcmFkaXVzIHBhcmFtZXRlcnNcbiAqIEBwYXJhbSBvcHRpb25zIC0gVGFuU3RhY2sgUXVlcnkgb3B0aW9uc1xuICogQHJldHVybnMgVGFuU3RhY2sgUXVlcnkgcmVzdWx0IHdpdGggbmVhcmJ5IHBpbnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZU5lYXJieVBpbnMoXG4gIHBhcmFtczogTmVhcmJ5UGluc1BhcmFtcyxcbiAgb3B0aW9ucz86IE9taXQ8VXNlUXVlcnlPcHRpb25zPE5lYXJieVBpbnNSZXNwb25zZT4sICdxdWVyeUtleScgfCAncXVlcnlGbic+XG4pOiBVc2VRdWVyeVJlc3VsdDxOZWFyYnlQaW5zUmVzcG9uc2U+IHtcbiAgcmV0dXJuIHVzZVF1ZXJ5KHtcbiAgICBxdWVyeUtleTogdXNlclBpbktleXMubmVhcmJ5KHBhcmFtcyksXG4gICAgcXVlcnlGbjogYXN5bmMgKCk6IFByb21pc2U8TmVhcmJ5UGluc1Jlc3BvbnNlPiA9PiB7XG4gICAgICBjb25zdCBjbGllbnQgPSBnZXRBcGlDbGllbnQoKTtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmdldDxOZWFyYnlQaW5zUmVzcG9uc2U+KCcvYXBpL3YxL3VzZXItcGlucy9uZWFyYnknLCB7XG4gICAgICAgIHBhcmFtczoge1xuICAgICAgICAgIGxhdDogcGFyYW1zLmxhdCxcbiAgICAgICAgICBsbmc6IHBhcmFtcy5sbmcsXG4gICAgICAgICAgcmFkaXVzOiBwYXJhbXMucmFkaXVzLFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gcmVzcG9uc2UuZGF0YTtcbiAgICB9LFxuICAgIGVuYWJsZWQ6IHBhcmFtcy5sYXQgIT09IHVuZGVmaW5lZCAmJiBwYXJhbXMubG5nICE9PSB1bmRlZmluZWQsXG4gICAgc3RhbGVUaW1lOiAzMCAqIDEwMDAsIC8vIDMwIHNlY29uZHMgLSBwaW5zIGNoYW5nZSBmcmVxdWVudGx5XG4gICAgLi4ub3B0aW9ucyxcbiAgfSk7XG59XG5cbi8qKlxuICogR2V0IGN1cnJlbnQgdXNlcidzIGFjdGl2ZSBwaW5zXG4gKlxuICogQGRlc2NyaXB0aW9uXG4gKiBSZXRyaWV2ZXMgdGhlIGF1dGhlbnRpY2F0ZWQgdXNlcidzIGFjdGl2ZSBwaW5zLlxuICogVXNlcnMgY2FuIGhhdmUgYXQgbW9zdCBvbmUgYWN0aXZlIHBpbiBhdCBhIHRpbWUuXG4gKlxuICogQGVuZHBvaW50IEdFVCAvYXBpL3YxL3VzZXItcGlucy9tZVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIGltcG9ydCB7IHVzZU15UGlucyB9IGZyb20gJ0Bncm93c29iZXIvc2RrJztcbiAqXG4gKiBmdW5jdGlvbiBNeVBpblN0YXR1cygpIHtcbiAqICAgY29uc3QgeyBkYXRhOiBwaW5zLCBpc0xvYWRpbmcgfSA9IHVzZU15UGlucygpO1xuICpcbiAqICAgaWYgKGlzTG9hZGluZykgcmV0dXJuIDxTcGlubmVyIC8+O1xuICpcbiAqICAgaWYgKCFwaW5zPy5sZW5ndGgpIHtcbiAqICAgICByZXR1cm4gPFRleHQ+WW91IGhhdmVuJ3QgZHJvcHBlZCBhIHBpbiB5ZXQ8L1RleHQ+O1xuICogICB9XG4gKlxuICogICBjb25zdCBwaW4gPSBwaW5zWzBdO1xuICogICByZXR1cm4gKFxuICogICAgIDxWaWV3PlxuICogICAgICAgPFRleHQ+WW91J3JlIGF0IHtwaW4ubG9jYXRpb25OYW1lfTwvVGV4dD5cbiAqICAgICAgIDxUZXh0PkFjdGl2aXR5OiB7cGluLmFjdGl2aXR5fTwvVGV4dD5cbiAqICAgICAgIDxUZXh0PkV4cGlyZXM6IHtmb3JtYXRUaW1lKHBpbi5leHBpcmVzQXQpfTwvVGV4dD5cbiAqICAgICA8L1ZpZXc+XG4gKiAgICk7XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFRhblN0YWNrIFF1ZXJ5IG9wdGlvbnNcbiAqIEByZXR1cm5zIFRhblN0YWNrIFF1ZXJ5IHJlc3VsdCB3aXRoIHVzZXIncyBhY3RpdmUgcGluc1xuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlTXlQaW5zKFxuICBvcHRpb25zPzogT21pdDxVc2VRdWVyeU9wdGlvbnM8VXNlclBpblJlc3BvbnNlW10+LCAncXVlcnlLZXknIHwgJ3F1ZXJ5Rm4nPlxuKTogVXNlUXVlcnlSZXN1bHQ8VXNlclBpblJlc3BvbnNlW10+IHtcbiAgcmV0dXJuIHVzZVF1ZXJ5KHtcbiAgICBxdWVyeUtleTogdXNlclBpbktleXMubWUoKSxcbiAgICBxdWVyeUZuOiBhc3luYyAoKTogUHJvbWlzZTxVc2VyUGluUmVzcG9uc2VbXT4gPT4ge1xuICAgICAgY29uc3QgY2xpZW50ID0gZ2V0QXBpQ2xpZW50KCk7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudC5nZXQ8VXNlclBpblJlc3BvbnNlW10+KCcvYXBpL3YxL3VzZXItcGlucy9tZScpO1xuICAgICAgcmV0dXJuIHJlc3BvbnNlLmRhdGE7XG4gICAgfSxcbiAgICBzdGFsZVRpbWU6IDYwICogMTAwMCwgLy8gMSBtaW51dGVcbiAgICAuLi5vcHRpb25zLFxuICB9KTtcbn1cbiJdfQ==
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@growsober/sdk",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Shared TypeScript SDK for GrowSober API - TanStack Query hooks, API client, and utilities",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.js",
@@ -21,3 +21,4 @@ export * from './ambassadors';
21
21
  export * from './grow90';
22
22
  export * from './matching';
23
23
  export * from './event-chat';
24
+ export * from './user-pins';
@@ -0,0 +1,186 @@
1
+ /**
2
+ * User Pins Mutation Hooks
3
+ *
4
+ * TanStack Query mutation hooks for user pin operations.
5
+ * These hooks handle creating and deleting user pins
6
+ * ("I'm here now" / "I'll be there").
7
+ *
8
+ * @module api/mutations/user-pins
9
+ */
10
+
11
+ import {
12
+ useMutation,
13
+ UseMutationOptions,
14
+ UseMutationResult,
15
+ useQueryClient,
16
+ } from '@tanstack/react-query';
17
+ import { getApiClient } from '../client';
18
+ import { userPinKeys, UserPinResponse, PinType } from '../queries/user-pins';
19
+
20
+ // ============================================================================
21
+ // REQUEST TYPES
22
+ // ============================================================================
23
+
24
+ export interface CreatePinRequest {
25
+ type: PinType;
26
+ latitude: number;
27
+ longitude: number;
28
+ locationName?: string;
29
+ activity: string;
30
+ venueId?: string;
31
+ scheduledTime?: string; // ISO date string, required for SCHEDULED type
32
+ duration?: number; // minutes, default 60 for HERE_NOW, 120 for SCHEDULED
33
+ }
34
+
35
+ // ============================================================================
36
+ // MUTATION HOOKS
37
+ // ============================================================================
38
+
39
+ /**
40
+ * Create a new user pin
41
+ *
42
+ * @description
43
+ * Creates a new pin showing where the user is or will be.
44
+ * Any existing active pin is automatically deactivated.
45
+ *
46
+ * Two types of pins:
47
+ * - HERE_NOW: User is currently at this location (default 1 hour duration)
48
+ * - SCHEDULED: User will be at this location at a specific time (default 2 hour duration)
49
+ *
50
+ * @endpoint POST /api/v1/user-pins
51
+ *
52
+ * @example
53
+ * Drop a "I'm here now" pin:
54
+ * ```tsx
55
+ * import { useCreateUserPin } from '@growsober/sdk';
56
+ *
57
+ * function DropPinButton({ location }) {
58
+ * const createPin = useCreateUserPin();
59
+ *
60
+ * const handleDropPin = () => {
61
+ * createPin.mutate({
62
+ * type: 'HERE_NOW',
63
+ * latitude: location.lat,
64
+ * longitude: location.lng,
65
+ * locationName: 'Fabrica Coffee',
66
+ * activity: 'Working remotely',
67
+ * duration: 120, // 2 hours
68
+ * });
69
+ * };
70
+ *
71
+ * return (
72
+ * <Button onPress={handleDropPin} loading={createPin.isPending}>
73
+ * Drop Pin
74
+ * </Button>
75
+ * );
76
+ * }
77
+ * ```
78
+ *
79
+ * @example
80
+ * Schedule a pin for later:
81
+ * ```tsx
82
+ * import { useCreateUserPin } from '@growsober/sdk';
83
+ *
84
+ * function SchedulePinForm() {
85
+ * const createPin = useCreateUserPin({
86
+ * onSuccess: () => {
87
+ * toast.show('Pin scheduled!');
88
+ * },
89
+ * });
90
+ *
91
+ * const handleSchedule = (data) => {
92
+ * createPin.mutate({
93
+ * type: 'SCHEDULED',
94
+ * latitude: data.venue.lat,
95
+ * longitude: data.venue.lng,
96
+ * locationName: data.venue.name,
97
+ * venueId: data.venue.id,
98
+ * activity: 'Coffee meetup',
99
+ * scheduledTime: data.time.toISOString(),
100
+ * duration: 90,
101
+ * });
102
+ * };
103
+ *
104
+ * return <ScheduleForm onSubmit={handleSchedule} />;
105
+ * }
106
+ * ```
107
+ *
108
+ * @param options - TanStack Query mutation options
109
+ * @returns TanStack Query mutation result
110
+ */
111
+ export function useCreateUserPin(
112
+ options?: Omit<
113
+ UseMutationOptions<UserPinResponse, Error, CreatePinRequest>,
114
+ 'mutationFn'
115
+ >
116
+ ): UseMutationResult<UserPinResponse, Error, CreatePinRequest> {
117
+ const queryClient = useQueryClient();
118
+
119
+ return useMutation({
120
+ mutationFn: async (data: CreatePinRequest): Promise<UserPinResponse> => {
121
+ const client = getApiClient();
122
+ const response = await client.post<UserPinResponse>('/api/v1/user-pins', data);
123
+ return response.data;
124
+ },
125
+ onSuccess: () => {
126
+ // Invalidate pin queries to reflect new pin
127
+ queryClient.invalidateQueries({ queryKey: userPinKeys.all });
128
+ },
129
+ ...options,
130
+ });
131
+ }
132
+
133
+ /**
134
+ * Delete a user pin
135
+ *
136
+ * @description
137
+ * Deactivates a user pin. Users can only delete their own pins.
138
+ *
139
+ * @endpoint DELETE /api/v1/user-pins/:id
140
+ *
141
+ * @example
142
+ * ```tsx
143
+ * import { useDeleteUserPin } from '@growsober/sdk';
144
+ *
145
+ * function MyPinCard({ pin }) {
146
+ * const deletePin = useDeleteUserPin({
147
+ * onSuccess: () => {
148
+ * toast.show('Pin removed');
149
+ * },
150
+ * });
151
+ *
152
+ * return (
153
+ * <Card>
154
+ * <Text>{pin.activity}</Text>
155
+ * <Text>At {pin.locationName}</Text>
156
+ * <Button
157
+ * onPress={() => deletePin.mutate(pin.id)}
158
+ * loading={deletePin.isPending}
159
+ * >
160
+ * Remove Pin
161
+ * </Button>
162
+ * </Card>
163
+ * );
164
+ * }
165
+ * ```
166
+ *
167
+ * @param options - TanStack Query mutation options
168
+ * @returns TanStack Query mutation result
169
+ */
170
+ export function useDeleteUserPin(
171
+ options?: Omit<UseMutationOptions<void, Error, string>, 'mutationFn'>
172
+ ): UseMutationResult<void, Error, string> {
173
+ const queryClient = useQueryClient();
174
+
175
+ return useMutation({
176
+ mutationFn: async (pinId: string): Promise<void> => {
177
+ const client = getApiClient();
178
+ await client.delete(`/api/v1/user-pins/${pinId}`);
179
+ },
180
+ onSuccess: () => {
181
+ // Invalidate pin queries to reflect deletion
182
+ queryClient.invalidateQueries({ queryKey: userPinKeys.all });
183
+ },
184
+ ...options,
185
+ });
186
+ }
@@ -23,3 +23,4 @@ export * from './ambassadors';
23
23
  export * from './grow90';
24
24
  export * from './matching';
25
25
  export * from './event-chat';
26
+ export * from './user-pins';
@@ -0,0 +1,193 @@
1
+ /**
2
+ * User Pins Query Hooks
3
+ *
4
+ * TanStack Query hooks for user pin read operations.
5
+ * These hooks handle fetching user pins for the map feature
6
+ * ("I'm here now" / "I'll be there").
7
+ *
8
+ * @module api/queries/user-pins
9
+ */
10
+
11
+ import { useQuery, UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
12
+ import { getApiClient } from '../client';
13
+
14
+ // ============================================================================
15
+ // TYPES
16
+ // ============================================================================
17
+
18
+ export type PinType = 'HERE_NOW' | 'SCHEDULED';
19
+
20
+ export interface UserPinResponse {
21
+ id: string;
22
+ userId: string;
23
+ type: PinType;
24
+ latitude: number;
25
+ longitude: number;
26
+ locationName: string | null;
27
+ activity: string;
28
+ venueId: string | null;
29
+ scheduledTime: string | null;
30
+ expiresAt: string;
31
+ duration: number | null;
32
+ isActive: boolean;
33
+ createdAt: string;
34
+ user?: {
35
+ id: string;
36
+ name: string | null;
37
+ profileImage: string | null;
38
+ };
39
+ venue?: {
40
+ id: string;
41
+ name: string;
42
+ slug: string | null;
43
+ };
44
+ }
45
+
46
+ export interface NearbyPinsResponse {
47
+ pins: UserPinResponse[];
48
+ total: number;
49
+ }
50
+
51
+ // ============================================================================
52
+ // QUERY KEYS
53
+ // ============================================================================
54
+
55
+ /**
56
+ * Query key factory for user pin queries
57
+ */
58
+ export const userPinKeys = {
59
+ all: ['user-pins'] as const,
60
+ nearby: (params: NearbyPinsParams) => [...userPinKeys.all, 'nearby', params] as const,
61
+ me: () => [...userPinKeys.all, 'me'] as const,
62
+ };
63
+
64
+ // ============================================================================
65
+ // PARAM TYPES
66
+ // ============================================================================
67
+
68
+ export interface NearbyPinsParams {
69
+ lat: number;
70
+ lng: number;
71
+ radius?: number; // km, default 5
72
+ }
73
+
74
+ // ============================================================================
75
+ // QUERY HOOKS
76
+ // ============================================================================
77
+
78
+ /**
79
+ * Get nearby user pins
80
+ *
81
+ * @description
82
+ * Retrieves active user pins within a radius of a location.
83
+ * Shows where other GrowSober members are or will be.
84
+ *
85
+ * @endpoint GET /api/v1/user-pins/nearby
86
+ *
87
+ * @example
88
+ * ```tsx
89
+ * import { useNearbyPins } from '@growsober/sdk';
90
+ *
91
+ * function MapWithPins() {
92
+ * const { data, isLoading } = useNearbyPins({
93
+ * lat: 38.7097,
94
+ * lng: -9.1367,
95
+ * radius: 5, // 5km radius
96
+ * });
97
+ *
98
+ * return (
99
+ * <Map>
100
+ * {data?.pins.map(pin => (
101
+ * <Marker
102
+ * key={pin.id}
103
+ * position={[pin.latitude, pin.longitude]}
104
+ * icon={pin.type === 'HERE_NOW' ? 'here' : 'scheduled'}
105
+ * >
106
+ * <Popup>
107
+ * <p>{pin.user?.name}</p>
108
+ * <p>{pin.activity}</p>
109
+ * </Popup>
110
+ * </Marker>
111
+ * ))}
112
+ * </Map>
113
+ * );
114
+ * }
115
+ * ```
116
+ *
117
+ * @param params - Location and radius parameters
118
+ * @param options - TanStack Query options
119
+ * @returns TanStack Query result with nearby pins
120
+ */
121
+ export function useNearbyPins(
122
+ params: NearbyPinsParams,
123
+ options?: Omit<UseQueryOptions<NearbyPinsResponse>, 'queryKey' | 'queryFn'>
124
+ ): UseQueryResult<NearbyPinsResponse> {
125
+ return useQuery({
126
+ queryKey: userPinKeys.nearby(params),
127
+ queryFn: async (): Promise<NearbyPinsResponse> => {
128
+ const client = getApiClient();
129
+ const response = await client.get<NearbyPinsResponse>('/api/v1/user-pins/nearby', {
130
+ params: {
131
+ lat: params.lat,
132
+ lng: params.lng,
133
+ radius: params.radius,
134
+ },
135
+ });
136
+ return response.data;
137
+ },
138
+ enabled: params.lat !== undefined && params.lng !== undefined,
139
+ staleTime: 30 * 1000, // 30 seconds - pins change frequently
140
+ ...options,
141
+ });
142
+ }
143
+
144
+ /**
145
+ * Get current user's active pins
146
+ *
147
+ * @description
148
+ * Retrieves the authenticated user's active pins.
149
+ * Users can have at most one active pin at a time.
150
+ *
151
+ * @endpoint GET /api/v1/user-pins/me
152
+ *
153
+ * @example
154
+ * ```tsx
155
+ * import { useMyPins } from '@growsober/sdk';
156
+ *
157
+ * function MyPinStatus() {
158
+ * const { data: pins, isLoading } = useMyPins();
159
+ *
160
+ * if (isLoading) return <Spinner />;
161
+ *
162
+ * if (!pins?.length) {
163
+ * return <Text>You haven't dropped a pin yet</Text>;
164
+ * }
165
+ *
166
+ * const pin = pins[0];
167
+ * return (
168
+ * <View>
169
+ * <Text>You're at {pin.locationName}</Text>
170
+ * <Text>Activity: {pin.activity}</Text>
171
+ * <Text>Expires: {formatTime(pin.expiresAt)}</Text>
172
+ * </View>
173
+ * );
174
+ * }
175
+ * ```
176
+ *
177
+ * @param options - TanStack Query options
178
+ * @returns TanStack Query result with user's active pins
179
+ */
180
+ export function useMyPins(
181
+ options?: Omit<UseQueryOptions<UserPinResponse[]>, 'queryKey' | 'queryFn'>
182
+ ): UseQueryResult<UserPinResponse[]> {
183
+ return useQuery({
184
+ queryKey: userPinKeys.me(),
185
+ queryFn: async (): Promise<UserPinResponse[]> => {
186
+ const client = getApiClient();
187
+ const response = await client.get<UserPinResponse[]>('/api/v1/user-pins/me');
188
+ return response.data;
189
+ },
190
+ staleTime: 60 * 1000, // 1 minute
191
+ ...options,
192
+ });
193
+ }