So I was working on cloning rarible tutorial but now I’m stuck.
first I encountered a problem that the ownedItems.forEach
doesn’t get recognized as a function.
and my second problem is that when I try to save the avatar of a user/my avatar doesn’t change and it gives the error that there is a duplicate value in a file I don’t even recognize here are the errors I am getting. If someone could help me that would be awesome been stuck on this for a few days now.
Have a nice day!
this is the
main.js
code:
// NFT2
Moralis.initialize("zGgSNOTQkkXCWjBTVH93dZ9JBzQT55xrtJe29JPB");
Moralis.serverURL = 'https://3rsjrx0pchtl.usemoralis.com:2053/server'
const TOKEN_CONTRACT_ADDRESS = "0x3D205305B9d3f477e767f849C55aB24f73B633eC";
const MARKETPLACE_CONTRACT_ADDRESS = "0x94aD855c7ABD8AE4Ec85936a9D21E2D1042A89E5";
init = async () => {
hideElement(userItemsSection);
hideElement(userInfo);
hideElement(createItemForm);
window.web3 = await Moralis.Web3.enable();
window.tokenContract = new web3.eth.Contract(tokenContractAbi, TOKEN_CONTRACT_ADDRESS);
window.marketplaceContract = new web3.eth.Contract(tokenContractAbi, MARKETPLACE_CONTRACT_ADDRESS);
initUser();
}
//if user logges in show userprofile and createitem else hide these buttons and show the button that the user has to connect.
initUser = async () => {
if(await Moralis.User.current()){
hideElement(userConnectButton);
showElement(userProfileButton);
showElement(openCreateItemButton);
showElement(openUserItemsButton);
loadUserItems();
} else {
showElement(userConnectButton);
hideElement(userProfileButton);
hideElement(openCreateItemButton);
hideElement(openUserItemsButton);
}
}
//login button.
login = async () => {
try{
await Moralis.Web3.authenticate();
initUser();
} catch (error) {
alert(error);
}
}
//logout button and hide the user info.
logout = async () => {
await Moralis.User.logOut();
hideElement(userInfo);
initUser();
}
//when user is logged in show the user info.
openUserInfo = async () => {
user = await Moralis.User.current();
if (user){
const email = user.get('email');
if(email){
userEmailField.value = email;
} else{
userEmailField.value = "";
}
userUsernameField.value = user.get('username');
const userAvatar = user.get('avatar');
if(userAvatar){
userAvatarImg.src = userAvatar.url();
showElement(userAvatarImg);
}else{
hideElement(userAvatarImg);
}
showElement(userInfo);
} else{
login();
}
}
//save user info set email and username.
saveUserinfo = async () => {
user.set('email', userEmailField.value);
user.set('username', userUsernameField.value);
if (userAvatarFile.files.length > 0) {
const avatar = new Moralis.File("avatar1.jpg", userAvatarFile.files[0]);
user.set('avatar', avatar);
}
await user.save();
alert("User info saved successfully!");
openUserInfo();
}
//create the item that the user selected.
createItem = async () => {
if (createItemFile.files.length == 0){
alert("Please select a file!");
return;
} else if(createItemNameField.value.length == 0){
alert("Please give item a name!");
return;
}
const nftFile = new Moralis.File("nftFile.jpg", createItemFile.files[0]);
await nftFile.saveIPFS();
const nftFilePath = nftFile.ipfs();
const nftFileHash = nftFile.hash();
const metadata = {
name: createItemNameField.value,
description: createItemDescriptionField.value,
image: nftFilePath
};
const nftFileMetadatFile = new Moralis.File("metadata.json", {base64 : btoa(JSON.stringify(metadata))});
await nftFileMetadatFile.saveIPFS();
const nftFileMetadatFilepath = nftFileMetadatFile.ipfs();
const nftFileMetadatFilehash = nftFileMetadatFile.hash();
const nftId = await mintNft(nftFileMetadatFilepath);
const Item = Moralis.Object.extend("Item");
// Create a new instance of that class.
const item = new Item();
item.set('name', createItemNameField.value);
item.set('description', createItemDescriptionField.value);
item.set('nftFilePath', nftFilePath);
item.set('nftFileHash', nftFileHash);
item.set('MetadatFilepath', nftFileMetadatFilepath);
item.set('MetadatFilehash', nftFileMetadatFilehash);
item.set('nftId', nftId);
item.set('nftContractAddress', TOKEN_CONTRACT_ADDRESS);
await item.save();
console.log(item);
user = await Moralis.User.current();
const userAddress = user.get('ethAddress');
switch(createItemStatusField.value){
case "0":
return;
case "1":
await ensureMarketplaceIsApproved(nftId, TOKEN_CONTRACT_ADDRESS);
await marketplaceContract.methods.addItemToMarket(nftId, TOKEN_CONTRACT_ADDRESS, createItemPriceFild.value);
break;
case "2":
alert("Not yet supported!");
return;
}
}
//mint nft call create item and send the NFT to the creator address
mintNft = async (metadetaUrl) => {
const receipt = await tokenContract.methods.createItem(metadetaUrl).send({from: ethereum.selectedAddress});
console.log(receipt);
return receipt.events.Transfer.returnValues.tokenId;
}
openUserItems = async () => {
user = await Moralis.User.current();
if (user){
showElement(userItemsSection);
} else{
login();
}
}
loadUserItems = async () => {
const ownedItems = await Moralis.Cloud.run("getUserItems");
console.log(ownedItems);
ownedItems.forEach(item => {
getAndRenderItemData(item, renderUserItem);
});
}
initTemplate = (id) => {
const template = document.getElementById(id);
template.id = "";
template.parentNode.removeChild(template);
return template;
}
renderUserItem = (item) => {
const userItem = userItemTemplate.cloneNode(true);
userItem.getElementsByTagName("img")[0].src = item.image;
userItem.getElementsByTagName("img")[0].alt = item.name;
userItem.getElementsByTagName("h5")[0].innerText = item.name;
userItem.getElementsByTagName("p")[0].innerText = item.description;
userItems.appendChild(userItem);
}
getAndRenderItemData = (item, renderFunction) => {
fetch(item.tokenUri)
.then(response => response.json())
.then(data => {
data.symbol = item.symbol;
data.tokenId = item.tokenId;
data.tokenAddress = item.tokenAddress;
renderFunction(data);
});
}
ensureMarketplaceIsApproved = async (tokenId, tokenAddress) => {
user = await Moralis.User.current();
const userAddress = user.get('ethAddress');
const contract = web3.eth.Contract(tokenContractAbi, tokenAddress);
const approvedAddress = await contract.methods.getApproved(tokenId).call({from: userAddress});
if (approvedAddress != MARKETPLACE_CONTRACT_ADDRESS){
await contract.methods.approve(MARKETPLACE_CONTRACT_ADDRESS, tokenId);
}
}
hideElement = (element) => element.style.display = "none";
showElement = (element) => element.style.display = "block";
// NavBar
const userConnectButton = document.getElementById("btnConnect");
userConnectButton.onclick = login;
const userProfileButton = document.getElementById("btnUserInfo");
userProfileButton.onclick = openUserInfo;
const openCreateItemButton = document.getElementById("btnOpenCreateItem");
openCreateItemButton.onclick = () => showElement(createItemForm);
// User profile
const userInfo = document.getElementById("userInfo");
const userUsernameField = document.getElementById("txtUsername");
const userEmailField = document.getElementById("txtEmail");
const userAvatarImg = document.getElementById("imgAvatar");
const userAvatarFile = document.getElementById("fileAvatar");
document.getElementById("btnCloseUserInfo").onclick = () => hideElement(userInfo);
document.getElementById("btnLogout").onclick = logout;
document.getElementById("btnSaveUserInfo").onclick = saveUserinfo;
// Item creation
const createItemForm = document.getElementById("createItem");
const createItemNameField = document.getElementById("txtCreateItemName");
const createItemDescriptionField = document.getElementById("txtCreateItemDescriptions");
const createItemPriceFild = document.getElementById("numCreateItemPrice");
const createItemStatusField = document.getElementById("selectCreateItemStatus");
const createItemFile = document.getElementById("fileCreateItemFile");
document.getElementById("btnCloseCreateItem").onclick = () => hideElement(createItemForm);
document.getElementById("btnCreateItem").onclick = createItem;
//User items
const userItemsSection = document.getElementById("userItems");
const userItems = document.getElementById("userItemsList");
document.getElementById("btnCloseUserItems").onclick = () => hideElement(btnCloseUserItems);
const openUserItemsButton = document.getElementById("btnMyItems");
openUserItemsButton.onclick = openUserItems;
const userItemTemplate = initTemplate("itemTemplate");
init();
this is my cloud function. Maybe i did something wrong here since it isn’t all the same in the tutorial:
Moralis.Cloud.define("getUserItems", async (request) => {
return request;
const query = new Moralis.Query("NFTTokenOwners");
query.equalTo("contract_type", "ERC721");
query.containedIn("owner_of", request.user.attributes.accounts);
const queryResults = await query.find();
const results = [];
let sum = 0;
for (let i = 0; i < queryResults.length; ++i) {
results.push({
"id": queryResults[i].attributes.objectId,
"tokenId": queryResults[i].attributes.token_id,
"tokenAddress": queryResults[i].attributes.token_address,
"symbol": queryResults[i].attributes.symbol,
"tokenUri": queryResults[i].attributes.token_uri,
});
}
return results;
});
and here is my index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Moralis SDK code -->
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Morarable</title>
</head>
<body>
<div>
<button id="btnConnect">Connect wallet</button>
<button id="btnUserInfo">Profile</button>
<button id="btnOpenCreateItem">Create</button>
<button id="btnMyItems">My items</button>
</div>
<div id="userInfo">
<h4>User Profile</h4>
<input type="text" id="txtUsername" required placeholder="Enter username">
<input type="text" id="txtEmail" placeholder="Enter email">
<small>Optional</small>
<img width="50" height="50" src="" id="imgAvatar" alt="">
<label for="fileAvatar">Select Avatar</label>
<input type="file" id="fileAvatar">
<button id="btnLogout">Log out</button>
<button id="btnCloseUserInfo">Close</button>
<button id="btnSaveUserInfo">Save</button>
</div>
<div id="createItem">
<h4>Create Item</h4>
<input type="text" id="txtCreateItemName" required placeholder="Enter name">
<textarea id="txtCreateItemDescriptions" cols="30" rows="5" placeholder="Enter description"></textarea>
<input type="number" min="1" step="1" id="numCreateItemPrice" placeholder="Enter price" required>
<label for="selectCreateItemStatus">Status</label>
<select id="selectCreateItemStatus">
<option value="0">Not for sale</option>
<option value="1">Instant buy</option>
<option value="2">Accept Offers</option>
</select>
<label for="fileCreateItemFile">Select File</label>
<input type="file" id="fileCreateItemFile">
<button id="btnCloseCreateItem">Close</button>
<button id="btnCreateItem">Create!</button>
</div>
<div id="userItems">
<h4>My Items</h4>
<div id="userItemsList"></div>
<button id="btnCloseUserItems">Close</button>
</div>
<div id="itemTemplate">
<img src="" alt="">
<h5></h5>
<p></p>
</div>
<script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
<script src="https://unpkg.com/moralis/dist/moralis.js"></script>
<script src="abi.js"></script>
<script src="main.js"></script>
</body>
</html>