Implements cloud-based file storage for plant photos, documents, and certificates: Storage Layer: - Multi-provider support (AWS S3, Cloudflare R2, MinIO, local filesystem) - S3-compatible provider with presigned URL generation - Local storage provider for development with signed URL verification - Configurable via environment variables Image Processing: - Automatic thumbnail generation (150x150, 300x300, 600x600, 1200x1200) - WebP conversion for optimized file sizes - EXIF data extraction for image metadata - Image optimization with Sharp API Endpoints: - POST /api/upload/image - Upload images with automatic processing - POST /api/upload/document - Upload documents (PDF, DOC, DOCX) - POST /api/upload/presigned - Get presigned URLs for direct uploads - GET/DELETE /api/upload/[fileId] - File management UI Components: - ImageUploader - Drag & drop image upload with preview - PhotoGallery - Grid gallery with lightbox view - DocumentUploader - Document upload with file type icons - ProgressBar - Animated upload progress indicator Database: - FileStore service with in-memory storage (Prisma schema ready for Agent 2) - File metadata tracking with soft delete support - Category-based file organization
63 lines
1.4 KiB
TypeScript
63 lines
1.4 KiB
TypeScript
/**
|
|
* Progress Bar Component
|
|
* Agent 3: File Upload & Storage System
|
|
*
|
|
* Animated progress bar for uploads
|
|
*/
|
|
|
|
import React from 'react';
|
|
|
|
interface ProgressBarProps {
|
|
progress: number;
|
|
showPercentage?: boolean;
|
|
color?: 'green' | 'blue' | 'purple' | 'orange';
|
|
size?: 'sm' | 'md' | 'lg';
|
|
animated?: boolean;
|
|
className?: string;
|
|
}
|
|
|
|
const colorClasses = {
|
|
green: 'bg-green-500',
|
|
blue: 'bg-blue-500',
|
|
purple: 'bg-purple-500',
|
|
orange: 'bg-orange-500',
|
|
};
|
|
|
|
const sizeClasses = {
|
|
sm: 'h-1',
|
|
md: 'h-2',
|
|
lg: 'h-3',
|
|
};
|
|
|
|
export function ProgressBar({
|
|
progress,
|
|
showPercentage = false,
|
|
color = 'green',
|
|
size = 'md',
|
|
animated = true,
|
|
className = '',
|
|
}: ProgressBarProps) {
|
|
const clampedProgress = Math.min(100, Math.max(0, progress));
|
|
|
|
return (
|
|
<div className={className}>
|
|
<div className={`bg-gray-200 rounded-full overflow-hidden ${sizeClasses[size]}`}>
|
|
<div
|
|
className={`
|
|
${colorClasses[color]} ${sizeClasses[size]} rounded-full
|
|
transition-all duration-300 ease-out
|
|
${animated && clampedProgress < 100 ? 'animate-pulse' : ''}
|
|
`}
|
|
style={{ width: `${clampedProgress}%` }}
|
|
/>
|
|
</div>
|
|
{showPercentage && (
|
|
<p className="text-xs text-gray-500 mt-1 text-right">
|
|
{Math.round(clampedProgress)}%
|
|
</p>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default ProgressBar;
|