flotilla/src/app/components/SignUp.svelte

127 lines
4.6 KiB
Svelte
Raw Normal View History

2024-08-16 22:17:30 +00:00
<script lang="ts">
import cx from "classnames"
2026-01-16 18:06:25 +00:00
import type {ClientOptions} from "@pomade/core"
import {assoc} from "@welshman/lib"
2026-07-28 16:16:26 +00:00
import {makeSecret, RELAYS, MESSAGING_RELAYS, makeEvent} from "@welshman/util"
import {Profile} from "@welshman/domain"
import {Thunks, nip01, publish, toSession} from "@welshman/app"
2025-09-10 22:26:39 +00:00
import Key from "@assets/icons/key-minimalistic.svg?dataurl"
2025-12-18 02:43:13 +00:00
import Letter from "@assets/icons/letter.svg?dataurl"
2026-01-16 18:06:25 +00:00
import {getKey, setKey} from "@lib/implicit"
2024-08-16 22:17:30 +00:00
import Icon from "@lib/components/Icon.svelte"
import Button from "@lib/components/Button.svelte"
2026-01-30 22:14:12 +00:00
import Modal from "@lib/components/Modal.svelte"
import ModalBody from "@lib/components/ModalBody.svelte"
import ModalTitle from "@lib/components/ModalTitle.svelte"
2024-08-16 22:17:30 +00:00
import LogIn from "@app/components/LogIn.svelte"
2026-01-16 18:06:25 +00:00
import SignUpEmail from "@app/components/SignUpEmail.svelte"
2025-08-18 22:02:17 +00:00
import SignUpProfile from "@app/components/SignUpProfile.svelte"
2026-07-28 16:16:26 +00:00
import type {ProfileValues} from "@app/components/ProfileEditForm.svelte"
2026-01-16 18:06:25 +00:00
import SignUpComplete from "@app/components/SignUpComplete.svelte"
import {attemptRelayAccess} from "@app/access"
import {
POMADE_SIGNERS,
INDEXER_RELAYS,
DEFAULT_RELAYS,
DEFAULT_MESSAGING_RELAYS,
2026-06-10 00:19:44 +00:00
DEFAULT_SPACES,
} from "@app/env"
import {forceHealthChecks} from "@app/healthChecks"
2026-06-08 21:14:40 +00:00
import {loginWithPomade} from "@app/pomade"
import {pushModal, clearModals} from "@app/modal"
2026-07-28 16:16:26 +00:00
import {app, domain, login, roomLists} from "@app/core"
2024-12-03 00:21:54 +00:00
2026-01-16 18:06:25 +00:00
setKey("signup.email", "")
setKey("signup.secret", makeSecret())
2026-07-28 16:16:26 +00:00
setKey("signup.profile", {})
2026-01-16 18:06:25 +00:00
setKey("signup.clientOptions", undefined)
2025-12-18 02:43:13 +00:00
const hasPomade = POMADE_SIGNERS.length >= 3
2024-12-03 00:21:54 +00:00
2026-07-28 16:16:26 +00:00
const showLogIn = () => pushModal(LogIn)
2024-08-16 22:17:30 +00:00
const completeSignup = async () => {
// Join default spaces so the relay is warmed up before we publish below
await Promise.all(DEFAULT_SPACES.map(url => attemptRelayAccess(url)))
// Add default outbox/inbox/messaging relays, profile, spaces
const thunks = await Promise.all([
2026-07-28 16:16:26 +00:00
$app.use(Thunks).publish({
event: makeEvent(RELAYS, {tags: DEFAULT_RELAYS.map(url => ["r", url])}),
relays: [...INDEXER_RELAYS, ...DEFAULT_RELAYS, ...DEFAULT_SPACES],
}),
2026-07-28 16:16:26 +00:00
$app.use(Thunks).publish({
event: makeEvent(MESSAGING_RELAYS, {tags: DEFAULT_MESSAGING_RELAYS.map(url => ["r", url])}),
relays: [...DEFAULT_RELAYS, ...DEFAULT_SPACES],
}),
2026-07-28 16:16:26 +00:00
$app.use(Thunks).publish({
event: await $domain
.writer(Profile)
.update(getKey<ProfileValues>("signup.profile")!)
.renderTemplate(),
relays: [...DEFAULT_RELAYS, ...DEFAULT_SPACES],
}),
2026-07-28 16:16:26 +00:00
$roomLists.setRelays(DEFAULT_SPACES).then(publish),
])
// Wait for all the thunks to complete
2026-07-28 16:16:26 +00:00
await Promise.all(thunks.map(thunk => thunk.waitForCompletion()))
2026-06-10 00:19:44 +00:00
// Go to the dashboard
clearModals()
}
2026-01-16 18:06:25 +00:00
const flows = {
email: {
start: () => pushModal(SignUpEmail, {next: flows.email.profile, step: 1, totalSteps: 3}),
profile: () => pushModal(SignUpProfile, {next: flows.email.complete, step: 2, totalSteps: 3}),
complete: () =>
pushModal(SignUpComplete, {next: flows.email.finalize, step: 3, totalSteps: 3}),
finalize: async () => {
2026-01-16 18:06:25 +00:00
const email = getKey<string>("signup.email")!
const clientOptions = getKey<ClientOptions>("signup.clientOptions")!
loginWithPomade(clientOptions, email)
await completeSignup()
2026-01-16 18:06:25 +00:00
},
},
nostr: {
start: () => pushModal(SignUpProfile, {next: flows.nostr.complete, step: 1, totalSteps: 2}),
complete: () =>
pushModal(SignUpComplete, {next: flows.nostr.finalize, step: 2, totalSteps: 2}),
finalize: async () => {
2026-01-16 18:06:25 +00:00
const secret = getKey<string>("signup.secret")!
2025-02-14 18:53:36 +00:00
2026-07-28 16:16:26 +00:00
await login(toSession(nip01, {secret}))
forceHealthChecks.update(assoc("backup-key", true))
await completeSignup()
2026-01-16 18:06:25 +00:00
},
},
}
2024-08-16 22:17:30 +00:00
</script>
2026-01-30 22:14:12 +00:00
<Modal>
<ModalBody>
<ModalTitle>Create an Account</ModalTitle>
2026-01-30 22:14:12 +00:00
<p class="m-auto max-w-sm text-center">
Get started in just a few clicks by picking one of the options below.
2026-01-30 22:14:12 +00:00
</p>
{#if hasPomade}
<Button onclick={flows.email.start} class="button button-primary">
2026-01-30 22:14:12 +00:00
<Icon icon={Letter} />
Sign up with email
</Button>
{/if}
<Button
onclick={flows.nostr.start}
class={cx(`button button-${hasPomade ? "neutral" : "primary"}`)}>
2026-01-30 22:14:12 +00:00
<Icon icon={Key} />
Generate a key
2024-11-27 00:39:49 +00:00
</Button>
2026-01-30 22:14:12 +00:00
<div class="text-sm">
Already have an account?
2026-07-28 16:16:26 +00:00
<Button class="link" onclick={showLogIn}>Log in instead</Button>
2026-01-30 22:14:12 +00:00
</div>
</ModalBody>
</Modal>