Completed code for Mango Heroes integration

This commit is contained in:
Yandre 2021-11-10 21:54:23 -05:00
parent 14147aab26
commit 9f66df9bf1
5 changed files with 114 additions and 55 deletions

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useEffect, useState } from 'react'
import { FunctionComponent } from 'react'
import Modal from './Modal'
import { ElementTitle } from './styles'
@ -6,9 +6,6 @@ import { Responsive, WidthProvider } from 'react-grid-layout'
import _ from 'lodash'
import Button from './Button'
import useMangoStore from '../stores/useMangoStore'
// import mango_hero from '../public/mango_heroes.jpg'
// import mango_hero1 from '../public/mango_heroes1.jpeg'
// import mango_hero2 from '../public/mango_heroes2.jpeg'
import { notify } from '../utils/notifications'
import { NFT } from '../utils/metaplex/models'
@ -25,30 +22,36 @@ const ChangeAvatarModal: FunctionComponent<ChangeAvatarModalProps> = ({
onClose,
currentAvatar,
}) => {
const nfts = useMangoStore((s) => s.settings.nfts)
const nfts = [...useMangoStore((s) => s.settings.nfts)].filter(
(nft) => nft.metadataUri
)
const currentIndex = nfts.indexOf(currentAvatar)
if (currentIndex != -1) nfts.splice(currentIndex, 1)
const testImageUrls = [nfts]
const listOfNFTs = [currentAvatar, ...nfts]
const [selectedIndex, setSelectedIndex] = useState(0)
const set = useMangoStore((state) => state.set)
const [layouts] = useState(
testImageUrls.map((url, key) => {
listOfNFTs.map((nft, key) => {
return {
i: String(key),
x: key % 3,
y: Math.floor(key / 3),
w: 1,
h: 1,
url: url,
nft: nft,
}
})
)
// Save selected profile picture
const saveSelection = () => {
const nft = listOfNFTs[selectedIndex]
set((state) => {
state.settings.avatar = testImageUrls[selectedIndex]
state.settings.avatar = nft.mintAddress.toBase58()
})
localStorage.setItem('profilePic', nft.mintAddress.toBase58())
notify({
title: 'Avatar changed successfully',
@ -83,7 +86,7 @@ const ChangeAvatarModal: FunctionComponent<ChangeAvatarModalProps> = ({
onClick={() => setSelectedIndex(+layout.i)}
>
<NFTDisplay
nft={layout.url}
nft={layout.nft}
selected={selectedIndex === +layout.i}
/>
</div>
@ -105,8 +108,37 @@ const ChangeAvatarModal: FunctionComponent<ChangeAvatarModalProps> = ({
}
const NFTDisplay = ({ nft, selected }) => {
const [imageUri, setImageUri] = useState()
useEffect(() => {
if (nft.imageUri) {
setImageUri(nft.imageUri)
} else {
try {
fetch(nft.metadataUri).then(async (_) => {
try {
const data = await _.json()
nft.imageUri = data['image']
setImageUri(nft.imageUri)
console.log('imageUri is: ', nft.imageUri)
} catch (ex) {
console.error('Error trying to parse JSON: ' + ex)
}
})
} catch (ex) {
console.error('Error trying to fetch Arweave metadata: ' + ex)
}
}
}, [imageUri])
return (
<div className="hover:scale-110">
<div
className={`hover:scale-110 ${
nft.imageUri == undefined
? 'bg-th-bkg-4 h-full w-full rounded-lg animate-pulse'
: ''
}`}
>
<img
className={`border ${
selected ? 'border-th-primary' : 'border-th-bkg-4'

View File

@ -21,48 +21,61 @@ import { useEffect } from 'react'
import SettingsModal from './SettingsModal'
import { UserCircleIcon } from '@heroicons/react/solid'
import ChangeAvatarModal from './ChangeAvatarModal'
import { NFT } from '../utils/metaplex/models'
const ConnectWalletButton = () => {
const wallet = useMangoStore((s) => s.wallet.current)
const connected = useMangoStore((s) => s.wallet.connected)
const nfts = useMangoStore((s) => s.settings.nfts)
const imageUrl = useMangoStore((s) => s.settings.avatar)
const profilePicMintAddress = useMangoStore((s) => s.settings.avatar)
const set = useMangoStore((s) => s.set)
const [showAccountsModal, setShowAccountsModal] = useState(false)
const [showSettingsModal, setShowSettingsModal] = useState(false)
const [showChangeAvatarModal, setChangeAvatarModal] = useState(false)
const [selectedWallet, setSelectedWallet] = useState(DEFAULT_PROVIDER.url)
const [profilePicture, setProfilePicture] = useState(new NFT())
const [imageUrl, setImageUrl] = useState('')
const [savedProviderUrl] = useLocalStorageState(
PROVIDER_LOCAL_STORAGE_KEY,
DEFAULT_PROVIDER.url
)
// update in useEffect to prevent SRR error from next.js
useEffect(() => {
setSelectedWallet(savedProviderUrl)
}, [savedProviderUrl])
if (nfts.length != 0 && imageUrl == '') {
const nft = nfts[0]
useEffect(() => {
if (!profilePicMintAddress && nfts.length == 0) {
return
}
const profilePics = nfts.filter(
(nft) => nft.mintAddress.toBase58() == profilePicMintAddress
)
const nft = profilePics.length == 1 ? profilePics[0] : nfts[0]
if (nft.imageUri) {
setImageUrl(nft.imageUri)
} else {
try {
fetch(nft).then(async (_) => {
fetch(nft.metadataUri).then(async (_) => {
try {
const data = await _.json()
set((state) => {
state.settings.avatar = data['image']
})
nft.imageUri = data['image']
setImageUrl(nft.imageUri)
} catch (ex) {
console.error('Error trying to parse JSON: ' + ex)
}
})
} catch (ex) {
console.error('Error trying to fetch Arweave metadata: ' + ex)
console.error('Error trying to fetch metadata: ' + ex)
}
}
const handleWalletConect = () => {
setProfilePicture(nft)
}, [nfts, profilePicMintAddress])
const handleWalletConnect = () => {
wallet.connect()
set((state) => {
state.selectedMangoAccount.initialLoad = true
@ -90,7 +103,6 @@ const ConnectWalletButton = () => {
}
>
{imageUrl == '' ? <ProfileIcon className="h-6 w-6" /> : null}
{/* <NewProfileIcon className="h-6 w-6" src={mango_hero.src} /> */}
</Menu.Button>
<Menu.Items className="bg-th-bkg-1 mt-2 p-1 absolute right-0 shadow-lg outline-none rounded-md w-48 z-20">
<Menu.Item>
@ -102,6 +114,7 @@ const ConnectWalletButton = () => {
<div className="pl-2 text-left">Accounts</div>
</button>
</Menu.Item>
{imageUrl != '' ? (
<Menu.Item>
<button
className="flex flex-row font-normal items-center rounded-none w-full p-2 hover:bg-th-bkg-2 hover:cursor-pointer focus:outline-none"
@ -111,6 +124,7 @@ const ConnectWalletButton = () => {
<div className="pl-2 text-left">Change Avatar</div>
</button>
</Menu.Item>
) : null}
<Menu.Item>
<button
className="flex flex-row font-normal items-center rounded-none w-full p-2 hover:bg-th-bkg-2 hover:cursor-pointer focus:outline-none"
@ -149,7 +163,7 @@ const ConnectWalletButton = () => {
) : (
<div className="bg-th-bkg-1 h-14 flex divide-x divide-th-bkg-3 justify-between">
<button
onClick={handleWalletConect}
onClick={handleWalletConnect}
disabled={!wallet}
className="rounded-none text-th-primary hover:bg-th-bkg-4 focus:outline-none disabled:text-th-fgd-4 disabled:cursor-wait"
>
@ -184,7 +198,7 @@ const ConnectWalletButton = () => {
<ChangeAvatarModal
onClose={() => setChangeAvatarModal(false)}
isOpen={showChangeAvatarModal}
url={imageUrl}
currentAvatar={profilePicture}
/>
) : null}
</>

View File

@ -107,7 +107,7 @@ export default function useWallet() {
actions.reloadOrders()
actions.fetchTradeHistory()
actions.fetchWalletTokens()
actions.fetchProfilePicture()
actions.fetchMangoHeroesNFTs()
notify({
title: 'Wallet connected',
description:
@ -145,7 +145,7 @@ export default function useWallet() {
useInterval(() => {
if (connected && mangoAccount) {
actions.fetchWalletTokens()
actions.fetchProfilePicture()
actions.fetchMangoHeroesNFTs()
actions.fetchTradeHistory()
}
}, 90 * SECONDS)

View File

@ -35,7 +35,11 @@ import { TOKEN_PROGRAM_ID } from '../utils/tokens'
import { findProgramAddress } from '../utils/metaplex/utils'
import * as borsh from 'borsh'
import { Metadata, METADATA_SCHEMA, NFT } from '../utils/metaplex/models'
import { METADATA_KEY, METADATA_PREFIX } from '../utils/metaplex/types'
import {
MANGO_HEROES_MINT_AUTHORITY,
METADATA_KEY,
METADATA_PREFIX,
} from '../utils/metaplex/types'
export const ENDPOINTS: EndpointInfo[] = [
{
@ -283,7 +287,7 @@ const useMangoStore = create<MangoStore>((set, get) => {
})
}
},
async fetchProfilePicture() {
async fetchMangoHeroesNFTs() {
const wallet = get().wallet.current
const connected = get().wallet.connected
const connection = get().connection.current
@ -295,7 +299,7 @@ const useMangoStore = create<MangoStore>((set, get) => {
{ programId: TOKEN_PROGRAM_ID }
)
const nfts = []
const walletNFTs = []
tokenAccounts.value.forEach((token) => {
const tokenAccount = token.account.data.parsed.info
@ -306,15 +310,17 @@ const useMangoStore = create<MangoStore>((set, get) => {
) {
const nft = new NFT()
nft.mintAddress = new PublicKey(tokenAccount.mint)
nfts.push(nft)
walletNFTs.push(nft)
}
})
if (nfts.length == 0) return
if (walletNFTs.length == 0) return
const metadataProgramId = new PublicKey(METADATA_KEY)
for (const nft of nfts) {
const mangoHeroesNFTs = []
for (const nft of walletNFTs) {
// The return value is [programDerivedAddress, bytes] but we only care about the address
const [pda] = await findProgramAddress(
@ -335,12 +341,17 @@ const useMangoStore = create<MangoStore>((set, get) => {
Metadata,
accountInfo!.data
)
if (metadata.updateAuthority == MANGO_HEROES_MINT_AUTHORITY) {
const uri = metadata.data.uri.replace(/\0/g, '')
nft.metadataUri = uri
mangoHeroesNFTs.push(nft)
}
}
set((state) => {
state.settings.nfts = nfts
;(state.settings.nfts = mangoHeroesNFTs),
(state.settings.avatar = localStorage.getItem('profilePic'))
})
}
},

View File

@ -7,6 +7,8 @@ export type StringPublicKey = string
export const EDITION = 'edition'
export const METADATA_PREFIX = 'metadata'
export const METADATA_KEY = 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s'
export const MANGO_HEROES_MINT_AUTHORITY =
'3RVBxNcF1LBAVbxPz1KsueWspASJhqz4ZJGDbxy2mKE3'
export const MAX_AUCTION_DATA_EXTENDED_SIZE = 8 + 9 + 2 + 200