chore: Sync Status molecule

---

Reviewed-by: schowdhuri
This commit is contained in:
Subir 2022-05-11 18:53:19 +05:30 committed by GitHub
parent a0c7875391
commit 6505f47ef9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 337 additions and 44498 deletions

44472
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -84,7 +84,7 @@
"dayjs": "^1.11.0", "dayjs": "^1.11.0",
"electron-store": "^8.0.1", "electron-store": "^8.0.1",
"electron-updater": "4.6.5", "electron-updater": "4.6.5",
"haveno-ts": "0.0.2", "haveno-ts": "0.0.3",
"joi": "^17.6.0", "joi": "^17.6.0",
"jsonwebtoken": "^8.5.1", "jsonwebtoken": "^8.5.1",
"lodash": "^4.17.21", "lodash": "^4.17.21",

View 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 { Stack } from "@mantine/core";
import type { ComponentStory, ComponentMeta } from "@storybook/react";
import { SyncStatus as SyncStatusOptions } from "@constants/sync-status";
import { SyncStatus } from ".";
export default {
title: "molecules/Sync Status",
component: SyncStatus,
argTypes: {
status: {
options: SyncStatusOptions,
control: {
type: "radio",
},
},
},
} as ComponentMeta<typeof SyncStatus>;
const Template: ComponentStory<typeof SyncStatus> = (args) => {
return (
<Stack>
<SyncStatus {...args} />
</Stack>
);
};
export const Default = Template.bind({});
Default.args = {
status: SyncStatusOptions.Full,
};

View 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 { describe, expect, it } from "vitest";
import { render } from "@testing-library/react";
import { AppProviders } from "@atoms/AppProviders";
import { SyncStatus as SyncStatusOptions } from "@constants/sync-status";
import { SyncStatus } from ".";
describe("atoms::Sync Status", () => {
it("renders the not synced status by default", () => {
const { asFragment } = render(
<AppProviders>
<SyncStatus />
</AppProviders>
);
expect(asFragment()).toMatchSnapshot();
});
it("renders the fully synced status", () => {
const { asFragment } = render(
<AppProviders>
<SyncStatus status={SyncStatusOptions.Full} />
</AppProviders>
);
expect(asFragment()).toMatchSnapshot();
});
it("renders the sync in progress status", () => {
const { asFragment } = render(
<AppProviders>
<SyncStatus status={SyncStatusOptions.InProgress} />
</AppProviders>
);
expect(asFragment()).toMatchSnapshot();
});
});

View File

@ -0,0 +1,61 @@
// =============================================================================
// 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 { Box, createStyles, Group } from "@mantine/core";
import { BodyText } from "@atoms/Typography";
import { SyncStatus as SyncStatusOptions } from "@constants/sync-status";
interface SyncStatusProps {
status?: SyncStatusOptions;
}
export function SyncStatus({
status = SyncStatusOptions.NotSynced,
}: SyncStatusProps) {
const { classes } = useStyles({ syncStatus: status });
return (
<Group className={classes.container} spacing="sm">
<Box component="span" className={classes.syncDot} />
<BodyText heavy className={classes.message}>
{status}
</BodyText>
</Group>
);
}
const useStyles = createStyles<string, { syncStatus: SyncStatusOptions }>(
(theme, { syncStatus }) => ({
container: {
backgroundColor: theme.colors.gray[1],
borderRadius: "0.5rem",
padding: "0.75rem 1rem",
},
message: {},
notSynced: {},
syncDot: {
backgroundColor:
syncStatus === SyncStatusOptions.Full
? theme.colors.green[4]
: syncStatus === SyncStatusOptions.InProgress
? theme.colors.orange[4]
: theme.colors.gray[4],
borderRadius: 50,
height: "0.5rem",
width: "0.5rem",
},
})
);

View File

@ -0,0 +1,52 @@
// Vitest Snapshot v1
exports[`atoms::Sync Status > renders the fully synced status 1`] = `
<DocumentFragment>
<div
class="mantine-Group-root mantine-33bl97"
>
<span
class="mantine-Group-child mantine-16wvh2m"
/>
<div
class="mantine-Text-root mantine-Group-child mantine-1mga3um"
>
Fully Synced
</div>
</div>
</DocumentFragment>
`;
exports[`atoms::Sync Status > renders the not synced status by default 1`] = `
<DocumentFragment>
<div
class="mantine-Group-root mantine-33bl97"
>
<span
class="mantine-Group-child mantine-1mmj0t1"
/>
<div
class="mantine-Text-root mantine-Group-child mantine-1mga3um"
>
Not Synced
</div>
</div>
</DocumentFragment>
`;
exports[`atoms::Sync Status > renders the sync in progress status 1`] = `
<DocumentFragment>
<div
class="mantine-Group-root mantine-33bl97"
>
<span
class="mantine-Group-child mantine-6c6x3l"
/>
<div
class="mantine-Text-root mantine-Group-child mantine-1mga3um"
>
Syncing
</div>
</div>
</DocumentFragment>
`;

View 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 "./SyncStatus";

View File

@ -20,16 +20,6 @@ exports[`atoms::Typography > ::BodyText > renders without exploding 1`] = `
</DocumentFragment> </DocumentFragment>
`; `;
exports[`atoms::Typography > ::Heading > renders h1 1`] = `
<DocumentFragment>
<h1
class="mantine-Title-root mantine-xz2ygd"
>
heading text
</h1>
</DocumentFragment>
`;
exports[`atoms::Typography > ::Heading > renders h1 by default 1`] = ` exports[`atoms::Typography > ::Heading > renders h1 by default 1`] = `
<DocumentFragment> <DocumentFragment>
<h1 <h1

View File

@ -75,6 +75,7 @@ const useStyles = createStyles<string, { isOpen: boolean }>(
border: `solid 1px ${theme.colors.gray[4]}`, border: `solid 1px ${theme.colors.gray[4]}`,
borderRadius: theme.radius.md, borderRadius: theme.radius.md,
padding: theme.spacing.md, padding: theme.spacing.md,
width: "100%",
"&:hover": { "&:hover": {
borderColor: theme.colors.gray[5], borderColor: theme.colors.gray[5],

View File

@ -3,7 +3,7 @@
exports[`molecules::WalletBalance > renders without exploding 1`] = ` exports[`molecules::WalletBalance > renders without exploding 1`] = `
<DocumentFragment> <DocumentFragment>
<button <button
class="mantine-UnstyledButton-root mantine-3om9so" class="mantine-UnstyledButton-root mantine-qmn0rn"
type="button" type="button"
> >
<div <div

View File

@ -17,14 +17,18 @@
import { Box, createStyles, Navbar, Stack } from "@mantine/core"; import { Box, createStyles, Navbar, Stack } from "@mantine/core";
import { WalletBalance } from "@molecules/WalletBalance"; import { WalletBalance } from "@molecules/WalletBalance";
import { ReactComponent as Logo } from "@assets/logo-icon.svg"; import { ReactComponent as Logo } from "@assets/logo-icon.svg";
import { NavLink } from "./_NavLink"; import { SyncStatus } from "@atoms/SyncStatus";
import { useSyncStatus } from "@hooks/haveno/useSyncStatus";
import { NAV_LINKS, WIDTH } from "./_constants"; import { NAV_LINKS, WIDTH } from "./_constants";
import { NavLink } from "./_NavLink";
export function Sidebar() { export function Sidebar() {
const { classes } = useStyles(); const { classes } = useStyles();
const { data: syncStatus } = useSyncStatus();
return ( return (
<Stack className={classes.container}> <Stack className={classes.container} justify="space-between">
<Navbar height="100%" p={0} pl="sm" width={{ base: WIDTH }}> <Navbar className={classes.nav} width={{ base: WIDTH - 1 }}>
<Navbar.Section> <Navbar.Section>
<Box component={Logo} className={classes.logo} /> <Box component={Logo} className={classes.logo} />
</Navbar.Section> </Navbar.Section>
@ -34,21 +38,38 @@ export function Sidebar() {
</Navbar.Section> </Navbar.Section>
))} ))}
<Navbar.Section> <Navbar.Section>
<Box mt="lg"> <Box className={classes.walletBalance}>
<WalletBalance /> <WalletBalance />
</Box> </Box>
</Navbar.Section> </Navbar.Section>
</Navbar> </Navbar>
<Box className={classes.syncStatusContainer}>
<SyncStatus status={syncStatus} />
</Box>
</Stack> </Stack>
); );
} }
const useStyles = createStyles((theme) => ({ const useStyles = createStyles((theme) => ({
container: {
borderRight: `solid 1px ${theme.colors.gray[1]}`,
position: "relative",
width: WIDTH,
},
logo: { logo: {
height: "2rem", height: "2rem",
padding: `${theme.spacing.lg}px ${theme.spacing.lg}px`, padding: `${theme.spacing.lg}px ${theme.spacing.lg}px`,
}, },
container: { nav: {
width: WIDTH, border: 0,
padding: 0,
paddingLeft: theme.spacing.md,
},
syncStatusContainer: {
margin: theme.spacing.lg,
},
walletBalance: {
marginRight: theme.spacing.lg,
marginTop: theme.spacing.lg,
}, },
})); }));

View File

@ -3,10 +3,10 @@
exports[`molecules::Sidebar > renders without exploding 1`] = ` exports[`molecules::Sidebar > renders without exploding 1`] = `
<DocumentFragment> <DocumentFragment>
<div <div
class="mantine-Stack-root mantine-dczm8e" class="mantine-Stack-root mantine-zbavia"
> >
<nav <nav
class="mantine-Navbar-root mantine-pjloqa" class="mantine-Navbar-root mantine-1kodx9a"
> >
<div <div
class="mantine-khtkeg" class="mantine-khtkeg"
@ -199,10 +199,10 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
class="mantine-khtkeg" class="mantine-khtkeg"
> >
<div <div
class="mantine-b98ato" class="mantine-865t33"
> >
<button <button
class="mantine-UnstyledButton-root mantine-3om9so" class="mantine-UnstyledButton-root mantine-qmn0rn"
type="button" type="button"
> >
<div <div
@ -343,6 +343,22 @@ exports[`molecules::Sidebar > renders without exploding 1`] = `
</div> </div>
</div> </div>
</nav> </nav>
<div
class="mantine-1o6xp10"
>
<div
class="mantine-Group-root mantine-33bl97"
>
<span
class="mantine-Group-child mantine-1mmj0t1"
/>
<div
class="mantine-Text-root mantine-Group-child mantine-1mga3um"
>
Not Synced
</div>
</div>
</div>
</div> </div>
</DocumentFragment> </DocumentFragment>
`; `;

View File

@ -18,6 +18,7 @@ export enum QueryKeys {
HavenoVersion = "Haveno.Version", HavenoVersion = "Haveno.Version",
Balances = "Haveno.Balances", Balances = "Haveno.Balances",
PaymentAccounts = "Haveno.PaymentAccounts", PaymentAccounts = "Haveno.PaymentAccounts",
SyncStatus = "Haveno.SyncStatus",
StorageAccountInfo = "Storage.AccountInfo", StorageAccountInfo = "Storage.AccountInfo",
StoragePreferences = "Storage.Preferences", StoragePreferences = "Storage.Preferences",

View File

@ -0,0 +1,21 @@
// =============================================================================
// 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 enum SyncStatus {
Full = "Fully Synced",
InProgress = "Syncing",
NotSynced = "Not Synced",
}

View File

@ -0,0 +1,34 @@
// =============================================================================
// 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";
import { SyncStatus } from "@constants/sync-status";
export function useSyncStatus() {
// const client = useHavenoClient();
return useQuery(
QueryKeys.SyncStatus,
async () => {
// TODO: this is a stub
return SyncStatus.NotSynced;
},
{
staleTime: 10000,
}
);
}

View File

@ -33,6 +33,7 @@ const config = {
*/ */
testTimeout: 30_000, testTimeout: 30_000,
hookTimeout: 30_000, hookTimeout: 30_000,
deps: { inline: ["haveno-ts"] },
}, },
}; };

View File

@ -7973,10 +7973,10 @@ hastscript@^6.0.0:
property-information "^5.0.0" property-information "^5.0.0"
space-separated-tokens "^1.0.0" space-separated-tokens "^1.0.0"
haveno-ts@0.0.2: haveno-ts@0.0.3:
version "0.0.2" version "0.0.3"
resolved "https://registry.yarnpkg.com/haveno-ts/-/haveno-ts-0.0.2.tgz#a9ca033a56c1b608c5b442a5097a6727a847d1e5" resolved "https://registry.yarnpkg.com/haveno-ts/-/haveno-ts-0.0.3.tgz#610807a3d5cb5cf2eab07c3a07cf146b0875762e"
integrity sha512-sPIVmfUk0JJUOx3gWvkFLKet7YLuIHyCpOOOV0LY9yzRDBoLI1BvUGgH9ow/HGvYEFlzrm4QaqBTcqy3hpT0Ng== integrity sha512-yU6Dx22J/ynEDL9h9YunLB5el0UsmAcjqNl7YRbpHfdcKEzSrMFVihDcHIIO5gCLJY8S5dYfEWe/Mtm6XzFyzg==
dependencies: dependencies:
"@types/node" "^17.0.30" "@types/node" "^17.0.30"
console "^0.7.2" console "^0.7.2"