Skip to content

Commit

Permalink
feat: Rework hiddenCollections to handle more easily displays in LLM (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
mcayuelas-ledger authored Dec 2, 2024
1 parent 40f1cd4 commit f0a34a0
Show file tree
Hide file tree
Showing 28 changed files with 456 additions and 200 deletions.
8 changes: 8 additions & 0 deletions .changeset/big-apricots-live.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"ledger-live-desktop": minor
"live-mobile": minor
"@ledgerhq/live-nft-react": minor
"@ledgerhq/live-nft": minor
---

Rework Hiddencollections
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import styled from "styled-components";
import { useOnScreen } from "~/renderer/screens/nft/useOnScreen";
import { getEnv } from "@ledgerhq/live-env";
import { useNftCollections } from "~/renderer/hooks/nfts/useNftCollections";
import { State } from "~/renderer/reducers";
import { useFeature } from "@ledgerhq/live-common/featureFlags/index";

const ScrollContainer = styled(Flex).attrs({
flexDirection: "column",
Expand All @@ -31,9 +33,13 @@ type Props = {

const NFTGallerySelector = ({ handlePickNft, selectedNftId }: Props) => {
const SUPPORTED_NFT_CURRENCIES = getEnv("NFT_CURRENCIES");
const nftsFromSimplehashFeature = useFeature("nftsFromSimplehash");
const accounts = useSelector(accountsSelector);
const nftsOrdered = useSelector(orderedVisibleNftsSelector, isEqual);

const nftsOrdered = useSelector(
(state: State) =>
orderedVisibleNftsSelector(state, Boolean(nftsFromSimplehashFeature?.enabled)),
isEqual,
);
const addresses = useMemo(
() =>
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ describe("useHideSpamCollection", () => {
collectionB: NftStatus.spam,
},
},
whitelistedNftCollections: ["collectionA", "collectionB"],
},
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ export function useHideSpamCollection() {

const hideSpamCollection = useCallback(
(collection: string, blockchain: BlockchainsType) => {
const elem = Object.entries(nftCollectionsStatusByNetwork).find(
([key]) => key === blockchain,
)?.[1];
const blockchainToCheck = nftCollectionsStatusByNetwork[blockchain] || {};
const elem = Object.entries(blockchainToCheck).find(([key, _]) => key === collection);

if (!elem) {
dispatch(updateNftStatus(blockchain, collection, NftStatus.spam));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,27 @@ import { nftCollectionsStatusByNetworkSelector } from "~/renderer/reducers/setti
import { NftStatus } from "@ledgerhq/live-nft/types";
import { BlockchainEVM } from "@ledgerhq/live-nft/supported";

export const nftCollectionParser = (
nftCollection: Record<BlockchainEVM, Record<string, NftStatus>>,
applyFilterFn: (arg0: [string, NftStatus]) => boolean,
) =>
Object.values(nftCollection).flatMap(contracts =>
Object.entries(contracts)
.filter(applyFilterFn)
.map(([contract]) => contract),
);

export function useNftCollectionsStatus() {
const nftsFromSimplehashFeature = useFeature("nftsFromSimplehash");
const nftCollectionsStatusByNetwork = useSelector(nftCollectionsStatusByNetworkSelector);

const shouldDisplaySpams = !nftsFromSimplehashFeature?.enabled;

const nftCollectionParser = (
nftCollection: Record<BlockchainEVM, Record<string, NftStatus>>,
applyFilterFn: (arg0: [string, NftStatus]) => boolean,
) =>
Object.values(nftCollection).flatMap(contracts =>
Object.entries(contracts)
.filter(applyFilterFn)
.map(([contract]) => contract),
);
const hideSpams = Boolean(nftsFromSimplehashFeature?.enabled);

const list = useMemo(() => {
return nftCollectionParser(nftCollectionsStatusByNetwork, ([_, status]) =>
!shouldDisplaySpams ? status !== NftStatus.whitelisted : status === NftStatus.blacklisted,
hideSpams ? status !== NftStatus.whitelisted : status === NftStatus.blacklisted,
);
}, [nftCollectionsStatusByNetwork, shouldDisplaySpams]);
}, [nftCollectionsStatusByNetwork, hideSpams]);

const whitelisted = useMemo(() => {
return nftCollectionParser(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useSelector } from "react-redux";
import { accountsSelector, orderedVisibleNftsSelector } from "~/renderer/reducers/accounts";
import isEqual from "lodash/isEqual";
import { getEnv } from "@ledgerhq/live-env";
import { State } from "~/renderer/reducers";

/**
* Represents the size of groups for batching address fetching.
Expand Down Expand Up @@ -41,9 +42,12 @@ export function useSyncNFTsWithAccounts() {
const threshold = getThreshold(nftsFromSimplehashFeature?.params?.threshold);

const { enabled, hideSpamCollection } = useHideSpamCollection();

const accounts = useSelector(accountsSelector);
const nftsOwned = useSelector(orderedVisibleNftsSelector, isEqual);
const nftsOwned = useSelector(
(state: State) =>
orderedVisibleNftsSelector(state, Boolean(nftsFromSimplehashFeature?.enabled)),
isEqual,
);

const addressGroups = useMemo(() => {
const uniqueAddresses = [
Expand Down
12 changes: 7 additions & 5 deletions apps/ledger-live-desktop/src/renderer/reducers/accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { isStarredAccountSelector } from "@ledgerhq/live-wallet/store";
import { nestedSortAccounts, AccountComparator } from "@ledgerhq/live-wallet/ordering";
import { AddAccountsAction } from "@ledgerhq/live-wallet/addAccounts";
import { NftStatus } from "@ledgerhq/live-nft/types";
import { nftCollectionParser } from "../hooks/nfts/useNftCollectionsStatus";

/*
FIXME
Expand Down Expand Up @@ -224,13 +225,14 @@ export const flattenAccountsSelector = createSelector(accountsSelector, flattenA
export const orderedVisibleNftsSelector = createSelector(
accountsSelector,
nftCollectionsStatusByNetworkSelector,
(accounts, nftCollectionsStatusByNetwork) => {
(_: State, hideSpam: boolean) => hideSpam,
(accounts, nftCollectionsStatusByNetwork, hideSpams) => {
const nfts = accounts.map(a => a.nfts ?? []).flat();

const hiddenNftCollections = Object.values(nftCollectionsStatusByNetwork).flatMap(contracts =>
Object.entries(contracts)
.filter(([_, status]) => status === NftStatus.blacklisted || status === NftStatus.spam)
.map(([contract]) => contract),
const hiddenNftCollections = nftCollectionParser(
nftCollectionsStatusByNetwork,
([_, status]) =>
hideSpams ? status !== NftStatus.whitelisted : status === NftStatus.blacklisted,
);

const visibleNfts = nfts.filter(
Expand Down
6 changes: 3 additions & 3 deletions apps/ledger-live-desktop/src/renderer/reducers/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import {
TOGGLE_MEV,
UPDATE_NFT_COLLECTION_STATUS,
} from "../actions/constants";
import { BlockchainsType } from "@ledgerhq/live-nft/supported";
import { BlockchainsType, SupportedBlockchainsType } from "@ledgerhq/live-nft/supported";
import { NftStatus } from "@ledgerhq/live-nft/types";

/* Initial state */
Expand Down Expand Up @@ -203,7 +203,7 @@ export const INITIAL_STATE: SettingsState = {
blacklistedTokenIds: [],
hiddenNftCollections: [],
whitelistedNftCollections: [],
nftCollectionsStatusByNetwork: {} as Record<BlockchainsType, Record<string, NftStatus>>,
nftCollectionsStatusByNetwork: {} as Record<SupportedBlockchainsType, Record<string, NftStatus>>,
hiddenOrdinalsAsset: [],
deepLinkUrl: null,
firstTimeLend: false,
Expand Down Expand Up @@ -255,7 +255,7 @@ type HandlersPayloads = {
SHOW_TOKEN: string;
BLACKLIST_TOKEN: string;
[UPDATE_NFT_COLLECTION_STATUS]: {
blockchain: BlockchainsType;
blockchain: SupportedBlockchainsType;
collectionId: string;
status: NftStatus;
};
Expand Down
20 changes: 3 additions & 17 deletions apps/ledger-live-mobile/src/actions/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
DangerouslyOverrideStatePayload,
SettingsDismissBannerPayload,
SettingsHideEmptyTokenAccountsPayload,
SettingsHideNftCollectionPayload,
SettingsImportDesktopPayload,
SettingsImportPayload,
SettingsSetHasInstalledAnyAppPayload,
Expand Down Expand Up @@ -41,7 +40,6 @@ import {
SettingsSetSwapSelectableCurrenciesPayload,
SettingsSetThemePayload,
SettingsShowTokenPayload,
SettingsUnhideNftCollectionPayload,
SettingsUpdateCurrencyPayload,
SettingsActionTypes,
SettingsSetWalletTabNavigatorLastVisitedTabPayload,
Expand Down Expand Up @@ -71,9 +69,8 @@ import {
SettingsRemoveStarredMarketcoinsPayload,
SettingsSetFromLedgerSyncOnboardingPayload,
SettingsSetHasBeenRedirectedToPostOnboardingPayload,
SettingsWhitelistNftCollectionPayload,
SettingsUnwhitelistNftCollectionPayload,
SettingsSetMevProtectionPayload,
SettingsUpdateNftCollectionStatus,
} from "./types";
import { ImageType } from "~/components/CustomImage/types";

Expand Down Expand Up @@ -144,19 +141,8 @@ export const blacklistToken = createAction<SettingsBlacklistTokenPayload>(
SettingsActionTypes.BLACKLIST_TOKEN,
);
export const showToken = createAction<SettingsShowTokenPayload>(SettingsActionTypes.SHOW_TOKEN);
export const hideNftCollection = createAction<SettingsHideNftCollectionPayload>(
SettingsActionTypes.HIDE_NFT_COLLECTION,
);
export const unhideNftCollection = createAction<SettingsUnhideNftCollectionPayload>(
SettingsActionTypes.UNHIDE_NFT_COLLECTION,
);

export const whitelistNftCollection = createAction<SettingsWhitelistNftCollectionPayload>(
SettingsActionTypes.WHITELIST_NFT_COLLECTION,
);

export const unwhitelistNftCollection = createAction<SettingsUnwhitelistNftCollectionPayload>(
SettingsActionTypes.UNWHITELIST_NFT_COLLECTION,
export const updateNftStatus = createAction<SettingsUpdateNftCollectionStatus>(
SettingsActionTypes.UPDATE_NFT_COLLECTION_STATUS,
);

export const dismissBanner = createAction<SettingsDismissBannerPayload>(
Expand Down
21 changes: 9 additions & 12 deletions apps/ledger-live-mobile/src/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ import type { Unpacked } from "../types/helpers";
import { HandlersPayloads } from "@ledgerhq/live-wallet/store";
import { ImportAccountsReduceInput } from "@ledgerhq/live-wallet/liveqr/importAccounts";
import { Steps } from "LLM/features/WalletSync/types/Activation";
import { NftStatus } from "@ledgerhq/live-nft/types";
import { BlockchainEVM } from "@ledgerhq/live-nft/supported";

// === ACCOUNTS ACTIONS ===

Expand Down Expand Up @@ -242,10 +244,7 @@ export enum SettingsActionTypes {
SETTINGS_FILTER_TOKEN_OPERATIONS_ZERO_AMOUNT = "SETTINGS_FILTER_TOKEN_OPERATIONS_ZERO_AMOUNT",
SHOW_TOKEN = "SHOW_TOKEN",
BLACKLIST_TOKEN = "BLACKLIST_TOKEN",
HIDE_NFT_COLLECTION = "HIDE_NFT_COLLECTION",
UNHIDE_NFT_COLLECTION = "UNHIDE_NFT_COLLECTION",
UNWHITELIST_NFT_COLLECTION = "UNWHITELIST_NFT_COLLECTION",
WHITELIST_NFT_COLLECTION = "WHITELIST_NFT_COLLECTION",
UPDATE_NFT_COLLECTION_STATUS = "UPDATE_NFT_COLLECTION_STATUS",
SETTINGS_DISMISS_BANNER = "SETTINGS_DISMISS_BANNER",
SETTINGS_SET_AVAILABLE_UPDATE = "SETTINGS_SET_AVAILABLE_UPDATE",
DANGEROUSLY_OVERRIDE_STATE = "DANGEROUSLY_OVERRIDE_STATE",
Expand Down Expand Up @@ -324,10 +323,11 @@ export type SettingsFilterTokenOperationsZeroAmountPayload =
SettingsState["filterTokenOperationsZeroAmount"];
export type SettingsShowTokenPayload = string;
export type SettingsBlacklistTokenPayload = string;
export type SettingsHideNftCollectionPayload = string;
export type SettingsUnhideNftCollectionPayload = string;
export type SettingsWhitelistNftCollectionPayload = string;
export type SettingsUnwhitelistNftCollectionPayload = string;
export type SettingsUpdateNftCollectionStatus = {
blockchain: BlockchainEVM;
collection: string;
status: NftStatus;
};
export type SettingsDismissBannerPayload = string;
export type SettingsSetAvailableUpdatePayload = SettingsState["hasAvailableUpdate"];
export type SettingsSetThemePayload = SettingsState["theme"];
Expand Down Expand Up @@ -425,10 +425,7 @@ export type SettingsPayload =
| SettingsHideEmptyTokenAccountsPayload
| SettingsShowTokenPayload
| SettingsBlacklistTokenPayload
| SettingsHideNftCollectionPayload
| SettingsUnhideNftCollectionPayload
| SettingsWhitelistNftCollectionPayload
| SettingsUnwhitelistNftCollectionPayload
| SettingsUpdateNftCollectionStatus
| SettingsDismissBannerPayload
| SettingsSetAvailableUpdatePayload
| SettingsSetThemePayload
Expand Down
20 changes: 11 additions & 9 deletions apps/ledger-live-mobile/src/components/Nft/HideNftDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ import { useDispatch, useSelector } from "react-redux";
import { Account } from "@ledgerhq/types-live";
import { decodeNftId } from "@ledgerhq/coin-framework/nft/nftId";
import { track, TrackScreen } from "~/analytics";
import { hideNftCollection, unwhitelistNftCollection } from "~/actions/settings";
import { accountSelector } from "~/reducers/accounts";
import { State } from "~/reducers/types";
import QueuedDrawer from "../QueuedDrawer";
import { whitelistedNftCollectionsSelector } from "~/reducers/settings";
import { updateNftStatus } from "~/actions/settings";
import { BlockchainEVM } from "@ledgerhq/live-nft/supported";
import { NftStatus } from "@ledgerhq/live-nft/types";

type Props = {
nftId?: string;
Expand All @@ -25,8 +26,6 @@ const HideNftDrawer = ({ nftId, nftContract, collection, isOpened, onClose }: Pr
const navigation = useNavigation();
const dispatch = useDispatch();

const whitelistedNftCollections = useSelector(whitelistedNftCollectionsSelector);

const { accountId } = decodeNftId(nftId ?? "");
const account = useSelector<State, Account | undefined>(state =>
accountSelector(state, { accountId }),
Expand All @@ -39,14 +38,17 @@ const HideNftDrawer = ({ nftId, nftContract, collection, isOpened, onClose }: Pr
});

const collectionId = `${account?.id}|${nftContract}`;
if (whitelistedNftCollections.includes(collectionId)) {
dispatch(unwhitelistNftCollection(collectionId));
}

dispatch(hideNftCollection(collectionId));
dispatch(
updateNftStatus({
collection: collectionId,
status: NftStatus.blacklisted,
blockchain: account?.currency.id as BlockchainEVM,
}),
);
onClose();
navigation.goBack();
}, [account?.id, dispatch, navigation, nftContract, onClose, whitelistedNftCollections]);
}, [account?.currency.id, account?.id, dispatch, navigation, nftContract, onClose]);

const onPressClose = useCallback(() => {
track("button_clicked", {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React, { useCallback } from "react";

import { useDispatch, useSelector } from "react-redux";
import { useDispatch } from "react-redux";
import { Text, IconsLegacy, BoxedIcon, Button, Flex } from "@ledgerhq/native-ui";
import { Account, ProtoNFT } from "@ledgerhq/types-live";
import { useTranslation } from "react-i18next";
import { hideNftCollection, unwhitelistNftCollection } from "~/actions/settings";
import { updateNftStatus } from "~/actions/settings";
import QueuedDrawer from "../QueuedDrawer";
import { whitelistedNftCollectionsSelector } from "~/reducers/settings";
import { NftStatus } from "@ledgerhq/live-nft/types";
import { BlockchainEVM } from "@ledgerhq/live-nft/supported";

type Props = {
isOpen: boolean;
Expand All @@ -19,17 +20,18 @@ const NftCollectionOptionsMenu = ({ isOpen, onClose, collection, account }: Prop
const { t } = useTranslation();
const dispatch = useDispatch();

const whitelistedNftCollections = useSelector(whitelistedNftCollectionsSelector);

const onConfirm = useCallback(() => {
const collectionId = `${account.id}|${collection?.[0]?.contract}`;
if (whitelistedNftCollections.includes(collectionId)) {
dispatch(unwhitelistNftCollection(collectionId));
}

dispatch(hideNftCollection(collectionId));
dispatch(
updateNftStatus({
collection: collectionId,
status: NftStatus.blacklisted,
blockchain: account.currency.id as BlockchainEVM,
}),
);
onClose();
}, [account.id, collection, whitelistedNftCollections, dispatch, onClose]);
}, [account.id, account.currency.id, collection, dispatch, onClose]);

return (
<QueuedDrawer isRequestingToBeOpened={isOpen} onClose={onClose}>
Expand Down
Loading

0 comments on commit f0a34a0

Please sign in to comment.