Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

web-wallet: Overhaul landing page #1536

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
9 changes: 9 additions & 0 deletions web-wallet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add autocomplete attribute on the login field [#1533]

### Changed

- Redesign the landing page [#1534]
- Trigger the Restore flow if a user tries to access a new wallet [#1535]
- Update `OperationResult` to infer error messages from arbitrary values [#1524]
- Update Tabs to use native scroll behavior [#1320]

Expand Down Expand Up @@ -183,6 +189,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#1514]: https://github.com/dusk-network/rusk/issues/1514
[#1519]: https://github.com/dusk-network/rusk/issues/1519
[#1524]: https://github.com/dusk-network/rusk/issues/1524
[#1533]: https://github.com/dusk-network/rusk/issues/1533
[#1534]: https://github.com/dusk-network/rusk/issues/1534
[#1535]: https://github.com/dusk-network/rusk/issues/1535
[#1537]: https://github.com/dusk-network/rusk/issues/1537

<!-- VERSIONS -->
Expand Down
10 changes: 0 additions & 10 deletions web-wallet/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion web-wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
"@floating-ui/dom": "1.6.3",
"@mdi/js": "7.4.47",
"bip39": "3.1.0",
"css-doodle": "0.38.4",
"lamb": "0.61.1",
"qr-scanner": "1.4.2",
"qrcode": "1.5.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
<Card iconPath={mdiAlertOutline} heading="Existing Wallet Detected">
<div class="flex flex-col gap-1">
<p>
Logging in to a new wallet will overwrite the current local wallet
cache, meaning that when you log in again with the previous
mnemonic/account you will need to wait for the wallet to sync.
Initializing a new wallet will replace your existing local wallet cache,
erasing any stored data. Ensure you have securely backed up your current
wallet's seed phrase to prevent loss. Proceeding without a backup can
lead to irreversible loss of access to your assets.
</p>
<div class="flex gap-1 w-100">
<AppAnchorButton
className="flex-1"
href="/setup"
href="/"
text="Back"
variant="tertiary"
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<script>
import { makeClassName } from "$lib/dusk/string";
import { Button, Textbox } from "..";

/** @type {TextboxTypes} */
export let type = "text";

/** @type {string} */
export let name;
export let autocomplete = "off";
export let placeholder = "";
export let value = "";

/** @type {string | undefined} */
export let className = undefined;

/** @type {string} */
export let buttonText = "Submit";

/** @type {Textbox} */
let inputElement;

export function focus() {
inputElement?.focus();
}

export function select() {
inputElement?.select();
}

$: classes = makeClassName(["dusk-field-button-group", className]);
</script>

<div class={classes}>
<Textbox
bind:this={inputElement}
tabindex={0}
{type}
{autocomplete}
{name}
required
bind:value
{placeholder}
/>
<Button on:click type="submit" text={buttonText} variant="secondary" />
</div>
111 changes: 59 additions & 52 deletions web-wallet/src/lib/dusk/components/Mnemonic/Mnemonic.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
enteredMnemonicPhrase = Array(wordLimit).fill("");
}

const isTriggeredByLogin =
nortonandreev marked this conversation as resolved.
Show resolved Hide resolved
enteredMnemonicPhrase.some((word) => word !== "") && currentIndex === 0;

/**
* @param {string} word
* @param {string} index
Expand Down Expand Up @@ -118,63 +121,67 @@
</script>

<div {...$$restProps} class={classes}>
<div class="dusk-mnemonic__actions-wrapper">
{#if type === "authenticate" && shouldShowPaste}
{#if !isTriggeredByLogin}
<div class="dusk-mnemonic__actions-wrapper">
{#if type === "authenticate" && shouldShowPaste}
<Button
icon={{ path: mdiContentPaste }}
text="Paste seed phrase"
variant="tertiary"
on:click={pasteSeed}
/>
{/if}
<Button
icon={{ path: mdiContentPaste }}
text="Paste seed phrase"
disabled={!currentIndex}
on:click={undoLastWord}
icon={{ path: mdiRedoVariant }}
text="Undo"
variant="tertiary"
on:click={pasteSeed}
/>
{/if}
<Button
disabled={!currentIndex}
on:click={undoLastWord}
icon={{ path: mdiRedoVariant }}
text="Undo"
variant="tertiary"
/>
</div>
</div>
{/if}

<Words words={enteredMnemonicPhrase} />

<div
class={type === "authenticate"
? "dusk-mnemonic__authenticate-actions-wrapper"
: "dusk-mnemonic__validate-actions-wrapper"}
>
{#if type === "authenticate" && enteredWordIndex.includes("")}
<Textbox
placeholder={`Enter word ${currentIndex + 1}`}
bind:this={textboxElement}
on:keydown={(e) =>
handleKeyDownOnAuthenticateTextbox(e, currentIndex.toString())}
maxlength={8}
type="text"
bind:value={currentInput}
/>
{#if suggestions.length}
<div class="dusk-mnemonic__suggestions-wrapper">
{#each suggestions as suggestion, index (`${suggestion}-${index}`)}
<Button
variant="tertiary"
text={suggestion}
data-value={suggestion}
on:click={handleWordButtonClick}
/>
{/each}
</div>
{/if}
{:else}
{#each mnemonicPhrase as word, index (`${word}-${index}`)}
<Button
variant="tertiary"
text={word}
data-value={word}
disabled={enteredWordIndex.includes(index.toString())}
on:click={(e) => handleWordButtonClick(e, index.toString())}
{#if !isTriggeredByLogin}
<div
class={type === "authenticate"
? "dusk-mnemonic__authenticate-actions-wrapper"
: "dusk-mnemonic__validate-actions-wrapper"}
>
{#if type === "authenticate" && enteredWordIndex.includes("")}
<Textbox
placeholder={`Enter word ${currentIndex + 1}`}
bind:this={textboxElement}
on:keydown={(e) =>
handleKeyDownOnAuthenticateTextbox(e, currentIndex.toString())}
maxlength={8}
type="text"
bind:value={currentInput}
/>
{/each}
{/if}
</div>
{#if suggestions.length}
<div class="dusk-mnemonic__suggestions-wrapper">
{#each suggestions as suggestion, index (`${suggestion}-${index}`)}
<Button
variant="tertiary"
text={suggestion}
data-value={suggestion}
on:click={handleWordButtonClick}
/>
{/each}
</div>
{/if}
{:else}
{#each mnemonicPhrase as word, index (`${word}-${index}`)}
<Button
variant="tertiary"
text={word}
data-value={word}
disabled={enteredWordIndex.includes(index.toString())}
on:click={(e) => handleWordButtonClick(e, index.toString())}
/>
{/each}
{/if}
</div>
{/if}
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { cleanup, fireEvent, render } from "@testing-library/svelte";
import { afterEach, describe, expect, it, vi } from "vitest";

import { FieldButtonGroup } from "..";

describe("FieldButtonGroup", () => {
const baseProps = { name: "test" };
const baseOptions = {
props: baseProps,
target: document.body,
};

afterEach(cleanup);

it("renders the component with default values", async () => {
const { getByRole, container } = render(FieldButtonGroup, baseOptions);

const input = getByRole("textbox");
const button = getByRole("button");

expect(input).toBeInTheDocument();
expect(button).toBeInTheDocument();

expect(container.firstChild).toMatchSnapshot();
});

it("updates input value on change", async () => {
const { getByRole, container } = render(FieldButtonGroup, baseOptions);
const input = getByRole("textbox");

await fireEvent.input(input, { target: { value: "test value" } });

expect(input).toHaveValue("test value");

expect(container.firstChild).toMatchSnapshot();
});

it("triggers click event on button click", async () => {
const { getByRole, component } = render(FieldButtonGroup);
const button = getByRole("button");

const mockClickHandler = vi.fn();
component.$on("click", mockClickHandler);

await fireEvent.click(button);

expect(mockClickHandler).toHaveBeenCalled();
});

it("focuses input on focus() call", async () => {
const { getByRole, component } = render(FieldButtonGroup);
const input = getByRole("textbox");

component.focus();
expect(input).toHaveFocus();
});

it("should expose a method to select the element's text", () => {
const { component, getByRole } = render(FieldButtonGroup, {
...baseProps,
value: "some input text",
});

const input = /** @type {HTMLInputElement} */ (getByRole("textbox"));

component.select();

const selectedText = input.value.substring(
Number(input.selectionStart),
Number(input.selectionEnd)
);

expect(selectedText).toBe("some input text");
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`FieldButtonGroup > renders the component with default values 1`] = `
<div
class="dusk-field-button-group"
>
<input
autocomplete="off"
class="dusk-textbox dusk-textbox-text"
name="test"
placeholder=""
required=""
tabindex="0"
type="text"
/>

<!--&lt;Textbox&gt;-->

<button
class="dusk-button dusk-button--type--submit dusk-button--variant--secondary dusk-button--size--normal"
type="submit"
>
<span
class="dusk-button__text"
>
Submit
</span>
</button>
<!--&lt;Button&gt;-->
</div>
`;

exports[`FieldButtonGroup > updates input value on change 1`] = `
<div
class="dusk-field-button-group"
>
<input
autocomplete="off"
class="dusk-textbox dusk-textbox-text"
name="test"
placeholder=""
required=""
tabindex="0"
type="text"
/>

<!--&lt;Textbox&gt;-->

<button
class="dusk-button dusk-button--type--submit dusk-button--variant--secondary dusk-button--size--normal"
type="submit"
>
<span
class="dusk-button__text"
>
Submit
</span>
</button>
<!--&lt;Button&gt;-->
</div>
`;
1 change: 1 addition & 0 deletions web-wallet/src/lib/dusk/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export { default as Checkbox } from "./Checkbox/Checkbox.svelte";
export { default as CircularIcon } from "./Icon/CircularIcon.svelte";
export { default as ErrorAlert } from "./ErrorAlert/ErrorAlert.svelte";
export { default as ErrorDetails } from "./ErrorDetails/ErrorDetails.svelte";
export { default as FieldButtonGroup } from "./FieldButtonGroup/FieldButtonGroup.svelte";
export { default as Icon } from "./Icon/Icon.svelte";
export { default as Mnemonic } from "./Mnemonic/Mnemonic.svelte";
export { default as ProgressBar } from "./ProgressBar/ProgressBar.svelte";
Expand Down
Loading