feat: Sell Mode Button (#4803)
* remove sort and search functionality * add sell mode button toggle * update cards to sell mode * split wallet asset display file * remove unused style * address comments Co-authored-by: Charles Bachmeier <charlie@genie.xyz>
This commit is contained in:
parent
b0b61f886d
commit
db4987f557
@ -11,7 +11,7 @@ import { useSpring } from 'react-spring'
|
|||||||
|
|
||||||
import * as styles from './ProfilePage.css'
|
import * as styles from './ProfilePage.css'
|
||||||
|
|
||||||
export const FilterSidebar = ({ SortDropdown }: { SortDropdown: () => JSX.Element }) => {
|
export const FilterSidebar = () => {
|
||||||
const collectionFilters = useWalletCollections((state) => state.collectionFilters)
|
const collectionFilters = useWalletCollections((state) => state.collectionFilters)
|
||||||
const setCollectionFilters = useWalletCollections((state) => state.setCollectionFilters)
|
const setCollectionFilters = useWalletCollections((state) => state.setCollectionFilters)
|
||||||
|
|
||||||
@ -62,11 +62,6 @@ export const FilterSidebar = ({ SortDropdown }: { SortDropdown: () => JSX.Elemen
|
|||||||
<Row marginTop="14" marginLeft="2" gap="6" flexWrap="wrap" width="276">
|
<Row marginTop="14" marginLeft="2" gap="6" flexWrap="wrap" width="276">
|
||||||
<ListStatusFilterButtons listFilter={listFilter} setListFilter={setListFilter} />
|
<ListStatusFilterButtons listFilter={listFilter} setListFilter={setListFilter} />
|
||||||
</Row>
|
</Row>
|
||||||
{isMobile && (
|
|
||||||
<Box paddingTop="20">
|
|
||||||
<SortDropdown />
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
<CollectionSelect
|
<CollectionSelect
|
||||||
collections={walletCollections}
|
collections={walletCollections}
|
||||||
collectionFilters={collectionFilters}
|
collectionFilters={collectionFilters}
|
||||||
|
@ -1,22 +1,11 @@
|
|||||||
import clsx from 'clsx'
|
|
||||||
import { AnimatedBox, Box } from 'nft/components/Box'
|
import { AnimatedBox, Box } from 'nft/components/Box'
|
||||||
import { assetList } from 'nft/components/collection/CollectionNfts.css'
|
import { assetList } from 'nft/components/collection/CollectionNfts.css'
|
||||||
import { FilterButton } from 'nft/components/collection/FilterButton'
|
import { FilterButton } from 'nft/components/collection/FilterButton'
|
||||||
import { LoadingSparkle } from 'nft/components/common/Loading/LoadingSparkle'
|
import { LoadingSparkle } from 'nft/components/common/Loading/LoadingSparkle'
|
||||||
import { SortDropdown } from 'nft/components/common/SortDropdown'
|
|
||||||
import { Center, Column, Row } from 'nft/components/Flex'
|
import { Center, Column, Row } from 'nft/components/Flex'
|
||||||
import {
|
import { CrossIcon, TagIcon } from 'nft/components/icons'
|
||||||
BagFillIcon,
|
|
||||||
ClockIconFilled,
|
|
||||||
CrossIcon,
|
|
||||||
NonRarityIconFilled,
|
|
||||||
PaintPaletteIconFilled,
|
|
||||||
TagFillIcon,
|
|
||||||
VerifiedIcon,
|
|
||||||
} from 'nft/components/icons'
|
|
||||||
import { FilterSidebar } from 'nft/components/profile/view/FilterSidebar'
|
import { FilterSidebar } from 'nft/components/profile/view/FilterSidebar'
|
||||||
import { subhead, subheadSmall } from 'nft/css/common.css'
|
import { buttonTextMedium, subhead } from 'nft/css/common.css'
|
||||||
import { vars } from 'nft/css/sprinkles.css'
|
|
||||||
import {
|
import {
|
||||||
useBag,
|
useBag,
|
||||||
useFiltersExpanded,
|
useFiltersExpanded,
|
||||||
@ -27,34 +16,35 @@ import {
|
|||||||
useWalletCollections,
|
useWalletCollections,
|
||||||
} from 'nft/hooks'
|
} from 'nft/hooks'
|
||||||
import { fetchMultipleCollectionStats, fetchWalletAssets, OSCollectionsFetcher } from 'nft/queries'
|
import { fetchMultipleCollectionStats, fetchWalletAssets, OSCollectionsFetcher } from 'nft/queries'
|
||||||
import { DropDownOption, ProfilePageStateType, WalletAsset, WalletCollection } from 'nft/types'
|
import { ProfilePageStateType, WalletCollection } from 'nft/types'
|
||||||
import { Dispatch, FormEvent, SetStateAction, useEffect, useMemo, useReducer, useState } from 'react'
|
import { Dispatch, SetStateAction, useEffect, useMemo, useReducer, useState } from 'react'
|
||||||
import InfiniteScroll from 'react-infinite-scroll-component'
|
import InfiniteScroll from 'react-infinite-scroll-component'
|
||||||
import { useInfiniteQuery, useQuery } from 'react-query'
|
import { useInfiniteQuery, useQuery } from 'react-query'
|
||||||
import { Link } from 'react-router-dom'
|
|
||||||
import { useSpring } from 'react-spring'
|
import { useSpring } from 'react-spring'
|
||||||
|
import styled from 'styled-components/macro'
|
||||||
|
|
||||||
import { EmptyWalletContent } from './EmptyWalletContent'
|
import { EmptyWalletContent } from './EmptyWalletContent'
|
||||||
import { ProfileAccountDetails } from './ProfileAccountDetails'
|
import { ProfileAccountDetails } from './ProfileAccountDetails'
|
||||||
import * as styles from './ProfilePage.css'
|
import * as styles from './ProfilePage.css'
|
||||||
|
import { WalletAssetDisplay } from './WalletAssetDisplay'
|
||||||
|
|
||||||
enum SortBy {
|
const SellModeButton = styled.button<{ active: boolean }>`
|
||||||
FloorPrice,
|
display: flex;
|
||||||
LastPrice,
|
flex-direction: row;
|
||||||
DateAcquired,
|
justify-content: center;
|
||||||
DateCreated,
|
align-items: center;
|
||||||
DateListed,
|
padding: 10px 12px;
|
||||||
}
|
border-radius: 12px;
|
||||||
|
gap: 8px;
|
||||||
const formatEth = (price: number) => {
|
cursor: pointer;
|
||||||
if (price > 1000000) {
|
background-color: ${({ theme, active }) => (active ? theme.accentAction : theme.backgroundInteractive)};
|
||||||
return `${Math.round(price / 1000000)}M`
|
color: #fff;
|
||||||
} else if (price > 1000) {
|
border: none;
|
||||||
return `${Math.round(price / 1000)}K`
|
outline: none;
|
||||||
} else {
|
&:hover {
|
||||||
return `${Math.round(price * 100 + Number.EPSILON) / 100}`
|
background-color: ${({ theme }) => theme.accentAction};
|
||||||
}
|
}
|
||||||
}
|
`
|
||||||
|
|
||||||
function roundFloorPrice(price?: number, n?: number) {
|
function roundFloorPrice(price?: number, n?: number) {
|
||||||
return price ? Math.round(price * Math.pow(10, n ?? 3) + Number.EPSILON) / Math.pow(10, n ?? 3) : 0
|
return price ? Math.round(price * Math.pow(10, n ?? 3) + Number.EPSILON) / Math.pow(10, n ?? 3) : 0
|
||||||
@ -65,6 +55,26 @@ export const ProfilePage = () => {
|
|||||||
const collectionFilters = useWalletCollections((state) => state.collectionFilters)
|
const collectionFilters = useWalletCollections((state) => state.collectionFilters)
|
||||||
const setCollectionFilters = useWalletCollections((state) => state.setCollectionFilters)
|
const setCollectionFilters = useWalletCollections((state) => state.setCollectionFilters)
|
||||||
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
|
const clearCollectionFilters = useWalletCollections((state) => state.clearCollectionFilters)
|
||||||
|
const walletAssets = useWalletCollections((state) => state.walletAssets)
|
||||||
|
const setWalletAssets = useWalletCollections((state) => state.setWalletAssets)
|
||||||
|
const displayAssets = useWalletCollections((state) => state.displayAssets)
|
||||||
|
const setDisplayAssets = useWalletCollections((state) => state.setDisplayAssets)
|
||||||
|
const walletCollections = useWalletCollections((state) => state.walletCollections)
|
||||||
|
const setWalletCollections = useWalletCollections((state) => state.setWalletCollections)
|
||||||
|
const listFilter = useWalletCollections((state) => state.listFilter)
|
||||||
|
const sellAssets = useSellAsset((state) => state.sellAssets)
|
||||||
|
const reset = useSellAsset((state) => state.reset)
|
||||||
|
const resetSellAssets = useSellAsset((state) => state.reset)
|
||||||
|
const setSellPageState = useProfilePageState((state) => state.setProfilePageState)
|
||||||
|
const [isFiltersExpanded, setFiltersExpanded] = useFiltersExpanded()
|
||||||
|
const isBagExpanded = useBag((state) => state.bagExpanded)
|
||||||
|
const isMobile = useIsMobile()
|
||||||
|
const [isSellMode, toggleSellMode] = useReducer((s) => !s, false)
|
||||||
|
|
||||||
|
const handleSellModeClick = () => {
|
||||||
|
resetSellAssets()
|
||||||
|
toggleSellMode()
|
||||||
|
}
|
||||||
|
|
||||||
const { data: ownerCollections } = useQuery(
|
const { data: ownerCollections } = useQuery(
|
||||||
['ownerCollections', address],
|
['ownerCollections', address],
|
||||||
@ -108,21 +118,9 @@ export const ProfilePage = () => {
|
|||||||
|
|
||||||
const ownerAssets = useMemo(() => (isSuccess ? ownerAssetsData?.pages.flat() : null), [isSuccess, ownerAssetsData])
|
const ownerAssets = useMemo(() => (isSuccess ? ownerAssetsData?.pages.flat() : null), [isSuccess, ownerAssetsData])
|
||||||
|
|
||||||
const walletAssets = useWalletCollections((state) => state.walletAssets)
|
useEffect(() => {
|
||||||
const setWalletAssets = useWalletCollections((state) => state.setWalletAssets)
|
setDisplayAssets(walletAssets, listFilter)
|
||||||
const displayAssets = useWalletCollections((state) => state.displayAssets)
|
}, [walletAssets, listFilter, setDisplayAssets])
|
||||||
const setDisplayAssets = useWalletCollections((state) => state.setDisplayAssets)
|
|
||||||
const walletCollections = useWalletCollections((state) => state.walletCollections)
|
|
||||||
const setWalletCollections = useWalletCollections((state) => state.setWalletCollections)
|
|
||||||
const listFilter = useWalletCollections((state) => state.listFilter)
|
|
||||||
const sellAssets = useSellAsset((state) => state.sellAssets)
|
|
||||||
const reset = useSellAsset((state) => state.reset)
|
|
||||||
const setSellPageState = useProfilePageState((state) => state.setProfilePageState)
|
|
||||||
const [sortBy, setSortBy] = useState(SortBy.DateAcquired)
|
|
||||||
const [orderByASC, setOrderBy] = useState(true)
|
|
||||||
const [searchText, setSearchText] = useState('')
|
|
||||||
const [isFiltersExpanded, setFiltersExpanded] = useFiltersExpanded()
|
|
||||||
const isMobile = useIsMobile()
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setWalletAssets(ownerAssets?.flat() ?? [])
|
setWalletAssets(ownerAssets?.flat() ?? [])
|
||||||
@ -132,15 +130,6 @@ export const ProfilePage = () => {
|
|||||||
ownerCollections && setWalletCollections(ownerCollections)
|
ownerCollections && setWalletCollections(ownerCollections)
|
||||||
}, [ownerCollections, setWalletCollections])
|
}, [ownerCollections, setWalletCollections])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (searchText) {
|
|
||||||
const filtered = walletAssets.filter((asset) => asset.name?.toLowerCase().includes(searchText.toLowerCase()))
|
|
||||||
setDisplayAssets(filtered, listFilter)
|
|
||||||
} else {
|
|
||||||
setDisplayAssets(walletAssets, listFilter)
|
|
||||||
}
|
|
||||||
}, [searchText, walletAssets, listFilter, setDisplayAssets])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ownerCollections?.length && collectionStats?.length) {
|
if (ownerCollections?.length && collectionStats?.length) {
|
||||||
const ownerCollectionsCopy = [...ownerCollections]
|
const ownerCollectionsCopy = [...ownerCollections]
|
||||||
@ -152,31 +141,6 @@ export const ProfilePage = () => {
|
|||||||
}
|
}
|
||||||
}, [collectionStats, ownerCollections, setWalletCollections])
|
}, [collectionStats, ownerCollections, setWalletCollections])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const sorted = displayAssets && [...displayAssets]
|
|
||||||
if (sortBy === SortBy.FloorPrice && orderByASC) sorted?.sort((a, b) => (b.floorPrice || 0) - (a.floorPrice || 0))
|
|
||||||
else if (sortBy === SortBy.FloorPrice && !orderByASC)
|
|
||||||
sorted?.sort((a, b) => (a.floorPrice || 0) - (b.floorPrice || 0))
|
|
||||||
else if (sortBy === SortBy.LastPrice && orderByASC) sorted?.sort((a, b) => b.lastPrice - a.lastPrice)
|
|
||||||
else if (sortBy === SortBy.LastPrice && !orderByASC) sorted?.sort((a, b) => a.lastPrice - b.lastPrice)
|
|
||||||
else if (sortBy === SortBy.DateCreated && orderByASC)
|
|
||||||
sorted?.sort(
|
|
||||||
(a, b) => new Date(a.asset_contract.created_date).getTime() - new Date(b.asset_contract.created_date).getTime()
|
|
||||||
)
|
|
||||||
else if (sortBy === SortBy.DateCreated && !orderByASC)
|
|
||||||
sorted?.sort(
|
|
||||||
(a, b) => new Date(b.asset_contract.created_date).getTime() - new Date(a.asset_contract.created_date).getTime()
|
|
||||||
)
|
|
||||||
else if (sortBy === SortBy.DateAcquired && orderByASC)
|
|
||||||
sorted?.sort((a, b) => new Date(a.date_acquired).getTime() - new Date(b.date_acquired).getTime())
|
|
||||||
else if (sortBy === SortBy.DateAcquired && !orderByASC)
|
|
||||||
sorted?.sort((a, b) => new Date(b.date_acquired).getTime() - new Date(a.date_acquired).getTime())
|
|
||||||
else if (sortBy === SortBy.DateListed && orderByASC) sorted?.sort((a, b) => +b.listing_date - +a.listing_date)
|
|
||||||
else if (sortBy === SortBy.DateListed && !orderByASC) sorted?.sort((a, b) => +a.listing_date - +b.listing_date)
|
|
||||||
setDisplayAssets(sorted, listFilter)
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [sortBy, orderByASC, listFilter])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ownerCollections?.length && collectionStats?.length) {
|
if (ownerCollections?.length && collectionStats?.length) {
|
||||||
const ownerCollectionsCopy = [...ownerCollections]
|
const ownerCollectionsCopy = [...ownerCollections]
|
||||||
@ -188,76 +152,22 @@ export const ProfilePage = () => {
|
|||||||
}
|
}
|
||||||
}, [collectionStats, ownerCollections, setWalletCollections])
|
}, [collectionStats, ownerCollections, setWalletCollections])
|
||||||
|
|
||||||
const { gridX, gridWidthOffset } = useSpring({
|
const { gridX } = useSpring({
|
||||||
gridX: isFiltersExpanded ? 300 : -16,
|
gridX: isFiltersExpanded ? 300 : -16,
|
||||||
gridWidthOffset: isFiltersExpanded ? 300 /* right padding */ : 0,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const sortDropDownOptions: DropDownOption[] = useMemo(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
displayText: 'Floor price',
|
|
||||||
onClick: () => {
|
|
||||||
setOrderBy(false)
|
|
||||||
setSortBy(SortBy.FloorPrice)
|
|
||||||
},
|
|
||||||
icon: <NonRarityIconFilled width="28" height="28" color={vars.color.blue400} />,
|
|
||||||
reverseOnClick: () => setOrderBy(!orderByASC),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayText: 'Last price',
|
|
||||||
onClick: () => {
|
|
||||||
setOrderBy(false)
|
|
||||||
setSortBy(SortBy.LastPrice)
|
|
||||||
},
|
|
||||||
icon: <ClockIconFilled width="28" height="28" />,
|
|
||||||
reverseOnClick: () => setOrderBy(!orderByASC),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayText: 'Date acquired',
|
|
||||||
onClick: () => {
|
|
||||||
setOrderBy(false)
|
|
||||||
setSortBy(SortBy.DateAcquired)
|
|
||||||
},
|
|
||||||
icon: <BagFillIcon width="28" height="28" color={vars.color.blue400} />,
|
|
||||||
reverseOnClick: () => setOrderBy(!orderByASC),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayText: 'Date created',
|
|
||||||
onClick: () => {
|
|
||||||
setOrderBy(false)
|
|
||||||
setSortBy(SortBy.DateCreated)
|
|
||||||
},
|
|
||||||
icon: <PaintPaletteIconFilled width="28" height="28" color={vars.color.blue400} />,
|
|
||||||
reverseOnClick: () => setOrderBy(!orderByASC),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
displayText: 'Date listed',
|
|
||||||
onClick: () => {
|
|
||||||
setOrderBy(false)
|
|
||||||
setSortBy(SortBy.DateListed)
|
|
||||||
},
|
|
||||||
icon: <TagFillIcon width="28" height="28" color={vars.color.blue400} />,
|
|
||||||
reverseOnClick: () => setOrderBy(!orderByASC),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[orderByASC]
|
|
||||||
)
|
|
||||||
|
|
||||||
const SortWalletAssetsDropdown = () => <SortDropdown dropDownOptions={sortDropDownOptions} />
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column
|
<Column
|
||||||
width="full"
|
width="full"
|
||||||
paddingLeft={{ sm: '16', md: '52' }}
|
paddingLeft={{ sm: '16', md: '52' }}
|
||||||
paddingRight={{ sm: '0', md: '72' }}
|
paddingRight={{ sm: '0', md: isBagExpanded ? '0' : '72' }}
|
||||||
paddingTop={{ sm: '16', md: '40' }}
|
paddingTop={{ sm: '16', md: '40' }}
|
||||||
>
|
>
|
||||||
{walletAssets.length === 0 ? (
|
{walletAssets.length === 0 ? (
|
||||||
<EmptyWalletContent />
|
<EmptyWalletContent />
|
||||||
) : (
|
) : (
|
||||||
<Row alignItems="flex-start" position="relative">
|
<Row alignItems="flex-start" position="relative">
|
||||||
<FilterSidebar SortDropdown={SortWalletAssetsDropdown} />
|
<FilterSidebar />
|
||||||
|
|
||||||
{(!isMobile || !isFiltersExpanded) && (
|
{(!isMobile || !isFiltersExpanded) && (
|
||||||
<Column width="full">
|
<Column width="full">
|
||||||
@ -267,19 +177,22 @@ export const ProfilePage = () => {
|
|||||||
flexShrink="0"
|
flexShrink="0"
|
||||||
style={{
|
style={{
|
||||||
transform: gridX.to((x) => `translate(${Number(x) - (!isMobile && isFiltersExpanded ? 300 : 0)}px)`),
|
transform: gridX.to((x) => `translate(${Number(x) - (!isMobile && isFiltersExpanded ? 300 : 0)}px)`),
|
||||||
width: gridWidthOffset.to((x) => `calc(100% - ${x}px)`),
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Row gap="8" flexWrap="nowrap">
|
<Row gap="8" flexWrap="nowrap" justifyContent="space-between">
|
||||||
<FilterButton
|
<FilterButton
|
||||||
isMobile={isMobile}
|
isMobile={isMobile}
|
||||||
isFiltersExpanded={isFiltersExpanded}
|
isFiltersExpanded={isFiltersExpanded}
|
||||||
results={displayAssets.length}
|
results={displayAssets.length}
|
||||||
onClick={() => setFiltersExpanded(!isFiltersExpanded)}
|
onClick={() => setFiltersExpanded(!isFiltersExpanded)}
|
||||||
/>
|
/>
|
||||||
{!isMobile && <SortDropdown dropDownOptions={sortDropDownOptions} />}
|
<Row gap="8" flexWrap="nowrap">
|
||||||
<CollectionSearch searchText={searchText} setSearchText={setSearchText} />
|
{isSellMode && <SelectAllButton />}
|
||||||
<SelectAllButton />
|
<SellModeButton active={isSellMode} onClick={handleSellModeClick}>
|
||||||
|
<TagIcon height={20} width={20} />
|
||||||
|
Sell
|
||||||
|
</SellModeButton>
|
||||||
|
</Row>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<CollectionFiltersRow
|
<CollectionFiltersRow
|
||||||
@ -304,7 +217,9 @@ export const ProfilePage = () => {
|
|||||||
>
|
>
|
||||||
<div className={assetList}>
|
<div className={assetList}>
|
||||||
{displayAssets && displayAssets.length
|
{displayAssets && displayAssets.length
|
||||||
? displayAssets.map((asset, index) => <WalletAssetDisplay asset={asset} key={index} />)
|
? displayAssets.map((asset, index) => (
|
||||||
|
<WalletAssetDisplay asset={asset} isSellMode={isSellMode} key={index} />
|
||||||
|
))
|
||||||
: null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
</InfiniteScroll>
|
</InfiniteScroll>
|
||||||
@ -358,125 +273,6 @@ export const ProfilePage = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WalletAssetDisplay = ({ asset }: { asset: WalletAsset }) => {
|
|
||||||
const sellAssets = useSellAsset((state) => state.sellAssets)
|
|
||||||
const selectSellAsset = useSellAsset((state) => state.selectSellAsset)
|
|
||||||
const removeSellAsset = useSellAsset((state) => state.removeSellAsset)
|
|
||||||
const cartExpanded = useBag((state) => state.bagExpanded)
|
|
||||||
const toggleCart = useBag((state) => state.toggleBag)
|
|
||||||
const isMobile = useIsMobile()
|
|
||||||
|
|
||||||
const [boxHovered, toggleBoxHovered] = useReducer((state) => {
|
|
||||||
return !state
|
|
||||||
}, false)
|
|
||||||
const [buttonHovered, toggleButtonHovered] = useReducer((state) => {
|
|
||||||
return !state
|
|
||||||
}, false)
|
|
||||||
|
|
||||||
const isSelected = useMemo(() => {
|
|
||||||
return sellAssets.some((item) => asset.id === item.id)
|
|
||||||
}, [asset, sellAssets])
|
|
||||||
|
|
||||||
const handleSelect = () => {
|
|
||||||
isSelected ? removeSellAsset(asset) : selectSellAsset(asset)
|
|
||||||
if (
|
|
||||||
!cartExpanded &&
|
|
||||||
!sellAssets.find(
|
|
||||||
(x) => x.tokenId === asset.tokenId && x.asset_contract.address === asset.asset_contract.address
|
|
||||||
) &&
|
|
||||||
!isMobile
|
|
||||||
)
|
|
||||||
toggleCart()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link
|
|
||||||
to={`/nfts/asset/${asset.asset_contract.address}/${asset.tokenId}?origin=profile`}
|
|
||||||
style={{ textDecoration: 'none' }}
|
|
||||||
>
|
|
||||||
<Column
|
|
||||||
color={'textPrimary'}
|
|
||||||
className={subheadSmall}
|
|
||||||
onMouseEnter={toggleBoxHovered}
|
|
||||||
onMouseLeave={toggleBoxHovered}
|
|
||||||
>
|
|
||||||
<Box
|
|
||||||
as="img"
|
|
||||||
alt={asset.name}
|
|
||||||
width="full"
|
|
||||||
borderTopLeftRadius="20"
|
|
||||||
borderTopRightRadius="20"
|
|
||||||
src={asset.image_url || '/nft/svgs/image-placeholder.svg'}
|
|
||||||
style={{ aspectRatio: '1' }}
|
|
||||||
/>
|
|
||||||
<Column
|
|
||||||
position="relative"
|
|
||||||
borderBottomLeftRadius="20"
|
|
||||||
borderBottomRightRadius="20"
|
|
||||||
transition="250"
|
|
||||||
backgroundColor={boxHovered ? 'backgroundOutline' : 'backgroundSurface'}
|
|
||||||
paddingY="12"
|
|
||||||
paddingX="12"
|
|
||||||
>
|
|
||||||
<Box className={subheadSmall} overflow="hidden" textOverflow="ellipsis" marginTop="4" lineHeight="20">
|
|
||||||
{asset.name ? asset.name : `#${asset.tokenId}`}
|
|
||||||
</Box>
|
|
||||||
<Box fontSize="12" marginTop="4" lineHeight="16" overflow="hidden" textOverflow="ellipsis">
|
|
||||||
{asset.collection?.name}
|
|
||||||
{asset.collectionIsVerified ? <VerifiedIcon className={styles.verifiedBadge} /> : null}
|
|
||||||
</Box>
|
|
||||||
<Box as="span" fontSize="12" lineHeight="16" color="textSecondary" marginTop="8">
|
|
||||||
Last:
|
|
||||||
{asset.lastPrice ? (
|
|
||||||
<>
|
|
||||||
{formatEth(asset.lastPrice)}
|
|
||||||
ETH
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Box as="span" marginLeft="6">
|
|
||||||
—
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
<Box as="span" fontSize="12" lineHeight="16" color="textSecondary" marginTop="4">
|
|
||||||
Floor:
|
|
||||||
{asset.floorPrice ? (
|
|
||||||
<>
|
|
||||||
{formatEth(asset.floorPrice)}
|
|
||||||
ETH
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<Box as="span" marginLeft="8">
|
|
||||||
—
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
</Box>
|
|
||||||
<Box
|
|
||||||
marginTop="12"
|
|
||||||
textAlign="center"
|
|
||||||
width="full"
|
|
||||||
borderRadius="12"
|
|
||||||
paddingY="8"
|
|
||||||
transition="250"
|
|
||||||
color={buttonHovered ? 'textPrimary' : isSelected ? 'red400' : 'genieBlue'}
|
|
||||||
backgroundColor={buttonHovered ? (isSelected ? 'red400' : 'genieBlue') : 'backgroundSurface'}
|
|
||||||
className={subheadSmall}
|
|
||||||
onMouseEnter={toggleButtonHovered}
|
|
||||||
onMouseLeave={toggleButtonHovered}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
handleSelect()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{isSelected ? 'Remove' : 'Select'}
|
|
||||||
</Box>
|
|
||||||
</Column>
|
|
||||||
</Column>
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const SelectAllButton = () => {
|
const SelectAllButton = () => {
|
||||||
const [isAllSelected, setIsAllSelected] = useState(false)
|
const [isAllSelected, setIsAllSelected] = useState(false)
|
||||||
const displayAssets = useWalletCollections((state) => state.displayAssets)
|
const displayAssets = useWalletCollections((state) => state.displayAssets)
|
||||||
@ -497,23 +293,13 @@ const SelectAllButton = () => {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
display="flex"
|
marginRight="12"
|
||||||
flexShrink="0"
|
paddingX="12"
|
||||||
flexDirection="row"
|
paddingY="10"
|
||||||
alignItems="center"
|
|
||||||
marginLeft={{ sm: '8', md: 'auto' }}
|
|
||||||
borderRadius="12"
|
|
||||||
backgroundColor="backgroundOutline"
|
|
||||||
fontWeight="medium"
|
|
||||||
height="44"
|
|
||||||
paddingTop="12"
|
|
||||||
paddingBottom="12"
|
|
||||||
paddingRight="16"
|
|
||||||
paddingLeft="16"
|
|
||||||
cursor="pointer"
|
cursor="pointer"
|
||||||
color="textPrimary"
|
color="textSecondary"
|
||||||
onClick={toggleAllSelected}
|
onClick={toggleAllSelected}
|
||||||
className={clsx(`${subheadSmall} ${isAllSelected ? styles.buttonSelected : null}`)}
|
className={buttonTextMedium}
|
||||||
>
|
>
|
||||||
{isAllSelected ? 'Deselect all' : 'Select all'}
|
{isAllSelected ? 'Deselect all' : 'Select all'}
|
||||||
</Box>
|
</Box>
|
||||||
@ -602,29 +388,3 @@ const CollectionFilterItem = ({
|
|||||||
</Row>
|
</Row>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const CollectionSearch = ({
|
|
||||||
searchText,
|
|
||||||
setSearchText,
|
|
||||||
}: {
|
|
||||||
searchText: string
|
|
||||||
setSearchText: Dispatch<SetStateAction<string>>
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<Box
|
|
||||||
as="input"
|
|
||||||
borderColor={{ default: 'backgroundOutline', focus: 'genieBlue' }}
|
|
||||||
borderWidth="1px"
|
|
||||||
borderStyle="solid"
|
|
||||||
borderRadius="8"
|
|
||||||
padding="12"
|
|
||||||
backgroundColor="backgroundSurface"
|
|
||||||
fontSize="14"
|
|
||||||
color={{ placeholder: 'textSecondary', default: 'textPrimary' }}
|
|
||||||
placeholder="Search by name"
|
|
||||||
value={searchText}
|
|
||||||
width="full"
|
|
||||||
onChange={(e: FormEvent<HTMLInputElement>) => setSearchText(e.currentTarget.value)}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
129
src/nft/components/profile/view/WalletAssetDisplay.tsx
Normal file
129
src/nft/components/profile/view/WalletAssetDisplay.tsx
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
import { Box } from 'nft/components/Box'
|
||||||
|
import { Column } from 'nft/components/Flex'
|
||||||
|
import { VerifiedIcon } from 'nft/components/icons'
|
||||||
|
import { subheadSmall } from 'nft/css/common.css'
|
||||||
|
import { useBag, useIsMobile, useSellAsset } from 'nft/hooks'
|
||||||
|
import { DetailsOrigin, WalletAsset } from 'nft/types'
|
||||||
|
import { formatEth, getAssetHref } from 'nft/utils'
|
||||||
|
import { useMemo, useReducer } from 'react'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
|
import * as styles from './ProfilePage.css'
|
||||||
|
|
||||||
|
export const WalletAssetDisplay = ({ asset, isSellMode }: { asset: WalletAsset; isSellMode: boolean }) => {
|
||||||
|
const sellAssets = useSellAsset((state) => state.sellAssets)
|
||||||
|
const selectSellAsset = useSellAsset((state) => state.selectSellAsset)
|
||||||
|
const removeSellAsset = useSellAsset((state) => state.removeSellAsset)
|
||||||
|
const cartExpanded = useBag((state) => state.bagExpanded)
|
||||||
|
const toggleCart = useBag((state) => state.toggleBag)
|
||||||
|
const isMobile = useIsMobile()
|
||||||
|
|
||||||
|
const [boxHovered, toggleBoxHovered] = useReducer((state) => {
|
||||||
|
return !state
|
||||||
|
}, false)
|
||||||
|
const [buttonHovered, toggleButtonHovered] = useReducer((state) => {
|
||||||
|
return !state
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
const isSelected = useMemo(() => {
|
||||||
|
return sellAssets.some((item) => asset.id === item.id)
|
||||||
|
}, [asset, sellAssets])
|
||||||
|
|
||||||
|
const handleSelect = () => {
|
||||||
|
isSelected ? removeSellAsset(asset) : selectSellAsset(asset)
|
||||||
|
if (
|
||||||
|
!cartExpanded &&
|
||||||
|
!sellAssets.find(
|
||||||
|
(x) => x.tokenId === asset.tokenId && x.asset_contract.address === asset.asset_contract.address
|
||||||
|
) &&
|
||||||
|
!isMobile
|
||||||
|
)
|
||||||
|
toggleCart()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Link to={getAssetHref(asset, DetailsOrigin.PROFILE)} style={{ textDecoration: 'none' }}>
|
||||||
|
<Column
|
||||||
|
color={'textPrimary'}
|
||||||
|
className={subheadSmall}
|
||||||
|
onMouseEnter={toggleBoxHovered}
|
||||||
|
onMouseLeave={toggleBoxHovered}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
as="img"
|
||||||
|
alt={asset.name}
|
||||||
|
width="full"
|
||||||
|
borderTopLeftRadius="20"
|
||||||
|
borderTopRightRadius="20"
|
||||||
|
src={asset.image_url ?? '/nft/svgs/image-placeholder.svg'}
|
||||||
|
style={{ aspectRatio: '1' }}
|
||||||
|
/>
|
||||||
|
<Column
|
||||||
|
position="relative"
|
||||||
|
borderBottomLeftRadius="20"
|
||||||
|
borderBottomRightRadius="20"
|
||||||
|
transition="250"
|
||||||
|
backgroundColor={boxHovered ? 'backgroundOutline' : 'backgroundSurface'}
|
||||||
|
paddingY="12"
|
||||||
|
paddingX="12"
|
||||||
|
>
|
||||||
|
<Box className={subheadSmall} overflow="hidden" textOverflow="ellipsis" marginTop="4" lineHeight="20">
|
||||||
|
{asset.name ? asset.name : `#${asset.tokenId}`}
|
||||||
|
</Box>
|
||||||
|
<Box fontSize="12" marginTop="4" lineHeight="16" overflow="hidden" textOverflow="ellipsis">
|
||||||
|
{asset.collection?.name}
|
||||||
|
{asset.collectionIsVerified ? <VerifiedIcon className={styles.verifiedBadge} /> : null}
|
||||||
|
</Box>
|
||||||
|
<Box as="span" fontSize="12" lineHeight="16" color="textSecondary" marginTop="8">
|
||||||
|
Last:
|
||||||
|
{asset.lastPrice ? (
|
||||||
|
<>
|
||||||
|
{formatEth(asset.lastPrice)}
|
||||||
|
ETH
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Box as="span" marginLeft="6">
|
||||||
|
—
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
<Box as="span" fontSize="12" lineHeight="16" color="textSecondary" marginTop="4">
|
||||||
|
Floor:
|
||||||
|
{asset.floorPrice ? (
|
||||||
|
<>
|
||||||
|
{formatEth(asset.floorPrice)}
|
||||||
|
ETH
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<Box as="span" marginLeft="8">
|
||||||
|
—
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
{isSellMode && (
|
||||||
|
<Box
|
||||||
|
marginTop="12"
|
||||||
|
textAlign="center"
|
||||||
|
width="full"
|
||||||
|
borderRadius="12"
|
||||||
|
paddingY="8"
|
||||||
|
transition="250"
|
||||||
|
color={buttonHovered ? 'textPrimary' : isSelected ? 'red400' : 'genieBlue'}
|
||||||
|
backgroundColor={buttonHovered ? (isSelected ? 'red400' : 'genieBlue') : 'backgroundSurface'}
|
||||||
|
className={subheadSmall}
|
||||||
|
onMouseEnter={toggleButtonHovered}
|
||||||
|
onMouseLeave={toggleButtonHovered}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
handleSelect()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isSelected ? 'Remove' : 'Select'}
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Column>
|
||||||
|
</Column>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
import { DetailsOrigin, GenieAsset } from 'nft/types'
|
import { DetailsOrigin, GenieAsset, WalletAsset } from 'nft/types'
|
||||||
|
|
||||||
export function getRarityStatus(
|
export function getRarityStatus(
|
||||||
rarityStatusCache: Map<string, boolean>,
|
rarityStatusCache: Map<string, boolean>,
|
||||||
@ -17,6 +17,10 @@ export function getRarityStatus(
|
|||||||
return hasRarity
|
return hasRarity
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAssetHref = (asset: GenieAsset, origin?: DetailsOrigin) => {
|
export const getAssetHref = (asset: GenieAsset | WalletAsset, origin?: DetailsOrigin) => {
|
||||||
return `/nfts/asset/${asset.address}/${asset.tokenId}${origin ? `?origin=${origin}` : ''}`
|
const address =
|
||||||
|
(asset as GenieAsset).address !== undefined
|
||||||
|
? (asset as GenieAsset).address
|
||||||
|
: (asset as WalletAsset).asset_contract.address
|
||||||
|
return `/nfts/asset/${address}/${asset.tokenId}${origin ? `?origin=${origin}` : ''}`
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user