Skip to content

Commit

Permalink
✨(lld): add discovery drawer for ordis (#7876)
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasWerey authored Sep 23, 2024
1 parent 2742dda commit c95ac37
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/neat-items-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ledger-live-desktop": patch
---

Add discovery drawer when arriving on BTC account
1 change: 1 addition & 0 deletions apps/ledger-live-desktop/src/config/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ export const urls = {
},
howToUpdateNewLedger: "https://support.ledger.com/article/9305992683165-zd",
genuineCheck: "https://support.ledger.com/article/4404389367057-zd",
whatAreOrdinals: "https://www.ledger.com/academy/bitcoin-ordinals",
};

export const vaultSigner = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from "react";
import { Flex, CryptoIcon } from "@ledgerhq/react-ui";

const DiscoveryDrawerHeader: React.FC = () => (
<Flex
borderRadius="100%"
justifyContent="center"
style={{
height: 400,
width: 400,
position: "absolute",
top: 0,
left: "50%",
transform: "translateX(-50%) translateY(-50%)",
filter: "blur(120px)",
}}
>
<CryptoIcon name="BTC" circleIcon size={300} />
</Flex>
);

export default DiscoveryDrawerHeader;
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React from "react";
import DiscoveryDrawerHeader from "./Header";
import { Button, CryptoIcon, Flex, Link, Text } from "@ledgerhq/react-ui";
import { SideDrawer } from "~/renderer/components/SideDrawer";
import { Direction } from "@ledgerhq/react-ui/components/layout/Drawer/index";
import { space } from "@ledgerhq/react-ui/styles/theme";
import { urls } from "~/config/urls";
import { openURL } from "~/renderer/linking";
import { useTranslation } from "react-i18next";

type Props = {
isOpen: boolean;
onClose: () => void;
};

const DiscoveryDrawer = ({ isOpen, onClose }: Props) => {
const { t } = useTranslation();
const learnMoreUrl = urls.whatAreOrdinals;
const onButtonClick = () => openURL(learnMoreUrl);
const onLinkClick = () => onClose();

return (
<SideDrawer
isOpen={isOpen}
withPaddingTop={false}
onRequestClose={onClose}
direction={Direction.Left}
forceDisableFocusTrap
>
<DiscoveryDrawerHeader />
<Flex
px={40}
mx={33}
height="100%"
justifyContent="center"
alignItems="center"
flexDirection="column"
>
<Flex p={18} bg="rgba(247, 147, 26, 0.05)" borderRadius="100%">
<CryptoIcon name="BTC" circleIcon size={36} />
</Flex>
<Text variant="h4Inter" textAlign="center" my={space[6]} fontSize="24px">
{t("ordinals.inscriptions.discoveryDrawer.title")}
</Text>
<Text
variant="bodyLineHeight"
color="neutral.c70"
fontSize="14px"
textAlign="center"
mb={space[8]}
>
{t("ordinals.inscriptions.discoveryDrawer.description")}
</Text>
<Button variant="main" mb={space[8]} onClick={onButtonClick}>
<Text variant="bodyLineHeight" fontSize={16} color="neutral.c00" textAlign="center">
{t("ordinals.inscriptions.discoveryDrawer.learnMore")}
</Text>
</Button>
<Link mb={space[8]} size="large" onClick={onLinkClick}>
{t("ordinals.inscriptions.discoveryDrawer.viewCoinControl")}
</Link>
</Flex>
</SideDrawer>
);
};

export default DiscoveryDrawer;
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
import React from "react";
import { Flex } from "@ledgerhq/react-ui";
import Inscriptions from "../../components/Inscriptions";
import RareSats from "../../components/RareSats";
import { Flex } from "@ledgerhq/react-ui";
import useFetchOrdinals from "LLD/features/Collectibles/hooks/useFetchOrdinals";
import DiscoveryDrawer from "../../components/Inscriptions/DiscoveryDrawer";
import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types";
import { useBitcoinAccountModel } from "./useBitcoinAccountModel";

type ViewProps = ReturnType<typeof useBitcoinAccountModel>;

type Props = {
interface Props {
account: BitcoinAccount;
};
}

const OrdinalsAccount: React.FC<Props> = ({ account }) => {
const { rareSats, inscriptions, ...rest } = useFetchOrdinals({
account,
});
const View: React.FC<ViewProps> = ({
inscriptions,
rest,
rareSats,
isDrawerOpen,
handleDrawerClose,
}) => (
<Flex mb={50} width="100%" flexDirection="column" rowGap={40}>
<Inscriptions inscriptions={inscriptions} {...rest} />
<RareSats rareSats={rareSats} {...rest} />
<DiscoveryDrawer isOpen={isDrawerOpen} onClose={handleDrawerClose} />
</Flex>
);

return (
<Flex mb={50} width="100%" flexDirection="column" rowGap={40}>
<Inscriptions inscriptions={inscriptions} {...rest} />
<RareSats rareSats={rareSats} {...rest} />
</Flex>
);
};
const OrdinalsAccount: React.FC<Props> = ({ account }) => (
<View {...useBitcoinAccountModel({ account })} />
);

export default OrdinalsAccount;
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types";
import useFetchOrdinals from "LLD/features/Collectibles/hooks/useFetchOrdinals";
import { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setHasSeenOrdinalsDiscoveryDrawer } from "~/renderer/actions/settings";
import { hasSeenOrdinalsDiscoveryDrawerSelector } from "~/renderer/reducers/settings";

interface Props {
account: BitcoinAccount;
}

export const useBitcoinAccountModel = ({ account }: Props) => {
const dispatch = useDispatch();
const hasSeenDiscoveryDrawer = useSelector(hasSeenOrdinalsDiscoveryDrawerSelector);

const { rareSats, inscriptions, ...rest } = useFetchOrdinals({ account });

const [isDrawerOpen, setIsDrawerOpen] = useState(!hasSeenDiscoveryDrawer);

useEffect(() => {
if (hasSeenDiscoveryDrawer) {
setIsDrawerOpen(false);
}
}, [hasSeenDiscoveryDrawer]);

const handleDrawerClose = () => {
setIsDrawerOpen(false);
dispatch(setHasSeenOrdinalsDiscoveryDrawer(true));
};

return { rareSats, inscriptions, rest, isDrawerOpen, handleDrawerClose };
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@
import React from "react";
import { render, screen, waitFor } from "tests/testUtils";
import { BitcoinPage } from "./shared";
import { openURL } from "~/renderer/linking";

jest.mock(
"electron",
() => ({ ipcRenderer: { on: jest.fn(), send: jest.fn(), invoke: jest.fn() } }),
{ virtual: true },
);

jest.mock("~/renderer/linking", () => ({
openURL: jest.fn(),
}));

describe("displayBitcoinPage", () => {
it("should display Bitcoin page with rare sats and inscriptions", async () => {
const { user } = render(<BitcoinPage />, {
initialRoute: `/`,
});
const { user } = render(<BitcoinPage />);

await waitFor(() => expect(screen.getByText(/inscription #63691311/i)).toBeVisible());
await waitFor(() => expect(screen.getByTestId(/raresaticon-palindrome-0/i)).toBeVisible());
Expand All @@ -33,4 +36,11 @@ describe("displayBitcoinPage", () => {
await user.hover(screen.getByTestId(/raresaticon-jpeg-0/i));
await waitFor(() => expect(screen.getByText(/journey into the past with jpeg/i)).toBeVisible());
});
it("should open discovery drawer when it is the first time feature is activated", async () => {
const { user } = render(<BitcoinPage />);

await waitFor(() => expect(screen.getByText(/discover ordinals/i)).toBeVisible());
await user.click(screen.getByText(/learn more/i));
expect(openURL).toHaveBeenCalledWith("https://www.ledger.com/academy/bitcoin-ordinals");
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ export const NoNftCollectionTest = withRouter(() => (
));

export const BitcoinPage = () => (
<Switch>
<Route path="/" render={() => <OrdinalsAccount account={MockedbtcAccount} />} />
</Switch>
<>
<div id="modals"></div>
<Switch>
<Route path="/" render={() => <OrdinalsAccount account={MockedbtcAccount} />} />
</Switch>
</>
);
5 changes: 5 additions & 0 deletions apps/ledger-live-desktop/src/renderer/actions/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,3 +388,8 @@ export const removeStarredMarketCoins = (payload: string) => ({
type: "MARKET_REMOVE_STARRED_COINS",
payload,
});

export const setHasSeenOrdinalsDiscoveryDrawer = (payload: boolean) => ({
type: "SET_HAS_SEEN_ORDINALS_DISCOVERY_DRAWER",
payload,
});
9 changes: 9 additions & 0 deletions apps/ledger-live-desktop/src/renderer/reducers/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export type SettingsState = {
dismissedContentCards: { [key: string]: number };
anonymousBrazeId: string | null;
starredMarketCoins: string[];
hasSeenOrdinalsDiscoveryDrawer: boolean;
};

export const getInitialLanguageAndLocale = (): { language: Language; locale: Locale } => {
Expand Down Expand Up @@ -169,6 +170,7 @@ export const INITIAL_STATE: SettingsState = {
preferredDeviceModel: DeviceModelId.nanoS,
hasInstalledApps: true,
lastSeenDevice: null,
hasSeenOrdinalsDiscoveryDrawer: false,
devicesModelList: [],
lastSeenCustomImage: {
size: 0,
Expand Down Expand Up @@ -261,6 +263,7 @@ type HandlersPayloads = {

MARKET_ADD_STARRED_COINS: string;
MARKET_REMOVE_STARRED_COINS: string;
SET_HAS_SEEN_ORDINALS_DISCOVERY_DRAWER: boolean;
};
type SettingsHandlers<PreciseKey = true> = Handlers<SettingsState, HandlersPayloads, PreciseKey>;

Expand Down Expand Up @@ -457,6 +460,10 @@ const handlers: SettingsHandlers = {
...state,
starredMarketCoins: state.starredMarketCoins.filter(id => id !== payload),
}),
SET_HAS_SEEN_ORDINALS_DISCOVERY_DRAWER: (state: SettingsState, { payload }) => ({
...state,
hasSeenOrdinalsDiscoveryDrawer: payload,
}),
};

export default handleActions<SettingsState, HandlersPayloads[keyof HandlersPayloads]>(
Expand Down Expand Up @@ -797,3 +804,5 @@ export const anonymousBrazeIdSelector = (state: State) => state.settings.anonymo
export const currenciesSettingsSelector = (state: State) => state.settings.currenciesSettings;

export const starredMarketCoinsSelector = (state: State) => state.settings.starredMarketCoins;
export const hasSeenOrdinalsDiscoveryDrawerSelector = (state: State) =>
state.settings.hasSeenOrdinalsDiscoveryDrawer;
10 changes: 9 additions & 1 deletion apps/ledger-live-desktop/static/i18n/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -6593,7 +6593,15 @@
}
},
"ordinals": {
"inscriptions": { "seeMore": "See more inscriptions" },
"inscriptions": {
"seeMore": "See more inscriptions",
"discoveryDrawer": {
"title": "Discover Ordinals",
"description": "Do you know that you may own valuable rare sats and inscriptions?",
"learnMore": "Learn more",
"viewCoinControl": "View coin control"
}
},
"rareSats": {
"title": "Rare Sats",
"table": {
Expand Down

0 comments on commit c95ac37

Please sign in to comment.