Fase 1 - UI: dark mode, skeletons, toasts Fase 2 - Filtros: avanzados Mi día, búsqueda global Ctrl+K Fase 3 - Datos: export Excel, notas apartados, auditoría Fase 4 - Dashboard: gráficas vendedor + métricas uso Fase 5 - Responsive: tablets optimizadas Fase 6 - PWA: IndexedDB offline, push notifications Backend: 3 tablas nuevas, 6 services, 6 endpoints nuevos 721 API tests + fronts verdes.
39 lines
1.4 KiB
TypeScript
39 lines
1.4 KiB
TypeScript
// Piezas visuales compartidas por las vistas del tablero (NovaSpark)
|
|
|
|
import type { ReactNode } from 'react'
|
|
|
|
/**
|
|
* Acciones que cada vista del tablero expone al header de DashboardPage:
|
|
* el botón "Actualizar" vive en el header sticky y dispara la recarga de la
|
|
* vista activa (sin cambiar fuentes de datos ni consultas).
|
|
*/
|
|
export type AccionesTablero = { actualizar: () => void; cargando: boolean }
|
|
|
|
export function EstadoVacio({ mensaje }: { mensaje: string }) {
|
|
return (
|
|
<div className="flex h-64 items-center justify-center rounded-xl border border-dashed border-[#E5E7EB] bg-white dark:border-[#334155] dark:bg-[#1E293B]">
|
|
<p className="text-xs font-medium uppercase tracking-wider text-[#64748B] dark:text-[#94A3B8]">{mensaje}</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function TituloSeccion({ children }: { children: string }) {
|
|
return <h2 className="mb-4 text-xs font-semibold uppercase tracking-wider text-[#64748B] dark:text-[#94A3B8]">{children}</h2>
|
|
}
|
|
|
|
/** Tarjeta contenedora de gráficas: título interno + padding consistente. */
|
|
export function TarjetaGrafica({
|
|
titulo,
|
|
children,
|
|
}: {
|
|
titulo: string
|
|
children: ReactNode
|
|
}) {
|
|
return (
|
|
<div className="rounded-xl border border-[#E5E7EB] bg-white p-5 dark:border-[#1E293B] dark:bg-[#1E293B] shadow-sm">
|
|
<h3 className="mb-4 text-xs font-semibold uppercase tracking-wider text-[#64748B] dark:text-[#94A3B8]">{titulo}</h3>
|
|
{children}
|
|
</div>
|
|
)
|
|
}
|