import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import useDrivePicker from 'react-google-drive-picker'; import ConnectorAuth from './ConnectorAuth'; import { getSessionToken, setSessionToken, removeSessionToken, validateProviderSession, } from '../utils/providerUtils'; import ConnectedStateSkeleton from './ConnectedStateSkeleton'; import FilesSectionSkeleton from './FileSelectionSkeleton'; interface PickerFile { id: string; name: string; mimeType: string; iconUrl: string; description?: string; sizeBytes?: string; } interface GoogleDrivePickerProps { token: string | null; onSelectionChange: (fileIds: string[], folderIds?: string[]) => void; } const GoogleDrivePicker: React.FC = ({ token, onSelectionChange, }) => { const { t } = useTranslation(); const [selectedFiles, setSelectedFiles] = useState([]); const [selectedFolders, setSelectedFolders] = useState([]); const [isLoading, setIsLoading] = useState(false); const [userEmail, setUserEmail] = useState(''); const [isConnected, setIsConnected] = useState(false); const [authError, setAuthError] = useState(''); const [accessToken, setAccessToken] = useState(null); const [isValidating, setIsValidating] = useState(false); const [openPicker] = useDrivePicker(); useEffect(() => { const sessionToken = getSessionToken('google_drive'); if (sessionToken) { setIsValidating(true); setIsConnected(true); // Optimistically set as connected for skeleton validateSession(sessionToken); } }, [token]); const validateSession = async (sessionToken: string) => { try { const validateResponse = await validateProviderSession( token, 'google_drive', ); if (!validateResponse.ok) { setIsConnected(false); setAuthError( t('modals.uploadDoc.connectors.googleDrive.sessionExpired'), ); setIsValidating(false); return false; } const validateData = await validateResponse.json(); if (validateData.success) { setUserEmail( validateData.user_email || t('modals.uploadDoc.connectors.auth.connectedUser'), ); setIsConnected(true); setAuthError(''); setAccessToken(validateData.access_token || null); setIsValidating(false); return true; } else { setIsConnected(false); setAuthError( validateData.error || t('modals.uploadDoc.connectors.googleDrive.sessionExpiredGeneric'), ); setIsValidating(false); return false; } } catch (error) { console.error('Error validating session:', error); setAuthError(t('modals.uploadDoc.connectors.googleDrive.validateFailed')); setIsConnected(false); setIsValidating(false); return false; } }; const handleOpenPicker = async () => { setIsLoading(true); const sessionToken = getSessionToken('google_drive'); if (!sessionToken) { setAuthError(t('modals.uploadDoc.connectors.googleDrive.noSession')); setIsLoading(false); return; } if (!accessToken) { setAuthError(t('modals.uploadDoc.connectors.googleDrive.noAccessToken')); setIsLoading(false); return; } try { const clientId: string = import.meta.env.VITE_GOOGLE_CLIENT_ID; // Derive appId from clientId (extract numeric part before first dash) const appId = clientId ? clientId.split('-')[0] : null; if (!clientId || !appId) { console.error('Missing Google Drive configuration'); setIsLoading(false); return; } openPicker({ clientId: clientId, developerKey: '', appId: appId, setSelectFolderEnabled: false, viewId: 'DOCS', showUploadView: false, showUploadFolders: false, supportDrives: false, multiselect: true, token: accessToken, viewMimeTypes: 'application/vnd.google-apps.document,application/vnd.google-apps.presentation,application/vnd.google-apps.spreadsheet,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.presentationml.presentation,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/msword,application/vnd.ms-powerpoint,application/vnd.ms-excel,text/plain,text/csv,text/html,text/markdown,text/x-rst,application/json,application/epub+zip,application/rtf,image/jpeg,image/jpg,image/png', callbackFunction: (data: any) => { setIsLoading(false); if (data.action === 'picked') { const docs = data.docs; const newFiles: PickerFile[] = []; const newFolders: PickerFile[] = []; docs.forEach((doc: any) => { const item = { id: doc.id, name: doc.name, mimeType: doc.mimeType, iconUrl: doc.iconUrl || '', description: doc.description, sizeBytes: doc.sizeBytes, }; if (doc.mimeType === 'application/vnd.google-apps.folder') { newFolders.push(item); } else { newFiles.push(item); } }); setSelectedFiles((prevFiles) => { const existingFileIds = new Set(prevFiles.map((file) => file.id)); const uniqueNewFiles = newFiles.filter( (file) => !existingFileIds.has(file.id), ); return [...prevFiles, ...uniqueNewFiles]; }); setSelectedFolders((prevFolders) => { const existingFolderIds = new Set( prevFolders.map((folder) => folder.id), ); const uniqueNewFolders = newFolders.filter( (folder) => !existingFolderIds.has(folder.id), ); return [...prevFolders, ...uniqueNewFolders]; }); onSelectionChange( [...selectedFiles, ...newFiles].map((file) => file.id), [...selectedFolders, ...newFolders].map((folder) => folder.id), ); } }, }); } catch (error) { console.error('Error opening picker:', error); setAuthError(t('modals.uploadDoc.connectors.googleDrive.pickerFailed')); setIsLoading(false); } }; const handleDisconnect = async () => { const sessionToken = getSessionToken('google_drive'); if (sessionToken) { try { const apiHost = import.meta.env.VITE_API_HOST; await fetch(`${apiHost}/api/connectors/disconnect`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}`, }, body: JSON.stringify({ provider: 'google_drive', session_token: sessionToken, }), }); } catch (err) { console.error('Error disconnecting from Google Drive:', err); } } removeSessionToken('google_drive'); setIsConnected(false); setSelectedFiles([]); setSelectedFolders([]); setAccessToken(null); setUserEmail(''); setAuthError(''); onSelectionChange([], []); }; return (
{isValidating ? ( <> ) : ( <> { setUserEmail( data.user_email || t('modals.uploadDoc.connectors.auth.connectedUser'), ); setIsConnected(true); setAuthError(''); if (data.session_token) { setSessionToken('google_drive', data.session_token); validateSession(data.session_token); } }} onError={(error) => { setAuthError(error); setIsConnected(false); }} isConnected={isConnected} userEmail={userEmail} onDisconnect={handleDisconnect} errorMessage={authError} /> {isConnected && (

{t('modals.uploadDoc.connectors.googleDrive.selectedFiles')}

{selectedFiles.length === 0 && selectedFolders.length === 0 ? (

{t( 'modals.uploadDoc.connectors.googleDrive.noFilesSelected', )}

) : (
{selectedFolders.length > 0 && (

{t('modals.uploadDoc.connectors.googleDrive.folders')}

{selectedFolders.map((folder) => (
{t( {folder.name}
))}
)} {selectedFiles.length > 0 && (

{t('modals.uploadDoc.connectors.googleDrive.files')}

{selectedFiles.map((file) => (
{t( {file.name}
))}
)}
)}
)} )}
); }; export default GoogleDrivePicker;