Joseph Ferano 9b753cf103 Porting database from SQLite to PostgreSQL
- 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.
2023-03-30 14:13:30 +07:00

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>
);
}