// ============ PRISMA · PANEL CLIENTE — core ============
const { useState, useEffect, useRef, useMemo } = React;
// ---- helpers ----
function hexA(hex, a) {
const n = parseInt(hex.slice(1), 16);
const r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255;
return `rgba(${r},${g},${b},${a})`;
}
function useMeasure() {
const ref = useRef(null);
const [w, setW] = useState(0);
useEffect(() => {
if (!ref.current) return;
const ro = new ResizeObserver((e) => {
const cw = e[0].contentRect.width;
if (cw > 0) setW(cw);
});
ro.observe(ref.current);
return () => ro.disconnect();
}, []);
return [ref, w];
}
// ---- accent palette ----
const CL_ACCENT = {
magenta: '#E8175D', azul: '#3B9EE0', indigo: '#5059A8', teal: '#0D9E8A',
ok: '#22C55E', warn: '#F59E0B', bad: '#EF4444',
};
const acHex = (k) => CL_ACCENT[k] || '#5059A8';
// ---- status: DB values (available/reserved/sold) <-> display (disponible/reservado/vendido) ----
const DB_TO_DISPLAY = { available: 'disponible', reserved: 'reservado', sold: 'vendido' };
const DISPLAY_TO_DB = { disponible: 'available', reservado: 'reserved', vendido: 'sold' };
const CL_STATUS = {
disponible: { label: 'Disponible', color: '#22C55E' },
reservado: { label: 'Reservado', color: '#F59E0B' },
vendido: { label: 'Vendido', color: '#EF4444' },
};
const CL_STATUS_CYCLE = ['disponible', 'reservado', 'vendido'];
function clCountStatuses(rows) {
const c = { disponible: 0, reservado: 0, vendido: 0 };
rows.forEach(r => r.floors.forEach(f => { c[f.status]++; }));
return c;
}
// ---- periodos para métricas ----
const CL_PERIODS = [
{ id: 'hoy', label: 'Hoy', days: 0 },
{ id: '3d', label: '3 días', days: 3 },
{ id: '7d', label: '7 días', days: 7 },
{ id: '1m', label: '1 mes', days: 30 },
{ id: '3m', label: '3 meses', days: 90 },
{ id: '6m', label: '6 meses', days: 180 },
];
function clRangeStart(periodId) {
const p = CL_PERIODS.find(x => x.id === periodId);
if (!p || p.days === 0) {
const d = new Date();
d.setHours(0, 0, 0, 0);
return d.toISOString();
}
return new Date(Date.now() - p.days * 86400000).toISOString();
}
// evento tipo → label legible
const CL_TIPO_LABEL = {
vista_seccion: 'Vista de sección',
click_unidad: 'Vista de unidad',
click_whatsapp: 'Click WhatsApp',
click_pdf: 'Descarga de PDF',
click_360: 'Recorrido 360°',
click_piso: 'Vista de piso',
click_qr: 'Escaneo QR',
};
const CL_TIPO_KIND = {
vista_seccion: 'view', click_unidad: 'view',
click_whatsapp: 'whatsapp', click_pdf: 'pdf',
click_360: 'tour', click_piso: 'view', click_qr: 'pdf',
};
Object.assign(window, {
hexA, useMeasure, acHex,
CL_ACCENT, CL_STATUS, CL_STATUS_CYCLE,
DB_TO_DISPLAY, DISPLAY_TO_DB,
clCountStatuses, CL_PERIODS, clRangeStart,
CL_TIPO_LABEL, CL_TIPO_KIND,
});
// ============ icons ============
const Ic = ({ d, size = 18, sw = 1.6, fill = 'none', children, ...p }) => (
);
const CiDashboard = (p) =>