diff --git a/shared/components/rstack-identity.ts b/shared/components/rstack-identity.ts index 4862a1d..600b245 100644 --- a/shared/components/rstack-identity.ts +++ b/shared/components/rstack-identity.ts @@ -420,62 +420,116 @@ export class RStackIdentity extends HTMLElement { const status = await res.json(); if (status.multiDevice) return; // already has 2+ devices - // Show a toast nudge + // Show a toast nudge with QR code const toast = document.createElement("div"); toast.className = "eid-device-nudge"; - toast.innerHTML = ` - -
- 📱 - Link a second device -
-
- Sign in from your phone or tablet too — it also acts as a backup if you ever lose access to this device. -
-
- - -
- `; - toast.querySelector('[data-action="setup"]')?.addEventListener("click", () => { - toast.remove(); - this.showAccountModal({ openSection: "device" }); - }); - toast.querySelector('[data-action="later"]')?.addEventListener("click", () => { - localStorage.setItem(NUDGE_KEY, String(Date.now())); - toast.style.animation = "eid-nudge-in 0.3s ease-in reverse forwards"; - setTimeout(() => toast.remove(), 300); - }); + let linkUrl = ""; + let linkError = ""; + + const renderNudge = () => { + const qrHTML = linkUrl + ? `
+ Scan to link device +
+ +
Expires in 10 minutes
` + : linkError + ? `
${linkError}
` + : `
Generating link…
`; + + toast.innerHTML = ` + +
+ 📱 + Link a second device +
+
+ Scan this QR code on your phone or tablet to add a passkey backup. +
+ ${qrHTML} +
+ +
+ `; + + toast.querySelector('[data-action="later"]')?.addEventListener("click", () => { + localStorage.setItem(NUDGE_KEY, String(Date.now())); + toast.style.animation = "eid-nudge-in 0.3s ease-in reverse forwards"; + setTimeout(() => toast.remove(), 300); + }); + toast.querySelector('[data-action="copy"]')?.addEventListener("click", () => { + navigator.clipboard.writeText(linkUrl).catch(() => {}); + const btn = toast.querySelector('[data-action="copy"]') as HTMLButtonElement; + if (btn) { btn.textContent = "Copied!"; setTimeout(() => { btn.textContent = "Copy"; }, 2000); } + }); + }; document.body.appendChild(toast); + renderNudge(); // show loading state + + // Generate device link + try { + const linkRes = await fetch(`${ENCRYPTID_URL}/api/device-link/start`, { + method: "POST", + headers: { Authorization: `Bearer ${getAccessToken()}` }, + }); + const linkData = await linkRes.json(); + if (!linkRes.ok || linkData.error) throw new Error(linkData.error || "Failed"); + linkUrl = linkData.linkUrl; + } catch { + linkError = "Could not generate link. Try My Account → Devices."; + } + renderNudge(); // show QR or error } catch { /* offline */ } }