From 1a5f2d20868658d06793698ced71d40d4d011f69 Mon Sep 17 00:00:00 2001 From: xbot Date: Mon, 6 Apr 2026 14:37:56 +0200 Subject: [PATCH] Redesign passkey UI flow When ?passkey=true and passkey is available: - Initial: email optional + subtext 'to receive updates about this letter' + primary button 'Sign with Passkey' + link 'sign with your email instead' - After clicking link: email required + checkbox opt-in + same button + link 'sign with passkey instead' When passkey NOT available: falls back to standard interface (email required + checkbox for updates) New i18n keys: sign.email.optional.subtext, sign.email.instead, sign.passkey.instead --- frontend/components/SignatureForm.js | 199 ++++++++++++++++++--------- frontend/public/locales/de.json | 3 + frontend/public/locales/en.json | 3 + frontend/public/locales/fr.json | 3 + frontend/public/locales/nl.json | 3 + 5 files changed, 145 insertions(+), 66 deletions(-) diff --git a/frontend/components/SignatureForm.js b/frontend/components/SignatureForm.js index 09a9346..17e64e1 100644 --- a/frontend/components/SignatureForm.js +++ b/frontend/components/SignatureForm.js @@ -20,11 +20,13 @@ class SignatureForm extends Component { this.state = { loading: false, passkeyAvailable: false, - usePasskey: false, // disabled by default; enabled only when ?passkey=true in URL + usePasskey: false, + emailOptional: false, // true when passkey is available and user hasn't switched to email form: { name: null, occupation: null, city: null, + organization: null, email: null, share_email: false, id: this.props.signature && this.props.signature.id, @@ -37,11 +39,10 @@ class SignatureForm extends Component { } async componentDidMount() { - // Only enable passkey when ?passkey=true is in the URL const params = new URLSearchParams(window.location.search); if (params.get('passkey') === 'true' && isPasskeySupported()) { const available = await isPlatformAuthenticatorAvailable(); - this.setState({ passkeyAvailable: available, usePasskey: available }); + this.setState({ passkeyAvailable: available, usePasskey: available, emailOptional: available }); } } @@ -62,7 +63,6 @@ class SignatureForm extends Component { await this.props.onSubmit(formData); - // just in case setTimeout(() => { this.setState({ loading: false }); }, 2000); @@ -73,9 +73,12 @@ class SignatureForm extends Component { render() { const { error, t, letter } = this.props; - const { passkeyAvailable, usePasskey } = this.state; - const showEmailField = !this.updatingSignature && !usePasskey; - const showEmailOptional = !this.updatingSignature && usePasskey && passkeyAvailable; + const { passkeyAvailable, usePasskey, emailOptional } = this.state; + + // When ?passkey=true and passkey is available, show the redesigned flow + const showPasskeyFlow = passkeyAvailable && !this.updatingSignature; + // Fallback: current interface when passkey is NOT available + const showFallbackFlow = !passkeyAvailable && !this.updatingSignature; return (
@@ -117,76 +120,140 @@ class SignatureForm extends Component { /> - {/* Passkey toggle */} - {passkeyAvailable && !this.updatingSignature && ( -
-
+ {/* ── Redesigned passkey flow ───────────────────────────────── */} + {showPasskeyFlow && ( + <> + {/* Email: optional (with subtext) or required (with checkbox) */} + {emailOptional ? ( + // Passkey-first mode: email optional + subtext +
+ +

+ {t('sign.email.optional.subtext')} +

+
+ ) : ( + // Email mode: required + checkbox opt-in +
+ + {letter.user_id && ( +
+ +
+ )} +
+ )} + + {/* Primary button */} +
+
+ + {/* Toggle link */} +
+ {emailOptional ? ( + + ) : ( + + )} +
+ + )} + + {/* ── Fallback: standard interface when passkey not available ── */} + {showFallbackFlow && ( + <> +
+ +
+ {letter.user_id && ( +
+ +
+ )} +
- {usePasskey && ( -

- {t('sign.passkey.info')} -

- )} -
- )} - - {/* Email field: required for email flow, optional for passkey (for updates) */} - {showEmailField && ( -
- -
- )} - {showEmailOptional && ( -
- -
+ )} - {!this.updatingSignature && !usePasskey && letter.user_id && ( -
- -
+ {/* ── Existing signature update (no passkey flow) ── */} + {this.updatingSignature && ( + <> +
+ +
+
+ +
+ )}
-
- -
{error &&
{error.message}
}
); diff --git a/frontend/public/locales/de.json b/frontend/public/locales/de.json index 30a08b2..d2ecfe1 100644 --- a/frontend/public/locales/de.json +++ b/frontend/public/locales/de.json @@ -75,6 +75,9 @@ "sign.city": "Stadt", "sign.email": "E-Mail", "sign.email.optional": "E-Mail (optional, für Updates)", + "sign.email.optional.subtext": "um Updates zu diesem Brief zu erhalten", + "sign.email.instead": "stattdessen mit Ihrer E-Mail anmelden", + "sign.passkey.instead": "stattdessen mit Passkey anmelden", "sign.name": "Ihr Name", "sign.occupation": "Beruf", "sign.organization": "Organisation", diff --git a/frontend/public/locales/en.json b/frontend/public/locales/en.json index 79c94dd..cf19b45 100644 --- a/frontend/public/locales/en.json +++ b/frontend/public/locales/en.json @@ -75,6 +75,9 @@ "sign.city": "city", "sign.email": "email", "sign.email.optional": "email (optional, for updates)", + "sign.email.optional.subtext": "to receive updates about this letter", + "sign.email.instead": "sign with your email instead", + "sign.passkey.instead": "sign with passkey instead", "sign.name": "Your name", "sign.occupation": "occupation", "sign.organization": "organization", diff --git a/frontend/public/locales/fr.json b/frontend/public/locales/fr.json index d8e126e..abeaec8 100644 --- a/frontend/public/locales/fr.json +++ b/frontend/public/locales/fr.json @@ -75,6 +75,9 @@ "sign.city": "ville", "sign.email": "email", "sign.email.optional": "email (optionnel, pour les mises à jour)", + "sign.email.optional.subtext": "pour recevoir des mises à jour concernant cette lettre", + "sign.email.instead": "signer avec votre email à la place", + "sign.passkey.instead": "signer avec passkey à la place", "sign.name": "Votre nom", "sign.occupation": "occupation", "sign.organization": "organisation", diff --git a/frontend/public/locales/nl.json b/frontend/public/locales/nl.json index 21bbe83..ac53e45 100644 --- a/frontend/public/locales/nl.json +++ b/frontend/public/locales/nl.json @@ -75,6 +75,9 @@ "sign.city": "stad", "sign.email": "email", "sign.email.optional": "email (optioneel, voor updates)", + "sign.email.optional.subtext": "om updates te ontvangen over deze brief", + "sign.email.instead": "in plaats daarvan aanmelden met je email", + "sign.passkey.instead": "in plaats daarvan aanmelden met passkey", "sign.name": "Uw naam", "sign.occupation": "beroep", "sign.organization": "organisatie",