fix(dark-mode): dark mode completo + gráficas adaptadas
Dark mode fixes: - Cards secundarias: Mis capturas, Mis clientes, Actividades, Apartados por vencer, Equipo - Botones: Exportar, Descartar, Afluencia, Agendo, Forzar reconexión, Subir archivo - Config: ModoTrabajo, Usuarios, Sistema, RolesPermisos, ConfigPage - Cotizador: inputs, tabs, placeholder, botón compartir - Alta clientes: BotonOcrIne, FileUploader - Cobranza: toggle dashboard, modal abono - Dashboards: tabs Gráficas Recharts: - CSS variables para colores chart (grid, text, tooltip) - Helper isDark() + axisTextColor() + gridStroke() + tooltipProps() - DashboardVendedor: grid, axes, tooltips adaptados - TableroGeneral: grid, axes, tooltips (BarChart, Funnel, PieChart) - MiTablero: tooltip adaptado - Perfilamiento: grid, axes, tooltip 7 apps construidas limpias.
This commit is contained in:
@@ -84,7 +84,7 @@ export default function BotonOcrIne({ archivo, onAplicar }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm">
|
<div className="rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<div className="flex items-center justify-between gap-4">
|
<div className="flex items-center justify-between gap-4">
|
||||||
<p className="text-xs font-semibold uppercase tracking-wider text-[#64748B] dark:text-[#94A3B8]">Lectura automática (OCR)</p>
|
<p className="text-xs font-semibold uppercase tracking-wider text-[#64748B] dark:text-[#94A3B8]">Lectura automática (OCR)</p>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export default function FileUploader({ slot, etiqueta, documento, onAgregar, onQ
|
|||||||
|
|
||||||
if (documento) {
|
if (documento) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between gap-4 rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm">
|
<div className="flex items-center justify-between gap-4 rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<div className="flex min-w-0 items-center gap-4">
|
<div className="flex min-w-0 items-center gap-4">
|
||||||
{urlObjeto && <Miniatura documento={documento} url={urlObjeto} />}
|
{urlObjeto && <Miniatura documento={documento} url={urlObjeto} />}
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
@@ -89,7 +89,7 @@ export default function FileUploader({ slot, etiqueta, documento, onAgregar, onQ
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onQuitar(slot)}
|
onClick={() => onQuitar(slot)}
|
||||||
className="shrink-0 rounded-lg border border-red-200 bg-white px-3 py-1.5 text-xs font-medium text-red-600 transition-all duration-100 ease-out hover:bg-red-50"
|
className="shrink-0 rounded-lg border border-red-200 bg-white px-3 py-1.5 text-xs font-medium text-red-600 transition-all duration-100 ease-out hover:bg-red-50 dark:bg-[#0F172A] dark:border-red-800 dark:text-red-400"
|
||||||
>
|
>
|
||||||
Quitar
|
Quitar
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export default function ModalAbono({ pago, onCancelar, onGuardar }: Props) {
|
|||||||
id="abono-monto"
|
id="abono-monto"
|
||||||
type="number"
|
type="number"
|
||||||
step="0.01"
|
step="0.01"
|
||||||
className={`mt-1 w-full rounded-lg border bg-white px-3 py-2.5 text-sm transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 ${errors.monto ? 'border-red-400' : 'border-[#D1D5DB]'}`}
|
className={`mt-1 w-full rounded-lg border bg-white px-3 py-2.5 text-sm transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#E2E8F0] ${errors.monto ? 'border-red-400' : 'border-[#D1D5DB]'}`}
|
||||||
{...regMonto}
|
{...regMonto}
|
||||||
ref={(el) => {
|
ref={(el) => {
|
||||||
regMonto.ref(el)
|
regMonto.ref(el)
|
||||||
@@ -100,7 +100,7 @@ export default function ModalAbono({ pago, onCancelar, onGuardar }: Props) {
|
|||||||
<input
|
<input
|
||||||
id="abono-fecha"
|
id="abono-fecha"
|
||||||
type="date"
|
type="date"
|
||||||
className={`mt-1 w-full rounded-lg border bg-white px-3 py-2.5 text-sm transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 ${errors.fechaPago ? 'border-red-400' : 'border-[#D1D5DB]'}`}
|
className={`mt-1 w-full rounded-lg border bg-white px-3 py-2.5 text-sm transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#E2E8F0] ${errors.fechaPago ? 'border-red-400' : 'border-[#D1D5DB]'}`}
|
||||||
{...register('fechaPago')}
|
{...register('fechaPago')}
|
||||||
/>
|
/>
|
||||||
{errors.fechaPago && <p className="mt-1 text-xs text-red-700">{errors.fechaPago.message}</p>}
|
{errors.fechaPago && <p className="mt-1 text-xs text-red-700">{errors.fechaPago.message}</p>}
|
||||||
@@ -112,7 +112,7 @@ export default function ModalAbono({ pago, onCancelar, onGuardar }: Props) {
|
|||||||
<input
|
<input
|
||||||
id="abono-referencia"
|
id="abono-referencia"
|
||||||
type="text"
|
type="text"
|
||||||
className={`mt-1 w-full rounded-lg border bg-white px-3 py-2.5 text-sm transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 ${errors.referencia ? 'border-red-400' : 'border-[#D1D5DB]'}`}
|
className={`mt-1 w-full rounded-lg border bg-white px-3 py-2.5 text-sm transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#E2E8F0] ${errors.referencia ? 'border-red-400' : 'border-[#D1D5DB]'}`}
|
||||||
placeholder="SPEI-000123"
|
placeholder="SPEI-000123"
|
||||||
{...register('referencia')}
|
{...register('referencia')}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -298,13 +298,13 @@ export default function DashboardPage() {
|
|||||||
{/* Filtros */}
|
{/* Filtros */}
|
||||||
<div className="flex flex-wrap items-center gap-3 border-b border-[#E5E7EB] p-4 md:gap-4 md:px-5">
|
<div className="flex flex-wrap items-center gap-3 border-b border-[#E5E7EB] p-4 md:gap-4 md:px-5">
|
||||||
{/* Toggle Mis planes / Todos (?mios=1 filtra en el API por el vendedor del token) */}
|
{/* Toggle Mis planes / Todos (?mios=1 filtra en el API por el vendedor del token) */}
|
||||||
<div className="flex rounded-lg border border-[#D1D5DB] bg-white" role="group" aria-label="Alcance de planes">
|
<div className="flex rounded-lg border border-[#D1D5DB] bg-white dark:border-[#334155] dark:bg-[#0F172A]" role="group" aria-label="Alcance de planes">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => actualizarParams({ vista: mios ? null : 'mios' })}
|
onClick={() => actualizarParams({ vista: mios ? null : 'mios' })}
|
||||||
aria-pressed={mios}
|
aria-pressed={mios}
|
||||||
className={`rounded-l-lg px-4 py-2.5 text-sm font-medium transition-all duration-100 ease-out ${
|
className={`rounded-l-lg px-4 py-2.5 text-sm font-medium transition-all duration-100 ease-out ${
|
||||||
mios ? 'bg-accent text-white shadow-sm' : 'bg-white text-[#64748B] dark:text-[#94A3B8] hover:text-[#111827] dark:text-[#E2E8F0]'
|
mios ? 'bg-accent text-white shadow-sm' : 'bg-white text-[#64748B] dark:text-[#94A3B8] hover:text-[#111827] dark:hover:text-[#E2E8F0] dark:bg-[#0F172A] dark:hover:bg-[#1E293B]'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Mis planes
|
Mis planes
|
||||||
@@ -314,7 +314,7 @@ export default function DashboardPage() {
|
|||||||
onClick={() => actualizarParams({ vista: mios ? 'todos' : null })}
|
onClick={() => actualizarParams({ vista: mios ? 'todos' : null })}
|
||||||
aria-pressed={!mios}
|
aria-pressed={!mios}
|
||||||
className={`rounded-r-lg px-4 py-2.5 text-sm font-medium transition-all duration-100 ease-out ${
|
className={`rounded-r-lg px-4 py-2.5 text-sm font-medium transition-all duration-100 ease-out ${
|
||||||
mios ? 'bg-white text-[#64748B] dark:text-[#94A3B8] hover:text-[#111827] dark:text-[#E2E8F0]' : 'bg-accent text-white shadow-sm'
|
mios ? 'bg-white text-[#64748B] dark:text-[#94A3B8] hover:text-[#111827] dark:hover:text-[#E2E8F0] dark:bg-[#0F172A] dark:hover:bg-[#1E293B]' : 'bg-accent text-white shadow-sm'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
Todos
|
Todos
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ const esquemaCliente = z.object({
|
|||||||
type FormularioCliente = z.infer<typeof esquemaCliente>
|
type FormularioCliente = z.infer<typeof esquemaCliente>
|
||||||
|
|
||||||
const campoInputBase =
|
const campoInputBase =
|
||||||
'w-full rounded-lg border bg-white px-3 py-2.5 text-sm transition-colors focus:border-accent focus:ring-2 focus:ring-accent/20 focus:outline-none'
|
'w-full rounded-lg border bg-white px-3 py-2.5 text-sm transition-colors focus:border-accent focus:ring-2 focus:ring-accent/20 focus:outline-none dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#E2E8F0]'
|
||||||
const campoInput = `${campoInputBase} border-[#D1D5DB]`
|
const campoInput = `${campoInputBase} border-[#D1D5DB]`
|
||||||
const campoInputError = `${campoInputBase} border-red-400`
|
const campoInputError = `${campoInputBase} border-red-400`
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ export default function CotizadorPage() {
|
|||||||
className={`px-4 py-2.5 text-xs font-medium transition-colors duration-100 ${
|
className={`px-4 py-2.5 text-xs font-medium transition-colors duration-100 ${
|
||||||
activo
|
activo
|
||||||
? 'bg-accent text-white'
|
? 'bg-accent text-white'
|
||||||
: 'bg-white text-[#4B5563] dark:text-[#CBD5E1] hover:bg-[#F9FAFB]'
|
: 'bg-white text-[#4B5563] dark:text-[#CBD5E1] hover:bg-[#F9FAFB] dark:bg-[#0F172A] dark:hover:bg-[#1E293B]'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{obtenerDesarrollo(id).nombre}
|
{obtenerDesarrollo(id).nombre}
|
||||||
@@ -398,7 +398,7 @@ export default function CotizadorPage() {
|
|||||||
className={`px-5 py-2.5 text-xs font-medium transition-colors duration-100 ${
|
className={`px-5 py-2.5 text-xs font-medium transition-colors duration-100 ${
|
||||||
activo
|
activo
|
||||||
? 'bg-accent text-white'
|
? 'bg-accent text-white'
|
||||||
: 'bg-white text-[#4B5563] dark:text-[#CBD5E1] hover:bg-[#F9FAFB]'
|
: 'bg-white text-[#4B5563] dark:text-[#CBD5E1] hover:bg-[#F9FAFB] dark:bg-[#0F172A] dark:hover:bg-[#1E293B]'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{opcion}
|
{opcion}
|
||||||
@@ -549,7 +549,7 @@ export default function CotizadorPage() {
|
|||||||
{/* Panel de propuestas */}
|
{/* Panel de propuestas */}
|
||||||
<section className="min-w-0">
|
<section className="min-w-0">
|
||||||
{!unidad ? (
|
{!unidad ? (
|
||||||
<div className="flex h-64 items-center justify-center rounded-xl border border-dashed border-[#D1D5DB] bg-white">
|
<div className="flex h-64 items-center justify-center rounded-xl border border-dashed border-[#D1D5DB] bg-white dark:border-[#334155] dark:bg-[#0F172A]">
|
||||||
<p className="text-sm text-[#64748B] dark:text-[#94A3B8]">
|
<p className="text-sm text-[#64748B] dark:text-[#94A3B8]">
|
||||||
Selecciona una unidad para ver las propuestas comerciales.
|
Selecciona una unidad para ver las propuestas comerciales.
|
||||||
</p>
|
</p>
|
||||||
@@ -595,7 +595,7 @@ export default function CotizadorPage() {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={handleCompartir}
|
onClick={handleCompartir}
|
||||||
disabled={!puedeGenerarPdf}
|
disabled={!puedeGenerarPdf}
|
||||||
className="rounded-lg border border-accent bg-white px-5 py-2.5 text-sm font-medium text-accent shadow-sm transition-all duration-100 ease-out hover:bg-accent hover:text-white disabled:cursor-not-allowed disabled:opacity-40"
|
className="rounded-lg border border-accent bg-white px-5 py-2.5 text-sm font-medium text-accent shadow-sm transition-all duration-100 ease-out hover:bg-accent hover:text-white disabled:cursor-not-allowed disabled:opacity-40 dark:bg-[#0F172A] dark:border-accent dark:text-accent"
|
||||||
>
|
>
|
||||||
Compartir
|
Compartir
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { Cell, Funnel, FunnelChart, LabelList, ResponsiveContainer, Tooltip } from 'recharts'
|
import { Cell, Funnel, FunnelChart, LabelList, ResponsiveContainer, Tooltip } from 'recharts'
|
||||||
|
import { tooltipProps } from '../lib/chart-theme'
|
||||||
import KpiCard from './KpiCard'
|
import KpiCard from './KpiCard'
|
||||||
import { EstadoVacio, TarjetaGrafica, type AccionesTablero } from './comunes'
|
import { EstadoVacio, TarjetaGrafica, type AccionesTablero } from './comunes'
|
||||||
import { funnelMisLeads, type ResumenMiDia } from '../lib/mi-tablero'
|
import { funnelMisLeads, type ResumenMiDia } from '../lib/mi-tablero'
|
||||||
@@ -95,7 +96,7 @@ export default function MiTablero({ alCambiarAcciones }: { alCambiarAcciones: (a
|
|||||||
<div className="h-72">
|
<div className="h-72">
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
<FunnelChart>
|
<FunnelChart>
|
||||||
<Tooltip />
|
<Tooltip {...tooltipProps()} />
|
||||||
<Funnel dataKey="valor" data={funnel} nameKey="etapa" isAnimationActive={false}>
|
<Funnel dataKey="valor" data={funnel} nameKey="etapa" isAnimationActive={false}>
|
||||||
{funnel.map((etapa, i) => (
|
{funnel.map((etapa, i) => (
|
||||||
<Cell key={etapa.etapa} fill={COLORES_FUNNEL[i % COLORES_FUNNEL.length]} />
|
<Cell key={etapa.etapa} fill={COLORES_FUNNEL[i % COLORES_FUNNEL.length]} />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'
|
import { Bar, BarChart, CartesianGrid, ResponsiveContainer, Tooltip, XAxis, YAxis } from 'recharts'
|
||||||
|
import { axisTextColor, gridStroke, tooltipProps } from '../lib/chart-theme'
|
||||||
import { EstadoVacio, TituloSeccion } from './comunes'
|
import { EstadoVacio, TituloSeccion } from './comunes'
|
||||||
import { rebanadasDe, type ResumenReportes } from '../lib/reportes'
|
import { rebanadasDe, type ResumenReportes } from '../lib/reportes'
|
||||||
|
|
||||||
@@ -28,10 +29,10 @@ function TarjetaDimension({ titulo, datos }: { titulo: string; datos: Record<str
|
|||||||
<div className="h-48">
|
<div className="h-48">
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
<BarChart data={rebanadas} layout="vertical" margin={{ top: 4, right: 24, left: 24, bottom: 0 }}>
|
<BarChart data={rebanadas} layout="vertical" margin={{ top: 4, right: 24, left: 24, bottom: 0 }}>
|
||||||
<CartesianGrid strokeDasharray="3 3" horizontal={false} />
|
<CartesianGrid strokeDasharray="3 3" stroke={gridStroke()} horizontal={false} />
|
||||||
<XAxis type="number" allowDecimals={false} tick={{ fontSize: 11 }} />
|
<XAxis type="number" allowDecimals={false} tick={{ fontSize: 11, fill: axisTextColor() }} />
|
||||||
<YAxis type="category" dataKey="nombre" width={90} tick={{ fontSize: 11 }} />
|
<YAxis type="category" dataKey="nombre" width={90} tick={{ fontSize: 11, fill: axisTextColor() }} />
|
||||||
<Tooltip />
|
<Tooltip {...tooltipProps()} />
|
||||||
<Bar dataKey="valor" name="Leads" fill="#2563EB" isAnimationActive={false} />
|
<Bar dataKey="valor" name="Leads" fill="#2563EB" isAnimationActive={false} />
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
XAxis,
|
XAxis,
|
||||||
YAxis,
|
YAxis,
|
||||||
} from 'recharts'
|
} from 'recharts'
|
||||||
|
import { axisTextColor, gridStroke, tooltipProps } from '../lib/chart-theme'
|
||||||
import KpiCard from './KpiCard'
|
import KpiCard from './KpiCard'
|
||||||
import Perfilamiento from './Perfilamiento'
|
import Perfilamiento from './Perfilamiento'
|
||||||
import SeccionEquipo from './SeccionEquipo'
|
import SeccionEquipo from './SeccionEquipo'
|
||||||
@@ -160,10 +161,10 @@ export default function TableroGeneral({
|
|||||||
<div className="h-72">
|
<div className="h-72">
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
<BarChart data={unidades} margin={{ top: 8, right: 8, left: -16, bottom: 0 }}>
|
<BarChart data={unidades} margin={{ top: 8, right: 8, left: -16, bottom: 0 }}>
|
||||||
<CartesianGrid strokeDasharray="3 3" vertical={false} />
|
<CartesianGrid strokeDasharray="3 3" stroke={gridStroke()} vertical={false} />
|
||||||
<XAxis dataKey="desarrollo" tick={{ fontSize: 11 }} />
|
<XAxis dataKey="desarrollo" tick={{ fontSize: 11, fill: axisTextColor() }} />
|
||||||
<YAxis allowDecimals={false} tick={{ fontSize: 11 }} />
|
<YAxis allowDecimals={false} tick={{ fontSize: 11, fill: axisTextColor() }} />
|
||||||
<Tooltip />
|
<Tooltip {...tooltipProps()} />
|
||||||
<Legend wrapperStyle={{ fontSize: 11 }} />
|
<Legend wrapperStyle={{ fontSize: 11 }} />
|
||||||
{Object.keys(COLORES_STATUS).map((status) => (
|
{Object.keys(COLORES_STATUS).map((status) => (
|
||||||
<Bar key={status} dataKey={status} stackId="unidades" fill={COLORES_STATUS[status]} />
|
<Bar key={status} dataKey={status} stackId="unidades" fill={COLORES_STATUS[status]} />
|
||||||
@@ -183,10 +184,10 @@ export default function TableroGeneral({
|
|||||||
<div className="h-80">
|
<div className="h-80">
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
<BarChart data={pipeline} layout="vertical" margin={{ top: 8, right: 24, left: 24, bottom: 0 }}>
|
<BarChart data={pipeline} layout="vertical" margin={{ top: 8, right: 24, left: 24, bottom: 0 }}>
|
||||||
<CartesianGrid strokeDasharray="3 3" horizontal={false} />
|
<CartesianGrid strokeDasharray="3 3" stroke={gridStroke()} horizontal={false} />
|
||||||
<XAxis type="number" allowDecimals={false} tick={{ fontSize: 11 }} />
|
<XAxis type="number" allowDecimals={false} tick={{ fontSize: 11, fill: axisTextColor() }} />
|
||||||
<YAxis type="category" dataKey="etapa" width={90} tick={{ fontSize: 11 }} />
|
<YAxis type="category" dataKey="etapa" width={90} tick={{ fontSize: 11, fill: axisTextColor() }} />
|
||||||
<Tooltip />
|
<Tooltip {...tooltipProps()} />
|
||||||
<Bar dataKey="valor" name="Unidades" fill="#2563EB" isAnimationActive={false} />
|
<Bar dataKey="valor" name="Unidades" fill="#2563EB" isAnimationActive={false} />
|
||||||
</BarChart>
|
</BarChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
@@ -203,7 +204,7 @@ export default function TableroGeneral({
|
|||||||
<div className="h-72">
|
<div className="h-72">
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
<FunnelChart>
|
<FunnelChart>
|
||||||
<Tooltip />
|
<Tooltip {...tooltipProps()} />
|
||||||
<Funnel dataKey="valor" data={funnel} nameKey="etapa" isAnimationActive={false}>
|
<Funnel dataKey="valor" data={funnel} nameKey="etapa" isAnimationActive={false}>
|
||||||
{funnel.map((etapa, i) => (
|
{funnel.map((etapa, i) => (
|
||||||
<Cell key={etapa.etapa} fill={COLORES_FUNNEL[i % COLORES_FUNNEL.length]} />
|
<Cell key={etapa.etapa} fill={COLORES_FUNNEL[i % COLORES_FUNNEL.length]} />
|
||||||
@@ -226,6 +227,7 @@ export default function TableroGeneral({
|
|||||||
<div className="h-72">
|
<div className="h-72">
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
<PieChart>
|
<PieChart>
|
||||||
|
<Tooltip {...tooltipProps()} />
|
||||||
<Pie
|
<Pie
|
||||||
data={cobranza}
|
data={cobranza}
|
||||||
dataKey="valor"
|
dataKey="valor"
|
||||||
@@ -240,7 +242,6 @@ export default function TableroGeneral({
|
|||||||
<Cell key={rebanada.nombre} fill={COLORES_COBRANZA[i % COLORES_COBRANZA.length]} />
|
<Cell key={rebanada.nombre} fill={COLORES_COBRANZA[i % COLORES_COBRANZA.length]} />
|
||||||
))}
|
))}
|
||||||
</Pie>
|
</Pie>
|
||||||
<Tooltip />
|
|
||||||
</PieChart>
|
</PieChart>
|
||||||
</ResponsiveContainer>
|
</ResponsiveContainer>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,6 +8,21 @@
|
|||||||
--color-accent-hover: #1D4ED8;
|
--color-accent-hover: #1D4ED8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--chart-grid: #E5E7EB;
|
||||||
|
--chart-text: #64748B;
|
||||||
|
--chart-tooltip-bg: white;
|
||||||
|
--chart-tooltip-border: #E5E7EB;
|
||||||
|
--chart-tooltip-text: #111827;
|
||||||
|
}
|
||||||
|
.dark {
|
||||||
|
--chart-grid: #334155;
|
||||||
|
--chart-text: #94A3B8;
|
||||||
|
--chart-tooltip-bg: #1E293B;
|
||||||
|
--chart-tooltip-border: #334155;
|
||||||
|
--chart-tooltip-text: #E2E8F0;
|
||||||
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
body {
|
body {
|
||||||
@apply bg-[#F8FAFC] text-[#111827] antialiased;
|
@apply bg-[#F8FAFC] text-[#111827] antialiased;
|
||||||
|
|||||||
24
apps/dashboards/src/lib/chart-theme.ts
Normal file
24
apps/dashboards/src/lib/chart-theme.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Helpers de tema para gráficas Recharts.
|
||||||
|
*
|
||||||
|
* Recharts renderiza SVG puro y no resuelve CSS custom properties en
|
||||||
|
* atributos como `fill` / `stroke`, así que necesitamos funciones que
|
||||||
|
* lean el estado dark-mode del documento y devuelvan los colores
|
||||||
|
* apropiados como strings literales.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** `true` cuando el `<html>` lleva la clase `dark` (Tailwind convention). */
|
||||||
|
export const isDark = (): boolean =>
|
||||||
|
typeof document !== 'undefined' && document.documentElement.classList.contains('dark')
|
||||||
|
|
||||||
|
/** Color de texto para los ejes (XAxis / YAxis tick fill). */
|
||||||
|
export const axisTextColor = (): string => (isDark() ? '#94A3B8' : '#64748B')
|
||||||
|
|
||||||
|
/** Color de la cuadrícula (CartesianGrid stroke). */
|
||||||
|
export const gridStroke = (): string => (isDark() ? '#334155' : '#E5E7EB')
|
||||||
|
|
||||||
|
/** Props comunes de Tooltip para aplicar estilo dark/light. */
|
||||||
|
export const tooltipProps = (): Record<string, unknown> =>
|
||||||
|
isDark()
|
||||||
|
? { contentStyle: { backgroundColor: '#1E293B', borderColor: '#334155', color: '#E2E8F0', borderRadius: 8, fontSize: 12 } }
|
||||||
|
: { contentStyle: { borderRadius: 8, fontSize: 12 } }
|
||||||
@@ -64,7 +64,7 @@ export default function DashboardPage() {
|
|||||||
<DarkModeToggle />
|
<DarkModeToggle />
|
||||||
{permitidas.length > 1 && (
|
{permitidas.length > 1 && (
|
||||||
<div
|
<div
|
||||||
className="inline-flex rounded-lg border border-[#E5E7EB] bg-[#F1F5F9] p-0.5 sm:p-1"
|
className="inline-flex rounded-lg border border-[#E5E7EB] bg-[#F1F5F9] p-0.5 dark:border-[#334155] dark:bg-[#1E293B] sm:p-1"
|
||||||
role="tablist"
|
role="tablist"
|
||||||
aria-label="Vista del tablero"
|
aria-label="Vista del tablero"
|
||||||
>
|
>
|
||||||
@@ -77,8 +77,8 @@ export default function DashboardPage() {
|
|||||||
onClick={() => setElegida(v.id)}
|
onClick={() => setElegida(v.id)}
|
||||||
className={
|
className={
|
||||||
vista === v.id
|
vista === v.id
|
||||||
? 'rounded-md bg-white px-2 py-1.5 text-[10px] font-medium text-[#111827] dark:text-[#E2E8F0] shadow-sm transition-all duration-100 ease-out sm:px-3 sm:text-xs'
|
? 'rounded-md bg-white px-2 py-1.5 text-[10px] font-medium text-[#111827] dark:text-[#E2E8F0] shadow-sm transition-all duration-100 ease-out sm:px-3 sm:text-xs dark:bg-[#1E293B]'
|
||||||
: 'rounded-md px-2 py-1.5 text-[10px] font-medium text-[#64748B] dark:text-[#94A3B8] transition-all duration-100 ease-out hover:text-[#111827] dark:text-[#E2E8F0] sm:px-3 sm:text-xs'
|
: 'rounded-md px-2 py-1.5 text-[10px] font-medium text-[#64748B] dark:text-[#94A3B8] transition-all duration-100 ease-out hover:text-[#111827] dark:hover:text-[#E2E8F0] sm:px-3 sm:text-xs'
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{v.etiqueta}
|
{v.etiqueta}
|
||||||
|
|||||||
@@ -30,18 +30,18 @@ export function ConfigPage({ onVolver }: Props) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onVolver}
|
onClick={onVolver}
|
||||||
className="rounded-lg border border-[#D1D5DB] bg-white px-4 py-2 text-sm font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB]"
|
className="rounded-lg border border-[#D1D5DB] bg-white px-4 py-2 text-sm font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB] dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#CBD5E1]"
|
||||||
>
|
>
|
||||||
← Volver
|
← Volver
|
||||||
</button>
|
</button>
|
||||||
<h1 className="text-2xl font-semibold tracking-tight text-[#111827] sm:text-3xl">
|
<h1 className="text-2xl font-semibold tracking-tight text-[#111827] dark:text-[#E2E8F0] sm:text-3xl">
|
||||||
Configuraciones
|
Configuraciones
|
||||||
</h1>
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tabs */}
|
{/* Tabs */}
|
||||||
<nav aria-label="Tabs de configuraciones" className="mt-8">
|
<nav aria-label="Tabs de configuraciones" className="mt-8">
|
||||||
<ul className="flex gap-1 rounded-xl border border-[#E5E7EB] bg-[#F9FAFB] p-1">
|
<ul className="flex gap-1 rounded-xl border border-[#E5E7EB] bg-[#F9FAFB] p-1 dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
{tabs.map((t) => (
|
{tabs.map((t) => (
|
||||||
<li key={t.key}>
|
<li key={t.key}>
|
||||||
<button
|
<button
|
||||||
@@ -49,8 +49,8 @@ export function ConfigPage({ onVolver }: Props) {
|
|||||||
onClick={() => setTab(t.key)}
|
onClick={() => setTab(t.key)}
|
||||||
className={`rounded-lg px-4 py-2 text-sm font-medium transition-colors ${
|
className={`rounded-lg px-4 py-2 text-sm font-medium transition-colors ${
|
||||||
tab === t.key
|
tab === t.key
|
||||||
? 'bg-white text-[#111827] shadow-sm'
|
? 'bg-white text-[#111827] shadow-sm dark:bg-[#1E293B] dark:text-[#E2E8F0]'
|
||||||
: 'text-[#64748B] hover:text-[#374151]'
|
: 'text-[#64748B] hover:text-[#374151] dark:text-[#94A3B8] dark:hover:text-[#CBD5E1]'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{t.label}
|
{t.label}
|
||||||
|
|||||||
@@ -75,22 +75,22 @@ export function ModoTrabajo() {
|
|||||||
|
|
||||||
if (cargando) {
|
if (cargando) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm">
|
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<p className="text-sm text-[#64748B]">Cargando estado del sistema…</p>
|
<p className="text-sm text-[#64748B] dark:text-[#94A3B8]">Cargando estado del sistema…</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm">
|
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<h2 className="text-lg font-semibold text-[#111827]">Modo de trabajo</h2>
|
<h2 className="text-lg font-semibold text-[#111827] dark:text-[#E2E8F0]">Modo de trabajo</h2>
|
||||||
|
|
||||||
{/* Indicador del estado de Monday */}
|
{/* Indicador del estado de Monday */}
|
||||||
<div className="mt-4 flex items-center gap-2">
|
<div className="mt-4 flex items-center gap-2">
|
||||||
<span
|
<span
|
||||||
className={`h-2.5 w-2.5 rounded-full ${estado?.mondayOk ? 'bg-green-500' : 'bg-red-500'}`}
|
className={`h-2.5 w-2.5 rounded-full ${estado?.mondayOk ? 'bg-green-500' : 'bg-red-500'}`}
|
||||||
/>
|
/>
|
||||||
<span className="text-sm text-[#64748B]">
|
<span className="text-sm text-[#64748B] dark:text-[#94A3B8]">
|
||||||
Monday: {estado?.mondayOk ? 'Conectado' : 'No disponible'}
|
Monday: {estado?.mondayOk ? 'Conectado' : 'No disponible'}
|
||||||
{estado && ` · ${estado.pendientesSync} pendiente(s) de sincronizar`}
|
{estado && ` · ${estado.pendientesSync} pendiente(s) de sincronizar`}
|
||||||
</span>
|
</span>
|
||||||
@@ -116,10 +116,10 @@ export function ModoTrabajo() {
|
|||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium text-[#111827]">
|
<p className="text-sm font-medium text-[#111827] dark:text-[#E2E8F0]">
|
||||||
{modoLocal ? 'Modo local (sin Monday)' : 'Vinculado a Monday'}
|
{modoLocal ? 'Modo local (sin Monday)' : 'Vinculado a Monday'}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-0.5 text-xs text-[#64748B]">
|
<p className="mt-0.5 text-xs text-[#64748B] dark:text-[#94A3B8]">
|
||||||
{modoLocal
|
{modoLocal
|
||||||
? 'Las capturas se guardan localmente y se sincronizarán cuando Monday esté disponible.'
|
? 'Las capturas se guardan localmente y se sincronizarán cuando Monday esté disponible.'
|
||||||
: 'Los leads, actividades y contactos se sincronizan con Monday en tiempo real.'}
|
: 'Los leads, actividades y contactos se sincronizan con Monday en tiempo real.'}
|
||||||
@@ -133,7 +133,7 @@ export function ModoTrabajo() {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => void reconectar()}
|
onClick={() => void reconectar()}
|
||||||
disabled={guardando}
|
disabled={guardando}
|
||||||
className="rounded-lg border border-[#D1D5DB] bg-white px-4 py-2 text-sm font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB] disabled:opacity-50"
|
className="rounded-lg border border-[#D1D5DB] bg-white px-4 py-2 text-sm font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB] disabled:opacity-50 dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#CBD5E1]"
|
||||||
>
|
>
|
||||||
{guardando ? 'Procesando…' : 'Forzar reconexión'}
|
{guardando ? 'Procesando…' : 'Forzar reconexión'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ export function RolesPermisos() {
|
|||||||
|
|
||||||
if (cargando) {
|
if (cargando) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm">
|
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<p className="text-sm text-[#64748B]">Cargando configuración de roles…</p>
|
<p className="text-sm text-[#64748B] dark:text-[#94A3B8]">Cargando configuración de roles…</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -168,7 +168,7 @@ export function RolesPermisos() {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => void restaurar()}
|
onClick={() => void restaurar()}
|
||||||
disabled={guardando}
|
disabled={guardando}
|
||||||
className="rounded-lg border border-[#D1D5DB] bg-white px-4 py-2 text-sm font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB] disabled:opacity-50"
|
className="rounded-lg border border-[#D1D5DB] bg-white px-4 py-2 text-sm font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB] disabled:opacity-50 dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#CBD5E1]"
|
||||||
>
|
>
|
||||||
Restaurar valores por defecto
|
Restaurar valores por defecto
|
||||||
</button>
|
</button>
|
||||||
@@ -183,11 +183,11 @@ export function RolesPermisos() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Tabla de roles */}
|
{/* Tabla de roles */}
|
||||||
<div className="overflow-x-auto rounded-xl border border-[#E5E7EB] bg-white shadow-sm">
|
<div className="overflow-x-auto rounded-xl border border-[#E5E7EB] bg-white shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<table className="w-full text-left text-sm">
|
<table className="w-full text-left text-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-[#E5E7EB] bg-[#F9FAFB]">
|
<tr className="border-b border-[#E5E7EB] bg-[#F9FAFB] dark:border-[#334155] dark:bg-[#1E293B]">
|
||||||
<th className="px-4 py-3 font-medium text-[#111827]">Rol</th>
|
<th className="px-4 py-3 font-medium text-[#111827] dark:text-[#E2E8F0]">Rol</th>
|
||||||
{MODULOS_DISPONIBLES.map((m) => (
|
{MODULOS_DISPONIBLES.map((m) => (
|
||||||
<th key={m} className="px-3 py-3 text-center text-xs font-medium text-[#64748B]">
|
<th key={m} className="px-3 py-3 text-center text-xs font-medium text-[#64748B]">
|
||||||
{MODULO_LABELS[m] ?? m}
|
{MODULO_LABELS[m] ?? m}
|
||||||
@@ -205,8 +205,8 @@ export function RolesPermisos() {
|
|||||||
const estado = edicion[r.rol]
|
const estado = edicion[r.rol]
|
||||||
if (!estado) return null
|
if (!estado) return null
|
||||||
return (
|
return (
|
||||||
<tr key={r.rol} className="border-b border-[#E5E7EB] last:border-0">
|
<tr key={r.rol} className="border-b border-[#E5E7EB] dark:border-[#334155] last:border-0">
|
||||||
<td className="whitespace-nowrap px-4 py-3 font-medium text-[#111827]">
|
<td className="whitespace-nowrap px-4 py-3 font-medium text-[#111827] dark:text-[#E2E8F0]">
|
||||||
{r.rol}
|
{r.rol}
|
||||||
</td>
|
</td>
|
||||||
{MODULOS_DISPONIBLES.map((m) => (
|
{MODULOS_DISPONIBLES.map((m) => (
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const TTL_OPTIONS = [
|
|||||||
|
|
||||||
const labelEstilo = 'block text-xs font-medium text-[#4B5563]'
|
const labelEstilo = 'block text-xs font-medium text-[#4B5563]'
|
||||||
const inputEstilo =
|
const inputEstilo =
|
||||||
'mt-2 w-full rounded-lg border border-[#D1D5DB] bg-white px-3 py-2.5 text-sm text-[#111827] transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20'
|
'mt-2 w-full rounded-lg border border-[#D1D5DB] bg-white px-3 py-2.5 text-sm text-[#111827] transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#E2E8F0]'
|
||||||
|
|
||||||
export function Sistema() {
|
export function Sistema() {
|
||||||
const [form, setForm] = useState<Formulario>({
|
const [form, setForm] = useState<Formulario>({
|
||||||
@@ -75,15 +75,15 @@ export function Sistema() {
|
|||||||
|
|
||||||
if (cargando) {
|
if (cargando) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm">
|
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<p className="text-sm text-[#64748B]">Cargando configuraciones…</p>
|
<p className="text-sm text-[#64748B] dark:text-[#94A3B8]">Cargando configuraciones…</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm">
|
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<h2 className="text-lg font-semibold text-[#111827]">Configuración del sistema</h2>
|
<h2 className="text-lg font-semibold text-[#111827] dark:text-[#E2E8F0]">Configuración del sistema</h2>
|
||||||
|
|
||||||
<div className="mt-6 grid gap-6 sm:grid-cols-2">
|
<div className="mt-6 grid gap-6 sm:grid-cols-2">
|
||||||
{/* Recordatorio inactividad */}
|
{/* Recordatorio inactividad */}
|
||||||
|
|||||||
@@ -120,8 +120,8 @@ export function Usuarios() {
|
|||||||
|
|
||||||
if (cargando) {
|
if (cargando) {
|
||||||
return (
|
return (
|
||||||
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm">
|
<div className="rounded-xl border border-[#E5E7EB] bg-white p-6 shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<p className="text-sm text-[#64748B]">Cargando usuarios…</p>
|
<p className="text-sm text-[#64748B] dark:text-[#94A3B8]">Cargando usuarios…</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -133,8 +133,8 @@ export function Usuarios() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Búsqueda */}
|
{/* Búsqueda */}
|
||||||
<div className="rounded-xl border border-[#E5E7EB] bg-white p-4 shadow-sm">
|
<div className="rounded-xl border border-[#E5E7EB] bg-white p-4 shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<label htmlFor="buscar-usuario" className="block text-xs font-medium text-[#4B5563]">
|
<label htmlFor="buscar-usuario" className="block text-xs font-medium text-[#4B5563] dark:text-[#CBD5E1]">
|
||||||
Buscar usuario
|
Buscar usuario
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -143,20 +143,20 @@ export function Usuarios() {
|
|||||||
value={busqueda}
|
value={busqueda}
|
||||||
onChange={(e) => setBusqueda(e.target.value)}
|
onChange={(e) => setBusqueda(e.target.value)}
|
||||||
placeholder="Nombre o usuario…"
|
placeholder="Nombre o usuario…"
|
||||||
className="mt-2 w-full max-w-sm rounded-lg border border-[#D1D5DB] bg-white px-3 py-2 text-sm text-[#111827] transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20"
|
className="mt-2 w-full max-w-sm rounded-lg border border-[#D1D5DB] bg-white px-3 py-2 text-sm text-[#111827] transition-colors focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#E2E8F0]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Tabla */}
|
{/* Tabla */}
|
||||||
<div className="overflow-x-auto rounded-xl border border-[#E5E7EB] bg-white shadow-sm">
|
<div className="overflow-x-auto rounded-xl border border-[#E5E7EB] bg-white shadow-sm dark:border-[#1E293B] dark:bg-[#1E293B]">
|
||||||
<table className="w-full text-left text-sm">
|
<table className="w-full text-left text-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-[#E5E7EB] bg-[#F9FAFB]">
|
<tr className="border-b border-[#E5E7EB] bg-[#F9FAFB] dark:border-[#334155] dark:bg-[#1E293B]">
|
||||||
<th className="px-4 py-3 font-medium text-[#111827]">Nombre</th>
|
<th className="px-4 py-3 font-medium text-[#111827] dark:text-[#E2E8F0]">Nombre</th>
|
||||||
<th className="px-4 py-3 font-medium text-[#111827]">Usuario</th>
|
<th className="px-4 py-3 font-medium text-[#111827] dark:text-[#E2E8F0]">Usuario</th>
|
||||||
<th className="px-4 py-3 font-medium text-[#111827]">Rol</th>
|
<th className="px-4 py-3 font-medium text-[#111827] dark:text-[#E2E8F0]">Rol</th>
|
||||||
<th className="px-4 py-3 font-medium text-[#111827]">Asignación</th>
|
<th className="px-4 py-3 font-medium text-[#111827] dark:text-[#E2E8F0]">Asignación</th>
|
||||||
<th className="px-4 py-3 text-center font-medium text-[#111827]">Activo</th>
|
<th className="px-4 py-3 text-center font-medium text-[#111827] dark:text-[#E2E8F0]">Activo</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -168,14 +168,14 @@ export function Usuarios() {
|
|||||||
</tr>
|
</tr>
|
||||||
) : (
|
) : (
|
||||||
filtrados.map((u) => (
|
filtrados.map((u) => (
|
||||||
<tr key={u.id} className="border-b border-[#E5E7EB] last:border-0">
|
<tr key={u.id} className="border-b border-[#E5E7EB] dark:border-[#334155] last:border-0">
|
||||||
<td className="whitespace-nowrap px-4 py-3 text-[#111827]">{u.nombre}</td>
|
<td className="whitespace-nowrap px-4 py-3 text-[#111827] dark:text-[#E2E8F0]">{u.nombre}</td>
|
||||||
<td className="whitespace-nowrap px-4 py-3 text-[#64748B]">{u.username}</td>
|
<td className="whitespace-nowrap px-4 py-3 text-[#64748B] dark:text-[#94A3B8]">{u.username}</td>
|
||||||
<td className="px-4 py-3">
|
<td className="px-4 py-3">
|
||||||
<select
|
<select
|
||||||
value={u.rol}
|
value={u.rol}
|
||||||
onChange={(e) => void cambiarRol(u.id, e.target.value)}
|
onChange={(e) => void cambiarRol(u.id, e.target.value)}
|
||||||
className="rounded-lg border border-[#D1D5DB] bg-white px-2 py-1.5 text-xs text-[#111827] focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20"
|
className="rounded-lg border border-[#D1D5DB] bg-white px-2 py-1.5 text-xs text-[#111827] focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#E2E8F0]"
|
||||||
>
|
>
|
||||||
{ROLES.map((r) => (
|
{ROLES.map((r) => (
|
||||||
<option key={r} value={r}>{ROL_LABELS[r]}</option>
|
<option key={r} value={r}>{ROL_LABELS[r]}</option>
|
||||||
@@ -186,7 +186,7 @@ export function Usuarios() {
|
|||||||
<select
|
<select
|
||||||
value={u.asignacion ?? ''}
|
value={u.asignacion ?? ''}
|
||||||
onChange={(e) => void cambiarAsignacion(u.id, e.target.value)}
|
onChange={(e) => void cambiarAsignacion(u.id, e.target.value)}
|
||||||
className="rounded-lg border border-[#D1D5DB] bg-white px-2 py-1.5 text-xs text-[#111827] focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20"
|
className="rounded-lg border border-[#D1D5DB] bg-white px-2 py-1.5 text-xs text-[#111827] focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/20 dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#E2E8F0]"
|
||||||
>
|
>
|
||||||
{ASIGNACIONES.map((a) => (
|
{ASIGNACIONES.map((a) => (
|
||||||
<option key={a} value={a}>{ASIGNACION_LABELS[a]}</option>
|
<option key={a} value={a}>{ASIGNACION_LABELS[a]}</option>
|
||||||
|
|||||||
@@ -4,15 +4,13 @@ import {
|
|||||||
Cell,
|
Cell,
|
||||||
} from 'recharts'
|
} from 'recharts'
|
||||||
import { fetchMiTablero, type MiTablero } from '../services/reporte-mi-tablero'
|
import { fetchMiTablero, type MiTablero } from '../services/reporte-mi-tablero'
|
||||||
|
import { axisTextColor, gridStroke, tooltipProps } from '../lib/chart-theme'
|
||||||
import KpiCard from './KpiCard'
|
import KpiCard from './KpiCard'
|
||||||
|
|
||||||
// ---------- Colores ----------
|
// ---------- Colores ----------
|
||||||
|
|
||||||
const COLORS = ['#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899', '#14B8A6']
|
const COLORS = ['#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6', '#EC4899', '#14B8A6']
|
||||||
|
|
||||||
const LIGHT_TEXT = '#64748B'
|
|
||||||
const GRID_LIGHT = '#E5E7EB'
|
|
||||||
|
|
||||||
// ---------- Sub-componentes ----------
|
// ---------- Sub-componentes ----------
|
||||||
|
|
||||||
function TituloSeccion({ children }: { children: string }) {
|
function TituloSeccion({ children }: { children: string }) {
|
||||||
@@ -129,16 +127,16 @@ export default function DashboardVendedor() {
|
|||||||
<TituloSeccion>Leads por día (últimos 30 días)</TituloSeccion>
|
<TituloSeccion>Leads por día (últimos 30 días)</TituloSeccion>
|
||||||
<ResponsiveContainer width="100%" height={260}>
|
<ResponsiveContainer width="100%" height={260}>
|
||||||
<BarChart data={tablero.leadsPorDia} margin={{ top: 8, right: 4, left: -16, bottom: 0 }}>
|
<BarChart data={tablero.leadsPorDia} margin={{ top: 8, right: 4, left: -16, bottom: 0 }}>
|
||||||
<CartesianGrid strokeDasharray="3 3" stroke={GRID_LIGHT} vertical={false} />
|
<CartesianGrid strokeDasharray="3 3" stroke={gridStroke()} vertical={false} />
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="fecha"
|
dataKey="fecha"
|
||||||
tickFormatter={(f: string) => f.slice(8)}
|
tickFormatter={(f: string) => f.slice(8)}
|
||||||
tick={{ fontSize: 10, fill: LIGHT_TEXT }}
|
tick={{ fontSize: 10, fill: axisTextColor() }}
|
||||||
interval="preserveStartEnd"
|
interval="preserveStartEnd"
|
||||||
/>
|
/>
|
||||||
<YAxis tick={{ fontSize: 10, fill: LIGHT_TEXT }} allowDecimals={false} />
|
<YAxis tick={{ fontSize: 10, fill: axisTextColor() }} allowDecimals={false} />
|
||||||
<Tooltip
|
<Tooltip
|
||||||
contentStyle={{ fontSize: 12, borderRadius: 8 }}
|
{...tooltipProps()}
|
||||||
labelFormatter={(f: unknown) => `Fecha: ${String(f)}`}
|
labelFormatter={(f: unknown) => `Fecha: ${String(f)}`}
|
||||||
formatter={(value: unknown) => [`${Number(value)} leads`, "Leads"]}
|
formatter={(value: unknown) => [`${Number(value)} leads`, "Leads"]}
|
||||||
/>
|
/>
|
||||||
@@ -166,16 +164,16 @@ export default function DashboardVendedor() {
|
|||||||
) : (
|
) : (
|
||||||
<ResponsiveContainer width="100%" height={260}>
|
<ResponsiveContainer width="100%" height={260}>
|
||||||
<BarChart data={datosOrigen} layout="vertical" margin={{ top: 8, right: 16, left: 8, bottom: 0 }}>
|
<BarChart data={datosOrigen} layout="vertical" margin={{ top: 8, right: 16, left: 8, bottom: 0 }}>
|
||||||
<CartesianGrid strokeDasharray="3 3" stroke={GRID_LIGHT} horizontal={false} />
|
<CartesianGrid strokeDasharray="3 3" stroke={gridStroke()} horizontal={false} />
|
||||||
<XAxis type="number" tick={{ fontSize: 10, fill: LIGHT_TEXT }} allowDecimals={false} />
|
<XAxis type="number" tick={{ fontSize: 10, fill: axisTextColor() }} allowDecimals={false} />
|
||||||
<YAxis
|
<YAxis
|
||||||
type="category"
|
type="category"
|
||||||
dataKey="origen"
|
dataKey="origen"
|
||||||
tick={{ fontSize: 10, fill: LIGHT_TEXT }}
|
tick={{ fontSize: 10, fill: axisTextColor() }}
|
||||||
width={100}
|
width={100}
|
||||||
/>
|
/>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
contentStyle={{ fontSize: 12, borderRadius: 8 }}
|
{...tooltipProps()}
|
||||||
formatter={(value: unknown, name: unknown) => [`${Number(value)}`, String(name) === "total" ? "Total" : "Convertidos"]}
|
formatter={(value: unknown, name: unknown) => [`${Number(value)}`, String(name) === "total" ? "Total" : "Convertidos"]}
|
||||||
/>
|
/>
|
||||||
<Bar dataKey="total" fill="#3B82F6" radius={[0, 4, 4, 0]} maxBarSize={18} />
|
<Bar dataKey="total" fill="#3B82F6" radius={[0, 4, 4, 0]} maxBarSize={18} />
|
||||||
@@ -193,16 +191,16 @@ export default function DashboardVendedor() {
|
|||||||
) : (
|
) : (
|
||||||
<ResponsiveContainer width="100%" height={260}>
|
<ResponsiveContainer width="100%" height={260}>
|
||||||
<BarChart data={datosDesarrollo} layout="vertical" margin={{ top: 8, right: 16, left: 8, bottom: 0 }}>
|
<BarChart data={datosDesarrollo} layout="vertical" margin={{ top: 8, right: 16, left: 8, bottom: 0 }}>
|
||||||
<CartesianGrid strokeDasharray="3 3" stroke={GRID_LIGHT} horizontal={false} />
|
<CartesianGrid strokeDasharray="3 3" stroke={gridStroke()} horizontal={false} />
|
||||||
<XAxis type="number" tick={{ fontSize: 10, fill: LIGHT_TEXT }} allowDecimals={false} />
|
<XAxis type="number" tick={{ fontSize: 10, fill: axisTextColor() }} allowDecimals={false} />
|
||||||
<YAxis
|
<YAxis
|
||||||
type="category"
|
type="category"
|
||||||
dataKey="desarrollo"
|
dataKey="desarrollo"
|
||||||
tick={{ fontSize: 10, fill: LIGHT_TEXT }}
|
tick={{ fontSize: 10, fill: axisTextColor() }}
|
||||||
width={90}
|
width={90}
|
||||||
/>
|
/>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
contentStyle={{ fontSize: 12, borderRadius: 8 }}
|
{...tooltipProps()}
|
||||||
formatter={(value: unknown) => [`${Number(value)} ventas`, "Ventas"]}
|
formatter={(value: unknown) => [`${Number(value)} ventas`, "Ventas"]}
|
||||||
/>
|
/>
|
||||||
<Bar dataKey="ventas" fill="#8B5CF6" radius={[0, 4, 4, 0]} maxBarSize={18}>
|
<Bar dataKey="ventas" fill="#8B5CF6" radius={[0, 4, 4, 0]} maxBarSize={18}>
|
||||||
|
|||||||
@@ -8,6 +8,21 @@
|
|||||||
--color-accent-hover: #1D4ED8;
|
--color-accent-hover: #1D4ED8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--chart-grid: #E5E7EB;
|
||||||
|
--chart-text: #64748B;
|
||||||
|
--chart-tooltip-bg: white;
|
||||||
|
--chart-tooltip-border: #E5E7EB;
|
||||||
|
--chart-tooltip-text: #111827;
|
||||||
|
}
|
||||||
|
.dark {
|
||||||
|
--chart-grid: #334155;
|
||||||
|
--chart-text: #94A3B8;
|
||||||
|
--chart-tooltip-bg: #1E293B;
|
||||||
|
--chart-tooltip-border: #334155;
|
||||||
|
--chart-tooltip-text: #E2E8F0;
|
||||||
|
}
|
||||||
|
|
||||||
@layer base {
|
@layer base {
|
||||||
body {
|
body {
|
||||||
@apply bg-[#F8FAFC] text-[#111827] antialiased;
|
@apply bg-[#F8FAFC] text-[#111827] antialiased;
|
||||||
|
|||||||
24
apps/mi-dia/src/lib/chart-theme.ts
Normal file
24
apps/mi-dia/src/lib/chart-theme.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Helpers de tema para gráficas Recharts.
|
||||||
|
*
|
||||||
|
* Recharts renderiza SVG puro y no resuelve CSS custom properties en
|
||||||
|
* atributos como `fill` / `stroke`, así que necesitamos funciones que
|
||||||
|
* lean el estado dark-mode del documento y devuelvan los colores
|
||||||
|
* apropiados como strings literales.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** `true` cuando el `<html>` lleva la clase `dark` (Tailwind convention). */
|
||||||
|
export const isDark = (): boolean =>
|
||||||
|
typeof document !== 'undefined' && document.documentElement.classList.contains('dark')
|
||||||
|
|
||||||
|
/** Color de texto para los ejes (XAxis / YAxis tick fill). */
|
||||||
|
export const axisTextColor = (): string => (isDark() ? '#94A3B8' : '#64748B')
|
||||||
|
|
||||||
|
/** Color de la cuadrícula (CartesianGrid stroke). */
|
||||||
|
export const gridStroke = (): string => (isDark() ? '#334155' : '#E5E7EB')
|
||||||
|
|
||||||
|
/** Props comunes de Tooltip para aplicar estilo dark/light. */
|
||||||
|
export const tooltipProps = (): Record<string, unknown> =>
|
||||||
|
isDark()
|
||||||
|
? { contentStyle: { backgroundColor: '#1E293B', borderColor: '#334155', color: '#E2E8F0', borderRadius: 8, fontSize: 12 } }
|
||||||
|
: { contentStyle: { borderRadius: 8, fontSize: 12 } }
|
||||||
@@ -236,7 +236,7 @@ function FilaOportunidad({
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={enviando}
|
disabled={enviando}
|
||||||
onClick={onAfluencia}
|
onClick={onAfluencia}
|
||||||
className="rounded-lg border border-accent bg-white px-3 py-1.5 text-xs font-medium text-accent shadow-sm transition-all duration-100 ease-out hover:bg-accent hover:text-white disabled:opacity-50"
|
className="rounded-lg border border-accent bg-white px-3 py-1.5 text-xs font-medium text-accent shadow-sm transition-all duration-100 ease-out hover:bg-accent hover:text-white disabled:opacity-50 dark:bg-[#0F172A] dark:border-accent dark:text-accent"
|
||||||
>
|
>
|
||||||
Afluencia →
|
Afluencia →
|
||||||
</button>
|
</button>
|
||||||
@@ -277,7 +277,7 @@ function FilaOportunidad({
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={enviando || (acciones !== undefined && !acciones.includes('descartar_lead'))}
|
disabled={enviando || (acciones !== undefined && !acciones.includes('descartar_lead'))}
|
||||||
onClick={onDescartar}
|
onClick={onDescartar}
|
||||||
className="rounded-lg border border-red-200 bg-white px-3 py-1.5 text-xs font-medium text-red-600 shadow-sm transition-all duration-100 ease-out hover:bg-red-50 disabled:opacity-50"
|
className="rounded-lg border border-red-200 bg-white px-3 py-1.5 text-xs font-medium text-red-600 shadow-sm transition-all duration-100 ease-out hover:bg-red-50 disabled:opacity-50 dark:bg-[#0F172A] dark:border-red-800 dark:text-red-400"
|
||||||
>
|
>
|
||||||
Descartar
|
Descartar
|
||||||
</button>
|
</button>
|
||||||
@@ -339,7 +339,7 @@ function FilaApartado({
|
|||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
fase === 'Cancelacion Apartado'
|
fase === 'Cancelacion Apartado'
|
||||||
? 'rounded-lg border border-red-200 bg-white px-3 py-1.5 text-xs font-medium text-red-600 shadow-sm transition-all duration-100 ease-out hover:bg-red-50 disabled:opacity-50'
|
? 'rounded-lg border border-red-200 bg-white px-3 py-1.5 text-xs font-medium text-red-600 shadow-sm transition-all duration-100 ease-out hover:bg-red-50 disabled:opacity-50 dark:bg-[#0F172A] dark:border-red-800 dark:text-red-400'
|
||||||
: fase === 'Firma Cliente (Venta)'
|
: fase === 'Firma Cliente (Venta)'
|
||||||
? 'rounded-lg bg-accent px-3 py-1.5 text-xs font-medium text-white shadow-sm transition-all duration-100 ease-out hover:bg-accent-hover disabled:opacity-50'
|
? 'rounded-lg bg-accent px-3 py-1.5 text-xs font-medium text-white shadow-sm transition-all duration-100 ease-out hover:bg-accent-hover disabled:opacity-50'
|
||||||
: fase === apartado.estado
|
: fase === apartado.estado
|
||||||
@@ -422,7 +422,7 @@ function PanelDocumentosApartado({ itemId }: { itemId: string }) {
|
|||||||
{slot.obligatorio && <span className="ml-1 text-red-600">*</span>}
|
{slot.obligatorio && <span className="ml-1 text-red-600">*</span>}
|
||||||
</p>
|
</p>
|
||||||
<label
|
<label
|
||||||
className={`cursor-pointer rounded-lg border border-accent bg-white px-3 py-1.5 text-xs font-medium text-accent transition-all duration-100 ease-out hover:bg-accent hover:text-white ${
|
className={`cursor-pointer rounded-lg border border-accent bg-white px-3 py-1.5 text-xs font-medium text-accent transition-all duration-100 ease-out hover:bg-accent hover:text-white dark:bg-[#0F172A] dark:border-accent dark:text-accent ${
|
||||||
subiendo !== null ? 'pointer-events-none opacity-50' : ''
|
subiendo !== null ? 'pointer-events-none opacity-50' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -574,7 +574,7 @@ function FilaLead({
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={enviando}
|
disabled={enviando}
|
||||||
onClick={onConvertir}
|
onClick={onConvertir}
|
||||||
className="rounded-lg border border-accent bg-white px-3 py-1.5 text-xs font-medium text-accent shadow-sm transition-all duration-100 ease-out hover:bg-accent hover:text-white disabled:opacity-50"
|
className="rounded-lg border border-accent bg-white px-3 py-1.5 text-xs font-medium text-accent shadow-sm transition-all duration-100 ease-out hover:bg-accent hover:text-white disabled:opacity-50 dark:bg-[#0F172A] dark:border-accent dark:text-accent"
|
||||||
>
|
>
|
||||||
Agendo →
|
Agendo →
|
||||||
</button>
|
</button>
|
||||||
@@ -582,7 +582,7 @@ function FilaLead({
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={enviando || (acciones !== undefined && !acciones.includes("descartar_lead"))}
|
disabled={enviando || (acciones !== undefined && !acciones.includes("descartar_lead"))}
|
||||||
onClick={onDescartar}
|
onClick={onDescartar}
|
||||||
className="rounded-lg border border-red-200 bg-white px-3 py-1.5 text-xs font-medium text-red-600 shadow-sm transition-all duration-100 ease-out hover:bg-red-50 disabled:opacity-50"
|
className="rounded-lg border border-red-200 bg-white px-3 py-1.5 text-xs font-medium text-red-600 shadow-sm transition-all duration-100 ease-out hover:bg-red-50 disabled:opacity-50 dark:bg-[#0F172A] dark:border-red-800 dark:text-red-400"
|
||||||
>
|
>
|
||||||
Descartar
|
Descartar
|
||||||
</button>
|
</button>
|
||||||
@@ -854,7 +854,7 @@ export default function MiDiaPage({ accionesSesion }: { accionesSesion: Acciones
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{resumen?.sinMapeoMonday && (
|
{resumen?.sinMapeoMonday && (
|
||||||
<p className="mb-6 rounded-lg border border-[#E5E7EB] bg-white px-4 py-3 text-sm font-medium text-[#64748B] dark:text-[#94A3B8] shadow-sm">
|
<p className="mb-6 rounded-lg border border-[#E5E7EB] bg-white px-4 py-3 text-sm font-medium text-[#64748B] dark:text-[#94A3B8] shadow-sm dark:bg-[#1E293B] dark:border-[#1E293B]">
|
||||||
Tu usuario aún no está vinculado a Monday; las acciones siguen funcionando
|
Tu usuario aún no está vinculado a Monday; las acciones siguen funcionando
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -907,7 +907,7 @@ export default function MiDiaPage({ accionesSesion }: { accionesSesion: Acciones
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => exportarLeads(leadsFiltrados)}
|
onClick={() => exportarLeads(leadsFiltrados)}
|
||||||
className="rounded-lg border border-[#D1D5DB] bg-white px-3 py-1.5 text-xs font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB]"
|
className="rounded-lg border border-[#D1D5DB] bg-white px-3 py-1.5 text-xs font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB] dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#CBD5E1]"
|
||||||
>
|
>
|
||||||
Exportar
|
Exportar
|
||||||
</button>
|
</button>
|
||||||
@@ -949,7 +949,7 @@ export default function MiDiaPage({ accionesSesion }: { accionesSesion: Acciones
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => exportarOportunidades(opsFiltradas)}
|
onClick={() => exportarOportunidades(opsFiltradas)}
|
||||||
className="rounded-lg border border-[#D1D5DB] bg-white px-3 py-1.5 text-xs font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB]"
|
className="rounded-lg border border-[#D1D5DB] bg-white px-3 py-1.5 text-xs font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB] dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#CBD5E1]"
|
||||||
>
|
>
|
||||||
Exportar
|
Exportar
|
||||||
</button>
|
</button>
|
||||||
@@ -995,7 +995,7 @@ export default function MiDiaPage({ accionesSesion }: { accionesSesion: Acciones
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => exportarApartados(apartadosFiltrados)}
|
onClick={() => exportarApartados(apartadosFiltrados)}
|
||||||
className="rounded-lg border border-[#D1D5DB] bg-white px-3 py-1.5 text-xs font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB]"
|
className="rounded-lg border border-[#D1D5DB] bg-white px-3 py-1.5 text-xs font-medium text-[#374151] shadow-sm transition-all duration-100 ease-out hover:bg-[#F9FAFB] dark:bg-[#0F172A] dark:border-[#334155] dark:text-[#CBD5E1]"
|
||||||
>
|
>
|
||||||
Exportar
|
Exportar
|
||||||
</button>
|
</button>
|
||||||
@@ -1040,7 +1040,7 @@ export default function MiDiaPage({ accionesSesion }: { accionesSesion: Acciones
|
|||||||
{resumen.misCapturas.map((c) => (
|
{resumen.misCapturas.map((c) => (
|
||||||
<li
|
<li
|
||||||
key={c.leadId}
|
key={c.leadId}
|
||||||
className="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm"
|
className="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm dark:bg-[#1E293B] dark:border-[#1E293B]"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p className="flex items-center gap-2 text-sm font-medium">
|
<p className="flex items-center gap-2 text-sm font-medium">
|
||||||
@@ -1075,7 +1075,7 @@ export default function MiDiaPage({ accionesSesion }: { accionesSesion: Acciones
|
|||||||
{resumen.misClientes.map((c) => (
|
{resumen.misClientes.map((c) => (
|
||||||
<li
|
<li
|
||||||
key={c.id}
|
key={c.id}
|
||||||
className="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm"
|
className="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm dark:bg-[#1E293B] dark:border-[#1E293B]"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm font-medium">{c.nombre}</p>
|
<p className="text-sm font-medium">{c.nombre}</p>
|
||||||
@@ -1120,7 +1120,7 @@ export default function MiDiaPage({ accionesSesion }: { accionesSesion: Acciones
|
|||||||
{resumen.misActividadesHoy.map((a) => (
|
{resumen.misActividadesHoy.map((a) => (
|
||||||
<li
|
<li
|
||||||
key={a.id}
|
key={a.id}
|
||||||
className="flex items-center justify-between gap-3 rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm"
|
className="flex items-center justify-between gap-3 rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm dark:bg-[#1E293B] dark:border-[#1E293B]"
|
||||||
>
|
>
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{a.nombre}
|
{a.nombre}
|
||||||
@@ -1146,7 +1146,7 @@ export default function MiDiaPage({ accionesSesion }: { accionesSesion: Acciones
|
|||||||
{resumen.apartadosPorVencer.map((a) => (
|
{resumen.apartadosPorVencer.map((a) => (
|
||||||
<li
|
<li
|
||||||
key={a.id}
|
key={a.id}
|
||||||
className="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm"
|
className="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm dark:bg-[#1E293B] dark:border-[#1E293B]"
|
||||||
>
|
>
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{a.nombre}
|
{a.nombre}
|
||||||
@@ -1309,7 +1309,7 @@ export default function MiDiaPage({ accionesSesion }: { accionesSesion: Acciones
|
|||||||
{resumen.equipo.porVendedor.map((v) => (
|
{resumen.equipo.porVendedor.map((v) => (
|
||||||
<li
|
<li
|
||||||
key={v.mondayUserId}
|
key={v.mondayUserId}
|
||||||
className="flex items-center justify-between rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm"
|
className="flex items-center justify-between rounded-xl border border-[#E5E7EB] bg-white px-4 py-3 shadow-sm dark:bg-[#1E293B] dark:border-[#1E293B]"
|
||||||
>
|
>
|
||||||
<p className="text-sm">{v.nombre ?? `Monday #${v.mondayUserId}`}</p>
|
<p className="text-sm">{v.nombre ?? `Monday #${v.mondayUserId}`}</p>
|
||||||
<span className="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium text-gray-600">
|
<span className="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium text-gray-600">
|
||||||
|
|||||||
Reference in New Issue
Block a user