Mejoras integrales: visitas, POS, WACRM, reportes, temas y módulos legacy

- Módulo Visitas completo (auto desde agenda, insumos con descargo de
  inventario, fotos antes/después y documentos, receta imprimible)
- Punto de Venta (catálogo + ticket sticky, cobro con cambio, pago con
  puntos monedero, ticket imprimible)
- WACRM: leads automáticos desde WhatsApp, asignación de conversaciones
  y leads a agentes, conversión lead→paciente, ficha del paciente en chat
- Pacientes: completitud de expediente, alertas clínicas, historial
  unificado con detalle, foto, WhatsApp, estado de cuenta, filtros
  rápidos (VIP/recientes/médico), documentos (expediente escaneado + galería)
- Agenda: vistas por médico y por hora, filtros rápidos (libres, primera
  vez, check-in, no-show), modal de acciones, bloqueos por médico,
  drag&drop para mover citas
- Reportes: 18 pestañas (diario, cortes, ingresos, inventario, adeudos,
  comisiones, pagos, devoluciones, top clientes, horas, paquetes,
  vendedores, concentrado, recomendaciones, KPIs) con exportación Excel
- Temas: nuevo tema Clásico (look legacy AdminLTE) con submenús tipo
  treeview, selector de tema; accesos rápidos personalizables con 3
  presentaciones; búsqueda global; notificaciones reales
- Configuración: secciones (clínica, usuarios con permisos por sección,
  recetas, catálogos de diagnósticos y procedimientos)
- Inventario: alertas de caducidad y sugerencia de compra, cron diario
  que descuenta artículos caducados, compras/bajas
- Consultas Médicas, página Expedientes, importadores delta
  (citas/visitas legacy idempotentes), depuración de duplicados
- Infra: tema Tailwind conectado (@config), gzip en nginx, secuencias
  Odoo corregidas (noupdate, company_id), rollback en validaciones
This commit is contained in:
2026-08-13 23:30:08 +00:00
parent a718592291
commit 01f6007e30
109 changed files with 19067 additions and 931 deletions

View File

@@ -1,5 +1,6 @@
import type { FC, ReactNode } from 'react';
import { useEffect, useState, useMemo } from 'react';
import { useNavigate } from 'react-router-dom';
import {
Calendar,
Users,
@@ -40,6 +41,7 @@ import {
} from '../components/ui';
import { odooApi, type DashboardStats, type Appointment, type Service, type ChartPoint } from '../services/odoo';
import { useTheme } from '../lib/theme';
import { useAuth } from '../lib/auth';
const formatCurrency = (value: number) =>
new Intl.NumberFormat('es-MX', { style: 'currency', currency: 'MXN', maximumFractionDigits: 0 }).format(value);
@@ -76,6 +78,8 @@ const StatCard: FC<StatCardProps> = ({ title, value, icon, trend, loading }) =>
const Dashboard: FC = () => {
const { theme } = useTheme();
const { user } = useAuth();
const navigate = useNavigate();
const isHomeNest = theme === 'homenest';
const [stats, setStats] = useState<DashboardStats | null>(null);
const [chartData, setChartData] = useState<ChartPoint[]>([]);
@@ -256,10 +260,10 @@ const Dashboard: FC = () => {
</p>
</div>
<div className="flex flex-wrap gap-3 shrink-0">
<Button variant="primary" size="md">
<Button variant="primary" size="md" onClick={() => navigate('/agenda')}>
<Calendar size={16} className="mr-2" /> Nueva cita
</Button>
<Button variant="outline" size="md">
<Button variant="outline" size="md" onClick={() => navigate('/reportes')}>
<TrendingUp size={16} className="mr-2" /> Ver reportes
</Button>
</div>
@@ -277,10 +281,10 @@ const Dashboard: FC = () => {
) : (
<>
<PageHeader title="Dashboard" subtitle="Resumen general de la clínica">
<Button variant="outline" size="sm">
<Sparkles size={16} className="mr-2" />
Bienvenido
</Button>
<span className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full text-sm font-medium bg-theme-accent-bg text-theme-heading">
<Sparkles size={16} />
Bienvenido{user?.name ? `, ${user.name.split(' ')[0]}` : ''}
</span>
</PageHeader>
<div className="bg-gradient-to-r from-[#EDA588] to-[#C7BCDD] rounded-2xl p-6 sm:p-8 text-white mb-6 sm:mb-8 shadow-sm">
@@ -292,7 +296,7 @@ const Dashboard: FC = () => {
</p>
</div>
<div className="shrink-0">
<Button variant="secondary" size="sm" className="bg-theme-surface/20 text-white border-white/30 hover:bg-theme-surface/30">
<Button variant="secondary" size="sm" className="bg-theme-surface/20 text-white border-white/30 hover:bg-theme-surface/30" onClick={() => navigate('/reportes')}>
<TrendingUp size={16} className="mr-2" />
Ver reportes
</Button>