import React, { useState, useEffect } from 'react'; import useDrivePicker from 'react-google-drive-picker'; import ConnectorAuth from './ConnectorAuth'; import { getSessionToken, setSessionToken, removeSessionToken } from '../utils/providerUtils'; 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 [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 apiHost = import.meta.env.VITE_API_HOST; const validateResponse = await fetch(`${apiHost}/api/connectors/validate-session`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ provider: 'google_drive', session_token: sessionToken }) }); if (!validateResponse.ok) { setIsConnected(false); setAuthError('Session expired. Please reconnect to Google Drive.'); setIsValidating(false); return false; } const validateData = await validateResponse.json(); if (validateData.success) { setUserEmail(validateData.user_email || 'Connected User'); setIsConnected(true); setAuthError(''); setAccessToken(validateData.access_token || null); setIsValidating(false); return true; } else { setIsConnected(false); setAuthError(validateData.error || 'Session expired. Please reconnect your account.'); setIsValidating(false); return false; } } catch (error) { console.error('Error validating session:', error); setAuthError('Failed to validate session. Please reconnect.'); setIsConnected(false); setIsValidating(false); return false; } }; const handleOpenPicker = async () => { setIsLoading(true); const sessionToken = getSessionToken('google_drive'); if (!sessionToken) { setAuthError('No valid session found. Please reconnect to Google Drive.'); setIsLoading(false); return; } if (!accessToken) { setAuthError('No access token available. Please reconnect to Google Drive.'); setIsLoading(false); return; } try { const clientId: string = import.meta.env.VITE_GOOGLE_CLIENT_ID; const developerKey : string = import.meta.env.VITE_GOOGLE_API_KEY; // Derive appId from clientId (extract numeric part before first dash) const appId = clientId ? clientId.split('-')[0] : null; if (!clientId || !developerKey || !appId) { console.error('Missing Google Drive configuration'); setIsLoading(false); return; } openPicker({ clientId: clientId, developerKey: "", appId: appId, setSelectFolderEnabled: true, viewId: "DOCS", showUploadView: false, showUploadFolders: true, supportDrives: false, multiselect: true, token: accessToken, viewMimeTypes: 'application/vnd.google-apps.folder,application/vnd.google-apps.document,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,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('Failed to open file picker. Please try again.'); 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([], []); }; const ConnectedStateSkeleton = () => (
); const FilesSectionSkeleton = () => (
); return (
{isValidating ? ( <> ) : ( <> { setUserEmail(data.user_email || 'Connected User'); 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 && (

Selected Files

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

No files or folders selected

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

Folders

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

Files

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