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; onError?: (error: Error) => void; } interface UseSharePointDownloadReturn { downloadSharePointFiles: (files: SharePointFile[]) => Promise; isDownloading: boolean; downloadProgress: SharePointBatchProgress | null; error: string | null; } export default function useSharePointDownload({ onFilesDownloaded, onError, }: UseSharePointDownloadProps = {}): UseSharePointDownloadReturn { const { showToast } = useToastContext(); const [downloadProgress, setDownloadProgress] = useState(null); const [error, setError] = useState(null); const { token, refetch: refetchToken } = useSharePointToken({ enabled: false, purpose: 'Download', }); const batchDownloadMutation = useSharePointBatchDownload(); const downloadSharePointFiles = useCallback( async (files: SharePointFile[]): Promise => { 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, }; }