Oleada UX 6: Reportes agrupados en familias con rango global persistente y favoritos; Configuracion con auditoria de cambios y simulador de comisiones

This commit is contained in:
2026-09-17 22:06:11 +00:00
parent cd945df6a5
commit 31c92ac419
21 changed files with 1325 additions and 137 deletions

View File

@@ -1,12 +1,14 @@
import type { FC } from 'react';
import { useEffect, useState } from 'react';
import { useSearchParams } from 'react-router-dom';
import { Phone, MapPin, Mail, Globe, Save, Building2, ArrowRightLeft, Percent, Check } from 'lucide-react';
import { Phone, MapPin, Mail, Globe, Save, Building2, ArrowRightLeft, Percent, Check, Calculator } from 'lucide-react';
import Layout from '../components/Layout';
import UsuariosPanel from '../components/UsuariosPanel';
import RolesPanel from '../components/RolesPanel';
import RecetasPanel from '../components/RecetasPanel';
import CatalogoPanel from '../components/CatalogoPanel';
import AuditoriaPanel from '../components/AuditoriaPanel';
import ImpactoModal from '../components/ImpactoModal';
import { Card, Button, Input, PageHeader, toast } from '../components/ui';
import { odooApi, type Doctor } from '../services/odoo';
@@ -16,6 +18,7 @@ const TABS = [
{ key: 'roles', label: 'Roles' },
{ key: 'recetas', label: 'Recetas' },
{ key: 'catalogos', label: 'Catálogos' },
{ key: 'auditoria', label: 'Auditoría' },
] as const;
const SUBCATALOGOS = [
@@ -117,6 +120,7 @@ const Configuracion: FC = () => {
const [commissionInputs, setCommissionInputs] = useState<Record<number, string>>({});
const [commissionSavingId, setCommissionSavingId] = useState<number | null>(null);
const [commissionSavedId, setCommissionSavedId] = useState<number | null>(null);
const [impactoOpen, setImpactoOpen] = useState(false);
useEffect(() => {
odooApi.getCommissionDefault()
@@ -212,6 +216,8 @@ const Configuracion: FC = () => {
<RecetasPanel />
</Card.Body>
</Card>
) : tab === 'auditoria' ? (
<AuditoriaPanel />
) : tab === 'catalogos' ? (
<Card>
<Card.Body>
@@ -387,6 +393,18 @@ const Configuracion: FC = () => {
<p className="text-sm text-theme-muted mb-4">
Porcentaje de comisión sobre las ventas atribuidas a cada médico (visible en su página "Mis ventas").
</p>
<div className="mb-5 p-4 bg-theme-bg rounded-xl flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">
<div>
<p className="text-sm font-medium text-theme-heading">¿Cuánto costaría esta configuración?</p>
<p className="text-xs text-theme-muted">
Simula la comisión de cada médico con las ventas atribuidas reales de un mes, sin guardar nada.
</p>
</div>
<Button variant="outline" onClick={() => setImpactoOpen(true)}>
<Calculator size={16} className="mr-2" />
Ver efecto
</Button>
</div>
<div className="flex flex-col sm:flex-row items-start sm:items-end gap-3 max-w-md mb-6">
<div className="flex-1 w-full">
<Input
@@ -467,6 +485,12 @@ const Configuracion: FC = () => {
</Card>
</div>
)}
<ImpactoModal
isOpen={impactoOpen}
onClose={() => setImpactoOpen(false)}
comisionGlobal={parseFloat(commissionDefault) || 0}
/>
</Layout>
);
};