Fraction NFT Marketplace - error in buyNFT - Not enough Ether sent to buy the shares

Hi everyone,
I'm trying to build fraction NFT Marketplace, It's now working when I try to create a new NFT and show it in the frontend.
I'm now facing an error in my buyNFT function and no matter what I try it keeps happening,

(reason="Error: VM Exception while processing transaction: reverted with reason string 'Not enough Ether sent to buy the shares.'", method="estimateGas",

can anyone guide me on what I should do?

this is my smart contract right now:

pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "./CustomERC20.sol";

contract FractionalNFTMarketplace is ERC721URIStorage, Ownable {
    using Strings for uint256;

    uint256 private _currentTokenId = 0;
    address public customERC20Address;

    struct FractionalToken {
        CustomERC20 token;
        uint256 totalShares;
        uint256 pricePerShare;
    }

    struct MarketItem {
        uint256 tokenId;
        address payable seller;
        address payable owner;
        uint256 totalShares;
        uint256 pricePerShare;
        bool isForSale;
    }

    mapping(uint256 => FractionalToken) private _fractionalTokens;
    mapping(uint256 => mapping(address => uint256)) private _shareOwners;
    mapping(uint256 => MarketItem) private _marketItems;

    Counters.Counter private _marketItemId;

    event TokenCreated(uint256 indexed tokenId, uint256 totalShares, uint256 pricePerShare);
    event TokenBought(uint256 indexed tokenId, address indexed buyer, uint256 shares);
    event MarketItemCreated(uint256 indexed tokenId, address indexed seller, uint256 totalShares, uint256 pricePerShare);
    event MarketItemSold(uint256 indexed marketItemId, address indexed buyer);
    event ApprovalForToken(uint256 indexed tokenId, address indexed owner, uint256 amount);

    constructor(address _customERC20Address) ERC721("Fractional NFT Marketplace", "FNFTM") {
        customERC20Address = _customERC20Address;
    }
    

    function createMarketItem(uint256 tokenId) private {
    require(_exists(tokenId), "Token ID does not exist.");

    address currentOwner = ownerOf(tokenId);

    FractionalToken storage fractionalToken = _fractionalTokens[tokenId];

    _marketItems[tokenId] = MarketItem(
        tokenId,
        payable(currentOwner),
        payable(address(this)),
        fractionalToken.totalShares,
        fractionalToken.pricePerShare,
        true
    );

    emit MarketItemCreated(tokenId, currentOwner, fractionalToken.totalShares, fractionalToken.pricePerShare);
}

    function createToken(uint256 totalShares, uint256 pricePerShare, string memory tokenURI) public payable returns (uint256) {
        require(totalShares > 0, "Total shares must be greater than 0.");
        require(pricePerShare > 0, "Price per share must be greater than 0.");
        
        uint256 newTokenId = _currentTokenId++;
        _mint(msg.sender, newTokenId);
        _setTokenURI(newTokenId, tokenURI);

        string memory name = string(abi.encodePacked("Shares of NFT #", newTokenId.toString()));
        string memory symbol = string(abi.encodePacked("SNFT", newTokenId.toString()));
        CustomERC20 newERC20Token = new CustomERC20(name, symbol);
        newERC20Token.mint(msg.sender, totalShares);

        _fractionalTokens[newTokenId] = FractionalToken(newERC20Token, totalShares, pricePerShare);
        _shareOwners[newTokenId][msg.sender] = totalShares;
        approveContractForToken(newTokenId,totalShares);
        createMarketItem(newTokenId);

        emit TokenCreated(newTokenId, totalShares, pricePerShare);
        return newTokenId;
    }

    function approveContractForToken(uint256 tokenId, uint256 amount) public {
        require(_exists(tokenId), "Token ID does not exist.");
        require(ownerOf(tokenId) == msg.sender, "Caller is not the owner of the token.");

        FractionalToken storage fractionalToken = _fractionalTokens[tokenId];
        fractionalToken.token.approve(address(this), amount);
        emit ApprovalForToken(tokenId, msg.sender, amount);
    }

    function getAllowance(uint256 tokenId, address owner, address spender) public view returns (uint256) {
        require(_exists(tokenId), "Token ID does not exist.");
        FractionalToken storage fractionalToken = _fractionalTokens[tokenId];
        return fractionalToken.token.allowance(owner, spender);
    }

    function buyToken(uint256 tokenId,uint256 totalPrice, uint256 shares) public payable {
        require(_exists(tokenId), "Token ID does not exist.");
        require(shares > 0, "Shares must be greater than 0.");

        FractionalToken storage fractionalToken = _fractionalTokens[tokenId];
        require(fractionalToken.totalShares >= shares, "Not enough shares available.");

        // uint256 totalPrice = fractionalToken.pricePerShare * shares;
        require(msg.value >= totalPrice, "Not enough Ether sent to buy the shares.");

        address seller = ownerOf(tokenId);

        CustomERC20 customERC20 = CustomERC20(customERC20Address);
        uint256 allowance = customERC20.allowance(seller, address(this));

        require(allowance >= shares, "Not enough allowance to transfer shares.");

        customERC20.transferFrom(seller, msg.sender, shares);
        payable(seller).transfer(totalPrice);
        fractionalToken.totalShares -= shares;
        _shareOwners[tokenId][seller] -= shares;
        _shareOwners[tokenId][msg.sender] += shares;
        emit TokenBought(tokenId, msg.sender, shares);
    }

This is my context.js file that connects it with the front-end:

const CreateNft = async (name, price, shares, image, description, router) => {
        if (!name || !description || !price || !image || !shares)
          return console.log("Data is Missing!");
      
        const data = JSON.stringify({ name, description, image });
        try {
          const added = await client.add(data);
          const url = `https://infura-ipfs.io/ipfs/${added.path}`;

          await createSale(url, price, shares);

        } catch (error) {
          console.log(error);
        }
    };

    //Create Sale
    const createSale = async (url, Price, shares, isResale, id) => {
      try {
        const price = ethers.utils.parseUnits(Price, "ether");
        const contract = await SmartContractConnect();
    
        const transaction = !isResale
          ? await contract.createToken(shares, price, url)
          : await contract.resellToken(id, price);
    
        await transaction.wait();
        console.log("Transaction Completed: ", transaction);
      } catch (error) {
        console.log("Error while creating sale: ", error);
      }
  };

    //Fetch NFTS
    const FetchNFTs = async () => {
        try {
          const provider = new ethers.providers.JsonRpcProvider();
          const contract = fetchSmartContract(provider);
      
          const data = await contract.fetchMarketItems();
          // console.log("Data: ", data);
          const items = await Promise.all(
            data.map(async ({ tokenId, seller,owner, pricePerShare,totalShares  }) => {
              const TokenURI = await contract.tokenURI(tokenId);
              const {
                data: { image, name, description },
              } = await axios.get(TokenURI);
      
              const price = ethers.utils.formatUnits(pricePerShare.toString(), "ether");

              return {
                price,
                tokenId: tokenId.toNumber(),
                seller,
                owner,
                image,
                name,
                description,
                TokenURI,
                totalShares: totalShares.toNumber()
              };
            })
          );
          // console.log("Fetch success: ", items);
          return items;
        } catch (error) {
          console.log("Error while fetching NFTs:  ", error);
        }
      };

    useEffect(()=>{
        FetchNFTs();
    },[]);

//Buy NFTs
    const BuyNFT = async (NFT, shares) => {
        try {
          const contract = await SmartContractConnect();
          const price = NFT.price*(shares)
          const totalPrice = ethers.utils.parseUnits(price.toString(), "ether");

      
          const transaction = await contract.buyToken(NFT.tokenId,totalPrice, shares);
      
          await transaction.wait();
          router.push("/profile");
        } catch (error) {
          console.log("Error while buying NFT", error);
        }
    };


If this is indeed your smart contract, then you should know that this line in your code:

require(msg.value >= totalPrice, "Not enough Ether sent to buy the shares.");

Requires you to call the function with an ETH amount equal to or larger than totalPrice.

can you share failed tx hash?

Based on the code in the question, that doesn't seem necessary in order to answer it.

Thanks for replying, I've actually noticed this after I posted immediately.
It's because I have been having another error since yesterday concerning the approving of tokens when I try to buy, I thought I fixed it but now it's back again and I'm trying to get it to work.
Thank you.