Our Personal Data Server from scratch!
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 146 lines 3.7 kB view raw
1<script lang="ts"> 2 import { onDestroy } from 'svelte' 3 import { api, ApiError } from '../api' 4 import { resendVerification } from '../auth.svelte' 5 import type { RegistrationFlow } from './flow.svelte' 6 7 interface Props { 8 flow: RegistrationFlow 9 } 10 11 let { flow }: Props = $props() 12 13 let verificationCode = $state('') 14 let resending = $state(false) 15 let resendMessage = $state<string | null>(null) 16 17 let pollingInterval: ReturnType<typeof setInterval> | null = null 18 19 $effect(() => { 20 if (flow.state.step === 'verify' && flow.account && !verificationCode.trim()) { 21 pollingInterval = setInterval(async () => { 22 if (verificationCode.trim()) return 23 const advanced = await flow.checkAndAdvanceIfVerified() 24 if (advanced && pollingInterval) { 25 clearInterval(pollingInterval) 26 pollingInterval = null 27 } 28 }, 3000) 29 } 30 31 return () => { 32 if (pollingInterval) { 33 clearInterval(pollingInterval) 34 pollingInterval = null 35 } 36 } 37 }) 38 39 onDestroy(() => { 40 if (pollingInterval) { 41 clearInterval(pollingInterval) 42 pollingInterval = null 43 } 44 }) 45 46 function channelLabel(ch: string): string { 47 switch (ch) { 48 case 'email': return 'email' 49 case 'discord': return 'Discord' 50 case 'telegram': return 'Telegram' 51 case 'signal': return 'Signal' 52 default: return ch 53 } 54 } 55 56 async function handleSubmit(e: Event) { 57 e.preventDefault() 58 if (!verificationCode.trim()) return 59 resendMessage = null 60 await flow.verifyAccount(verificationCode) 61 } 62 63 async function handleResend() { 64 if (resending || !flow.account) return 65 resending = true 66 resendMessage = null 67 flow.clearError() 68 69 try { 70 await resendVerification(flow.account.did) 71 resendMessage = 'Verification code resent!' 72 } catch (err) { 73 if (err instanceof ApiError) { 74 flow.setError(err.message || 'Failed to resend code') 75 } else if (err instanceof Error) { 76 flow.setError(err.message || 'Failed to resend code') 77 } else { 78 flow.setError('Failed to resend code') 79 } 80 } finally { 81 resending = false 82 } 83 } 84</script> 85 86<div class="verification-step"> 87 <p class="info-text"> 88 We've sent a verification code to your {channelLabel(flow.info.verificationChannel)}. 89 Enter it below to continue. 90 </p> 91 92 {#if resendMessage} 93 <div class="message success">{resendMessage}</div> 94 {/if} 95 96 <form onsubmit={handleSubmit}> 97 <div class="field"> 98 <label for="verification-code">Verification Code</label> 99 <input 100 id="verification-code" 101 type="text" 102 bind:value={verificationCode} 103 placeholder="XXXX-XXXX-XXXX-XXXX" 104 disabled={flow.state.submitting} 105 required 106 autocomplete="one-time-code" 107 class="code-input" 108 /> 109 <span class="hint">Copy the entire code from your message, including dashes.</span> 110 </div> 111 112 <button type="submit" disabled={flow.state.submitting || !verificationCode.trim()}> 113 {flow.state.submitting ? 'Verifying...' : 'Verify'} 114 </button> 115 116 <button type="button" class="secondary" onclick={handleResend} disabled={resending}> 117 {resending ? 'Resending...' : 'Resend Code'} 118 </button> 119 </form> 120</div> 121 122<style> 123 .verification-step { 124 display: flex; 125 flex-direction: column; 126 gap: var(--space-4); 127 } 128 129 .info-text { 130 color: var(--text-secondary); 131 margin: 0; 132 } 133 134 .code-input { 135 font-family: var(--font-mono, monospace); 136 font-size: var(--text-base); 137 letter-spacing: 0.05em; 138 } 139 140 .hint { 141 display: block; 142 color: var(--text-secondary); 143 font-size: var(--text-sm); 144 margin-top: var(--space-1); 145 } 146</style>