Skip to content

Commit

Permalink
upgrade nft media getting/rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
samepant committed Jan 19, 2024
1 parent 00e9520 commit a55a3b3
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 51 deletions.
18 changes: 2 additions & 16 deletions frontend/src/components/NFTGridItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useState } from "react"
import clsx from "clsx"
import { Link } from "react-router-dom"

import classes from "./NFTItem.module.css"
import ChainIcon from "../ChainIcon"
import { CHAINS } from "../../chains"
import { MoralisNFT } from "../../types/Token"
import NFTMedia from "../NFTMedia"

interface Props {
nft: { deployed: boolean } & MoralisNFT
Expand All @@ -14,8 +14,6 @@ interface Props {
}

const NFTGridItem: React.FC<Props> = ({ nft, chainId, showCollectionName }) => {
const [imageError, setImageError] = useState(false)

const chain = CHAINS[chainId]

const metadata = JSON.parse(nft.metadata || "{}")
Expand Down Expand Up @@ -48,19 +46,7 @@ const NFTGridItem: React.FC<Props> = ({ nft, chainId, showCollectionName }) => {
</div>
</div>
<div className={classes.main}>
{(imageError || !metadata.image) && (
<div className={classes.noImage}></div>
)}
{!imageError && metadata.image && (
<div className={classes.imageContainer}>
<img
src={metadata.image}
alt={name}
className={classes.image}
onError={() => setImageError(true)}
/>
</div>
)}
<NFTMedia nft={nft} />
</div>
<div className={classes.visit}>
<h3>⬈⬈⬈⬈⬈⬈⬈⬈⬈</h3>
Expand Down
32 changes: 0 additions & 32 deletions frontend/src/components/NFTItem/NFTItem.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -40,38 +40,6 @@
display: flex;
justify-content: space-between;
}

.imageContainer {
width: 50%;
display: flex;
justify-content: flex-start;
}

.main .image {
object-fit: contain;
object-position: top;
height: min-content;
max-height: 100%;
border-radius: 10px;
}

.noImage {
width: 50%;
height: 100%;
background-color: var(--box-bg);
border-radius: 10px;
}

.noImage::after {
content: "?";
height: 100%;
width: 100%;
font-size: 5em;
opacity: 0.2;
display: flex;
justify-content: center;
align-items: center;
}
.info {
width: 45%;
display: flex;
Expand Down
28 changes: 28 additions & 0 deletions frontend/src/components/NFTMedia/NFTMedia.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.noImage {
height: 100%;
background-color: var(--box-bg);
border-radius: 10px;
}

.noImage::after {
content: "?";
height: 100%;
width: 100%;
font-size: 5em;
opacity: 0.2;
display: flex;
justify-content: center;
align-items: center;
}

.imageContainer {
aspect-ratio: 1;
display: flex;
justify-content: center;
}

.image {
object-fit: cover;
max-height: 100%;
border-radius: 10px;
}
74 changes: 74 additions & 0 deletions frontend/src/components/NFTMedia/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useState } from "react"
import { MoralisNFT } from "../../types/Token"

import classes from "./NFTMedia.module.css"

const getIPFSHashFromURL = (url: string) => {
const match = url.match(
/^ipfs:\/\/(Qm[1-9A-HJ-NP-Za-km-z]{44,}|b[A-Za-z2-7]{58,}|B[A-Z2-7]{58,}|z[1-9A-HJ-NP-Za-km-z]{48,}|F[0-9A-F]{50,})(\/(\d|\w|\.)+)*$/
)
return match ? match[1] : null
}

const NFTMedia = ({ nft }: { nft: MoralisNFT }) => {
const [imageError, setImageError] = useState(false)
const metadata = JSON.parse(nft.metadata || "{}")
const alt = metadata.name || "NFT image"

let src = ""
let type = "image/*"

if (!nft.media) {
return <div className={classes.noImage}></div>
}

switch (nft.media.status) {
case "success":
// use media url
src = nft.media.media_collection.high.url
type = nft.media.mimetype
break

case "host_unavailable":
// could be an ipfs url or an unreachable url
const ipfsHash = getIPFSHashFromURL(nft.media.original_media_url)
if (ipfsHash) {
src = `https://cloudflare-ipfs.com/ipfs/${ipfsHash}`
} else {
src = nft.media.original_media_url
}
break

default:
src = nft.media.original_media_url
break
}
return (
<>
{(imageError || !src) && <div className={classes.noImage}></div>}
{!imageError && src && (
<div className={classes.imageContainer}>
{type.includes("image") && (
<img
src={src}
alt={alt}
className={classes.image}
onError={() => setImageError(true)}
/>
)}
{type.includes("video") && (
<video
src={src}
className={classes.image}
onError={() => setImageError(true)}
autoPlay
muted
/>
)}
</div>
)}
</>
)
}

export default NFTMedia
2 changes: 1 addition & 1 deletion frontend/src/hooks/useCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const useCollection = ({ tokenAddress, chainId, page = 0 }: Props) => {

// get collection metadata
const nftRes = await fetch(
`${process.env.REACT_APP_PROXY_URL}/${chainId}/moralis/nft/${tokenAddress}`
`${process.env.REACT_APP_PROXY_URL}/${chainId}/moralis/nft/${tokenAddress}?media_items=true`
)
if (!nftRes.ok) {
throw new Error("NFT request failed")
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/hooks/useTokenBalances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const useTokenBalances = ({ accountAddress, chainId }: Props) => {
try {
// get nfts
const nftRes = await fetch(
`${process.env.REACT_APP_PROXY_URL}/${chainId}/moralis/${accountAddress}/nft`
`${process.env.REACT_APP_PROXY_URL}/${chainId}/moralis/${accountAddress}/nft?media_items=true`
)
if (!nftRes.ok) {
throw new Error("NFT request failed")
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/hooks/useTokenMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const useNFTMetadata = ({ tokenAddress, tokenId, chainId }: Props) => {

// get nfts
const nftRes = await fetch(
`${process.env.REACT_APP_PROXY_URL}/${chainId}/moralis/nft/${tokenAddress}/${tokenId}`
`${process.env.REACT_APP_PROXY_URL}/${chainId}/moralis/nft/${tokenAddress}/${tokenId}?media_items=true`
)
if (!nftRes.ok) {
throw new Error("NFT request failed")
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/types/Token.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ export interface NFTContext {

export type NFTType = "ERC721" | "ERC1155"

interface MoralisMediaItem {
width: number
height: number
url: string
}

export interface MoralisMediaCollection {
status: string
updateAt: string
mimetype: string
parent_hash: string
media_collection: {
low: MoralisMediaItem
medium: MoralisMediaItem
high: MoralisMediaItem
}
original_media_url: string
}

export interface MoralisNFT {
amount: string
token_id: string
Expand All @@ -22,6 +41,7 @@ export interface MoralisNFT {
minter_address: string
verified_collection: boolean
possible_spam: boolean
media?: MoralisMediaCollection
}

export interface MoralisFungible {
Expand Down

1 comment on commit a55a3b3

@vercel
Copy link

@vercel vercel bot commented on a55a3b3 Jan 19, 2024

Choose a reason for hiding this comment

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

Please sign in to comment.