/* @component-map * App — Main container, handles view switching and session state * Header — App header with title and divider * WelcomeView — Landing screen with GM setup button * SetupView — Session creation with system selection and field config * GMDashboard — GM view showing all player character cards * CharacterCard — Single character card display for GM grid * PlayerForm — Character creation form for players joining a session * PlayerCard — Self-view card for a player with editable fields * Toast — Notification toast component * @end-component-map */ import { useCollection } from '@deplixo/sdk'; import { Header } from './components/Header.jsx'; import { WelcomeView } from './components/WelcomeView.jsx'; import { SetupView } from './components/SetupView.jsx'; import { GMDashboard } from './components/GMDashboard.jsx'; import { PlayerForm } from './components/PlayerForm.jsx'; import { PlayerCard } from './components/PlayerCard.jsx'; import { Toast } from './components/Toast.jsx'; import { useEffect, useState } from 'react'; import { SYSTEMS } from './components/systems.jsx'; function App() { const [view, setView] = useState('welcome'); const [session, setSession] = useState(null); const [myCharId, setMyCharId] = useState(null); const [toastMsg, setToastMsg] = useState(''); const sessionCol = useCollection('session', { personal: true }); const charCol = useCollection('characters', { personal: true }); const toast = (msg) => { setToastMsg(msg); setTimeout(() => setToastMsg(''), 2200); }; useEffect(() => { if (sessionCol.loading || charCol.loading) return; if (sessionCol.items.length > 0 && !session) { const s = sessionCol.items[0]; setSession(s); setView('gm'); } }, [sessionCol.loading, sessionCol.items, charCol.loading]); useEffect(() => { if (!session || view !== 'gm') return; const mine = charCol.items.find(c => c.id === myCharId); if (myCharId && mine) setView('player-card'); }, [charCol.items, myCharId, session]); return (