@adventurelabs/scout-core 1.4.23 → 1.4.25

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.
@@ -417,25 +417,30 @@ const feedCursorEq = (a, b) => {
417
417
  export const useInfiniteFeedByHerd = (herdId, options) => {
418
418
  const [pages, setPages] = useState([]);
419
419
  const [currentCursor, setCurrentCursor] = useState(null);
420
- const prevHerdIdRef = useRef();
420
+ const prevHerdIdRef = useRef(undefined);
421
421
  const lastAddedCursorRef = useRef(undefined);
422
+ const lastResultRef = useRef(null);
423
+ const pagesLengthRef = useRef(0);
422
424
  const currentQuery = useGetFeedInfiniteByHerdQuery({
423
425
  herdId,
424
426
  limit: options.limit || 20,
425
427
  cursor: currentCursor,
426
428
  supabase: options.supabase,
427
429
  }, { skip: !options.enabled || !herdId });
430
+ useEffect(() => {
431
+ pagesLengthRef.current = pages.length;
432
+ }, [pages.length]);
433
+ // Clear all state whenever herd id changes (including to/from undefined)
428
434
  useEffect(() => {
429
435
  if (prevHerdIdRef.current !== undefined &&
430
- prevHerdIdRef.current !== herdId &&
431
- options.enabled &&
432
- herdId) {
436
+ prevHerdIdRef.current !== herdId) {
433
437
  setPages([]);
434
438
  setCurrentCursor(null);
435
439
  lastAddedCursorRef.current = undefined;
440
+ lastResultRef.current = null;
436
441
  }
437
442
  prevHerdIdRef.current = herdId;
438
- }, [herdId, options.enabled]);
443
+ }, [herdId]);
439
444
  // When we request a new page (cursor changed), clear ref so we merge the new response
440
445
  useEffect(() => {
441
446
  lastAddedCursorRef.current = undefined;
@@ -443,18 +448,22 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
443
448
  useEffect(() => {
444
449
  if (!currentQuery.data || currentQuery.isLoading)
445
450
  return;
446
- // Don't skip the first page after reset: only skip when we already have pages for this cursor
447
- if (pages.length > 0 &&
451
+ // Match dummy: only skip merge when we already have pages and this cursor was already added as a full page
452
+ if (pagesLengthRef.current > 0 &&
448
453
  feedCursorEq(lastAddedCursorRef.current ?? null, currentCursor))
449
454
  return;
455
+ const items = Array.isArray(currentQuery.data?.items)
456
+ ? currentQuery.data.items
457
+ : [];
458
+ const limit = options.limit || 20;
459
+ // Store hasMore/nextCursor from this response so loadMore can use it (like dummy's currentResult)
460
+ lastResultRef.current = {
461
+ hasMore: currentQuery.data.hasMore ?? false,
462
+ nextCursor: currentQuery.data.nextCursor ?? null,
463
+ };
450
464
  setPages((prev) => {
451
465
  const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
452
466
  if (!existingPage) {
453
- const items = Array.isArray(currentQuery.data?.items)
454
- ? currentQuery.data.items
455
- : [];
456
- const limit = options.limit || 20;
457
- // Only mark "last added" for full pages so partial/empty responses don't block a later merge
458
467
  if (items.length >= limit) {
459
468
  lastAddedCursorRef.current = currentCursor;
460
469
  }
@@ -467,16 +476,18 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
467
476
  });
468
477
  }, [currentQuery.data, currentQuery.isLoading, currentCursor, pages.length, options.limit]);
469
478
  const loadMore = useCallback(() => {
470
- if (currentQuery.data?.hasMore &&
471
- currentQuery.data.nextCursor &&
479
+ const result = lastResultRef.current;
480
+ if (result?.hasMore &&
481
+ result.nextCursor != null &&
472
482
  !currentQuery.isLoading) {
473
- setCurrentCursor(currentQuery.data.nextCursor);
483
+ setCurrentCursor(result.nextCursor);
474
484
  }
475
- }, [currentQuery.data, currentQuery.isLoading]);
485
+ }, [currentQuery.isLoading]);
476
486
  const refetch = useCallback(() => {
477
487
  setPages([]);
478
488
  setCurrentCursor(null);
479
489
  lastAddedCursorRef.current = undefined;
490
+ lastResultRef.current = null;
480
491
  currentQuery.refetch();
481
492
  }, [currentQuery]);
482
493
  const allItems = useMemo(() => {
@@ -493,7 +504,7 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
493
504
  items: allItems,
494
505
  isLoading: currentQuery.isLoading && pages.length === 0,
495
506
  isLoadingMore: currentQuery.isLoading && pages.length > 0,
496
- hasMore: (currentQuery.data?.hasMore ??
507
+ hasMore: (lastResultRef.current?.hasMore ??
497
508
  (currentCursor !== null && pages.length > 0)) ??
498
509
  false,
499
510
  loadMore,
@@ -504,25 +515,30 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
504
515
  export const useInfiniteFeedByDevice = (deviceId, options) => {
505
516
  const [pages, setPages] = useState([]);
506
517
  const [currentCursor, setCurrentCursor] = useState(null);
507
- const prevDeviceIdRef = useRef();
518
+ const prevDeviceIdRef = useRef(undefined);
508
519
  const lastAddedCursorRef = useRef(undefined);
520
+ const lastResultRef = useRef(null);
521
+ const pagesLengthRef = useRef(0);
509
522
  const currentQuery = useGetFeedInfiniteByDeviceQuery({
510
523
  deviceId,
511
524
  limit: options.limit || 20,
512
525
  cursor: currentCursor,
513
526
  supabase: options.supabase,
514
527
  }, { skip: !options.enabled || !deviceId });
528
+ useEffect(() => {
529
+ pagesLengthRef.current = pages.length;
530
+ }, [pages.length]);
531
+ // Clear all state whenever device id changes (including to/from undefined)
515
532
  useEffect(() => {
516
533
  if (prevDeviceIdRef.current !== undefined &&
517
- prevDeviceIdRef.current !== deviceId &&
518
- options.enabled &&
519
- deviceId) {
534
+ prevDeviceIdRef.current !== deviceId) {
520
535
  setPages([]);
521
536
  setCurrentCursor(null);
522
537
  lastAddedCursorRef.current = undefined;
538
+ lastResultRef.current = null;
523
539
  }
524
540
  prevDeviceIdRef.current = deviceId;
525
- }, [deviceId, options.enabled]);
541
+ }, [deviceId]);
526
542
  // When we request a new page (cursor changed), clear ref so we merge the new response
527
543
  useEffect(() => {
528
544
  lastAddedCursorRef.current = undefined;
@@ -530,7 +546,7 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
530
546
  useEffect(() => {
531
547
  if (!currentQuery.data || currentQuery.isLoading)
532
548
  return;
533
- if (pages.length > 0 &&
549
+ if (pagesLengthRef.current > 0 &&
534
550
  feedCursorEq(lastAddedCursorRef.current ?? null, currentCursor))
535
551
  return;
536
552
  setPages((prev) => {
@@ -543,6 +559,10 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
543
559
  if (items.length >= limit) {
544
560
  lastAddedCursorRef.current = currentCursor;
545
561
  }
562
+ lastResultRef.current = {
563
+ hasMore: currentQuery.data?.hasMore ?? false,
564
+ nextCursor: currentQuery.data?.nextCursor ?? null,
565
+ };
546
566
  return [
547
567
  ...prev,
548
568
  { cursor: currentCursor, data: items },
@@ -552,16 +572,18 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
552
572
  });
553
573
  }, [currentQuery.data, currentQuery.isLoading, currentCursor, pages.length, options.limit]);
554
574
  const loadMore = useCallback(() => {
555
- if (currentQuery.data?.hasMore &&
556
- currentQuery.data.nextCursor &&
575
+ const result = lastResultRef.current;
576
+ if (result?.hasMore &&
577
+ result.nextCursor != null &&
557
578
  !currentQuery.isLoading) {
558
- setCurrentCursor(currentQuery.data.nextCursor);
579
+ setCurrentCursor(result.nextCursor);
559
580
  }
560
- }, [currentQuery.data, currentQuery.isLoading]);
581
+ }, [currentQuery.isLoading]);
561
582
  const refetch = useCallback(() => {
562
583
  setPages([]);
563
584
  setCurrentCursor(null);
564
585
  lastAddedCursorRef.current = undefined;
586
+ lastResultRef.current = null;
565
587
  currentQuery.refetch();
566
588
  }, [currentQuery]);
567
589
  const allItems = useMemo(() => {
@@ -578,7 +600,7 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
578
600
  items: allItems,
579
601
  isLoading: currentQuery.isLoading && pages.length === 0,
580
602
  isLoadingMore: currentQuery.isLoading && pages.length > 0,
581
- hasMore: (currentQuery.data?.hasMore ??
603
+ hasMore: (lastResultRef.current?.hasMore ??
582
604
  (currentCursor !== null && pages.length > 0)) ??
583
605
  false,
584
606
  loadMore,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.4.23",
3
+ "version": "1.4.25",
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",