366 lines
25 KiB
JavaScript
366 lines
25 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import { fetchOrganizationUsage } from '../api/organization';
|
|
import { useNotification } from '../context/NotificationContext';
|
|
import '../assets/organization-animations.css';
|
|
|
|
export default function Organization() {
|
|
const [info, setInfo] = useState(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState('');
|
|
const { showMessage } = useNotification();
|
|
// Estado para animar el progress bar
|
|
const [animatedPercent, setAnimatedPercent] = useState(0);
|
|
|
|
useEffect(() => {
|
|
const token = localStorage.getItem('access');
|
|
if (!token) {
|
|
setError('No se encontró el token de acceso.');
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
fetchOrganizationUsage(token)
|
|
.then(data => {
|
|
setInfo(data);
|
|
setLoading(false);
|
|
})
|
|
.catch(err => {
|
|
if (err.message === 'SESSION_EXPIRED') {
|
|
localStorage.removeItem('access');
|
|
localStorage.removeItem('refresh');
|
|
showMessage('Tu sesión ha expirado, por favor inicia sesión de nuevo.', 'error');
|
|
setTimeout(() => {
|
|
window.location.href = '/login';
|
|
}, 2000);
|
|
} else {
|
|
setError(err.message);
|
|
}
|
|
setLoading(false);
|
|
});
|
|
}, [showMessage]);
|
|
|
|
// Animación del progress bar
|
|
useEffect(() => {
|
|
if (!info) return;
|
|
const used = info.espacio_utilizado_gb || 0;
|
|
const limit = info.limite_almacenamiento_gb || 1;
|
|
const percent = Math.min(100, (100 * used / limit));
|
|
let start = 0;
|
|
// Si ya está en el valor correcto, no animar
|
|
if (animatedPercent === percent) return;
|
|
// Animar de 0 a percent
|
|
const step = () => {
|
|
setAnimatedPercent(prev => {
|
|
if (prev < percent) {
|
|
const next = Math.min(prev + 2, percent); // velocidad de animación
|
|
if (next < percent) {
|
|
setTimeout(step, 10);
|
|
}
|
|
return next;
|
|
} else {
|
|
return percent;
|
|
}
|
|
});
|
|
};
|
|
setAnimatedPercent(0);
|
|
setTimeout(step, 200); // pequeño delay para que se note la animación
|
|
// eslint-disable-next-line
|
|
}, [info]);
|
|
|
|
if (loading) return (
|
|
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 flex items-center justify-center p-4">
|
|
<div className="text-center bg-white rounded-3xl shadow-2xl border border-gray-100 p-8 sm:p-12 max-w-md mx-auto">
|
|
<div className="relative inline-block mb-6">
|
|
<svg className="animate-spin h-16 w-16 text-blue-600 mx-auto" fill="none" viewBox="0 0 24 24">
|
|
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"></circle>
|
|
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
<div className="absolute inset-0 bg-blue-500/10 rounded-full blur-xl animate-pulse"></div>
|
|
</div>
|
|
<h3 className="text-xl font-bold text-gray-900 mb-2">Cargando información</h3>
|
|
<p className="text-gray-600">Obteniendo datos de la organización...</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
if (error) return (
|
|
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 flex items-center justify-center p-4">
|
|
<div className="bg-white rounded-3xl shadow-2xl border border-red-100 p-8 sm:p-12 max-w-md mx-auto relative overflow-hidden">
|
|
<div className="absolute inset-0 bg-gradient-to-br from-red-500/5 to-orange-500/5"></div>
|
|
<div className="relative z-10 text-center">
|
|
<div className="bg-red-100 rounded-full p-4 w-16 h-16 mx-auto mb-6 flex items-center justify-center">
|
|
<svg className="h-8 w-8 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
|
</svg>
|
|
</div>
|
|
<h3 className="text-xl font-bold text-gray-900 mb-3">Error al cargar</h3>
|
|
<p className="text-red-700 font-medium bg-red-50 rounded-xl p-3 border border-red-200">{error}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gradient-to-br from-slate-50 via-blue-50 to-indigo-100 p-4 sm:p-6 lg:p-8">
|
|
<div className="max-w-7xl mx-auto">
|
|
{/* Header mejorado y decorativo */}
|
|
<div className="mb-6 sm:mb-8 relative overflow-hidden rounded-3xl shadow-2xl bg-gradient-to-r from-blue-600 via-blue-700 to-blue-800 p-6 sm:p-8 flex items-center gap-4 sm:gap-6 animate-fadein-slideup opacity-0" style={{ animation: 'fadein-slideup 0.7s cubic-bezier(0.22,1,0.36,1) 0.05s forwards' }}>
|
|
<div className="flex-shrink-0 bg-white/20 backdrop-blur-sm rounded-full p-3 sm:p-4 shadow-lg animate-bounce-slow">
|
|
<svg className="h-8 w-8 sm:h-10 sm:w-10 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M3 7c0 2.21 3.582 4 8 4s8-1.79 8-4M3 7c0-2.21 3.582-4 8-4s8 1.79 8 4" />
|
|
</svg>
|
|
</div>
|
|
<div className="flex-1 min-w-0">
|
|
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-extrabold text-white tracking-tight mb-1 flex flex-col sm:flex-row sm:items-center gap-2">
|
|
<span>Mi Organización</span>
|
|
{info && (
|
|
<span className="inline-block bg-white/20 backdrop-blur-sm text-white text-xs sm:text-sm font-semibold px-3 py-1 rounded-full shadow-lg animate-fade-in">
|
|
{info.total_usuarios} usuarios
|
|
</span>
|
|
)}
|
|
</h1>
|
|
<p className="text-sm sm:text-lg text-blue-100 font-medium leading-relaxed">Información y métricas de uso de tu organización</p>
|
|
</div>
|
|
{/* Efectos decorativos de fondo modernos */}
|
|
<div className="absolute -top-10 -right-10 opacity-20 pointer-events-none select-none">
|
|
<div className="w-32 h-32 bg-white/10 rounded-full blur-xl"></div>
|
|
</div>
|
|
<div className="absolute -bottom-6 -left-6 opacity-15 pointer-events-none select-none">
|
|
<div className="w-24 h-24 bg-white/10 rounded-full blur-lg"></div>
|
|
</div>
|
|
{/* Partículas flotantes */}
|
|
<div className="absolute inset-0 overflow-hidden pointer-events-none">
|
|
<div className="absolute top-1/4 left-1/4 w-2 h-2 bg-white/30 rounded-full animate-ping"></div>
|
|
<div className="absolute top-3/4 right-1/3 w-1 h-1 bg-white/40 rounded-full animate-pulse"></div>
|
|
<div className="absolute top-1/2 right-1/4 w-3 h-3 bg-white/20 rounded-full animate-bounce"></div>
|
|
</div>
|
|
{/* Animación personalizada para el icono y contador */}
|
|
<style>{`
|
|
@keyframes bounce-slow {
|
|
0%, 100% { transform: translateY(0) scale(1); }
|
|
50% { transform: translateY(-8px) scale(1.05); }
|
|
}
|
|
.animate-bounce-slow {
|
|
animation: bounce-slow 3s infinite;
|
|
}
|
|
@keyframes fade-in {
|
|
from { opacity: 0; transform: scale(0.9) translateY(10px); }
|
|
to { opacity: 1; transform: scale(1) translateY(0); }
|
|
}
|
|
.animate-fade-in {
|
|
animation: fade-in 0.8s ease-out;
|
|
}
|
|
@keyframes float {
|
|
0%, 100% { transform: translateY(0px) rotate(0deg); }
|
|
33% { transform: translateY(-10px) rotate(2deg); }
|
|
66% { transform: translateY(-5px) rotate(-1deg); }
|
|
}
|
|
.animate-float {
|
|
animation: float 4s ease-in-out infinite;
|
|
}
|
|
`}</style>
|
|
</div>
|
|
|
|
{/* Barra de almacenamiento con color y progress bar */}
|
|
<div className="mb-6 sm:mb-10">
|
|
<div className="bg-white rounded-3xl shadow-2xl border border-gray-100 p-4 sm:p-6 lg:p-8 relative overflow-hidden">
|
|
<div className="absolute inset-0 bg-gradient-to-br from-green-500/3 to-blue-500/3"></div>
|
|
<div className="relative z-10">
|
|
<h2 className="text-xl sm:text-2xl font-bold text-gray-900 mb-4 sm:mb-6 flex items-center">
|
|
<div className="bg-gradient-to-br from-green-500 to-emerald-600 rounded-full p-2 sm:p-3 shadow-lg mr-3">
|
|
<svg className="w-5 h-5 sm:w-6 sm:h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4" />
|
|
</svg>
|
|
</div>
|
|
Uso de Almacenamiento
|
|
</h2>
|
|
|
|
{/* Estadísticas rápidas */}
|
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 mb-6">
|
|
<div className="bg-gradient-to-br from-green-50 to-emerald-50 rounded-2xl p-4 border border-green-100">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-3 h-3 bg-green-500 rounded-full"></div>
|
|
<span className="text-sm font-medium text-gray-600">Usado</span>
|
|
</div>
|
|
<div className="text-2xl font-bold text-green-700 mt-1">
|
|
{info?.espacio_utilizado_gb?.toFixed(2)} GB
|
|
</div>
|
|
</div>
|
|
<div className="bg-gradient-to-br from-blue-50 to-blue-100 rounded-2xl p-4 border border-blue-100">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-3 h-3 bg-blue-500 rounded-full"></div>
|
|
<span className="text-sm font-medium text-gray-600">Disponible</span>
|
|
</div>
|
|
<div className="text-2xl font-bold text-blue-700 mt-1">
|
|
{info?.espacio_disponible_bytes ? (info.espacio_disponible_bytes / (1024 * 1024 * 1024)).toFixed(2) : 0} GB
|
|
</div>
|
|
</div>
|
|
<div className="bg-gradient-to-br from-gray-50 to-slate-50 rounded-2xl p-4 border border-gray-100">
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-3 h-3 bg-gray-500 rounded-full"></div>
|
|
<span className="text-sm font-medium text-gray-600">Límite</span>
|
|
</div>
|
|
<div className="text-2xl font-bold text-gray-700 mt-1">
|
|
{info?.limite_almacenamiento_gb} GB
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Barra de progreso mejorada */}
|
|
<div className="relative w-full h-6 sm:h-8 bg-gray-200 rounded-full overflow-hidden shadow-inner">
|
|
{/* Progress bar de color dinámico según porcentaje */}
|
|
{(() => {
|
|
const used = info?.espacio_utilizado_gb || 0;
|
|
const limit = info?.limite_almacenamiento_gb || 1;
|
|
const percent = Math.min(100, (100 * used / limit));
|
|
let barColor = 'linear-gradient(90deg, #22c55e 0%, #16a34a 100%)'; // verde
|
|
if (animatedPercent >= 80) {
|
|
barColor = 'linear-gradient(90deg, #ef4444 0%, #b91c1c 100%)'; // rojo
|
|
} else if (animatedPercent >= 50) {
|
|
barColor = 'linear-gradient(90deg, #f59e42 0%, #d97706 100%)'; // naranja
|
|
}
|
|
return (
|
|
<div
|
|
className="absolute left-0 top-0 h-full rounded-full shadow-lg transition-all duration-700 flex items-center justify-end pr-3"
|
|
style={{ width: `${animatedPercent}%`, background: barColor }}
|
|
>
|
|
{animatedPercent > 20 && (
|
|
<span className="text-white font-bold text-xs sm:text-sm">
|
|
{animatedPercent.toFixed(1)}%
|
|
</span>
|
|
)}
|
|
</div>
|
|
);
|
|
})()}
|
|
{/* Indicador de porcentaje fuera de la barra si es muy pequeña */}
|
|
{animatedPercent <= 20 && (
|
|
<div className="absolute right-3 top-1/2 transform -translate-y-1/2">
|
|
<span className="text-gray-600 font-bold text-xs sm:text-sm">
|
|
{animatedPercent.toFixed(1)}%
|
|
</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 xl:grid-cols-4 gap-4 sm:gap-6">
|
|
{/* Tarjeta Organización */}
|
|
<div className="group bg-white rounded-2xl shadow-lg border border-gray-100 p-4 sm:p-6 flex flex-col items-center min-w-0 opacity-0 translate-y-6 animate-fadein-slideup transition-all duration-500 hover:scale-105 hover:shadow-2xl relative overflow-hidden" style={{ animationDelay: '0ms', animationFillMode: 'forwards', transitionTimingFunction: 'cubic-bezier(0.22,1,0.36,1)' }}>
|
|
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/5 to-blue-600/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
|
<div className="relative z-10 w-full flex flex-col items-center">
|
|
<div className="w-12 h-12 sm:w-14 sm:h-14 bg-gradient-to-br from-blue-500 to-blue-700 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow duration-300 mb-3">
|
|
<svg className="w-6 h-6 sm:w-7 sm:h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M3 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M3 7c0 2.21 3.582 4 8 4s8-1.79 8-4M3 7c0-2.21 3.582-4 8-4s8 1.79 8 4" />
|
|
</svg>
|
|
</div>
|
|
<span className="text-xs sm:text-sm font-medium text-gray-500 uppercase tracking-wide text-center mb-2">Organización</span>
|
|
<span className="text-lg sm:text-xl lg:text-2xl font-bold text-gray-900 text-center break-words">{info?.organizacion}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Tarjeta Usuarios */}
|
|
<div className="group bg-white rounded-2xl shadow-lg border border-gray-100 p-4 sm:p-6 flex flex-col items-center min-w-0 opacity-0 translate-y-6 animate-fadein-slideup transition-all duration-500 hover:scale-105 hover:shadow-2xl relative overflow-hidden" style={{ animationDelay: '50ms', animationFillMode: 'forwards', transitionTimingFunction: 'cubic-bezier(0.22,1,0.36,1)' }}>
|
|
<div className="absolute inset-0 bg-gradient-to-br from-green-500/5 to-emerald-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
|
<div className="relative z-10 w-full flex flex-col items-center">
|
|
<div className="w-12 h-12 sm:w-14 sm:h-14 bg-gradient-to-br from-green-500 to-green-700 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow duration-300 mb-3">
|
|
<svg className="w-6 h-6 sm:w-7 sm:h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M17 20h5v-2a4 4 0 00-3-3.87M9 20H4v-2a4 4 0 013-3.87m9-4a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
</svg>
|
|
</div>
|
|
<span className="text-xs sm:text-sm font-medium text-gray-500 uppercase tracking-wide text-center mb-2">Usuarios</span>
|
|
<span className="text-2xl sm:text-3xl font-bold text-gray-900">{info?.total_usuarios}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Tarjeta Pedimentos */}
|
|
<div className="group bg-white rounded-2xl shadow-lg border border-gray-100 p-4 sm:p-6 flex flex-col items-center min-w-0 opacity-0 translate-y-6 animate-fadein-slideup transition-all duration-500 hover:scale-105 hover:shadow-2xl relative overflow-hidden" style={{ animationDelay: '100ms', animationFillMode: 'forwards', transitionTimingFunction: 'cubic-bezier(0.22,1,0.36,1)' }}>
|
|
<div className="absolute inset-0 bg-gradient-to-br from-orange-500/5 to-amber-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
|
<div className="relative z-10 w-full flex flex-col items-center">
|
|
<div className="w-12 h-12 sm:w-14 sm:h-14 bg-gradient-to-br from-orange-500 to-orange-600 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow duration-300 mb-3">
|
|
<svg className="w-6 h-6 sm:w-7 sm:h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
</svg>
|
|
</div>
|
|
<span className="text-xs sm:text-sm font-medium text-gray-500 uppercase tracking-wide text-center mb-2">Pedimentos</span>
|
|
<span className="text-2xl sm:text-3xl font-bold text-gray-900">{info?.total_pedimentos}</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Tarjeta Documentos */}
|
|
<div className="group bg-white rounded-2xl shadow-lg border border-gray-100 p-4 sm:p-6 flex flex-col items-center min-w-0 opacity-0 translate-y-6 animate-fadein-slideup transition-all duration-500 hover:scale-105 hover:shadow-2xl relative overflow-hidden" style={{ animationDelay: '150ms', animationFillMode: 'forwards', transitionTimingFunction: 'cubic-bezier(0.22,1,0.36,1)' }}>
|
|
<div className="absolute inset-0 bg-gradient-to-br from-yellow-500/5 to-amber-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
|
<div className="relative z-10 w-full flex flex-col items-center">
|
|
<div className="w-12 h-12 sm:w-14 sm:h-14 bg-gradient-to-br from-yellow-500 to-yellow-600 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow duration-300 mb-3">
|
|
<svg className="w-6 h-6 sm:w-7 sm:h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M7 7h10M7 11h10M7 15h6M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
|
</svg>
|
|
</div>
|
|
<span className="text-xs sm:text-sm font-medium text-gray-500 uppercase tracking-wide text-center mb-2">Documentos</span>
|
|
<span className="text-2xl sm:text-3xl font-bold text-gray-900">{info?.total_documentos}</span>
|
|
</div>
|
|
</div>
|
|
{/* Tarjeta Límite de Almacenamiento */}
|
|
<div className="group bg-white rounded-2xl shadow-lg border border-gray-100 p-4 sm:p-6 flex flex-col items-center min-w-0 opacity-0 translate-y-6 animate-fadein-slideup transition-all duration-500 hover:scale-105 hover:shadow-2xl relative overflow-hidden" style={{ animationDelay: '200ms', animationFillMode: 'forwards', transitionTimingFunction: 'cubic-bezier(0.22,1,0.36,1)' }}>
|
|
<div className="absolute inset-0 bg-gradient-to-br from-gray-500/5 to-slate-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
|
<div className="relative z-10 w-full flex flex-col items-center">
|
|
<div className="w-12 h-12 sm:w-14 sm:h-14 bg-gradient-to-br from-gray-500 to-gray-600 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow duration-300 mb-3">
|
|
<svg className="w-6 h-6 sm:w-7 sm:h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
|
</svg>
|
|
</div>
|
|
<span className="text-xs sm:text-sm font-medium text-gray-500 uppercase tracking-wide text-center mb-2">Límite de Almacenamiento</span>
|
|
<span className="text-2xl sm:text-3xl font-bold text-gray-900">{info?.limite_almacenamiento_gb} GB</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Tarjeta Espacio Utilizado */}
|
|
<div className="group bg-white rounded-2xl shadow-lg border border-gray-100 p-4 sm:p-6 flex flex-col items-center min-w-0 opacity-0 translate-y-6 animate-fadein-slideup transition-all duration-500 hover:scale-105 hover:shadow-2xl relative overflow-hidden" style={{ animationDelay: '250ms', animationFillMode: 'forwards', transitionTimingFunction: 'cubic-bezier(0.22,1,0.36,1)' }}>
|
|
<div className="absolute inset-0 bg-gradient-to-br from-pink-500/5 to-rose-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
|
<div className="relative z-10 w-full flex flex-col items-center">
|
|
<div className="w-12 h-12 sm:w-14 sm:h-14 bg-gradient-to-br from-pink-500 to-pink-600 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow duration-300 mb-3">
|
|
<svg className="w-6 h-6 sm:w-7 sm:h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
|
</svg>
|
|
</div>
|
|
<span className="text-xs sm:text-sm font-medium text-gray-500 uppercase tracking-wide text-center mb-2">Espacio Utilizado</span>
|
|
<span className="text-2xl sm:text-3xl font-bold text-gray-900">{info?.espacio_utilizado_gb?.toFixed(2)} GB</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Tarjeta Espacio Disponible */}
|
|
<div className="group bg-white rounded-2xl shadow-lg border border-gray-100 p-4 sm:p-6 flex flex-col items-center min-w-0 opacity-0 translate-y-6 animate-fadein-slideup transition-all duration-500 hover:scale-105 hover:shadow-2xl relative overflow-hidden" style={{ animationDelay: '300ms', animationFillMode: 'forwards', transitionTimingFunction: 'cubic-bezier(0.22,1,0.36,1)' }}>
|
|
<div className="absolute inset-0 bg-gradient-to-br from-emerald-500/5 to-green-500/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
|
<div className="relative z-10 w-full flex flex-col items-center">
|
|
<div className="w-12 h-12 sm:w-14 sm:h-14 bg-gradient-to-br from-emerald-500 to-green-600 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow duration-300 mb-3">
|
|
<svg className="w-6 h-6 sm:w-7 sm:h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z" />
|
|
</svg>
|
|
</div>
|
|
<span className="text-xs sm:text-sm font-medium text-gray-500 uppercase tracking-wide text-center mb-2">Espacio Disponible</span>
|
|
<span className="text-2xl sm:text-3xl font-bold text-gray-900">{info?.espacio_disponible_bytes ? (info.espacio_disponible_bytes / (1024 * 1024 * 1024)).toFixed(2) : 0} GB</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Tarjeta Porcentaje Utilizado */}
|
|
<div className="group bg-white rounded-2xl shadow-lg border border-gray-100 p-4 sm:p-6 flex flex-col items-center min-w-0 opacity-0 translate-y-6 animate-fadein-slideup transition-all duration-500 hover:scale-105 hover:shadow-2xl relative overflow-hidden" style={{ animationDelay: '350ms', animationFillMode: 'forwards', transitionTimingFunction: 'cubic-bezier(0.22,1,0.36,1)' }}>
|
|
<div className="absolute inset-0 bg-gradient-to-br from-blue-500/5 to-blue-600/5 opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
|
|
<div className="relative z-10 w-full flex flex-col items-center">
|
|
<div className="w-12 h-12 sm:w-14 sm:h-14 bg-gradient-to-br from-blue-500 to-blue-700 rounded-2xl flex items-center justify-center shadow-lg group-hover:shadow-xl transition-shadow duration-300 mb-3">
|
|
<svg className="w-6 h-6 sm:w-7 sm:h-7 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<circle cx="12" cy="12" r="10" strokeWidth="2" />
|
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M12 6v6l4 2" />
|
|
</svg>
|
|
</div>
|
|
<span className="text-xs sm:text-sm font-medium text-gray-500 uppercase tracking-wide text-center mb-2">Porcentaje Utilizado</span>
|
|
<span className="text-2xl sm:text-3xl font-bold text-gray-900">{info?.porcentaje_utilizado}%</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* ...existing code... */}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|