const $ = s => document.querySelector(s); const fail = e => { $('#err').textContent = e && e.name === 'NotAllowedError' ? 'Cancelled. Try again.' : (e.message || String(e)); }; async function signIn() { $('#err').textContent = ''; try { await passkeyLogin(); location.replace('/'); } catch (e) { fail(e); } } // ---- Name tiles: on a remembered device (a family screen or a person's own device) the sign-in page shows who lives here. Tap your name, then use your PIN or passkey. const escH = t => String(t == null ? '' : t).replace(/[&<>"']/g, c => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])); async function tilesLogin() { let r; try { r = await fetch('/api/login/people'); } catch { return false; } if (!r.ok) return false; const { people } = await r.json(); if (!people.length) return false; document.querySelector('.box').classList.add('wide'); $('#sub').textContent = "Who's signing in? Tap your name"; const av = p => `${escH((p.name.trim()[0] || '?').toUpperCase())}`; const home = () => { $('#err').textContent = ''; $('#sub').textContent = "Who's signing in? Tap your name"; $('#ui').innerHTML = `
Sign in another way (any passkey, invite or recovery code)
`; $('#ui').querySelectorAll('.tile').forEach(t => t.onclick = () => who(people.find(p => p.id === t.dataset.id))); $('#other').onclick = e => { e.preventDefault(); classicLogin(); }; }; const who = p => { $('#err').textContent = ''; $('#sub').textContent = ''; const tile = `Sign in as ${escH(p.name)}?
${passkeyBtn}${back}`; wire(); $('#yes').onclick = async () => { try { await pinPost(p.id); done(); } catch (e) { fail(e); } }; return; } if (!p.pin) { $('#ui').innerHTML = `${tile}${escH(p.name)} has not set a PIN yet.
${p.passkey ? '' : 'Set a PIN or add a passkey in Settings on a device where you are signed in.
'}${back}`; wire(); return; } let pin = ''; $('#ui').innerHTML = `${tile}Enter your PIN
New device or lost your devices? Use an invite or recovery code
'); $('#inv').onclick = e => { e.preventDefault(); $('#err').textContent = ''; $('#sub').textContent = 'Add this device'; $('#ui').innerHTML = ``; $('#f').onsubmit = async ev => { ev.preventDefault(); $('#err').textContent = ''; try { await passkeyRegister('', $('#nm').value.trim() || 'Passkey', $('#ic').value.trim()); location.replace('/'); } catch (err) { fail(err); } }; }; // Offer the passkey straight away unless the user came here to use an invite code. signIn(); } else { $('#sub').textContent = 'First-time setup: create a passkey for this device'; $('#ui').innerHTML = ``; $('#f').onsubmit = async e => { e.preventDefault(); $('#err').textContent = ''; try { await passkeyRegister($('#sc').value.trim(), $('#nm').value.trim() || 'Passkey'); location.replace('/'); } catch (err) { fail(err); } }; } } init().catch(fail);