// WealthIntelligence — shared UI components const { useState, useEffect, useMemo, useRef, useCallback } = React; // ------- Icons (line set) ------- const Icon = ({name, size=18, stroke=1.6, style={}}) => { const paths = { home: , inventory: , people: <>, vault: <>, informed: , profile: <>, search: <>, plus: , arrow_right: , close: , check: , chevron_right: , chevron_down: , dot_menu: <>, filter: , shield: , mail: , lock: <>, unlock: <>, clock: <>, eye_off: , sparkle: , bell: <>, settings: <>, edit: , trash: , alert: <>, activity: , medkit: <>, key: <>, }; return React.createElement('svg', { width:size, height:size, viewBox:'0 0 24 24', fill:'none', stroke:'currentColor', strokeWidth:stroke, strokeLinecap:'round', strokeLinejoin:'round', style, }, paths[name] || null); }; // ------- Monogram ------- const Monogram = ({name, color='#307D86', initials, size='md'}) => { const init = initials || (name||'').split(' ').map(w=>w[0]).join('').slice(0,2).toUpperCase(); return {init}; }; // ------- Stacked monograms ------- const MonoStack = ({people, size='sm', max=3}) => { if (!people || !people.length) return null; const shown = people.slice(0, max); const more = people.length - max; return {shown.map(p => )} {more > 0 && +{more}} ; }; // ------- Cassetta icon badge ------- const CassettaBadge = ({icon, color, size=38}) => ( {icon} ); // ------- Trigger badge ------- const TriggerBadge = ({trigger, t, short=false}) => { const cls = trigger==='temporary' ? 'temporary' : 'permanent'; const label = short ? t.vault.triggers[`${cls}_short`] : t.vault.triggers[cls]; return {label} ; }; // ------- Sidebar ------- const Sidebar = ({route, setRoute, t, state}) => { const unassignedItems = state.inventory.filter(it => !state.cassette.some(c => c.itemIds.includes(it.id))).length; const items = [ {id:'home', icon:'home', label:t.nav.home}, {id:'inventory', icon:'inventory', label:t.nav.inventory, badge: unassignedItems || null}, {id:'trustworthy', icon:'people', label:t.nav.trustworthy}, {id:'vault', icon:'vault', label:t.nav.vault, badge: state.cassette.length}, {id:'informed', icon:'informed', label:t.nav.informed, count: state.informed?.length || 0}, {id:'profile', icon:'profile', label:t.nav.profile}, ]; return ; }; // ------- Page header ------- const PageHeader = ({eyebrow, title, subtitle, actions}) => { return
{eyebrow &&
{eyebrow}
}

{title}

{subtitle &&

{subtitle}

}
{actions &&
{actions}
}
; }; // ------- Section header ------- const SectionHeader = ({eyebrow, title, action}) => { return
{eyebrow &&
{eyebrow}
} {title &&

{title}

}
{action}
; }; // ------- Inventory item icon (square) ------- const ItemBadge = ({icon, color, size=36}) => ( 40?18:14, flexShrink:0, }}>{icon} ); // ------- Mini KPI ------- const KpiCell = ({num, label, tone}) =>
{num}
{label}
; // ------- Generic dialog header ------- const DialogHeader = ({title, onClose}) => (

{title}

); // ------- Field wrapper ------- const Field = ({label, help, children}) => ( ); // ------- Helpers ------- const fmtEur = (n, opts={}) => { if (typeof n !== 'number') return '—'; return new Intl.NumberFormat('it-IT', { style:'currency', currency:'EUR', maximumFractionDigits: opts.decimals ?? 0, }).format(n); }; const fmtDateTime = (iso) => { if (!iso) return ''; try { return new Date(iso).toLocaleString('it-IT', { day:'numeric', month:'short', year:'numeric', hour:'2-digit', minute:'2-digit' }); } catch(e){ return iso; } }; Object.assign(window, { Icon, Monogram, MonoStack, CassettaBadge, TriggerBadge, Sidebar, PageHeader, SectionHeader, ItemBadge, KpiCell, DialogHeader, Field, fmtEur, fmtDateTime, });