diff --git a/examples/react/src/components/Connected.tsx b/examples/react/src/components/Connected.tsx index 3885a8d75..a6c534e19 100644 --- a/examples/react/src/components/Connected.tsx +++ b/examples/react/src/components/Connected.tsx @@ -516,6 +516,23 @@ export const Connected = () => { description="View your integrated wallet" onClick={() => setOpenWalletModal(true)} /> + + setOpenWalletModal(true, { + defaultNavigation: { + location: 'search-collectibles', + params: { + selectedCollection: { + chainId: 137, + contractAddress: '0x92473261F2c26F2264429C451F70b0192f858795' + } + } + } + }) + } + /> {(sponsoredContractAddresses[chainId] || networkForCurrentChainId.testnet) && isWaasConnectionActive && ( void enableFilters?: boolean gridColumns?: number + // Used only if a single collection is selected + collectionHeaderInfo?: { + logoURI?: string + name?: string + chainId: number + } }) => { const pageSize = 8 @@ -101,6 +109,24 @@ export const CollectiblesList = ({ {enableFilters && } + + {collectionHeaderInfo && ( +
+
+ +
+ {collectionHeaderInfo.name && ( +

{collectionHeaderInfo.name}

+ )} + + +

+ {collectibleBalances.length} Unique Collectible + {collectibleBalances.length === 0 || collectibleBalances.length > 1 ? 's' : ''} +

+
+ )} +
{ case 'search-tokens': return case 'search-collectibles': - return + return ( + + ) case 'settings': return case 'settings-wallets': diff --git a/packages/wallet-widget/src/contexts/Navigation.ts b/packages/wallet-widget/src/contexts/Navigation.ts index 9f837b685..e83e82589 100644 --- a/packages/wallet-widget/src/contexts/Navigation.ts +++ b/packages/wallet-widget/src/contexts/Navigation.ts @@ -87,6 +87,17 @@ export interface SendCollectibleNavigation { params: SendCollectibleParams } +export interface SearchCollectiblesParams { + selectedCollection: { + chainId: number + contractAddress: string + } +} + +export interface SearchCollectiblesNavigation { + location: 'search-collectibles' + params?: SearchCollectiblesParams +} export interface BasicNavigation { location: | 'home' @@ -108,7 +119,6 @@ export interface BasicNavigation { | 'connect-dapp' | 'search' | 'search-tokens' - | 'search-collectibles' } export type Navigation = @@ -116,6 +126,7 @@ export type Navigation = | CoinDetailsNavigation | CollectibleDetailsNavigation | TransactionDetailsNavigation + | SearchCollectiblesNavigation | SearchViewAllNavigation | SendCoinNavigation | SendCollectibleNavigation diff --git a/packages/wallet-widget/src/hooks/useOpenWalletModal.ts b/packages/wallet-widget/src/hooks/useOpenWalletModal.ts index 5a5f3d21c..2e965c114 100644 --- a/packages/wallet-widget/src/hooks/useOpenWalletModal.ts +++ b/packages/wallet-widget/src/hooks/useOpenWalletModal.ts @@ -1,21 +1,22 @@ -import { useWalletModalContext } from '../contexts/WalletModal' +import { useWalletModalContext, WalletOptions } from '../contexts/WalletModal' /** * Return type for the useOpenWalletModal hook. * - * @property {function(isOpen: boolean): void} setOpenWalletModal - Function to open or close the Wallet modal + * @property {function(isOpen: boolean, options?: WalletOptions): void} setOpenWalletModal - Function to open or close the Wallet modal * @property {boolean} openWalletModalState - Current open state of the Wallet modal */ type UseOpenWalletModalReturnType = { - setOpenWalletModal: (isOpen: boolean) => void + setOpenWalletModal: (isOpen: boolean, options?: WalletOptions) => void openWalletModalState: boolean } /** - * Hook to manage the Wallet Inventory modal that allows users to view their tokens and NFTs. + * Hook to manage the Wallet Widget modal. * - * This hook provides a method to open and close the wallet inventory modal, and access its current open state. - * The Wallet modal displays all tokens, NFTs and collectibles present in the connected wallet. + * This hook provides a method to open and close the wallet widget modal, and access its current open state. + * The Wallet Widget displays your Tokens, Collectibles, Transactions, Settings, multiple connected / linked wallets and also allows + * to send, receive, buy (on-ramp) and swap tokens. * * @see {@link https://docs.sequence.xyz/sdk/web/hooks/useOpenWalletModal} for more detailed documentation. * @@ -29,17 +30,17 @@ type UseOpenWalletModalReturnType = { * // Get the function to open/close the wallet modal * const { setOpenWalletModal } = useOpenWalletModal() * - * // Function to handle opening the wallet inventory - * const handleViewInventory = () => { - * setOpenWalletModal(true) // Open the wallet modal to view tokens + * // Function to handle opening the wallet widget modal + * const handleViewWallet = () => { + * setOpenWalletModal(true) // Open the wallet widget modal * } * * return ( * * ) * } diff --git a/packages/wallet-widget/src/views/Home/index.tsx b/packages/wallet-widget/src/views/Home/index.tsx index 819a36320..e7bccf3dd 100644 --- a/packages/wallet-widget/src/views/Home/index.tsx +++ b/packages/wallet-widget/src/views/Home/index.tsx @@ -374,7 +374,7 @@ export const Home = () => { )} {walletFilterOpen && ( - setWalletFilterOpen(false)} label="Select active wallet"> + setWalletFilterOpen(false)} label="Filter items by wallet"> )} diff --git a/packages/wallet-widget/src/views/Search/SearchCollectibles.tsx b/packages/wallet-widget/src/views/Search/SearchCollectibles.tsx index 22a4fd18b..3b0792ae3 100644 --- a/packages/wallet-widget/src/views/Search/SearchCollectibles.tsx +++ b/packages/wallet-widget/src/views/Search/SearchCollectibles.tsx @@ -1,14 +1,51 @@ +import { useGetContractInfo } from '@0xsequence/hooks' import { useObservable } from 'micro-observables' +import { useEffect } from 'react' import { CollectiblesList } from '../../components/SearchLists/CollectiblesList' import { useSettings, useNavigation, useGetAllTokensDetails } from '../../hooks' import { TokenBalanceWithPrice } from '../../utils' -export const SearchCollectibles = () => { - const { selectedWalletsObservable, selectedNetworksObservable, selectedCollectionsObservable, hideUnlistedTokens } = - useSettings() +export const SearchCollectibles = ({ + contractAddress, + chainId +}: { + contractAddress: string | undefined + chainId: number | undefined +}) => { + const { + selectedWalletsObservable, + selectedNetworksObservable, + selectedCollectionsObservable, + hideUnlistedTokens, + setSelectedCollections + } = useSettings() const { setNavigation } = useNavigation() + // Only fetch contract info if contract address and chain id are provided + const { data: contractInfo } = useGetContractInfo( + { + chainID: String(chainId), + contractAddress: contractAddress || '' + }, + { disabled: !contractAddress || !chainId } + ) + + useEffect(() => { + if (contractAddress && chainId && contractInfo) { + setSelectedCollections([ + { + contractAddress, + chainId: Number(chainId), + logoURI: contractInfo.logoURI, + name: contractInfo.name + } + ]) + } else { + setSelectedCollections([]) + } + }, [contractInfo, contractAddress, chainId]) + const selectedWallets = useObservable(selectedWalletsObservable) const selectedNetworks = useObservable(selectedNetworksObservable) const selectedCollections = useObservable(selectedCollectionsObservable) @@ -23,8 +60,12 @@ export const SearchCollectibles = () => { const isSingleCollectionSelected = selectedCollections.length === 1 const collectibleBalancesFiltered = tokenBalancesData.filter(token => { - if (isSingleCollectionSelected) { - return token.chainId === selectedCollections[0].chainId + if (isSingleCollectionSelected && selectedCollections[0]) { + // Ensure we only show tokens from the selected collection's chain and contract + return ( + token.chainId === selectedCollections[0].chainId && + token.contractAddress.toLowerCase() === selectedCollections[0].contractAddress.toLowerCase() + ) } return true }) @@ -41,13 +82,26 @@ export const SearchCollectibles = () => { }) } + // Get the single selected collection details if available + const singleCollection = isSingleCollectionSelected ? selectedCollections[0] : null + + // Prepare the header info object, only if a single collection is selected + const collectionHeaderInfo = singleCollection + ? { + logoURI: singleCollection.logoURI, + name: singleCollection.name, + chainId: singleCollection.chainId + // We could add collectibleBalancesFiltered.length here if needed later + } + : undefined + return ( -
+
)