diff options
| author | Adam Soltys <[email protected]> | 2023-11-15 23:02:29 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2023-11-15 23:02:29 -0800 |
| commit | b466b3d39c3b9ec792ef924c7f4750fb70b6a016 (patch) | |
| tree | 9f0071056f7f53129e1eb81a1bca268300d41a05 /src/routes/(app)/register | |
| parent | 6d8eb8a609ebb6c1781c463a837bf9e19a6d3d4b (diff) | |
| download | coinos-ui-b466b3d39c3b9ec792ef924c7f4750fb70b6a016.tar.gz coinos-ui-b466b3d39c3b9ec792ef924c7f4750fb70b6a016.zip | |
prefill register page
Diffstat (limited to 'src/routes/(app)/register')
| -rw-r--r-- | src/routes/(app)/register/+page.server.js | 29 | ||||
| -rw-r--r-- | src/routes/(app)/register/+page.svelte | 245 |
2 files changed, 269 insertions, 5 deletions
diff --git a/src/routes/(app)/register/+page.server.js b/src/routes/(app)/register/+page.server.js index c90d4ee3..f2b49e3f 100644 --- a/src/routes/(app)/register/+page.server.js +++ b/src/routes/(app)/register/+page.server.js @@ -1,9 +1,32 @@ +import { + NumberDictionary, + uniqueNamesGenerator, + colors, + adjectives, + animals +} from 'unique-names-generator'; import { fail, redirect } from '@sveltejs/kit'; import { fd, post, login } from '$lib/utils'; export const load = async ({ parent }) => { let { user } = await parent(); if (user) throw redirect(307, `/${user.username}`); + + let username = uniqueNamesGenerator({ + dictionaries: [animals, NumberDictionary.generate({ min: 10, max: 99 })], + length: 2, + separator: '' + }); + + let password = uniqueNamesGenerator({ + dictionaries: [colors, NumberDictionary.generate({ min: 100, max: 999 })], + length: 2, + separator: '' + }); + + let index = Math.floor(Math.random() * 64) + 1; + + return { index, username, password }; }; export const actions = { @@ -11,8 +34,8 @@ export const actions = { let ip = request.headers.get('cf-connecting-ip'); let form = await fd(request); - let { username, password, cipher, salt, pubkey, loginRedirect } = form; - let user = { username, password, cipher, salt, pubkey }; + let { profile, username, password, cipher, salt, pubkey, loginRedirect } = form; + let user = { profile, username, password, cipher, salt, pubkey }; let error; if (loginRedirect === 'undefined') loginRedirect = undefined; @@ -20,7 +43,7 @@ export const actions = { try { await post('/register', { user }, { 'cf-connecting-ip': ip }); } catch (e) { - console.log(e) + console.log(e); if (e.message.includes('taken')) error = e.message; } diff --git a/src/routes/(app)/register/+page.svelte b/src/routes/(app)/register/+page.svelte index fd9e4417..37ff67c8 100644 --- a/src/routes/(app)/register/+page.svelte +++ b/src/routes/(app)/register/+page.svelte @@ -1,7 +1,33 @@ <script> + import punks from '$lib/punks'; + import { upload } from '$lib/upload'; import { afterNavigate, invalidateAll } from '$app/navigation'; - import { RegisterOrLogin } from '$comp'; + import { applyAction, deserialize } from '$app/forms'; + import { tick } from 'svelte'; + import { fly } from 'svelte/transition'; + import { enhance } from '$app/forms'; + import { Pin, Icon, Spinner } from '$comp'; + import { focus, fail } from '$lib/utils'; + import { avatar, password, loginRedirect } from '$lib/store'; + import { t } from '$lib/translations'; + import { page } from '$app/stores'; + import { generate } from '$lib/nostr'; + export let form; + export let data; + + let cleared; + let clear = () => { + if (!cleared) { + cleared = true; + username = ''; + $password = ''; + revealPassword = false; + } + }; + + let { index, username } = data; + $password = data.password; afterNavigate(async () => { try { @@ -10,6 +36,221 @@ console.log(e); } }); + + let token, formElement; + let code = []; + let redirect; + + $: need2fa = form?.message === '2fa'; + let cancel = () => (need2fa = false); + $: if (form?.message === '2fa' && form.token === token) token = ''; + + let email, btn; + + $: update(form); + let update = (form) => form && ({ username, password: $password } = form); + + $: token && token?.length === 6 && tick().then(() => btn.click()); + + let revealPassword = true; + + let loading; + async function handleSubmit(e) { + loading = true; + + let data = new FormData(this); + let user = Object.fromEntries(data); + await generate(user); + + for (let k in user) { + data.set(k, user[k]); + } + + data.set('profile', punks[index]); + if ($avatar) { + try { + let { hash } = JSON.parse( + await upload($avatar.file, $avatar.type, $avatar.progress, token) + ); + + data.set('profile', hash); + await fetch(`/api/public/${hash}.webp`, { cache: 'reload', mode: 'no-cors' }); + } catch (e) { + console.log('problem uploading avatar', e); + } + } + + const response = await fetch('/register', { + method: 'POST', + body: data + }); + + const result = deserialize(await response.text()); + + if (result.type === 'success') { + await invalidateAll(); + } + + applyAction(result); + loading = false; + } + + let avatarInput; + $: src = `/api/public/${punks[index]}.webp`; + let decr = () => (index = index <= 1 ? 64 : index - 1); + let incr = () => (index = index >= 64 ? 1 : index + 1); + let selectAvatar = () => avatarInput.click(); + + let progress; + let handleFile = async ({ target }) => { + let type = 'profile'; + let file = target.files[0]; + if (!file) return; + + if (file.size > 10000000) form.error = 'File too large'; + $avatar = { file, type, progress }; + + var reader = new FileReader(); + reader.onload = async (e) => { + src = e.target.result; + }; + + reader.readAsDataURL(file); + }; </script> -<RegisterOrLogin pageID="register" bind:form /> +{#if need2fa} + <Pin bind:value={token} title="Enter 2FA Code" {cancel} notify={false} /> +{/if} + +<div class="pt-10"> + <div class="w-[243px] mx-auto mb-10"> + <a href="/"> + <Icon icon="logo" /> + </a> + </div> + + <div class="flex justify-center items-center"> + <div class="shadow-xl rounded-3xl p-10 pb-12 space-y-5 w-full mx-5 md:mx-0 md:w-[400px]"> + <h1 class="text-2xl font-bold text-center">{$t('login.register')}</h1> + + <input + type="file" + class="hidden" + bind:this={avatarInput} + on:change={(e) => handleFile(e, 'profile')} + /> + + <div class="relative"> + <button class="absolute w-8 h-12 left-8 bg-white rounded top-12" on:click={decr}> + <Icon icon="chevron-left" style="w-8 " /> + </button> + <div class="relative w-36 mx-auto" on:click={selectAvatar}> + <button + class="w-36 h-36 rounded-full border-4 border-white overflow-hidden flex mx-auto relative" + > + <img + {src} + class="w-full h-full object-cover object-center overflow-hidden" + alt={username} + /> + </button> + <button + class="absolute bg-white rounded-full p-2 mx-auto right-0 bottom-0 z-10 bg-opacity-80" + > + <Icon icon="upload" style="w-8" /> + </button> + </div> + <button class="absolute w-8 h-12 right-8 bg-white rounded top-12" on:click={incr}> + <Icon icon="chevron-left" style="w-8 rotate-180" /> + </button> + </div> + + {#if form?.error} + <div class="text-red-600 text-center" in:fly> + {form.error} + </div> + {/if} + + <form class="space-y-5" on:submit|preventDefault={handleSubmit} method="POST"> + <input + type="hidden" + name="loginRedirect" + value={$loginRedirect || $page.url.searchParams.get('redirect')} + /> + <input type="hidden" name="token" value={token} /> + + <div> + <label for="username" class="font-semibold">{$t('login.username')}</label> + <input + name="username" + type="text" + required + class="bg-primary" + bind:value={username} + on:focus={clear} + autocapitalize="none" + /> + </div> + + <div class="relative"> + <label for="password" class="block font-semibold">{$t('login.password')}</label> + {#if revealPassword} + <input + name="password" + type="text" + required + class="bg-primary" + bind:value={$password} + autocapitalize="none" + /> + {:else} + <input + name="password" + type="password" + required + class="bg-primary" + bind:value={$password} + autocapitalize="none" + on:focus={clear} + /> + {/if} + <button + type="button" + on:click={() => (revealPassword = !revealPassword)} + class="absolute right-5 top-10" + > + <Icon icon={revealPassword ? 'eye' : 'eye-off'} /> + </button> + </div> + + <p class="text-secondary text-sm"> + {$t('login.passwordRecommendation')} + </p> + + <button + type="submit" + class="bg-black text-white w-full rounded-2xl p-4 font-semibold hover:opacity-80" + disabled={loading} + bind:this={btn} + > + {#if loading} + <Spinner /> + {:else} + {$t('login.register')} + {/if} + </button> + </form> + + <p class="text-secondary text-center font-medium"> + {$t('login.haveAccount')} + <a + href={'/login'} + class="block md:inline text-black underline underline-offset-4 hover:opacity-80" + > + {$t('login.signIn')} + </a> + </p> + </div> + </div> +</div> |
