Fix dark mode for ConsumptionPage cards and AuditoriaPage table
- ConsumptionPage: Add dark mode to StatCard, filters panel, pagination, TypeBadge, BatteryIndicator, and SignalIndicator components - AuditoriaPage: Add dark mode to table tbody, details modal, action badges, success/failure badges, and pagination elements Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -86,18 +86,18 @@ export default function AuditoriaPage() {
|
||||
|
||||
const getActionColor = (action: AuditAction) => {
|
||||
const colors: Record<AuditAction, string> = {
|
||||
CREATE: "bg-green-100 text-green-800",
|
||||
UPDATE: "bg-blue-100 text-blue-800",
|
||||
DELETE: "bg-red-100 text-red-800",
|
||||
LOGIN: "bg-purple-100 text-purple-800",
|
||||
LOGOUT: "bg-gray-100 text-gray-800",
|
||||
READ: "bg-cyan-100 text-cyan-800",
|
||||
EXPORT: "bg-yellow-100 text-yellow-800",
|
||||
BULK_UPLOAD: "bg-orange-100 text-orange-800",
|
||||
STATUS_CHANGE: "bg-indigo-100 text-indigo-800",
|
||||
PERMISSION_CHANGE: "bg-pink-100 text-pink-800",
|
||||
CREATE: "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400",
|
||||
UPDATE: "bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-400",
|
||||
DELETE: "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400",
|
||||
LOGIN: "bg-purple-100 dark:bg-purple-900/30 text-purple-800 dark:text-purple-400",
|
||||
LOGOUT: "bg-gray-100 dark:bg-zinc-700 text-gray-800 dark:text-zinc-300",
|
||||
READ: "bg-cyan-100 dark:bg-cyan-900/30 text-cyan-800 dark:text-cyan-400",
|
||||
EXPORT: "bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-400",
|
||||
BULK_UPLOAD: "bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-400",
|
||||
STATUS_CHANGE: "bg-indigo-100 dark:bg-indigo-900/30 text-indigo-800 dark:text-indigo-400",
|
||||
PERMISSION_CHANGE: "bg-pink-100 dark:bg-pink-900/30 text-pink-800 dark:text-pink-400",
|
||||
};
|
||||
return colors[action] || "bg-gray-100 text-gray-800";
|
||||
return colors[action] || "bg-gray-100 dark:bg-zinc-700 text-gray-800 dark:text-zinc-300";
|
||||
};
|
||||
|
||||
const filteredLogs = logs.filter((log) => {
|
||||
@@ -248,7 +248,7 @@ export default function AuditoriaPage() {
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="bg-white divide-y divide-gray-200 dark:divide-zinc-700">
|
||||
<tbody className="bg-white dark:bg-zinc-900 divide-y divide-gray-200 dark:divide-zinc-700">
|
||||
{filteredLogs.map((log) => (
|
||||
<tr key={log.id} className="hover:bg-gray-50 dark:hover:bg-zinc-800">
|
||||
<td className="px-4 py-3 text-sm text-gray-900 dark:text-zinc-100 whitespace-nowrap">
|
||||
@@ -279,8 +279,8 @@ export default function AuditoriaPage() {
|
||||
<span
|
||||
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
|
||||
log.success
|
||||
? "bg-green-100 text-green-800"
|
||||
: "bg-red-100 text-red-800"
|
||||
? "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400"
|
||||
: "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400"
|
||||
}`}
|
||||
>
|
||||
{log.success ? "Éxito" : "Fallo"}
|
||||
@@ -307,15 +307,15 @@ export default function AuditoriaPage() {
|
||||
{/* Page Info */}
|
||||
<div className="text-sm text-gray-600 dark:text-zinc-400">
|
||||
Mostrando{" "}
|
||||
<span className="font-semibold text-gray-800">
|
||||
<span className="font-semibold text-gray-800 dark:text-zinc-200">
|
||||
{(currentPage - 1) * limit + 1}
|
||||
</span>{" "}
|
||||
a{" "}
|
||||
<span className="font-semibold text-gray-800">
|
||||
<span className="font-semibold text-gray-800 dark:text-zinc-200">
|
||||
{Math.min(currentPage * limit, total)}
|
||||
</span>{" "}
|
||||
de{" "}
|
||||
<span className="font-semibold text-gray-800">{total}</span>{" "}
|
||||
<span className="font-semibold text-gray-800 dark:text-zinc-200">{total}</span>{" "}
|
||||
registros
|
||||
</div>
|
||||
|
||||
@@ -344,7 +344,7 @@ export default function AuditoriaPage() {
|
||||
>
|
||||
Anterior
|
||||
</button>
|
||||
<span className="px-4 py-2 text-sm text-gray-700">
|
||||
<span className="px-4 py-2 text-sm text-gray-700 dark:text-zinc-300">
|
||||
Página {currentPage} de {totalPages}
|
||||
</span>
|
||||
<button
|
||||
@@ -365,14 +365,14 @@ export default function AuditoriaPage() {
|
||||
{/* Details Modal */}
|
||||
{showDetails && selectedLog && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="bg-white rounded-lg shadow-xl max-w-3xl w-full max-h-[90vh] overflow-auto m-4">
|
||||
<div className="p-6 border-b border-gray-200">
|
||||
<h2 className="text-xl font-semibold">Detalles del Registro</h2>
|
||||
<div className="bg-white dark:bg-zinc-900 rounded-lg shadow-xl max-w-3xl w-full max-h-[90vh] overflow-auto m-4 dark:border dark:border-zinc-700">
|
||||
<div className="p-6 border-b border-gray-200 dark:border-zinc-700">
|
||||
<h2 className="text-xl font-semibold dark:text-white">Detalles del Registro</h2>
|
||||
</div>
|
||||
<div className="p-6 space-y-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-zinc-300">
|
||||
ID
|
||||
</label>
|
||||
<p className="text-sm text-gray-900 dark:text-zinc-100 font-mono">
|
||||
@@ -380,7 +380,7 @@ export default function AuditoriaPage() {
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-zinc-300">
|
||||
Fecha/Hora
|
||||
</label>
|
||||
<p className="text-sm text-gray-900 dark:text-zinc-100">
|
||||
@@ -388,14 +388,14 @@ export default function AuditoriaPage() {
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-zinc-300">
|
||||
Usuario
|
||||
</label>
|
||||
<p className="text-sm text-gray-900 dark:text-zinc-100">{selectedLog.user_name}</p>
|
||||
<p className="text-xs text-gray-500">{selectedLog.user_email}</p>
|
||||
<p className="text-xs text-gray-500 dark:text-zinc-400">{selectedLog.user_email}</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-zinc-300">
|
||||
Acción
|
||||
</label>
|
||||
<span
|
||||
@@ -407,13 +407,13 @@ export default function AuditoriaPage() {
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-zinc-300">
|
||||
Tabla
|
||||
</label>
|
||||
<p className="text-sm text-gray-900 dark:text-zinc-100">{selectedLog.table_name}</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-zinc-300">
|
||||
Record ID
|
||||
</label>
|
||||
<p className="text-sm text-gray-900 dark:text-zinc-100 font-mono">
|
||||
@@ -421,7 +421,7 @@ export default function AuditoriaPage() {
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-zinc-300">
|
||||
IP Address
|
||||
</label>
|
||||
<p className="text-sm text-gray-900 dark:text-zinc-100">
|
||||
@@ -429,14 +429,14 @@ export default function AuditoriaPage() {
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-zinc-300">
|
||||
Estado
|
||||
</label>
|
||||
<span
|
||||
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
|
||||
selectedLog.success
|
||||
? "bg-green-100 text-green-800"
|
||||
: "bg-red-100 text-red-800"
|
||||
? "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400"
|
||||
: "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400"
|
||||
}`}
|
||||
>
|
||||
{selectedLog.success ? "Éxito" : "Fallo"}
|
||||
@@ -458,7 +458,7 @@ export default function AuditoriaPage() {
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2">
|
||||
Valores Anteriores
|
||||
</label>
|
||||
<pre className="bg-gray-50 p-3 rounded text-xs overflow-auto">
|
||||
<pre className="bg-gray-50 dark:bg-zinc-800 dark:text-zinc-300 p-3 rounded text-xs overflow-auto">
|
||||
{JSON.stringify(selectedLog.old_values, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
@@ -469,7 +469,7 @@ export default function AuditoriaPage() {
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2">
|
||||
Valores Nuevos
|
||||
</label>
|
||||
<pre className="bg-gray-50 p-3 rounded text-xs overflow-auto">
|
||||
<pre className="bg-gray-50 dark:bg-zinc-800 dark:text-zinc-300 p-3 rounded text-xs overflow-auto">
|
||||
{JSON.stringify(selectedLog.new_values, null, 2)}
|
||||
</pre>
|
||||
</div>
|
||||
@@ -489,7 +489,7 @@ export default function AuditoriaPage() {
|
||||
<div className="p-6 border-t border-gray-200 dark:border-zinc-700 flex justify-end">
|
||||
<button
|
||||
onClick={() => setShowDetails(false)}
|
||||
className="px-4 py-2 bg-gray-200 hover:bg-gray-300 text-gray-800 rounded-md"
|
||||
className="px-4 py-2 bg-gray-200 dark:bg-zinc-700 hover:bg-gray-300 dark:hover:bg-zinc-600 text-gray-800 dark:text-zinc-200 rounded-md"
|
||||
>
|
||||
Cerrar
|
||||
</button>
|
||||
|
||||
@@ -310,8 +310,8 @@ export default function ConsumptionPage() {
|
||||
onClick={() => setShowFilters(!showFilters)}
|
||||
className={`inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-xl transition-all ${
|
||||
showFilters || hasFilters
|
||||
? "bg-blue-50 text-blue-600 border border-blue-200"
|
||||
: "text-slate-600 bg-slate-50 hover:bg-slate-100"
|
||||
? "bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400 border border-blue-200 dark:border-blue-800"
|
||||
: "text-slate-600 dark:text-zinc-300 bg-slate-50 dark:bg-zinc-800 hover:bg-slate-100 dark:hover:bg-zinc-700"
|
||||
}`}
|
||||
>
|
||||
<Filter size={16} />
|
||||
@@ -326,7 +326,7 @@ export default function ConsumptionPage() {
|
||||
{hasFilters && (
|
||||
<button
|
||||
onClick={clearFilters}
|
||||
className="inline-flex items-center gap-1 px-2 py-1 text-xs text-slate-500 hover:text-slate-700"
|
||||
className="inline-flex items-center gap-1 px-2 py-1 text-xs text-slate-500 dark:text-zinc-400 hover:text-slate-700 dark:hover:text-zinc-200"
|
||||
>
|
||||
<X size={14} />
|
||||
Limpiar
|
||||
@@ -342,23 +342,23 @@ export default function ConsumptionPage() {
|
||||
</span>
|
||||
|
||||
{pagination.totalPages > 1 && (
|
||||
<div className="flex items-center gap-1 bg-slate-50 rounded-lg p-1">
|
||||
<div className="flex items-center gap-1 bg-slate-50 dark:bg-zinc-800 rounded-lg p-1">
|
||||
<button
|
||||
onClick={() => loadData(pagination.page - 1)}
|
||||
disabled={pagination.page === 1}
|
||||
className="p-1.5 rounded-md hover:bg-white disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
className="p-1.5 rounded-md hover:bg-white dark:hover:bg-zinc-700 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
<ChevronLeft size={16} />
|
||||
<ChevronLeft size={16} className="dark:text-zinc-300" />
|
||||
</button>
|
||||
<span className="px-2 text-xs font-medium">
|
||||
<span className="px-2 text-xs font-medium dark:text-zinc-300">
|
||||
{pagination.page} / {pagination.totalPages}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => loadData(pagination.page + 1)}
|
||||
disabled={pagination.page === pagination.totalPages}
|
||||
className="p-1.5 rounded-md hover:bg-white disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
className="p-1.5 rounded-md hover:bg-white dark:hover:bg-zinc-700 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
<ChevronRight size={16} />
|
||||
<ChevronRight size={16} className="dark:text-zinc-300" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
@@ -367,9 +367,9 @@ export default function ConsumptionPage() {
|
||||
|
||||
{/* Filters Panel */}
|
||||
{showFilters && (
|
||||
<div className="px-5 py-4 bg-slate-50/50 border-b border-slate-100 dark:border-zinc-800 flex flex-wrap items-center gap-4">
|
||||
<div className="px-5 py-4 bg-slate-50/50 dark:bg-zinc-800/50 border-b border-slate-100 dark:border-zinc-800 flex flex-wrap items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<label className="text-xs font-medium text-slate-500 uppercase tracking-wide">
|
||||
<label className="text-xs font-medium text-slate-500 dark:text-zinc-400 uppercase tracking-wide">
|
||||
Proyecto
|
||||
</label>
|
||||
<select
|
||||
@@ -388,7 +388,7 @@ export default function ConsumptionPage() {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<label className="text-xs font-medium text-slate-500 uppercase tracking-wide">
|
||||
<label className="text-xs font-medium text-slate-500 dark:text-zinc-400 uppercase tracking-wide">
|
||||
Desde
|
||||
</label>
|
||||
<input
|
||||
@@ -400,7 +400,7 @@ export default function ConsumptionPage() {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<label className="text-xs font-medium text-slate-500 uppercase tracking-wide">
|
||||
<label className="text-xs font-medium text-slate-500 dark:text-zinc-400 uppercase tracking-wide">
|
||||
Hasta
|
||||
</label>
|
||||
<input
|
||||
@@ -417,37 +417,37 @@ export default function ConsumptionPage() {
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
<tr className="bg-slate-50/80">
|
||||
<th className="px-5 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">
|
||||
<tr className="bg-slate-50/80 dark:bg-zinc-800">
|
||||
<th className="px-5 py-3 text-left text-xs font-semibold text-slate-500 dark:text-zinc-400 uppercase tracking-wider">
|
||||
Fecha
|
||||
</th>
|
||||
<th className="px-5 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">
|
||||
<th className="px-5 py-3 text-left text-xs font-semibold text-slate-500 dark:text-zinc-400 uppercase tracking-wider">
|
||||
Medidor
|
||||
</th>
|
||||
<th className="px-5 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">
|
||||
<th className="px-5 py-3 text-left text-xs font-semibold text-slate-500 dark:text-zinc-400 uppercase tracking-wider">
|
||||
Serial
|
||||
</th>
|
||||
<th className="px-5 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">
|
||||
<th className="px-5 py-3 text-left text-xs font-semibold text-slate-500 dark:text-zinc-400 uppercase tracking-wider">
|
||||
Ubicación
|
||||
</th>
|
||||
<th className="px-5 py-3 text-right text-xs font-semibold text-slate-500 uppercase tracking-wider">
|
||||
<th className="px-5 py-3 text-right text-xs font-semibold text-slate-500 dark:text-zinc-400 uppercase tracking-wider">
|
||||
Consumo
|
||||
</th>
|
||||
<th className="px-5 py-3 text-center text-xs font-semibold text-slate-500 uppercase tracking-wider">
|
||||
<th className="px-5 py-3 text-center text-xs font-semibold text-slate-500 dark:text-zinc-400 uppercase tracking-wider">
|
||||
Tipo
|
||||
</th>
|
||||
<th className="px-5 py-3 text-center text-xs font-semibold text-slate-500 uppercase tracking-wider">
|
||||
<th className="px-5 py-3 text-center text-xs font-semibold text-slate-500 dark:text-zinc-400 uppercase tracking-wider">
|
||||
Estado
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-slate-100">
|
||||
<tbody className="divide-y divide-slate-100 dark:divide-zinc-700">
|
||||
{loadingReadings ? (
|
||||
Array.from({ length: 8 }).map((_, i) => (
|
||||
<tr key={i}>
|
||||
{Array.from({ length: 7 }).map((_, j) => (
|
||||
<td key={j} className="px-5 py-4">
|
||||
<div className="h-4 bg-slate-100 rounded-md animate-pulse" />
|
||||
<div className="h-4 bg-slate-100 dark:bg-zinc-700 rounded-md animate-pulse" />
|
||||
</td>
|
||||
))}
|
||||
</tr>
|
||||
@@ -456,11 +456,11 @@ export default function ConsumptionPage() {
|
||||
<tr>
|
||||
<td colSpan={7} className="px-5 py-16 text-center">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="w-16 h-16 bg-slate-100 rounded-2xl flex items-center justify-center mb-4">
|
||||
<div className="w-16 h-16 bg-slate-100 dark:bg-zinc-800 rounded-2xl flex items-center justify-center mb-4">
|
||||
<Droplets size={32} className="text-slate-400" />
|
||||
</div>
|
||||
<p className="text-slate-600 font-medium">No hay lecturas disponibles</p>
|
||||
<p className="text-slate-400 text-sm mt-1">
|
||||
<p className="text-slate-600 dark:text-zinc-300 font-medium">No hay lecturas disponibles</p>
|
||||
<p className="text-slate-400 dark:text-zinc-500 text-sm mt-1">
|
||||
{hasFilters
|
||||
? "Intenta ajustar los filtros de búsqueda"
|
||||
: "Las lecturas aparecerán aquí cuando se reciban datos"}
|
||||
@@ -472,31 +472,31 @@ export default function ConsumptionPage() {
|
||||
filteredReadings.map((reading, idx) => (
|
||||
<tr
|
||||
key={reading.id}
|
||||
className={`group hover:bg-blue-50/40 transition-colors ${
|
||||
idx % 2 === 0 ? "bg-white" : "bg-slate-50/30"
|
||||
className={`group hover:bg-blue-50/40 dark:hover:bg-zinc-800 transition-colors ${
|
||||
idx % 2 === 0 ? "bg-white dark:bg-zinc-900" : "bg-slate-50/30 dark:bg-zinc-800/50"
|
||||
}`}
|
||||
>
|
||||
<td className="px-5 py-3.5">
|
||||
<span className="text-sm text-slate-600">{formatDate(reading.receivedAt)}</span>
|
||||
<span className="text-sm text-slate-600 dark:text-zinc-300">{formatDate(reading.receivedAt)}</span>
|
||||
</td>
|
||||
<td className="px-5 py-3.5">
|
||||
<span className="text-sm font-medium text-slate-800">
|
||||
<span className="text-sm font-medium text-slate-800 dark:text-zinc-100">
|
||||
{reading.meterName || "—"}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-5 py-3.5">
|
||||
<code className="text-xs text-slate-500 bg-slate-100 px-2 py-0.5 rounded">
|
||||
<code className="text-xs text-slate-500 dark:text-zinc-400 bg-slate-100 dark:bg-zinc-700 px-2 py-0.5 rounded">
|
||||
{reading.meterSerialNumber || "—"}
|
||||
</code>
|
||||
</td>
|
||||
<td className="px-5 py-3.5">
|
||||
<span className="text-sm text-slate-600">{reading.meterLocation || "—"}</span>
|
||||
<span className="text-sm text-slate-600 dark:text-zinc-300">{reading.meterLocation || "—"}</span>
|
||||
</td>
|
||||
<td className="px-5 py-3.5 text-right">
|
||||
<span className="text-sm font-semibold text-slate-800 tabular-nums">
|
||||
<span className="text-sm font-semibold text-slate-800 dark:text-zinc-100 tabular-nums">
|
||||
{Number(reading.readingValue).toFixed(2)}
|
||||
</span>
|
||||
<span className="text-xs text-slate-400 ml-1">m³</span>
|
||||
<span className="text-xs text-slate-400 dark:text-zinc-500 ml-1">m³</span>
|
||||
</td>
|
||||
<td className="px-5 py-3.5 text-center">
|
||||
<TypeBadge type={reading.readingType} />
|
||||
@@ -515,24 +515,24 @@ export default function ConsumptionPage() {
|
||||
</div>
|
||||
|
||||
{!loadingReadings && filteredReadings.length > 0 && (
|
||||
<div className="px-5 py-4 border-t border-slate-100 flex flex-wrap items-center justify-between gap-4">
|
||||
<div className="text-sm text-slate-600">
|
||||
<div className="px-5 py-4 border-t border-slate-100 dark:border-zinc-700 flex flex-wrap items-center justify-between gap-4">
|
||||
<div className="text-sm text-slate-600 dark:text-zinc-300">
|
||||
Mostrando{" "}
|
||||
<span className="font-semibold text-slate-800">
|
||||
<span className="font-semibold text-slate-800 dark:text-zinc-200">
|
||||
{(pagination.page - 1) * pagination.pageSize + 1}
|
||||
</span>{" "}
|
||||
a{" "}
|
||||
<span className="font-semibold text-slate-800">
|
||||
<span className="font-semibold text-slate-800 dark:text-zinc-200">
|
||||
{Math.min(pagination.page * pagination.pageSize, pagination.total)}
|
||||
</span>{" "}
|
||||
de{" "}
|
||||
<span className="font-semibold text-slate-800">{pagination.total}</span>{" "}
|
||||
<span className="font-semibold text-slate-800 dark:text-zinc-200">{pagination.total}</span>{" "}
|
||||
resultados
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-slate-600">Filas por página:</span>
|
||||
<span className="text-sm text-slate-600 dark:text-zinc-300">Filas por página:</span>
|
||||
<select
|
||||
value={pagination.pageSize}
|
||||
onChange={(e) => handlePageSizeChange(Number(e.target.value))}
|
||||
@@ -548,9 +548,9 @@ export default function ConsumptionPage() {
|
||||
<button
|
||||
onClick={() => handlePageChange(pagination.page - 1)}
|
||||
disabled={pagination.page === 1}
|
||||
className="p-2 rounded-lg hover:bg-slate-100 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
className="p-2 rounded-lg hover:bg-slate-100 dark:hover:bg-zinc-800 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
<ChevronLeft size={18} className="text-slate-600" />
|
||||
<ChevronLeft size={18} className="text-slate-600 dark:text-zinc-400" />
|
||||
</button>
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
@@ -567,14 +567,14 @@ export default function ConsumptionPage() {
|
||||
return (
|
||||
<div key={pageNum} className="flex items-center">
|
||||
{showEllipsis && (
|
||||
<span className="px-2 text-slate-400">...</span>
|
||||
<span className="px-2 text-slate-400 dark:text-zinc-500">...</span>
|
||||
)}
|
||||
<button
|
||||
onClick={() => handlePageChange(pageNum)}
|
||||
className={`min-w-[36px] px-3 py-1.5 text-sm rounded-lg transition-colors ${
|
||||
pageNum === pagination.page
|
||||
? "bg-blue-600 text-white font-semibold"
|
||||
: "text-slate-600 hover:bg-slate-100"
|
||||
: "text-slate-600 dark:text-zinc-300 hover:bg-slate-100 dark:hover:bg-zinc-800"
|
||||
}`}
|
||||
>
|
||||
{pageNum}
|
||||
@@ -587,9 +587,9 @@ export default function ConsumptionPage() {
|
||||
<button
|
||||
onClick={() => handlePageChange(pagination.page + 1)}
|
||||
disabled={pagination.page === pagination.totalPages}
|
||||
className="p-2 rounded-lg hover:bg-slate-100 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
className="p-2 rounded-lg hover:bg-slate-100 dark:hover:bg-zinc-800 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||
>
|
||||
<ChevronRight size={18} className="text-slate-600" />
|
||||
<ChevronRight size={18} className="text-slate-600 dark:text-zinc-400" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -627,17 +627,17 @@ function StatCard({
|
||||
gradient: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="relative bg-white rounded-2xl p-5 shadow-sm shadow-slate-200/50 border border-slate-200/60 overflow-hidden group hover:shadow-md hover:shadow-slate-200/50 transition-all">
|
||||
<div className="relative bg-white dark:bg-zinc-900 rounded-2xl p-5 shadow-sm shadow-slate-200/50 dark:shadow-none border border-slate-200/60 dark:border-zinc-800 overflow-hidden group hover:shadow-md hover:shadow-slate-200/50 dark:hover:shadow-none transition-all">
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="space-y-2">
|
||||
<p className="text-sm font-medium text-slate-500">{label}</p>
|
||||
<p className="text-sm font-medium text-slate-500 dark:text-zinc-400">{label}</p>
|
||||
{loading ? (
|
||||
<div className="h-8 w-24 bg-slate-100 rounded-lg animate-pulse" />
|
||||
<div className="h-8 w-24 bg-slate-100 dark:bg-zinc-700 rounded-lg animate-pulse" />
|
||||
) : (
|
||||
<p className="text-2xl font-bold text-slate-800 dark:text-white">{value}</p>
|
||||
)}
|
||||
{trend && !loading && (
|
||||
<div className="inline-flex items-center gap-1 text-xs font-medium text-emerald-600 bg-emerald-50 px-2 py-0.5 rounded-full">
|
||||
<div className="inline-flex items-center gap-1 text-xs font-medium text-emerald-600 dark:text-emerald-400 bg-emerald-50 dark:bg-emerald-900/30 px-2 py-0.5 rounded-full">
|
||||
<TrendingUp size={12} />
|
||||
{trend}
|
||||
</div>
|
||||
@@ -657,15 +657,15 @@ function StatCard({
|
||||
}
|
||||
|
||||
function TypeBadge({ type }: { type: string | null }) {
|
||||
if (!type) return <span className="text-slate-400">—</span>;
|
||||
if (!type) return <span className="text-slate-400 dark:text-zinc-500">—</span>;
|
||||
|
||||
const styles: Record<string, { bg: string; text: string; dot: string }> = {
|
||||
AUTOMATIC: { bg: "bg-emerald-50", text: "text-emerald-700", dot: "bg-emerald-500" },
|
||||
MANUAL: { bg: "bg-blue-50", text: "text-blue-700", dot: "bg-blue-500" },
|
||||
SCHEDULED: { bg: "bg-violet-50", text: "text-violet-700", dot: "bg-violet-500" },
|
||||
AUTOMATIC: { bg: "bg-emerald-50 dark:bg-emerald-900/30", text: "text-emerald-700 dark:text-emerald-400", dot: "bg-emerald-500" },
|
||||
MANUAL: { bg: "bg-blue-50 dark:bg-blue-900/30", text: "text-blue-700 dark:text-blue-400", dot: "bg-blue-500" },
|
||||
SCHEDULED: { bg: "bg-violet-50 dark:bg-violet-900/30", text: "text-violet-700 dark:text-violet-400", dot: "bg-violet-500" },
|
||||
};
|
||||
|
||||
const style = styles[type] || { bg: "bg-slate-50", text: "text-slate-700", dot: "bg-slate-500" };
|
||||
const style = styles[type] || { bg: "bg-slate-50 dark:bg-zinc-800", text: "text-slate-700 dark:text-zinc-300", dot: "bg-slate-500" };
|
||||
|
||||
return (
|
||||
<span
|
||||
@@ -688,13 +688,13 @@ function BatteryIndicator({ level }: { level: number | null }) {
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-1" title={`Batería: ${level}%`}>
|
||||
<div className="w-6 h-3 border border-slate-300 rounded-sm relative overflow-hidden">
|
||||
<div className="w-6 h-3 border border-slate-300 dark:border-zinc-600 rounded-sm relative overflow-hidden">
|
||||
<div
|
||||
className={`absolute left-0 top-0 bottom-0 ${getColor()} transition-all`}
|
||||
style={{ width: `${level}%` }}
|
||||
/>
|
||||
</div>
|
||||
<span className="text-[10px] text-slate-500 font-medium">{level}%</span>
|
||||
<span className="text-[10px] text-slate-500 dark:text-zinc-400 font-medium">{level}%</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -717,7 +717,7 @@ function SignalIndicator({ strength }: { strength: number | null }) {
|
||||
<div
|
||||
key={i}
|
||||
className={`w-1 rounded-sm transition-colors ${
|
||||
i <= bars ? "bg-emerald-500" : "bg-slate-200"
|
||||
i <= bars ? "bg-emerald-500" : "bg-slate-200 dark:bg-zinc-600"
|
||||
}`}
|
||||
style={{ height: `${i * 2 + 4}px` }}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user