// WealthIntelligence — main App const { useState: uS, useEffect: uE, useMemo: uM } = React; const LS_KEY = 'wi_v2'; function loadState(){ try { const raw = localStorage.getItem(LS_KEY); if (raw) return JSON.parse(raw); } catch(e){} return JSON.parse(JSON.stringify(window.WI.SEED)); } function App(){ const [state, setState] = uS(loadState); const [route, setRoute] = uS(() => localStorage.getItem('wi_route') || 'home'); const [lang, setLang] = uS(() => localStorage.getItem('wi_lang') || 'it'); const [serif, setSerif] = uS(() => localStorage.getItem('wi_serif') !== 'off'); const [tweaksOpen, setTweaksOpen] = uS(false); // Cassetta editor state: { cassetta?, isNew? } | null const [editingCassetta, setEditingCassetta] = uS(null); // Item / Person detail drawers const [detailItem, setDetailItem] = uS(null); const [detailPerson, setDetailPerson] = uS(null); // Item / Person editor drawers const [editingItem, setEditingItem] = uS(null); const [editingPerson, setEditingPerson] = uS(null); // User editor const [editingUser, setEditingUser] = uS(false); uE(()=>{ localStorage.setItem(LS_KEY, JSON.stringify(state)); }, [state]); uE(()=>{ localStorage.setItem('wi_route', route); }, [route]); uE(()=>{ localStorage.setItem('wi_lang', lang); }, [lang]); uE(()=>{ localStorage.setItem('wi_serif', serif?'on':'off'); document.body.dataset.serif = serif?'on':'off'; }, [serif]); const t = window.WI.I18N[lang]; const updateState = (fn) => setState(s => typeof fn==='function' ? fn(s) : {...s, ...fn}); // Cassetta CRUD const openCassettaEditor = (cassetta=null) => setEditingCassetta({ cassetta, isNew: !cassetta }); const saveCassetta = (data) => { setState(s => { if (editingCassetta?.isNew) { const id = 'c' + (Math.max(0, ...s.cassette.map(c=>parseInt(c.id.slice(1))||0)) + 1); return { ...s, cassette: [...s.cassette, { ...data, id }] }; } return { ...s, cassette: s.cassette.map(c => c.id===data.id ? {...c, ...data} : c) }; }); setEditingCassetta(null); }; const deleteCassetta = (id) => { setState(s => ({ ...s, cassette: s.cassette.filter(c => c.id!==id) })); setEditingCassetta(null); }; // Toggle a person's access on a cassetta (matrix cell click) const togglePersonOnCassetta = (cassettaId, personId) => { setState(s => ({ ...s, cassette: s.cassette.map(c => { if (c.id !== cassettaId) return c; const has = c.assignees.includes(personId); return { ...c, assignees: has ? c.assignees.filter(id => id!==personId) : [...c.assignees, personId] }; }), })); }; // Activate / deactivate a single cassetta const setCassettaActivated = (cassettaId, activated) => { setState(s => ({ ...s, cassette: s.cassette.map(c => c.id===cassettaId ? {...c, activated, activatedAt: activated ? new Date().toISOString() : null} : c), })); }; // Temporary illness toggle (activates all 'temporary' cassette) const setTemporaryIllness = (active, note='') => { setState(s => ({ ...s, temporaryIllness: { active, since: active ? new Date().toISOString() : null, note: active ? note : '' }, cassette: s.cassette.map(c => c.trigger==='temporary' ? { ...c, activated: active, activatedAt: active ? new Date().toISOString() : null } : c), })); }; const openItemDetail = (item) => setDetailItem(item); const openPersonDetail = (person) => setDetailPerson(person); // Item editor + CRUD const openItemEditor = (item=null) => setEditingItem({ item, isNew: !item }); const saveItem = (data) => { setState(s => { if (editingItem?.isNew) { const id = 'i' + (Math.max(0, ...s.inventory.map(it=>parseInt(it.id.slice(1))||0)) + 1); return { ...s, inventory: [...s.inventory, { ...data, id }] }; } return { ...s, inventory: s.inventory.map(it => it.id===data.id ? {...it, ...data} : it) }; }); setEditingItem(null); }; const deleteItem = (id) => { setState(s => ({ ...s, inventory: s.inventory.filter(it => it.id !== id), // also remove the item id from any cassetta cassette: s.cassette.map(c => ({ ...c, itemIds: c.itemIds.filter(i => i !== id) })), })); setEditingItem(null); }; // Person editor + CRUD const openPersonEditor = (person=null) => setEditingPerson({ person, isNew: !person }); const savePerson = (data) => { setState(s => { if (editingPerson?.isNew) { const id = 'p' + (Math.max(0, ...s.people.map(p=>parseInt(p.id.slice(1))||0)) + 1); return { ...s, people: [...s.people, { ...data, id }] }; } return { ...s, people: s.people.map(p => p.id===data.id ? {...p, ...data} : p) }; }); setEditingPerson(null); }; const deletePerson = (id) => { setState(s => ({ ...s, people: s.people.filter(p => p.id !== id), // remove from any cassetta assignees cassette: s.cassette.map(c => ({ ...c, assignees: c.assignees.filter(pid => pid !== id) })), // remove from inactivity trusted contacts inactivity: { ...s.inactivity, trustedContacts: (s.inactivity.trustedContacts||[]).filter(pid => pid !== id) }, })); setEditingPerson(null); }; // User editor + save const openUserEditor = () => setEditingUser(true); const saveUser = (data) => { setState(s => ({ ...s, user: {...s.user, ...data} })); setEditingUser(false); }; const pageProps = { state, t, setRoute, updateState, openCassettaEditor, togglePersonOnCassetta, setCassettaActivated, setTemporaryIllness, openItemDetail, openPersonDetail, openItemEditor, openPersonEditor, openUserEditor, }; return
{route==='home' && } {route==='inventory' && } {route==='trustworthy' && } {route==='vault' && } {route==='informed' && } {route==='profile' && }
{editingCassetta && ( setEditingCassetta(null)} onSave={saveCassetta} onDelete={deleteCassetta} /> )} {detailItem && ( setDetailItem(null)} onOpenCassetta={(c)=>{ setDetailItem(null); openCassettaEditor(c); }} onEdit={()=>{ const it = detailItem; setDetailItem(null); openItemEditor(it); }} /> )} {detailPerson && ( setDetailPerson(null)} onOpenCassetta={(c)=>{ setDetailPerson(null); openCassettaEditor(c); }} onEdit={()=>{ const p = detailPerson; setDetailPerson(null); openPersonEditor(p); }} /> )} {editingItem && ( setEditingItem(null)} onSave={saveItem} onDelete={deleteItem} /> )} {editingPerson && ( setEditingPerson(null)} onSave={savePerson} onDelete={deletePerson} /> )} {editingUser && ( setEditingUser(false)} onSave={saveUser} /> )} {/* Tweaks: title style + lang + reset seed */} {tweaksOpen && (

Tweaks

Titoli
Lingua

)}
; } const root = ReactDOM.createRoot(document.getElementById('root')); root.render();