@adventurelabs/scout-core 1.2.5 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/helpers/cache.js +3 -1
- package/dist/helpers/pins.d.ts +2 -0
- package/dist/helpers/pins.js +58 -42
- package/dist/helpers/session_summaries.d.ts +6 -0
- package/dist/helpers/session_summaries.js +51 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.js +4 -0
- package/dist/hooks/useHerdData.d.ts +167 -0
- package/dist/hooks/useHerdData.js +153 -0
- package/dist/hooks/useInfiniteQuery.d.ts +24 -0
- package/dist/hooks/useInfiniteQuery.js +360 -0
- package/dist/hooks/useScoutRealtimeEvents.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeEvents.js +18 -23
- package/dist/hooks/useScoutRealtimeSessions.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeSessions.js +20 -12
- package/dist/hooks/useScoutRealtimeTags.d.ts +1 -1
- package/dist/hooks/useScoutRealtimeTags.js +15 -12
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/providers/ScoutRefreshProvider.d.ts +123 -6
- package/dist/store/api.d.ts +968 -0
- package/dist/store/api.js +377 -0
- package/dist/store/configureStore.d.ts +96 -0
- package/dist/store/configureStore.js +40 -0
- package/dist/store/hooks.d.ts +5 -0
- package/dist/store/hooks.js +21 -3
- package/dist/store/index.d.ts +1 -0
- package/dist/store/index.js +1 -0
- package/dist/store/scout.d.ts +13 -50
- package/dist/store/scout.js +33 -141
- package/dist/types/db.d.ts +18 -0
- package/dist/types/herd_module.d.ts +4 -16
- package/dist/types/herd_module.js +17 -23
- package/dist/types/supabase.d.ts +123 -6
- package/package.json +1 -1
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import { useState, useCallback, useMemo, useEffect } from "react";
|
|
2
|
+
import { useGetSessionsInfiniteByHerdQuery, useGetSessionsInfiniteByDeviceQuery, useGetEventsInfiniteByHerdQuery, useGetEventsInfiniteByDeviceQuery, useGetArtifactsInfiniteByHerdQuery, useGetArtifactsInfiniteByDeviceQuery, } from "../store/api";
|
|
3
|
+
// =====================================================
|
|
4
|
+
// SESSIONS INFINITE SCROLL HOOKS
|
|
5
|
+
// =====================================================
|
|
6
|
+
export const useInfiniteSessionsByHerd = (herdId, options) => {
|
|
7
|
+
const [pages, setPages] = useState([]);
|
|
8
|
+
const [currentCursor, setCurrentCursor] = useState(null);
|
|
9
|
+
const currentQuery = useGetSessionsInfiniteByHerdQuery({
|
|
10
|
+
herdId,
|
|
11
|
+
limit: options.limit || 20,
|
|
12
|
+
cursor: currentCursor,
|
|
13
|
+
supabase: options.supabase,
|
|
14
|
+
}, {
|
|
15
|
+
skip: !options.enabled,
|
|
16
|
+
});
|
|
17
|
+
// Update pages when new data arrives
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
if (currentQuery.data && !currentQuery.isLoading) {
|
|
20
|
+
setPages((prev) => {
|
|
21
|
+
const existingPage = prev.find((p) => (p.cursor === null && currentCursor === null) ||
|
|
22
|
+
(p.cursor &&
|
|
23
|
+
currentCursor &&
|
|
24
|
+
p.cursor.id === currentCursor.id &&
|
|
25
|
+
p.cursor.timestamp === currentCursor.timestamp));
|
|
26
|
+
if (!existingPage) {
|
|
27
|
+
return [
|
|
28
|
+
...prev,
|
|
29
|
+
{ cursor: currentCursor, data: currentQuery.data.sessions },
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
return prev;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}, [currentQuery.data, currentQuery.isLoading, currentCursor]);
|
|
36
|
+
const loadMore = useCallback(() => {
|
|
37
|
+
if (currentQuery.data?.hasMore &&
|
|
38
|
+
currentQuery.data.nextCursor &&
|
|
39
|
+
!currentQuery.isLoading) {
|
|
40
|
+
setCurrentCursor(currentQuery.data.nextCursor);
|
|
41
|
+
}
|
|
42
|
+
}, [currentQuery.data, currentQuery.isLoading]);
|
|
43
|
+
const refetch = useCallback(() => {
|
|
44
|
+
setPages([]);
|
|
45
|
+
setCurrentCursor(null);
|
|
46
|
+
currentQuery.refetch();
|
|
47
|
+
}, [currentQuery]);
|
|
48
|
+
// Flatten all pages into single array
|
|
49
|
+
const allItems = useMemo(() => {
|
|
50
|
+
return pages.flatMap((page) => page.data);
|
|
51
|
+
}, [pages]);
|
|
52
|
+
return {
|
|
53
|
+
items: allItems,
|
|
54
|
+
isLoading: currentQuery.isLoading && pages.length === 0,
|
|
55
|
+
isLoadingMore: currentQuery.isLoading && pages.length > 0,
|
|
56
|
+
hasMore: currentQuery.data?.hasMore || false,
|
|
57
|
+
loadMore,
|
|
58
|
+
refetch,
|
|
59
|
+
error: currentQuery.error,
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
export const useInfiniteSessionsByDevice = (deviceId, options) => {
|
|
63
|
+
const [pages, setPages] = useState([]);
|
|
64
|
+
const [currentCursor, setCurrentCursor] = useState(null);
|
|
65
|
+
const currentQuery = useGetSessionsInfiniteByDeviceQuery({
|
|
66
|
+
deviceId,
|
|
67
|
+
limit: options.limit || 20,
|
|
68
|
+
cursor: currentCursor,
|
|
69
|
+
supabase: options.supabase,
|
|
70
|
+
}, {
|
|
71
|
+
skip: !options.enabled,
|
|
72
|
+
});
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (currentQuery.data && !currentQuery.isLoading) {
|
|
75
|
+
setPages((prev) => {
|
|
76
|
+
const existingPage = prev.find((p) => (p.cursor === null && currentCursor === null) ||
|
|
77
|
+
(p.cursor &&
|
|
78
|
+
currentCursor &&
|
|
79
|
+
p.cursor.id === currentCursor.id &&
|
|
80
|
+
p.cursor.timestamp === currentCursor.timestamp));
|
|
81
|
+
if (!existingPage) {
|
|
82
|
+
return [
|
|
83
|
+
...prev,
|
|
84
|
+
{ cursor: currentCursor, data: currentQuery.data.sessions },
|
|
85
|
+
];
|
|
86
|
+
}
|
|
87
|
+
return prev;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}, [currentQuery.data, currentQuery.isLoading, currentCursor]);
|
|
91
|
+
const loadMore = useCallback(() => {
|
|
92
|
+
if (currentQuery.data?.hasMore &&
|
|
93
|
+
currentQuery.data.nextCursor &&
|
|
94
|
+
!currentQuery.isLoading) {
|
|
95
|
+
setCurrentCursor(currentQuery.data.nextCursor);
|
|
96
|
+
}
|
|
97
|
+
}, [currentQuery.data, currentQuery.isLoading]);
|
|
98
|
+
const refetch = useCallback(() => {
|
|
99
|
+
setPages([]);
|
|
100
|
+
setCurrentCursor(null);
|
|
101
|
+
currentQuery.refetch();
|
|
102
|
+
}, [currentQuery]);
|
|
103
|
+
const allItems = useMemo(() => {
|
|
104
|
+
return pages.flatMap((page) => page.data);
|
|
105
|
+
}, [pages]);
|
|
106
|
+
return {
|
|
107
|
+
items: allItems,
|
|
108
|
+
isLoading: currentQuery.isLoading && pages.length === 0,
|
|
109
|
+
isLoadingMore: currentQuery.isLoading && pages.length > 0,
|
|
110
|
+
hasMore: currentQuery.data?.hasMore || false,
|
|
111
|
+
loadMore,
|
|
112
|
+
refetch,
|
|
113
|
+
error: currentQuery.error,
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
// =====================================================
|
|
117
|
+
// EVENTS INFINITE SCROLL HOOKS
|
|
118
|
+
// =====================================================
|
|
119
|
+
export const useInfiniteEventsByHerd = (herdId, options) => {
|
|
120
|
+
const [pages, setPages] = useState([]);
|
|
121
|
+
const [currentCursor, setCurrentCursor] = useState(null);
|
|
122
|
+
const currentQuery = useGetEventsInfiniteByHerdQuery({
|
|
123
|
+
herdId,
|
|
124
|
+
limit: options.limit || 20,
|
|
125
|
+
cursor: currentCursor,
|
|
126
|
+
supabase: options.supabase,
|
|
127
|
+
}, {
|
|
128
|
+
skip: !options.enabled,
|
|
129
|
+
});
|
|
130
|
+
useEffect(() => {
|
|
131
|
+
if (currentQuery.data && !currentQuery.isLoading) {
|
|
132
|
+
setPages((prev) => {
|
|
133
|
+
const existingPage = prev.find((p) => (p.cursor === null && currentCursor === null) ||
|
|
134
|
+
(p.cursor &&
|
|
135
|
+
currentCursor &&
|
|
136
|
+
p.cursor.id === currentCursor.id &&
|
|
137
|
+
p.cursor.timestamp === currentCursor.timestamp));
|
|
138
|
+
if (!existingPage) {
|
|
139
|
+
return [
|
|
140
|
+
...prev,
|
|
141
|
+
{ cursor: currentCursor, data: currentQuery.data.events },
|
|
142
|
+
];
|
|
143
|
+
}
|
|
144
|
+
return prev;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}, [currentQuery.data, currentQuery.isLoading, currentCursor]);
|
|
148
|
+
const loadMore = useCallback(() => {
|
|
149
|
+
if (currentQuery.data?.hasMore &&
|
|
150
|
+
currentQuery.data.nextCursor &&
|
|
151
|
+
!currentQuery.isLoading) {
|
|
152
|
+
setCurrentCursor(currentQuery.data.nextCursor);
|
|
153
|
+
}
|
|
154
|
+
}, [currentQuery.data, currentQuery.isLoading]);
|
|
155
|
+
const refetch = useCallback(() => {
|
|
156
|
+
setPages([]);
|
|
157
|
+
setCurrentCursor(null);
|
|
158
|
+
currentQuery.refetch();
|
|
159
|
+
}, [currentQuery]);
|
|
160
|
+
const allItems = useMemo(() => {
|
|
161
|
+
return pages.flatMap((page) => page.data);
|
|
162
|
+
}, [pages]);
|
|
163
|
+
return {
|
|
164
|
+
items: allItems,
|
|
165
|
+
isLoading: currentQuery.isLoading && pages.length === 0,
|
|
166
|
+
isLoadingMore: currentQuery.isLoading && pages.length > 0,
|
|
167
|
+
hasMore: currentQuery.data?.hasMore || false,
|
|
168
|
+
loadMore,
|
|
169
|
+
refetch,
|
|
170
|
+
error: currentQuery.error,
|
|
171
|
+
};
|
|
172
|
+
};
|
|
173
|
+
export const useInfiniteEventsByDevice = (deviceId, options) => {
|
|
174
|
+
const [pages, setPages] = useState([]);
|
|
175
|
+
const [currentCursor, setCurrentCursor] = useState(null);
|
|
176
|
+
const currentQuery = useGetEventsInfiniteByDeviceQuery({
|
|
177
|
+
deviceId,
|
|
178
|
+
limit: options.limit || 20,
|
|
179
|
+
cursor: currentCursor,
|
|
180
|
+
supabase: options.supabase,
|
|
181
|
+
}, {
|
|
182
|
+
skip: !options.enabled,
|
|
183
|
+
});
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
if (currentQuery.data && !currentQuery.isLoading) {
|
|
186
|
+
setPages((prev) => {
|
|
187
|
+
const existingPage = prev.find((p) => (p.cursor === null && currentCursor === null) ||
|
|
188
|
+
(p.cursor &&
|
|
189
|
+
currentCursor &&
|
|
190
|
+
p.cursor.id === currentCursor.id &&
|
|
191
|
+
p.cursor.timestamp === currentCursor.timestamp));
|
|
192
|
+
if (!existingPage) {
|
|
193
|
+
return [
|
|
194
|
+
...prev,
|
|
195
|
+
{ cursor: currentCursor, data: currentQuery.data.events },
|
|
196
|
+
];
|
|
197
|
+
}
|
|
198
|
+
return prev;
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}, [currentQuery.data, currentQuery.isLoading, currentCursor]);
|
|
202
|
+
const loadMore = useCallback(() => {
|
|
203
|
+
if (currentQuery.data?.hasMore &&
|
|
204
|
+
currentQuery.data.nextCursor &&
|
|
205
|
+
!currentQuery.isLoading) {
|
|
206
|
+
setCurrentCursor(currentQuery.data.nextCursor);
|
|
207
|
+
}
|
|
208
|
+
}, [currentQuery.data, currentQuery.isLoading]);
|
|
209
|
+
const refetch = useCallback(() => {
|
|
210
|
+
setPages([]);
|
|
211
|
+
setCurrentCursor(null);
|
|
212
|
+
currentQuery.refetch();
|
|
213
|
+
}, [currentQuery]);
|
|
214
|
+
const allItems = useMemo(() => {
|
|
215
|
+
return pages.flatMap((page) => page.data);
|
|
216
|
+
}, [pages]);
|
|
217
|
+
return {
|
|
218
|
+
items: allItems,
|
|
219
|
+
isLoading: currentQuery.isLoading && pages.length === 0,
|
|
220
|
+
isLoadingMore: currentQuery.isLoading && pages.length > 0,
|
|
221
|
+
hasMore: currentQuery.data?.hasMore || false,
|
|
222
|
+
loadMore,
|
|
223
|
+
refetch,
|
|
224
|
+
error: currentQuery.error,
|
|
225
|
+
};
|
|
226
|
+
};
|
|
227
|
+
// =====================================================
|
|
228
|
+
// ARTIFACTS INFINITE SCROLL HOOKS
|
|
229
|
+
// =====================================================
|
|
230
|
+
export const useInfiniteArtifactsByHerd = (herdId, options) => {
|
|
231
|
+
const [pages, setPages] = useState([]);
|
|
232
|
+
const [currentCursor, setCurrentCursor] = useState(null);
|
|
233
|
+
const currentQuery = useGetArtifactsInfiniteByHerdQuery({
|
|
234
|
+
herdId,
|
|
235
|
+
limit: options.limit || 20,
|
|
236
|
+
cursor: currentCursor,
|
|
237
|
+
supabase: options.supabase,
|
|
238
|
+
}, {
|
|
239
|
+
skip: !options.enabled,
|
|
240
|
+
});
|
|
241
|
+
useEffect(() => {
|
|
242
|
+
if (currentQuery.data && !currentQuery.isLoading) {
|
|
243
|
+
setPages((prev) => {
|
|
244
|
+
const existingPage = prev.find((p) => (p.cursor === null && currentCursor === null) ||
|
|
245
|
+
(p.cursor &&
|
|
246
|
+
currentCursor &&
|
|
247
|
+
p.cursor.id === currentCursor.id &&
|
|
248
|
+
p.cursor.timestamp === currentCursor.timestamp));
|
|
249
|
+
if (!existingPage) {
|
|
250
|
+
return [
|
|
251
|
+
...prev,
|
|
252
|
+
{ cursor: currentCursor, data: currentQuery.data.artifacts },
|
|
253
|
+
];
|
|
254
|
+
}
|
|
255
|
+
return prev;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}, [currentQuery.data, currentQuery.isLoading, currentCursor]);
|
|
259
|
+
const loadMore = useCallback(() => {
|
|
260
|
+
if (currentQuery.data?.hasMore &&
|
|
261
|
+
currentQuery.data.nextCursor &&
|
|
262
|
+
!currentQuery.isLoading) {
|
|
263
|
+
setCurrentCursor(currentQuery.data.nextCursor);
|
|
264
|
+
}
|
|
265
|
+
}, [currentQuery.data, currentQuery.isLoading]);
|
|
266
|
+
const refetch = useCallback(() => {
|
|
267
|
+
setPages([]);
|
|
268
|
+
setCurrentCursor(null);
|
|
269
|
+
currentQuery.refetch();
|
|
270
|
+
}, [currentQuery]);
|
|
271
|
+
const allItems = useMemo(() => {
|
|
272
|
+
return pages.flatMap((page) => page.data);
|
|
273
|
+
}, [pages]);
|
|
274
|
+
return {
|
|
275
|
+
items: allItems,
|
|
276
|
+
isLoading: currentQuery.isLoading && pages.length === 0,
|
|
277
|
+
isLoadingMore: currentQuery.isLoading && pages.length > 0,
|
|
278
|
+
hasMore: currentQuery.data?.hasMore || false,
|
|
279
|
+
loadMore,
|
|
280
|
+
refetch,
|
|
281
|
+
error: currentQuery.error,
|
|
282
|
+
};
|
|
283
|
+
};
|
|
284
|
+
export const useInfiniteArtifactsByDevice = (deviceId, options) => {
|
|
285
|
+
const [pages, setPages] = useState([]);
|
|
286
|
+
const [currentCursor, setCurrentCursor] = useState(null);
|
|
287
|
+
const currentQuery = useGetArtifactsInfiniteByDeviceQuery({
|
|
288
|
+
deviceId,
|
|
289
|
+
limit: options.limit || 20,
|
|
290
|
+
cursor: currentCursor,
|
|
291
|
+
supabase: options.supabase,
|
|
292
|
+
}, {
|
|
293
|
+
skip: !options.enabled,
|
|
294
|
+
});
|
|
295
|
+
useEffect(() => {
|
|
296
|
+
if (currentQuery.data && !currentQuery.isLoading) {
|
|
297
|
+
setPages((prev) => {
|
|
298
|
+
const existingPage = prev.find((p) => (p.cursor === null && currentCursor === null) ||
|
|
299
|
+
(p.cursor &&
|
|
300
|
+
currentCursor &&
|
|
301
|
+
p.cursor.id === currentCursor.id &&
|
|
302
|
+
p.cursor.timestamp === currentCursor.timestamp));
|
|
303
|
+
if (!existingPage) {
|
|
304
|
+
return [
|
|
305
|
+
...prev,
|
|
306
|
+
{ cursor: currentCursor, data: currentQuery.data.artifacts },
|
|
307
|
+
];
|
|
308
|
+
}
|
|
309
|
+
return prev;
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}, [currentQuery.data, currentQuery.isLoading, currentCursor]);
|
|
313
|
+
const loadMore = useCallback(() => {
|
|
314
|
+
if (currentQuery.data?.hasMore &&
|
|
315
|
+
currentQuery.data.nextCursor &&
|
|
316
|
+
!currentQuery.isLoading) {
|
|
317
|
+
setCurrentCursor(currentQuery.data.nextCursor);
|
|
318
|
+
}
|
|
319
|
+
}, [currentQuery.data, currentQuery.isLoading]);
|
|
320
|
+
const refetch = useCallback(() => {
|
|
321
|
+
setPages([]);
|
|
322
|
+
setCurrentCursor(null);
|
|
323
|
+
currentQuery.refetch();
|
|
324
|
+
}, [currentQuery]);
|
|
325
|
+
const allItems = useMemo(() => {
|
|
326
|
+
return pages.flatMap((page) => page.data);
|
|
327
|
+
}, [pages]);
|
|
328
|
+
return {
|
|
329
|
+
items: allItems,
|
|
330
|
+
isLoading: currentQuery.isLoading && pages.length === 0,
|
|
331
|
+
isLoadingMore: currentQuery.isLoading && pages.length > 0,
|
|
332
|
+
hasMore: currentQuery.data?.hasMore || false,
|
|
333
|
+
loadMore,
|
|
334
|
+
refetch,
|
|
335
|
+
error: currentQuery.error,
|
|
336
|
+
};
|
|
337
|
+
};
|
|
338
|
+
// =====================================================
|
|
339
|
+
// INTERSECTION OBSERVER HOOK FOR AUTO-LOADING
|
|
340
|
+
// =====================================================
|
|
341
|
+
export const useIntersectionObserver = (callback, options = {}) => {
|
|
342
|
+
const [element, setElement] = useState(null);
|
|
343
|
+
useEffect(() => {
|
|
344
|
+
if (!element)
|
|
345
|
+
return;
|
|
346
|
+
const observer = new IntersectionObserver((entries) => {
|
|
347
|
+
const first = entries[0];
|
|
348
|
+
if (first.isIntersecting) {
|
|
349
|
+
callback();
|
|
350
|
+
}
|
|
351
|
+
}, { threshold: 0.1, ...options });
|
|
352
|
+
observer.observe(element);
|
|
353
|
+
return () => {
|
|
354
|
+
if (element) {
|
|
355
|
+
observer.unobserve(element);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
}, [element, callback, options]);
|
|
359
|
+
return setElement;
|
|
360
|
+
};
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { IEventAndTagsPrettyLocation } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimeEvents(scoutSupabase: SupabaseClient<Database>,
|
|
5
|
+
export declare function useScoutRealtimeEvents(scoutSupabase: SupabaseClient<Database>, invalidateRTKQuery?: boolean): [RealtimeData<IEventAndTagsPrettyLocation> | null, () => void];
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { useAppDispatch } from "../store/hooks";
|
|
3
3
|
import { useSelector } from "react-redux";
|
|
4
4
|
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
|
-
import { updateEventValuesForHerdModule } from "../store/scout";
|
|
6
5
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
7
|
-
|
|
6
|
+
import { scoutApi } from "../store/api";
|
|
7
|
+
export function useScoutRealtimeEvents(scoutSupabase, invalidateRTKQuery = true) {
|
|
8
8
|
const channels = useRef([]);
|
|
9
9
|
const dispatch = useAppDispatch();
|
|
10
10
|
const [latestEventUpdate, setLatestEventUpdate] = useState(null);
|
|
@@ -17,37 +17,32 @@ export function useScoutRealtimeEvents(scoutSupabase, shouldUpdateGlobalStateOnC
|
|
|
17
17
|
if (!eventData)
|
|
18
18
|
return;
|
|
19
19
|
let operation;
|
|
20
|
-
// TODO: UNCOMMENT GLOBAL STORE OPERATIONS IF OKAY WITH FREQUENT
|
|
21
20
|
switch (data.operation) {
|
|
22
21
|
case "INSERT":
|
|
23
22
|
operation = EnumRealtimeOperation.INSERT;
|
|
24
|
-
if (data.record &&
|
|
25
|
-
console.log("[Events] New event received:", data.record);
|
|
26
|
-
//
|
|
27
|
-
dispatch(
|
|
28
|
-
herd_id: activeHerdId,
|
|
29
|
-
events: [data.record],
|
|
30
|
-
}));
|
|
23
|
+
if (data.record && invalidateRTKQuery) {
|
|
24
|
+
console.log("[Events] New event received, invalidating RTK Query cache:", data.record);
|
|
25
|
+
// Invalidate all events queries to refetch fresh data
|
|
26
|
+
dispatch(scoutApi.util.invalidateTags(["Event"]));
|
|
31
27
|
}
|
|
32
28
|
break;
|
|
33
29
|
case "UPDATE":
|
|
34
30
|
operation = EnumRealtimeOperation.UPDATE;
|
|
35
|
-
if (data.record &&
|
|
36
|
-
console.log("[Events] Event updated:", data.record);
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
if (data.record && invalidateRTKQuery) {
|
|
32
|
+
console.log("[Events] Event updated, invalidating RTK Query cache:", data.record);
|
|
33
|
+
// Invalidate specific event and list queries
|
|
34
|
+
dispatch(scoutApi.util.invalidateTags([
|
|
35
|
+
{ type: "Event", id: data.record.id || "unknown" },
|
|
36
|
+
{ type: "Event", id: "LIST" },
|
|
37
|
+
]));
|
|
41
38
|
}
|
|
42
39
|
break;
|
|
43
40
|
case "DELETE":
|
|
44
41
|
operation = EnumRealtimeOperation.DELETE;
|
|
45
|
-
if (data.old_record &&
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
// TODO: WRITE DELETION STORE ACTION
|
|
50
|
-
console.log("[Events] Event deletion detected - manual refresh may be needed");
|
|
42
|
+
if (data.old_record && invalidateRTKQuery) {
|
|
43
|
+
console.log("[Events] Event deleted, invalidating RTK Query cache:", data.old_record);
|
|
44
|
+
// Invalidate all events queries since item was deleted
|
|
45
|
+
dispatch(scoutApi.util.invalidateTags(["Event"]));
|
|
51
46
|
}
|
|
52
47
|
break;
|
|
53
48
|
default:
|
|
@@ -59,7 +54,7 @@ export function useScoutRealtimeEvents(scoutSupabase, shouldUpdateGlobalStateOnC
|
|
|
59
54
|
};
|
|
60
55
|
console.log(`[scout-core realtime] EVENT ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
61
56
|
setLatestEventUpdate(realtimeData);
|
|
62
|
-
}, [dispatch,
|
|
57
|
+
}, [dispatch, invalidateRTKQuery]);
|
|
63
58
|
// Clear latest update
|
|
64
59
|
const clearLatestUpdate = useCallback(() => {
|
|
65
60
|
setLatestEventUpdate(null);
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { ISessionWithCoordinates } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimeSessions(scoutSupabase: SupabaseClient<Database>,
|
|
5
|
+
export declare function useScoutRealtimeSessions(scoutSupabase: SupabaseClient<Database>, invalidateRTKQuery?: boolean): [RealtimeData<ISessionWithCoordinates> | null, () => void];
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { useAppDispatch } from "../store/hooks";
|
|
3
2
|
import { useSelector } from "react-redux";
|
|
3
|
+
import { useAppDispatch } from "../store/hooks";
|
|
4
4
|
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
|
-
import { addSessionToStore, deleteSessionFromStore, updateSessionInStore, } from "../store/scout";
|
|
6
5
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
7
|
-
|
|
6
|
+
import { scoutApi } from "../store/api";
|
|
7
|
+
export function useScoutRealtimeSessions(scoutSupabase, invalidateRTKQuery = true) {
|
|
8
8
|
const channels = useRef([]);
|
|
9
9
|
const dispatch = useAppDispatch();
|
|
10
10
|
const [latestSessionUpdate, setLatestSessionUpdate] = useState(null);
|
|
@@ -20,21 +20,29 @@ export function useScoutRealtimeSessions(scoutSupabase, shouldUpdateGlobalStateO
|
|
|
20
20
|
switch (data.operation) {
|
|
21
21
|
case "INSERT":
|
|
22
22
|
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
-
if (data.record &&
|
|
24
|
-
console.log("[Sessions] New session received:", data.record);
|
|
25
|
-
|
|
23
|
+
if (data.record && invalidateRTKQuery) {
|
|
24
|
+
console.log("[Sessions] New session received, invalidating RTK Query cache:", data.record);
|
|
25
|
+
// Invalidate all sessions queries to refetch fresh data
|
|
26
|
+
dispatch(scoutApi.util.invalidateTags(["Session"]));
|
|
26
27
|
}
|
|
27
28
|
break;
|
|
28
29
|
case "UPDATE":
|
|
29
30
|
operation = EnumRealtimeOperation.UPDATE;
|
|
30
|
-
if (data.record &&
|
|
31
|
-
|
|
31
|
+
if (data.record && invalidateRTKQuery) {
|
|
32
|
+
console.log("[Sessions] Session updated, invalidating RTK Query cache:", data.record);
|
|
33
|
+
// Invalidate specific session and list queries
|
|
34
|
+
dispatch(scoutApi.util.invalidateTags([
|
|
35
|
+
{ type: "Session", id: data.record.id || "unknown" },
|
|
36
|
+
{ type: "Session", id: "LIST" },
|
|
37
|
+
]));
|
|
32
38
|
}
|
|
33
39
|
break;
|
|
34
40
|
case "DELETE":
|
|
35
41
|
operation = EnumRealtimeOperation.DELETE;
|
|
36
|
-
if (data.old_record &&
|
|
37
|
-
|
|
42
|
+
if (data.old_record && invalidateRTKQuery) {
|
|
43
|
+
console.log("[Sessions] Session deleted, invalidating RTK Query cache:", data.old_record);
|
|
44
|
+
// Invalidate all sessions queries since item was deleted
|
|
45
|
+
dispatch(scoutApi.util.invalidateTags(["Session"]));
|
|
38
46
|
}
|
|
39
47
|
break;
|
|
40
48
|
default:
|
|
@@ -46,7 +54,7 @@ export function useScoutRealtimeSessions(scoutSupabase, shouldUpdateGlobalStateO
|
|
|
46
54
|
};
|
|
47
55
|
console.log(`[scout-core realtime] SESSION ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
48
56
|
setLatestSessionUpdate(realtimeData);
|
|
49
|
-
}, [dispatch]);
|
|
57
|
+
}, [invalidateRTKQuery, dispatch]);
|
|
50
58
|
// Clear latest update
|
|
51
59
|
const clearLatestUpdate = useCallback(() => {
|
|
52
60
|
setLatestSessionUpdate(null);
|
|
@@ -78,6 +86,6 @@ export function useScoutRealtimeSessions(scoutSupabase, shouldUpdateGlobalStateO
|
|
|
78
86
|
channels.current.push(channel);
|
|
79
87
|
}
|
|
80
88
|
return cleanupChannels;
|
|
81
|
-
}, [activeHerdId, clearLatestUpdate]);
|
|
89
|
+
}, [activeHerdId, clearLatestUpdate, handleSessionBroadcast]);
|
|
82
90
|
return [latestSessionUpdate, clearLatestUpdate];
|
|
83
91
|
}
|
|
@@ -2,4 +2,4 @@ import { SupabaseClient } from "@supabase/supabase-js";
|
|
|
2
2
|
import { Database } from "../types/supabase";
|
|
3
3
|
import { ITagPrettyLocation } from "../types/db";
|
|
4
4
|
import { RealtimeData } from "../types/realtime";
|
|
5
|
-
export declare function useScoutRealtimeTags(scoutSupabase: SupabaseClient<Database>,
|
|
5
|
+
export declare function useScoutRealtimeTags(scoutSupabase: SupabaseClient<Database>, invalidateRTKQuery?: boolean): [RealtimeData<ITagPrettyLocation> | null, () => void];
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
import { useAppDispatch } from "../store/hooks";
|
|
3
3
|
import { useSelector } from "react-redux";
|
|
4
4
|
import { useEffect, useRef, useCallback, useState } from "react";
|
|
5
|
-
import { addTag, deleteTag, updateTag } from "../store/scout";
|
|
6
5
|
import { EnumRealtimeOperation } from "../types/realtime";
|
|
7
|
-
|
|
6
|
+
import { scoutApi } from "../store/api";
|
|
7
|
+
export function useScoutRealtimeTags(scoutSupabase, invalidateRTKQuery = true) {
|
|
8
8
|
const channels = useRef([]);
|
|
9
9
|
const dispatch = useAppDispatch();
|
|
10
10
|
const [latestTagUpdate, setLatestTagUpdate] = useState(null);
|
|
@@ -20,23 +20,26 @@ export function useScoutRealtimeTags(scoutSupabase, shouldUpdateGlobalStateOnCha
|
|
|
20
20
|
switch (data.operation) {
|
|
21
21
|
case "INSERT":
|
|
22
22
|
operation = EnumRealtimeOperation.INSERT;
|
|
23
|
-
if (data.record &&
|
|
24
|
-
console.log("[Tags] New tag received:", data.record);
|
|
25
|
-
|
|
23
|
+
if (data.record && invalidateRTKQuery) {
|
|
24
|
+
console.log("[Tags] New tag received, invalidating RTK Query cache:", data.record);
|
|
25
|
+
// Tags are part of events, so invalidate events queries
|
|
26
|
+
dispatch(scoutApi.util.invalidateTags(["Event"]));
|
|
26
27
|
}
|
|
27
28
|
break;
|
|
28
29
|
case "UPDATE":
|
|
29
30
|
operation = EnumRealtimeOperation.UPDATE;
|
|
30
|
-
if (data.record &&
|
|
31
|
-
console.log("[Tags] Tag updated:", data.record);
|
|
32
|
-
|
|
31
|
+
if (data.record && invalidateRTKQuery) {
|
|
32
|
+
console.log("[Tags] Tag updated, invalidating RTK Query cache:", data.record);
|
|
33
|
+
// Invalidate events queries since tags are embedded in events
|
|
34
|
+
dispatch(scoutApi.util.invalidateTags(["Event"]));
|
|
33
35
|
}
|
|
34
36
|
break;
|
|
35
37
|
case "DELETE":
|
|
36
38
|
operation = EnumRealtimeOperation.DELETE;
|
|
37
|
-
if (data.old_record &&
|
|
38
|
-
console.log("[Tags] Tag deleted:", data.old_record);
|
|
39
|
-
|
|
39
|
+
if (data.old_record && invalidateRTKQuery) {
|
|
40
|
+
console.log("[Tags] Tag deleted, invalidating RTK Query cache:", data.old_record);
|
|
41
|
+
// Invalidate events queries since tags are embedded in events
|
|
42
|
+
dispatch(scoutApi.util.invalidateTags(["Event"]));
|
|
40
43
|
}
|
|
41
44
|
break;
|
|
42
45
|
default:
|
|
@@ -48,7 +51,7 @@ export function useScoutRealtimeTags(scoutSupabase, shouldUpdateGlobalStateOnCha
|
|
|
48
51
|
};
|
|
49
52
|
console.log(`[scout-core realtime] TAG ${data.operation} received:`, JSON.stringify(realtimeData));
|
|
50
53
|
setLatestTagUpdate(realtimeData);
|
|
51
|
-
}, [dispatch]);
|
|
54
|
+
}, [dispatch, invalidateRTKQuery]);
|
|
52
55
|
// Clear latest update
|
|
53
56
|
const clearLatestUpdate = useCallback(() => {
|
|
54
57
|
setLatestTagUpdate(null);
|
package/dist/index.d.ts
CHANGED
|
@@ -48,6 +48,7 @@ export * from "./hooks/useScoutRealtimeSessions";
|
|
|
48
48
|
export * from "./hooks/useScoutRealtimePlans";
|
|
49
49
|
export * from "./hooks/useScoutRealtimePins";
|
|
50
50
|
export * from "./hooks/useScoutRefresh";
|
|
51
|
+
export * from "./hooks/useInfiniteQuery";
|
|
51
52
|
export * from "./providers";
|
|
52
53
|
export * from "./store/scout";
|
|
53
54
|
export * from "./store/hooks";
|
package/dist/index.js
CHANGED
|
@@ -52,6 +52,7 @@ export * from "./hooks/useScoutRealtimeSessions";
|
|
|
52
52
|
export * from "./hooks/useScoutRealtimePlans";
|
|
53
53
|
export * from "./hooks/useScoutRealtimePins";
|
|
54
54
|
export * from "./hooks/useScoutRefresh";
|
|
55
|
+
export * from "./hooks/useInfiniteQuery";
|
|
55
56
|
// Providers
|
|
56
57
|
export * from "./providers";
|
|
57
58
|
// Store
|