Skip to content

Commit 0ee967d

Browse files
authored
Refactor authentication screens into a single AuthWizard (#3197)
* Refactor authentication screens into a single AuthWizard. * Refactor authentication screens into a single AuthWizard. * Refactor authentication screens into a single AuthWizard.
1 parent 571b6ad commit 0ee967d

File tree

13 files changed

+342
-315
lines changed

13 files changed

+342
-315
lines changed

src/frontend/src/lib/components/views/AuthDialog.svelte

Lines changed: 0 additions & 63 deletions
This file was deleted.

src/frontend/src/lib/components/wizards/MigrationWizard.svelte

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
<script lang="ts">
2-
import AuthPanel from "$lib/components/layout/AuthPanel.svelte";
3-
import Header from "$lib/components/layout/Header.svelte";
4-
import Footer from "$lib/components/layout/Footer.svelte";
52
import Input from "$lib/components/ui/Input.svelte";
63
import Button from "$lib/components/ui/Button.svelte";
74
import { isNullish, nonNullish } from "@dfinity/utils";
85
import { MigrationFlow } from "$lib/flows/migrationFlow.svelte";
9-
import CreatePasskey from "$lib/components/views/CreatePasskey.svelte";
10-
import { goto } from "$app/navigation";
11-
import { lastUsedIdentitiesStore } from "$lib/stores/last-used-identities.store";
6+
import CreatePasskey from "$lib/components/wizards/auth/views/CreatePasskey.svelte";
127
import ProgressRing from "$lib/components/ui/ProgressRing.svelte";
138
import { handleError } from "$lib/components/utils/error";
149
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
<script lang="ts">
2+
import { nonNullish } from "@dfinity/utils";
3+
import { AuthFlow } from "$lib/flows/authFlow.svelte";
4+
import { AuthLastUsedFlow } from "$lib/flows/authLastUsedFlow.svelte";
5+
import type { Snippet } from "svelte";
6+
import SolveCaptcha from "$lib/components/wizards/auth/views/SolveCaptcha.svelte";
7+
import PickAuthenticationMethod from "$lib/components/wizards/auth/views/PickAuthenticationMethod.svelte";
8+
import Dialog from "$lib/components/ui/Dialog.svelte";
9+
import SetupOrUseExistingPasskey from "$lib/components/wizards/auth/views/SetupOrUseExistingPasskey.svelte";
10+
import CreatePasskey from "$lib/components/wizards/auth/views/CreatePasskey.svelte";
11+
import SystemOverlayBackdrop from "$lib/components/utils/SystemOverlayBackdrop.svelte";
12+
13+
interface Props {
14+
isAuthenticating?: boolean;
15+
onSignIn: (identityNumber: bigint) => void;
16+
onSignUp: (identityNumber: bigint) => void;
17+
onError: (error: unknown) => void;
18+
withinDialog?: boolean;
19+
children?: Snippet;
20+
}
21+
22+
let {
23+
isAuthenticating = $bindable(),
24+
onSignIn,
25+
onSignUp,
26+
onError,
27+
withinDialog = false,
28+
children,
29+
}: Props = $props();
30+
31+
const authFlow = new AuthFlow();
32+
const authLastUsedFlow = new AuthLastUsedFlow();
33+
34+
const handleContinueWithExistingPasskey = async () => {
35+
isAuthenticating = true;
36+
try {
37+
onSignIn(await authFlow.continueWithExistingPasskey());
38+
} catch (error) {
39+
onError(error);
40+
} finally {
41+
isAuthenticating = false;
42+
}
43+
};
44+
const handleCreatePasskey = async (name: string) => {
45+
isAuthenticating = true;
46+
try {
47+
onSignUp(await authFlow.createPasskey(name));
48+
} catch (error) {
49+
onError(error);
50+
} finally {
51+
isAuthenticating = false;
52+
}
53+
};
54+
const handleContinueWithGoogle = async () => {
55+
isAuthenticating = true;
56+
try {
57+
const { identityNumber, type } = await authFlow.continueWithGoogle();
58+
(type === "signUp" ? onSignUp : onSignIn)(identityNumber);
59+
} catch (error) {
60+
onError(error);
61+
} finally {
62+
isAuthenticating = false;
63+
}
64+
};
65+
</script>
66+
67+
{#snippet dialogContent()}
68+
{#if authFlow.view === "setupOrUseExistingPasskey"}
69+
<SetupOrUseExistingPasskey
70+
setupNew={authFlow.setupNewPasskey}
71+
useExisting={handleContinueWithExistingPasskey}
72+
/>
73+
{:else if authFlow.view === "setupNewPasskey"}
74+
<CreatePasskey create={handleCreatePasskey} />
75+
{/if}
76+
{/snippet}
77+
78+
{#if nonNullish(authFlow.captcha)}
79+
<SolveCaptcha {...authFlow.captcha} />
80+
{:else}
81+
{#if authFlow.view === "chooseMethod" || !withinDialog}
82+
{@render children?.()}
83+
<PickAuthenticationMethod
84+
setupOrUseExistingPasskey={authFlow.setupOrUseExistingPasskey}
85+
continueWithGoogle={handleContinueWithGoogle}
86+
/>
87+
{/if}
88+
{#if authFlow.view !== "chooseMethod"}
89+
{#if !withinDialog}
90+
<Dialog
91+
onClose={authFlow.chooseMethod}
92+
showCloseButton={!isAuthenticating}
93+
closeOnOutsideClick={!isAuthenticating}
94+
>
95+
{@render dialogContent()}
96+
</Dialog>
97+
{:else}
98+
{@render dialogContent()}
99+
{/if}
100+
{/if}
101+
{/if}
102+
103+
{#if authFlow.systemOverlay || authLastUsedFlow.systemOverlay}
104+
<SystemOverlayBackdrop />
105+
{/if}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as AuthWizard } from "./AuthWizard.svelte";

src/frontend/src/lib/components/views/CreatePasskey.svelte renamed to src/frontend/src/lib/components/wizards/auth/views/CreatePasskey.svelte

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,23 @@
66
import Button from "$lib/components/ui/Button.svelte";
77
import Input from "$lib/components/ui/Input.svelte";
88
import ProgressRing from "$lib/components/ui/ProgressRing.svelte";
9-
import { handleError } from "$lib/components/utils/error";
109
1110
interface Props {
1211
create: (name: string) => Promise<void>;
13-
onError?: (error: unknown) => void;
1412
}
1513
16-
const { create, onError = handleError }: Props = $props();
14+
const { create }: Props = $props();
1715
1816
let inputRef = $state<HTMLInputElement>();
1917
let name = $state("");
20-
let loading = $state(false);
18+
let creating = $state(false);
2119
22-
const handleSubmit = async () => {
23-
loading = true;
20+
const handleCreate = async () => {
21+
creating = true;
2422
try {
2523
await create(name.trim());
26-
} catch (error) {
27-
loading = false;
28-
onError(error);
24+
} finally {
25+
creating = false;
2926
}
3027
};
3128
@@ -56,20 +53,20 @@
5653
autocomplete="off"
5754
autocorrect="off"
5855
spellcheck="false"
59-
disabled={loading}
56+
disabled={creating}
6057
error={name.length > 64 ? "Maximum length is 64 characters." : undefined}
6158
aria-label="Identity name"
6259
/>
6360
</div>
6461
<div class="mt-auto flex flex-col items-stretch gap-3">
6562
<Button
66-
onclick={handleSubmit}
63+
onclick={handleCreate}
6764
variant="primary"
6865
size="lg"
6966
type="submit"
70-
disabled={name.length === 0 || name.length > 64 || loading}
67+
disabled={name.length === 0 || name.length > 64 || creating}
7168
>
72-
{#if loading}
69+
{#if creating}
7370
<ProgressRing />
7471
<span>Creating Passkey...</span>
7572
{:else}

src/frontend/src/lib/components/views/PickAuthenticationMethod.svelte renamed to src/frontend/src/lib/components/wizards/auth/views/PickAuthenticationMethod.svelte

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,22 @@
66
import Alert from "$lib/components/ui/Alert.svelte";
77
import ProgressRing from "$lib/components/ui/ProgressRing.svelte";
88
import { canisterConfig } from "$lib/globals";
9-
import { handleError } from "$lib/components/utils/error";
109
1110
interface Props {
1211
setupOrUseExistingPasskey: () => void;
1312
continueWithGoogle: () => Promise<void>;
14-
onError?: (error: unknown) => void;
1513
}
1614
17-
const {
18-
setupOrUseExistingPasskey,
19-
continueWithGoogle,
20-
onError = handleError,
21-
}: Props = $props();
15+
const { setupOrUseExistingPasskey, continueWithGoogle }: Props = $props();
2216
23-
let googleLoading = $state(false);
17+
let authenticating = $state(false);
2418
2519
const handleContinueWithGoogle = async () => {
26-
googleLoading = true;
20+
authenticating = true;
2721
try {
2822
await continueWithGoogle();
29-
} catch (error) {
30-
onError(error);
3123
} finally {
32-
googleLoading = false;
24+
authenticating = false;
3325
}
3426
};
3527
@@ -48,7 +40,7 @@
4840
<div class="flex flex-col items-stretch gap-3">
4941
<Button
5042
onclick={setupOrUseExistingPasskey}
51-
disabled={!supportsPasskeys || googleLoading}
43+
disabled={!supportsPasskeys || authenticating}
5244
size="xl"
5345
>
5446
<PasskeyIcon />
@@ -58,10 +50,10 @@
5850
<Button
5951
onclick={handleContinueWithGoogle}
6052
variant="secondary"
61-
disabled={googleLoading}
53+
disabled={authenticating}
6254
size="xl"
6355
>
64-
{#if googleLoading}
56+
{#if authenticating}
6557
<ProgressRing />
6658
<span>Authenticating with Google...</span>
6759
{:else}

src/frontend/src/lib/components/views/SetupOrUseExistingPasskey.svelte renamed to src/frontend/src/lib/components/wizards/auth/views/SetupOrUseExistingPasskey.svelte

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,22 @@
33
import Button from "$lib/components/ui/Button.svelte";
44
import PasskeyIllustration from "$lib/components/illustrations/PasskeyIllustration.svelte";
55
import ProgressRing from "$lib/components/ui/ProgressRing.svelte";
6-
import { handleError } from "$lib/components/utils/error";
76
87
interface Props {
98
setupNew: () => void;
109
useExisting: () => Promise<void>;
11-
onError?: (error: unknown) => void;
1210
}
1311
14-
const { setupNew, useExisting, onError = handleError }: Props = $props();
12+
const { setupNew, useExisting }: Props = $props();
1513
16-
let loading = $state(false);
14+
let isAuthenticating = $state(false);
1715
1816
const handleUseExisting = async () => {
19-
loading = true;
17+
isAuthenticating = true;
2018
try {
2119
await useExisting();
22-
} catch (error) {
23-
onError(error);
2420
} finally {
25-
loading = false;
21+
isAuthenticating = false;
2622
}
2723
};
2824
</script>
@@ -38,16 +34,16 @@
3834
</p>
3935
</div>
4036
<div class="flex flex-col gap-3">
41-
<Button onclick={setupNew} size="lg" disabled={loading}
37+
<Button onclick={setupNew} size="lg" disabled={isAuthenticating}
4238
>Set up a new Passkey</Button
4339
>
4440
<Button
4541
onclick={handleUseExisting}
4642
variant="secondary"
4743
size="lg"
48-
disabled={loading}
44+
disabled={isAuthenticating}
4945
>
50-
{#if loading}
46+
{#if isAuthenticating}
5147
<ProgressRing />
5248
<span>Authenticating...</span>
5349
{:else}

0 commit comments

Comments
 (0)