diff --git a/package.json b/package.json index 1ffbffb..4d0aa04 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "explorer-dapp", "description": "Itheum Explorer is a DApp for the public to explore and visualize data within the Itheum protocol", - "version": "1.13.12", + "version": "1.13.13", "author": "Itheum", "license": "GPL-3.0-or-later", "dependencies": { diff --git a/src/components/Layout/Navbar.tsx b/src/components/Layout/Navbar.tsx index 0e1483b..29edc5d 100644 --- a/src/components/Layout/Navbar.tsx +++ b/src/components/Layout/Navbar.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from "react"; -import { FlaskRound, Home, Menu, Store, Wallet } from "lucide-react"; +import { FlaskRound, Gift, Home, Menu, Store, Wallet } from "lucide-react"; import { Link } from "react-router-dom"; import { SUPPORTED_APPS } from "appsConfig"; import logo192 from "assets/img/logo192.png"; @@ -32,14 +32,17 @@ import { useTheme } from "../../libComponents/ThemeProvider"; import { useAccountStore } from "../../store/account"; import { Popover, PopoverContent, PopoverTrigger } from "../../libComponents/Popover"; import * as PopoverPrimitive from "@radix-ui/react-popover"; -import { BIT_GAME_WINDOW_HOURS, BIT_GAME_TOP_LEADER_BOARD_GROUP } from "../../pages/AppMarketplace/GetBitz"; +import { BIT_GAME_WINDOW_HOURS } from "../../pages/AppMarketplace/GetBitz"; +import Countdown from "react-countdown"; export const Navbar = () => { const isLoggedIn = useGetIsLoggedIn(); const bitzBalance = useAccountStore((state: any) => state.bitzBalance); + const cooldown = useAccountStore((state: any) => state.cooldown); const { address } = useGetAccount(); const { theme } = useTheme(); const [systemTheme, setSystemTheme] = useState(); + const getSystemTheme = () => { if (window.matchMedia("(prefers-color-scheme: dark)").matches) { return "dark"; @@ -58,6 +61,47 @@ export const Navbar = () => { logout(`${window.location.origin}`, undefined, false); }; + const ClaimBitzButton = () => ( + + + + {cooldown === -2 ? ( + ... + ) : cooldown > 0 ? ( + { + if (props.completed) { + return ( + +
+ + Claim your {``} +
+
+ ); + } else { + return ( + + Play again in {props.hours > 0 ? (props.hours + props.hours === 1 ? " Hour " : " Hours ") : ""} + {props.minutes > 0 ? props.minutes + " Min : " : ""} {props.seconds} Sec + + ); + } + }} + /> + ) : ( + +
+ + Claim your {``} +
+
+ )} +
+ + ); + return (
@@ -162,16 +206,11 @@ export const Navbar = () => {

What is {``} XP?

-

+

{``} are Itheum Protocol XP. {``} can be collected every {BIT_GAME_WINDOW_HOURS} hours by playing the Get {``} game Data Widget. Top LEADERBOARD climbers get special perks and drops!

- - - - Get {``} - - + diff --git a/src/libs/utils/functions.ts b/src/libs/utils/functions.ts new file mode 100644 index 0000000..e11fb49 --- /dev/null +++ b/src/libs/utils/functions.ts @@ -0,0 +1,7 @@ +export const computeRemainingCooldown = (startTime: number, cooldown: number) => { + const timePassedFromLastPlay = Date.now() - startTime; + console.log("timePassedFromLastPlay", timePassedFromLastPlay); + const _cooldown = cooldown - timePassedFromLastPlay; + + return _cooldown > 0 ? _cooldown + Date.now() : 0; +}; diff --git a/src/pages/AppMarketplace/GetBitz/BurningImage.tsx b/src/pages/AppMarketplace/GetBitz/BurningImage.tsx index e2f6e31..cc9dcce 100644 --- a/src/pages/AppMarketplace/GetBitz/BurningImage.tsx +++ b/src/pages/AppMarketplace/GetBitz/BurningImage.tsx @@ -26,7 +26,7 @@ export const BurningImage: React.FC<{ src: string; burnProgress: number }> = ({ }; return ( -
+
{ const [checkingIfHasGameDataNFT, setCheckingIfHasGameDataNFT] = useState(true); const [hasGameDataNFT, setHasGameDataNFT] = useState(false); const [isLoading, setIsLoading] = useState(true); + const bitzBalance = useAccountStore((state: any) => state.bitzBalance); + const cooldown = useAccountStore((state: any) => state.cooldown); const updateBitzBalance = useAccountStore((state) => state.updateBitzBalance); + const updateCooldown = useAccountStore((state) => state.updateCooldown); // a single game-play related (so we have to reset these if the user wants to "replay") const [isFetchingDataMarshal, setIsFetchingDataMarshal] = useState(false); @@ -243,6 +247,17 @@ export const GetBitz = () => { setGameDataFetched(true); setIsFetchingDataMarshal(false); setViewDataRes(viewDataPayload); + console.log("viewDataPayload", viewDataPayload.data.gamePlayResult); + console.log( + "cooldown", + computeRemainingCooldown(viewDataPayload.data.gamePlayResult.lastPlayedAndCommitted, viewDataPayload.data.gamePlayResult.configCanPlayEveryMSecs) + ); + updateCooldown( + computeRemainingCooldown( + Math.max(viewDataPayload.data.gamePlayResult.lastPlayedAndCommitted, viewDataPayload.data.gamePlayResult.lastPlayedBeforeThisPlay), + viewDataPayload.data.gamePlayResult.configCanPlayEveryMSecs + ) + ); if (viewDataPayload.data.gamePlayResult.bitsScoreAfterPlay > -1) { updateBitzBalance(viewDataPayload.data.gamePlayResult.bitsScoreAfterPlay); @@ -326,7 +341,7 @@ export const GetBitz = () => { } // user is logged in and we are checking if they have the data nft to proceed with a play - if (address && checkingIfHasGameDataNFT && !hasGameDataNFT) { + if ((address && checkingIfHasGameDataNFT && !hasGameDataNFT) || cooldown === -2) { return (
{"Checking Data NFT"} /> @@ -347,19 +362,6 @@ export const GetBitz = () => {
); } - - // user has data nft, so load the "start game" view - if (!_loadBlankGameCanvas && !_isFetchingDataMarshal) { - return ( -
{ - setLoadBlankGameCanvas(true); - }}> - {"Start -
- ); - } - const CountDownComplete = () => (
{ // Render a countdown return ( - {props.hours}H:{props.minutes}M:{props.seconds}S + {props.hours > 0 ? (props.hours + props.hours === 1 ? " Hour " : " Hours ") : ""} + {props.minutes > 0 ? props.minutes + " Min : " : ""} {props.seconds} Sec ); } }; + // user has data nft, so load the "start game" view + if (!_loadBlankGameCanvas && !_isFetchingDataMarshal) { + return ( +
+ {cooldown > 0 && ( + { + if (props.completed) { + return <> ; + } else { + return ( +
+
+
+

You can play again in:

{" "} + {props.hours > 0 ? (props.hours + props.hours === 1 ? " Hour " : " Hours ") : ""} + {props.minutes > 0 ? props.minutes + " Min : " : ""} {props.seconds} Sec +
+
+
+ ); + } + }} + /> + )} + { + setLoadBlankGameCanvas(true); + }} + className="rounded-[3rem] w-full cursor-pointer" + src={ImgPlayGame} + alt={"Start Game"} + /> +
+ ); + } + // user clicked on the start game view, so load the empty blank game canvas if (_loadBlankGameCanvas && !_gameDataFetched) { return ( diff --git a/src/pages/AppMarketplace/MultiversxInfographics/index.tsx b/src/pages/AppMarketplace/MultiversxInfographics/index.tsx index 9ff6c05..dda3e77 100644 --- a/src/pages/AppMarketplace/MultiversxInfographics/index.tsx +++ b/src/pages/AppMarketplace/MultiversxInfographics/index.tsx @@ -104,11 +104,11 @@ export const MultiversxInfographics = () => { "authorization": `Bearer ${tokenLogin.nativeAuthToken}`, }, }; - // console.log("arg", arg); - if (!dataNft.dataMarshal || dataNft.dataMarshal === "") { + + if (!dataNft.dataMarshal || dataNft.dataMarshal === "") { dataNft.updateDataNft({ dataMarshal: getApiDataMarshal(chainID) }); } - res = await dataNft.viewDataViaMVXNativeAuth(arg); + res = await dataNft.viewDataViaMVXNativeAuth(arg); let blobDataType = BlobDataType.TEXT; diff --git a/src/pages/PlayStationGamer.tsx b/src/pages/PlayStationGamer.tsx index 94bfff7..e3cf0e7 100644 --- a/src/pages/PlayStationGamer.tsx +++ b/src/pages/PlayStationGamer.tsx @@ -30,7 +30,6 @@ export const PlayStationGamer = () => { const _nfts: DataNft[] = await DataNft.createManyFromApi( PLAYSTATION_GAMER_PASSPORT_TOKENS.map((v) => ({ nonce: v.nonce, tokenIdentifier: v.tokenIdentifier })) ); - // console.log("ccDataNfts", _nfts); setCcDataNfts(_nfts); setIsLoading(false); } else { diff --git a/src/store/StoreProvider.tsx b/src/store/StoreProvider.tsx index 6fb9aa4..5c43d95 100644 --- a/src/store/StoreProvider.tsx +++ b/src/store/StoreProvider.tsx @@ -6,6 +6,7 @@ import { useGetAccount } from "hooks"; import { decodeNativeAuthToken } from "libs/utils"; import { useAccountStore } from "./account"; import { viewDataJSONCore } from "../pages/AppMarketplace/GetBitz"; +import { computeRemainingCooldown } from "libs/utils/functions"; export const StoreProvider = ({ children }: PropsWithChildren) => { const { address } = useGetAccount(); @@ -13,6 +14,7 @@ export const StoreProvider = ({ children }: PropsWithChildren) => { // ACCOUNT STORE const updateBitzBalance = useAccountStore((state) => state.updateBitzBalance); + const updateCooldown = useAccountStore((state) => state.updateCooldown); useEffect(() => { if (!address || !(tokenLogin && tokenLogin.nativeAuthToken)) { @@ -46,10 +48,17 @@ export const StoreProvider = ({ children }: PropsWithChildren) => { if (getBitzGameResult) { updateBitzBalance(getBitzGameResult.data.gamePlayResult.bitsScoreBeforePlay); + updateCooldown( + computeRemainingCooldown( + getBitzGameResult.data.gamePlayResult.lastPlayedBeforeThisPlay, + getBitzGameResult.data.gamePlayResult.configCanPlayEveryMSecs + ) + ); } } else { console.log("info: user does NOT OWN the bitz score data nft"); updateBitzBalance(-1); + updateCooldown(-1); } })(); }, [address, tokenLogin]); diff --git a/src/store/account.ts b/src/store/account.ts index f5d2f7e..dba5128 100644 --- a/src/store/account.ts +++ b/src/store/account.ts @@ -2,13 +2,17 @@ import { create } from "zustand"; type State = { bitzBalance: number; + cooldown: number; }; type Action = { updateBitzBalance: (bitzBalance: State["bitzBalance"]) => void; + updateCooldown: (cooldown: State["cooldown"]) => void; }; export const useAccountStore = create((set) => ({ bitzBalance: -2, + cooldown: -2, updateBitzBalance: (value: number) => set(() => ({ bitzBalance: value })), + updateCooldown: (value: number) => set(() => ({ cooldown: value })), }));