fase 2.6: membresias y suscripciones (modulo skeen_membresias: planes recurrentes con sesiones incluidas o ilimitadas, alta/cobro/renovacion/congelamiento/cancelacion, consumo de sesiones desde POS y expediente, cron de vencimientos y avisos, reporte de ingresos recurrentes); apagado por defecto

This commit is contained in:
2026-10-11 10:49:44 +00:00
parent 9286ab8ee2
commit 8ff13b9c2a
33 changed files with 3873 additions and 22 deletions

View File

@@ -36,6 +36,7 @@ import {
TicketCheck,
Layers,
Download,
Repeat,
} from 'lucide-react';
import { Button, Modal, Input } from './ui';
import QuickLinksDock, { QuickLinksModePicker } from './QuickLinksDock';
@@ -44,6 +45,7 @@ import ThemePicker from './ThemePicker';
import NotificationBell from './NotificationBell';
import { useAuth } from '../lib/auth';
import { useGlosario, traducirMenu, traducirEtiqueta } from '../lib/glosario';
import { useClinicSettings } from '../lib/clinic-settings';
import { useChatUnread } from '../lib/chat';
import { useQuickLinks } from '../lib/quicklinks';
import { odooApi } from '../services/odoo';
@@ -110,16 +112,26 @@ const MENU_SECTIONS = [
},
];
const HOME_MEMBRESIA_ITEM = { label: 'Membresías', icon: Repeat, href: '/membresias' };
export const HomeNestLayout: FC<LayoutProps> = ({ children, title: _title, subtitle: _subtitle }) => {
const location = useLocation();
const navigate = useNavigate();
const { user, canSee, hasRole, logout, brand } = useAuth();
const { term } = useGlosario();
const { membresias: membresiasCfg } = useClinicSettings();
const topNavItems = useMemo(
() => TOP_NAV_ITEMS.map((it) => ({ ...it, label: traducirEtiqueta(it.label, term) })),
[term]
);
const menuSections = useMemo(() => traducirMenu(MENU_SECTIONS, term), [term]);
const menuSections = useMemo(() => {
const base = membresiasCfg.activo
? MENU_SECTIONS.map((s) => (s.label === 'Clínica'
? { ...s, items: [...s.items, HOME_MEMBRESIA_ITEM] }
: s))
: MENU_SECTIONS;
return traducirMenu(base, term);
}, [term, membresiasCfg.activo]);
const [menuOpen, setMenuOpen] = useState(false);
const [expanded, setExpanded] = useState<string[]>(['Clínica']);
const chatUnread = useChatUnread();