@adventurelabs/scout-core 1.4.19 → 1.4.20

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.
@@ -418,6 +418,7 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
418
418
  const [pages, setPages] = useState([]);
419
419
  const [currentCursor, setCurrentCursor] = useState(null);
420
420
  const prevHerdIdRef = useRef();
421
+ const lastAddedCursorRef = useRef(undefined);
421
422
  const currentQuery = useGetFeedInfiniteByHerdQuery({
422
423
  herdId,
423
424
  limit: options.limit || 20,
@@ -431,22 +432,29 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
431
432
  herdId) {
432
433
  setPages([]);
433
434
  setCurrentCursor(null);
435
+ lastAddedCursorRef.current = undefined;
434
436
  }
435
437
  prevHerdIdRef.current = herdId;
436
438
  }, [herdId, options.enabled]);
437
439
  useEffect(() => {
438
- if (currentQuery.data && !currentQuery.isLoading) {
439
- setPages((prev) => {
440
- const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
441
- if (!existingPage) {
442
- return [
443
- ...prev,
444
- { cursor: currentCursor, data: currentQuery.data.items },
445
- ];
446
- }
447
- return prev;
448
- });
449
- }
440
+ if (!currentQuery.data || currentQuery.isLoading)
441
+ return;
442
+ if (feedCursorEq(lastAddedCursorRef.current ?? null, currentCursor))
443
+ return;
444
+ setPages((prev) => {
445
+ const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
446
+ if (!existingPage) {
447
+ const items = Array.isArray(currentQuery.data?.items)
448
+ ? currentQuery.data.items
449
+ : [];
450
+ lastAddedCursorRef.current = currentCursor;
451
+ return [
452
+ ...prev,
453
+ { cursor: currentCursor, data: items },
454
+ ];
455
+ }
456
+ return prev;
457
+ });
450
458
  }, [currentQuery.data, currentQuery.isLoading, currentCursor]);
451
459
  const loadMore = useCallback(() => {
452
460
  if (currentQuery.data?.hasMore &&
@@ -458,9 +466,19 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
458
466
  const refetch = useCallback(() => {
459
467
  setPages([]);
460
468
  setCurrentCursor(null);
469
+ lastAddedCursorRef.current = undefined;
461
470
  currentQuery.refetch();
462
471
  }, [currentQuery]);
463
- const allItems = useMemo(() => pages.flatMap((p) => p.data), [pages]);
472
+ const allItems = useMemo(() => {
473
+ const seen = new Set();
474
+ return pages.flatMap((p) => p.data).filter((item) => {
475
+ const key = `${item.sort_ts ?? ''}_${item.sort_id ?? ''}_${item.feed_type ?? ''}`;
476
+ if (seen.has(key))
477
+ return false;
478
+ seen.add(key);
479
+ return true;
480
+ });
481
+ }, [pages]);
464
482
  return {
465
483
  items: allItems,
466
484
  isLoading: currentQuery.isLoading && pages.length === 0,
@@ -475,6 +493,7 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
475
493
  const [pages, setPages] = useState([]);
476
494
  const [currentCursor, setCurrentCursor] = useState(null);
477
495
  const prevDeviceIdRef = useRef();
496
+ const lastAddedCursorRef = useRef(undefined);
478
497
  const currentQuery = useGetFeedInfiniteByDeviceQuery({
479
498
  deviceId,
480
499
  limit: options.limit || 20,
@@ -488,22 +507,29 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
488
507
  deviceId) {
489
508
  setPages([]);
490
509
  setCurrentCursor(null);
510
+ lastAddedCursorRef.current = undefined;
491
511
  }
492
512
  prevDeviceIdRef.current = deviceId;
493
513
  }, [deviceId, options.enabled]);
494
514
  useEffect(() => {
495
- if (currentQuery.data && !currentQuery.isLoading) {
496
- setPages((prev) => {
497
- const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
498
- if (!existingPage) {
499
- return [
500
- ...prev,
501
- { cursor: currentCursor, data: currentQuery.data.items },
502
- ];
503
- }
504
- return prev;
505
- });
506
- }
515
+ if (!currentQuery.data || currentQuery.isLoading)
516
+ return;
517
+ if (feedCursorEq(lastAddedCursorRef.current ?? null, currentCursor))
518
+ return;
519
+ setPages((prev) => {
520
+ const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
521
+ if (!existingPage) {
522
+ const items = Array.isArray(currentQuery.data?.items)
523
+ ? currentQuery.data.items
524
+ : [];
525
+ lastAddedCursorRef.current = currentCursor;
526
+ return [
527
+ ...prev,
528
+ { cursor: currentCursor, data: items },
529
+ ];
530
+ }
531
+ return prev;
532
+ });
507
533
  }, [currentQuery.data, currentQuery.isLoading, currentCursor]);
508
534
  const loadMore = useCallback(() => {
509
535
  if (currentQuery.data?.hasMore &&
@@ -515,9 +541,19 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
515
541
  const refetch = useCallback(() => {
516
542
  setPages([]);
517
543
  setCurrentCursor(null);
544
+ lastAddedCursorRef.current = undefined;
518
545
  currentQuery.refetch();
519
546
  }, [currentQuery]);
520
- const allItems = useMemo(() => pages.flatMap((p) => p.data), [pages]);
547
+ const allItems = useMemo(() => {
548
+ const seen = new Set();
549
+ return pages.flatMap((p) => p.data).filter((item) => {
550
+ const key = `${item.sort_ts ?? ''}_${item.sort_id ?? ''}_${item.feed_type ?? ''}`;
551
+ if (seen.has(key))
552
+ return false;
553
+ seen.add(key);
554
+ return true;
555
+ });
556
+ }, [pages]);
521
557
  return {
522
558
  items: allItems,
523
559
  isLoading: currentQuery.isLoading && pages.length === 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.4.19",
3
+ "version": "1.4.20",
4
4
  "description": "Core utilities and helpers for Adventure Labs Scout applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",