Skip to content

Commit

Permalink
ipfs upload with pinata. nft minting function done
Browse files Browse the repository at this point in the history
  • Loading branch information
iskysun96 committed Jan 16, 2024
1 parent 20dbe67 commit 69a0924
Show file tree
Hide file tree
Showing 8 changed files with 392 additions and 12 deletions.
92 changes: 92 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
"@txnlab/use-wallet": "^2.1.1",
"@walletconnect/modal-sign-html": "^2.6.1",
"algosdk": "^2.5.0",
"axios": "^1.6.5",
"daisyui": "^3.1.0",
"form-data": "^4.0.0",
"notistack": "^3.0.1",
"react": "^18.2.0",
"react-dom": "18.2.0",
Expand Down
13 changes: 10 additions & 3 deletions src/components/Hero.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { useWallet } from '@txnlab/use-wallet'
import { useState } from 'react'
import ConnectWallet from './ConnectWallet'
import MintNft from './mintNft'
import MintNft from './MintNft'

const Hero = () => {
const [openWalletModal, setOpenWalletModal] = useState<boolean>(false)
const [openTransactModal, setOpenTransactModal] = useState<boolean>(false)
const { activeAddress } = useWallet()

const toggleWalletModal = () => {
setOpenWalletModal(!openWalletModal)
}

const toggleTransactModal = () => {

Check warning on line 15 in src/components/Hero.tsx

View workflow job for this annotation

GitHub Actions / checks

'toggleTransactModal' is assigned a value but never used

Check warning on line 15 in src/components/Hero.tsx

View workflow job for this annotation

GitHub Actions / CI dApp / checks

'toggleTransactModal' is assigned a value but never used
setOpenTransactModal(!openTransactModal)
}
return (
<div className="hero min-h-screen bg-base-200">
<div className="hero-content text-center">
Expand All @@ -23,11 +28,13 @@ const Hero = () => {
</p>

{activeAddress ? (
<MintNft />
<div>
<MintNft />
</div>
) : (
<div>
<button
className="btn m-2 bg-green-500 rounded border-none hover:bg-green-600 transition-colors duration-300"
className="btn m-2 bg-yellow-200 rounded border-none hover:bg-yellow-300 transition-colors duration-300"
onClick={toggleWalletModal}
>
{activeAddress ? 'Disconnect' : 'Connect Wallet'}
Expand Down
112 changes: 107 additions & 5 deletions src/components/MintNft.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,35 @@ Minting
- Minting should:
= upload image to IPFS
- unitName should start with "dia"+ today's date?
= NFT name should be the emotion of the day + date (e.g. "happy 2021-09-01")
= NFT name should be one sentence explaining the day + date (e.g. "Walk in the park 2021-09-01")
*/

import * as algokit from '@algorandfoundation/algokit-utils'
import { TransactionSignerAccount } from '@algorandfoundation/algokit-utils/types/account'
import { useWallet } from '@txnlab/use-wallet'
import algosdk from 'algosdk'
import { useSnackbar } from 'notistack'
import { useCallback, useEffect, useState } from 'react'
import { useDropzone } from 'react-dropzone'
import { pinFileToIPFS, pinJSONToIPFS } from '../utils/pinata'
import { getAlgodClient } from '../utils/setupClients'

const MintNft = () => {
const [nftImageUrl, setNftImageUrl] = useState<string>('')
const [nftImage, setNftImage] = useState<File | undefined>()
const [nftName, setNftName] = useState<string>('')
const [loading, setLoading] = useState<boolean>(false)

const { enqueueSnackbar } = useSnackbar()
const { signer, activeAddress, signTransactions, sendTransactions } = useWallet()

Check warning on line 38 in src/components/MintNft.tsx

View workflow job for this annotation

GitHub Actions / checks

'signTransactions' is assigned a value but never used

Check warning on line 38 in src/components/MintNft.tsx

View workflow job for this annotation

GitHub Actions / checks

'sendTransactions' is assigned a value but never used

Check warning on line 38 in src/components/MintNft.tsx

View workflow job for this annotation

GitHub Actions / CI dApp / checks

'signTransactions' is assigned a value but never used

Check warning on line 38 in src/components/MintNft.tsx

View workflow job for this annotation

GitHub Actions / CI dApp / checks

'sendTransactions' is assigned a value but never used

const today = new Date()
const formattedDate = today.toLocaleDateString('en-CA')
const DateWithoutDashes = formattedDate.replace(/-/g, '').substring(2)

const onDrop = useCallback((acceptedFiles: FileList) => {
// setNFTImageUrl to preview image
setNftImage(acceptedFiles[0])
const reader = new FileReader()
reader.onload = () => {
setNftImageUrl(reader.result as string)
Expand All @@ -34,24 +52,108 @@ const MintNft = () => {
}, [])
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })

const imageToArc3 = async (file: File): Promise<string> => {
const ipfsHash = await pinFileToIPFS(file)
const metadataRoot = await pinJSONToIPFS(`${nftName} ${formattedDate}`, `dia${formattedDate}`, String(ipfsHash), file)

console.log(metadataRoot)

Check warning on line 59 in src/components/MintNft.tsx

View workflow job for this annotation

GitHub Actions / checks

Unexpected console statement

Check warning on line 59 in src/components/MintNft.tsx

View workflow job for this annotation

GitHub Actions / CI dApp / checks

Unexpected console statement
return String(metadataRoot)
}

// Set up algod, Indexer
const algodClient = getAlgodClient()

const handleTextInput = (e: { target: { value: string } }) => {
setNftName(e.target.value)
}

const handleFormSummit = async () => {
setLoading(true)

if (!signer || !activeAddress) {
enqueueSnackbar('Please connect wallet first', { variant: 'warning' })
setLoading(false)
return
}

const signingAccount = { signer, addr: activeAddress } as TransactionSignerAccount

if (!nftImage) {
enqueueSnackbar('Please connect wallet first', { variant: 'warning' })
setLoading(false)
return
}
const metadataRoot = await imageToArc3(nftImage).catch((e: Error) => {
enqueueSnackbar(`Error during image upload to IPFS: ${e.message}`, { variant: 'error' })
setLoading(false)
return
})
console.log('metadataRoot: ', metadataRoot)

Check warning on line 91 in src/components/MintNft.tsx

View workflow job for this annotation

GitHub Actions / checks

Unexpected console statement

Check warning on line 91 in src/components/MintNft.tsx

View workflow job for this annotation

GitHub Actions / CI dApp / checks

Unexpected console statement
console.log(DateWithoutDashes)

Check warning on line 92 in src/components/MintNft.tsx

View workflow job for this annotation

GitHub Actions / checks

Unexpected console statement

Check warning on line 92 in src/components/MintNft.tsx

View workflow job for this annotation

GitHub Actions / CI dApp / checks

Unexpected console statement
try {
const sp = await algodClient.getTransactionParams().do()
const nftCreateTxn = algosdk.makeAssetCreateTxnWithSuggestedParamsFromObject({
from: activeAddress,
suggestedParams: sp,
defaultFrozen: false,
assetName: `${nftName} ${formattedDate}`,
unitName: `pd${DateWithoutDashes}`,
manager: activeAddress,
reserve: activeAddress,
assetURL: `ipfs://${metadataRoot}/#arc3`,
total: 1,
decimals: 0,
})

const { transaction, confirmation } = await algokit.sendTransaction(
{
transaction: nftCreateTxn,
from: signingAccount,
sendParams: {
suppressLog: true,
},
},
algodClient,
)

enqueueSnackbar(`Successfully Created Photo Diary with Asset ID: ${confirmation?.assetIndex}`, { variant: 'success' })

console.log(`Asset ID created: ${confirmation?.assetIndex}`)
setNftImageUrl('')
setNftImage(undefined)
setNftName('')
} catch (error) {
console.error(error)
setLoading(false)
}
setLoading(false)
}

useEffect(() => {
console.log(nftImageUrl)
}, [nftImageUrl])

return (
<div className="max-w-xl mt-4 mb-4">
{nftImageUrl ? (
<div className="flex flex-col">
<div className="form-control">
<img src={nftImageUrl} />
<input type="text" className="rounded mt-2 mb-2" placeholder="Enter NFT Name" onChange={handleTextInput} />
<button>Create Photo Diary</button>
<input
type="text"
placeholder="What did you do today?"
className="input rounded-r w-full my-4"
onChange={handleTextInput}
maxLength={21} //max asa name is 32 bytes so 32 characters long. 11 characters for date
/>
<button
className="btn m-2 bg-yellow-200 rounded border-none hover:bg-yellow-300 transition-colors duration-300"
onClick={handleFormSummit}
>
{loading ? <span className="loading loading-spinner" /> : 'Create Photo Diary'}
</button>
</div>
) : (
<label className="flex justify-center w-full h-32 px-4 transition bg-white border-2 border-gray-300 border-dashed rounded-md appearance-none cursor-pointer hover:border-gray-400 focus:outline-none">
<label className="flex justify-center w-full h-64 px-4 transition bg-white border-2 border-gray-300 border-dashed rounded-md appearance-none cursor-pointer hover:border-gray-400 focus:outline-none">
<div {...getRootProps()} className="flex items-center">
{isDragActive ? (
<p>Drag 'n' drop some files here, or click to select files</p>
Expand Down
8 changes: 4 additions & 4 deletions src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { useWallet } from '@txnlab/use-wallet'
import { useState } from 'react'
import ConnectWallet from './ConnectWallet'
// types
interface NavItemProps {
active?: boolean
}
// interface NavItemProps {
// active?: boolean
// }

interface MyNavbarProps {
activeTab: number
Expand Down Expand Up @@ -82,7 +82,7 @@ export const Navbar = ({ setActiveTab, activeTab }: MyNavbarProps) => {
{activeAddress && (
<div className="flex-end">
<button
className="btn m-2 bg-green-500 rounded border-none hover:bg-green-600 transition-colors duration-300"
className="btn m-2 bg-yellow-200 rounded border-none hover:bg-yellow-300 transition-colors duration-300"
onClick={toggleWalletModal}
>
Disconnect
Expand Down
Loading

0 comments on commit 69a0924

Please sign in to comment.