LibreChat/client/src/hooks/Files/useSharePointDownload.ts

130 lines
4 KiB
TypeScript
Raw Normal View History

import { useCallback, useState } from 'react';
import { useToastContext } from '@librechat/client';
import type { SharePointFile, SharePointBatchProgress } from '~/data-provider/Files';
import { useSharePointBatchDownload } from '~/data-provider/Files';
import useSharePointToken from './useSharePointToken';
interface UseSharePointDownloadProps {
onFilesDownloaded?: (files: File[]) => void | Promise<void>;
onError?: (error: Error) => void;
}
interface UseSharePointDownloadReturn {
downloadSharePointFiles: (files: SharePointFile[]) => Promise<File[]>;
isDownloading: boolean;
downloadProgress: SharePointBatchProgress | null;
error: string | null;
}
export default function useSharePointDownload({
onFilesDownloaded,
onError,
}: UseSharePointDownloadProps = {}): UseSharePointDownloadReturn {
const { showToast } = useToastContext();
const [downloadProgress, setDownloadProgress] = useState<SharePointBatchProgress | null>(null);
const [error, setError] = useState<string | null>(null);
const { token, refetch: refetchToken } = useSharePointToken({
enabled: false,
purpose: 'Download',
});
const batchDownloadMutation = useSharePointBatchDownload();
const downloadSharePointFiles = useCallback(
async (files: SharePointFile[]): Promise<File[]> => {
if (!files || files.length === 0) {
throw new Error('No files provided for download');
}
setError(null);
setDownloadProgress({ completed: 0, total: files.length, failed: [] });
try {
let accessToken = token?.access_token;
if (!accessToken) {
showToast({
message: 'Getting SharePoint access token...',
status: 'info',
duration: 2000,
});
const tokenResult = await refetchToken();
accessToken = tokenResult.data?.access_token;
if (!accessToken) {
throw new Error('Failed to obtain SharePoint access token');
}
}
showToast({
message: `Downloading ${files.length} file(s) from SharePoint...`,
status: 'info',
duration: 3000,
});
const downloadedFiles = await batchDownloadMutation.mutateAsync({
files,
accessToken,
onProgress: (progress) => {
setDownloadProgress(progress);
if (files.length > 5 && progress.completed % 3 === 0) {
showToast({
message: `Downloaded ${progress.completed}/${progress.total} files...`,
status: 'info',
duration: 1000,
});
}
},
});
if (downloadedFiles.length > 0) {
const failedCount = files.length - downloadedFiles.length;
const successMessage =
failedCount > 0
? `Downloaded ${downloadedFiles.length}/${files.length} files from SharePoint (${failedCount} failed)`
: `Successfully downloaded ${downloadedFiles.length} file(s) from SharePoint`;
showToast({
message: successMessage,
status: failedCount > 0 ? 'warning' : 'success',
duration: 4000,
});
if (onFilesDownloaded) {
await onFilesDownloaded(downloadedFiles);
}
}
setDownloadProgress(null);
return downloadedFiles;
} catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown download error';
setError(errorMessage);
showToast({
message: `SharePoint download failed: ${errorMessage}`,
status: 'error',
duration: 5000,
});
if (onError) {
onError(error instanceof Error ? error : new Error(errorMessage));
}
setDownloadProgress(null);
throw error;
}
},
[token, showToast, batchDownloadMutation, onFilesDownloaded, onError, refetchToken],
);
return {
downloadSharePointFiles,
isDownloading: batchDownloadMutation.isLoading,
downloadProgress,
error,
};
}