@adventurelabs/scout-core 1.4.31 → 1.4.32
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.
|
@@ -20,6 +20,7 @@ export declare const useInfiniteEventsByHerd: (herdId: number, options: UseInfin
|
|
|
20
20
|
export declare const useInfiniteEventsByDevice: (deviceId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IEventAndTagsPrettyLocation>;
|
|
21
21
|
export declare const useInfiniteArtifactsByHerd: (herdId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IArtifactWithMediaUrl>;
|
|
22
22
|
export declare const useInfiniteArtifactsByDevice: (deviceId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IArtifactWithMediaUrl>;
|
|
23
|
+
/** useInfiniteFeedByHerd: logic matches useInfiniteFeedByHerdDummy verbatim; only the fetch is via API (RTK Query) instead of supabase.rpc. */
|
|
23
24
|
export declare const useInfiniteFeedByHerd: (herdId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IFeedItem>;
|
|
24
25
|
export declare const useInfiniteFeedByDevice: (deviceId: number, options: UseInfiniteScrollOptions) => InfiniteScrollData<IFeedItem>;
|
|
25
26
|
export declare const useIntersectionObserver: (callback: () => void, options?: IntersectionObserverInit) => import("react").Dispatch<import("react").SetStateAction<Element | null>>;
|
|
@@ -408,96 +408,131 @@ export const useInfiniteArtifactsByDevice = (deviceId, options) => {
|
|
|
408
408
|
};
|
|
409
409
|
};
|
|
410
410
|
const feedCursorEq = (a, b) => {
|
|
411
|
-
if (a ===
|
|
411
|
+
if (a === b)
|
|
412
412
|
return true;
|
|
413
|
-
if (
|
|
413
|
+
if (a == null || b == null)
|
|
414
414
|
return false;
|
|
415
|
-
return a.timestamp === b.timestamp &&
|
|
415
|
+
return (a.timestamp === b.timestamp &&
|
|
416
|
+
a.id === b.id &&
|
|
417
|
+
a.feed_type === b.feed_type);
|
|
416
418
|
};
|
|
419
|
+
/** useInfiniteFeedByHerd: logic matches useInfiniteFeedByHerdDummy verbatim; only the fetch is via API (RTK Query) instead of supabase.rpc. */
|
|
417
420
|
export const useInfiniteFeedByHerd = (herdId, options) => {
|
|
421
|
+
const limit = options.limit ?? 20;
|
|
422
|
+
const enabled = !!(options.enabled && herdId);
|
|
418
423
|
const [pages, setPages] = useState([]);
|
|
419
424
|
const [currentCursor, setCurrentCursor] = useState(null);
|
|
420
|
-
|
|
421
|
-
const [lastResult, setLastResult] = useState(null);
|
|
425
|
+
const [currentResult, setCurrentResult] = useState(null);
|
|
422
426
|
const prevHerdIdRef = useRef(undefined);
|
|
423
427
|
const lastAddedCursorRef = useRef(undefined);
|
|
424
428
|
const pagesLengthRef = useRef(0);
|
|
425
429
|
const currentQuery = useGetFeedInfiniteByHerdQuery({
|
|
426
430
|
herdId,
|
|
427
|
-
limit
|
|
431
|
+
limit,
|
|
428
432
|
cursor: currentCursor,
|
|
429
433
|
supabase: options.supabase,
|
|
430
|
-
}, { skip: !
|
|
434
|
+
}, { skip: !enabled });
|
|
435
|
+
const isLoading = currentQuery.isLoading;
|
|
431
436
|
useEffect(() => {
|
|
432
437
|
pagesLengthRef.current = pages.length;
|
|
433
438
|
}, [pages.length]);
|
|
434
|
-
//
|
|
439
|
+
// Reset when herd changes (match dummy: prev !== herdId && enabled && herdId)
|
|
435
440
|
useEffect(() => {
|
|
436
441
|
if (prevHerdIdRef.current !== undefined &&
|
|
437
|
-
prevHerdIdRef.current !== herdId
|
|
442
|
+
prevHerdIdRef.current !== herdId &&
|
|
443
|
+
enabled &&
|
|
444
|
+
herdId) {
|
|
438
445
|
setPages([]);
|
|
439
446
|
setCurrentCursor(null);
|
|
447
|
+
setCurrentResult(null);
|
|
440
448
|
lastAddedCursorRef.current = undefined;
|
|
441
|
-
setLastResult(null);
|
|
442
449
|
}
|
|
443
450
|
prevHerdIdRef.current = herdId;
|
|
444
|
-
}, [herdId]);
|
|
445
|
-
// When
|
|
451
|
+
}, [herdId, enabled]);
|
|
452
|
+
// When cursor changes, clear ref so we merge the new response
|
|
446
453
|
useEffect(() => {
|
|
447
454
|
lastAddedCursorRef.current = undefined;
|
|
448
455
|
}, [currentCursor]);
|
|
456
|
+
// Merge when we have data (mirror dummy's .then() logic; fetch is done by RTK Query)
|
|
449
457
|
useEffect(() => {
|
|
450
458
|
if (!currentQuery.data || currentQuery.isLoading)
|
|
451
459
|
return;
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
feedCursorEq(lastAddedCursorRef.current ?? null, currentCursor))
|
|
455
|
-
return;
|
|
456
|
-
const items = Array.isArray(currentQuery.data?.items)
|
|
460
|
+
const cursor = currentCursor;
|
|
461
|
+
const items = Array.isArray(currentQuery.data.items)
|
|
457
462
|
? currentQuery.data.items
|
|
458
463
|
: [];
|
|
459
|
-
const
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
464
|
+
const hasMore = currentQuery.data.hasMore ?? false;
|
|
465
|
+
const nextCursor = currentQuery.data.nextCursor ?? null;
|
|
466
|
+
// Only update currentResult for successful response (match dummy)
|
|
467
|
+
if (items.length === 0 && cursor === null) {
|
|
468
|
+
// Leave currentResult unchanged on spurious empty first page
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
setCurrentResult({
|
|
472
|
+
hasMore: hasMore && nextCursor != null,
|
|
473
|
+
nextCursor,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
if (items.length === 0)
|
|
477
|
+
return;
|
|
478
|
+
// Skip merge exactly like dummy: full page already added for this cursor and we have pages
|
|
479
|
+
if (items.length >= limit &&
|
|
480
|
+
feedCursorEq(lastAddedCursorRef.current ?? null, cursor) &&
|
|
481
|
+
pagesLengthRef.current > 0) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
465
484
|
setPages((prev) => {
|
|
466
|
-
const existingPage = prev.find((p) => feedCursorEq(p.cursor,
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
];
|
|
485
|
+
const existingPage = prev.find((p) => feedCursorEq(p.cursor, cursor));
|
|
486
|
+
const next = !existingPage
|
|
487
|
+
? [...prev, { cursor, data: items }]
|
|
488
|
+
: items.length > existingPage.data.length
|
|
489
|
+
? prev.map((p) => feedCursorEq(p.cursor, cursor) ? { cursor, data: items } : p)
|
|
490
|
+
: prev;
|
|
491
|
+
if (!existingPage && items.length >= limit) {
|
|
492
|
+
lastAddedCursorRef.current = cursor;
|
|
475
493
|
}
|
|
476
|
-
|
|
494
|
+
if (existingPage &&
|
|
495
|
+
items.length > existingPage.data.length &&
|
|
496
|
+
items.length >= limit) {
|
|
497
|
+
lastAddedCursorRef.current = cursor;
|
|
498
|
+
}
|
|
499
|
+
return next;
|
|
477
500
|
});
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
501
|
+
}, [
|
|
502
|
+
currentQuery.data,
|
|
503
|
+
currentQuery.isLoading,
|
|
504
|
+
currentCursor,
|
|
505
|
+
pages.length,
|
|
506
|
+
limit,
|
|
507
|
+
]);
|
|
484
508
|
const loadMore = useCallback(() => {
|
|
485
|
-
if (
|
|
486
|
-
|
|
487
|
-
!
|
|
488
|
-
setCurrentCursor(
|
|
509
|
+
if (currentResult?.hasMore &&
|
|
510
|
+
currentResult.nextCursor != null &&
|
|
511
|
+
!isLoading) {
|
|
512
|
+
setCurrentCursor(currentResult.nextCursor);
|
|
489
513
|
}
|
|
490
|
-
}, [
|
|
514
|
+
}, [currentResult, isLoading]);
|
|
491
515
|
const refetch = useCallback(() => {
|
|
492
516
|
setPages([]);
|
|
493
517
|
setCurrentCursor(null);
|
|
518
|
+
setCurrentResult(null);
|
|
494
519
|
lastAddedCursorRef.current = undefined;
|
|
495
|
-
setLastResult(null);
|
|
496
520
|
currentQuery.refetch();
|
|
497
521
|
}, [currentQuery]);
|
|
498
522
|
const allItems = useMemo(() => {
|
|
523
|
+
const sorted = [...pages].sort((a, b) => {
|
|
524
|
+
if (feedCursorEq(a.cursor, b.cursor))
|
|
525
|
+
return 0;
|
|
526
|
+
if (a.cursor === null)
|
|
527
|
+
return -1;
|
|
528
|
+
if (b.cursor === null)
|
|
529
|
+
return 1;
|
|
530
|
+
const ta = a.cursor.timestamp ?? '';
|
|
531
|
+
const tb = b.cursor.timestamp ?? '';
|
|
532
|
+
return tb.localeCompare(ta);
|
|
533
|
+
});
|
|
499
534
|
const seen = new Set();
|
|
500
|
-
return
|
|
535
|
+
return sorted.flatMap((p) => p.data).filter((item) => {
|
|
501
536
|
const key = `${item.sort_ts ?? ''}_${item.sort_id ?? ''}_${item.feed_type ?? ''}`;
|
|
502
537
|
if (seen.has(key))
|
|
503
538
|
return false;
|
|
@@ -507,10 +542,10 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
|
|
|
507
542
|
}, [pages]);
|
|
508
543
|
return {
|
|
509
544
|
items: allItems,
|
|
510
|
-
isLoading:
|
|
511
|
-
isLoadingMore:
|
|
512
|
-
hasMore:
|
|
513
|
-
(currentCursor !== null && pages.length > 0)
|
|
545
|
+
isLoading: isLoading && pages.length === 0,
|
|
546
|
+
isLoadingMore: isLoading && pages.length > 0,
|
|
547
|
+
hasMore: currentResult?.hasMore ??
|
|
548
|
+
(currentCursor !== null && pages.length > 0) ??
|
|
514
549
|
false,
|
|
515
550
|
loadMore,
|
|
516
551
|
refetch,
|