From b19b8b727ed49237e8067806404e361d57394927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oytun=20=C3=87oban?= Date: Wed, 1 Feb 2023 15:57:28 +0300 Subject: [PATCH 1/4] Tab desings and State Context --- packages/frontend/components/Header.tsx | 9 +- packages/frontend/components/Layout.tsx | 160 ++++++++---------- .../components/contract/GetDrawnNumbers.tsx | 1 - 3 files changed, 72 insertions(+), 98 deletions(-) diff --git a/packages/frontend/components/Header.tsx b/packages/frontend/components/Header.tsx index 456095b..7f1ed54 100644 --- a/packages/frontend/components/Header.tsx +++ b/packages/frontend/components/Header.tsx @@ -15,10 +15,10 @@ interface ITab { } export const tabs: ITab[] = [ - { name: "Mint", href: "/mint", active: true }, - { name: "The Draw", href: "/lucky-numbers", active: false }, - { name: "The Winner", href: "/winner", active: false }, - { name: "My Cards", href: "/my-cards", active: true }, + { name: "🎲 Mint", href: "/mint", active: true }, + { name: "🎰 The Draw", href: "/lucky-numbers", active: false }, + { name: "🫶 The Impact", href: "/winner", active: false }, + { name: "🃏 My Cards", href: "/my-cards", active: true }, ]; function classNames(...classes: any[]) { @@ -34,7 +34,6 @@ export default function Header(props: HeaderProps) { const isMobile = useMediaQuery({ query: "(max-width: 768px)" }); const isPortrait = useMediaQuery({ query: "(orientation: portrait)" }); const bingoState = useContext(BingoStateContext); - console.log("Bingo:", bingoState); switch (bingoState) { case BingoState.MINT: tabs[0].active = true; diff --git a/packages/frontend/components/Layout.tsx b/packages/frontend/components/Layout.tsx index 1376873..4e74b37 100644 --- a/packages/frontend/components/Layout.tsx +++ b/packages/frontend/components/Layout.tsx @@ -1,12 +1,12 @@ -import { BGBlur, Header, Footer } from "@/components"; -import { BingoState, useBingoContract } from "@/hooks/useBingoContract"; -import { BigNumber, Contract } from "ethers"; -import Link from "next/link"; +import { Footer, Header } from "@/components"; +import { CHAIN_ID, CONTRACT_ABI, CONTRACT_ADDRESS } from "@/config"; +import { BingoState } from "@/hooks/useBingoContract"; +import { getNetwork, GetNetworkResult, watchNetwork } from "@wagmi/core"; import { createContext, PropsWithChildren, useEffect, useState } from "react"; import { toast } from "react-toastify"; -import { useProvider } from "wagmi"; -import { getNetwork, GetNetworkResult, watchNetwork } from "@wagmi/core"; -import { CHAIN_ID } from "@/config"; +import { useContractRead } from "wagmi"; +import { useWatchContractEvent } from "../hooks/useWatchContractEvent"; +import { useWatchNetwork } from "../hooks/useWatchNetwork"; type LayoutProps = {}; @@ -22,106 +22,82 @@ function Layout(props: PropsWithChildren) { const [bingoState, setBingoState] = useState(); const [winnerCardId, setWinnerCardId] = useState(); const [isOnCorrectNetwork, setIsOnCorrectNetwork] = useState(false); - const [initialFetchCompleted, setInitialFetchCompleted] = useState(false); - const [trigger, setTrigger] = useState(); // Web3 Hooks - const provider = useProvider(); - const contract: Contract | undefined = useBingoContract(provider); const [network, setNetwork] = useState(() => getNetwork()); - watchNetwork((newNetwork) => { - if (newNetwork.chain?.id != network.chain?.id) { - setNetwork(newNetwork); - } + useWatchNetwork(network, setNetwork); + + // Throttle lock + let throttleLock: boolean = false; + + const getBingoState = useContractRead({ + abi: CONTRACT_ABI, + address: CONTRACT_ADDRESS, + functionName: "bingoState", + args: [], + onSuccess: (data: any) => { + setBingoState(data); + }, + onError: (error: any) => { + toast.error("Coudln't fetch bingo state!"); + console.log("Error:", error); + }, + onSettled: () => { + console.log("Bingo State fetched!"); + }, + watch: true, }); + useWatchContractEvent("DrawStarted", getBingoState, throttleLock); useEffect(() => { if (network.chain?.id == CHAIN_ID) { setIsOnCorrectNetwork(true); } + getBingoState.refetch(); + }, [network.chain?.id]); - const getBingoState = async () => { - try { - const state = await contract!.bingoState(); - return state; - } catch (error) { - console.log(error); - } - }; - if (!contract) { - return; - } - - if (!initialFetchCompleted || trigger) { - getBingoState().then((state) => { - if (state !== undefined) { - setBingoState((prevState) => { - if (prevState === undefined && state !== undefined) { - setInitialFetchCompleted(true); - } - return state; - }); - } - }); - } - }, [trigger, network.chain?.id]); - - useEffect(() => { - if (contract) { - contract.on("DrawStarted", drawStartedHandler); - contract.on("ClaimPrize", gameFinishedHandler); - } - return () => { - if (contract) { - contract.off("DrawStarted", drawStartedHandler); - contract.off("ClaimPrize", gameFinishedHandler); - } - }; - }, [initialFetchCompleted, trigger]); - async function drawStartedHandler(event: Event) { - toast.info(`Draw has been started, good luck!`); - setTrigger((trigger) => event); - } + // TODO: Migrate to useWatchContractEvent + // async function drawStartedHandler(event: Event) { + // toast.info(`Draw has been started, good luck!`); + // setTrigger((trigger) => event); + // } - async function gameFinishedHandler( - id: BigNumber, - winnerAddress: string, - event: Event - ) { - const CustomToastWithLink = (id: BigNumber) => { - return ( -
- Looks like we have a winner, congratulations!{" "} - - Check the card - -
- ); - }; - setWinnerCardId(Number(id)); - toast.info(CustomToastWithLink(id)); - setTrigger((trigger) => event); - } + // async function gameFinishedHandler( + // id: BigNumber, + // winnerAddress: string, + // event: Event + // ) { + // const CustomToastWithLink = (id: BigNumber) => { + // return ( + //
+ // Looks like we have a winner, congratulations!{" "} + // + // Check the card + // + //
+ // ); + // }; + // setWinnerCardId(Number(id)); + // toast.info(CustomToastWithLink(id)); + // setTrigger((trigger) => event); + // } return (
- -
-
- - - - {props.children} - - - -
+ + + +
+
{props.children}
+
+
+
); diff --git a/packages/frontend/components/contract/GetDrawnNumbers.tsx b/packages/frontend/components/contract/GetDrawnNumbers.tsx index cb96265..91ace08 100644 --- a/packages/frontend/components/contract/GetDrawnNumbers.tsx +++ b/packages/frontend/components/contract/GetDrawnNumbers.tsx @@ -27,7 +27,6 @@ export const GetDrawnNumbers = (props: GetDrawnNumbersProps) => { abi: CONTRACT_ABI, functionName: "getDrawnNumbers", onSuccess(data: any) { - console.log(data); setDrawnNumbers(data); setMessage(""); }, From 6fa0d0e2cbe857317a24481cc64e5aa59eca3293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oytun=20=C3=87oban?= Date: Wed, 1 Feb 2023 18:45:33 +0300 Subject: [PATCH 2/4] Initial approach for banner flow --- packages/frontend/components/Banner.tsx | 132 ++++++++++++++++++++++++ packages/frontend/components/Header.tsx | 14 ++- packages/frontend/components/Layout.tsx | 17 ++- 3 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 packages/frontend/components/Banner.tsx diff --git a/packages/frontend/components/Banner.tsx b/packages/frontend/components/Banner.tsx new file mode 100644 index 0000000..4e19ceb --- /dev/null +++ b/packages/frontend/components/Banner.tsx @@ -0,0 +1,132 @@ +import React, { useEffect, useState } from "react"; +import { MegaphoneIcon, XMarkIcon } from "@heroicons/react/24/outline"; +import Link from "next/link"; +import { useContext } from "react"; +import { BingoStateContext } from "@/components/Layout"; +import { BingoState } from "@/hooks/useBingoContract"; +import { tabs } from "@/components/Header"; +import moment, { now } from "moment"; +import { useContractRead } from "wagmi"; +import { CONTRACT_ABI, CONTRACT_ADDRESS } from "../config"; + +type BannerProps = { + setShowBanner: React.Dispatch>; + activeTab: string; +}; + +export function Banner(props: BannerProps) { + const { setShowBanner, activeTab } = props; + const [bannerContent, setBannerContent] = useState(""); + const bingoState = useContext(BingoStateContext); + const [drawTimestamp, setDrawTimestamp] = useState(0); + const [humanizedCountdown, setHumanizedCountdown] = useState(""); + const [icon, setIcon] = useState( +