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:
Exteban08
2026-02-03 12:07:01 +00:00
parent 3087af11e1
commit 27494e7868
2 changed files with 93 additions and 93 deletions

View File

@@ -86,18 +86,18 @@ export default function AuditoriaPage() {
const getActionColor = (action: AuditAction) => { const getActionColor = (action: AuditAction) => {
const colors: Record<AuditAction, string> = { const colors: Record<AuditAction, string> = {
CREATE: "bg-green-100 text-green-800", CREATE: "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400",
UPDATE: "bg-blue-100 text-blue-800", UPDATE: "bg-blue-100 dark:bg-blue-900/30 text-blue-800 dark:text-blue-400",
DELETE: "bg-red-100 text-red-800", DELETE: "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400",
LOGIN: "bg-purple-100 text-purple-800", LOGIN: "bg-purple-100 dark:bg-purple-900/30 text-purple-800 dark:text-purple-400",
LOGOUT: "bg-gray-100 text-gray-800", LOGOUT: "bg-gray-100 dark:bg-zinc-700 text-gray-800 dark:text-zinc-300",
READ: "bg-cyan-100 text-cyan-800", READ: "bg-cyan-100 dark:bg-cyan-900/30 text-cyan-800 dark:text-cyan-400",
EXPORT: "bg-yellow-100 text-yellow-800", EXPORT: "bg-yellow-100 dark:bg-yellow-900/30 text-yellow-800 dark:text-yellow-400",
BULK_UPLOAD: "bg-orange-100 text-orange-800", BULK_UPLOAD: "bg-orange-100 dark:bg-orange-900/30 text-orange-800 dark:text-orange-400",
STATUS_CHANGE: "bg-indigo-100 text-indigo-800", STATUS_CHANGE: "bg-indigo-100 dark:bg-indigo-900/30 text-indigo-800 dark:text-indigo-400",
PERMISSION_CHANGE: "bg-pink-100 text-pink-800", 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) => { const filteredLogs = logs.filter((log) => {
@@ -248,7 +248,7 @@ export default function AuditoriaPage() {
</th> </th>
</tr> </tr>
</thead> </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) => ( {filteredLogs.map((log) => (
<tr key={log.id} className="hover:bg-gray-50 dark:hover:bg-zinc-800"> <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"> <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 <span
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${ className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
log.success log.success
? "bg-green-100 text-green-800" ? "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400"
: "bg-red-100 text-red-800" : "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400"
}`} }`}
> >
{log.success ? "Éxito" : "Fallo"} {log.success ? "Éxito" : "Fallo"}
@@ -307,15 +307,15 @@ export default function AuditoriaPage() {
{/* Page Info */} {/* Page Info */}
<div className="text-sm text-gray-600 dark:text-zinc-400"> <div className="text-sm text-gray-600 dark:text-zinc-400">
Mostrando{" "} Mostrando{" "}
<span className="font-semibold text-gray-800"> <span className="font-semibold text-gray-800 dark:text-zinc-200">
{(currentPage - 1) * limit + 1} {(currentPage - 1) * limit + 1}
</span>{" "} </span>{" "}
a{" "} a{" "}
<span className="font-semibold text-gray-800"> <span className="font-semibold text-gray-800 dark:text-zinc-200">
{Math.min(currentPage * limit, total)} {Math.min(currentPage * limit, total)}
</span>{" "} </span>{" "}
de{" "} de{" "}
<span className="font-semibold text-gray-800">{total}</span>{" "} <span className="font-semibold text-gray-800 dark:text-zinc-200">{total}</span>{" "}
registros registros
</div> </div>
@@ -344,7 +344,7 @@ export default function AuditoriaPage() {
> >
Anterior Anterior
</button> </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} Página {currentPage} de {totalPages}
</span> </span>
<button <button
@@ -365,14 +365,14 @@ export default function AuditoriaPage() {
{/* Details Modal */} {/* Details Modal */}
{showDetails && selectedLog && ( {showDetails && selectedLog && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> <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="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"> <div className="p-6 border-b border-gray-200 dark:border-zinc-700">
<h2 className="text-xl font-semibold">Detalles del Registro</h2> <h2 className="text-xl font-semibold dark:text-white">Detalles del Registro</h2>
</div> </div>
<div className="p-6 space-y-4"> <div className="p-6 space-y-4">
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
<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">
ID ID
</label> </label>
<p className="text-sm text-gray-900 dark:text-zinc-100 font-mono"> <p className="text-sm text-gray-900 dark:text-zinc-100 font-mono">
@@ -380,7 +380,7 @@ export default function AuditoriaPage() {
</p> </p>
</div> </div>
<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 Fecha/Hora
</label> </label>
<p className="text-sm text-gray-900 dark:text-zinc-100"> <p className="text-sm text-gray-900 dark:text-zinc-100">
@@ -388,14 +388,14 @@ export default function AuditoriaPage() {
</p> </p>
</div> </div>
<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 Usuario
</label> </label>
<p className="text-sm text-gray-900 dark:text-zinc-100">{selectedLog.user_name}</p> <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>
<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 Acción
</label> </label>
<span <span
@@ -407,13 +407,13 @@ export default function AuditoriaPage() {
</span> </span>
</div> </div>
<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 Tabla
</label> </label>
<p className="text-sm text-gray-900 dark:text-zinc-100">{selectedLog.table_name}</p> <p className="text-sm text-gray-900 dark:text-zinc-100">{selectedLog.table_name}</p>
</div> </div>
<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 Record ID
</label> </label>
<p className="text-sm text-gray-900 dark:text-zinc-100 font-mono"> <p className="text-sm text-gray-900 dark:text-zinc-100 font-mono">
@@ -421,7 +421,7 @@ export default function AuditoriaPage() {
</p> </p>
</div> </div>
<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 IP Address
</label> </label>
<p className="text-sm text-gray-900 dark:text-zinc-100"> <p className="text-sm text-gray-900 dark:text-zinc-100">
@@ -429,14 +429,14 @@ export default function AuditoriaPage() {
</p> </p>
</div> </div>
<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 Estado
</label> </label>
<span <span
className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${ className={`inline-flex px-2 py-1 text-xs font-semibold rounded-full ${
selectedLog.success selectedLog.success
? "bg-green-100 text-green-800" ? "bg-green-100 dark:bg-green-900/30 text-green-800 dark:text-green-400"
: "bg-red-100 text-red-800" : "bg-red-100 dark:bg-red-900/30 text-red-800 dark:text-red-400"
}`} }`}
> >
{selectedLog.success ? "Éxito" : "Fallo"} {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"> <label className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2">
Valores Anteriores Valores Anteriores
</label> </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)} {JSON.stringify(selectedLog.old_values, null, 2)}
</pre> </pre>
</div> </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"> <label className="block text-sm font-medium text-gray-700 dark:text-zinc-300 mb-2">
Valores Nuevos Valores Nuevos
</label> </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)} {JSON.stringify(selectedLog.new_values, null, 2)}
</pre> </pre>
</div> </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"> <div className="p-6 border-t border-gray-200 dark:border-zinc-700 flex justify-end">
<button <button
onClick={() => setShowDetails(false)} 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 Cerrar
</button> </button>

View File

@@ -310,8 +310,8 @@ export default function ConsumptionPage() {
onClick={() => setShowFilters(!showFilters)} onClick={() => setShowFilters(!showFilters)}
className={`inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-xl transition-all ${ className={`inline-flex items-center gap-2 px-3 py-2 text-sm font-medium rounded-xl transition-all ${
showFilters || hasFilters showFilters || hasFilters
? "bg-blue-50 text-blue-600 border border-blue-200" ? "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 bg-slate-50 hover:bg-slate-100" : "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} /> <Filter size={16} />
@@ -326,7 +326,7 @@ export default function ConsumptionPage() {
{hasFilters && ( {hasFilters && (
<button <button
onClick={clearFilters} 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} /> <X size={14} />
Limpiar Limpiar
@@ -342,23 +342,23 @@ export default function ConsumptionPage() {
</span> </span>
{pagination.totalPages > 1 && ( {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 <button
onClick={() => loadData(pagination.page - 1)} onClick={() => loadData(pagination.page - 1)}
disabled={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> </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} {pagination.page} / {pagination.totalPages}
</span> </span>
<button <button
onClick={() => loadData(pagination.page + 1)} onClick={() => loadData(pagination.page + 1)}
disabled={pagination.page === pagination.totalPages} 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> </button>
</div> </div>
)} )}
@@ -367,9 +367,9 @@ export default function ConsumptionPage() {
{/* Filters Panel */} {/* Filters Panel */}
{showFilters && ( {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"> <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 Proyecto
</label> </label>
<select <select
@@ -388,7 +388,7 @@ export default function ConsumptionPage() {
</div> </div>
<div className="flex items-center gap-2"> <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 Desde
</label> </label>
<input <input
@@ -400,7 +400,7 @@ export default function ConsumptionPage() {
</div> </div>
<div className="flex items-center gap-2"> <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 Hasta
</label> </label>
<input <input
@@ -417,37 +417,37 @@ export default function ConsumptionPage() {
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<table className="w-full"> <table className="w-full">
<thead> <thead>
<tr className="bg-slate-50/80"> <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 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">
Fecha Fecha
</th> </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 Medidor
</th> </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 Serial
</th> </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 Ubicación
</th> </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 Consumo
</th> </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 Tipo
</th> </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 Estado
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-slate-100"> <tbody className="divide-y divide-slate-100 dark:divide-zinc-700">
{loadingReadings ? ( {loadingReadings ? (
Array.from({ length: 8 }).map((_, i) => ( Array.from({ length: 8 }).map((_, i) => (
<tr key={i}> <tr key={i}>
{Array.from({ length: 7 }).map((_, j) => ( {Array.from({ length: 7 }).map((_, j) => (
<td key={j} className="px-5 py-4"> <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> </td>
))} ))}
</tr> </tr>
@@ -456,11 +456,11 @@ export default function ConsumptionPage() {
<tr> <tr>
<td colSpan={7} className="px-5 py-16 text-center"> <td colSpan={7} className="px-5 py-16 text-center">
<div className="flex flex-col items-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" /> <Droplets size={32} className="text-slate-400" />
</div> </div>
<p className="text-slate-600 font-medium">No hay lecturas disponibles</p> <p className="text-slate-600 dark:text-zinc-300 font-medium">No hay lecturas disponibles</p>
<p className="text-slate-400 text-sm mt-1"> <p className="text-slate-400 dark:text-zinc-500 text-sm mt-1">
{hasFilters {hasFilters
? "Intenta ajustar los filtros de búsqueda" ? "Intenta ajustar los filtros de búsqueda"
: "Las lecturas aparecerán aquí cuando se reciban datos"} : "Las lecturas aparecerán aquí cuando se reciban datos"}
@@ -472,31 +472,31 @@ export default function ConsumptionPage() {
filteredReadings.map((reading, idx) => ( filteredReadings.map((reading, idx) => (
<tr <tr
key={reading.id} key={reading.id}
className={`group hover:bg-blue-50/40 transition-colors ${ className={`group hover:bg-blue-50/40 dark:hover:bg-zinc-800 transition-colors ${
idx % 2 === 0 ? "bg-white" : "bg-slate-50/30" 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"> <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>
<td className="px-5 py-3.5"> <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 || "—"} {reading.meterName || "—"}
</span> </span>
</td> </td>
<td className="px-5 py-3.5"> <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 || "—"} {reading.meterSerialNumber || "—"}
</code> </code>
</td> </td>
<td className="px-5 py-3.5"> <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>
<td className="px-5 py-3.5 text-right"> <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)} {Number(reading.readingValue).toFixed(2)}
</span> </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>
<td className="px-5 py-3.5 text-center"> <td className="px-5 py-3.5 text-center">
<TypeBadge type={reading.readingType} /> <TypeBadge type={reading.readingType} />
@@ -515,24 +515,24 @@ export default function ConsumptionPage() {
</div> </div>
{!loadingReadings && filteredReadings.length > 0 && ( {!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="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"> <div className="text-sm text-slate-600 dark:text-zinc-300">
Mostrando{" "} 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} {(pagination.page - 1) * pagination.pageSize + 1}
</span>{" "} </span>{" "}
a{" "} 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)} {Math.min(pagination.page * pagination.pageSize, pagination.total)}
</span>{" "} </span>{" "}
de{" "} 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 resultados
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="flex items-center gap-2"> <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 <select
value={pagination.pageSize} value={pagination.pageSize}
onChange={(e) => handlePageSizeChange(Number(e.target.value))} onChange={(e) => handlePageSizeChange(Number(e.target.value))}
@@ -548,9 +548,9 @@ export default function ConsumptionPage() {
<button <button
onClick={() => handlePageChange(pagination.page - 1)} onClick={() => handlePageChange(pagination.page - 1)}
disabled={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> </button>
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
@@ -567,14 +567,14 @@ export default function ConsumptionPage() {
return ( return (
<div key={pageNum} className="flex items-center"> <div key={pageNum} className="flex items-center">
{showEllipsis && ( {showEllipsis && (
<span className="px-2 text-slate-400">...</span> <span className="px-2 text-slate-400 dark:text-zinc-500">...</span>
)} )}
<button <button
onClick={() => handlePageChange(pageNum)} onClick={() => handlePageChange(pageNum)}
className={`min-w-[36px] px-3 py-1.5 text-sm rounded-lg transition-colors ${ className={`min-w-[36px] px-3 py-1.5 text-sm rounded-lg transition-colors ${
pageNum === pagination.page pageNum === pagination.page
? "bg-blue-600 text-white font-semibold" ? "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} {pageNum}
@@ -587,9 +587,9 @@ export default function ConsumptionPage() {
<button <button
onClick={() => handlePageChange(pagination.page + 1)} onClick={() => handlePageChange(pagination.page + 1)}
disabled={pagination.page === pagination.totalPages} 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> </button>
</div> </div>
</div> </div>
@@ -627,17 +627,17 @@ function StatCard({
gradient: string; gradient: string;
}) { }) {
return ( 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="flex items-start justify-between">
<div className="space-y-2"> <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 ? ( {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> <p className="text-2xl font-bold text-slate-800 dark:text-white">{value}</p>
)} )}
{trend && !loading && ( {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} /> <TrendingUp size={12} />
{trend} {trend}
</div> </div>
@@ -657,15 +657,15 @@ function StatCard({
} }
function TypeBadge({ type }: { type: string | null }) { 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 }> = { const styles: Record<string, { bg: string; text: string; dot: string }> = {
AUTOMATIC: { bg: "bg-emerald-50", text: "text-emerald-700", dot: "bg-emerald-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", text: "text-blue-700", dot: "bg-blue-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", text: "text-violet-700", dot: "bg-violet-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 ( return (
<span <span
@@ -688,13 +688,13 @@ function BatteryIndicator({ level }: { level: number | null }) {
return ( return (
<div className="flex items-center gap-1" title={`Batería: ${level}%`}> <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 <div
className={`absolute left-0 top-0 bottom-0 ${getColor()} transition-all`} className={`absolute left-0 top-0 bottom-0 ${getColor()} transition-all`}
style={{ width: `${level}%` }} style={{ width: `${level}%` }}
/> />
</div> </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> </div>
); );
} }
@@ -717,7 +717,7 @@ function SignalIndicator({ strength }: { strength: number | null }) {
<div <div
key={i} key={i}
className={`w-1 rounded-sm transition-colors ${ 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` }} style={{ height: `${i * 2 + 4}px` }}
/> />