From 81fc03c705a2aec896ffc346314d2e4bf414b7b2 Mon Sep 17 00:00:00 2001 From: Lewis Date: Wed, 18 Mar 2026 18:36:16 +0200 Subject: [PATCH] refactor(frontend): refactor migration and registration lib --- .../src/components/CommsChannelPicker.svelte | 139 +++++++++ frontend/src/components/HandleInput.svelte | 34 +++ .../src/components/IdentityTypeSection.svelte | 78 ++++++ frontend/src/components/ReauthModal.svelte | 26 +- frontend/src/lib/flows/email-verification.ts | 29 ++ frontend/src/lib/flows/migration-shared.ts | 56 ++++ .../lib/flows/perform-passkey-registration.ts | 54 ++++ frontend/src/lib/migration/atproto-client.ts | 72 ++--- frontend/src/lib/migration/flow.svelte.ts | 140 ++++++---- .../src/lib/migration/offline-flow.svelte.ts | 152 ++++------ frontend/src/lib/migration/types.ts | 23 +- frontend/src/lib/portal.ts | 11 + .../lib/registration/AppPasswordStep.svelte | 51 ---- frontend/src/lib/registration/flow.svelte.ts | 264 +++++++----------- frontend/src/lib/registration/index.ts | 2 +- 15 files changed, 706 insertions(+), 425 deletions(-) create mode 100644 frontend/src/components/CommsChannelPicker.svelte create mode 100644 frontend/src/components/IdentityTypeSection.svelte create mode 100644 frontend/src/lib/flows/email-verification.ts create mode 100644 frontend/src/lib/flows/migration-shared.ts create mode 100644 frontend/src/lib/flows/perform-passkey-registration.ts create mode 100644 frontend/src/lib/portal.ts delete mode 100644 frontend/src/lib/registration/AppPasswordStep.svelte diff --git a/frontend/src/components/CommsChannelPicker.svelte b/frontend/src/components/CommsChannelPicker.svelte new file mode 100644 index 0000000..0bc6f06 --- /dev/null +++ b/frontend/src/components/CommsChannelPicker.svelte @@ -0,0 +1,139 @@ + + +
+ + +
+ +{#if channel === 'email'} +
+ + onEmailChange((e.target as HTMLInputElement).value)} + placeholder={$_('register.emailPlaceholder')} + {disabled} + required + /> +
+{:else if channel === 'discord'} +
+ + onDiscordChange((e.target as HTMLInputElement).value)} + onblur={() => onCheckInUse?.('discord', discordUsername)} + placeholder={$_('register.discordUsernamePlaceholder')} + {disabled} + required + /> + {#if discordInUse} +

{$_('register.discordInUseWarning')}

+ {/if} +
+{:else if channel === 'telegram'} +
+ + onTelegramChange((e.target as HTMLInputElement).value)} + onblur={() => onCheckInUse?.('telegram', telegramUsername)} + placeholder={$_('register.telegramUsernamePlaceholder')} + {disabled} + required + /> + {#if telegramInUse} +

{$_('register.telegramInUseWarning')}

+ {/if} +
+{:else if channel === 'signal'} +
+ + onSignalChange((e.target as HTMLInputElement).value)} + onblur={() => onCheckInUse?.('signal', signalUsername)} + placeholder={$_('register.signalUsernamePlaceholder')} + {disabled} + required + /> +

{$_('register.signalUsernameHint')}

+ {#if signalInUse} +

{$_('register.signalInUseWarning')}

+ {/if} +
+{/if} diff --git a/frontend/src/components/HandleInput.svelte b/frontend/src/components/HandleInput.svelte index 98d359a..eb1f077 100644 --- a/frontend/src/components/HandleInput.svelte +++ b/frontend/src/components/HandleInput.svelte @@ -7,6 +7,9 @@ placeholder?: string id?: string autocomplete?: HTMLInputElement['autocomplete'] + checkAvailability?: (fullHandle: string) => Promise + available?: boolean | null + checking?: boolean onInput: (value: string) => void onDomainChange: (domain: string) => void } @@ -19,11 +22,42 @@ placeholder = 'username', id = 'handle', autocomplete = 'off', + checkAvailability, + available = $bindable(null), + checking = $bindable(false), onInput, onDomainChange, }: Props = $props() const showDomainSelect = $derived(domains.length > 1 && !value.includes('.')) + + let checkTimeout: ReturnType | null = null + + $effect(() => { + void value + void selectedDomain + if (!checkAvailability) return + if (checkTimeout) clearTimeout(checkTimeout) + available = null + if (value.trim().length >= 3 && !value.includes('.')) { + checkTimeout = setTimeout(() => runCheck(), 400) + } + }) + + async function runCheck() { + if (!checkAvailability) return + const fullHandle = value.includes('.') + ? value.trim() + : `${value.trim()}.${selectedDomain}` + checking = true + try { + available = await checkAvailability(fullHandle) + } catch { + available = null + } finally { + checking = false + } + }
diff --git a/frontend/src/components/IdentityTypeSection.svelte b/frontend/src/components/IdentityTypeSection.svelte new file mode 100644 index 0000000..75c6a6e --- /dev/null +++ b/frontend/src/components/IdentityTypeSection.svelte @@ -0,0 +1,78 @@ + + +
+ {$_('registerPasskey.identityType')} +
+ + + +
+
+ +{#if didType === 'web'} +
+ {$_('registerPasskey.didWebWarningTitle')} +
    +
  • {$_('registerPasskey.didWebWarning1')} {@html $_('registerPasskey.didWebWarning1Detail', { values: { did: `did:web:yourhandle.${defaultDomain}` } })}
  • +
  • {$_('registerPasskey.didWebWarning2')} {$_('registerPasskey.didWebWarning2Detail')}
  • +
  • {$_('registerPasskey.didWebWarning3')} {$_('registerPasskey.didWebWarning3Detail')}
  • +
  • {$_('registerPasskey.didWebWarning4')} {$_('registerPasskey.didWebWarning4Detail')}
  • +
+
+{/if} + +{#if didType === 'web-external'} +
+ + onExternalDidChange(e.currentTarget.value)} placeholder={$_('registerPasskey.externalDidPlaceholder')} {disabled} required /> +

{$_('registerPasskey.externalDidHint')} https://{externalDid ? extractDomain(externalDid) : 'yourdomain.com'}/.well-known/did.json

+
+{/if} diff --git a/frontend/src/components/ReauthModal.svelte b/frontend/src/components/ReauthModal.svelte index 8253a20..cb7a238 100644 --- a/frontend/src/components/ReauthModal.svelte +++ b/frontend/src/components/ReauthModal.svelte @@ -1,4 +1,5 @@ {#if show} -