1import { Show, createSignal } from "solid-js";23export interface AdoptionConsentModalProps {4 receiverDeviceName: string;5 sas: string;6 verifyMasterPassword(password: string): Promise<boolean>;7 onCancel(): void;8 onApprove(): Promise<void>;9}1011export function AdoptionConsentModal(props: AdoptionConsentModalProps) {12 const [password, setPassword] = createSignal("");13 const [error, setError] = createSignal("");14 const [busy, setBusy] = createSignal(false);1516 async function submit() {17 if (!password() || busy()) return;18 setBusy(true);19 setError("");20 try {21 const ok = await props.verifyMasterPassword(password());22 if (!ok) {23 setPassword("");24 setError("Incorrect password");25 queueMicrotask(() => document.getElementById("adoption-consent-password")?.focus());26 return;27 }28 await props.onApprove();29 } finally {30 setBusy(false);31 }32 }3334 return (35 <div class="peach-adoption-consent-backdrop" role="presentation">36 <section37 class="peach-adoption-consent"38 role="dialog"39 aria-modal="true"40 aria-labelledby="adoption-consent-title"41 >42 <div class="peach-adoption-consent-icon" aria-hidden="true">!</div>43 <h2 id="adoption-consent-title">Share vault with new device?</h2>44 <p class="peach-adoption-consent-device">45 <strong>{props.receiverDeviceName}</strong> wants to join this vault.46 </p>47 <p class="peach-adoption-consent-warning">48 This copies your entire vault including all passwords and Pro to that device.49 </p>50 <div class="peach-adoption-consent-sas">51 <span>Confirm the code matches</span>52 <strong>{props.sas.replace(/(\d)(?=\d)/g, "$1 ")}</strong>53 </div>54 <label class="peach-label" for="adoption-consent-password">55 Enter your master password to approve56 </label>57 <input58 id="adoption-consent-password"59 class="peach-underline-input"60 type="password"61 autocomplete="current-password"62 value={password()}63 disabled={busy()}64 aria-invalid={error() ? "true" : "false"}65 aria-describedby={error() ? "adoption-consent-error" : undefined}66 onInput={(event) => {67 setPassword((event.target as HTMLInputElement).value);68 if (error()) setError("");69 }}70 onKeyDown={(event) => {71 if (event.key === "Enter") void submit();72 if (event.key === "Escape") props.onCancel();73 }}74 />75 <Show when={error()}>76 <p id="adoption-consent-error" class="peach-hint peach-hint-error">{error()}</p>77 </Show>78 <div class="peach-adoption-consent-actions">79 <button80 type="button"81 class="peach-btn peach-btn--ghost peach-btn--md"82 disabled={busy()}83 onClick={props.onCancel}84 >85 Cancel86 </button>87 <button88 type="button"89 class="peach-btn peach-btn--accent peach-btn--md peach-adoption-consent-share"90 disabled={!password() || busy()}91 onClick={() => void submit()}92 >93 {busy() ? "Sharing..." : "Share vault ->"}94 </button>95 </div>96 </section>97 </div>98 );99}