Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨(lld): add empty message and dummy drawer for ordis #7881

Merged
merged 1 commit into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/empty-clouds-glow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"ledger-live-desktop": patch
---

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
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import React from "react";
import { Flex, Icons, Text } from "@ledgerhq/react-ui";
import { useTranslation } from "react-i18next";

const Error: React.FC = () => {
type Props = {
error: Error;
};

const Error: React.FC<Props> = ({ error }) => {
const { t } = useTranslation();

return (
<Flex justifyContent="center" my={4} columnGap={2}>
<Flex my={4} ml={4} alignItems={"center"} columnGap={2}>
<Icons.Warning size="S" color="error.c60" />
<Text color="error.c60">{t("crash.title")}</Text>
<Text fontSize={12} alignSelf={"flex-end"} color="error.c40">{`(${error?.message})`}</Text>
</Flex>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from "react";
import { SideDrawer } from "~/renderer/components/SideDrawer";
import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";

type Props = {
inscription: SimpleHashNft;
onClose: () => void;
};
const InscriptionDetailsDrawer: React.FC<Props> = ({ inscription, onClose }) => {
// will be replaced by DetailsDrawer from collectibles
return (
<SideDrawer direction={"left"} isOpen={!!inscription} onRequestClose={onClose}>
{inscription.name || inscription.contract.name}
</SideDrawer>
);
};

export default InscriptionDetailsDrawer;
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ function matchCorrespondingIcon(
});
}

export function getInscriptionsData(inscriptions: SimpleHashNft[]) {
export function getInscriptionsData(
inscriptions: SimpleHashNft[],
onInscriptionClick: (inscription: SimpleHashNft) => void,
) {
const inscriptionsWithIcons = matchCorrespondingIcon(inscriptions);
return inscriptionsWithIcons.map(item => ({
tokenName: item.name || item.contract.name || "",
Expand All @@ -39,9 +42,6 @@ export function getInscriptionsData(inscriptions: SimpleHashNft[]) {
contentType: item.extra_metadata?.ordinal_details?.content_type,
mediaType: "image",
},
onClick: () => {
console.log(`you clicked on : \x1b[32m${item.name}\x1b[0m inscription`);
},
// it does nothing for now but it will be used for the next PR with the drawer
onClick: () => onInscriptionClick(item),
}));
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { Box, Flex } from "@ledgerhq/react-ui";
import { Box, Flex, Icons } from "@ledgerhq/react-ui";
import { useInscriptionsModel } from "./useInscriptionsModel";
import TableContainer from "~/renderer/components/TableContainer";
import TableHeader from "LLD/features/Collectibles/components/Collection/TableHeader";
Expand All @@ -9,31 +9,47 @@ import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
import Loader from "../Loader";
import Error from "../Error";
import Item from "./Item";
import EmptyCollection from "LLD/features/Collectibles/components/Collection/EmptyCollection";
import { CollectibleTypeEnum } from "../../../types/enum/Collectibles";
import Button from "~/renderer/components/Button";
import { useTranslation } from "react-i18next";

type ViewProps = ReturnType<typeof useInscriptionsModel> & { isLoading: boolean; isError: boolean };
type ViewProps = ReturnType<typeof useInscriptionsModel> & {
isLoading: boolean;
isError: boolean;
error: Error | null;
onReceive: () => void;
};

type Props = {
inscriptions: SimpleHashNft[];
isLoading: boolean;
isError: boolean;
error: Error | null;
onReceive: () => void;
onInscriptionClick: (inscription: SimpleHashNft) => void;
};

const View: React.FC<ViewProps> = ({
displayShowMore,
isLoading,
isError,
inscriptions,
error,
onShowMore,
onReceive,
}) => {
const { t } = useTranslation();
const hasInscriptions = inscriptions.length > 0 && !isError;
const nothingToShow = !hasInscriptions && !isLoading && !isError;
const hasError = isError && error;

return (
<Box>
<TableContainer id="ordinals-inscriptions">
<TableHeader titleKey={TableHeaderTitleKey.Inscriptions} />
{isLoading && <Loader />}
{isError && <Error />}
{hasError && <Error error={error} />}
{hasInscriptions &&
inscriptions.map((item, index) => (
<Item
Expand All @@ -48,18 +64,36 @@ const View: React.FC<ViewProps> = ({
/>
))}
{nothingToShow && (
<Flex justifyContent="center" my={4}>
{"NOTHING TO SHOW WAITING FOR DESIGN"}
</Flex>
<EmptyCollection collectionType={CollectibleTypeEnum.Inscriptions}>
<Button small primary onClick={onReceive} icon>
<Flex alignItems={"center"}>
<Icons.ArrowDown size="XS" />
<Box>{t("ordinals.inscriptions.receive")}</Box>
</Flex>
</Button>
</EmptyCollection>
)}
{displayShowMore && !isError && <ShowMore onShowMore={onShowMore} isInscriptions />}
</TableContainer>
</Box>
);
};

const Inscriptions: React.FC<Props> = ({ inscriptions, isLoading, isError }) => (
<View isLoading={isLoading} isError={isError} {...useInscriptionsModel({ inscriptions })} />
const Inscriptions: React.FC<Props> = ({
inscriptions,
isLoading,
isError,
error,
onReceive,
onInscriptionClick,
}) => (
<View
isLoading={isLoading}
isError={isError}
error={error}
onReceive={onReceive}
{...useInscriptionsModel({ inscriptions, onInscriptionClick })}
/>
);

export default Inscriptions;
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,28 @@ import { InscriptionsItemProps } from "LLD/features/Collectibles/types/Inscripti

type Props = {
inscriptions: SimpleHashNft[];
onInscriptionClick: (inscription: SimpleHashNft) => void;
};

export const useInscriptionsModel = ({ inscriptions }: Props) => {
const [displayShowMore, setDisplayShowMore] = useState(false);
const [displayedObjects, setDisplayedObjects] = useState<InscriptionsItemProps[]>([]);

export const useInscriptionsModel = ({ inscriptions, onInscriptionClick }: Props) => {
const items: InscriptionsItemProps[] = useMemo(
() => getInscriptionsData(inscriptions),
[inscriptions],
() => getInscriptionsData(inscriptions, onInscriptionClick),
[inscriptions, onInscriptionClick],
);

const initialDisplayedObjects = items.slice(0, 3);
const initialDisplayShowMore = items.length > 3;

const [displayShowMore, setDisplayShowMore] = useState(initialDisplayShowMore);
const [displayedObjects, setDisplayedObjects] =
useState<InscriptionsItemProps[]>(initialDisplayedObjects);

useEffect(() => {
if (items.length > 3) setDisplayShowMore(true);
setDisplayedObjects(items.slice(0, 3));
}, [items]);
if (displayedObjects.length === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's to avoid to trigger it at each re render. Sometimes (and when a drawer just opened) displayedObjects comes back to his initial state with only 3 object in it. So I trigger it only at the first render

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed to not do it with a use Effect to make easier to read

if (items.length > 3) setDisplayShowMore(true);
setDisplayedObjects(items.slice(0, 3));
}
}, [items, displayedObjects.length]);

const onShowMore = () => {
setDisplayedObjects(prevDisplayedObjects => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,46 @@ import TableContainer from "~/renderer/components/TableContainer";
import TableHeader from "LLD/features/Collectibles/components/Collection/TableHeader";
import Item from "./Item";
import { TableHeaderTitleKey } from "LLD/features/Collectibles/types/Collection";
import { Box, Flex } from "@ledgerhq/react-ui";
import { Box, Flex, Icons } from "@ledgerhq/react-ui";
import { TableHeader as TableHeaderContainer } from "./TableHeader";
import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
import Loader from "../Loader";
import Error from "../Error";
import EmptyCollection from "../../../components/Collection/EmptyCollection";
import { CollectibleTypeEnum } from "../../../types/enum/Collectibles";
import Button from "~/renderer/components/Button";
import { useTranslation } from "react-i18next";

type ViewProps = ReturnType<typeof useRareSatsModel> & {
isLoading: boolean;
isError: boolean;
isFetched: boolean;
error: Error | null;
onReceive: () => void;
};

type Props = {
rareSats: SimpleHashNft[];
isLoading: boolean;
isError: boolean;
isFetched: boolean;
error: Error | null;
onReceive: () => void;
};

function View({ rareSats, isLoading, isError, isFetched }: ViewProps) {
const isLoaded = isFetched;
function View({ rareSats, isLoading, isError, isFetched, error, onReceive }: ViewProps) {
const { t } = useTranslation();
const isLoaded = isFetched && !isError && !isLoading;
const hasRareSats = Object.values(rareSats).length > 0;
const dataReady = isLoaded && hasRareSats;
const hasError = isError && error;

return (
<Box>
<TableContainer id="oridinals-raresats">
<TableHeader titleKey={TableHeaderTitleKey.RareSats} />
{isLoading && <Loader />}
{isError && <Error />}
{hasError && <Error error={error} />}
{dataReady && <TableHeaderContainer />}
<Flex flexDirection="column">
{dataReady &&
Expand All @@ -45,22 +55,29 @@ function View({ rareSats, isLoading, isError, isFetched }: ViewProps) {
</Flex>
))}
{isLoaded && !hasRareSats && (
<Flex justifyContent="center" my={4}>
{"NOTHING TO SHOW WAITING FOR DESIGN"}
</Flex>
<EmptyCollection collectionType={CollectibleTypeEnum.RareSat}>
<Button small primary onClick={onReceive} icon>
<Flex alignItems={"center"}>
<Icons.ArrowDown size="XS" />
<Box>{t("ordinals.rareSats.receive")}</Box>
</Flex>
</Button>
</EmptyCollection>
)}
</Flex>
</TableContainer>
</Box>
);
}

const RareSats = ({ rareSats, isLoading, isError, isFetched }: Props) => {
const RareSats = ({ rareSats, isLoading, isError, isFetched, error, onReceive }: Props) => {
return (
<View
isFetched={isFetched}
isLoading={isLoading}
isError={isError}
error={error}
onReceive={onReceive}
{...useRareSatsModel({ rareSats })}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import RareSats from "../../components/RareSats";
import DiscoveryDrawer from "../../components/Inscriptions/DiscoveryDrawer";
import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types";
import { useBitcoinAccountModel } from "./useBitcoinAccountModel";
import InscriptionDetailsDrawer from "../../components/Inscriptions/DetailsDrawer";

type ViewProps = ReturnType<typeof useBitcoinAccountModel>;

Expand All @@ -17,12 +18,24 @@ const View: React.FC<ViewProps> = ({
rest,
rareSats,
isDrawerOpen,
selectedInscription,
handleDrawerClose,
onReceive,
onInscriptionClick,
onDetailsDrawerClose,
}) => (
<Flex mb={50} width="100%" flexDirection="column" rowGap={40}>
<Inscriptions inscriptions={inscriptions} {...rest} />
<RareSats rareSats={rareSats} {...rest} />
<Inscriptions
inscriptions={inscriptions}
onReceive={onReceive}
onInscriptionClick={onInscriptionClick}
{...rest}
/>
<RareSats rareSats={rareSats} onReceive={onReceive} {...rest} />
<DiscoveryDrawer isOpen={isDrawerOpen} onClose={handleDrawerClose} />
{selectedInscription && (
<InscriptionDetailsDrawer inscription={selectedInscription} onClose={onDetailsDrawerClose} />
)}
</Flex>
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { BitcoinAccount } from "@ledgerhq/coin-bitcoin/lib/types";
import { SimpleHashNft } from "@ledgerhq/live-nft/api/types";
import useFetchOrdinals from "LLD/features/Collectibles/hooks/useFetchOrdinals";
import { useState, useEffect } from "react";
import { useState, useEffect, useCallback } from "react";
import { useDispatch, useSelector } from "react-redux";
import { openModal } from "~/renderer/actions/modals";
import { setHasSeenOrdinalsDiscoveryDrawer } from "~/renderer/actions/settings";
import { hasSeenOrdinalsDiscoveryDrawerSelector } from "~/renderer/reducers/settings";

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

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

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

return { rareSats, inscriptions, rest, isDrawerOpen, handleDrawerClose };
const onReceive = useCallback(() => {
dispatch(
openModal("MODAL_RECEIVE", {
account,
receiveOrdinalMode: true,
}),
);
}, [dispatch, account]);

const onInscriptionClick = (inscription: SimpleHashNft) => setSelectedInscription(inscription);

const onDetailsDrawerClose = () => setSelectedInscription(null);

return {
rareSats,
inscriptions,
rest,
isDrawerOpen,
selectedInscription,
onReceive,
handleDrawerClose,
onInscriptionClick,
onDetailsDrawerClose,
};
};
Loading
Loading