Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
I
interface
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
LuckySwap
interface
Commits
4b1b6098
Unverified
Commit
4b1b6098
authored
Nov 04, 2022
by
aballerr
Committed by
GitHub
Nov 04, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: Details implementation (#5059)
* Details Page Update
parent
53a6acc1
Changes
25
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
1219 additions
and
542 deletions
+1219
-542
SuggestionRow.tsx
src/components/NavBar/SuggestionRow.tsx
+1
-1
Collection.ts
src/graphql/data/nft/Collection.ts
+3
-4
Details.ts
src/graphql/data/nft/Details.ts
+5
-6
Bag.tsx
src/nft/components/bag/Bag.tsx
+17
-1
Activity.css.ts
src/nft/components/collection/Activity.css.ts
+0
-1
Activity.tsx
src/nft/components/collection/Activity.tsx
+1
-1
ActivityCells.tsx
src/nft/components/collection/ActivityCells.tsx
+18
-6
CollectionStats.tsx
src/nft/components/collection/CollectionStats.tsx
+5
-5
AssetActivity.tsx
src/nft/components/details/AssetActivity.tsx
+182
-0
AssetDetails.css.ts
src/nft/components/details/AssetDetails.css.ts
+5
-8
AssetDetails.tsx
src/nft/components/details/AssetDetails.tsx
+418
-346
AssetPriceDetails.tsx
src/nft/components/details/AssetPriceDetails.tsx
+178
-52
DetailsContainer.tsx
src/nft/components/details/DetailsContainer.tsx
+132
-0
InfoContainer.tsx
src/nft/components/details/InfoContainer.tsx
+89
-0
Traits.css.ts
src/nft/components/details/Traits.css.ts
+0
-18
Traits.tsx
src/nft/components/details/Traits.tsx
+0
-62
TraitsContainer.tsx
src/nft/components/details/TraitsContainer.tsx
+97
-0
icons.tsx
src/nft/components/icons.tsx
+2
-3
Asset.tsx
src/nft/pages/asset/Asset.tsx
+23
-4
ActivityFetcher.ts
src/nft/queries/genie/ActivityFetcher.ts
+8
-4
SingleAssetFetcher.ts
src/nft/queries/genie/SingleAssetFetcher.ts
+10
-1
collection.ts
src/nft/types/collection/collection.ts
+2
-1
common.ts
src/nft/types/common/common.ts
+18
-14
fetchPrice.ts
src/nft/utils/fetchPrice.ts
+4
-3
putCommas.ts
src/nft/utils/putCommas.ts
+1
-1
No files found.
src/components/NavBar/SuggestionRow.tsx
View file @
4b1b6098
...
@@ -93,7 +93,7 @@ export const CollectionRow = ({
...
@@ -93,7 +93,7 @@ export const CollectionRow = ({
<
Box
className=
{
styles
.
primaryText
}
>
{
collection
.
name
}
</
Box
>
<
Box
className=
{
styles
.
primaryText
}
>
{
collection
.
name
}
</
Box
>
{
collection
.
isVerified
&&
<
VerifiedIcon
className=
{
styles
.
suggestionIcon
}
/>
}
{
collection
.
isVerified
&&
<
VerifiedIcon
className=
{
styles
.
suggestionIcon
}
/>
}
</
Row
>
</
Row
>
<
Box
className=
{
styles
.
secondaryText
}
>
{
putCommas
(
collection
.
stats
?.
total_supply
)
}
items
</
Box
>
<
Box
className=
{
styles
.
secondaryText
}
>
{
putCommas
(
collection
?.
stats
?.
total_supply
??
0
)
}
items
</
Box
>
</
Column
>
</
Column
>
</
Row
>
</
Row
>
{
collection
.
stats
?.
floor_price
?
(
{
collection
.
stats
?.
floor_price
?
(
...
...
src/graphql/data/nft/Collection.ts
View file @
4b1b6098
import
graphql
from
'
babel-plugin-relay/macro
'
import
graphql
from
'
babel-plugin-relay/macro
'
import
{
Trait
}
from
'
nft/hooks/useCollectionFilters
'
import
{
GenieCollection
,
Trait
}
from
'
nft/types
'
import
{
GenieCollection
}
from
'
nft/types
'
import
{
useLazyLoadQuery
}
from
'
react-relay
'
import
{
useLazyLoadQuery
}
from
'
react-relay
'
import
{
CollectionQuery
}
from
'
./__generated__/CollectionQuery.graphql
'
import
{
CollectionQuery
}
from
'
./__generated__/CollectionQuery.graphql
'
...
@@ -122,8 +121,8 @@ export function useCollectionQuery(address: string): GenieCollection | undefined
...
@@ -122,8 +121,8 @@ export function useCollectionQuery(address: string): GenieCollection | undefined
:
{},
:
{},
traits
,
traits
,
// marketplaceCount: { marketplace: string; count: number }[], // TODO add when backend supports
// marketplaceCount: { marketplace: string; count: number }[], // TODO add when backend supports
imageUrl
:
queryCollection
?.
image
?.
url
,
imageUrl
:
queryCollection
?.
image
?.
url
??
''
,
twitter
:
queryCollection
?.
twitterName
??
undefined
,
twitter
Url
:
queryCollection
?.
twitterName
??
''
,
instagram
:
queryCollection
?.
instagramName
??
undefined
,
instagram
:
queryCollection
?.
instagramName
??
undefined
,
discordUrl
:
queryCollection
?.
discordUrl
??
undefined
,
discordUrl
:
queryCollection
?.
discordUrl
??
undefined
,
externalUrl
:
queryCollection
?.
homepageUrl
??
undefined
,
externalUrl
:
queryCollection
?.
homepageUrl
??
undefined
,
...
...
src/graphql/data/nft/Details.ts
View file @
4b1b6098
import
{
parseEther
}
from
'
@ethersproject/units
'
import
{
parseEther
}
from
'
@ethersproject/units
'
import
graphql
from
'
babel-plugin-relay/macro
'
import
graphql
from
'
babel-plugin-relay/macro
'
import
{
Trait
}
from
'
nft/hooks
'
import
{
CollectionInfoForAsset
,
GenieAsset
,
SellOrder
,
TokenType
}
from
'
nft/types
'
import
{
CollectionInfoForAsset
,
GenieAsset
,
SellOrder
,
TokenType
}
from
'
nft/types
'
import
{
useLazyLoadQuery
}
from
'
react-relay
'
import
{
useLazyLoadQuery
}
from
'
react-relay
'
...
@@ -141,14 +140,14 @@ export function useDetailsQuery(address: string, tokenId: string): [GenieAsset,
...
@@ -141,14 +140,14 @@ export function useDetailsQuery(address: string, tokenId: string): [GenieAsset,
})
})
:
undefined
,
:
undefined
,
},
},
owner
:
asset
?.
ownerAddress
??
undefined
,
owner
:
{
address
:
asset
?.
ownerAddress
??
''
}
,
creator
:
{
creator
:
{
profile_img_url
:
asset
?.
creator
?.
profileImage
?.
url
,
profile_img_url
:
asset
?.
creator
?.
profileImage
?.
url
??
''
,
address
:
asset
?.
creator
?.
address
,
address
:
asset
?.
creator
?.
address
??
''
,
},
},
metadataUrl
:
asset
?.
metadataUrl
??
undefined
,
metadataUrl
:
asset
?.
metadataUrl
??
''
,
traits
:
asset
?.
traits
?.
map
((
trait
)
=>
{
traits
:
asset
?.
traits
?.
map
((
trait
)
=>
{
return
{
trait_type
:
trait
.
name
??
undefined
,
trait_value
:
trait
.
value
??
undefined
}
as
Trait
return
{
trait_type
:
trait
.
name
??
''
,
trait_value
:
trait
.
value
??
''
}
}),
}),
},
},
{
{
...
...
src/nft/components/bag/Bag.tsx
View file @
4b1b6098
...
@@ -29,6 +29,7 @@ import { combineBuyItemsWithTxRoute } from 'nft/utils/txRoute/combineItemsWithTx
...
@@ -29,6 +29,7 @@ import { combineBuyItemsWithTxRoute } from 'nft/utils/txRoute/combineItemsWithTx
import
{
useCallback
,
useEffect
,
useMemo
,
useRef
,
useState
}
from
'
react
'
import
{
useCallback
,
useEffect
,
useMemo
,
useRef
,
useState
}
from
'
react
'
import
{
useQuery
,
useQueryClient
}
from
'
react-query
'
import
{
useQuery
,
useQueryClient
}
from
'
react-query
'
import
{
useLocation
}
from
'
react-router-dom
'
import
{
useLocation
}
from
'
react-router-dom
'
import
styled
from
'
styled-components/macro
'
import
*
as
styles
from
'
./Bag.css
'
import
*
as
styles
from
'
./Bag.css
'
import
{
BagContent
}
from
'
./BagContent
'
import
{
BagContent
}
from
'
./BagContent
'
...
@@ -41,6 +42,15 @@ interface SeparatorProps {
...
@@ -41,6 +42,15 @@ interface SeparatorProps {
show
?:
boolean
show
?:
boolean
}
}
const
DetailsPageBackground
=
styled
.
div
`
position: fixed;
background: rgba(0, 0, 0, 0.7);
backdrop-filter: blur(12px);
top: 72px;
width: 100%;
height: 100%;
`
const
ScrollingIndicator
=
({
top
,
show
}:
SeparatorProps
)
=>
(
const
ScrollingIndicator
=
({
top
,
show
}:
SeparatorProps
)
=>
(
<
Box
<
Box
marginX=
"16"
marginX=
"16"
...
@@ -82,6 +92,8 @@ const Bag = () => {
...
@@ -82,6 +92,8 @@ const Bag = () => {
const
shouldShowBag
=
isNFTPage
||
isProfilePage
const
shouldShowBag
=
isNFTPage
||
isProfilePage
const
isMobile
=
useIsMobile
()
const
isMobile
=
useIsMobile
()
const
isDetailsPage
=
pathname
.
includes
(
'
/nfts/asset/
'
)
const
sendTransaction
=
useSendTransaction
((
state
)
=>
state
.
sendTransaction
)
const
sendTransaction
=
useSendTransaction
((
state
)
=>
state
.
sendTransaction
)
const
transactionState
=
useSendTransaction
((
state
)
=>
state
.
state
)
const
transactionState
=
useSendTransaction
((
state
)
=>
state
.
state
)
const
setTransactionState
=
useSendTransaction
((
state
)
=>
state
.
setState
)
const
setTransactionState
=
useSendTransaction
((
state
)
=>
state
.
setState
)
...
@@ -304,7 +316,11 @@ const Bag = () => {
...
@@ -304,7 +316,11 @@ const Bag = () => {
<
ListingModal
/>
<
ListingModal
/>
)
}
)
}
</
Column
>
</
Column
>
{
isOpen
&&
<
Overlay
onClick=
{
()
=>
(
!
bagIsLocked
?
setModalIsOpen
(
false
)
:
undefined
)
}
/>
}
{
isDetailsPage
?
(
<
DetailsPageBackground
onClick=
{
toggleBag
}
/>
)
:
(
isOpen
&&
<
Overlay
onClick=
{
()
=>
(
!
bagIsLocked
?
setModalIsOpen
(
false
)
:
undefined
)
}
/>
)
}
</
Portal
>
</
Portal
>
)
:
null
}
)
:
null
}
</>
</>
...
...
src/nft/components/collection/Activity.css.ts
View file @
4b1b6098
...
@@ -79,7 +79,6 @@ export const detailsName = style([
...
@@ -79,7 +79,6 @@ export const detailsName = style([
export
const
eventDetail
=
style
([
export
const
eventDetail
=
style
([
subhead
,
subhead
,
sprinkles
({
sprinkles
({
marginBottom
:
'
4
'
,
gap
:
'
8
'
,
gap
:
'
8
'
,
}),
}),
{
{
...
...
src/nft/components/collection/Activity.tsx
View file @
4b1b6098
...
@@ -48,7 +48,7 @@ const initialFilterState = {
...
@@ -48,7 +48,7 @@ const initialFilterState = {
[
ActivityEventType
.
CancelListing
]:
false
,
[
ActivityEventType
.
CancelListing
]:
false
,
}
}
const
reduceFilters
=
(
state
:
typeof
initialFilterState
,
action
:
{
eventType
:
ActivityEventType
})
=>
{
export
const
reduceFilters
=
(
state
:
typeof
initialFilterState
,
action
:
{
eventType
:
ActivityEventType
})
=>
{
return
{
...
state
,
[
action
.
eventType
]:
!
state
[
action
.
eventType
]
}
return
{
...
state
,
[
action
.
eventType
]:
!
state
[
action
.
eventType
]
}
}
}
...
...
src/nft/components/collection/ActivityCells.tsx
View file @
4b1b6098
...
@@ -10,6 +10,7 @@ import {
...
@@ -10,6 +10,7 @@ import {
ActivityListingIcon
,
ActivityListingIcon
,
ActivitySaleIcon
,
ActivitySaleIcon
,
ActivityTransferIcon
,
ActivityTransferIcon
,
CancelListingIcon
,
RarityVerifiedIcon
,
RarityVerifiedIcon
,
}
from
'
nft/components/icons
'
}
from
'
nft/components/icons
'
import
{
import
{
...
@@ -157,7 +158,7 @@ export const AddressCell = ({ address, desktopLBreakpoint, chainId }: AddressCel
...
@@ -157,7 +158,7 @@ export const AddressCell = ({ address, desktopLBreakpoint, chainId }: AddressCel
)
)
}
}
const
MarketplaceIcon
=
({
marketplace
}:
{
marketplace
:
Markets
})
=>
{
export
const
MarketplaceIcon
=
({
marketplace
}:
{
marketplace
:
Markets
})
=>
{
return
(
return
(
<
Box
<
Box
as=
"img"
as=
"img"
...
@@ -204,8 +205,9 @@ interface EventCellProps {
...
@@ -204,8 +205,9 @@ interface EventCellProps {
eventType
:
ActivityEventType
eventType
:
ActivityEventType
eventTimestamp
?:
number
eventTimestamp
?:
number
eventTransactionHash
?:
string
eventTransactionHash
?:
string
eventOnly
?:
boolean
price
?:
string
price
?:
string
isMobile
:
boolean
isMobile
?
:
boolean
}
}
const
renderEventIcon
=
(
eventType
:
ActivityEventType
)
=>
{
const
renderEventIcon
=
(
eventType
:
ActivityEventType
)
=>
{
...
@@ -216,6 +218,8 @@ const renderEventIcon = (eventType: ActivityEventType) => {
...
@@ -216,6 +218,8 @@ const renderEventIcon = (eventType: ActivityEventType) => {
return
<
ActivitySaleIcon
width=
{
16
}
height=
{
16
}
/>
return
<
ActivitySaleIcon
width=
{
16
}
height=
{
16
}
/>
case
ActivityEventType
.
Transfer
:
case
ActivityEventType
.
Transfer
:
return
<
ActivityTransferIcon
width=
{
16
}
height=
{
16
}
/>
return
<
ActivityTransferIcon
width=
{
16
}
height=
{
16
}
/>
case
ActivityEventType
.
CancelListing
:
return
<
CancelListingIcon
width=
{
16
}
height=
{
16
}
/>
default
:
default
:
return
null
return
null
}
}
...
@@ -237,13 +241,20 @@ const eventColors = (eventType: ActivityEventType) => {
...
@@ -237,13 +241,20 @@ const eventColors = (eventType: ActivityEventType) => {
[
ActivityEventType
.
Listing
]:
'
gold
'
,
[
ActivityEventType
.
Listing
]:
'
gold
'
,
[
ActivityEventType
.
Sale
]:
'
green
'
,
[
ActivityEventType
.
Sale
]:
'
green
'
,
[
ActivityEventType
.
Transfer
]:
'
violet
'
,
[
ActivityEventType
.
Transfer
]:
'
violet
'
,
[
ActivityEventType
.
CancelListing
]:
'
error
'
,
[
ActivityEventType
.
CancelListing
]:
'
accentFailure
'
,
}
}
return
activityEvents
[
eventType
]
as
'
gold
'
|
'
green
'
|
'
violet
'
|
'
accentFailure
'
return
activityEvents
[
eventType
]
as
'
gold
'
|
'
green
'
|
'
violet
'
|
'
accentFailure
'
}
}
export
const
EventCell
=
({
eventType
,
eventTimestamp
,
eventTransactionHash
,
price
,
isMobile
}:
EventCellProps
)
=>
{
export
const
EventCell
=
({
eventType
,
eventTimestamp
,
eventTransactionHash
,
eventOnly
,
price
,
isMobile
,
}:
EventCellProps
)
=>
{
const
formattedPrice
=
useMemo
(()
=>
(
price
?
putCommas
(
formatEthPrice
(
price
))?.
toString
()
:
null
),
[
price
])
const
formattedPrice
=
useMemo
(()
=>
(
price
?
putCommas
(
formatEthPrice
(
price
))?.
toString
()
:
null
),
[
price
])
return
(
return
(
<
Column
height=
"full"
justifyContent=
"center"
gap=
"4"
>
<
Column
height=
"full"
justifyContent=
"center"
gap=
"4"
>
...
@@ -251,7 +262,7 @@ export const EventCell = ({ eventType, eventTimestamp, eventTransactionHash, pri
...
@@ -251,7 +262,7 @@ export const EventCell = ({ eventType, eventTimestamp, eventTransactionHash, pri
{
renderEventIcon
(
eventType
)
}
{
renderEventIcon
(
eventType
)
}
{
ActivityEventTypeDisplay
[
eventType
]
}
{
ActivityEventTypeDisplay
[
eventType
]
}
</
Row
>
</
Row
>
{
eventTimestamp
&&
isValidDate
(
eventTimestamp
)
&&
!
isMobile
&&
(
{
eventTimestamp
&&
isValidDate
(
eventTimestamp
)
&&
!
isMobile
&&
!
eventOnly
&&
(
<
Row
className=
{
styles
.
eventTime
}
>
<
Row
className=
{
styles
.
eventTime
}
>
{
getTimeDifference
(
eventTimestamp
.
toString
())
}
{
getTimeDifference
(
eventTimestamp
.
toString
())
}
{
eventTransactionHash
&&
<
ExternalLinkIcon
transactionHash=
{
eventTransactionHash
}
/>
}
{
eventTransactionHash
&&
<
ExternalLinkIcon
transactionHash=
{
eventTransactionHash
}
/>
}
...
@@ -301,9 +312,10 @@ interface RankingProps {
...
@@ -301,9 +312,10 @@ interface RankingProps {
rarity
:
TokenRarity
rarity
:
TokenRarity
collectionName
:
string
collectionName
:
string
rarityVerified
:
boolean
rarityVerified
:
boolean
details
?:
boolean
}
}
const
Ranking
=
({
rarity
,
collectionName
,
rarityVerified
}:
RankingProps
)
=>
{
const
Ranking
=
({
details
,
rarity
,
collectionName
,
rarityVerified
}:
RankingProps
)
=>
{
const
rarityProviderLogo
=
getRarityProviderLogo
(
rarity
.
source
)
const
rarityProviderLogo
=
getRarityProviderLogo
(
rarity
.
source
)
return
(
return
(
...
...
src/nft/components/collection/CollectionStats.tsx
View file @
4b1b6098
...
@@ -76,8 +76,8 @@ const MobileSocialsPopover = ({
...
@@ -76,8 +76,8 @@ const MobileSocialsPopover = ({
</
Box
>
</
Box
>
</
MobileSocialsIcon
>
</
MobileSocialsIcon
>
)
:
null
}
)
:
null
}
{
collectionStats
.
twitter
?
(
{
collectionStats
.
twitter
Url
?
(
<
MobileSocialsIcon
href=
{
'
https://twitter.com/
'
+
collectionStats
.
twitter
}
>
<
MobileSocialsIcon
href=
{
'
https://twitter.com/
'
+
collectionStats
.
twitter
Url
}
>
<
Box
margin=
"auto"
paddingTop=
"6"
>
<
Box
margin=
"auto"
paddingTop=
"6"
>
<
TwitterIcon
<
TwitterIcon
fill=
{
themeVars
.
colors
.
textSecondary
}
fill=
{
themeVars
.
colors
.
textSecondary
}
...
@@ -161,8 +161,8 @@ const CollectionName = ({
...
@@ -161,8 +161,8 @@ const CollectionName = ({
/>
/>
</
SocialsIcon
>
</
SocialsIcon
>
)
:
null
}
)
:
null
}
{
collectionStats
.
twitter
?
(
{
collectionStats
.
twitter
Url
?
(
<
SocialsIcon
href=
{
'
https://twitter.com/
'
+
collectionStats
.
twitter
}
>
<
SocialsIcon
href=
{
'
https://twitter.com/
'
+
collectionStats
.
twitter
Url
}
>
<
TwitterIcon
<
TwitterIcon
fill=
{
themeVars
.
colors
.
textSecondary
}
fill=
{
themeVars
.
colors
.
textSecondary
}
color=
{
themeVars
.
colors
.
textSecondary
}
color=
{
themeVars
.
colors
.
textSecondary
}
...
@@ -186,7 +186,7 @@ const CollectionName = ({
...
@@ -186,7 +186,7 @@ const CollectionName = ({
</
Row
>
</
Row
>
{
isMobile
&&
{
isMobile
&&
(
collectionStats
.
discordUrl
||
(
collectionStats
.
discordUrl
||
collectionStats
.
twitter
||
collectionStats
.
twitter
Url
||
collectionStats
.
instagram
||
collectionStats
.
instagram
||
collectionStats
.
externalUrl
)
&&
(
collectionStats
.
externalUrl
)
&&
(
<
MobileSocialsPopover
<
MobileSocialsPopover
...
...
src/nft/components/details/AssetActivity.tsx
0 → 100644
View file @
4b1b6098
import
{
ActivityEventResponse
}
from
'
nft/types
'
import
{
shortenAddress
}
from
'
nft/utils/address
'
import
{
formatEthPrice
}
from
'
nft/utils/currency
'
import
{
getTimeDifference
}
from
'
nft/utils/date
'
import
{
putCommas
}
from
'
nft/utils/putCommas
'
import
styled
from
'
styled-components/macro
'
import
{
EventCell
}
from
'
../collection/ActivityCells
'
import
{
MarketplaceIcon
}
from
'
../collection/ActivityCells
'
const
TR
=
styled
.
tr
`
border-bottom:
${({
theme
})
=>
`1px solid
${
theme
.
backgroundOutline
}
`
}
;
width: 100%;
&:last-child {
border-bottom: none;
}
`
const
TH
=
styled
.
th
`
color:
${({
theme
})
=>
theme
.
textSecondary
}
;
font-weight: 600;
font-size: 14px;
line-height: 20px;
width: 20%;
@media (max-width: 960px) {
&:nth-child(4) {
display: none;
}
}
@media (max-width: 720px) {
&:nth-child(2) {
display: none;
}
}
`
const
Table
=
styled
.
table
`
border-collapse: collapse;
text-align: left;
width: 100%;
`
const
TD
=
styled
.
td
`
height: 56px;
padding: 8px 0px;
text-align: left;
vertical-align: middle;
width: 20%;
@media (max-width: 960px) {
&:nth-child(4) {
display: none;
}
}
@media (max-width: 720px) {
&:nth-child(2) {
display: none;
}
}
`
const
PriceContainer
=
styled
.
div
`
align-items: center;
display: flex;
gap: 8px;
`
const
Link
=
styled
.
a
`
color:
${({
theme
})
=>
theme
.
textPrimary
}
;
text-decoration: none;
&:hover {
opacity:
${({
theme
})
=>
theme
.
opacity
.
hover
}
;
}
&:active {
opacity:
${({
theme
})
=>
theme
.
opacity
.
click
}
;
}
transition:
${({
theme
:
{
transition
:
{
duration
,
timing
},
},
})
=>
`opacity
${
duration
.
medium
}
${
timing
.
ease
}
`
}
;
`
const
ActivityContainer
=
styled
.
div
`
max-height: 310px;
overflow: auto;
// Firefox scrollbar styling
scrollbar-width: thin;
scrollbar-color:
${({
theme
})
=>
`
${
theme
.
backgroundOutline
}
transparent`
}
;
// safari and chrome scrollbar styling
::-webkit-scrollbar {
background: transparent;
width: 4px;
}
::-webkit-scrollbar-thumb {
background:
${({
theme
})
=>
theme
.
backgroundOutline
}
;
border-radius: 8px;
}
`
const
AssetActivity
=
({
eventsData
}:
{
eventsData
:
ActivityEventResponse
|
undefined
})
=>
{
return
(
<
ActivityContainer
id=
"activityContainer"
>
<
Table
>
<
thead
>
<
TR
>
<
TH
>
Event
</
TH
>
<
TH
>
Price
</
TH
>
<
TH
>
By
</
TH
>
<
TH
>
To
</
TH
>
<
TH
>
Time
</
TH
>
</
TR
>
</
thead
>
<
tbody
>
{
eventsData
?.
events
&&
eventsData
.
events
.
map
((
event
,
index
)
=>
{
const
{
eventTimestamp
,
eventType
,
fromAddress
,
marketplace
,
price
,
toAddress
,
transactionHash
}
=
event
const
formattedPrice
=
price
?
putCommas
(
formatEthPrice
(
price
)).
toString
()
:
null
return
(
<
TR
key=
{
index
}
>
<
TD
>
<
EventCell
eventType=
{
eventType
}
eventTimestamp=
{
eventTimestamp
}
eventTransactionHash=
{
transactionHash
}
eventOnly
/>
</
TD
>
<
TD
>
{
formattedPrice
&&
(
<
PriceContainer
>
{
marketplace
&&
<
MarketplaceIcon
marketplace=
{
marketplace
}
/>
}
{
formattedPrice
}
ETH
</
PriceContainer
>
)
}
</
TD
>
<
TD
>
{
fromAddress
&&
(
<
Link
href=
{
`https://etherscan.io/address/${fromAddress}`
}
target=
"_blank"
rel=
"noopener noreferrer"
>
{
shortenAddress
(
fromAddress
,
2
,
4
)
}
</
Link
>
)
}
</
TD
>
<
TD
>
{
toAddress
&&
(
<
Link
href=
{
`https://etherscan.io/address/${toAddress}`
}
target=
"_blank"
rel=
"noopener noreferrer"
>
{
shortenAddress
(
toAddress
,
2
,
4
)
}
</
Link
>
)
}
</
TD
>
<
TD
>
{
eventTimestamp
&&
getTimeDifference
(
eventTimestamp
.
toString
())
}
</
TD
>
</
TR
>
)
})
}
</
tbody
>
</
Table
>
</
ActivityContainer
>
)
}
export
default
AssetActivity
src/nft/components/details/AssetDetails.css.ts
View file @
4b1b6098
...
@@ -6,19 +6,18 @@ import { sprinkles, vars } from '../../css/sprinkles.css'
...
@@ -6,19 +6,18 @@ import { sprinkles, vars } from '../../css/sprinkles.css'
export
const
image
=
style
([
export
const
image
=
style
([
sprinkles
({
borderRadius
:
'
20
'
,
height
:
'
full
'
,
alignSelf
:
'
center
'
}),
sprinkles
({
borderRadius
:
'
20
'
,
height
:
'
full
'
,
alignSelf
:
'
center
'
}),
{
{
width
:
'
calc(90vh - 165px)
'
,
maxHeight
:
'
calc(90vh - 165px)
'
,
height
:
'
calc(90vh - 165px)
'
,
minHeight
:
400
,
maxHeight
:
'
678px
'
,
maxWidth
:
780
,
maxWidth
:
'
678px
'
,
boxShadow
:
`0px 20px 50px var(--shadow), 0px 10px 50px rgba(70, 115, 250, 0.2)`
,
boxShadow
:
`0px 20px 50px var(--shadow), 0px 10px 50px rgba(70, 115, 250, 0.2)`
,
'
@media
'
:
{
'
@media
'
:
{
'
(max-width: 1024px)
'
:
{
'
(max-width: 1024px)
'
:
{
maxHeight
:
'
64vh
'
,
maxHeight
:
'
64vh
'
,
maxWidth
:
'
64vh
'
,
},
},
'
(max-width: 640px)
'
:
{
'
(max-width: 640px)
'
:
{
minHeight
:
280
,
maxHeight
:
'
56vh
'
,
maxHeight
:
'
56vh
'
,
maxWidth
:
'
56vh
'
,
maxWidth
:
'
100%
'
,
},
},
},
},
},
},
...
@@ -81,8 +80,6 @@ export const columns = style([
...
@@ -81,8 +80,6 @@ export const columns = style([
])
])
export
const
column
=
style
({
export
const
column
=
style
({
maxWidth
:
'
50%
'
,
width
:
'
50%
'
,
alignSelf
:
'
center
'
,
alignSelf
:
'
center
'
,
'
@media
'
:
{
'
@media
'
:
{
'
(max-width: 1024px)
'
:
{
'
(max-width: 1024px)
'
:
{
...
...
src/nft/components/details/AssetDetails.tsx
View file @
4b1b6098
This diff is collapsed.
Click to expand it.
src/nft/components/details/AssetPriceDetails.tsx
View file @
4b1b6098
This diff is collapsed.
Click to expand it.
src/nft/components/details/DetailsContainer.tsx
0 → 100644
View file @
4b1b6098
import
useCopyClipboard
from
'
hooks/useCopyClipboard
'
import
{
CollectionInfoForAsset
,
GenieAsset
}
from
'
nft/types
'
import
{
putCommas
}
from
'
nft/utils
'
import
{
shortenAddress
}
from
'
nft/utils/address
'
import
{
useCallback
}
from
'
react
'
import
{
Copy
}
from
'
react-feather
'
import
styled
from
'
styled-components/macro
'
const
Details
=
styled
.
div
`
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-gap: 40px;
@media (max-width: 600px) {
grid-template-columns: 1fr 1fr 1fr;
}
@media (max-width: 450px) {
grid-template-columns: 1fr 1fr;
}
`
const
Header
=
styled
.
div
`
color:
${({
theme
})
=>
theme
.
textSecondary
}
;
font-size: 14px;
line-height: 20px;
`
const
Body
=
styled
.
div
`
color:
${({
theme
})
=>
theme
.
textPrimary
}
;
font-size: 14px;
line-height: 20px;
margin-top: 8px;
`
const
Center
=
styled
.
span
`
align-items: center;
cursor: pointer;
display: flex;
gap: 8px;
&:hover {
opacity:
${({
theme
})
=>
theme
.
opacity
.
hover
}
;
}
&:active {
opacity:
${({
theme
})
=>
theme
.
opacity
.
click
}
;
}
transition:
${({
theme
:
{
transition
:
{
duration
,
timing
},
},
})
=>
`opacity
${
duration
.
medium
}
${
timing
.
ease
}
`
}
;
`
const
CreatorLink
=
styled
.
a
`
color:
${({
theme
})
=>
theme
.
textPrimary
}
;
text-decoration: none;
&:hover {
opacity:
${({
theme
})
=>
theme
.
opacity
.
hover
}
;
}
&:active {
opacity:
${({
theme
})
=>
theme
.
opacity
.
click
}
;
}
transition:
${({
theme
:
{
transition
:
{
duration
,
timing
},
},
})
=>
`opacity
${
duration
.
medium
}
${
timing
.
ease
}
`
}
;
`
const
CopyIcon
=
styled
(
Copy
)
`
cursor: pointer;
`
const
GridItem
=
({
header
,
body
}:
{
header
:
string
;
body
:
React
.
ReactNode
})
=>
{
return
(
<
div
>
<
Header
>
{
header
}
</
Header
>
<
Body
>
{
body
}
</
Body
>
</
div
>
)
}
const
stringShortener
=
(
text
:
string
)
=>
`
${
text
.
substring
(
0
,
4
)}
...
${
text
.
substring
(
text
.
length
-
4
,
text
.
length
)}
`
const
DetailsContainer
=
({
asset
,
collection
}:
{
asset
:
GenieAsset
;
collection
:
CollectionInfoForAsset
})
=>
{
const
{
address
,
tokenId
,
tokenType
,
creator
}
=
asset
const
{
totalSupply
}
=
collection
const
[,
setCopied
]
=
useCopyClipboard
()
const
copy
=
useCallback
(()
=>
{
setCopied
(
address
??
''
)
},
[
address
,
setCopied
])
return
(
<
Details
>
<
GridItem
header=
"Contract address"
body=
{
<
Center
onClick=
{
copy
}
>
{
shortenAddress
(
address
,
2
,
4
)
}
<
CopyIcon
size=
{
13
}
/>
</
Center
>
}
/>
<
GridItem
header=
"Token ID"
body=
{
tokenId
.
length
>
9
?
stringShortener
(
tokenId
)
:
tokenId
}
/>
<
GridItem
header=
"Token standard"
body=
{
tokenType
}
/>
<
GridItem
header=
"Blockchain"
body=
"Ethereum"
/>
<
GridItem
header=
"Total supply"
body=
{
`${putCommas(totalSupply ?? 0)}`
}
/>
<
GridItem
header=
"Creator"
body=
{
creator
?.
address
&&
(
<
CreatorLink
href=
{
`https://etherscan.io/address/${creator.address}`
}
rel=
"noopener noreferrer"
target=
"_blank"
>
{
shortenAddress
(
creator
.
address
,
2
,
4
)
}
</
CreatorLink
>
)
}
/>
</
Details
>
)
}
export
default
DetailsContainer
src/nft/components/details/InfoContainer.tsx
0 → 100644
View file @
4b1b6098
import
{
useState
}
from
'
react
'
import
{
ChevronDown
,
ChevronUp
}
from
'
react-feather
'
import
styled
,
{
css
}
from
'
styled-components/macro
'
const
Header
=
styled
.
div
<
{
isOpen
:
boolean
}
>
`
display: flex;
border-radius:
${({
isOpen
})
=>
(
isOpen
?
'
16px 16px 0px 0px
'
:
'
16px
'
)}
;
justify-content: space-between;
background-color:
${({
theme
})
=>
theme
.
backgroundSurface
}
;
padding: 14px 20px;
cursor: pointer;
border: 1px solid
${({
theme
})
=>
theme
.
backgroundOutline
}
;
margin-top: 28px;
width: 100%;
align-items: center;
&:hover {
background-color:
${({
theme
})
=>
theme
.
stateOverlayHover
}
;
}
&:active {
background-color:
${({
theme
})
=>
theme
.
stateOverlayPressed
}
;
}
transition:
${({
theme
:
{
transition
:
{
duration
,
timing
},
},
})
=>
css
`background-color
${
duration
.
medium
}
${
timing
.
ease
}
`
}
;
`
const
PrimaryHeader
=
styled
.
span
`
display: flex;
align-items: center;
gap: 16px;
color:
${({
theme
})
=>
theme
.
textPrimary
}
;
font-weight: 500;
line-height: 28px;
font-size: 20px;
`
const
SecondaryHeader
=
styled
.
span
`
font-size: 12px;
color:
${({
theme
})
=>
theme
.
textSecondary
}
;
`
const
SecondaryHeaderContainer
=
styled
.
span
`
display: flex;
align-items: center;
justify-content: center;
gap: 32px;
color:
${({
theme
})
=>
theme
.
textPrimary
}
;
`
const
ContentContainer
=
styled
.
div
`
padding: 20px;
border: 1px solid
${({
theme
})
=>
theme
.
backgroundOutline
}
;
border-top: none;
border-radius: 0px 0px 16px 16px;
background-color:
${({
theme
})
=>
theme
.
backgroundSurface
}
; ;
`
const
InfoContainer
=
({
children
,
primaryHeader
,
secondaryHeader
,
defaultOpen
,
}:
{
children
:
JSX
.
Element
primaryHeader
:
string
secondaryHeader
:
React
.
ReactNode
defaultOpen
?:
boolean
})
=>
{
const
[
isOpen
,
setIsOpen
]
=
useState
(
!!
defaultOpen
)
return
(
<
div
>
<
Header
isOpen=
{
isOpen
}
onClick=
{
()
=>
setIsOpen
(
!
isOpen
)
}
>
<
PrimaryHeader
>
{
primaryHeader
}
<
SecondaryHeader
>
{
secondaryHeader
}
</
SecondaryHeader
>
</
PrimaryHeader
>
<
SecondaryHeaderContainer
>
{
isOpen
?
<
ChevronUp
/>
:
<
ChevronDown
/>
}
</
SecondaryHeaderContainer
>
</
Header
>
{
isOpen
&&
<
ContentContainer
>
{
children
}
</
ContentContainer
>
}
</
div
>
)
}
export
default
InfoContainer
src/nft/components/details/Traits.css.ts
deleted
100644 → 0
View file @
53a6acc1
import
{
style
}
from
'
@vanilla-extract/css
'
import
{
sprinkles
}
from
'
../../css/sprinkles.css
'
export
const
grid
=
style
([
sprinkles
({
gap
:
'
16
'
,
display
:
'
grid
'
}),
{
gridTemplateColumns
:
'
repeat(4, 1fr)
'
,
'
@media
'
:
{
'
(max-width: 1536px)
'
:
{
gridTemplateColumns
:
'
repeat(3, 1fr)
'
,
},
'
(max-width: 640px)
'
:
{
gridTemplateColumns
:
'
repeat(2, 1fr)
'
,
},
},
},
])
src/nft/components/details/Traits.tsx
deleted
100644 → 0
View file @
53a6acc1
import
{
Trait
}
from
'
nft/hooks
'
import
qs
from
'
query-string
'
import
{
badge
}
from
'
../../css/common.css
'
import
{
Box
}
from
'
../Box
'
import
{
Column
}
from
'
../Flex
'
import
*
as
styles
from
'
./Traits.css
'
const
TraitRow
:
React
.
FC
<
Trait
>
=
({
trait_type
,
trait_value
}:
Trait
)
=>
(
<
Column
backgroundColor=
"backgroundSurface"
padding=
"16"
gap=
"4"
borderRadius=
"12"
>
<
Box
as=
"span"
className=
{
badge
}
color=
"textSecondary"
whiteSpace=
"nowrap"
overflow=
"hidden"
textOverflow=
"ellipsis"
style=
{
{
textTransform
:
'
uppercase
'
}
}
maxWidth=
{
{
sm
:
'
120
'
,
md
:
'
160
'
}
}
>
{
trait_type
}
</
Box
>
<
Box
as=
"span"
color=
"textPrimary"
fontSize=
"16"
fontWeight=
"normal"
whiteSpace=
"nowrap"
overflow=
"hidden"
textOverflow=
"ellipsis"
maxWidth=
{
{
sm
:
'
120
'
,
md
:
'
160
'
}
}
>
{
trait_value
}
</
Box
>
</
Column
>
)
export
const
Traits
=
({
traits
,
collectionAddress
}:
{
traits
:
Trait
[];
collectionAddress
:
string
})
=>
(
<
div
className=
{
styles
.
grid
}
>
{
traits
.
length
===
0
?
'
No traits
'
:
traits
.
map
((
item
)
=>
{
const
params
=
qs
.
stringify
(
{
traits
:
[
`("${item.trait_type}","${item.trait_value}")`
]
},
{
arrayFormat
:
'
comma
'
,
}
)
return
(
<
a
key=
{
`${item.trait_type}-${item.trait_value}`
}
href=
{
`#/nfts/collection/${collectionAddress}?${params}`
}
style=
{
{
textDecoration
:
'
none
'
}
}
>
<
TraitRow
trait_type=
{
item
.
trait_type
}
trait_value=
{
item
.
trait_value
}
/>
</
a
>
)
})
}
</
div
>
)
src/nft/components/details/TraitsContainer.tsx
0 → 100644
View file @
4b1b6098
import
{
GenieAsset
,
Trait
}
from
'
nft/types
'
import
qs
from
'
query-string
'
import
{
useMemo
}
from
'
react
'
import
{
Link
}
from
'
react-router-dom
'
import
styled
from
'
styled-components/macro
'
const
Grid
=
styled
.
div
`
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
gap: 16px;
max-width: 780px;
@media (max-width: 960px) {
grid-template-columns: 1fr 1fr 1fr;
}
@media (max-width: 420px) {
grid-template-columns: 1fr 1fr;
}
`
const
GridItemContainer
=
styled
(
Link
)
`
background-color:
${({
theme
})
=>
theme
.
backgroundInteractive
}
;
border-radius: 12px;
cursor: pointer;
padding: 12px;
text-decoration: none;
&:hover {
opacity:
${({
theme
})
=>
theme
.
opacity
.
hover
}
;
}
&:active {
opacity:
${({
theme
})
=>
theme
.
opacity
.
click
}
;
}
transition:
${({
theme
:
{
transition
:
{
duration
,
timing
},
},
})
=>
`opacity
${
duration
.
medium
}
${
timing
.
ease
}
`
}
;
min-width: 0;
`
const
TraitType
=
styled
.
div
`
color:
${({
theme
})
=>
theme
.
textSecondary
}
;
font-weight: 600;
font-size: 10px;
line-height: 12px;
white-space: nowrap;
width: 100%;
`
const
TraitValue
=
styled
.
div
`
color:
${({
theme
})
=>
theme
.
textPrimary
}
;
font-size: 16px;
line-height: 24px;
margin-top: 4px;
display: inline-block;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100%;
`
const
GridItem
=
({
trait
,
collectionAddress
}:
{
trait
:
Trait
;
collectionAddress
:
string
})
=>
{
const
{
trait_type
,
trait_value
}
=
trait
const
params
=
qs
.
stringify
(
{
traits
:
[
`("
${
trait_type
}
","
${
trait_value
}
")`
]
},
{
arrayFormat
:
'
comma
'
,
}
)
return
(
<
GridItemContainer
to=
{
`/nfts/collection/${collectionAddress}?${params}`
}
>
<
TraitType
>
{
trait_type
}
</
TraitType
>
<
TraitValue
>
{
trait_value
}
</
TraitValue
>
</
GridItemContainer
>
)
}
const
TraitsContainer
=
({
asset
}:
{
asset
:
GenieAsset
})
=>
{
const
traits
=
useMemo
(()
=>
asset
.
traits
?.
sort
((
a
,
b
)
=>
a
.
trait_type
.
localeCompare
(
b
.
trait_type
)),
[
asset
])
return
(
<
Grid
>
{
traits
?.
map
((
trait
)
=>
{
return
<
GridItem
key=
{
trait
.
trait_type
}
trait=
{
trait
}
collectionAddress=
{
asset
.
address
}
/>
})
}
</
Grid
>
)
}
export
default
TraitsContainer
src/nft/components/icons.tsx
View file @
4b1b6098
...
@@ -1495,11 +1495,10 @@ export const EmptyNFTWalletIcon = (props: SVGProps) => (
...
@@ -1495,11 +1495,10 @@ export const EmptyNFTWalletIcon = (props: SVGProps) => (
)
)
export
const
CancelListingIcon
=
(
props
:
SVGProps
)
=>
(
export
const
CancelListingIcon
=
(
props
:
SVGProps
)
=>
(
<
svg
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
{
...
props
}
>
<
svg
width=
"15"
height=
"15"
viewBox=
"0 0 15 15"
fill=
"none"
xmlns=
"http://www.w3.org/2000/svg"
{
...
props
}
>
<
path
<
path
d=
"M
71 31L75.36 35.36C76.85 36.8589 77.6863 38.8865 77.6863 41C77.6863 43.1135 76.85 45.1411 75.36 46.64L46.68 75.32C45.937 76.0638 45.0547 76.6539 44.0835 77.0565C43.1123 77.4591 42.0713 77.6663 41.02 77.6663C39.9687 77.6663 38.9277 77.4591 37.9565 77.0565C36.9853 76.6539 36.103 76.0638 35.36 75.32L31 71M47.8 7.8L41 1H1V41L7.8 47.8M77.6863 1L1.62987 77.0565M21 21H21.0333
"
d=
"M
12.6667 6L13.3933 6.72667C13.6417 6.97648 13.7811 7.31442 13.7811 7.66667C13.7811 8.01891 13.6417 8.35685 13.3933 8.60667L8.61333 13.3867C8.4895 13.5106 8.34245 13.609 8.18059 13.6761C8.01872 13.7432 7.84522 13.7777 7.67 13.7777C7.49478 13.7777 7.32128 13.7432 7.15941 13.6761C6.99755 13.609 6.8505 13.5106 6.72667 13.3867L6 12.6667M8.8 2.13333L7.66667 1H1V7.66667L2.13333 8.8M13.7811 1L1.10498 13.6761M4.33333 4.33333H4.33889
"
stroke=
"currentColor"
stroke=
"currentColor"
strokeWidth=
"2"
strokeLinecap=
"round"
strokeLinecap=
"round"
strokeLinejoin=
"round"
strokeLinejoin=
"round"
/>
/>
...
...
src/nft/pages/asset/Asset.tsx
View file @
4b1b6098
...
@@ -5,6 +5,7 @@ import { useDetailsQuery } from 'graphql/data/nft/Details'
...
@@ -5,6 +5,7 @@ import { useDetailsQuery } from 'graphql/data/nft/Details'
import
{
AssetDetails
}
from
'
nft/components/details/AssetDetails
'
import
{
AssetDetails
}
from
'
nft/components/details/AssetDetails
'
import
{
AssetPriceDetails
}
from
'
nft/components/details/AssetPriceDetails
'
import
{
AssetPriceDetails
}
from
'
nft/components/details/AssetPriceDetails
'
import
{
fetchSingleAsset
}
from
'
nft/queries
'
import
{
fetchSingleAsset
}
from
'
nft/queries
'
import
{
CollectionStatsFetcher
}
from
'
nft/queries
'
import
{
useMemo
}
from
'
react
'
import
{
useMemo
}
from
'
react
'
import
{
useQuery
}
from
'
react-query
'
import
{
useQuery
}
from
'
react-query
'
import
{
useParams
}
from
'
react-router-dom
'
import
{
useParams
}
from
'
react-router-dom
'
...
@@ -12,8 +13,20 @@ import styled from 'styled-components/macro'
...
@@ -12,8 +13,20 @@ import styled from 'styled-components/macro'
const
AssetContainer
=
styled
.
div
`
const
AssetContainer
=
styled
.
div
`
display: flex;
display: flex;
padding-right: 116px;
width: 100%;
padding-left: 116px;
justify-content: center;
gap: 60px;
padding: 48px 40px 0 40px;
`
const
AssetPriceDetailsContainer
=
styled
.
div
`
min-width: 360px;
position: relative;
padding-right: 100px;
@media (max-width: 960px) {
display: none;
}
`
`
const
Asset
=
()
=>
{
const
Asset
=
()
=>
{
...
@@ -37,6 +50,10 @@ const Asset = () => {
...
@@ -37,6 +50,10 @@ const Asset = () => {
[
data
,
gqlData
,
isNftGraphQl
]
[
data
,
gqlData
,
isNftGraphQl
]
)
)
const
{
data
:
collectionStats
}
=
useQuery
([
'
collectionStats
'
,
contractAddress
],
()
=>
CollectionStatsFetcher
(
contractAddress
)
)
return
(
return
(
<>
<>
<
Trace
<
Trace
...
@@ -46,8 +63,10 @@ const Asset = () => {
...
@@ -46,8 +63,10 @@ const Asset = () => {
>
>
{
asset
&&
collection
?
(
{
asset
&&
collection
?
(
<
AssetContainer
>
<
AssetContainer
>
<
AssetDetails
collection=
{
collection
}
asset=
{
asset
}
/>
<
AssetDetails
collection=
{
collection
}
asset=
{
asset
}
collectionStats=
{
collectionStats
}
/>
<
AssetPriceDetails
collection=
{
collection
}
asset=
{
asset
}
/>
<
AssetPriceDetailsContainer
>
<
AssetPriceDetails
collection=
{
collection
}
asset=
{
asset
}
/>
</
AssetPriceDetailsContainer
>
</
AssetContainer
>
</
AssetContainer
>
)
:
(
)
:
(
<
div
>
Holder for loading ...
</
div
>
<
div
>
Holder for loading ...
</
div
>
...
...
src/nft/queries/genie/ActivityFetcher.ts
View file @
4b1b6098
...
@@ -3,15 +3,19 @@ import { ActivityEventResponse, ActivityFilter } from '../../types'
...
@@ -3,15 +3,19 @@ import { ActivityEventResponse, ActivityFilter } from '../../types'
export
const
ActivityFetcher
=
async
(
export
const
ActivityFetcher
=
async
(
contractAddress
:
string
,
contractAddress
:
string
,
filters
?:
ActivityFilter
,
filters
?:
ActivityFilter
,
cursor
?:
string
cursor
?:
string
,
limit
?:
string
):
Promise
<
ActivityEventResponse
>
=>
{
):
Promise
<
ActivityEventResponse
>
=>
{
const
filterParam
=
const
filterParam
=
filters
&&
filters
.
eventTypes
filters
&&
filters
.
eventTypes
?
`&
${
filters
.
eventTypes
?.
map
((
eventType
)
=>
`event_types[]=
${
eventType
}
`
).
join
(
'
&
'
)}
`
?
`&
${
filters
.
eventTypes
?.
map
((
eventType
)
=>
`event_types[]=
${
eventType
}
`
).
join
(
'
&
'
)}
`
: ''
: ''
const url = `
$
{
process
.
env
.
REACT_APP_GENIE_V3_API_URL
const tokenId = filters?.token_id ? `
&
token_id
=
$
{
filters
?.
token_id
}
` : ''
}
/collections/
$
{
contractAddress
}
/activity
?
limit=25${filterParam}${cursor
?
`&cursor=${cursor}` : ''}
`
const url = `
$
{
process
.
env
.
REACT_APP_GENIE_V3_API_URL
}
/collections/
$
{
contractAddress
}
/activity
?
limit=$
{
limit
?
limit
:
'
25
'
}
$
{
filterParam
}
$
{
cursor
?
`&cursor=
${
cursor
}
`
:
''
}
$
{
tokenId
}
`
const r = await fetch(url, {
const r = await fetch(url, {
method: 'GET',
method: 'GET',
...
...
src/nft/queries/genie/SingleAssetFetcher.ts
View file @
4b1b6098
import
{
CollectionInfoForAsset
,
GenieAsset
}
from
'
../../types
'
import
{
CollectionInfoForAsset
,
GenieAsset
}
from
'
../../types
'
interface
ReponseTrait
{
trait_type
:
string
value
:
string
}
export
const
fetchSingleAsset
=
async
({
export
const
fetchSingleAsset
=
async
({
contractAddress
,
contractAddress
,
tokenId
,
tokenId
,
...
@@ -10,5 +15,9 @@ export const fetchSingleAsset = async ({
...
@@ -10,5 +15,9 @@ export const fetchSingleAsset = async ({
const
url
=
`
${
process
.
env
.
REACT_APP_GENIE_V3_API_URL
}
/assetDetails?address=
${
contractAddress
}
&tokenId=
${
tokenId
}
`
const
url
=
`
${
process
.
env
.
REACT_APP_GENIE_V3_API_URL
}
/assetDetails?address=
${
contractAddress
}
&tokenId=
${
tokenId
}
`
const
r
=
await
fetch
(
url
)
const
r
=
await
fetch
(
url
)
const
data
=
await
r
.
json
()
const
data
=
await
r
.
json
()
return
[
data
.
asset
[
0
],
data
.
collection
]
const
asset
=
data
.
asset
[
0
]
asset
.
traits
=
asset
.
traits
.
map
((
trait
:
ReponseTrait
)
=>
({
trait_type
:
trait
.
trait_type
,
trait_value
:
trait
.
value
}))
return
[
asset
,
data
.
collection
]
}
}
src/nft/types/collection/collection.ts
View file @
4b1b6098
...
@@ -51,7 +51,7 @@ export enum ActivityEventTypeDisplay {
...
@@ -51,7 +51,7 @@ export enum ActivityEventTypeDisplay {
'
LISTING
'
=
'
Listed
'
,
'
LISTING
'
=
'
Listed
'
,
'
SALE
'
=
'
Sold
'
,
'
SALE
'
=
'
Sold
'
,
'
TRANSFER
'
=
'
Transferred
'
,
'
TRANSFER
'
=
'
Transferred
'
,
'
CANCEL_LISTING
'
=
'
Cancell
ed
'
,
'
CANCEL_LISTING
'
=
'
Cancell
ation
'
,
}
}
export
enum
OrderStatus
{
export
enum
OrderStatus
{
...
@@ -65,6 +65,7 @@ export interface ActivityFilter {
...
@@ -65,6 +65,7 @@ export interface ActivityFilter {
collectionAddress
?:
string
collectionAddress
?:
string
eventTypes
?:
ActivityEventType
[]
eventTypes
?:
ActivityEventType
[]
marketplaces
?:
Markets
[]
marketplaces
?:
Markets
[]
token_id
?:
string
}
}
export
interface
ActivityEventResponse
{
export
interface
ActivityEventResponse
{
...
...
src/nft/types/common/common.ts
View file @
4b1b6098
import
{
Trait
}
from
'
nft/hooks/useCollectionFilters
'
import
{
Deprecated_SellOrder
,
SellOrder
}
from
'
../sell
'
import
{
Deprecated_SellOrder
,
SellOrder
}
from
'
../sell
'
export
interface
OpenSeaCollection
{
export
interface
OpenSeaCollection
{
...
@@ -43,13 +41,6 @@ export interface OpenSeaAsset {
...
@@ -43,13 +41,6 @@ export interface OpenSeaAsset {
collection
?:
OpenSeaCollection
collection
?:
OpenSeaCollection
}
}
interface
OpenSeaUser
{
user
?:
null
profile_img_url
?:
string
address
?:
string
config
?:
string
}
export
enum
TokenType
{
export
enum
TokenType
{
ERC20
=
'
ERC20
'
,
ERC20
=
'
ERC20
'
,
ERC721
=
'
ERC721
'
,
ERC721
=
'
ERC721
'
,
...
@@ -77,6 +68,14 @@ export interface Rarity {
...
@@ -77,6 +68,14 @@ export interface Rarity {
providers
?:
{
provider
:
string
;
rank
?:
number
;
url
?:
string
;
score
?:
number
}[]
providers
?:
{
provider
:
string
;
rank
?:
number
;
url
?:
string
;
score
?:
number
}[]
}
}
export
interface
Trait
{
trait_type
:
string
trait_value
:
string
display_type
?:
any
max_value
?:
any
trait_count
?:
number
order
?:
any
}
export
interface
GenieAsset
{
export
interface
GenieAsset
{
id
?:
string
// This would be a random id created and assigned by front end
id
?:
string
// This would be a random id created and assigned by front end
address
:
string
address
:
string
...
@@ -96,9 +95,14 @@ export interface GenieAsset {
...
@@ -96,9 +95,14 @@ export interface GenieAsset {
totalCount
?:
number
// The totalCount from the query to /assets
totalCount
?:
number
// The totalCount from the query to /assets
collectionIsVerified
?:
boolean
collectionIsVerified
?:
boolean
rarity
?:
Rarity
rarity
?:
Rarity
owner
?:
string
owner
:
{
creator
:
OpenSeaUser
address
:
string
metadataUrl
?:
string
}
metadataUrl
:
string
creator
:
{
address
:
string
profile_img_url
:
string
}
traits
?:
Trait
[]
traits
?:
Trait
[]
}
}
...
@@ -122,8 +126,8 @@ export interface GenieCollection {
...
@@ -122,8 +126,8 @@ export interface GenieCollection {
}
}
traits
?:
Record
<
string
,
Trait
[]
>
traits
?:
Record
<
string
,
Trait
[]
>
marketplaceCount
?:
{
marketplace
:
string
;
count
:
number
}[]
marketplaceCount
?:
{
marketplace
:
string
;
count
:
number
}[]
imageUrl
?
:
string
imageUrl
:
string
twitter
?:
string
twitter
Url
?:
string
instagram
?:
string
instagram
?:
string
discordUrl
?:
string
discordUrl
?:
string
externalUrl
?:
string
externalUrl
?:
string
...
...
src/nft/utils/fetchPrice.ts
View file @
4b1b6098
...
@@ -20,7 +20,8 @@ export const fetchPrice = async (currency: Currency = Currency.ETH): Promise<num
...
@@ -20,7 +20,8 @@ export const fetchPrice = async (currency: Currency = Currency.ETH): Promise<num
export
function
useUsdPrice
(
asset
:
GenieAsset
):
string
|
undefined
{
export
function
useUsdPrice
(
asset
:
GenieAsset
):
string
|
undefined
{
const
{
data
:
fetchedPriceData
}
=
useQuery
([
'
fetchPrice
'
,
{}],
()
=>
fetchPrice
(),
{})
const
{
data
:
fetchedPriceData
}
=
useQuery
([
'
fetchPrice
'
,
{}],
()
=>
fetchPrice
(),
{})
return
fetchedPriceData
&&
asset
.
priceInfo
.
ETHPrice
?
(
parseFloat
(
formatEther
(
asset
.
priceInfo
.
ETHPrice
))
*
fetchedPriceData
).
toString
()
return
fetchedPriceData
&&
asset
?.
priceInfo
?.
ETHPrice
:
undefined
?
(
parseFloat
(
formatEther
(
asset
?.
priceInfo
?.
ETHPrice
))
*
fetchedPriceData
).
toString
()
:
''
}
}
src/nft/utils/putCommas.ts
View file @
4b1b6098
export
const
putCommas
=
(
value
?
:
number
)
=>
{
export
const
putCommas
=
(
value
:
number
)
=>
{
try
{
try
{
if
(
!
value
)
return
value
if
(
!
value
)
return
value
return
value
.
toString
().
replace
(
/
\B(?=(\d{3})
+
(?!\d))
/g
,
'
,
'
)
return
value
.
toString
().
replace
(
/
\B(?=(\d{3})
+
(?!\d))
/g
,
'
,
'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment