I CLONED RARIBLE IN 24H | I can always press the put for sale button

I did the tutorial and most of the things are working. I don’t use modals i made an own site for mynfts and the marketplace. I can always press the “Put for Sale” Button even when the Item is on the Marketplace already.

Moralis.initialize("YD9aYXgNHsHa4ia8gRrC75mGKIQpFNtwg5gJasCZ");
Moralis.serverURL = 'https://ynetmdkm7kum.grandmoralis.com:2053/server'
const TOKEN_CONTRACT_ADDRESS = "0xd682Eff96763D5b2dE98AA6A080c182a07933AdD";
const MARKETPLACE_CONTRACT_ADDRESS = "0x4354a46d5f8B729C9953bDEB111201acC84230C9";

init = async () => {
    window.web3 = await Moralis.Web3.enable();
    window.tokenContract = new web3.eth.Contract(tokenContractAbi, TOKEN_CONTRACT_ADDRESS);
    window.marketplaceContract = new web3.eth.Contract(marketplaceContractAbi, MARKETPLACE_CONTRACT_ADDRESS);
    loadUserItems();

    const soldItemsQuery = new Moralis.Query('SoldItems');
    const soldItemsSubscription = await soldItemsQuery.subscribe();
    soldItemsSubscription.on("create", onItemSold);

    const itemsAddedQuery = new Moralis.Query('ItemsForSale');
    const itemsAddedSubscription = await itemsAddedQuery.subscribe();
    itemsAddedSubscription.on("create", onItemAdded);
}

openUserItems = async () => {
    user = await Moralis.User.current();
    if (user){    
        return;
    }else{
        login();
    }

}

loadUserItems = async () => {
    const ownedItems = await Moralis.Cloud.run("getUserItems");
    ownedItems.forEach(item => {
        const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
        if (userItemListing) return;
        getAndRenderItemData(item, renderUserItem);
    });
}

// loadItems = async () => {
//     const items = await Moralis.Cloud.run("getItems");
//     user = await Moralis.User.current();
//     items.forEach(item => {
//         if (user){
//             if (user.attributes.accounts.includes(item.ownerOf)){
//                 const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
//                 if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);
//                 getAndRenderItemData(item, renderUserItem);
//                 return;
//             }
//         }
//         getAndRenderItemData(item, renderItem);
//     });
// }

onItemSold = async (item) => {
    const listing = document.getElementById(`item-${item.attributes.uid}`);
    if (listing){
        listing.parentNode.removeChild(listing);
    }
    
    user = await Moralis.User.current();
    if (user){
        const params = {uid: `${item.attributes.uid}`};
        const soldItem = await Moralis.Cloud.run('getItem', params);
        if (soldItem){
            if (user.get('accounts').includes(item.attributes.buyer)){
                getAndRenderItemData(soldItem, renderUserItem);
            }

            const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
            if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);
          
        }
    }
}

onItemAdded = async (item) => {
    const params = {uid: `${item.attributes.uid}`};
    const addedItem = await Moralis.Cloud.run('getItem', params);
    if (addedItem){
        user = await Moralis.User.current();
        if (user){
            if (user.get('accounts').includes(addedItem.ownerOf)){
                const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
                if (userItemListing) userItemListing.parentNode.removeChild(userItemListing);

                getAndRenderItemData(addedItem, renderUserItem);
                return;
            }
        }
        getAndRenderItemData(addedItem, renderItem);
    }

}

initTemplate = (id) => {
    const template = document.getElementById(id);
    template.id = "";
    template.parentNode.removeChild(template);
    return template;
}

renderUserItem = async (item) => {
    const userItemListing = document.getElementById(`user-item-${item.tokenObjectId}`);
    if (userItemListing) return;

    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;

    userItem.getElementsByTagName("input")[0].value = item.askingPrice ?? 1;
    userItem.getElementsByTagName("input")[0].disabled = item.askingPrice > 0;
    userItem.getElementsByTagName("button")[0].disabled = item.askingPrice > 0;
    userItem.getElementsByTagName("button")[0].onclick = async () => {
        user = await Moralis.User.current();
        if (!user){
            login();
            return;
        }
        await ensureMarketplaceIsApproved(item.tokenId, item.tokenAddress);
        await marketplaceContract.methods.addItemToMarket(item.tokenId, item.tokenAddress, userItem.getElementsByTagName("input")[0].value).send({from: user.get('ethAddress') });
    };

    userItem.id = `user-item-${item.tokenObjectId}`
    userItems.appendChild(userItem);
}

// renderItem = (item) => {
//     const itemForSale = marketplaceItemTemplate.cloneNode(true);
//     if (item.sellerAvatar){
//         itemForSale.getElementsByTagName("img")[0].src = item.sellerAvatar.url();
//         itemForSale.getElementsByTagName("img")[0].alt = item.sellerUsername;
     
//     }

//     itemForSale.getElementsByTagName("img")[1].src = item.image;
//     itemForSale.getElementsByTagName("img")[1].alt = item.name;
//     itemForSale.getElementsByTagName("h5")[0].innerText = item.name;
//     itemForSale.getElementsByTagName("p")[0].innerText = item.description;

//     itemForSale.getElementsByTagName("button")[0].innerText = `Buy for ${item.askingPrice}`;
//     itemForSale.getElementsByTagName("button")[0].onclick = () => buyItem(item);
//     itemForSale.id = `item-${item.uid}`;
//     itemsForSale.appendChild(itemForSale);
// }


getAndRenderItemData = (item, renderFunction) => {
    
    fetch(item.tokenUri)
    .then(response => response.json())
    .then(data => {
        item.name = data.name;
        item.description = data.description;
        item.image = data.image;
        renderFunction(item);
    })
}

ensureMarketplaceIsApproved = async (tokenId, tokenAddress) => {
    user = await Moralis.User.current();
    const userAddress = user.get('ethAddress');
    const contract = new 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).send({from: userAddress});
    }
}


const userItemsSection = document.getElementById("userItems");
const userItems = document.getElementById("userItemsList");

window.onload = function() {
    openUserItems();
  };

document.getElementById("btnCloseUserItems").onclick = function () {
    window.location.href = "marketplace.html";
};

const userItemTemplate = initTemplate("itemTemplate");

/* const openUserItemsButton = document.getElementById("btnMyItems");
openUserItemsButton.onclick = openUserItems; */

const itemsForSale = document.getElementById("itemsForSale");

init();

<!DOCTYPE html>
<html lang="en">
<head>
    <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>Load NFTs</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">
    <link rel="stylesheet" href="css/mynfts.css">
</head>
<body>
    
    <div class="content bg-dark text-light">
        <div class="header">
        <h5 class="title" >My Items</h5>
        </div>
        <div class="body row row-cols-1 row-cols-md-4 mt-5" id="userItemsList">

        </div>
        <div class="footer">
            <button type="button" id="btnCloseUserItems" class="btn btn-secondary">Close</button>
        </div>
    </div>

    <div class="col mb-4" id="itemTemplate">
        <div class="card h-100 border-light bg-transparent text-light">
            <img src="marketplace.html" class="card-img-top" alt="...">
            <div class="card-body d-flex align-items-end">
                <div class="w-100">
                    <h5 class="card-title"></h5>
                    <p class="card-text"></p>

                    <div class="input-group mb-3">
                        <input type="number" min="1" step="1" class="form-control" placeholder="Price">
                        <div class="input-group-append">
                          <button class="btn btn-outline-secondary" type="button">Put for sale</button>
                        </div>
                      </div>
                </div>
        
            </div>
          </div>
    </div>
    
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/web3.min.js"></script>
    <script src="https://unpkg.com/moralis/dist/moralis.js"></script>
    <script src="js/abi.js"></script>
    <script src="js/mynfts.js"></script>
</body>
</html>

Please let me know if you need any further information.

1 Like

Hey @Manuel138

I suggest you to compare your code and the code from tutorial. Take a look at Solving common problems [Rarible Clone]

I did that but the problem is that i have more than one .js files, so it’s hard for me to compare them.

    <script src="js/abi.js"></script>
    <script src="js/mynfts.js"></script>

should be:

    <script src="abi.js"></script>
    <script src="mynfts.js"></script>

And I can’t find login() function in your code
image

The problem you described is logical. So what I can suggest to you is to make a “checker” if the item is already on sale :man_mechanic: