Files
readest/apps/readest-app/src/hooks/useTransferQueue.ts
T
Huang Xin 3f4d4b8643 fix(transfer): persist queue when clearing completed/failed/all (#4947)
Clear Completed, Clear Failed and Clear All mutated the Zustand store
directly, so the cleared items were never written back to localStorage.
On the next load the persisted queue restored them and they reappeared
in the Transfer Queue panel.

Route these clears through transferManager (like clearPending already
does) so each calls persistQueue() after mutating the store.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 19:01:43 +02:00

148 lines
4.5 KiB
TypeScript

import { useEffect, useCallback, useMemo } from 'react';
import { useEnv } from '@/context/EnvContext';
import { useTranslation } from './useTranslation';
import { useLibraryStore } from '@/store/libraryStore';
import { useTransferStore, TransferType } from '@/store/transferStore';
import { transferManager } from '@/services/transferManager';
import { Book } from '@/types/book';
export function useTransferQueue(libraryLoaded = true, delayInit = 0) {
const { envConfig, appService } = useEnv();
const _ = useTranslation();
const transfers = useTransferStore((state) => state.transfers);
const isQueuePaused = useTransferStore((state) => state.isQueuePaused);
const setIsTransferQueueOpen = useTransferStore((state) => state.setIsTransferQueueOpen);
useEffect(() => {
const initManager = async () => {
if (appService && envConfig) {
const getLibrary = () => useLibraryStore.getState().library;
const updateBookFn = async (book: Book) => {
await useLibraryStore.getState().updateBook(envConfig, book);
};
const translationFn = _;
await transferManager.initialize(appService, getLibrary, updateBookFn, translationFn);
}
};
// Initialize transfer manager only when library is loaded
if (libraryLoaded) {
setTimeout(() => {
initManager();
}, delayInit);
}
}, [appService, envConfig, libraryLoaded, delayInit, _]);
const queueUpload = useCallback((book: Book, priority?: number) => {
return transferManager.queueUpload(book, priority);
}, []);
const queueDownload = useCallback((book: Book, priority?: number) => {
return transferManager.queueDownload(book, priority);
}, []);
const queueBatchUploads = useCallback((books: Book[], priority?: number) => {
return transferManager.queueBatchUploads(books, priority);
}, []);
const cancelTransfer = useCallback((transferId: string) => {
transferManager.cancelTransfer(transferId);
}, []);
const retryTransfer = useCallback((transferId: string) => {
transferManager.retryTransfer(transferId);
}, []);
const retryAllFailed = useCallback(() => {
transferManager.retryAllFailed();
}, []);
const pauseQueue = useCallback(() => {
transferManager.pauseQueue();
}, []);
const resumeQueue = useCallback(() => {
transferManager.resumeQueue();
}, []);
const clearCompleted = useCallback(() => {
transferManager.clearCompleted();
}, []);
const clearFailed = useCallback(() => {
transferManager.clearFailed();
}, []);
const clearPending = useCallback(() => {
transferManager.clearPending();
}, []);
const clearAll = useCallback(() => {
transferManager.clearAll();
}, []);
const getTransferProgress = useCallback((bookHash: string, type: TransferType) => {
return useTransferStore.getState().getTransferByBookHash(bookHash, type);
}, []);
const stats = useMemo(() => {
const transferList = Object.values(transfers);
return {
pending: transferList.filter((t) => t.status === 'pending').length,
active: transferList.filter((t) => t.status === 'in_progress').length,
completed: transferList.filter((t) => t.status === 'completed').length,
failed: transferList.filter((t) => t.status === 'failed' || t.status === 'cancelled').length,
total: transferList.length,
};
}, [transfers]);
const pendingTransfers = useMemo(() => {
return Object.values(transfers).filter((t) => t.status === 'pending');
}, [transfers]);
const activeTransfers = useMemo(() => {
return Object.values(transfers).filter((t) => t.status === 'in_progress');
}, [transfers]);
const failedTransfers = useMemo(() => {
return Object.values(transfers).filter(
(t) => t.status === 'failed' || t.status === 'cancelled',
);
}, [transfers]);
const completedTransfers = useMemo(() => {
return Object.values(transfers).filter((t) => t.status === 'completed');
}, [transfers]);
const hasActiveTransfers = useMemo(() => {
return pendingTransfers.length > 0 || activeTransfers.length > 0;
}, [pendingTransfers, activeTransfers]);
return {
transfers: Object.values(transfers),
isQueuePaused,
stats,
pendingTransfers,
activeTransfers,
failedTransfers,
completedTransfers,
hasActiveTransfers,
setIsTransferQueueOpen,
queueUpload,
queueDownload,
queueBatchUploads,
cancelTransfer,
retryTransfer,
retryAllFailed,
pauseQueue,
resumeQueue,
clearCompleted,
clearFailed,
clearPending,
clearAll,
getTransferProgress,
};
}