// Top-level component. Two responsibilities: // 1. Boot — load key + settings from storage, wire up the API client, // flip the booted flag so we stop showing the black splash. // 2. Render either the Welcome auth flow (no key yet) or the Shell // (3-panel layout + current section). import React, { useEffect, useState } from 'react'; import { useStore } from '@/lib/store'; import { loadKeyFile, loadSettings, loadContacts } from '@/lib/storage'; import { setNodeUrl } from '@/lib/api'; import { Shell } from '@/shell/Shell'; import { Welcome } from '@/auth/Welcome'; export function App(): React.ReactElement { const booted = useStore(s => s.booted); const keyFile = useStore(s => s.keyFile); const [bootError, setBootError] = useState(null); useEffect(() => { (async () => { try { const set = loadSettings(); setNodeUrl(set.nodeUrl); useStore.getState().setSettings(set); const cs = loadContacts(); useStore.getState().setContacts(cs); const kf = await loadKeyFile(); useStore.getState().setKeyFile(kf); useStore.getState().setBooted(true); } catch (err) { // Show the error inline — the boundary only catches render // throws, not async-effect throws like this one. setBootError(err instanceof Error ? err.message : String(err)); } })(); }, []); if (bootError) { return (

Boot failed

{bootError}

This usually means the Electron preload script didn't load. Check that `npm run build:main` has produced `dist-electron/preload.js` and restart `npm run dev`.

); } if (!booted) { // Matches the splash: whole window is already black from index.html, // so showing nothing is the right behaviour — no flash, no spinner. return
; } return keyFile ? : ; }