// app.jsx — Main App component
// t, useState, useEffect, useCallback etc. available from components.jsx (loaded first)
const LS_KEY = 'dopo_me_v1';
function App() {
const [route, setRoute] = useState('home');
const [data, setData] = useState(() => {
try {
const saved = localStorage.getItem(LS_KEY);
if (saved) {
const parsed = JSON.parse(saved);
// Merge with seed to ensure all fields present
return {
...DOPO.SEED,
...parsed,
services: parsed.services || DOPO.SEED.services,
assets: parsed.assets || DOPO.SEED.assets,
memories: parsed.memories || DOPO.SEED.memories,
people: parsed.people || DOPO.SEED.people,
bequests: parsed.bequests || DOPO.SEED.bequests,
mailboxes: parsed.mailboxes || DOPO.SEED.mailboxes,
inactivity: parsed.inactivity || DOPO.SEED.inactivity,
};
}
} catch (e) {
console.warn('Could not load saved state:', e);
}
return DOPO.SEED;
});
// Persist to localStorage on change
useEffect(() => {
try {
localStorage.setItem(LS_KEY, JSON.stringify(data));
} catch (e) {
console.warn('Could not save state:', e);
}
}, [data]);
// Destiny drawer state
const [destinyItem, setDestinyItem] = useState(null);
const [destinyItemType, setDestinyItemType] = useState('service');
const openDestiny = useCallback((item, type) => {
setDestinyItem(item);
setDestinyItemType(type);
}, []);
const closeDestiny = useCallback(() => {
setDestinyItem(null);
}, []);
const saveDestiny = useCallback((updated) => {
setData(prev => {
if (destinyItemType === 'service') {
return {
...prev,
services: prev.services.map(s => s.id === updated.id ? updated : s),
};
} else if (destinyItemType === 'asset') {
return {
...prev,
assets: prev.assets.map(a => a.id === updated.id ? updated : a),
};
} else if (destinyItemType === 'memory') {
return {
...prev,
memories: prev.memories.map(m => m.id === updated.id ? updated : m),
};
}
return prev;
});
}, [destinyItemType]);
// Recalculate profile progress
useEffect(() => {
const total = data.services.length + data.assets.length + data.memories.length + data.people.length;
const assigned = data.services.filter(s => s.destiny).length
+ data.assets.filter(a => a.destiny).length
+ data.memories.filter(m => m.assignees.length > 0).length
+ data.people.filter(p => p.invited).length;
const pct = total > 0 ? Math.round((assigned / total) * 100) : 0;
if (pct !== data.profileProgress) {
setData(prev => ({ ...prev, profileProgress: pct }));
}
}, [data.services, data.assets, data.memories, data.people]);
function renderPage() {
switch (route) {
case 'home':
return