This commit is contained in:
Lokimorty 2026-02-07 01:28:47 +04:00 committed by GitHub
commit 2a6ff35e9f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 181 additions and 5 deletions

View file

@ -28,9 +28,11 @@ export function LoadingPanel({
...props
}: LoadingPanelProps): ReactNode {
const empty = isEmpty ?? checkEmpty(data);
const hasData = data && !empty;
// Show loading spinner only if no data exists
if (isLoading || isFetching) {
// Show loading only on initial load when no data exists yet
// Don't show loading during background refetches when we already have data
if ((isLoading || isFetching) && !hasData) {
return (
<Column position="relative" height="100%" width="100%" {...props}>
<Loading icon={loadingIcon} placement={loadingPlacement} />
@ -48,8 +50,8 @@ export function LoadingPanel({
return renderEmpty();
}
// Show main content when data exists
if (!isLoading && !isFetching && !error && !empty) {
// Show content when we have data (even during background refetch)
if (hasData) {
return children;
}

View file

@ -79,6 +79,7 @@ export * from './useNavigation';
export * from './usePagedQuery';
export * from './usePageParameters';
export * from './useRegionNames';
export * from './useSessionStream';
export * from './useSlug';
export * from './useSticky';
export * from './useTimezone';

View file

@ -0,0 +1,61 @@
import { useEffect, useRef } from 'react';
import { useQueryClient } from '@tanstack/react-query';
const MAX_RETRY_DELAY = 30000;
const INITIAL_RETRY_DELAY = 1000;
export function useSessionStream(websiteId?: string) {
const queryClient = useQueryClient();
const retryCountRef = useRef(0);
const retryTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
if (!websiteId) return;
let eventSource: EventSource | null = null;
let isMounted = true;
const connect = () => {
if (!isMounted) return;
eventSource = new EventSource(`/api/websites/${websiteId}/sessions/stream`);
eventSource.onmessage = event => {
try {
const data = JSON.parse(event.data);
if (data.sessionId) {
retryCountRef.current = 0;
queryClient.invalidateQueries({ queryKey: ['sessions', { websiteId }] });
}
} catch (error) {
// eslint-disable-next-line no-console
console.error('Failed to parse session event:', error);
}
};
eventSource.onerror = () => {
eventSource?.close();
if (!isMounted) return;
const delay = Math.min(
INITIAL_RETRY_DELAY * Math.pow(2, retryCountRef.current),
MAX_RETRY_DELAY,
);
retryCountRef.current += 1;
retryTimeoutRef.current = setTimeout(connect, delay);
};
};
connect();
return () => {
isMounted = false;
if (retryTimeoutRef.current) {
clearTimeout(retryTimeoutRef.current);
}
eventSource?.close();
};
}, [websiteId, queryClient]);
}