mirror of
https://github.com/haveno-dex/haveno-ui.git
synced 2025-05-02 06:26:22 -04:00
feat: wallet seed phrase
--- Co-authored-by: @schowdhuri Reviewed-by: @schowdhuri
This commit is contained in:
parent
250d742d48
commit
ad493f5147
13 changed files with 890 additions and 1 deletions
|
@ -0,0 +1,67 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import {
|
||||||
|
createStyles,
|
||||||
|
Group,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
Space,
|
||||||
|
Stack,
|
||||||
|
} from "@mantine/core";
|
||||||
|
import { BodyText } from "@atoms/Typography";
|
||||||
|
import { useXmrSeed } from "@hooks/haveno/useXmrSeed";
|
||||||
|
|
||||||
|
export function SeedPhrase() {
|
||||||
|
const { classes } = useStyles();
|
||||||
|
const { data: xmrseeds, isLoading } = useXmrSeed();
|
||||||
|
const seeds = xmrseeds?.split(" ");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack>
|
||||||
|
<Space h="lg" />
|
||||||
|
{isLoading && <BodyText>Loading Wallet Seeds...</BodyText>}
|
||||||
|
<List type="ordered" className={classes.container}>
|
||||||
|
{seeds?.map((label, index) => (
|
||||||
|
<Group key={index} className={classes.background} spacing="sm">
|
||||||
|
<ListItem>{label}</ListItem>
|
||||||
|
</Group>
|
||||||
|
))}
|
||||||
|
</List>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles((theme) => ({
|
||||||
|
background: {
|
||||||
|
backgroundColor: theme.colors.gray[3],
|
||||||
|
borderRadius: "0.5rem",
|
||||||
|
flex: "0 30%",
|
||||||
|
li: {
|
||||||
|
color: theme.colors.gray[6],
|
||||||
|
},
|
||||||
|
padding: "0.75rem 1rem",
|
||||||
|
span: {
|
||||||
|
color: theme.colors.gray[9],
|
||||||
|
},
|
||||||
|
width: "15rem",
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
display: "flex",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
gap: "1rem",
|
||||||
|
},
|
||||||
|
}));
|
|
@ -0,0 +1,30 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import type { ComponentStory, ComponentMeta } from "@storybook/react";
|
||||||
|
import { WalletManagement } from ".";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "organisms/Wallet Management",
|
||||||
|
component: WalletManagement,
|
||||||
|
} as ComponentMeta<typeof WalletManagement>;
|
||||||
|
|
||||||
|
const Template: ComponentStory<typeof WalletManagement> = () => {
|
||||||
|
return <WalletManagement />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Default = Template.bind({});
|
||||||
|
Default.args = {};
|
|
@ -0,0 +1,62 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||||
|
import { render, waitForElementToBeRemoved } from "@testing-library/react";
|
||||||
|
import { AppProviders } from "@atoms/AppProviders";
|
||||||
|
import { WalletManagement } from ".";
|
||||||
|
import { SeedPhrase } from "./SeedPhrase";
|
||||||
|
|
||||||
|
describe("molecules::WalletManagement", () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
vi.mock("@hooks/haveno/useValidatePassword", () => ({
|
||||||
|
useValidatePassword: () => ({
|
||||||
|
isLoading: false,
|
||||||
|
isSuccess: true,
|
||||||
|
data: true,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@hooks/haveno/useXmrSeed", () => ({
|
||||||
|
useXmrSeed: () => ({
|
||||||
|
isLoading: true,
|
||||||
|
isSuccess: true,
|
||||||
|
data: "baptism ounce solved gimmick cafe absorb pouch gesture fawns degrees bikini inline island oncoming menu tissue cajun inwardly chlorine popular sleepless taboo aces arises popular",
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders loading state", () => {
|
||||||
|
const { asFragment } = render(
|
||||||
|
<AppProviders>
|
||||||
|
<WalletManagement />
|
||||||
|
</AppProviders>
|
||||||
|
);
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("renders after loading data", async () => {
|
||||||
|
const { asFragment, queryByText } = render(
|
||||||
|
<AppProviders>
|
||||||
|
<SeedPhrase />
|
||||||
|
</AppProviders>
|
||||||
|
);
|
||||||
|
if (queryByText("Loading...")) {
|
||||||
|
await waitForElementToBeRemoved(() => queryByText("Loading..."));
|
||||||
|
}
|
||||||
|
expect(asFragment()).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,109 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
import { useForm } from "@mantine/hooks";
|
||||||
|
import { Group, Space, Stack } from "@mantine/core";
|
||||||
|
import { showNotification } from "@mantine/notifications";
|
||||||
|
import { Button } from "@atoms/Buttons";
|
||||||
|
import { PasswordInput } from "@atoms/PasswordInput";
|
||||||
|
import { useValidatePassword } from "@hooks/haveno/useValidatePassword";
|
||||||
|
import { LangKeys } from "@constants/lang";
|
||||||
|
import { SeedPhrase } from "./SeedPhrase";
|
||||||
|
|
||||||
|
export function WalletManagement() {
|
||||||
|
const [isRevealed, setRevealed] = useState(false);
|
||||||
|
const { getInputProps, onSubmit, values, reset } = useForm<FormValues>({
|
||||||
|
initialValues: {
|
||||||
|
password: "",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { refetch: validatePassword } = useValidatePassword(
|
||||||
|
{
|
||||||
|
password: values.password,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
validatePassword().then(({ data: isValidPassword }) => {
|
||||||
|
if (isValidPassword) {
|
||||||
|
setRevealed(true);
|
||||||
|
reset();
|
||||||
|
} else {
|
||||||
|
setRevealed(false);
|
||||||
|
showNotification({
|
||||||
|
color: "red",
|
||||||
|
title: "Invalid password",
|
||||||
|
message: "Please check your password",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack>
|
||||||
|
{isRevealed ? (
|
||||||
|
<Stack>
|
||||||
|
<SeedPhrase />
|
||||||
|
<Space h="lg" />
|
||||||
|
<Group position="left">
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
onClick={() => {
|
||||||
|
setRevealed(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Hide Seed Phrase
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
) : (
|
||||||
|
<form onSubmit={onSubmit(handleSubmit)}>
|
||||||
|
<Stack>
|
||||||
|
<Space h="sm" />
|
||||||
|
<PasswordInput
|
||||||
|
autoFocus
|
||||||
|
id="password"
|
||||||
|
required
|
||||||
|
label={
|
||||||
|
<FormattedMessage
|
||||||
|
id={LangKeys.AccountWalletPassword}
|
||||||
|
defaultMessage="Password"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{...getInputProps("password")}
|
||||||
|
/>
|
||||||
|
<Space h="lg" />
|
||||||
|
<Group position="right">
|
||||||
|
<Button type="submit" disabled={values.password ? false : true}>
|
||||||
|
Reveal Seed Phrase
|
||||||
|
</Button>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FormValues {
|
||||||
|
password: string;
|
||||||
|
}
|
|
@ -0,0 +1,494 @@
|
||||||
|
// Vitest Snapshot v1
|
||||||
|
|
||||||
|
exports[`molecules::WalletManagement > renders after loading data 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<div
|
||||||
|
class="mantine-Stack-root mantine-lfk3cq"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mantine-63n06h"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="mantine-Text-root mantine-1ogvxnc"
|
||||||
|
>
|
||||||
|
Loading Wallet Seeds...
|
||||||
|
</div>
|
||||||
|
<ol
|
||||||
|
class="mantine-List-root mantine-14df5ct"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
baptism
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
ounce
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
solved
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
gimmick
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
cafe
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
absorb
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
pouch
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
gesture
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
fawns
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
degrees
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
bikini
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
inline
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
island
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
oncoming
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
menu
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
tissue
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
cajun
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
inwardly
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
chlorine
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
popular
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
sleepless
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
taboo
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
aces
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
arises
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-1qkd5ve"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
class="mantine-List-item mantine-Group-child mantine-xm6zd"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="__mantine-ref-itemWrapper mantine-1hf9p21 mantine-List-itemWrapper"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
popular
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`molecules::WalletManagement > renders loading state 1`] = `
|
||||||
|
<DocumentFragment>
|
||||||
|
<div
|
||||||
|
class="mantine-Stack-root mantine-lfk3cq"
|
||||||
|
>
|
||||||
|
<form>
|
||||||
|
<div
|
||||||
|
class="mantine-Stack-root mantine-lfk3cq"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mantine-78ek8g"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="mantine-PasswordInput-root mantine-14qek68"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
class="mantine-PasswordInput-label mantine-1bjo575"
|
||||||
|
for="password"
|
||||||
|
id="password-label"
|
||||||
|
>
|
||||||
|
Password
|
||||||
|
<span
|
||||||
|
class="mantine-1wc35tu mantine-PasswordInput-required"
|
||||||
|
>
|
||||||
|
*
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
class="mantine-PasswordInput-wrapper mantine-12sbrde"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
aria-invalid="false"
|
||||||
|
class="mantine-PasswordInput-defaultVariant mantine-PasswordInput-input mantine-PasswordInput-input mantine-nakpsh"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
class="mantine-PasswordInput-innerInput mantine-17c0t6q"
|
||||||
|
id="password"
|
||||||
|
required=""
|
||||||
|
type="password"
|
||||||
|
value=""
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-o3oqoy mantine-PasswordInput-rightSection"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
aria-hidden="true"
|
||||||
|
class="mantine-ActionIcon-hover mantine-ActionIcon-root mantine-PasswordInput-visibilityToggle mantine-910bvd"
|
||||||
|
tabindex="-1"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
fill="none"
|
||||||
|
height="15"
|
||||||
|
viewBox="0 0 15 15"
|
||||||
|
width="15"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="M7.5 11C4.80285 11 2.52952 9.62184 1.09622 7.50001C2.52952 5.37816 4.80285 4 7.5 4C10.1971 4 12.4705 5.37816 13.9038 7.50001C12.4705 9.62183 10.1971 11 7.5 11ZM7.5 3C4.30786 3 1.65639 4.70638 0.0760002 7.23501C-0.0253338 7.39715 -0.0253334 7.60288 0.0760014 7.76501C1.65639 10.2936 4.30786 12 7.5 12C10.6921 12 13.3436 10.2936 14.924 7.76501C15.0253 7.60288 15.0253 7.39715 14.924 7.23501C13.3436 4.70638 10.6921 3 7.5 3ZM7.5 9.5C8.60457 9.5 9.5 8.60457 9.5 7.5C9.5 6.39543 8.60457 5.5 7.5 5.5C6.39543 5.5 5.5 6.39543 5.5 7.5C5.5 8.60457 6.39543 9.5 7.5 9.5Z"
|
||||||
|
fill="currentColor"
|
||||||
|
fill-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="mantine-63n06h"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="mantine-Group-root mantine-147cgkf"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="mantine-Button-filled mantine-Button-root mantine-Group-child mantine-s2bdxi"
|
||||||
|
disabled=""
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mantine-3xbgk5 mantine-Button-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="mantine-qo1k2 mantine-Button-label"
|
||||||
|
>
|
||||||
|
Reveal Seed Phrase
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</DocumentFragment>
|
||||||
|
`;
|
|
@ -0,0 +1,17 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
export * from "./WalletManagement";
|
|
@ -50,4 +50,7 @@ export enum LangKeys {
|
||||||
AccountSecurityFieldCurrentPassword = "account.security.field.currentPassword",
|
AccountSecurityFieldCurrentPassword = "account.security.field.currentPassword",
|
||||||
AccountSecurityFieldPasswordFormatMsg = "account.security.field.password.format.message",
|
AccountSecurityFieldPasswordFormatMsg = "account.security.field.password.format.message",
|
||||||
AccountSecurityFieldRepeatPasswordMatchMsg = "account.security.field.repeatPassword.match.message",
|
AccountSecurityFieldRepeatPasswordMatchMsg = "account.security.field.repeatPassword.match.message",
|
||||||
|
AccountWalletTitle = "account.wallet.title",
|
||||||
|
AccountWalletDesc = "account.wallet.desc",
|
||||||
|
AccountWalletPassword = "account.wallet.field.password",
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,10 @@ const LangPackEN: { [key in LangKeys]: string } = {
|
||||||
[LangKeys.AccountSecurityFieldRepeatPasswordMatchMsg]:
|
[LangKeys.AccountSecurityFieldRepeatPasswordMatchMsg]:
|
||||||
"Passwords don't match",
|
"Passwords don't match",
|
||||||
[LangKeys.CreatePassword]: "Create password",
|
[LangKeys.CreatePassword]: "Create password",
|
||||||
|
[LangKeys.AccountWalletTitle]: "Your wallet details",
|
||||||
|
[LangKeys.AccountWalletDesc]:
|
||||||
|
"The Haveno wallet is permanently connected to your account. Solely saving your seed phrase is not enough to recover your account, you need to download a backup of your account, which you can download via the backup section.",
|
||||||
|
[LangKeys.AccountWalletPassword]: "Password",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LangPackEN;
|
export default LangPackEN;
|
||||||
|
|
|
@ -59,6 +59,10 @@ const LangPackES: { [key in LangKeys]: string } = {
|
||||||
[LangKeys.AccountSecurityFieldRepeatPasswordMatchMsg]:
|
[LangKeys.AccountSecurityFieldRepeatPasswordMatchMsg]:
|
||||||
"La confirmación de la contraseña no coincide con la contraseña.",
|
"La confirmación de la contraseña no coincide con la contraseña.",
|
||||||
[LangKeys.CreatePassword]: "Crear contraseña",
|
[LangKeys.CreatePassword]: "Crear contraseña",
|
||||||
|
[LangKeys.AccountWalletTitle]: "Detalles de tu billetera",
|
||||||
|
[LangKeys.AccountWalletDesc]:
|
||||||
|
"La billetera Haveno está permanentemente conectada a su cuenta. Solo guardar su frase inicial no es suficiente para recuperar su cuenta, necesita descargar una copia de seguridad de su cuenta, que puede descargar a través de la sección de copia de seguridad.",
|
||||||
|
[LangKeys.AccountWalletPassword]: "contraseña",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LangPackES;
|
export default LangPackES;
|
||||||
|
|
|
@ -26,11 +26,13 @@ export enum QueryKeys {
|
||||||
Prices = "Haveno.Prices",
|
Prices = "Haveno.Prices",
|
||||||
PrimaryAddress = "Haveno.PrimaryAddress",
|
PrimaryAddress = "Haveno.PrimaryAddress",
|
||||||
SyncStatus = "Haveno.SyncStatus",
|
SyncStatus = "Haveno.SyncStatus",
|
||||||
|
XmrSeed = "Haveno.XmrSeed",
|
||||||
|
|
||||||
// Storage
|
// Storage
|
||||||
StorageAccountInfo = "Storage.AccountInfo",
|
StorageAccountInfo = "Storage.AccountInfo",
|
||||||
StoragePreferences = "Storage.Preferences",
|
StoragePreferences = "Storage.Preferences",
|
||||||
StorageRemoteMoneroNode = "Storage.RemoteMoneroNode",
|
StorageRemoteMoneroNode = "Storage.RemoteMoneroNode",
|
||||||
|
StorageIsPasswordValid = "Storage.IsPasswordValid",
|
||||||
|
|
||||||
// Others
|
// Others
|
||||||
AuthSession = "AuthSession",
|
AuthSession = "AuthSession",
|
||||||
|
|
45
packages/renderer/src/hooks/haveno/useValidatePassword.ts
Normal file
45
packages/renderer/src/hooks/haveno/useValidatePassword.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { QueryKeys } from "@constants/query-keys";
|
||||||
|
import { useQuery } from "react-query";
|
||||||
|
|
||||||
|
interface Variables {
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
enabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useValidatePassword(variables: Variables, options?: Options) {
|
||||||
|
return useQuery<boolean>(
|
||||||
|
QueryKeys.StorageIsPasswordValid,
|
||||||
|
async () => {
|
||||||
|
try {
|
||||||
|
const authToken = await window.electronStore.verifyPassword(
|
||||||
|
variables.password
|
||||||
|
);
|
||||||
|
return Boolean(authToken);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: options?.enabled ?? true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
26
packages/renderer/src/hooks/haveno/useXmrSeed.ts
Normal file
26
packages/renderer/src/hooks/haveno/useXmrSeed.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// =============================================================================
|
||||||
|
// Copyright 2022 Haveno
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
import { useQuery } from "react-query";
|
||||||
|
import { QueryKeys } from "@constants/query-keys";
|
||||||
|
import { useHavenoClient } from "./useHavenoClient";
|
||||||
|
|
||||||
|
export function useXmrSeed() {
|
||||||
|
const client = useHavenoClient();
|
||||||
|
return useQuery(QueryKeys.XmrSeed, async () => {
|
||||||
|
return client.getXmrSeed();
|
||||||
|
});
|
||||||
|
}
|
|
@ -14,12 +14,38 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
|
import { Box, createStyles, Group, Stack } from "@mantine/core";
|
||||||
|
import { BodyText, Heading } from "@atoms/Typography";
|
||||||
|
import { WalletManagement } from "@organisms/WalletManagement/WalletManagement";
|
||||||
import { AccountLayout } from "@templates/AccountLayout";
|
import { AccountLayout } from "@templates/AccountLayout";
|
||||||
|
import { LangKeys } from "@constants/lang";
|
||||||
|
|
||||||
export function Wallet() {
|
export function Wallet() {
|
||||||
|
const { classes } = useStyles();
|
||||||
return (
|
return (
|
||||||
<AccountLayout>
|
<AccountLayout>
|
||||||
<h1>Account Wallet</h1>
|
<Box>
|
||||||
|
<Stack spacing="lg" className={classes.content}>
|
||||||
|
<Group spacing="sm">
|
||||||
|
<Heading stringId={LangKeys.AccountWalletTitle} order={3}>
|
||||||
|
Your wallet details
|
||||||
|
</Heading>
|
||||||
|
<BodyText heavy stringId={LangKeys.AccountWalletDesc} size="md">
|
||||||
|
The Haveno wallet is permanently connected to your account. Solely
|
||||||
|
saving your seed phrase is not enough to recover your account, you
|
||||||
|
need to download a backup of your account, which you can download
|
||||||
|
via the backup section.
|
||||||
|
</BodyText>
|
||||||
|
</Group>
|
||||||
|
</Stack>
|
||||||
|
<WalletManagement />
|
||||||
|
</Box>
|
||||||
</AccountLayout>
|
</AccountLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const useStyles = createStyles((theme) => ({
|
||||||
|
content: {
|
||||||
|
maxWidth: theme.other.contentWidthMd,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue