Overview
SGD-MCS provides a comprehensive document upload system with drag-and-drop support, automatic UUID generation, and integration with Google Drive. Documents can be uploaded directly to entity folders or to the document history registry.
Upload Components
The system includes two main upload interfaces:
- DocumentUpload Component - Standalone document registry uploader
- FileUploader Component - Drive folder file manager
Basic Document Upload
Using the DocumentUpload Component
Location: Fronted/src/components/common/DocumentUpload.jsx
This component provides a simple drag-and-drop interface for uploading documents to the system registry.
Access Upload Interface
The document upload component can be used anywhere in the application:<DocumentUpload
onSuccess={handleUploadSuccess}
beneficiaryId="EST0001"
beneficiaryName="Juan Perez"
/>
Drag or Select File
You can either:
- Drag a file into the upload zone
- Click the zone to open the file picker
// Fronted/src/components/common/DocumentUpload.jsx:20
const handleDrop = (e) => {
e.preventDefault();
e.stopPropagation();
setDragActive(false);
if (e.dataTransfer.files && e.dataTransfer.files[0]) {
setFile(e.dataTransfer.files[0]);
}
};
Select Document Type
Choose the document category from the dropdown:
- Cédula (ID Card)
- Tesis / Proyecto (Thesis/Project)
- Acta de Grado (Graduation Certificate)
- Diploma
- Certificado (Certificate)
- Otros (Others)
// Fronted/src/components/common/DocumentUpload.jsx:105
<select value={docType} onChange={e => setDocType(e.target.value)}>
<option>Cédula</option>
<option>Tesis / Proyecto</option>
<option>Acta de Grado</option>
<option>Diploma</option>
<option>Certificado</option>
<option>Otros</option>
</select>
Upload Document
Click Confirmar Carga to upload. The system:
- Generates a UUID for the file
- Creates metadata (size, mime type, extension)
- Registers in document history
- Displays success notification
// Fronted/src/components/common/DocumentUpload.jsx:40
const uuid = crypto.randomUUID();
const fileData = {
url: `https://storage.nexodo.com/archives/${uuid}.${file.name.split('.').pop()}`,
peso: `${(file.size / (1024 * 1024)).toFixed(2)} MB`,
tipo_mime: file.type,
nombre_original: file.name,
extension: file.name.split('.').pop()
};
Uploading to Google Drive Folders
Using the FileUploader Component
Location: Fronted/src/pages/repository/FileUploader.jsx
This component uploads files directly to Google Drive folders associated with entities.
Navigate to Entity
Open a student, teacher, or other entity detail page. The system displays the linked Drive folder.
Click Upload Button
Click SUBIR ARCHIVO in the folder explorer section:// Fronted/src/components/common/FolderExplorer.jsx:85
<button onClick={() => setShowUploader(true)}>
<Upload size={14} />
SUBIR ARCHIVO
</button>
Select Files
The FileUploader modal opens. You can:
- Select multiple files at once
- Drag and drop files
- See a live preview before upload
Confirm Upload
Click Subir Archivos to upload to Drive. The backend processes each file:// Backend/services/DriveFileManager.js
function uploadFile(folderId, fileData) {
const folder = DriveApp.getFolderById(folderId);
const blob = Utilities.newBlob(
Utilities.base64Decode(fileData.content),
fileData.mimeType,
fileData.name
);
const file = folder.createFile(blob);
return {
id: file.getId(),
url: file.getUrl(),
name: file.getName(),
size: file.getSize()
};
}
The system automatically collects file metadata during upload:
// Fronted/src/components/common/DocumentUpload.jsx:41
const fileData = {
url: `https://storage.nexodo.com/archives/${uuid}.${file.name.split('.').pop()}`,
peso: `${(file.size / (1024 * 1024)).toFixed(2)} MB`,
tipo_mime: file.type,
nombre_original: file.name,
extension: file.name.split('.').pop()
};
Metadata Fields:
url - Storage URL with UUID
peso - File size in MB
tipo_mime - MIME type (e.g., application/pdf)
nombre_original - Original filename
extension - File extension (pdf, docx, jpg, etc.)
Document History Registry
Uploaded documents are registered in the history sheet:
// Fronted/src/components/common/DocumentUpload.jsx:49
const payload = {
ID_Documento: uuid,
ID_Beneficiario: beneficiaryId || 'GUEST',
Nombre_Beneficiario: beneficiaryName || 'Anónimo',
Tipo_Documento: docType,
Usuario_Emisor: 'Admin',
Detalle_Origen: 'Carga Manual',
Detalles_JSON: JSON.stringify(fileData),
Fecha_Registro: new Date().toISOString()
};
await api.history.create(payload);
UUID Generation
Files are automatically renamed with UUIDs to prevent duplicates and ensure unique identification.
How UUIDs Work
// Generate a new UUID
const uuid = crypto.randomUUID();
// Example: "550e8400-e29b-41d4-a716-446655440000"
// Construct storage URL
const url = `https://storage.nexodo.com/archives/${uuid}.${extension}`;
// Example: "https://storage.nexodo.com/archives/550e8400-e29b-41d4-a716-446655440000.pdf"
Benefits:
- Prevents filename conflicts
- Maintains file traceability
- Enables version control
- Simplifies storage management
Drive Folder Upload
Entity Folder Structure
When uploading to entity folders, files are organized hierarchically:
SGD_DATABASE_ROOT/
└── Estudiantes/
└── 2024-1/
└── EST0001 - Juan Perez/
├── Cedula.pdf
├── Diploma.pdf
└── Tesis_Final.docx
Uploading via API
The frontend communicates with Google Drive via the API layer:
// Fronted/src/services/api.js:255
await api.drive.uploadFile(folderId, fileData);
In development mode, this returns a mock response. In production, it calls the Google Apps Script backend.
File Type Support
SGD-MCS supports all standard file types:
- Documents: PDF, DOCX, DOC, TXT, RTF
- Spreadsheets: XLSX, XLS, CSV
- Images: JPG, PNG, GIF, BMP, SVG
- Archives: ZIP, RAR, 7Z
- Other: Any file type supported by Google Drive
Upload Validation
Frontend Validation
// Check if file exists before upload
if (!file) return;
// Validate file size (example: 50MB limit)
if (file.size > 50 * 1024 * 1024) {
toast.error('Error', 'El archivo es demasiado grande (máximo 50MB)');
return;
}
Backend Validation
// Backend validation in Google Apps Script
function uploadFile(folderId, fileData) {
try {
// Verify folder exists
const folder = DriveApp.getFolderById(folderId);
if (folder.isTrashed()) {
throw new Error('La carpeta está en la papelera');
}
// Validate file data
if (!fileData.content || !fileData.name) {
throw new Error('Datos de archivo inválidos');
}
// Create file
const file = folder.createFile(blob);
// Log action
logDocumentAction({
action: 'FILE_UPLOAD',
fileId: file.getId(),
fileName: file.getName(),
folderId: folderId
});
return { success: true, id: file.getId() };
} catch (error) {
return { success: false, message: error.toString() };
}
}
Progress Tracking
For large uploads or batch uploads, display progress:
const [uploadProgress, setUploadProgress] = useState({
current: 0,
total: 0,
status: 'idle'
});
// Update during upload
setUploadProgress({
current: i + 1,
total: files.length,
status: 'uploading'
});
Error Handling
Always implement error handling for upload operations to provide user feedback.
try {
await api.history.create(payload);
toast.success('¡Archivo Cargado!', 'El documento se ha guardado en el historial.');
setFile(null);
if (onSuccess) onSuccess();
} catch (error) {
console.error('Upload error:', error);
toast.error('Error', 'No se pudo subir el archivo.');
} finally {
setUploading(false);
}
Best Practices
- Always validate file size and type before upload
- Use UUIDs for unique file identification
- Provide clear feedback during upload process
- Implement proper error handling
- Log all upload actions for audit trail
Recommended Upload Flow
- Validate - Check file size, type, and user permissions
- Generate UUID - Create unique identifier
- Collect Metadata - Extract file information
- Upload - Send to storage/Drive
- Register - Record in document history
- Notify - Inform user of success/failure
- Cleanup - Clear temporary data
Viewing Uploaded Documents
After upload, documents can be accessed via:
- Document History - View all uploads in chronological order
- Entity Folders - Access files via Drive folder links
- Search - Find documents by name, type, or date
Next Steps