Skip to content

Commit c276755

Browse files
authored
Merge pull request #10034 from LedgerHQ/feat/select-network-component
feat(LLD): select network component
2 parents c15054c + c608146 commit c276755

File tree

8 files changed

+205
-3
lines changed

8 files changed

+205
-3
lines changed

.changeset/eight-parrots-leave.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"ledger-live-desktop": minor
3+
"@ledgerhq/react-ui": minor
4+
---
5+
6+
Add network selection components

apps/ledger-live-desktop/src/newArch/features/ModularDrawer/components/SelectAssetFlow.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { CryptoOrTokenCurrency, Currency } from "@ledgerhq/types-cryptoassets";
66
import Fuse from "fuse.js";
77
import { useCurrenciesByMarketcap } from "@ledgerhq/live-common/currencies/hooks";
88
import Text from "~/renderer/components/Text";
9-
import { CurrencyList } from "~/renderer/drawers/DataSelector/CurrencyList";
9+
import { SelectNetwork } from "./SelectNetwork";
1010
import { listAndFilterCurrencies } from "@ledgerhq/live-common/platform/helpers";
1111
import { getEnv } from "@ledgerhq/live-env";
1212

@@ -81,8 +81,13 @@ function SelectAssetFlow(props: SelectAccountAndCurrencyDrawerProps) {
8181
onChange={setSearchValue}
8282
/>
8383
</SearchInputContainer>
84-
{/* @ts-expect-error compatibility issue betwenn CryptoOrTokenCurrency and Currency (which includes Fiat) and the SelectAccountDrawer components */}
85-
<CurrencyList currencies={filteredCurrencies} onCurrencySelect={handleCurrencySelected} />
84+
<SelectNetwork
85+
// @ts-expect-error compatibility issue between CryptoOrTokenCurrency and Currency (which includes Fiat) and the SelectAccountDrawer components
86+
networks={filteredCurrencies}
87+
onNetworkSelected={handleCurrencySelected}
88+
flow="Modular Asset Flow"
89+
source="Accounts"
90+
/>
8691
</SelectorContent>
8792
</SelectAccountAndCurrencyDrawerContainer>
8893
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from "react";
2+
import { CryptoOrTokenCurrency } from "@ledgerhq/types-cryptoassets";
3+
import { NetworkList } from "@ledgerhq/react-ui/pre-ldls";
4+
import { track } from "~/renderer/analytics/segment";
5+
import TrackPage from "~/renderer/analytics/TrackPage";
6+
7+
type SelectNetworkProps = {
8+
networks: CryptoOrTokenCurrency[];
9+
onNetworkSelected: (network: CryptoOrTokenCurrency) => void;
10+
source: string;
11+
flow: string;
12+
};
13+
14+
export const SelectNetwork = ({
15+
networks,
16+
onNetworkSelected,
17+
source,
18+
flow,
19+
}: SelectNetworkProps) => {
20+
const onClick = (networkId: string) => {
21+
track("network_clicked", { network: networkId, page: "Modular Asset Flow", flow });
22+
23+
const network = networks.find(({ id }) => id === networkId);
24+
if (!network) return;
25+
26+
onNetworkSelected(network);
27+
};
28+
29+
return (
30+
<>
31+
<TrackPage category={source} name="Modular Network Selection" flow={flow} />
32+
<div style={{ flex: "1 1 auto", width: "100%" }}>
33+
<NetworkList networks={networks} onClick={onClick} />
34+
</div>
35+
</>
36+
);
37+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { Meta, StoryObj } from "@storybook/react";
2+
import { NetworkItem } from "./NetworkItem";
3+
import { expect, within } from "@storybook/test";
4+
5+
const meta: Meta<typeof NetworkItem> = {
6+
component: NetworkItem,
7+
title: "PreLdls/Components/NetworkItem",
8+
tags: ["autodocs"],
9+
args: { name: "Bitcoin" },
10+
};
11+
export default meta;
12+
13+
type Story = StoryObj<typeof NetworkItem>;
14+
15+
export const Default: Story = {};
16+
17+
export const TestNetworkItem: Story = {
18+
play: async ({ canvasElement }) => {
19+
const canvas = within(canvasElement);
20+
21+
const name = canvas.getByText("Bitcoin");
22+
23+
await expect(name).toBeInTheDocument();
24+
},
25+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import React from "react";
2+
import styled from "styled-components";
3+
import { withTokens } from "../../libs";
4+
import { Text } from "../../../components";
5+
6+
type NetworkItemProps = {
7+
name: string;
8+
onClick: () => void;
9+
};
10+
11+
const TempAssetBadge = () => (
12+
// TODO: To be replaced with LIVE-18221
13+
<div style={{ display: "flex", alignItems: "center" }}>
14+
<span
15+
style={{
16+
height: 48,
17+
width: 48,
18+
borderRadius: 48,
19+
backgroundColor: "grey",
20+
display: "inline-block",
21+
}}
22+
/>
23+
</div>
24+
);
25+
26+
const Wrapper = styled.div`
27+
${withTokens(
28+
"spacing-xs",
29+
"marging-s",
30+
"colors-content-default-default",
31+
"colors-surface-transparent-hover",
32+
"colors-surface-transparent-pressed",
33+
)}
34+
display: flex;
35+
padding: var(--spacing-xs);
36+
cursor: pointer;
37+
38+
:hover {
39+
background-color: var(--colors-surface-transparent-hover);
40+
}
41+
42+
:active {
43+
background-color: var(--colors-surface-transparent-pressed);
44+
}
45+
`;
46+
47+
const InfoWrapper = styled.div`
48+
display: flex;
49+
flex-direction: column;
50+
justify-content: center;
51+
margin-left: var(--marging-s);
52+
`;
53+
54+
export const NetworkItem = ({ name, onClick }: NetworkItemProps) => {
55+
return (
56+
<Wrapper onClick={onClick}>
57+
<TempAssetBadge />
58+
<InfoWrapper>
59+
<Text
60+
variant="largeLineHeight"
61+
fontWeight="semiBold"
62+
color="var(--colors-content-default-default)"
63+
>
64+
{name}
65+
</Text>
66+
</InfoWrapper>
67+
</Wrapper>
68+
);
69+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from "react";
2+
import type { Meta, StoryObj } from "@storybook/react";
3+
import { NetworkList } from "./NetworkList";
4+
import { expect, fn, userEvent, within } from "@storybook/test";
5+
6+
const testFn = fn();
7+
8+
const meta: Meta<typeof NetworkList> = {
9+
component: NetworkList,
10+
decorators: [
11+
Story => (
12+
<div style={{ height: "400px" }}>
13+
<Story />
14+
</div>
15+
),
16+
],
17+
title: "PreLdls/Components/NetworkList",
18+
tags: ["autodocs"],
19+
args: {
20+
networks: Array.from({ length: 50 }, (_, i) => ({ name: `Bitcoin ${i}`, id: `btc${i}` })),
21+
onClick: testFn,
22+
},
23+
};
24+
export default meta;
25+
26+
type Story = StoryObj<typeof NetworkList>;
27+
28+
export const Default: Story = {};
29+
30+
export const TestNetworkClick: Story = {
31+
play: async ({ canvasElement }) => {
32+
const canvas = within(canvasElement);
33+
const input = canvas.getByText("Bitcoin 1");
34+
await userEvent.click(input);
35+
await expect(testFn).toHaveBeenCalledWith("btc1");
36+
},
37+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
import { NetworkItem } from "../NetworkItem/NetworkItem";
3+
import { VirtualList } from "../VirtualList/VirtualList";
4+
5+
export const NetworkList = ({
6+
networks,
7+
onClick,
8+
}: {
9+
networks: { name: string; id: string }[];
10+
onClick: (networkId: string) => void;
11+
}) => {
12+
return (
13+
<VirtualList
14+
itemHeight={64}
15+
count={networks.length}
16+
renderItem={(i: number) => (
17+
<NetworkItem name={networks[i].name} onClick={() => onClick(networks[i].id)} />
18+
)}
19+
/>
20+
);
21+
};
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
export * from "./AssetItem/AssetItem";
22
export * from "./AssetList/AssetList";
33
export * from "./Input/Input";
4+
export * from "./NetworkItem/NetworkItem";
5+
export * from "./NetworkList/NetworkList";
46
export * from "./Search/Search";
57
export * from "./VirtualList/VirtualList";

0 commit comments

Comments
 (0)