feat: added sse for upload section

This commit is contained in:
2026-07-02 14:28:28 +05:30
parent 53fe4e11fe
commit 278b9591d7
5 changed files with 133 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
'use client';
import { useCallback, useMemo, useRef } from 'react';
import { useQueryClient } from '@tanstack/react-query';
import { API_ROUTES } from '@/constants/apiRoutes';
import { useSseWithToken } from '@/hooks/sse/useSseWithToken';
import { videoService } from '@/services/api';
import type {
PaginationParams,
UploadListResponse,
UploadStatusEvent,
} from '@/types';
import { uploadKeys } from './useUploadQueries';
function getUploadListParams(queryKey: readonly unknown[]) {
const params = queryKey[2];
if (!params || typeof params !== 'object' || Array.isArray(params)) {
return undefined;
}
return params as PaginationParams;
}
function patchUploadList(
current: UploadListResponse | undefined,
event: UploadStatusEvent,
params?: PaginationParams,
) {
if (!current) return current;
const existingIndex = current.items.findIndex(
(upload) => upload.id === event.item.id,
);
if (existingIndex >= 0) {
return {
...current,
items: current.items.map((upload) =>
upload.id === event.item.id ? event.item : upload,
),
};
}
if (event.kind !== 'created') return current;
const nextTotal = current.total + 1;
if ((params?.skip ?? 0) !== 0) {
return { ...current, total: nextTotal };
}
const pageLimit = params?.limit ?? current.items.length + 1;
return {
items: [event.item, ...current.items].slice(0, pageLimit),
total: nextTotal,
};
}
export function useUploadListEvents(enabled = true) {
const queryClient = useQueryClient();
const hasInvalidatedAfterConnectionErrorRef = useRef(false);
const events = useMemo(
() => ({
upload_status: (event: UploadStatusEvent) => {
queryClient
.getQueryCache()
.findAll({ queryKey: uploadKeys.lists() })
.forEach((query) => {
queryClient.setQueryData<UploadListResponse>(
query.queryKey,
(current) =>
patchUploadList(
current,
event,
getUploadListParams(query.queryKey),
),
);
});
},
heartbeat: () => undefined,
}),
[queryClient],
);
const getPath = useCallback(
(token: string) => API_ROUTES.VIDEOS.UPLOAD_EVENTS(token),
[],
);
const onConnectionError = useCallback(() => {
if (hasInvalidatedAfterConnectionErrorRef.current) return;
hasInvalidatedAfterConnectionErrorRef.current = true;
queryClient.invalidateQueries({ queryKey: uploadKeys.lists() });
}, [queryClient]);
const onConnectionOpen = useCallback(() => {
hasInvalidatedAfterConnectionErrorRef.current = false;
}, []);
useSseWithToken({
enabled,
getToken: videoService.createUploadEventsToken,
getPath,
events,
onConnectionError,
onConnectionOpen,
});
}

View File

@@ -12,11 +12,13 @@ import { useUploadListColumns } from './components/UploadListColumns';
import { UploadTable } from './components/UploadTable';
import { UploadVideoDialog } from './components/UploadVideoDialog';
import { useUploadFilters } from './hooks/useUploadFilters';
import { useUploadListEvents } from './hooks/useUploadListEvents';
import { useUploadsQuery } from './hooks/useUploadQueries';
export default function UploadPage() {
const { skip, setSkip, limit, setLimit } = useUploadFilters();
const uploadsQuery = useUploadsQuery({ skip, limit });
useUploadListEvents();
const [isCreateOpen, setIsCreateOpen] = useState(false);
const [videoUpload, setVideoUpload] = useState<UploadListItem | null>(null);