Skip to content

Commit

Permalink
🌈🧪 -> Thanks @mallory-jpg for fix in #15 #16 selectCharacter
Browse files Browse the repository at this point in the history
  • Loading branch information
Gizmotronn committed Feb 18, 2022
1 parent e5bb48b commit 47d608f
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 75 deletions.
64 changes: 50 additions & 14 deletions frontend/src/App.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from 'react';
import twitterLogo from './assets/twitter-logo.svg';
import './App.css';
import LoadingIndicator from './Components/LoadingIndicator';

// Smart contract component imports
import SelectCharacter from './Components/SelectCharacter';
Expand Down Expand Up @@ -81,6 +82,8 @@ const App = () => {
const [currentAccount, setCurrentAccount] = useState(null);
const [characterNFT, setCharacterNFT] = useState(null);

const [isLoading, setIsLoading] = useState(false);

// Actions
const checkIfWalletIsConnected = async () => {
try {
Expand All @@ -107,8 +110,41 @@ const App = () => {
}
};

// Render -> if user is connected AND does not have a character NFT, show SelectCharacter component
useEffect(() => {
const fetchNFTMetadata = async () => {
console.log('Checking for Character NFT on address:', currentAccount);

const provider = new ethers.providers.Web3Provider(window.ethereum); // component that talks to the ethereum nodes
const signer = provider.getSigner();
const gameContract = new ethers.Contract( // Contract object -> creates connection to the contract
CONTRACT_ADDRESS,
GameContent.abi,
signer
);

const txn = await gameContract.checkIfUserHasNFT();
if (txn.name) {
console.log('User has character NFT');
setCharacterNFT(transformCharacterData(txn));
} else {
console.log('User does not have character NFT');
}
};

// Only run this if the user is connected
if (currentAccount) {
console.log('Checking for Character NFT on address:', currentAccount);
fetchNFTMetadata();
}
}, [currentAccount]); // Fire this useEffect only when currentAccount changes

// Rendering dynamic user content to the frontend
const renderContent = () => {
console.log(currentAccount, " - ", characterNFT);
if (currentAccount && isLoading) {
return <LoadingIndicator />;
}
// If user isn't signed in
if (!currentAccount) {
return (
Expand Down Expand Up @@ -154,20 +190,6 @@ const App = () => {
}
};

useEffect(() => {
checkIfWalletIsConnected();

const checkNetwork = async () => {
try {
if (window.ethereum.networkVersion !== '4') {
alert('Please switch to the Rinkeby test network');
}
} catch (error) {
console.log(error);
}
}
}, []);

// Render -> if user is connected AND does not have a character NFT, show SelectCharacter component
useEffect(() => {
const fetchNFTMetadata = async () => {
Expand Down Expand Up @@ -197,6 +219,20 @@ const App = () => {
}
}, [currentAccount]); // Fire this useEffect only when currentAccount changes

useEffect(() => {
checkIfWalletIsConnected();

const checkNetwork = async () => {
try {
if (window.ethereum.networkVersion !== '4') {
alert('Please switch to the Rinkeby test network');
}
} catch (error) {
console.log(error);
}
}
}, []);

return (
<div className="App">
<div className="container">
Expand Down
121 changes: 68 additions & 53 deletions frontend/src/Components/SelectCharacter/index.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
import React, { useEffect, useState } from 'react';
import './SelectCharacter.css'
import './SelectCharacter.css';
import { ethers } from 'ethers';
import { CONTRACT_ADDRESS, transformCharacterData } from '../../constants';
import GameContent from '../../utils/GameContent.json';
import gameContent from '../../utils/GameContent.json'
// import LoadingIndicator from './Components/LoadingIndicator';
import './SelectCharacter.css';

const SelectCharacter = ({ setCharacterNFT }) => {
const [characters, setCharacters] = useState([]);
const [gameContract, setGameContract] = useState(null);
const [mintingCharacter, setMintingCharacter] = useState(false);

const mintCharacterNFTAction = (characterId) => async () => {
try {
if (gameContract) {
console.log('Minting character in progress...');
const mintTxn = await gameContract.mintCharacterNFT(characterId);
await mintTxn.wait();
console.log('mintTxn:', mintTxn);
}
} catch (error) {
console.warn('MintCharacterAction Error:', error);
}
}
// Render Methods
const renderCharacters = () =>
characters.map((character, index) => (
<div className="character-item" key={character.name}>
<div className="name-container">
<p>{character.name}</p>
</div>
<img src={character.imageURI} alt={character.name} />
<button
type="button"
className="character-mint-button"
onClick={mintCharacterNFTAction(index)}
>{`Mint ${character.name}`}</button>
</div>
));

// Display mintable characters
// UseEffect
useEffect(() => {
const { ethereum } = window;

Expand All @@ -30,94 +36,103 @@ const SelectCharacter = ({ setCharacterNFT }) => {
const signer = provider.getSigner();
const gameContract = new ethers.Contract(
CONTRACT_ADDRESS,
GameContent.abi,
gameContent.abi,
signer
);

// Set the gameContract in state
setGameContract(gameContract);
} else {
console.log("Ethereum object not found");
console.log('Ethereum object not found');
}

}, []);

// Fetch all characters
// Actions
const mintCharacterNFTAction = (characterId) => async () => {
try {
if (gameContract) {
setMintingCharacter(true);
console.log('Minting character in progress...');
const mintTxn = await gameContract.mintCharacterNFT(characterId);
await mintTxn.wait();
console.log('mintTxn:', mintTxn);
// hides loading indicator when done with Action
setMintingCharacter(false);
}
} catch (error) {
console.warn('MintCharacterAction Error:', error);
setMintingCharacter(false);
}

};

useEffect(() => {
const getCharacters = async () => {
try {
console.log('Getting contract characters to mint');

// Call contract function to get all characters
const charactersTxn = await gameContract.getAllDefaultCharacters();
console.log('charactersTxn:', charactersTxn);

// Transform the data of all the characters
const characters = charactersTxn.map((characterData) =>
transformCharacterData(characterData)
);

// Set all mint-able characters in state
setCharacters(characters);
} catch (error) {
console.error("Something went wrong fetching characters:", error);
console.error('Something went wrong fetching characters:', error);
}
};

const onCharacterMint = async (sender, tokenId, characterIndex) => { // Called whenever a new character NFT is minted
const onCharacterMint = async (sender, tokenId, characterIndex) => {
console.log(
`CharacterNFTMinted - sender: ${sender} tokenId: ${tokenId.toNumber()} characterIndex: ${characterIndex.toNumber()}`
);
alert(`Your NFT is all done -- see it here: https://testnets.opensea.io/assets/${gameContract}/${tokenId.toNumber()}`);

// Once the character NFT is minted, we can fetch the metadata from the contract and set it in state to move onto the Arena (game scene)
if (gameContract) {
const characterNFT = await gameContract.checkIfUserHasNFT();
console.log('Character NFT: ', characterNFT);
console.log('CharacterNFT: ', characterNFT);
setCharacterNFT(transformCharacterData(characterNFT));
}
};

// Get the characters
if (gameContract) {
getCharacters();

// Set up NFT Minted listener
gameContract.on('CharacterNFTMinted', onCharacterMint);
// alert(`Your NFT is all done -- see it here: https://testnets.opensea.io/assets/${gameContract}/${tokenId.toNumber()}`);
}

return () => {
// When the component unmounts, clean up this listener
if (gameContract) {
gameContract.off('CharacterNFTMinted', onCharacterMint);
}
};
}, [gameContract]);

// Render MethodsComp
const renderCharacters = () => {
characters.map((character, index) => (
<div className="characters-item" key={characters.name}>
<div className="name-container">
<p>{characters.name}</p>
</div>
<img src={characters.imageURI} alt={characters.name} />
<button
type="button"
className='character-mint-button'
onClick={mintCharacterNFTAction(index)}
>{`Mint ${character.name}`}</button>
</div>
));
}

return (
<div className="select-character-container">
<h2>Mint Your Hero. Choose wisely.</h2>
{/* Only show this when there are characters in state */}
<h2>Mint Your Hero. Save El Barrio.</h2>
{characters.length > 0 && (
<div className="character-grid">{renderCharacters()}</div>
)}
{mintingCharacter}
</div>

);
};

export default SelectCharacter;


export default SelectCharacter;

/*
{* Only show our loading state if mintingCharacter is true *}
{mintingCharacter && (
<div className="loading-indicator">
<LoadingIndicator />
<p>Minting In Progress...</p>
<img
src="https://media1.giphy.com/media/Q8yVhekmYfdZvyojKx/giphy.gif?cid=ecf05e47k8h41kmgubdok3raoc8rto2xue8p4n2c1h8f72dq&rid=giphy.gif&ct=g"
alt="Minting loading indicator"
/>
</div>
)}
*/
2 changes: 1 addition & 1 deletion frontend/src/constants.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const CONTRACT_ADDRESS = "0x8aD3C1b653E5543dfb72bd9c249D943968e0fA77";
const CONTRACT_ADDRESS = "0x1Ffe78935e014927E5064F0656b072fD5e2b1b8e";

const transformCharacterData = (characterData) => {
return {
Expand Down
8 changes: 5 additions & 3 deletions hardhat.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ module.exports = {
solidity: '0.8.1',
networks: {
rinkeby: {
url: process.env.ALCHEMY, // Alchemy Rinkeby URL
accounts: [process.env.PRIVATE], // This is the private key of the account (rinkeby)
url: "https://eth-rinkeby.alchemyapi.io/v2/gQUHfEyfP_v73J37inUmWzPnYN0nOLr_",
accounts: ["a7a2f59191ce8477761f043f9da63a40ced24f803fd6a423930585e981ef5554"]
/*url: process.env.ALCHEMY, // Alchemy Rinkeby URL
accounts: [process.env.PRIVATE], // This is the private key of the account (rinkeby)*/
},
},
};
};
8 changes: 4 additions & 4 deletions scripts/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ const main = async () => {
const gameContractFactory = await hre.ethers.getContractFactory("GameContent"); // Compiles the contract
const gameContract = await gameContractFactory.deploy(
["Scrooby", "Gizmo", "Elsie"], // Names
["https://i.imgur.com/pKd5Sdk.png", // Images
"https://i.imgur.com/xVu4vFL.png",
"https://i.imgur.com/WMB6g9u.png"],
["https://www.pinclipart.com/picdir/middle/85-850316_r2-d2-icon-r2d2-icon-clipart.png", // Images
"https://static.thenounproject.com/png/318368-200.png",
"https://www.clipartmax.com/png/middle/31-312830_bb8-vector-google-search-star-wars-bb8-birthday-card.png"],
[100, 200, 300], // HP Values
[100, 50, 25], // Attack damage values
"Scroobus", // Boss name
"https://i.imgur.com/AksR0tt.png", // Boss image
"https://w7.pngwing.com/pngs/759/987/png-transparent-php-computer-icons-web-development-logo-icon-text-trademark-logo.png", // Boss image
10000, // Boss HP
500 // Boss attack damage
); // Hardhat creates a local Eth network just for this contract with refresh for every deploy
Expand Down

0 comments on commit 47d608f

Please sign in to comment.