447 lines
18 KiB
TypeScript
447 lines
18 KiB
TypeScript
import { useRouter } from "next/router";
|
|
import { useEffect, useState } from "react";
|
|
import { getAccessToken, getEmbeddedConnectedWallet, usePrivy, useWallets } from "@privy-io/react-auth";
|
|
import Head from "next/head";
|
|
import { useBalance } from 'wagmi';
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
import { faDiscord, faGoogle, faMeta, faTwitter, faXTwitter } from "@fortawesome/free-brands-svg-icons";
|
|
import { faAdd, faFileExport, faLink, faTrash, faUnlink, faWallet } from "@fortawesome/free-solid-svg-icons";
|
|
import { useSetActiveWallet } from "@privy-io/wagmi";
|
|
import { encodeFunctionData, parseAbi } from 'viem';
|
|
import { gameDataABI } from "./data";
|
|
import { arbitrumSepolia, baseSepolia } from "viem/chains";
|
|
|
|
export default function DashboardPage() {
|
|
const [verifyResult, setVerifyResult] = useState(0);
|
|
const [username, setUsername] = useState('');
|
|
const [vaultData, setVaultData] = useState({ prehp: "0", vc: "0" });
|
|
const [showPopup, setShowPopup] = useState(false);
|
|
const [ticketAmount, setTicketAmount] = useState(1);
|
|
const router = useRouter();
|
|
|
|
const { ready, authenticated, user, logout, exportWallet, linkWallet, unlinkWallet, linkDiscord, unlinkDiscord, linkTwitter, unlinkTwitter, linkGoogle, unlinkGoogle } = usePrivy();
|
|
const { wallets } = useWallets();
|
|
|
|
const [activeWallet, setActiveWallet] = useState(user?.wallet?.address);
|
|
const [activeWalletObj, setActiveWalletObj] = useState(wallets[0]);
|
|
const [ticketsCount, setTicketsCount] = useState(0);
|
|
|
|
const { data: balanceData } = useBalance({
|
|
address: activeWallet as `0x${string}`,
|
|
token: "0x22b6c31c2beb8f2d0d5373146eed41ab9ede3caf"
|
|
});
|
|
|
|
const balance = balanceData?.formatted;
|
|
const token = balanceData?.symbol;
|
|
|
|
|
|
function ToggleDiscord() {
|
|
if (user?.discord) {
|
|
unlinkDiscord(user?.discord.subject);
|
|
} else {
|
|
linkDiscord();
|
|
}
|
|
}
|
|
|
|
function ToggleTwitter() {
|
|
if (user?.twitter) {
|
|
unlinkTwitter(user?.twitter.subject);
|
|
} else {
|
|
linkTwitter();
|
|
}
|
|
}
|
|
|
|
function ToggleGoogle() {
|
|
if (user?.google) {
|
|
unlinkGoogle(user?.google.subject);
|
|
} else {
|
|
linkGoogle();
|
|
}
|
|
}
|
|
async function handleWalletClick(address: string) {
|
|
setActiveWallet(address);
|
|
const url = `http://vps.playpoolstudios.com/metahunt/api/launcher/set_wallet.php?id=${user?.id}&wallet=${address}`;
|
|
const response = await fetch(url);
|
|
console.log(url);
|
|
|
|
wallets.forEach((element) => {
|
|
if (element.address == address) {
|
|
setActiveWalletObj(element);
|
|
element.switchChain(chainId);
|
|
}
|
|
});
|
|
|
|
}
|
|
|
|
|
|
useEffect(() => {
|
|
if (ready && !authenticated) {
|
|
router.push("/");
|
|
}
|
|
if (ready) {
|
|
if (username == "-1") {
|
|
console.log(user?.id);
|
|
router.push("/logincomplete");
|
|
}
|
|
}
|
|
}, [ready, authenticated, router, username]);
|
|
|
|
useEffect(() => {
|
|
async function fetchUsername() {
|
|
if (ready) {
|
|
try {
|
|
const response = await fetch(`https://vps.playpoolstudios.com/metahunt/api/launcher/get_display_name_public.php?id=${user?.id}`);
|
|
const data = await response.text();
|
|
setUsername(data);
|
|
} catch (error) {
|
|
console.error("Error fetching username:", error);
|
|
}
|
|
}
|
|
}
|
|
|
|
async function fetchVaultData() {
|
|
if (user?.id) {
|
|
try {
|
|
const response = await fetch(`http://vps.playpoolstudios.com/metahunt/api/launcher/get_vault.php?id=${user?.id}`);
|
|
const data = await response.json();
|
|
setVaultData({ prehp: data.prehp, vc: data.vc });
|
|
} catch (error) {
|
|
console.error("Error fetching vault data:", error);
|
|
}
|
|
}
|
|
}
|
|
|
|
fetchUsername();
|
|
fetchVaultData();
|
|
}, [ready]);
|
|
|
|
async function autoSetActiveWallet(){
|
|
try {
|
|
const response = await fetch(`http://vps.playpoolstudios.com/metahunt/api/launcher/get_active_wallet.php?id=${user?.id}`);
|
|
const activeWalletString = await response.text();
|
|
wallets.forEach((element)=>{
|
|
if(element.address == activeWalletString){
|
|
setActiveWallet(element.address);
|
|
setActiveWalletObj(element);
|
|
}
|
|
});
|
|
|
|
if(activeWalletString != activeWallet){
|
|
setActiveWalletObj(wallets[0]);
|
|
}
|
|
} catch (error) {
|
|
console.error("Error fetching vault data:", error);
|
|
}
|
|
|
|
}
|
|
|
|
const chainId = arbitrumSepolia.id;
|
|
|
|
useEffect(() => {
|
|
setActiveWallet(getEmbeddedConnectedWallet(wallets)?.address);
|
|
autoSetActiveWallet();
|
|
getTickets();
|
|
}, [wallets]);
|
|
|
|
useEffect(() => {
|
|
getTickets();
|
|
}, [activeWalletObj]);
|
|
|
|
|
|
const contractAddress = "0x7e06ae145dc3d73350c7da040355654EbF11f1bc";
|
|
async function buyTicket(amount: number) {
|
|
const isEmbedded = getEmbeddedConnectedWallet(wallets)?.address == activeWalletObj?.address;
|
|
const provider = await activeWalletObj?.getEthereumProvider();
|
|
if (!provider) {
|
|
console.error("Ethereum provider not found");
|
|
return;
|
|
}
|
|
|
|
const data = encodeFunctionData({
|
|
abi: gameDataABI,
|
|
functionName: 'buyTickets',
|
|
args: [amount],
|
|
});
|
|
const value = 1000000000000 * amount;
|
|
console.log(`isEmbbedded : ${isEmbedded}`)
|
|
const transactionRequest = {
|
|
from: activeWalletObj?.address,
|
|
to: contractAddress,
|
|
data: data,
|
|
value: isEmbedded ? value : value.toString(),
|
|
};
|
|
|
|
try {
|
|
const transactionHash = await provider.request({
|
|
method: 'eth_sendTransaction',
|
|
params: [transactionRequest],
|
|
});
|
|
// Polling for the transaction receipt
|
|
const checkTransactionReceipt = async () => {
|
|
const receipt = await provider.request({
|
|
method: 'eth_getTransactionReceipt',
|
|
params: [transactionHash],
|
|
});
|
|
|
|
if (receipt && receipt.status) {
|
|
if (receipt.status === '0x1') { // Transaction was successful
|
|
console.log('Transaction confirmed:', receipt);
|
|
getTickets(); // Call getTickets() after the transaction is confirmed
|
|
//setShowPopup(false); // Close the popup after successful transaction
|
|
} else {
|
|
console.error('Transaction failed:', receipt);
|
|
}
|
|
} else {
|
|
// Retry after some delay if the receipt is not available yet
|
|
setTimeout(checkTransactionReceipt, 2000); // Poll every 2 seconds
|
|
}
|
|
};
|
|
|
|
checkTransactionReceipt();
|
|
setShowPopup(false); // Close the popup after successful transaction
|
|
} catch (error) {
|
|
console.error('Transaction failed:', error);
|
|
}
|
|
}
|
|
|
|
async function getTickets() {
|
|
const provider = await activeWalletObj?.getEthereumProvider();
|
|
if (!provider) {
|
|
console.error("Ethereum provider not found");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const data = encodeFunctionData({
|
|
abi: gameDataABI,
|
|
functionName: 'balanceOf',
|
|
args: [activeWalletObj?.address, 0],
|
|
});
|
|
|
|
const callRequest = {
|
|
from: activeWalletObj?.address,
|
|
to: contractAddress,
|
|
data: data,
|
|
};
|
|
|
|
const result = await provider.request({
|
|
method: 'eth_call',
|
|
params: [callRequest],
|
|
});
|
|
|
|
const balanceHex = result;
|
|
const balance = parseInt(balanceHex, 16);
|
|
setTicketsCount(balance);
|
|
} catch (error) {
|
|
console.error('Call failed:', error);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<Head>
|
|
<title>W3B Games Dashboard</title>
|
|
</Head>
|
|
|
|
<main className="flex flex-col min-h-screen px-4 sm:px-20 py-6 sm:py-10 bg-black text-white">
|
|
{ready && authenticated ? (
|
|
<>
|
|
<div className="flex flex-row justify-between">
|
|
<h1 className="text-2xl font-semibold text-white">Welcome {username || "User"},</h1>
|
|
<button
|
|
onClick={logout}
|
|
className="text-sm bg-red-500 hover:bg-red-700 py-2 px-4 rounded-md text-violet-100"
|
|
>
|
|
Logout
|
|
</button>
|
|
</div>
|
|
<div className="flex flex-wrap items-center justify-center">
|
|
<div className="items-center justify-center p-20">
|
|
<h1 className="text-s">Vault Credits</h1>
|
|
<h1 className="text-4xl flex justify-center">{vaultData.vc || "0"} VC</h1>
|
|
</div>
|
|
<div className="items-center justify-center p-20">
|
|
<h1 className="text-xs">{activeWallet}</h1>
|
|
<h1 className="text-4xl flex justify-center">{balance || 0} {token}</h1>
|
|
</div>
|
|
<div className="items-center justify-center p-20">
|
|
<h1 className="text-s">Hunt Tickets</h1>
|
|
<h1 className="text-4xl flex justify-center">{ticketsCount || "0"}</h1>
|
|
<button
|
|
onClick={() => setShowPopup(true)}
|
|
className="mt-2 bg-blue-500 hover:bg-blue-700 py-2 px-4 rounded-md text-white"
|
|
>
|
|
Buy Tickets
|
|
</button>
|
|
</div>
|
|
<div className="items-center justify-center p-20">
|
|
<h1 className="text-s">Pre-hunt Points</h1>
|
|
<h1 className="text-4xl flex justify-center">{vaultData.prehp || "0"} PHP</h1>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-10 ">
|
|
<div className="bg-opacity-40 bg-gray-900 rounded-3xl h-[250px] itmes-center justify-center p-5 grid ">
|
|
<h1 className="text-xl flex justify-center">Socials</h1>
|
|
<div className="h-5"></div>
|
|
|
|
<div className="flex h-12 items-center">
|
|
<FontAwesomeIcon className="p-2 w-12" icon={faXTwitter} size={'2x'} />
|
|
<p className="w-16">Twitter</p>
|
|
<div className="px-5"></div>
|
|
<div className={`bg-gray-${user?.twitter ? "8" : "7"}00 rounded-xl items-center justify-center flex w-64 p-1`}>
|
|
<p>{user?.twitter ? "@" + user?.twitter.username : "-"}</p>
|
|
</div>
|
|
<div className="p-5" />
|
|
<button className={`rounded-full ${user?.twitter ? "bg-red-700" : "bg-green-700"} px-4 py-1`} onClick={ToggleTwitter}>
|
|
{user?.twitter ? "Unlink" : "Link"}
|
|
</button>
|
|
</div>
|
|
<div className="flex h-12 items-center">
|
|
<FontAwesomeIcon className="p-2 w-12" icon={faDiscord} size={'2x'} />
|
|
<p className="w-16">Discord</p>
|
|
<div className="px-5"></div>
|
|
<div className={`bg-gray-${user?.discord ? "8" : "7"}00 rounded-xl items-center justify-center flex w-64 p-1`}>
|
|
<p>{user?.discord ? "@" + user?.discord?.username : "-"}</p>
|
|
</div>
|
|
<div className="p-5" />
|
|
<button className={`rounded-full ${user?.discord ? "bg-red-700" : "bg-green-700"} px-4 py-1`} onClick={ToggleDiscord}>
|
|
{user?.discord ? "Unlink" : "Link"}
|
|
</button>
|
|
</div>
|
|
<div className="flex h-12 items-center">
|
|
<FontAwesomeIcon className="p-2 w-12" icon={faGoogle} size={'2x'} />
|
|
<p className="w-16">Google</p>
|
|
<div className="px-5"></div>
|
|
<div className={`bg-gray-${user?.google ? "8" : "7"}00 rounded-xl items-center justify-center flex w-64 p-1`}>
|
|
<p>{user?.google ? "@" + user?.google?.email : "-"}</p>
|
|
</div>
|
|
<div className="p-5" />
|
|
<button className={`rounded-full ${user?.google ? "bg-red-700" : "bg-green-700"} px-4 py-1`} onClick={ToggleGoogle}>
|
|
{user?.google ? "Unlink" : "Link"}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-opacity-40 bg-gray-900 rounded-3xl itmes-center justify-center p-5 grid">
|
|
<h1 className="text-xl flex justify-center mb-5">Wallets</h1>
|
|
<div>
|
|
<div>
|
|
<div className={`grid grid-cols-6 ${activeWallet == getEmbeddedConnectedWallet(wallets)?.address ? "bg-gray-600" : "bg-gray-800"} rounded-full py-2 px-20 items-center h-20`} onClick={() => { handleWalletClick(getEmbeddedConnectedWallet(wallets)?.address ?? ""); }}>
|
|
<button className="w-12">
|
|
<FontAwesomeIcon icon={faLink} />
|
|
</button>
|
|
<div className="grid col-span-4">
|
|
<p className="flex justify-center items-center">W3B Wallet</p>
|
|
<div className="h-2"></div>
|
|
<p>{getEmbeddedConnectedWallet(wallets)?.address}</p>
|
|
|
|
</div>
|
|
{/* <button className="justify-center items-center flex bg-red-400 ml-8 rounded-full h-10" onClick={()=>{unlinkWallet(wallet.address)}}>
|
|
<FontAwesomeIcon icon={faUnlink}/>
|
|
</button> */}
|
|
<button className="justify-center items-center flex bg-purple-400 ml-8 rounded-full h-10" onClick={exportWallet}>
|
|
<FontAwesomeIcon icon={faFileExport} className="w-6" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="h-7"></div>
|
|
<div className="grid gap-2 p-2">
|
|
{
|
|
wallets.map((wallet) => {
|
|
if (wallet.connectorType == "embedded") { return ""; }
|
|
const address = wallet.address;
|
|
return (
|
|
<div>
|
|
<div className={`grid grid-cols-6 ${wallet.linked ? (address == activeWallet ? "bg-gray-600" : "bg-gray-800") : "bg-gray-900 bg-opacity-30 text-gray-600"} rounded-full py-2 px-20 items-center h-20`} onClick={() => { handleWalletClick(address) }}>
|
|
<button className="w-8">
|
|
<FontAwesomeIcon icon={faWallet} />
|
|
</button>
|
|
<div className="grid col-span-4">
|
|
<p className="flex justify-center items-center">{wallet.walletClientType}</p>
|
|
<div className="h-2"></div>
|
|
<p>{wallet.address}</p>
|
|
|
|
</div>
|
|
{wallet.linked ? <button className="justify-center items-center flex bg-red-400 ml-8 rounded-full h-10" onClick={() => { unlinkWallet(wallet.address) }}>
|
|
<FontAwesomeIcon icon={faUnlink} className="w-6" />
|
|
</button> :
|
|
<FontAwesomeIcon icon={faUnlink} className="w-6 justify-center items-center flex ml-8 rounded-full h-10" />
|
|
}
|
|
|
|
</div>
|
|
</div>
|
|
);
|
|
})
|
|
}
|
|
</div>
|
|
<div className="h-5"></div>
|
|
<button onClick={linkWallet} className="justify-center bg-green-700 flex rounded-full w-96 h-10 items-center mx-auto">
|
|
<div className="flex">
|
|
<div className="">
|
|
<FontAwesomeIcon icon={faAdd} />
|
|
</div>
|
|
<div className="px-10">
|
|
+ Connect New Wallet
|
|
</div>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{showPopup && (
|
|
<div className="fixed inset-0 bg-black bg-opacity-75 flex justify-center items-center">
|
|
<div className="bg-gray-800 p-8 rounded-lg">
|
|
<h2 className="text-xl mb-4">Enter Ticket Amount</h2>
|
|
<div className="flex items-center">
|
|
<button
|
|
onClick={() => setTicketAmount(ticketAmount > 1 ? ticketAmount - 1 : 1)}
|
|
className="text-lg bg-gray-600 hover:bg-gray-500 text-white py-1 px-3 rounded-l"
|
|
>
|
|
-
|
|
</button>
|
|
<input
|
|
type="number"
|
|
value={ticketAmount}
|
|
onChange={(e) => setTicketAmount(Number(e.target.value))}
|
|
className="w-16 text-center text-white bg-black appearance-none"
|
|
style={{
|
|
appearance: 'textfield',
|
|
WebkitAppearance: 'none',
|
|
MozAppearance: 'textfield',
|
|
}}
|
|
/>
|
|
<button
|
|
onClick={() => setTicketAmount(ticketAmount + 1)}
|
|
className="text-lg bg-gray-600 hover:bg-gray-500 text-white py-1 px-3 rounded-r"
|
|
>
|
|
+
|
|
</button>
|
|
</div>
|
|
<div className="mt-4 flex justify-between">
|
|
<button
|
|
onClick={() => buyTicket(ticketAmount)}
|
|
className="bg-green-600 hover:bg-green-700 text-white py-2 px-4 rounded-md"
|
|
>
|
|
Buy
|
|
</button>
|
|
<button
|
|
onClick={() => setShowPopup(false)}
|
|
className="bg-red-600 hover:bg-red-700 text-white py-2 px-4 rounded-md"
|
|
>
|
|
Cancel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
) : (
|
|
<p>Loading...</p>
|
|
)}
|
|
</main>
|
|
</>
|
|
);
|
|
}
|