leumas-private-shared
Version:
Private React JSX Package For Leumas Shared Components, Headers, Footers, Asides, Login Pages, API Key Manager and much more. Styles and everything reusable to avoid DRY code across all of our subdomains
203 lines (159 loc) • 6.94 kB
JSX
import { useState, useEffect } from 'react';
import Web3 from 'web3';
import LeumasTokenABI from "../../../assets/LeumasToken.json";
import Manual from './Manual';
import MessageResponse from './MessageResponse';
import Spinner2 from '../../Loaders/Spinner2';
import React from 'react';
const TOKEN_ADDRESS = `${import.meta.env.VITE_REACT_APP_LEUMAS_TOKEN_ADDRESS}`;
const PurchaseToken = () => {
const [web3, setWeb3] = useState(null);
const [tokenContract, setTokenContract] = useState(null);
const [ethAmount, setEthAmount] = useState(0);
const [leumasTokens, setLeumasTokens] = useState(0);
const [userAddress, setUserAddress] = useState(null);
const [userBalance, setUserBalance] = useState(0);
const [exchangeRate, setExchangeRate] = useState(0);
const [message, setMessage] = useState(null);
const [loading, setLoading] = useState(false);
const [messageType, setMessageType] = useState(null);
const [mode, setMode] = useState("dex");
const updateBalance = async (address, contract) => {
try {
const balance = await contract.methods.balanceOf(address).call();
const balanceNumber = Number(balance.toString()) / 1e18; // Convert to a regular number and divide by 10^18
const roundedBalance = balanceNumber.toFixed(2); // Round to 2 decimal places
setUserBalance(roundedBalance);
console.log("balance: ", roundedBalance);
} catch (err) {
console.error("Error fetching balance", err);
}
};
useEffect(() => {
const initialize = async () => {
if (window.ethereum) {
const web3Instance = new Web3(window.ethereum);
setWeb3(web3Instance);
const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
setUserAddress(accounts[0]);
const checksumAddress = web3Instance.utils.toChecksumAddress(TOKEN_ADDRESS);
const contractInstance = new web3Instance.eth.Contract(LeumasTokenABI, checksumAddress);
setTokenContract(contractInstance);
// Event listeners
window.ethereum.on('accountsChanged', async (accounts) => {
setUserAddress(accounts[0]);
const balance = await contractInstance.methods.balanceOf(accounts[0]).call();
setUserBalance(balance);
});
// Initial fetch
const rate = await contractInstance.methods.unitsOneEthCanBuy().call();
setExchangeRate(rate);
// Get and set the initial balance
const initialBalance = await contractInstance.methods.balanceOf(accounts[0]).call();
setUserBalance(initialBalance.toNumber()); // Convert to a number
updateBalance(accounts[0], contractInstance);
} else {
console.error("Please install MetaMask");
}
};
initialize();
}, []);
useEffect(() => {
if (userAddress && tokenContract) {
updateBalance(userAddress, tokenContract);
}
}, [userAddress, tokenContract]);
const handleTokenAmountChange = (e) => {
const tokens = parseFloat(e.target.value || '0');
setLeumasTokens(tokens);
const eth = tokens / parseFloat(exchangeRate.toString()); // Calculate ETH based on token amount and rate
setEthAmount(eth);
};
const purchaseTokens = async () => {
setLoading(true);
setMessage(null);
if (!userAddress || !tokenContract) {
setMessage('Please connect your MetaMask account and ensure the contract is loaded.');
setMessageType('error');
setLoading(false);
return;
}
try {
const weiValue = web3.utils.toWei(ethAmount.toString(), 'ether');
const transactionReceipt = await tokenContract.methods.transfer(
tokenContract.options.address,
web3.utils.toWei(leumasTokens.toString(), 'ether')
).send({
from: userAddress,
value: weiValue
});
const txHash = transactionReceipt.transactionHash;
// Construct the Etherscan URL for Goerli testnet
const etherscanURL = `https://goerli.etherscan.io/tx/${txHash}`;
setMessage(
<span>
Tokens purchased successfully! Transaction Hash:{' '}
<a href={etherscanURL} target="_blank" rel="noopener noreferrer">
{txHash}
</a>
</span>
);
setMessageType('success');
// Update the user's LeumasTokens balance
updateBalance(userAddress, tokenContract);
setTimeout(() => {
setLoading(false);
}, 3000);
} catch (error) {
setMessage(`Failed to purchase tokens: ${error.message}`);
setMessageType('error');
setLoading(false);
}
};
return (
<div className="min-w-[400px] bg-gray-900 text-gray-100 flex flex-col justify-center items-center p-4 w-full overflow-x-none">
<div className='flex gap-4 p-4 hover:text-blue-400'>
<button className='text-white z-50' onClick={()=>setMode("manual")}>Manual</button>
<button className='text-white z-50' onClick={()=>setMode("dex")}>Trade</button>
</div>
<div className="w-full max-w-xl border-2 rounded-lg shadow-xl p-4">
<h2 className="text-3xl font-extrabold mb-4">
{mode === "dex" ? "Purchase Leumas Token" : "Get Started with Leumas Token"}
</h2>
{mode === "dex" ? (
<>
<div className="mb-4 grid grid-cols-1 gap-4 items-center">
<div className="relative">
<input
type="number"
placeholder="Enter amount in LeumasTokens"
onChange={handleTokenAmountChange}
value={leumasTokens}
className="p-2 pr-12 border-2 border-gray-600 rounded focus:border-blue-500 focus:outline-none text-black w-full"
/>
<button
onClick={purchaseTokens}
className="absolute top-0 right-0 h-full px-6 py-2 bg-blue-500 hover:bg-blue-600 text-white rounded-r font-bold focus:outline-none focus:ring-2 focus:ring-blue-400"
>
Buy
</button>
</div>
</div>
<div className="flex items-center justify-between text-lg mb-4">
<p>{leumasTokens} Leumas Token = {ethAmount.toFixed(4)} ETH.</p>
<p>Your Tokens: {userBalance || 0} LDT</p>
</div>
<p>1 ETH = 5000 LMS Tokens </p>
</>
) : (
<Manual />
)}
<Spinner2 loading={loading} />
{message && (
<MessageResponse message={message} messageType={messageType} />
)}
</div>
</div>
);
}
export default PurchaseToken;