- New Postgres table schemas - Using Stored Procedures with transactions that validate business logic - User Ids now use UUID - Updated and simplified all endpoints to call the stored procedures Notes: There are still a few things missing that broke because of the migration, in particular, because we moved a lot of the business logic into the database, we now require that certain data that lived in the game-config.json to be present in the database as well, to prevent cheating and truly have a single source of truth.
124 lines
3.4 KiB
TypeScript
124 lines
3.4 KiB
TypeScript
"use client";
|
|
import { Dispatch, SetStateAction, useEffect, useState } from "react";
|
|
import type { PublicKey } from "@solana/web3.js";
|
|
import { PhantomProvider } from "typings";
|
|
import { useRouter } from "next/navigation";
|
|
import { BiLoaderAlt } from "react-icons/bi";
|
|
|
|
export default function Navbar({
|
|
setUserId,
|
|
}: {
|
|
setUserId: Dispatch<SetStateAction<string>>;
|
|
}) {
|
|
const router = useRouter();
|
|
|
|
const [provider, setProvider] = useState<PhantomProvider>();
|
|
const [walletAddress, setWalletAddress] = useState("");
|
|
const [showErrorMessage, setShowErrorMessage] = useState(false);
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
const provider = getProvider();
|
|
setProvider(provider);
|
|
|
|
if (provider) {
|
|
provider.on("connect", async (publicKey: PublicKey) => {
|
|
setIsLoading(true);
|
|
const body = { wallet: publicKey };
|
|
const res = await fetch("/api/user/login", {
|
|
method: "POST",
|
|
body: JSON.stringify(body),
|
|
headers: { "Content-Type": "application/json" },
|
|
});
|
|
if (res.status === 200) {
|
|
const { userId } = await res.json();
|
|
localStorage.setItem("userId", userId);
|
|
setWalletAddress(publicKey.toBase58());
|
|
setUserId(userId);
|
|
}
|
|
if (res.status === 404) {
|
|
setShowErrorMessage(true);
|
|
setTimeout(() => {
|
|
setShowErrorMessage(false);
|
|
}, 3000);
|
|
}
|
|
setIsLoading(false);
|
|
});
|
|
}
|
|
|
|
const localStorageUserId = localStorage.getItem("userId");
|
|
if (localStorageUserId) {
|
|
setUserId(localStorageUserId);
|
|
const fetchWallet = async () => {
|
|
const res = await fetch(`/api/user/${localStorageUserId}/wallet`);
|
|
if (res.status === 200) {
|
|
const { wallet } = await res.json();
|
|
setWalletAddress(wallet);
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
fetchWallet();
|
|
return;
|
|
}
|
|
setIsLoading(false);
|
|
}, []);
|
|
|
|
const getProvider = () => {
|
|
if ("phantom" in window) {
|
|
const anyWindow: any = window;
|
|
const provider = anyWindow.phantom.solana;
|
|
if (provider.isPhantom) return provider;
|
|
}
|
|
};
|
|
|
|
const connectWallet = () => {
|
|
if (!provider) return console.log("no provider");
|
|
provider.connect();
|
|
};
|
|
|
|
const logout = () => {
|
|
localStorage.removeItem("userId");
|
|
setUserId("");
|
|
setWalletAddress("");
|
|
provider?.disconnect();
|
|
router.refresh();
|
|
};
|
|
|
|
return (
|
|
<nav className="text-white flex justify-between mt-4">
|
|
<button
|
|
onClick={() => router.push("/")}
|
|
className="p-2 m-4 text-3xl font-bold"
|
|
>
|
|
Moon Miners
|
|
</button>
|
|
{showErrorMessage && (
|
|
<div className="p-2 m-4 bg-red-800 rounded-lg">
|
|
Wallet address not registered!
|
|
</div>
|
|
)}
|
|
{walletAddress.length === 0 ? (
|
|
<button
|
|
onClick={connectWallet}
|
|
className="p-2 m-4 bg-slate-800 rounded-lg"
|
|
>
|
|
{isLoading ? (
|
|
<BiLoaderAlt className="animate-spin w-28" />
|
|
) : (
|
|
"Connect Wallet"
|
|
)}
|
|
</button>
|
|
) : (
|
|
<div className="flex items-stretch">
|
|
<button className="p-2 m-4 bg-slate-800 rounded-lg">
|
|
{walletAddress}
|
|
</button>
|
|
<button onClick={logout} className="p-2 m-4 bg-slate-800 rounded-lg">
|
|
Logout
|
|
</button>
|
|
</div>
|
|
)}
|
|
</nav>
|
|
);
|
|
}
|