paginate open streams (#252)
* paginate for open and closed streams * fix: add platform abstraction for deeplink (#251) * fix: add platform abstraction for deeplink This was crashing App.tsx due to the deep link listener calling methods on window which do not exist. * fix: apply CodeRabbit auto-fixes Fixed 1 file(s) based on 1 unresolved review comment. Co-authored-by: CodeRabbit <noreply@coderabbit.ai> * log error --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: CodeRabbit <noreply@coderabbit.ai> * cleanup * fix: import --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
This commit was merged in pull request #252.
This commit is contained in:
@@ -11,6 +11,7 @@ import NetworkSelector from '@/features/network-selector';
|
|||||||
import NetworkRoot from '@/features/network-root';
|
import NetworkRoot from '@/features/network-root';
|
||||||
import ParticleViewResolver from '@/features/particles/particle-view-resolver';
|
import ParticleViewResolver from '@/features/particles/particle-view-resolver';
|
||||||
import Layout from '@/features/layout';
|
import Layout from '@/features/layout';
|
||||||
|
import { logError } from '@/lib/errors';
|
||||||
import NetworkSettingsPage from '@/features/network-settings';
|
import NetworkSettingsPage from '@/features/network-settings';
|
||||||
import { Toaster } from '@/components/ui/sonner';
|
import { Toaster } from '@/components/ui/sonner';
|
||||||
import { PusherProvider } from '@/lib/pusher-provider';
|
import { PusherProvider } from '@/lib/pusher-provider';
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ export type StreamParticle = Particle & {
|
|||||||
properties: StreamProperties;
|
properties: StreamProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CLOSED_INITIAL_PAGE_SIZE = 50;
|
const INITIAL_PAGE_SIZE = 12;
|
||||||
const CLOSED_PAGE_INCREMENT = 50;
|
const PAGE_INCREMENT = 12;
|
||||||
|
|
||||||
// Stable where-constraint references so the Firestore subscription only
|
// Stable where-constraint references so the Firestore subscription only
|
||||||
// re-attaches when the tab actually changes, not on every render.
|
// re-attaches when the tab actually changes, not on every render.
|
||||||
@@ -28,11 +28,7 @@ function useVisibilityScopes(userId?: string, networkId?: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface UseStreamParticlesOptions {
|
interface UseStreamParticlesOptions {
|
||||||
/**
|
// Which streams to subscribe to
|
||||||
* Which streams to subscribe to. Open streams are loaded in full (bounded
|
|
||||||
* by active work — full realtime coverage is needed for autoplay/huddles).
|
|
||||||
* Closed streams are paginated via `loadMore`.
|
|
||||||
*/
|
|
||||||
status: 'open' | 'closed';
|
status: 'open' | 'closed';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,9 +36,9 @@ interface UseStreamParticlesResult {
|
|||||||
streams: StreamParticle[];
|
streams: StreamParticle[];
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
networkId: string;
|
networkId: string;
|
||||||
/** True when more closed streams may exist beyond the current window. */
|
/** True when more streams may exist beyond the current window. */
|
||||||
canLoadMore: boolean;
|
canLoadMore: boolean;
|
||||||
/** Extend the pagination window. No-op on the open tab. */
|
/** Extend the pagination window. */
|
||||||
loadMore: () => void;
|
loadMore: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,21 +50,10 @@ export function useStreamParticles(
|
|||||||
const user = useAuthStore((s) => s.user);
|
const user = useAuthStore((s) => s.user);
|
||||||
const visibilityScopes = useVisibilityScopes(user?.id, networkId);
|
const visibilityScopes = useVisibilityScopes(user?.id, networkId);
|
||||||
|
|
||||||
const [closedLimit, setClosedLimit] = useState(CLOSED_INITIAL_PAGE_SIZE);
|
const [limit, setLimit] = useState(INITIAL_PAGE_SIZE);
|
||||||
const [prevStatus, setPrevStatus] = useState(status);
|
|
||||||
|
|
||||||
// Switching back to the closed tab starts a fresh window, avoiding an
|
|
||||||
// ever-growing subscription across a long session.
|
|
||||||
if (status !== prevStatus) {
|
|
||||||
setPrevStatus(status);
|
|
||||||
if (status === 'closed') {
|
|
||||||
setClosedLimit(CLOSED_INITIAL_PAGE_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const whereFilter: QueryFieldFilterConstraint =
|
const whereFilter: QueryFieldFilterConstraint =
|
||||||
status === 'open' ? OPEN_STATUS_FILTER : CLOSED_STATUS_FILTER;
|
status === 'open' ? OPEN_STATUS_FILTER : CLOSED_STATUS_FILTER;
|
||||||
const limit = status === 'closed' ? closedLimit : undefined;
|
|
||||||
|
|
||||||
const { children, isLoading } = useLiveParticleChildren(path, {
|
const { children, isLoading } = useLiveParticleChildren(path, {
|
||||||
orderByField: 'last_child_created_at',
|
orderByField: 'last_child_created_at',
|
||||||
@@ -85,12 +70,11 @@ export function useStreamParticles(
|
|||||||
|
|
||||||
// Heuristic: if we got back as many items as we asked for, assume there
|
// Heuristic: if we got back as many items as we asked for, assume there
|
||||||
// might be more. Clicking load-more when there are no more is a no-op.
|
// might be more. Clicking load-more when there are no more is a no-op.
|
||||||
const canLoadMore = status === 'closed' && streams.length >= closedLimit;
|
const canLoadMore = streams.length >= limit;
|
||||||
|
|
||||||
const loadMore = useCallback(() => {
|
const loadMore = useCallback(() => {
|
||||||
if (status !== 'closed') return;
|
setLimit((prev) => prev + PAGE_INCREMENT);
|
||||||
setClosedLimit((prev) => prev + CLOSED_PAGE_INCREMENT);
|
}, []);
|
||||||
}, [status]);
|
|
||||||
|
|
||||||
return { streams, isLoading, networkId, canLoadMore, loadMore };
|
return { streams, isLoading, networkId, canLoadMore, loadMore };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user