mirror of
https://github.com/haveno-dex/haveno-ui.git
synced 2024-12-23 14:39:45 -05:00
fix: wallet balance
- fiat balance display - currency formatting - added tests for WalletBalance - added test coverage scripts - bumped haveno-ts to v0.0.5 --- Reviewed-by: localredhead
This commit is contained in:
parent
bc6ed842d5
commit
71bbc7e3f5
6
.gitignore
vendored
6
.gitignore
vendored
@ -55,4 +55,10 @@ thumbs.db
|
||||
.idea/httpRequests
|
||||
/.idea/csv-plugin.xml
|
||||
|
||||
# Dev environment variables
|
||||
.env
|
||||
|
||||
# Coverage reports
|
||||
packages/main/coverage/
|
||||
packages/preload/coverage/
|
||||
packages/renderer/coverage/
|
||||
|
@ -23,6 +23,10 @@
|
||||
"test:preload": "vitest run -r packages/preload --passWithNoTests",
|
||||
"test:renderer": "vitest run -r packages/renderer --passWithNoTests",
|
||||
"test:renderer:watch": "vitest -r packages/renderer",
|
||||
"coverage:main": "vitest run -r packages/main --coverage",
|
||||
"coverage:preload": "vitest run -r packages/preload --coverage",
|
||||
"coverage:renderer": "vitest run -r packages/renderer --coverage",
|
||||
"coverage": "npm run coverage:main && npm run coverage:preload && npm run coverage:renderer",
|
||||
"watch": "node scripts/watch.js",
|
||||
"format": "prettier --write .",
|
||||
"lint": "eslint .",
|
||||
@ -84,7 +88,7 @@
|
||||
"dayjs": "^1.11.0",
|
||||
"electron-store": "^8.0.1",
|
||||
"electron-updater": "4.6.5",
|
||||
"haveno-ts": "0.0.4",
|
||||
"haveno-ts": "0.0.5",
|
||||
"joi": "^17.6.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"lodash": "^4.17.21",
|
||||
|
32
packages/main/vitest.coverage.config.js
Normal file
32
packages/main/vitest.coverage.config.js
Normal file
@ -0,0 +1,32 @@
|
||||
// =============================================================================
|
||||
// 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.
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Config for global end-to-end tests
|
||||
* placed in project root tests folder
|
||||
* @type {import('vite').UserConfig}
|
||||
* @see https://vitest.dev/config/
|
||||
*/
|
||||
const config = {
|
||||
test: {
|
||||
include: ["./src/**/*.{test,spec}.{ts,tsx}"],
|
||||
coverage: {
|
||||
reporter: ["html"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
32
packages/preload/vitest.coverage.config.js
Normal file
32
packages/preload/vitest.coverage.config.js
Normal file
@ -0,0 +1,32 @@
|
||||
// =============================================================================
|
||||
// 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.
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Config for global end-to-end tests
|
||||
* placed in project root tests folder
|
||||
* @type {import('vite').UserConfig}
|
||||
* @see https://vitest.dev/config/
|
||||
*/
|
||||
const config = {
|
||||
test: {
|
||||
include: ["./src/**/*.{test,spec}.{ts,tsx}"],
|
||||
coverage: {
|
||||
reporter: ["html"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
@ -0,0 +1,41 @@
|
||||
// =============================================================================
|
||||
// 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 { BodyText } from "@atoms/Typography";
|
||||
import { Stack } from "@mantine/core";
|
||||
import type { ComponentStory, ComponentMeta } from "@storybook/react";
|
||||
import { Currency } from ".";
|
||||
|
||||
export default {
|
||||
title: "atoms/Currency",
|
||||
component: Currency,
|
||||
} as ComponentMeta<typeof Currency>;
|
||||
|
||||
const Template: ComponentStory<typeof Currency> = (args) => {
|
||||
return (
|
||||
<Stack>
|
||||
<BodyText heavy>
|
||||
<Currency {...args} />
|
||||
</BodyText>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export const Default = Template.bind({});
|
||||
Default.args = {
|
||||
currencyCode: "EUR",
|
||||
value: 400000.12,
|
||||
};
|
@ -0,0 +1,49 @@
|
||||
// =============================================================================
|
||||
// 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 { describe, expect, it } from "vitest";
|
||||
import { render } from "@testing-library/react";
|
||||
import { AppProviders } from "@atoms/AppProviders";
|
||||
import { Currency } from ".";
|
||||
|
||||
describe("atoms::Currency", () => {
|
||||
it("renders without exploding", () => {
|
||||
const { asFragment } = render(
|
||||
<AppProviders>
|
||||
<Currency value={10} />
|
||||
</AppProviders>
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders currency value", () => {
|
||||
const { asFragment } = render(
|
||||
<AppProviders>
|
||||
<Currency currencyCode="USD" value={10} />
|
||||
</AppProviders>
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders decimal value", () => {
|
||||
const { asFragment } = render(
|
||||
<AppProviders>
|
||||
<Currency value={10.12345678} />
|
||||
</AppProviders>
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
50
packages/renderer/src/components/atoms/Currency/Currency.tsx
Normal file
50
packages/renderer/src/components/atoms/Currency/Currency.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
// =============================================================================
|
||||
// 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 { useMemo } from "react";
|
||||
import { useIntl } from "react-intl";
|
||||
|
||||
interface CurrencyProps {
|
||||
currencyCode?: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export function Currency(props: CurrencyProps) {
|
||||
const { currencyCode, value } = props;
|
||||
const intl = useIntl();
|
||||
|
||||
const formattedNumber = useMemo(
|
||||
() =>
|
||||
intl
|
||||
.formatNumber(value, {
|
||||
...(currencyCode
|
||||
? {
|
||||
currency: currencyCode,
|
||||
currencyDisplay: "code",
|
||||
style: "currency",
|
||||
}
|
||||
: {
|
||||
style: "decimal",
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 12,
|
||||
}),
|
||||
})
|
||||
.replace(/XXX\s/, ""),
|
||||
[currencyCode, value]
|
||||
);
|
||||
|
||||
return <>{formattedNumber}</>;
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`atoms::Currency > renders currency value 1`] = `
|
||||
<DocumentFragment>
|
||||
USD 10.00
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`atoms::Currency > renders decimal value 1`] = `
|
||||
<DocumentFragment>
|
||||
10.12345678
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`atoms::Currency > renders without exploding 1`] = `
|
||||
<DocumentFragment>
|
||||
10.00
|
||||
</DocumentFragment>
|
||||
`;
|
17
packages/renderer/src/components/atoms/Currency/index.ts
Normal file
17
packages/renderer/src/components/atoms/Currency/index.ts
Normal file
@ -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 "./Currency";
|
@ -14,14 +14,14 @@
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
import type { ReactText } from "react";
|
||||
import type { ReactNode, ReactText } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import type { TextProps as MTextProps } from "@mantine/core";
|
||||
import { Text as MText, createStyles } from "@mantine/core";
|
||||
import type { LangKeys } from "@constants/lang";
|
||||
|
||||
type TextProps<TComponent> = MTextProps<TComponent> & {
|
||||
children: ReactText;
|
||||
children: ReactText | ReactNode;
|
||||
stringId?: LangKeys;
|
||||
};
|
||||
|
||||
@ -44,7 +44,10 @@ export function BodyText<TComponent = "p">(props: BodyTextProps<TComponent>) {
|
||||
size={size}
|
||||
>
|
||||
{stringId ? (
|
||||
<FormattedMessage id={stringId} defaultMessage={children.toString()} />
|
||||
<FormattedMessage
|
||||
id={stringId}
|
||||
defaultMessage={children ? children.toString() : ""}
|
||||
/>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
@ -59,7 +62,10 @@ export function InfoText<TComponent = "p">(props: TextProps<TComponent>) {
|
||||
return (
|
||||
<MText {...rest} className={cx(className, classes.info)}>
|
||||
{stringId ? (
|
||||
<FormattedMessage id={stringId} defaultMessage={children.toString()} />
|
||||
<FormattedMessage
|
||||
id={stringId}
|
||||
defaultMessage={children ? children.toString() : ""}
|
||||
/>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
@ -74,7 +80,10 @@ export function LabelText(props: TextProps<"label">) {
|
||||
return (
|
||||
<MText component="label" {...rest} className={cx(className, classes.label)}>
|
||||
{stringId ? (
|
||||
<FormattedMessage id={stringId} defaultMessage={children.toString()} />
|
||||
<FormattedMessage
|
||||
id={stringId}
|
||||
defaultMessage={children ? children.toString() : ""}
|
||||
/>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
|
@ -14,13 +14,45 @@
|
||||
// limitations under the License.
|
||||
// =============================================================================
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { render } from "@testing-library/react";
|
||||
import { beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { render, waitForElementToBeRemoved } from "@testing-library/react";
|
||||
import { AppProviders } from "@atoms/AppProviders";
|
||||
import { WalletBalance } from ".";
|
||||
|
||||
describe("molecules::WalletBalance", () => {
|
||||
it("renders without exploding", () => {
|
||||
beforeAll(() => {
|
||||
vi.mock("@hooks/haveno/useHavenoClient", () => ({
|
||||
useHavenoClient: () => ({
|
||||
getBalances: async () => {
|
||||
return {
|
||||
getLockedBalance: () => 12,
|
||||
getReservedTradeBalance: () => 14,
|
||||
getBalance: () => 15,
|
||||
};
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@hooks/storage/useAccountInfo", () => ({
|
||||
useAccountInfo: () => ({
|
||||
isLoading: false,
|
||||
isSuccess: true,
|
||||
data: {
|
||||
primaryFiat: "USD",
|
||||
},
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("@hooks/haveno/usePrice", () => ({
|
||||
usePrice: () => ({
|
||||
isLoading: false,
|
||||
isSuccess: true,
|
||||
data: 300,
|
||||
}),
|
||||
}));
|
||||
});
|
||||
|
||||
it("renders loading state", () => {
|
||||
const { asFragment } = render(
|
||||
<AppProviders>
|
||||
<WalletBalance />
|
||||
@ -28,4 +60,16 @@ describe("molecules::WalletBalance", () => {
|
||||
);
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders after loading data", async () => {
|
||||
const { asFragment, queryByText } = render(
|
||||
<AppProviders>
|
||||
<WalletBalance />
|
||||
</AppProviders>
|
||||
);
|
||||
if (queryByText("Loading...")) {
|
||||
await waitForElementToBeRemoved(() => queryByText("Loading..."));
|
||||
}
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -26,19 +26,37 @@ import {
|
||||
import { ReactComponent as XMRLogo } from "@assets/xmr-logo-1.svg";
|
||||
import { ReactComponent as ArrowDown } from "@assets/arrow-down.svg";
|
||||
import { useBalances } from "@hooks/haveno/useBalances";
|
||||
import { useAccountInfo } from "@hooks/storage/useAccountInfo";
|
||||
import { usePrice } from "@hooks/haveno/usePrice";
|
||||
import { Currency } from "@atoms/Currency";
|
||||
import { BodyText } from "@atoms/Typography";
|
||||
|
||||
export function WalletBalance() {
|
||||
const [isOpen, setOpen] = useState(false);
|
||||
const { classes } = useStyles({ isOpen });
|
||||
const { data: availableBalances } = useBalances();
|
||||
const Total = useMemo(() => {
|
||||
const { data: availableBalances, isLoading: isLoadingBalance } =
|
||||
useBalances();
|
||||
const { data: accountInfo, isLoading: isLoadingAccountInfo } =
|
||||
useAccountInfo();
|
||||
const { data: price } = usePrice(accountInfo?.primaryFiat);
|
||||
|
||||
const totalBalance = useMemo(() => {
|
||||
return (
|
||||
Number(availableBalances?.getLockedBalance() || 0) +
|
||||
Number(availableBalances?.getReservedTradeBalance() || 0)
|
||||
).toString();
|
||||
);
|
||||
}, [availableBalances]);
|
||||
|
||||
const fiatBalance = useMemo(() => {
|
||||
if (!totalBalance || !price || !accountInfo?.primaryFiat) {
|
||||
return 0;
|
||||
}
|
||||
return totalBalance * price;
|
||||
}, [totalBalance, price, accountInfo]);
|
||||
|
||||
return (
|
||||
<UnstyledButton
|
||||
aria-label="Show Balance"
|
||||
className={classes.btnToggle}
|
||||
onClick={() => setOpen(!isOpen)}
|
||||
>
|
||||
@ -49,35 +67,60 @@ export function WalletBalance() {
|
||||
Available Balance
|
||||
</Text>
|
||||
</Group>
|
||||
<Stack spacing={4}>
|
||||
<Group>
|
||||
<Text className={classes.xmr}>
|
||||
{availableBalances?.getBalance() ?? 0}
|
||||
</Text>
|
||||
<ArrowDown className={classes.toggleIcon} />
|
||||
</Group>
|
||||
<Text className={classes.fiat}>(EUR 2441,02)</Text>
|
||||
</Stack>
|
||||
<Collapse in={isOpen}>
|
||||
{isLoadingAccountInfo || isLoadingBalance ? (
|
||||
<Stack>
|
||||
<Stack spacing={4}>
|
||||
<Text className={classes.balanceLabel}>Total</Text>
|
||||
<Text className={classes.balanceValue}>{Total}</Text>
|
||||
</Stack>
|
||||
<Stack spacing={4}>
|
||||
<Text className={classes.balanceLabel}>Reserved</Text>
|
||||
<Text className={classes.balanceValue}>
|
||||
{availableBalances?.getReservedTradeBalance() ?? 0}
|
||||
</Text>
|
||||
</Stack>
|
||||
<Stack spacing={4}>
|
||||
<Text className={classes.balanceLabel}>Locked</Text>
|
||||
<Text className={classes.balanceValue}>
|
||||
{availableBalances?.getLockedBalance() ?? 0}
|
||||
</Text>
|
||||
</Stack>
|
||||
<BodyText size="xs">Loading...</BodyText>
|
||||
</Stack>
|
||||
</Collapse>
|
||||
) : (
|
||||
<>
|
||||
<Stack spacing={4}>
|
||||
<Group>
|
||||
<Text className={classes.xmr}>
|
||||
<Currency
|
||||
value={Number(availableBalances?.getBalance() ?? 0)}
|
||||
/>
|
||||
</Text>
|
||||
<ArrowDown className={classes.toggleIcon} />
|
||||
</Group>
|
||||
<Text className={classes.fiat}>
|
||||
(
|
||||
<Currency
|
||||
currencyCode={accountInfo?.primaryFiat}
|
||||
value={fiatBalance}
|
||||
/>
|
||||
)
|
||||
</Text>
|
||||
</Stack>
|
||||
<Collapse in={isOpen}>
|
||||
<Stack>
|
||||
<Stack spacing={4}>
|
||||
<Text className={classes.balanceLabel}>Total</Text>
|
||||
<Text className={classes.balanceValue}>
|
||||
<Currency value={totalBalance} />
|
||||
</Text>
|
||||
</Stack>
|
||||
<Stack spacing={4}>
|
||||
<Text className={classes.balanceLabel}>Reserved</Text>
|
||||
<Text className={classes.balanceValue}>
|
||||
<Currency
|
||||
value={Number(
|
||||
availableBalances?.getReservedTradeBalance() ?? 0
|
||||
)}
|
||||
/>
|
||||
</Text>
|
||||
</Stack>
|
||||
<Stack spacing={4}>
|
||||
<Text className={classes.balanceLabel}>Locked</Text>
|
||||
<Text className={classes.balanceValue}>
|
||||
<Currency
|
||||
value={Number(availableBalances?.getLockedBalance() ?? 0)}
|
||||
/>
|
||||
</Text>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Collapse>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</UnstyledButton>
|
||||
);
|
||||
|
@ -1,8 +1,9 @@
|
||||
// Vitest Snapshot v1
|
||||
|
||||
exports[`molecules::WalletBalance > renders without exploding 1`] = `
|
||||
exports[`molecules::WalletBalance > renders after loading data 1`] = `
|
||||
<DocumentFragment>
|
||||
<button
|
||||
aria-label="Show Balance"
|
||||
class="mantine-UnstyledButton-root mantine-3om9so"
|
||||
type="button"
|
||||
>
|
||||
@ -59,7 +60,7 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
|
||||
<div
|
||||
class="mantine-Text-root mantine-Group-child mantine-q5labh"
|
||||
>
|
||||
0
|
||||
15.00
|
||||
</div>
|
||||
<svg
|
||||
class="mantine-Group-child mantine-qg5oag"
|
||||
@ -80,7 +81,7 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
|
||||
<div
|
||||
class="mantine-Text-root mantine-1pfxwhx"
|
||||
>
|
||||
(EUR 2441,02)
|
||||
(USD 7,800.00)
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -105,7 +106,7 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
|
||||
<div
|
||||
class="mantine-Text-root mantine-14d5cdm"
|
||||
>
|
||||
0
|
||||
26.00
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -119,7 +120,7 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
|
||||
<div
|
||||
class="mantine-Text-root mantine-14d5cdm"
|
||||
>
|
||||
0
|
||||
14.00
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@ -133,7 +134,7 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
|
||||
<div
|
||||
class="mantine-Text-root mantine-14d5cdm"
|
||||
>
|
||||
0
|
||||
12.00
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -143,3 +144,68 @@ exports[`molecules::WalletBalance > renders without exploding 1`] = `
|
||||
</button>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
||||
exports[`molecules::WalletBalance > renders loading state 1`] = `
|
||||
<DocumentFragment>
|
||||
<button
|
||||
aria-label="Show Balance"
|
||||
class="mantine-UnstyledButton-root mantine-3om9so"
|
||||
type="button"
|
||||
>
|
||||
<div
|
||||
class="mantine-Stack-root mantine-lfk3cq"
|
||||
>
|
||||
<div
|
||||
class="mantine-Group-root mantine-1lumg83"
|
||||
>
|
||||
<svg
|
||||
class="mantine-Group-child mantine-oilh7i"
|
||||
fill="none"
|
||||
height="1em"
|
||||
viewBox="0 0 20 20"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g
|
||||
clip-path="url(#clip0_3508_17165)"
|
||||
>
|
||||
<path
|
||||
d="M10.0026 0C4.4815 0 -0.00311409 4.48323 0.0039145 9.9987C0.00529892 11.1022 0.18128 12.1636 0.51157 13.1565H3.5034V4.74512L10.0026 11.2436L16.5015 4.74512V13.1567H19.494C19.8247 12.1639 19.9998 11.1024 20.0018 9.99885C20.0112 4.47764 15.5243 0.00133103 10.0026 0.00133103V0Z"
|
||||
fill="#111111"
|
||||
/>
|
||||
<path
|
||||
d="M8.50535 12.7375L5.66905 9.90137V15.1943H3.50057L1.45435 15.1946C3.20952 18.0739 6.38154 20 9.99999 20C13.6184 20 16.7906 18.0735 18.5461 15.1942H14.3303V9.90137L11.4938 12.7375L9.99967 14.2315L8.50545 12.7375H8.50535Z"
|
||||
fill="#111111"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clippath
|
||||
id="clip0_3508_17165"
|
||||
>
|
||||
<rect
|
||||
fill="white"
|
||||
height="20"
|
||||
width="20"
|
||||
/>
|
||||
</clippath>
|
||||
</defs>
|
||||
</svg>
|
||||
<div
|
||||
class="mantine-Text-root mantine-Group-child mantine-1iw7oli"
|
||||
>
|
||||
Available Balance
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mantine-Stack-root mantine-lfk3cq"
|
||||
>
|
||||
<div
|
||||
class="mantine-Text-root mantine-1152338"
|
||||
>
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</DocumentFragment>
|
||||
`;
|
||||
|
@ -202,6 +202,7 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
|
||||
class="mantine-865t33"
|
||||
>
|
||||
<button
|
||||
aria-label="Show Balance"
|
||||
class="mantine-UnstyledButton-root mantine-3om9so"
|
||||
type="button"
|
||||
>
|
||||
@ -250,92 +251,12 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mantine-Stack-root mantine-1kb6t4k"
|
||||
class="mantine-Stack-root mantine-lfk3cq"
|
||||
>
|
||||
<div
|
||||
class="mantine-Group-root mantine-6y1794"
|
||||
class="mantine-Text-root mantine-1152338"
|
||||
>
|
||||
<div
|
||||
class="mantine-Text-root mantine-Group-child mantine-q5labh"
|
||||
>
|
||||
0
|
||||
</div>
|
||||
<svg
|
||||
class="mantine-Group-child mantine-qg5oag"
|
||||
fill="none"
|
||||
height="1em"
|
||||
viewBox="0 0 7 4"
|
||||
width="1em"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
clip-rule="evenodd"
|
||||
d="M2.91916 3.69319C3.23963 4.04927 3.76166 4.04657 4.07971 3.69319L6.82329 0.644746C7.14377 0.288661 7.01636 0 6.53811 0H0.460749C-0.0172283 0 -0.14248 0.291357 0.17557 0.644746L2.91916 3.69319Z"
|
||||
fill="#111111"
|
||||
fill-rule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="mantine-Text-root mantine-1pfxwhx"
|
||||
>
|
||||
(EUR 2441,02)
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="mantine-1avyp1d"
|
||||
style="box-sizing: border-box; display: none; height: 0px; overflow: hidden;"
|
||||
>
|
||||
<div
|
||||
style="opacity: 0; transition: opacity 200ms ease;"
|
||||
>
|
||||
<div
|
||||
class="mantine-Stack-root mantine-lfk3cq"
|
||||
>
|
||||
<div
|
||||
class="mantine-Stack-root mantine-1kb6t4k"
|
||||
>
|
||||
<div
|
||||
class="mantine-Text-root mantine-kaqdcf"
|
||||
>
|
||||
Total
|
||||
</div>
|
||||
<div
|
||||
class="mantine-Text-root mantine-14d5cdm"
|
||||
>
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mantine-Stack-root mantine-1kb6t4k"
|
||||
>
|
||||
<div
|
||||
class="mantine-Text-root mantine-kaqdcf"
|
||||
>
|
||||
Reserved
|
||||
</div>
|
||||
<div
|
||||
class="mantine-Text-root mantine-14d5cdm"
|
||||
>
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mantine-Stack-root mantine-1kb6t4k"
|
||||
>
|
||||
<div
|
||||
class="mantine-Text-root mantine-kaqdcf"
|
||||
>
|
||||
Locked
|
||||
</div>
|
||||
<div
|
||||
class="mantine-Text-root mantine-14d5cdm"
|
||||
>
|
||||
0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -19,6 +19,8 @@ import { ReactComponent as EthLogo } from "@assets/eth.svg";
|
||||
import { ReactComponent as EurLogo } from "@assets/eur.svg";
|
||||
import { PaymentMethodIds } from "./payment-methods";
|
||||
|
||||
export type SupportedFiat = "USD" | "ETH" | "GBP";
|
||||
|
||||
export const SupportedCurrencies = [
|
||||
{
|
||||
id: "BTC",
|
||||
|
@ -15,17 +15,21 @@
|
||||
// =============================================================================
|
||||
|
||||
export enum QueryKeys {
|
||||
HavenoVersion = "Haveno.Version",
|
||||
// Haveno
|
||||
Balances = "Haveno.Balances",
|
||||
PaymentAccounts = "Haveno.PaymentAccounts",
|
||||
MoneroNodeSettings = "Haveno.MoneroNodeSettings",
|
||||
HavenoVersion = "Haveno.Version",
|
||||
MoneroNodeIsRunning = "Haveno.MoneroNodeIsRunning",
|
||||
MoneroNodeSettings = "Haveno.MoneroNodeSettings",
|
||||
MoneroRemoteNodes = "Haveno.MoneroRemoteNodes",
|
||||
|
||||
PaymentAccounts = "Haveno.PaymentAccounts",
|
||||
Prices = "Haveno.Prices",
|
||||
PrimaryAddress = "Haveno.PrimaryAddress",
|
||||
SyncStatus = "Haveno.SyncStatus",
|
||||
|
||||
// Storage
|
||||
StorageAccountInfo = "Storage.AccountInfo",
|
||||
StoragePreferences = "Storage.Preferences",
|
||||
|
||||
// Others
|
||||
AuthSession = "AuthSession",
|
||||
}
|
||||
|
26
packages/renderer/src/hooks/haveno/useAddress.ts
Normal file
26
packages/renderer/src/hooks/haveno/useAddress.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 { QueryKeys } from "@constants/query-keys";
|
||||
import { useQuery } from "react-query";
|
||||
import { useHavenoClient } from "./useHavenoClient";
|
||||
|
||||
export function useAddress() {
|
||||
const client = useHavenoClient();
|
||||
return useQuery(QueryKeys.PrimaryAddress, async () =>
|
||||
client.getXmrPrimaryAddress()
|
||||
);
|
||||
}
|
@ -15,12 +15,13 @@
|
||||
// =============================================================================
|
||||
|
||||
import { useQuery } from "react-query";
|
||||
import type { XmrBalanceInfo } from "haveno-ts";
|
||||
import { QueryKeys } from "@constants/query-keys";
|
||||
import { useHavenoClient } from "./useHavenoClient";
|
||||
|
||||
export function useBalances() {
|
||||
const client = useHavenoClient();
|
||||
return useQuery(QueryKeys.Balances, async () => {
|
||||
return client.getBalances();
|
||||
});
|
||||
return useQuery<XmrBalanceInfo, Error>(QueryKeys.Balances, async () =>
|
||||
client.getBalances()
|
||||
);
|
||||
}
|
||||
|
@ -20,7 +20,5 @@ import { useHavenoClient } from "./useHavenoClient";
|
||||
|
||||
export function useHavenoVersion() {
|
||||
const client = useHavenoClient();
|
||||
return useQuery(QueryKeys.HavenoVersion, async () => {
|
||||
return client.getVersion();
|
||||
});
|
||||
return useQuery(QueryKeys.HavenoVersion, async () => client.getVersion());
|
||||
}
|
||||
|
37
packages/renderer/src/hooks/haveno/usePaymentMethods.txt
Normal file
37
packages/renderer/src/hooks/haveno/usePaymentMethods.txt
Normal file
@ -0,0 +1,37 @@
|
||||
// =============================================================================
|
||||
// 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";
|
||||
import { useHavenoClient } from "./useHavenoClient";
|
||||
|
||||
export function usePaymentMethods() {
|
||||
const client = useHavenoClient();
|
||||
return useQuery(QueryKeys.PaymentMethods, async () => {
|
||||
// TODO: replace with getSupportedAssets(): TradeCurrency[]
|
||||
// const mns = await client.getMoneroNodeSettings();
|
||||
const mns = await client._moneroNodeClient.getMoneroNodeSettings({}, {});
|
||||
console.log("monero node settings: ", mns?.toObject());
|
||||
if (mns) {
|
||||
const mns2 = mns.setStartupFlagsList(["foo1"]);
|
||||
mns;
|
||||
}
|
||||
const assetCodes = await client.getSupportedAssetCodes();
|
||||
return await Promise.all(
|
||||
assetCodes.map((assetCode) => client.getPaymentMethods(assetCode))
|
||||
);
|
||||
});
|
||||
}
|
46
packages/renderer/src/hooks/haveno/usePrice.ts
Normal file
46
packages/renderer/src/hooks/haveno/usePrice.ts
Normal file
@ -0,0 +1,46 @@
|
||||
// =============================================================================
|
||||
// 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 { useEffect, useState } from "react";
|
||||
import { usePrices } from "./usePrices";
|
||||
|
||||
export function usePrice(currencyCode?: string) {
|
||||
const [data, setData] = useState(0);
|
||||
const [error, setError] = useState("");
|
||||
|
||||
const { data: prices, isLoading, isSuccess, error: _error } = usePrices();
|
||||
|
||||
useEffect(() => {
|
||||
if (!currencyCode) {
|
||||
return;
|
||||
}
|
||||
if (!isSuccess) {
|
||||
setError(_error?.message ?? "Something went wrong");
|
||||
return;
|
||||
}
|
||||
const price = (prices ?? []).find(
|
||||
(price) => price.currencyCode === currencyCode
|
||||
);
|
||||
if (!price) {
|
||||
setError("Unknown currency code");
|
||||
return;
|
||||
}
|
||||
setData(price.price);
|
||||
setError("");
|
||||
}, []);
|
||||
|
||||
return { data, isLoading, isSuccess, error, isError: Boolean(error) };
|
||||
}
|
31
packages/renderer/src/hooks/haveno/usePrices.ts
Normal file
31
packages/renderer/src/hooks/haveno/usePrices.ts
Normal file
@ -0,0 +1,31 @@
|
||||
// =============================================================================
|
||||
// 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 { MarketPriceInfo } from "haveno-ts";
|
||||
import { QueryKeys } from "@constants/query-keys";
|
||||
import { useQuery } from "react-query";
|
||||
import { useHavenoClient } from "./useHavenoClient";
|
||||
|
||||
export function usePrices() {
|
||||
const client = useHavenoClient();
|
||||
return useQuery<Array<MarketPriceInfo.AsObject>, Error>(
|
||||
QueryKeys.Prices,
|
||||
async () => {
|
||||
const prices = await client.getPrices();
|
||||
return prices.map((price) => price.toObject());
|
||||
}
|
||||
);
|
||||
}
|
@ -21,7 +21,6 @@ import { AccountLayout } from "@templates/AccountLayout";
|
||||
|
||||
export function AccountPaymentAccounts() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<AccountLayout>
|
||||
<PaymentMethodList
|
||||
|
@ -21,7 +21,7 @@ import { LangKeys } from "@constants/lang/LangKeys";
|
||||
import { CenteredLayout } from "@templates/CenteredLayout";
|
||||
import { Heading } from "@atoms/Typography";
|
||||
import Logo from "@assets/logo.svg";
|
||||
import { useAccountInfo } from "@src/hooks/storage/useGetAccountInfo";
|
||||
import { useAccountInfo } from "@hooks/storage/useAccountInfo";
|
||||
import { ROUTES } from "@constants/routes";
|
||||
import { showNotification } from "@mantine/notifications";
|
||||
|
||||
|
32
packages/renderer/vitest.coverage.config.js
Normal file
32
packages/renderer/vitest.coverage.config.js
Normal file
@ -0,0 +1,32 @@
|
||||
// =============================================================================
|
||||
// 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.
|
||||
// =============================================================================
|
||||
|
||||
/**
|
||||
* Config for global end-to-end tests
|
||||
* placed in project root tests folder
|
||||
* @type {import('vite').UserConfig}
|
||||
* @see https://vitest.dev/config/
|
||||
*/
|
||||
const config = {
|
||||
test: {
|
||||
include: ["./src/**/*.{test,spec}.{ts,tsx}"],
|
||||
coverage: {
|
||||
reporter: ["html"],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
@ -33,7 +33,6 @@ const config = {
|
||||
*/
|
||||
testTimeout: 30_000,
|
||||
hookTimeout: 30_000,
|
||||
deps: { inline: ["haveno-ts"] },
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -7973,10 +7973,10 @@ hastscript@^6.0.0:
|
||||
property-information "^5.0.0"
|
||||
space-separated-tokens "^1.0.0"
|
||||
|
||||
haveno-ts@0.0.4:
|
||||
version "0.0.4"
|
||||
resolved "https://registry.yarnpkg.com/haveno-ts/-/haveno-ts-0.0.4.tgz#4d9fac6601887f384e5b380471988ee3e8b17783"
|
||||
integrity sha512-8Yf1kyeuBCbfOr7T0uy87XcnNk8pfwS6uN4iuXgkAKLySByGl8Mxay7C0Fq1qPExz4hPJsJ8ql2qbaU1HJkbkg==
|
||||
haveno-ts@0.0.5:
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/haveno-ts/-/haveno-ts-0.0.5.tgz#996e290b4dd1659e58f86aff4e0cc0d3c7516ad3"
|
||||
integrity sha512-HzBuvMmsQLUybk99NqOe50lAcYmnwv2uv0/5IMAIuUpqFmJq2xvPW6vvZASXkRBVYPdRYjLLnUV5ygy8Rq7Yog==
|
||||
dependencies:
|
||||
"@types/node" "^17.0.30"
|
||||
console "^0.7.2"
|
||||
|
Loading…
Reference in New Issue
Block a user