Skip to content

Commit

Permalink
Merge pull request #81 from yuki-wtf/handle-pending-mints
Browse files Browse the repository at this point in the history
Handle pending mints
  • Loading branch information
lorcan-codes authored Jan 29, 2024
2 parents c5332d0 + 8c62391 commit b15ebcd
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 116 deletions.
22 changes: 21 additions & 1 deletion app/components/Snapshot/Snapshot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,24 @@ const SkeletonImagePreview = () => {
</StyledSkeletonGridContainer>
)
}
export interface MintedNFT {
type: 'minted'
tokenId: string
userAddress: string
gameGeneration: string
transactionHash: string
contractAddress: string
}

export interface PendingNFT {
type: 'pending'
generation: string
status: string
txHash: string
userId: string
}

export type NFT = MintedNFT | PendingNFT
interface Props {
readonly onClick?: React.MouseEventHandler<HTMLLIElement>
readonly onClickTwitter?: React.MouseEventHandler<HTMLAnchorElement | HTMLButtonElement>
Expand All @@ -228,6 +245,8 @@ interface Props {
readonly initial?: AnimationProps['initial']
readonly animate?: AnimationProps['animate']
readonly exit?: AnimationProps['exit']
readonly refreshPage?: () => void
readonly nft?: NFT
}

const Snapshot = ({
Expand All @@ -242,6 +261,7 @@ const Snapshot = ({
animate,
exit,
nft,
refreshPage,
}: Props) => {
const formattedUser = user ? getShortChecksumAddress(user) : null

Expand Down Expand Up @@ -292,7 +312,7 @@ const Snapshot = ({
width: '100%',
}}
>
{gameGeneration && <SnapshotMint generation={gameGeneration} nft={nft} />}
{gameGeneration && <SnapshotMint generation={gameGeneration} nft={nft} refreshPage={refreshPage} />}
{large && (
<Button
tertiary
Expand Down
114 changes: 76 additions & 38 deletions app/components/Snapshot/SnapshotMint.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import { useAccount, useProvider } from '@starknet-react/core'
import { CallData, cairo } from 'starknet'
import Button from '../Button'
import { useRootLoaderData } from '~/hooks/useRootLoaderData'
import { useFetcher } from '@remix-run/react'
import { useNftContract } from '~/hooks/useNftContract'
import { useCheckNetwork } from '~/helpers/useCheckNetwork'
import { useDialog } from '~/hooks/Dialog'
import { useUser } from '~/hooks/useUser'
import type { NFT } from './Snapshot'

const MintedAddressContainer = styled.div`
display: flex;
Expand Down Expand Up @@ -37,16 +38,56 @@ const MintedAddressContainer = styled.div`
}
`

export const SnapshotMint = ({ generation, nft }: { generation: string }) => {
interface Props {
generation: string
nft?: NFT
refreshPage?: () => void
}
export const SnapshotMint = ({ generation, nft, refreshPage }: Props) => {
const user = useUser()
const { account } = useAccount()
const { provider } = useProvider()
const { env } = useRootLoaderData()
const starkscan = env.USE_MAINNET ? 'https://starkscan.co' : 'https://testnet.starkscan.co'
const fetcher = useFetcher()
const { isCorrectNetwork } = useCheckNetwork()
const [_, setDialog] = useDialog()
const { contract: nftContract } = useNftContract()

const addMintToPending = async (generationNumber: number, txHash: string) => {
const formData = new FormData()

formData.append('generation', String(generationNumber))
formData.append('txHash', txHash)
formData.append('userId', user?.userId || '')
formData.append('status', 'RECEIVED')

const res = await fetch('/api/mints', {
body: formData,
method: 'post',
})

const data = await res.json()
if (data.status === 'success') {
refreshPage?.()
}
}

const onMintError = async (generationNumber: string) => {
const formData = new FormData()

formData.append('generation', String(generationNumber))

const res = await fetch('/api/mints', {
body: formData,
method: 'delete',
})

const data = await res.json()
if (data.status === 'success') {
refreshPage?.()
}
}

const mintGame = async (generation: string) => {
if (!account || !nftContract) {
return
Expand All @@ -69,57 +110,54 @@ export const SnapshotMint = ({ generation, nft }: { generation: string }) => {
calldata: CallData.compile([generation]),
},
])

addMintToPending(generation, multiCall.transaction_hash)

return provider.waitForTransaction(multiCall.transaction_hash)
}

const isLoading = false
if (!nft) {
const isPending = nft?.type === 'pending'
if (!nft || isPending) {
return (
<Button
secondary
label={isLoading ? 'Pending' : 'Mint as NFT'}
isLoading={isLoading}
icon={isLoading}
label={isPending ? 'Pending' : 'Mint as NFT'}
isLoading={isPending}
icon={isPending}
color="#F3E9E1"
disabled={isPending}
onClick={(e) => {
e.stopPropagation()
if (!isCorrectNetwork) {
setDialog('WrongNetworkDialog')
return
}
mintGame(generation).then((minted) => {
console.log('minted', minted)
fetcher.load('/snapshots')
})
mintGame(generation).catch((err) => onMintError(generation))
}}
/>
)
}

if (nft) {
return (
<MintedAddressContainer>
<FaCircleCheck color="#27CE60" />
<div className="address">
MINTED ON CHAIN:
<a
href={`${starkscan}/nft/${nft.contractAddress}/${nft.gameGeneration}`}
target="_blank"
rel="noreferrer"
style={{
display: 'flex',
alignItems: 'center',
gap: '2px',
}}
onClick={(e) => e.stopPropagation()}
>
{getShortMintAddress(nft.transactionHash, 5, 3)}
<HiOutlineExternalLink />
</a>
</div>
</MintedAddressContainer>
)
}

return null
return (
<MintedAddressContainer>
<FaCircleCheck color="#27CE60" />
<div className="address">
MINTED ON CHAIN:
<a
href={`${starkscan}/nft/${nft.contractAddress}/${nft.gameGeneration}`}
target="_blank"
rel="noreferrer"
style={{
display: 'flex',
alignItems: 'center',
gap: '2px',
}}
onClick={(e) => e.stopPropagation()}
>
{getShortMintAddress(nft.transactionHash, 5, 3)}
<HiOutlineExternalLink />
</a>
</div>
</MintedAddressContainer>
)
}
48 changes: 48 additions & 0 deletions app/helpers/addMintedNftDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck

import { getChecksumAddress } from 'starknet'
import type { MintedNFT } from '~/components/Snapshot/Snapshot'
const targetContractAddress = process.env.NFT_CONTRACT_ADDRESS

function transformNfts(nfts) {
const nftsByGeneration = {}
nfts.forEach((nft) => {
if (nft.token_id) {
nftsByGeneration[nft.token_id] = nft
}
})
return nftsByGeneration
}

export function addMintedNftDetails(snapshots, nfts) {
const nftsByGeneration = transformNfts(nfts)

const snapshotsWithNfts = snapshots.map((snapshot) => {
const snapshotWithNft = { ...snapshot }
const nft = nftsByGeneration[snapshot.gameGeneration]

if (nft && getChecksumAddress(nft.contract_address) === getChecksumAddress(targetContractAddress)) {
const gameModeAttribute = nft.attributes.find((attr) => attr.trait_type === 'Game Mode')

const nftData: MintedNFT = {
type: 'minted',
tokenId: nft.token_id,
userAddress: nft.minted_by_address,
gameGeneration: snapshot.gameGeneration,
transactionHash: nft.minted_at_transaction_hash,
contractAddress: nft.contract_address,
}
if (gameModeAttribute) {
nftData.gameMode = gameModeAttribute.value
}
snapshotWithNft.nft = nftData
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return snapshotWithNft
})

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return snapshotsWithNfts
}
28 changes: 28 additions & 0 deletions app/helpers/addPendingNftDetails.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { PendingNFT } from '~/components/Snapshot/Snapshot'

export const addPendingNftDetails = (snapshotsWithMintedNfts: any[], pendingMints: any[]) => {
const idsToRemove: number[] = []
const snapshotsWithPendingAndMintedNfts = [...snapshotsWithMintedNfts]
snapshotsWithPendingAndMintedNfts.forEach((snapshot: any) => {
const pendingMint = pendingMints.find((mint) => mint.generation == snapshot.gameGeneration)

if (pendingMint) {
if (snapshot.nft) {
idsToRemove.push(pendingMint.generation)
// remove pending mint from db
} else {
const pendingNft: PendingNFT = {
type: 'pending',
generation: pendingMint.generation,
status: pendingMint.status,
txHash: pendingMint.txHash,
userId: pendingMint.userId,
}

snapshot.nft = pendingNft
}
}
})

return { snapshotsWithPendingAndMintedNfts, idsToRemove }
}
Loading

0 comments on commit b15ebcd

Please sign in to comment.