Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 119 additions & 42 deletions src/lib/components/account/sendVerificationEmailModal.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<script lang="ts">
import { invalidate, goto } from '$app/navigation';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { Modal } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { Button, InputEmail, InputPassword } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { user } from '$lib/stores/user';
import { get } from 'svelte/store';
Expand All @@ -28,6 +29,17 @@
let resendTimer = $state(0);
let timerInterval: ReturnType<typeof setInterval> | null = null;

let showUpdateEmail = $state(false);
let newEmail = $state('');
let newPassword = $state('');
let updating = $state(false);

$effect(() => {
if (showUpdateEmail) {
newEmail = email || get(user)?.email || '';
}
});

async function logout() {
error = null;
try {
Expand Down Expand Up @@ -114,6 +126,32 @@
}
}

async function updateEmail() {
error = null;
updating = true;
try {
await sdk.forConsole.account.updateEmail({
email: newEmail,
password: newPassword
});
await invalidate(Dependencies.ACCOUNT);
trackEvent(Submit.AccountUpdateEmail);
resetUpdateEmailForm();
} catch (err) {
error = err.message;
trackError(err, Submit.AccountUpdateEmail);
} finally {
updating = false;
}
}

function resetUpdateEmailForm() {
showUpdateEmail = false;
newEmail = '';
newPassword = '';
error = null;
}

onMount(restoreTimerState);

onDestroy(() => {
Expand All @@ -129,48 +167,87 @@
</script>

<div class="email-verification-scrim">
<Modal
bind:show
bind:error
title="Verify your email address"
{onSubmit}
dismissible={false}
autoClose={false}
backdrop={false}>
<Card.Base variant="secondary" padding="s">
<Layout.Stack gap="xxs">
<Typography.Text gap="m">
To continue using Appwrite Cloud, please verify your email address. An email
will be sent to <Typography.Text
variant="m-600"
color="neutral-secondary"
style="display: inline;">{email || get(user)?.email}</Typography.Text>
</Typography.Text>

<Link variant="default" on:click={() => logout()}>Switch account</Link>

{#if emailSent && resendTimer > 0}
<div transition:slide={{ duration: 150 }}>
<Typography.Text
{#if !showUpdateEmail}
<Modal
bind:show
bind:error
title="Verify your email address"
{onSubmit}
dismissible={false}
autoClose={false}
backdrop={false}>
<Card.Base variant="secondary" padding="s">
<Layout.Stack gap="xxs">
<Typography.Text gap="m">
To continue using Appwrite Cloud, please verify your email address. An email
will be sent to <Typography.Text
variant="m-600"
color="neutral-secondary"
style="margin-block-start: var(--gap-L, 16px);">
Didn't get the email? Try again in {resendTimer}s
</Typography.Text>
</div>
{/if}
</Layout.Stack>
</Card.Base>

<svelte:fragment slot="footer">
<Button
submit
submissionLoader
forceShowLoader={creating}
disabled={creating || resendTimer > 0}>
{emailSent ? 'Resend email' : 'Send email'}
</Button>
</svelte:fragment>
</Modal>
style="display: inline;">{email || get(user)?.email}</Typography.Text>
</Typography.Text>

<Typography.Text>
Wrong email? <Link
variant="default"
on:click={() => {
showUpdateEmail = true;
error = null;
}}>Update email address</Link> or <Link
variant="default"
on:click={() => logout()}>Switch account</Link>
</Typography.Text>

{#if emailSent && resendTimer > 0}
<div transition:slide={{ duration: 150 }}>
<Typography.Text
color="neutral-secondary"
style="margin-block-start: var(--gap-L, 16px);">
Didn't get the email? Try again in {resendTimer}s
</Typography.Text>
</div>
{/if}
</Layout.Stack>
</Card.Base>

<svelte:fragment slot="footer">
<Button
submit
submissionLoader
forceShowLoader={creating}
disabled={creating || resendTimer > 0}>
{emailSent ? 'Resend email' : 'Send email'}
</Button>
</svelte:fragment>
</Modal>
{:else}
<Modal
bind:show={showUpdateEmail}
bind:error
title="Update email address"
onSubmit={updateEmail}
autoClose={false}
backdrop={false}>
<InputEmail
id="new-email"
label="Email"
placeholder="Enter email"
bind:value={newEmail}
required
helper="You'll need access to this email to verify your account" />
<InputPassword
id="update-password"
label="Password"
placeholder="Enter password"
required
bind:value={newPassword} />

<svelte:fragment slot="footer">
<Button text on:click={resetUpdateEmailForm}>Cancel</Button>
<Button submit submissionLoader forceShowLoader={updating} disabled={updating}
>Update</Button>
</svelte:fragment>
</Modal>
{/if}
</div>

<style>
Expand Down
3 changes: 2 additions & 1 deletion src/lib/elements/forms/inputEmail.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
export let readonly = false;
export let autofocus = false;
export let autocomplete = false;
export let helper: string = undefined;
export let leadingIcon: ComponentType | undefined = undefined;

let error: string;
Expand Down Expand Up @@ -49,7 +50,7 @@
on:input
on:invalid={handleInvalid}
type="email"
helper={error}
helper={error || helper}
state={error ? 'error' : 'default'}
autofocus={autofocus || undefined}
autocomplete={autocomplete ? 'on' : 'off'}
Expand Down
Loading