template-saas/apps/frontend/src/components/storage/StorageUsageCard.tsx
rckrdmrd 50a821a415
Some checks failed
CI / Backend CI (push) Has been cancelled
CI / Frontend CI (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / CI Summary (push) Has been cancelled
[SIMCO-V38] feat: Actualizar a SIMCO v3.8.0
- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8
- Actualizaciones de configuracion

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 08:53:08 -06:00

110 lines
3.7 KiB
TypeScript

import { HardDrive, Folder } from 'lucide-react';
import { useStorageUsage } from '@/hooks/useStorage';
interface StorageUsageCardProps {
className?: string;
}
function formatBytes(bytes: number): string {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
}
export function StorageUsageCard({ className = '' }: StorageUsageCardProps) {
const { data, isLoading, error } = useStorageUsage();
if (isLoading) {
return (
<div className={`bg-white rounded-lg border p-6 ${className}`}>
<div className="animate-pulse">
<div className="h-4 bg-gray-200 rounded w-1/3 mb-4" />
<div className="h-8 bg-gray-200 rounded w-1/2 mb-4" />
<div className="h-2 bg-gray-200 rounded w-full" />
</div>
</div>
);
}
if (error || !data) {
return (
<div className={`bg-white rounded-lg border p-6 ${className}`}>
<p className="text-gray-500">Unable to load storage usage</p>
</div>
);
}
const usedPercent = data.maxBytes ? data.usagePercent : 0;
const progressColor =
usedPercent > 90 ? 'bg-red-500' : usedPercent > 70 ? 'bg-yellow-500' : 'bg-blue-500';
return (
<div className={`bg-white rounded-lg border p-6 ${className}`}>
<div className="flex items-center gap-3 mb-4">
<div className="p-2 bg-blue-100 rounded-lg">
<HardDrive className="w-5 h-5 text-blue-600" />
</div>
<h3 className="font-semibold text-gray-900">Storage Usage</h3>
</div>
{/* Usage stats */}
<div className="space-y-4">
<div>
<div className="flex justify-between text-sm mb-1">
<span className="text-gray-600">
{formatBytes(data.totalBytes)} used
</span>
{data.maxBytes && (
<span className="text-gray-500">
of {formatBytes(data.maxBytes)}
</span>
)}
</div>
{data.maxBytes && (
<div className="w-full bg-gray-200 rounded-full h-2">
<div
className={`${progressColor} h-2 rounded-full transition-all duration-300`}
style={{ width: `${Math.min(usedPercent, 100)}%` }}
/>
</div>
)}
</div>
{/* Files count */}
<div className="flex justify-between text-sm">
<span className="text-gray-600">Total files</span>
<span className="font-medium">{data.totalFiles.toLocaleString()}</span>
</div>
{/* Max file size */}
{data.maxFileSize && (
<div className="flex justify-between text-sm">
<span className="text-gray-600">Max file size</span>
<span className="font-medium">{formatBytes(data.maxFileSize)}</span>
</div>
)}
{/* Files by folder */}
{Object.keys(data.filesByFolder).length > 0 && (
<div className="pt-4 border-t">
<h4 className="text-sm font-medium text-gray-900 mb-2">By Folder</h4>
<div className="space-y-2">
{Object.entries(data.filesByFolder).map(([folder, count]) => (
<div key={folder} className="flex items-center justify-between text-sm">
<div className="flex items-center gap-2 text-gray-600">
<Folder className="w-4 h-4" />
<span>{folder}</span>
</div>
<span className="font-medium">{count}</span>
</div>
))}
</div>
</div>
)}
</div>
</div>
);
}