/* GestiFalla — iconos + componentes compartidos */ const { useState, useEffect, useRef } = React; window.useState = React.useState; window.useEffect = React.useEffect; window.useRef = React.useRef; /* ---------- Icon set (outline, 20px viewBox 24) ---------- */ const I = { bell: (p) => , chat: (p) => , chevR: (p) => , chevD: (p) => , back: (p) => , star: (p) => , home: (p) => , id: (p) => , calendar: (p) => , wallet: (p) => , user: (p) => , transfer: (p) => , plus: (p) => , list: (p) => , cart: (p) => , users: (p) => , euro: (p) => , doc: (p) => , home2: (p) => , pin: (p) => , note: (p) => , check: (p) => , eye: (p) => , eyeOff: (p) => , share: (p) => , download: (p) => , shield: (p) => , logout: (p) => , bellGear: (p) => , qr: (p) => , ticket: (p) => , arrowUp: (p) => , arrowDown: (p) => , clock: (p) => , }; /* ---------- Avatar ---------- */ function Avatar({ name, src, size = 44, fontSize, ring }) { const initials = name ? name.split(' ').slice(0,2).map(w => w[0]).join('').toUpperCase() : '?'; const st = { width: size, height: size, fontSize: fontSize || size * 0.36 }; if (ring) Object.assign(st, { boxShadow: `0 0 0 ${ring}px rgba(255,255,255,0.25)` }); if (src) return {name}; return
{initials}
; } /* ---------- Header universal ---------- */ function Header({ children }) { return
{children}
; } function HeaderBrand({ onBell, onChat, notif = true }) { return (
GestiFalla
); } function SubHeader({ title, onBack, right }) { return ( <>
{onBack && }
{title}
{right}
); } /* ---------- Data cell ---------- */ function Cell({ label, value }) { return (
{label}
{value}
); } /* ---------- Bottom nav ---------- */ const NAV = [ { id: 'home', label: 'Inicio', icon: I.home }, { id: 'ficha', label: 'Mi ficha', icon: I.id }, { id: 'eventos', label: 'Eventos', icon: I.calendar }, { id: 'monedero', label: 'Monedero', icon: I.wallet }, { id: 'perfil', label: 'Perfil', icon: I.user }, ]; function BottomNav({ active, onNav }) { return ( ); } /* ---------- Toast ---------- */ function Toast({ msg, show }) { if (!show) return null; return (
{msg}
); } function useToast() { const [toast, setToast] = useState(null); const fire = (msg) => { setToast(msg); }; useEffect(() => { if (toast) { const t = setTimeout(() => setToast(null), 2500); return () => clearTimeout(t); } }, [toast]); return [toast, fire]; } /* ---------- Bottom sheet ---------- */ function Sheet({ open, onClose, title, children }) { if (!open) return null; return (
e.stopPropagation()}>
{title &&
{title}
} {children}
); } /* ---------- QR code (deterministic pseudo-pattern) ---------- */ function QR({ size = 96, fg = '#0d2a50', seed = 7 }) { const n = 21; const cell = size / n; const rects = []; let s = seed; const rnd = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; }; const finder = (x, y) => x < 7 && y < 7 || x >= n-7 && y < 7 || x < 7 && y >= n-7; for (let y = 0; y < n; y++) for (let x = 0; x < n; x++) { if (finder(x,y)) continue; if (rnd() > 0.52) rects.push(); } const Finder = ({ x, y }) => ( ); return ( {rects} ); } Object.assign(window, { I, Avatar, Header, HeaderBrand, SubHeader, Cell, BottomNav, NAV, Toast, useToast, Sheet, QR });