// Welcome — shown when no key is loaded. // // Three options, matching mobile parity: // * Create — generate a new Ed25519 + X25519 keypair. // * Import — load node.json file (dialog). // * Pair — pair with an existing phone/desktop (QR-less, 6-digit code // + device key, symmetrical with mobile's /auth/pair flow). // // v2.2.0-alpha4 wires the first two functionally and stubs Pair with a // button that routes to a placeholder — the pairing poll loop shared // with mobile comes in alpha5. import React, { useState } from 'react'; import { useStore } from '@/lib/store'; import { saveKeyFile } from '@/lib/storage'; import { generateKeyFile } from '@/lib/crypto'; import type { KeyFile } from '@/lib/types'; import { Pair } from './Pair'; export function Welcome(): React.ReactElement { const setKeyFile = useStore(s => s.setKeyFile); const [busy, setBusy] = useState(false); const [err, setErr] = useState(null); const [screen, setScreen] = useState<'welcome' | 'pair'>('welcome'); if (screen === 'pair') return setScreen('welcome')} />; const onCreate = async () => { setBusy(true); setErr(null); try { const kf = generateKeyFile(); await saveKeyFile(kf); setKeyFile(kf); } catch (e) { setErr(String(e)); } finally { setBusy(false); } }; const onImport = async () => { setBusy(true); setErr(null); try { const file = await window.dchain.dialog.openFile({ title: 'Select node.json', filters: [{ name: 'JSON', extensions: ['json'] }], properties: ['openFile'], }); if (!file) return; const contents = await window.dchain.fs.readText(file); const parsed = JSON.parse(contents) as KeyFile; if (!parsed.pub_key || !parsed.priv_key) { throw new Error('file doesn\'t look like a key file'); } await saveKeyFile(parsed); setKeyFile(parsed); } catch (e) { setErr(e instanceof Error ? e.message : String(e)); } finally { setBusy(false); } }; const onPair = () => { setErr(null); setScreen('pair'); }; return (
D

DChain

Decentralised messenger + social feed. Your keys stay on this device.

{err && (
{err}
)}
); } function PrimaryBtn({ label, onClick, disabled }: { label: string; onClick: () => void; disabled?: boolean; }) { return ( ); } function SecondaryBtn({ label, onClick, disabled }: { label: string; onClick: () => void; disabled?: boolean; }) { return ( ); }