Skip to content

Commit b829c8c

Browse files
committed
✨(lld): add empty message and dummy drawer for ordis
1 parent be1d33b commit b829c8c

File tree

13 files changed

+180
-41
lines changed

13 files changed

+180
-41
lines changed

.changeset/empty-clouds-glow.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"ledger-live-desktop": patch
3+
---
4+
5+
Add ui for empty rare sats and inscriptions. Add error message from Error when inscriptions / rare sats can't load. Add dumy drawer for inscriptions

apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Error.tsx

+7-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,18 @@ import React from "react";
22
import { Flex, Icons, Text } from "@ledgerhq/react-ui";
33
import { useTranslation } from "react-i18next";
44

5-
const Error: React.FC = () => {
5+
type Props = {
6+
error: Error;
7+
};
8+
9+
const Error: React.FC<Props> = ({ error }) => {
610
const { t } = useTranslation();
711

812
return (
9-
<Flex justifyContent="center" my={4} columnGap={2}>
13+
<Flex my={4} ml={4} alignItems={"center"} columnGap={2}>
1014
<Icons.Warning size="S" color="error.c60" />
1115
<Text color="error.c60">{t("crash.title")}</Text>
16+
<Text fontSize={12} alignSelf={"flex-end"} color="error.c40">{`(${error?.message})`}</Text>
1217
</Flex>
1318
);
1419
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from "react";
2+
import { SideDrawer } from "~/renderer/components/SideDrawer";
3+
import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
4+
5+
type Props = {
6+
inscription: SimpleHashNft;
7+
onClose: () => void;
8+
};
9+
const InscriptionDetailsDrawer: React.FC<Props> = ({ inscription, onClose }) => {
10+
// will be replaced by DetailsDrawer from collectibles
11+
return (
12+
<SideDrawer direction={"left"} isOpen={!!inscription} onRequestClose={onClose}>
13+
{inscription.name || inscription.contract.name}
14+
</SideDrawer>
15+
);
16+
};
17+
18+
export default InscriptionDetailsDrawer;

apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/helpers.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,10 @@ function matchCorrespondingIcon(
2525
});
2626
}
2727

28-
export function getInscriptionsData(inscriptions: SimpleHashNft[]) {
28+
export function getInscriptionsData(
29+
inscriptions: SimpleHashNft[],
30+
onInscriptionClick: (inscription: SimpleHashNft) => void,
31+
) {
2932
const inscriptionsWithIcons = matchCorrespondingIcon(inscriptions);
3033
return inscriptionsWithIcons.map(item => ({
3134
tokenName: item.name || item.contract.name || "",
@@ -39,9 +42,6 @@ export function getInscriptionsData(inscriptions: SimpleHashNft[]) {
3942
contentType: item.extra_metadata?.ordinal_details?.content_type,
4043
mediaType: "image",
4144
},
42-
onClick: () => {
43-
console.log(`you clicked on : \x1b[32m${item.name}\x1b[0m inscription`);
44-
},
45-
// it does nothing for now but it will be used for the next PR with the drawer
45+
onClick: () => onInscriptionClick(item),
4646
}));
4747
}

apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/index.tsx

+42-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from "react";
2-
import { Box, Flex } from "@ledgerhq/react-ui";
2+
import { Box, Flex, Icons } from "@ledgerhq/react-ui";
33
import { useInscriptionsModel } from "./useInscriptionsModel";
44
import TableContainer from "~/renderer/components/TableContainer";
55
import TableHeader from "LLD/features/Collectibles/components/Collection/TableHeader";
@@ -9,31 +9,47 @@ import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
99
import Loader from "../Loader";
1010
import Error from "../Error";
1111
import Item from "./Item";
12+
import EmptyCollection from "LLD/features/Collectibles/components/Collection/EmptyCollection";
13+
import { CollectibleTypeEnum } from "../../../types/enum/Collectibles";
14+
import Button from "~/renderer/components/Button";
15+
import { useTranslation } from "react-i18next";
1216

13-
type ViewProps = ReturnType<typeof useInscriptionsModel> & { isLoading: boolean; isError: boolean };
17+
type ViewProps = ReturnType<typeof useInscriptionsModel> & {
18+
isLoading: boolean;
19+
isError: boolean;
20+
error: Error | null;
21+
onReceive: () => void;
22+
};
1423

1524
type Props = {
1625
inscriptions: SimpleHashNft[];
1726
isLoading: boolean;
1827
isError: boolean;
28+
error: Error | null;
29+
onReceive: () => void;
30+
onInscriptionClick: (inscription: SimpleHashNft) => void;
1931
};
2032

2133
const View: React.FC<ViewProps> = ({
2234
displayShowMore,
2335
isLoading,
2436
isError,
2537
inscriptions,
38+
error,
2639
onShowMore,
40+
onReceive,
2741
}) => {
42+
const { t } = useTranslation();
2843
const hasInscriptions = inscriptions.length > 0 && !isError;
2944
const nothingToShow = !hasInscriptions && !isLoading && !isError;
45+
const hasError = isError && error;
3046

3147
return (
3248
<Box>
3349
<TableContainer id="ordinals-inscriptions">
3450
<TableHeader titleKey={TableHeaderTitleKey.Inscriptions} />
3551
{isLoading && <Loader />}
36-
{isError && <Error />}
52+
{hasError && <Error error={error} />}
3753
{hasInscriptions &&
3854
inscriptions.map((item, index) => (
3955
<Item
@@ -48,18 +64,36 @@ const View: React.FC<ViewProps> = ({
4864
/>
4965
))}
5066
{nothingToShow && (
51-
<Flex justifyContent="center" my={4}>
52-
{"NOTHING TO SHOW WAITING FOR DESIGN"}
53-
</Flex>
67+
<EmptyCollection collectionType={CollectibleTypeEnum.Inscriptions}>
68+
<Button small primary onClick={onReceive} icon>
69+
<Flex alignItems={"center"}>
70+
<Icons.ArrowDown size="XS" />
71+
<Box>{t("ordinals.inscriptions.receive")}</Box>
72+
</Flex>
73+
</Button>
74+
</EmptyCollection>
5475
)}
5576
{displayShowMore && !isError && <ShowMore onShowMore={onShowMore} isInscriptions />}
5677
</TableContainer>
5778
</Box>
5879
);
5980
};
6081

61-
const Inscriptions: React.FC<Props> = ({ inscriptions, isLoading, isError }) => (
62-
<View isLoading={isLoading} isError={isError} {...useInscriptionsModel({ inscriptions })} />
82+
const Inscriptions: React.FC<Props> = ({
83+
inscriptions,
84+
isLoading,
85+
isError,
86+
error,
87+
onReceive,
88+
onInscriptionClick,
89+
}) => (
90+
<View
91+
isLoading={isLoading}
92+
isError={isError}
93+
error={error}
94+
onReceive={onReceive}
95+
{...useInscriptionsModel({ inscriptions, onInscriptionClick })}
96+
/>
6397
);
6498

6599
export default Inscriptions;

apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/Inscriptions/useInscriptionsModel.tsx

+9-6
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,24 @@ import { InscriptionsItemProps } from "LLD/features/Collectibles/types/Inscripti
55

66
type Props = {
77
inscriptions: SimpleHashNft[];
8+
onInscriptionClick: (inscription: SimpleHashNft) => void;
89
};
910

10-
export const useInscriptionsModel = ({ inscriptions }: Props) => {
11+
export const useInscriptionsModel = ({ inscriptions, onInscriptionClick }: Props) => {
1112
const [displayShowMore, setDisplayShowMore] = useState(false);
1213
const [displayedObjects, setDisplayedObjects] = useState<InscriptionsItemProps[]>([]);
1314

1415
const items: InscriptionsItemProps[] = useMemo(
15-
() => getInscriptionsData(inscriptions),
16-
[inscriptions],
16+
() => getInscriptionsData(inscriptions, onInscriptionClick),
17+
[inscriptions, onInscriptionClick],
1718
);
1819

1920
useEffect(() => {
20-
if (items.length > 3) setDisplayShowMore(true);
21-
setDisplayedObjects(items.slice(0, 3));
22-
}, [items]);
21+
if (displayedObjects.length === 0) {
22+
if (items.length > 3) setDisplayShowMore(true);
23+
setDisplayedObjects(items.slice(0, 3));
24+
}
25+
}, [items, displayedObjects.length]);
2326

2427
const onShowMore = () => {
2528
setDisplayedObjects(prevDisplayedObjects => {

apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/components/RareSats/index.tsx

+25-8
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,46 @@ import TableContainer from "~/renderer/components/TableContainer";
44
import TableHeader from "LLD/features/Collectibles/components/Collection/TableHeader";
55
import Item from "./Item";
66
import { TableHeaderTitleKey } from "LLD/features/Collectibles/types/Collection";
7-
import { Box, Flex } from "@ledgerhq/react-ui";
7+
import { Box, Flex, Icons } from "@ledgerhq/react-ui";
88
import { TableHeader as TableHeaderContainer } from "./TableHeader";
99
import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
1010
import Loader from "../Loader";
1111
import Error from "../Error";
12+
import EmptyCollection from "../../../components/Collection/EmptyCollection";
13+
import { CollectibleTypeEnum } from "../../../types/enum/Collectibles";
14+
import Button from "~/renderer/components/Button";
15+
import { useTranslation } from "react-i18next";
1216

1317
type ViewProps = ReturnType<typeof useRareSatsModel> & {
1418
isLoading: boolean;
1519
isError: boolean;
1620
isFetched: boolean;
21+
error: Error | null;
22+
onReceive: () => void;
1723
};
1824

1925
type Props = {
2026
rareSats: SimpleHashNft[];
2127
isLoading: boolean;
2228
isError: boolean;
2329
isFetched: boolean;
30+
error: Error | null;
31+
onReceive: () => void;
2432
};
2533

26-
function View({ rareSats, isLoading, isError, isFetched }: ViewProps) {
27-
const isLoaded = isFetched;
34+
function View({ rareSats, isLoading, isError, isFetched, error, onReceive }: ViewProps) {
35+
const { t } = useTranslation();
36+
const isLoaded = isFetched && !isError && !isLoading;
2837
const hasRareSats = Object.values(rareSats).length > 0;
2938
const dataReady = isLoaded && hasRareSats;
39+
const hasError = isError && error;
3040

3141
return (
3242
<Box>
3343
<TableContainer id="oridinals-raresats">
3444
<TableHeader titleKey={TableHeaderTitleKey.RareSats} />
3545
{isLoading && <Loader />}
36-
{isError && <Error />}
46+
{hasError && <Error error={error} />}
3747
{dataReady && <TableHeaderContainer />}
3848
<Flex flexDirection="column">
3949
{dataReady &&
@@ -45,22 +55,29 @@ function View({ rareSats, isLoading, isError, isFetched }: ViewProps) {
4555
</Flex>
4656
))}
4757
{isLoaded && !hasRareSats && (
48-
<Flex justifyContent="center" my={4}>
49-
{"NOTHING TO SHOW WAITING FOR DESIGN"}
50-
</Flex>
58+
<EmptyCollection collectionType={CollectibleTypeEnum.RareSat}>
59+
<Button small primary onClick={onReceive} icon>
60+
<Flex alignItems={"center"}>
61+
<Icons.ArrowDown size="XS" />
62+
<Box>{t("ordinals.rareSats.receive")}</Box>
63+
</Flex>
64+
</Button>
65+
</EmptyCollection>
5166
)}
5267
</Flex>
5368
</TableContainer>
5469
</Box>
5570
);
5671
}
5772

58-
const RareSats = ({ rareSats, isLoading, isError, isFetched }: Props) => {
73+
const RareSats = ({ rareSats, isLoading, isError, isFetched, error, onReceive }: Props) => {
5974
return (
6075
<View
6176
isFetched={isFetched}
6277
isLoading={isLoading}
6378
isError={isError}
79+
error={error}
80+
onReceive={onReceive}
6481
{...useRareSatsModel({ rareSats })}
6582
/>
6683
);

apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/index.tsx

+15-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import RareSats from "../../components/RareSats";
55
import DiscoveryDrawer from "../../components/Inscriptions/DiscoveryDrawer";
66
import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types";
77
import { useBitcoinAccountModel } from "./useBitcoinAccountModel";
8+
import InscriptionDetailsDrawer from "../../components/Inscriptions/DetailsDrawer";
89

910
type ViewProps = ReturnType<typeof useBitcoinAccountModel>;
1011

@@ -17,12 +18,24 @@ const View: React.FC<ViewProps> = ({
1718
rest,
1819
rareSats,
1920
isDrawerOpen,
21+
selectedInscription,
2022
handleDrawerClose,
23+
onReceive,
24+
onInscriptionClick,
25+
onDetailsDrawerClose,
2126
}) => (
2227
<Flex mb={50} width="100%" flexDirection="column" rowGap={40}>
23-
<Inscriptions inscriptions={inscriptions} {...rest} />
24-
<RareSats rareSats={rareSats} {...rest} />
28+
<Inscriptions
29+
inscriptions={inscriptions}
30+
onReceive={onReceive}
31+
onInscriptionClick={onInscriptionClick}
32+
{...rest}
33+
/>
34+
<RareSats rareSats={rareSats} onReceive={onReceive} {...rest} />
2535
<DiscoveryDrawer isOpen={isDrawerOpen} onClose={handleDrawerClose} />
36+
{selectedInscription && (
37+
<InscriptionDetailsDrawer inscription={selectedInscription} onClose={onDetailsDrawerClose} />
38+
)}
2639
</Flex>
2740
);
2841

apps/ledger-live-desktop/src/newArch/features/Collectibles/Ordinals/screens/Account/useBitcoinAccountModel.ts

+28-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types";
2+
import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
23
import useFetchOrdinals from "LLD/features/Collectibles/hooks/useFetchOrdinals";
3-
import { useState, useEffect } from "react";
4+
import { useState, useEffect, useCallback } from "react";
45
import { useDispatch, useSelector } from "react-redux";
6+
import { openModal } from "~/renderer/actions/modals";
57
import { setHasSeenOrdinalsDiscoveryDrawer } from "~/renderer/actions/settings";
68
import { hasSeenOrdinalsDiscoveryDrawerSelector } from "~/renderer/reducers/settings";
79

@@ -12,6 +14,7 @@ interface Props {
1214
export const useBitcoinAccountModel = ({ account }: Props) => {
1315
const dispatch = useDispatch();
1416
const hasSeenDiscoveryDrawer = useSelector(hasSeenOrdinalsDiscoveryDrawerSelector);
17+
const [selectedInscription, setSelectedInscription] = useState<SimpleHashNft | null>(null);
1518

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

@@ -28,5 +31,28 @@ export const useBitcoinAccountModel = ({ account }: Props) => {
2831
dispatch(setHasSeenOrdinalsDiscoveryDrawer(true));
2932
};
3033

31-
return { rareSats, inscriptions, rest, isDrawerOpen, handleDrawerClose };
34+
const onReceive = useCallback(() => {
35+
dispatch(
36+
openModal("MODAL_RECEIVE", {
37+
account,
38+
receiveOrdinalMode: true,
39+
}),
40+
);
41+
}, [dispatch, account]);
42+
43+
const onInscriptionClick = (inscription: SimpleHashNft) => setSelectedInscription(inscription);
44+
45+
const onDetailsDrawerClose = () => setSelectedInscription(null);
46+
47+
return {
48+
rareSats,
49+
inscriptions,
50+
rest,
51+
isDrawerOpen,
52+
selectedInscription,
53+
onReceive,
54+
handleDrawerClose,
55+
onInscriptionClick,
56+
onDetailsDrawerClose,
57+
};
3258
};

0 commit comments

Comments
 (0)