반응형
사용할 프레임 워크 : chakra UI
강의에서는 리액트 17 버전을 사용중이기 때문에 차크라 UI 는 1버전으로 다운로드 해줘야 정상 실행된다.
App.tsx
import React, { FC, useState, useEffect } from "react";
import { BrowserRouter, Routes, Route} from "react-router-dom";
import Layout from "./components/Layout";
import Main from "./routes/main";
import MyAnimal from "./routes/my-animal";
import SaleAnimal from "./routes/sale-animal";
const App: FC = () => {
const [account, setAccount] = useState<string>("");
const getAccount = async () => {
try{
if(window.ethereum){
const accounts = await window.ethereum.request({
method:'eth_requestAccounts',
})
setAccount(accounts[0])
} else{
alert("Install Metamask");
}
}catch(err){
console.log(err);
}
}
useEffect(() => {
getAccount();
console.log(account)
}, [account])
return (
<BrowserRouter>
<Layout>
<Routes>
<Route path="/" element={<Main account={account}/>} />
<Route path="my-animal" element={<MyAnimal account={account}/>} />
<Route path="sale-animal" element={<SaleAnimal account={account}/>} />
</Routes>
</Layout>
</BrowserRouter>
)
};
export default App;
- account 가 바뀔때마다 렌더링을 해주는 방식
- Metamask 설치 유무또한 확인해 주어야한다.
main.tsx
import React , {FC, useState} from 'react';
import {Button, Box, Text, Flex} from '@chakra-ui/react';
import { mintAnimalTokenContract } from '../contracts';
import AnimalCard from '../components/AnimalCard';
interface MainProps {
account :string;
}
const Main : FC<MainProps> = ({account}) => {
const [NewAnimalType, setNewAnimalType] = useState<string>("")
const onClickMint = async () =>{
try{
if(!account) return;
const response = await mintAnimalTokenContract.methods
.mintAnimalToken()
.send({from: account});
console.log(response);
if(response.status){
const balanceLength = await mintAnimalTokenContract.methods
.balanceOf(account)
.call();
const animalTokenId = await mintAnimalTokenContract.methods
.tokenOfOwnerByIndex(account, parseInt(balanceLength.length, 10) -1)
.call();
const animalType = await mintAnimalTokenContract.methods
.animalTypes(animalTokenId)
.call();
setNewAnimalType(animalType);
console.log(NewAnimalType);
}
}catch(err){
console.log(err);
}
}
return <Flex w="full" h= "100vh" justifyContent="center" alignItems="center" direction="column">
<Box>
{NewAnimalType ? <AnimalCard animalType={NewAnimalType} /> : <Text>Let's mint Animal Card!</Text>}
</Box>
<Box>
<Button mt={4} size="sm" colorScheme="blue" onClick={onClickMint}>Mint</Button>
</Box>
</Flex>
}
export default Main;
함수설명
- onClickMint
- 컨트랙트 함수에서 mint 를 호출하여 토큰을 생성하고 토큰의 id, type 을 저장한다.
my-animal.tsx
import React , {FC, useState, useEffect} from "react";
import AnimalCard from "../components/AnimalCard";
import { mintAnimalTokenContract, saleAnimalTokenAddress, saleAnimalTokenContract } from "../contracts";
import {Grid, Box , Button, Text, Flex} from '@chakra-ui/react'
import MyAnimalCard, { IMyanimalCard } from "../components/MyAnimalCard";
interface MyAnimalProps {
account : string;
}
const MyAnimal : FC<MyAnimalProps> = ({account}) =>{
const [AnimalCardArray, setAnimalCardArray] = useState<IMyanimalCard[]>();
const [SaleStatus, setSaleStatus] = useState<boolean>(false);
const getAnimalTokens = async() => {
try{
const balanceLength = await mintAnimalTokenContract.methods
.balanceOf(account)
.call();
if(balanceLength =="0") return ;
const tempAnimalCardArray: IMyanimalCard[] = [];
const response = await mintAnimalTokenContract.methods.getAnimalTokens(account).call();
console.log(response)
response.map((v: IMyanimalCard) => {
tempAnimalCardArray.push({animalTokenId : v.animalTokenId, animalType : v.animalType, animalPrice : v.animalPrice})
})
setAnimalCardArray(tempAnimalCardArray);
}catch(err){
console.log(err);
}
};
const getIsApprovedForAll = async () =>{
try{
const response = await mintAnimalTokenContract.methods
.isApprovedForAll(account, saleAnimalTokenAddress)
.call();
if(response){
setSaleStatus(response);
}
console.log(response);
}catch(err){
console.log(err)
}
}
const onClickApproveToggle = async () =>{
try{
if(!account) return;
const response = await mintAnimalTokenContract.methods
.setApprovalForAll(saleAnimalTokenAddress, !SaleStatus)
.send({from:account});
if(response.status){
setSaleStatus(!SaleStatus);
}
}catch(err){
console.log(err);
}
}
useEffect(() => {
if(!account) return;
getAnimalTokens();
getIsApprovedForAll();
}, [account])
useEffect(() => {
console.log(AnimalCardArray)
}, [AnimalCardArray])
return(
<>
<Flex alignItems="center">
<Text display="inline-block">
Sale Status : {SaleStatus ? "True" : "False"}
</Text>
<Button size="xs" ml={2} colorScheme={SaleStatus ? "red" : "blue"} onClick={onClickApproveToggle}>
{SaleStatus ? "Cancel" : "Approve"}
</Button>
</Flex>
<Grid templateColumns ="repeat(4,1fr)" gap={8} mt={2}>
{
AnimalCardArray && AnimalCardArray.map((v,i) =>{
return <MyAnimalCard key={i} animalTokenId={v.animalTokenId} animalType={v.animalType} animalPrice={v.animalPrice} saleStatus={SaleStatus} account={account}/>;
}
)}
</Grid>
</>
);
}
export default MyAnimal
함수 설명
- getAnimalTokens
- account 가 소유한 카드들을 불러와서 배열형태로 리턴한다.
- getIsApprovedAll
- account 와 카드의 주인이 지닌 주소를 비교해 같지 않은지 확인 한다.
- true 값이 반환되어야 판매등록이 가능하다.
- onClickApproveToggle
- getIsApprovedAll 을 위한 버튼 함수
sale-animal.tsx
import React , {FC, useState, useEffect} from "react";
import {Grid} from "@chakra-ui/react"
import { IMyanimalCard } from "../components/MyAnimalCard";
import { mintAnimalTokenContract, saleAnimalTokenContract } from "../contracts";
import SaleAnimalCard from "../components/SaleAnimalCard";
interface SaleAnimalProps {
account:string;
}
const SaleAnimal:FC<SaleAnimalProps> = ({account}) =>{
const [saleAnimalCard, setSaleAnimalCard] = useState<IMyanimalCard[]>()
const getOnSaleAnimalTokens = async () =>{
try{
const getOnSaleAnimalTokenArrayLength = await saleAnimalTokenContract.methods.getOnSaleAnimalTokenArrayLength().call();
const tempOnSaleArray : IMyanimalCard[] = [];
for(let i = 0;i<parseInt(getOnSaleAnimalTokenArrayLength, 10); i++){
const animalTokenId = await saleAnimalTokenContract.methods.onSaleAnimalTokenArray(i).call();
const animalType = await mintAnimalTokenContract.methods.animalTypes(animalTokenId).call();
const animalPrice = await saleAnimalTokenContract.methods.animalTokenPrices(animalTokenId).call();
tempOnSaleArray.push({animalTokenId, animalType, animalPrice})
}
setSaleAnimalCard(tempOnSaleArray);
} catch(err){
console.log(err);
}
}
useEffect(() => {
getOnSaleAnimalTokens();
}, [])
return(
<Grid mt={4} templateColumns="repeat(4, 1fr)" gap={8}>
{saleAnimalCard && saleAnimalCard.map((v,i) => {
return <SaleAnimalCard key={i} animalType={v.animalType} animalPrice={v.animalPrice} animalTokenId={v.animalTokenId} account={account} getOnSaleAnimalTokens={getOnSaleAnimalTokens}/>
})}
</Grid>
);
}
export default SaleAnimal
함수 설명
- getOnSaleAnimalTokens
- 판매중인 토큰들을 불러오는 함수
- my-animal 과 같이 컨트랙트에서 배열을 받아오면 되지만 강의에서는 귀찮아서 for문으로 했다.
반응형
'BlockChain > Solidity' 카테고리의 다른 글
[DP/NFT] 3. SaleAnimalToken 작성 (0) | 2022.09.05 |
---|---|
[DP/NFT] 2. Minting contract 작성 (0) | 2022.09.05 |
[DP/NFT] 1. Install Solidity & Metamask (0) | 2022.08.25 |