mango-v4-ui/components/rewards/RewardsComponents.tsx

245 lines
7.8 KiB
TypeScript
Raw Normal View History

import {
Dispatch,
SetStateAction,
useCallback,
useEffect,
useRef,
useState,
} from 'react'
import { init, onClick } from '../../lib/render'
import { Claim } from '@blockworks-foundation/mango-mints-redemption'
import { Token } from 'types/jupiter'
import BigNumber from 'bignumber.js'
import { IconButton } from '@components/shared/Button'
import { XMarkIcon } from '@heroicons/react/20/solid'
import useMangoGroup from 'hooks/useMangoGroup'
import { PublicKey } from '@solana/web3.js'
import { CUSTOM_TOKEN_ICONS } from 'utils/constants'
import { Sft, SftWithToken, Nft, NftWithToken } from '@metaplex-foundation/js'
type Prize = {
//symbol
item: string
//amount
info: string
rarity: 'Rare' | 'Legendary' | 'Common'
//eg [32, 32] token, nft [400,400]
itemResolution: number[]
itemUrl: string
particleId: 'particles-coins' | 'particles-fireworks'
stencilUrl:
| '/models/tex_procedural/tex_card_front_gold_circle_albedo.png'
| '/models/tex_procedural/tex_card_front_silver_square_albedo.png'
frontMaterialId:
| 'loader_mat_card_gold_front_circle'
| 'loader_mat_card_silver_front_square'
backMaterialId: 'loader_mat_card_gold_back' | 'loader_mat_card_silver_back'
}
export default function RewardsComponent({
setShowRender,
claims,
tokensInfo,
nftsRewardsInfo,
}: {
setShowRender: Dispatch<SetStateAction<boolean>>
claims: Claim[]
tokensInfo: Token[]
nftsRewardsInfo: (Sft | SftWithToken | Nft | NftWithToken)[]
}) {
const renderLoaded = useRef<boolean>(false)
const { group } = useMangoGroup()
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const [collectedPrizes, setCollectedPrize] = useState([] as any[])
const [muted, setMuted] = useState(true)
const [prizes, setPrizes] = useState<Prize[]>([])
const [currentPrize, setCurrentPrize] = useState()
useEffect(() => {
if (!renderLoaded.current && prizes.length) {
try {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const v1 = document.getElementById('particles-fireworks') as any
v1.onloadedmetadata = () => (v1.currentTime = v1.duration)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const v2 = document.getElementById('particles-coins') as any
v2.onloadedmetadata = () => (v2.currentTime = v2.duration)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
init(document, window, prizes, (prize: any) => {
console.log('callback:showPrize', prize)
setCurrentPrize(prize)
collectedPrizes.push(prize)
setCollectedPrize(collectedPrizes)
setTimeout(() => {
console.log('callback:hidePrize')
setCurrentPrize(undefined)
}, 5000)
})
renderLoaded.current = true
} catch (e) {
//if webgl is turned off or someone uses old computer
console.log(e)
setShowRender(false)
}
}
}, [prizes])
const getFallbackImg = useCallback(
(mint: PublicKey, jupiterLogoUrl: string | undefined) => {
const bank = group?.getFirstBankByMint(mint)
const tokenSymbol = bank?.name.toLowerCase()
const hasCustomIcon = tokenSymbol
? CUSTOM_TOKEN_ICONS[tokenSymbol]
: false
if (hasCustomIcon) {
return `/icons/${tokenSymbol}.svg`
} else {
return jupiterLogoUrl || '/icons/mngo.svg'
}
},
[group],
)
useEffect(() => {
const claimsAsPrizes: Prize[] = claims.map((x) => {
const tokenInfo =
x.mintProperties.type === 'token'
? tokensInfo.find((t) => t.address === x.mint.toBase58())
: null
const nftInfo =
x.mintProperties.type === 'nft'
? nftsRewardsInfo.find(
(ni) => ni.address.toBase58() === x.mint.toBase58(),
)
: null
const resultion =
x.mintProperties.type === 'token' ? [32, 32] : [400, 400]
const materials: {
[key: string]: Omit<
Prize,
'item' | 'info' | 'rarity' | 'itemResolution' | 'itemUrl'
>
} = {
Common: {
particleId: 'particles-coins',
frontMaterialId: 'loader_mat_card_silver_front_square',
backMaterialId: 'loader_mat_card_silver_back',
stencilUrl:
'/models/tex_procedural/tex_card_front_silver_square_albedo.png',
},
Legendary: {
particleId: 'particles-fireworks',
frontMaterialId: 'loader_mat_card_gold_front_circle',
backMaterialId: 'loader_mat_card_gold_back',
stencilUrl:
'/models/tex_procedural/tex_card_front_gold_circle_albedo.png',
},
Rare: {
particleId: 'particles-fireworks',
frontMaterialId: 'loader_mat_card_gold_front_circle',
backMaterialId: 'loader_mat_card_gold_back',
stencilUrl:
'/models/tex_procedural/tex_card_front_gold_circle_albedo.png',
},
}
return {
item: x.mintProperties.name,
info:
x.mintProperties.type === 'token'
? new BigNumber(x.quantity.toString())
.shiftedBy(-tokenInfo!.decimals)
.toString()
: x.quantity.toString(),
rarity: x.mintProperties.rarity,
itemResolution: resultion,
//fallback of img from files if mint matches mango bank
itemUrl:
x.mintProperties.type === 'token'
? getFallbackImg(x.mint, tokenInfo?.logoURI)
: nftInfo?.json?.image || '/icons/mngo.svg',
...materials[
x.mintProperties.rarity as 'Rare' | 'Legendary' | 'Common'
],
}
})
setPrizes(claimsAsPrizes)
}, [claims, getFallbackImg, tokensInfo])
useEffect(() => {
setTimeout(() => {
setMuted(false)
}, 0)
}, [prizes])
return (
<main className="from-midnight-sky to-midnight-horizon static h-screen w-screen bg-gradient-to-b">
<div className="absolute left-[80px] top-0 pl-4">
<IconButton
className="fixed right-4 top-4"
onClick={() => {
setShowRender(false)
}}
>
<XMarkIcon className="h-8 w-8 text-th-fgd-2" />
</IconButton>
<div className="my-2 flex flex-row gap-2">
{collectedPrizes.map((p, i) => {
return (
// eslint-disable-next-line @next/next/no-img-element, jsx-a11y/alt-text
<img key={i} className="h-24 rounded-lg" src={p.cardImgUrl} />
)
})}
</div>
{!!currentPrize && (
<>
2023-09-28 04:02:32 -07:00
<p className={`-mb-3 font-rewards text-4xl text-white`}>
{currentPrize['item']}
</p>
{/* common: text-sky-300
rare: text-yellow-300
legendary: text-orange-400 */}
2023-09-28 04:02:32 -07:00
<p className={`-mb-2 font-rewards text-3xl text-yellow-300`}>
{currentPrize['rarity']}
</p>
<p id="info-text" className={`font-rewards text-3xl text-white`}>
{currentPrize['info']}
</p>
</>
)}
</div>
<div id="render-output" onClick={onClick}></div>
<video
className="hidden"
id="particles-coins"
preload="true"
playsInline
muted={muted}
>
<source
src="/particles/coins_2k_hvc1.mov"
type="video/mp4;codecs=hvc1"
/>
<source src="/particles/coins_2k_vp9.webm" type="video/webm" />
</video>
<video
className="hidden"
id="particles-fireworks"
preload="true"
playsInline
muted={muted}
>
<source
src="/particles/fireworks_2k_hvc1.mov"
type="video/mp4;codecs=hvc1"
/>
<source src="/particles/fireworks_2k_vp9.webm" type="video/webm" />
</video>
</main>
)
}