From b4edbd08f5bba0c0f5a8382fb77120fc7dce75d6 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Fri, 8 Mar 2024 15:43:41 +0300 Subject: [PATCH 001/192] new fonts --- web/pages/_document.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/web/pages/_document.tsx b/web/pages/_document.tsx index 175e73d5..88e47376 100644 --- a/web/pages/_document.tsx +++ b/web/pages/_document.tsx @@ -8,6 +8,13 @@ export default function Document() { name="robots" content={process.env.NEXT_PUBLIC_BUILD_TARGET == "alpha" ? "noindex" : "all"} /> + + + + Date: Fri, 8 Mar 2024 15:44:06 +0300 Subject: [PATCH 002/192] config next images --- web/next.config.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/web/next.config.js b/web/next.config.js index bf2eb08b..d1264ada 100644 --- a/web/next.config.js +++ b/web/next.config.js @@ -2,6 +2,16 @@ const nextConfig = { reactStrictMode: true, trailingSlash: true, + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "static.simiotics.com", + port: "", + pathname: "/fullcount/**", + }, + ], + }, }; module.exports = nextConfig; From 01b25b5ad53cea377a4c5447a4e4da64fb9233f0 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Sat, 9 Mar 2024 14:54:26 +0300 Subject: [PATCH 003/192] style for --- web/src/styles/globals.css | 123 ++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 36 deletions(-) diff --git a/web/src/styles/globals.css b/web/src/styles/globals.css index 3a96a7ee..5a60296a 100644 --- a/web/src/styles/globals.css +++ b/web/src/styles/globals.css @@ -1,40 +1,91 @@ :root { - --max-width: 1100px; - --border-radius: 12px; - --font-mono: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", "Roboto Mono", - "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", "Fira Mono", "Droid Sans Mono", - "Courier New", monospace; - - --foreground-rgb: 0, 0, 0; - --background-start-rgb: 214, 219, 220; - --background-end-rgb: 255, 255, 255; - - --primary-glow: conic-gradient( - from 180deg at 50% 50%, - #16abff33 0deg, - #0885ff33 55deg, - #54d6ff33 120deg, - #0071ff33 160deg, - transparent 360deg - ); - --secondary-glow: radial-gradient(rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)); - - --tile-start-rgb: 239, 245, 249; - --tile-end-rgb: 228, 232, 233; - --tile-border: conic-gradient( - #00000080, - #00000040, - #00000030, - #00000020, - #00000010, - #00000010, - #00000080 - ); - - --callout-rgb: 238, 240, 241; - --callout-border-rgb: 172, 175, 176; - --card-rgb: 180, 185, 188; - --card-border-rgb: 131, 134, 135; +} + + +input { + display: flex; + padding: 9px 14px; + align-items: center; + margin-bottom: 10px; + align-self: stretch; + border: 1px solid #4D4D4D; + background: #FCECD9; + color: #262019; + font-family: 'Pangolin', sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + + + +input:focus-visible { + border: 1px solid #4D4D4D; + outline: none; +} + + +input::placeholder { + color: #7E8E7F; + font-family: 'Pangolin', sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + +input::-webkit-input-placeholder { /* Chrome/Opera/Safari */ + color: #7E8E7F; + font-family: 'Pangolin', sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + + input::-moz-placeholder { /* Firefox 19+ */ + color: #7E8E7F; + font-family: 'Pangolin', sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + +input:-ms-input-placeholder { /* IE 10+ */ + color: #7E8E7F; + font-family: 'Pangolin', sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + +input:-moz-placeholder { /* Firefox 18- */ + color: #7E8E7F; + font-family: 'Pangolin', sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + +.inputError { + border-color: darkred; +} + +.inputError::-webkit-input-placeholder { + color: darkred; +} +.inputError::-moz-placeholder { + color: darkred; +} +.inputError:-ms-input-placeholder { + color: darkred; +} +.inputError:-moz-placeholder { + color: darkred; } @media (prefers-color-scheme: dark) { From fe5d2fa1611a2889574ff2bff78eb45cb1306d4a Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Sat, 9 Mar 2024 15:38:41 +0300 Subject: [PATCH 004/192] useLogin to return isSuccess --- web/src/hooks/useLogin.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/src/hooks/useLogin.ts b/web/src/hooks/useLogin.ts index 6f6cc2a9..cb357942 100644 --- a/web/src/hooks/useLogin.ts +++ b/web/src/hooks/useLogin.ts @@ -9,6 +9,7 @@ const useLogin = () => { const { mutate: login, isLoading, + isSuccess, error, data, } = useMutation(loginService, { @@ -29,6 +30,7 @@ const useLogin = () => { return { login, isLoading, + isSuccess, data, error, }; From d4123da1a7394463791b774069f97e6aedba474d Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Sat, 9 Mar 2024 15:43:15 +0300 Subject: [PATCH 005/192] fallback font for inputs --- web/src/styles/globals.css | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/web/src/styles/globals.css b/web/src/styles/globals.css index 5a60296a..0ae9321a 100644 --- a/web/src/styles/globals.css +++ b/web/src/styles/globals.css @@ -11,7 +11,7 @@ input { border: 1px solid #4D4D4D; background: #FCECD9; color: #262019; - font-family: 'Pangolin', sans-serif; + font-family: 'Pangolin', cursive; font-size: 16px; font-style: normal; font-weight: 400; @@ -28,7 +28,7 @@ input:focus-visible { input::placeholder { color: #7E8E7F; - font-family: 'Pangolin', sans-serif; + font-family: 'Pangolin', cursive; font-size: 16px; font-style: normal; font-weight: 400; @@ -37,7 +37,7 @@ input::placeholder { input::-webkit-input-placeholder { /* Chrome/Opera/Safari */ color: #7E8E7F; - font-family: 'Pangolin', sans-serif; + font-family: 'Pangolin', cursive; font-size: 16px; font-style: normal; font-weight: 400; @@ -46,7 +46,7 @@ input::-webkit-input-placeholder { /* Chrome/Opera/Safari */ input::-moz-placeholder { /* Firefox 19+ */ color: #7E8E7F; - font-family: 'Pangolin', sans-serif; + font-family: 'Pangolin', cursive; font-size: 16px; font-style: normal; font-weight: 400; @@ -55,7 +55,7 @@ input::-webkit-input-placeholder { /* Chrome/Opera/Safari */ input:-ms-input-placeholder { /* IE 10+ */ color: #7E8E7F; - font-family: 'Pangolin', sans-serif; + font-family: 'Pangolin', cursive; font-size: 16px; font-style: normal; font-weight: 400; @@ -64,7 +64,7 @@ input:-ms-input-placeholder { /* IE 10+ */ input:-moz-placeholder { /* Firefox 18- */ color: #7E8E7F; - font-family: 'Pangolin', sans-serif; + font-family: 'Pangolin', cursive; font-size: 16px; font-style: normal; font-weight: 400; From 4d5489d9807968d40fd43133b746641a132b9f74 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Sat, 9 Mar 2024 15:45:27 +0300 Subject: [PATCH 006/192] login and sign up CSS --- web/src/components/account/Account.module.css | 106 +++++++----------- 1 file changed, 40 insertions(+), 66 deletions(-) diff --git a/web/src/components/account/Account.module.css b/web/src/components/account/Account.module.css index 4d7ae828..c4be75d5 100644 --- a/web/src/components/account/Account.module.css +++ b/web/src/components/account/Account.module.css @@ -1,84 +1,58 @@ -.loginButton { + +.container { display: flex; - padding: 5px 10px; - justify-content: center; + flex-direction: column; align-items: center; - gap: 10px; - border-radius: 20px; - background: #353535; - color: #FFF; - font-family: Space Grotesk, sans-serif; - font-size: 12px; - font-style: normal; - font-weight: 400; - line-height: 1; - white-space: nowrap; + gap: 0; + width: 100%; } -.signUpButton { - display: flex; - padding: 5px 10px; - justify-content: center; - align-items: center; - gap: 10px; - border-radius: 20px; - background: #F56646; - color: #FFF; - font-family: Space Grotesk, sans-serif; - font-size: 12px; +.header { + color: #262019; + text-align: center; + font-family: Bangers, cursive, fantasy; + font-size: 30px; font-style: normal; - font-weight: 700; + font-weight: 400; line-height: 100%; - white-space: nowrap; + letter-spacing: 1.5px; + margin-bottom: 20px; + } + +.label { + color: #262019; + font-family: Pangolin, cursive; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; + text-align: start; + place-self: start; + margin-bottom: 5px; } -.portalButton { +.button { + margin-top: 10px; display: flex; - padding: 4px 9px; + height: 50px; + padding: 10px 20px; + justify-content: center; align-items: center; gap: 10px; - border-radius: 30px; - border: 1px solid #FFF; - background-color: transparent; + width: 100%; + border: 1px solid #262019; + background: #328449; color: #FFF; text-align: center; - font-family: Space Grotesk, sans-serif; - font-size: 12px; + font-family: Bangers, cursive, fantasy; + font-size: 24px; font-style: normal; font-weight: 400; - line-height: 100%; /* 12px */ -} - -.divider { - background-color: #8F8F8F; - height: 3px; - width: 3px; - border-radius: 50%; -} - -@media (min-width: 768px) { - .portalButton { - padding: 9px 14px; - height: 36px; - font-size: 16px; - } - - .loginButton, .signUpButton { - padding: 5px 15px; - font-size: 16px; - height: 36px; - - } + line-height: normal; + letter-spacing: 1.2px; } -.portalButton:hover { - background-color: #FFF; - color: black; +.fadeOut { + opacity: 0; + transition: opacity 1s ease-out; } - - -.portalButtonText:hover { - background: -webkit-linear-gradient(0deg, #F56646, #f89a85); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; -} \ No newline at end of file From 794eb54ac301d844016ec49e9cb13a541cc38050 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Sat, 9 Mar 2024 15:46:23 +0300 Subject: [PATCH 007/192] login and sign up forms --- web/src/components/account/LoginForm.tsx | 66 +++++++++++++++++++++ web/src/components/account/SignUpForm.tsx | 72 +++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 web/src/components/account/LoginForm.tsx create mode 100644 web/src/components/account/SignUpForm.tsx diff --git a/web/src/components/account/LoginForm.tsx b/web/src/components/account/LoginForm.tsx new file mode 100644 index 00000000..b2145ef0 --- /dev/null +++ b/web/src/components/account/LoginForm.tsx @@ -0,0 +1,66 @@ +import React, { useEffect, useState } from "react"; + +import { Spinner } from "@chakra-ui/react"; + +import styles from "./Account.module.css"; +import useLogin from "../../hooks/useLogin"; + +const LoginForm = ({ setIsSuccess }: { setIsSuccess: (isSuccess: boolean) => void }) => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const { login, isLoading, isSuccess } = useLogin(); + const [showInvalid, setShowInvalid] = useState(false); + + const isUsernameValid = !!username; + const isPasswordValid = !!password; + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + if (!isUsernameValid || !isPasswordValid) { + setShowInvalid(true); + return; + } + login({ username, password }); + }; + + useEffect(() => { + setIsSuccess(isSuccess); + }, [isSuccess]); + + return ( +
+
+
Welcome!
+ + { + setShowInvalid(false); + setUsername(event.target.value); + }} + /> +
Password
+ { + setShowInvalid(false); + setPassword(event.target.value); + }} + /> +
+ +
+ ); +}; + +export default LoginForm; diff --git a/web/src/components/account/SignUpForm.tsx b/web/src/components/account/SignUpForm.tsx new file mode 100644 index 00000000..1300f11d --- /dev/null +++ b/web/src/components/account/SignUpForm.tsx @@ -0,0 +1,72 @@ +import React, { useEffect, useState } from "react"; + +import { Spinner } from "@chakra-ui/react"; + +import useSignUp from "../../hooks/useSignUp"; +import styles from "./Account.module.css"; + +const SignUpForm = ({ setIsSuccess }: { setIsSuccess: (isSuccess: boolean) => void }) => { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [email, setEmail] = useState(""); + const [showErrors, setShowErrors] = useState(false); + + const { signUp, isLoading, isSuccess } = useSignUp(); + + const handleSubmit = (event: React.FormEvent) => { + event.preventDefault(); + if (username && password && email) { + signUp({ username, email, password }); + } else { + setShowErrors(true); + } + }; + useEffect(() => { + setShowErrors(false); + }, [username, email, password]); + + useEffect(() => { + setIsSuccess(isSuccess); + }, [isSuccess]); + + return ( +
+
+
Welcome!
+ + setUsername(event.target.value)} + /> +
Email
+ setEmail(event.target.value)} + /> + +
Password
+ setPassword(event.target.value)} + /> +
+ +
+ ); +}; + +export default SignUpForm; From 015acb9186d37faa0b4530ce14475842c04dacdc Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Sat, 9 Mar 2024 15:47:31 +0300 Subject: [PATCH 008/192] Title screen --- web/src/components/TitleScreen.module.css | 53 +++++++++++++++++++++ web/src/components/TitleScreen.tsx | 58 ++++++++++++++++------- 2 files changed, 93 insertions(+), 18 deletions(-) diff --git a/web/src/components/TitleScreen.module.css b/web/src/components/TitleScreen.module.css index 8106a71f..cc0307c6 100644 --- a/web/src/components/TitleScreen.module.css +++ b/web/src/components/TitleScreen.module.css @@ -15,6 +15,41 @@ backdrop-filter: blur(25px); } +.content { + display: flex; + padding: 20px; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 10px; + flex-grow: 1; + width: 100%; +} + +.footer{ + display: flex; + gap: 5px; +} + +.footerText{ + color: #262019; + font-family: Pangolin; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + +.footerButton { + color: #328449; + font-family: Pangolin; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; + cursor: pointer; +} + .title2 { color: #fff; text-align: center; @@ -55,3 +90,21 @@ font-size: 18px; } } + +.loginContainer { + display: flex; + padding-top: 20px; + flex-direction: column; + justify-content: center; + align-items: center; + background: #FCECD9; + min-height: 100vh; + width: 100%; +} + +.logo { + height: 84px; + width: 158px; +} + + diff --git a/web/src/components/TitleScreen.tsx b/web/src/components/TitleScreen.tsx index fd410264..a9033bc6 100644 --- a/web/src/components/TitleScreen.tsx +++ b/web/src/components/TitleScreen.tsx @@ -1,32 +1,54 @@ -import { useContext, useEffect } from "react"; -import { useQueryClient } from "react-query"; +import { useState } from "react"; +import Image from "next/image"; -import ConnectingView from "./ConnectingView"; -import Web3Context from "../contexts/Web3Context/context"; -import TitleScreenLayout from "./layout/TitleScreenLayout"; +import styles from "./TitleScreen.module.css"; +import useUser from "../contexts/UserContext"; import PlayingLayout from "./layout/PlayingLayout"; import Playing from "./Playing"; -import { useGameContext } from "../contexts/GameContext"; +import SignUpForm from "./account/SignUpForm"; +import LoginForm from "./account/LoginForm"; +import { FULLCOUNT_ASSETS_PATH } from "../constants"; const TitleScreen = () => { - const web3ctx = useContext(Web3Context); - - const { chainId } = useGameContext(); - - const queryClient = useQueryClient(); - - useEffect(() => { - queryClient.invalidateQueries(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [web3ctx.chainId, web3ctx.account]); + const { user } = useUser(); + const [isLogging, setIsLogging] = useState(false); // login or signUp + const [isSuccess, setIsSuccess] = useState(false); return ( <> - <> + {user ? ( - + ) : ( +
+ {""} +
+ {!isLogging ? ( + setIsSuccess(value)} /> + ) : ( + setIsSuccess(value)} /> + )} + {!isSuccess && ( +
+
+ {isLogging ? "New to Fullcount?" : "Already have an account?"} +
+
setIsLogging((prev) => !prev)}> + {isLogging ? "Create an account" : "Log in"} +
+
+ )} +
+
+ )} ); }; From efe72ca44091bc4eb2cb38cf392b709ae00af5d5 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Sat, 9 Mar 2024 17:06:28 +0300 Subject: [PATCH 009/192] prefetch banner --- web/pages/_document.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/web/pages/_document.tsx b/web/pages/_document.tsx index 88e47376..7247bb32 100644 --- a/web/pages/_document.tsx +++ b/web/pages/_document.tsx @@ -1,4 +1,5 @@ import { Html, Head, Main, NextScript } from "next/document"; +import { FULLCOUNT_ASSETS_PATH } from "../src/constants"; export default function Document() { return ( @@ -8,6 +9,8 @@ export default function Document() { name="robots" content={process.env.NEXT_PUBLIC_BUILD_TARGET == "alpha" ? "noindex" : "all"} /> + + Date: Sat, 9 Mar 2024 17:07:01 +0300 Subject: [PATCH 010/192] invalid input animation --- web/src/styles/globals.css | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/web/src/styles/globals.css b/web/src/styles/globals.css index 0ae9321a..09da2e44 100644 --- a/web/src/styles/globals.css +++ b/web/src/styles/globals.css @@ -73,19 +73,33 @@ input:-moz-placeholder { /* Firefox 18- */ .inputError { border-color: darkred; + transition: all 0.5s ease-out; +} + +.inputError:focus-visible { + border-color: darkred; + outline: none; } .inputError::-webkit-input-placeholder { color: darkred; + transition: all 0.5s ease-out; + } .inputError::-moz-placeholder { color: darkred; + transition: all 1s ease-out; + } .inputError:-ms-input-placeholder { color: darkred; + transition: all 1s ease-out; + } .inputError:-moz-placeholder { color: darkred; + transition: all 1s ease-out; + } @media (prefers-color-scheme: dark) { From 29ee5de8c05a8a241d521d0cce82dba6d977f992 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Sat, 9 Mar 2024 17:07:28 +0300 Subject: [PATCH 011/192] login by default --- web/src/components/TitleScreen.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/TitleScreen.tsx b/web/src/components/TitleScreen.tsx index a9033bc6..cb808756 100644 --- a/web/src/components/TitleScreen.tsx +++ b/web/src/components/TitleScreen.tsx @@ -11,7 +11,7 @@ import LoginForm from "./account/LoginForm"; import { FULLCOUNT_ASSETS_PATH } from "../constants"; const TitleScreen = () => { const { user } = useUser(); - const [isLogging, setIsLogging] = useState(false); // login or signUp + const [isLogging, setIsLogging] = useState(true); // login or signUp const [isSuccess, setIsSuccess] = useState(false); return ( From 2745e95d4d17b80af2bde1691f1d2cec75f47fff Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Sun, 10 Mar 2024 16:06:46 +0300 Subject: [PATCH 012/192] moving token query up --- .../sessions/SessionsView.module.css | 18 +++++ web/src/components/sessions/SessionsView.tsx | 77 +++++++++++++------ web/src/components/tokens/OwnedTokens.tsx | 38 ++++----- 3 files changed, 87 insertions(+), 46 deletions(-) diff --git a/web/src/components/sessions/SessionsView.module.css b/web/src/components/sessions/SessionsView.module.css index 940a4ae4..727abbff 100644 --- a/web/src/components/sessions/SessionsView.module.css +++ b/web/src/components/sessions/SessionsView.module.css @@ -62,4 +62,22 @@ line-height: 100%; /* 24px */ } +.suspend { + width: 100%; + height: 100%; + overflow: hidden; +} + +.suspendImage { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center; +} + +.fadeOut { + opacity: 0; + transition: opacity 1s ease-out; +} + diff --git a/web/src/components/sessions/SessionsView.tsx b/web/src/components/sessions/SessionsView.tsx index 19374485..56bc7c6e 100644 --- a/web/src/components/sessions/SessionsView.tsx +++ b/web/src/components/sessions/SessionsView.tsx @@ -13,10 +13,16 @@ import InviteView from "./InviteView"; import OwnedTokens from "../tokens/OwnedTokens"; import styles from "./SessionsView.module.css"; -import { FullcountContractSession, Session, Token } from "../../types"; +import { FullcountContractSession, OwnedToken, Session, Token } from "../../types"; import { getAtBatOutputs, outputs } from "../../web3/abi/ABIITems"; import { getContracts } from "../../utils/getWeb3Contracts"; +import Image from "next/image"; +import { FULLCOUNT_ASSETS_PATH } from "../../constants"; +import { fetchOwnedBLBTokens } from "../../tokenInterfaces/BLBTokenAPI"; +import { fetchFullcountPlayerTokens } from "../../tokenInterfaces/FullcountPlayerAPI"; +import queryCacheProps from "../../hooks/hookCommon"; +import useUser from "../../contexts/UserContext"; const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; @@ -29,6 +35,7 @@ const SessionsView = () => { const router = useRouter(); const { isOpen, onOpen, onClose } = useDisclosure(); + const { user } = useUser(); useEffect(() => { if (router.query.invitedBy && router.query.session) { @@ -237,31 +244,57 @@ const SessionsView = () => { return Array.from(uniqueAtBatIDArray.values()); }; + const ownedTokens = useQuery( + ["owned_tokens", web3ctx.account, user], + async () => { + console.log("FETCHING TOKENS"); + const BLBTokens = user ? [] : await fetchOwnedBLBTokens({ web3ctx }); + const fullcountPlayerTokens = user ? await fetchFullcountPlayerTokens({ web3ctx }) : []; + const ownedTokens = BLBTokens.concat(fullcountPlayerTokens); + updateContext({ ownedTokens: [...ownedTokens] }); + return ownedTokens; + }, + { + ...queryCacheProps, + refetchInterval: 3000, + }, + ); + return ( - - - - - - - + <> + {!ownedTokens.data ? ( +
+ ) : ( + + {ownedTokens.data && ( + + + + + + + )} - - {sessions.data && ( - - {sessions.data.map((session, idx) => ( - - {progressFilter[session.progress] && ( - <> - - {idx + 1 < sessions.data.length && } - - )} - - ))} + + {sessions.data && ( + + {sessions.data.map((session, idx) => ( + + {progressFilter[session.progress] && ( + <> + + {idx + 1 < sessions.data.length && ( + + )} + + )} + + ))} + + )} )} - + ); }; diff --git a/web/src/components/tokens/OwnedTokens.tsx b/web/src/components/tokens/OwnedTokens.tsx index 2d0cad17..f6644bae 100644 --- a/web/src/components/tokens/OwnedTokens.tsx +++ b/web/src/components/tokens/OwnedTokens.tsx @@ -47,7 +47,13 @@ const TokenABI = TokenABIImported as unknown as AbiItem[]; const assets = FULLCOUNT_ASSETS_PATH; -const OwnedTokens = ({ forJoin = false }: { forJoin?: boolean }) => { +const OwnedTokens = ({ + forJoin = false, + ownedTokens, +}: { + forJoin?: boolean; + ownedTokens: OwnedToken[]; +}) => { const web3ctx = useContext(Web3Context); const { tokenAddress, @@ -91,22 +97,6 @@ const OwnedTokens = ({ forJoin = false }: { forJoin?: boolean }) => { }, ); - const ownedTokens = useQuery( - ["owned_tokens", web3ctx.account, user], - async () => { - console.log("FETCHING TOKENS"); - const BLBTokens = user ? [] : await fetchOwnedBLBTokens({ web3ctx }); - const fullcountPlayerTokens = user ? await fetchFullcountPlayerTokens({ web3ctx }) : []; - const ownedTokens = BLBTokens.concat(fullcountPlayerTokens); - updateContext({ ownedTokens: [...ownedTokens] }); - return ownedTokens; - }, - { - ...queryCacheProps, - refetchInterval: 3000, - }, - ); - const startSession = useMutation( async ({ role, @@ -313,17 +303,17 @@ const OwnedTokens = ({ forJoin = false }: { forJoin?: boolean }) => { ); useEffect(() => { - if (!selectedToken || !ownedTokens.data) return; - const newSelectedToken = ownedTokens.data.find( + if (!selectedToken || !ownedTokens) return; + const newSelectedToken = ownedTokens.find( (t) => t.address === selectedToken.address && t.id === selectedToken.id, ); updateContext({ selectedToken: newSelectedToken }); - }, [ownedTokens.data]); + }, [ownedTokens]); return ( <> - {(user || web3ctx.account) && ownedTokens.data && ownedTokens.data.length < 1 && ( + {(user || web3ctx.account) && ownedTokens && ownedTokens.length < 1 && ( <> { )} - {ownedTokens.data && - ownedTokens.data + {ownedTokens && + ownedTokens .filter((t) => !forJoin || !t.isStaked) .map((token: OwnedToken, idx: number) => ( @@ -498,7 +488,7 @@ const OwnedTokens = ({ forJoin = false }: { forJoin?: boolean }) => { )} ))} - {ownedTokens.data && ownedTokens.data.length > 0 && ( + {ownedTokens && ownedTokens.length > 0 && ( Date: Mon, 11 Mar 2024 12:45:29 +0300 Subject: [PATCH 013/192] plug out web3ctx --- web/src/tokenInterfaces/BLBTokenAPI.ts | 35 +++++++------------ web/src/tokenInterfaces/FullcountPlayerAPI.ts | 8 +---- web/src/types.d.ts | 2 +- web/src/utils/getWeb3Contracts.ts | 6 ++-- web/src/utils/multicall.ts | 9 ++--- 5 files changed, 22 insertions(+), 38 deletions(-) diff --git a/web/src/tokenInterfaces/BLBTokenAPI.ts b/web/src/tokenInterfaces/BLBTokenAPI.ts index bc666ead..8dff6460 100644 --- a/web/src/tokenInterfaces/BLBTokenAPI.ts +++ b/web/src/tokenInterfaces/BLBTokenAPI.ts @@ -22,7 +22,7 @@ export const fetchOwnedBLBTokens = async ({ return []; } try { - const { tokenContract } = getContracts(web3ctx); + const { tokenContract } = getContracts(); const balanceOf = await tokenContract.methods.balanceOf(web3ctx.account).call(); const tokensQueries = []; for (let i = 0; i < balanceOf; i += 1) { @@ -32,14 +32,8 @@ export const fetchOwnedBLBTokens = async ({ }); } - const [tokens] = await getMulticallResults( - web3ctx, - TokenABI, - ["tokenOfOwnerByIndex"], - tokensQueries, - ); + const [tokens] = await getMulticallResults(TokenABI, ["tokenOfOwnerByIndex"], tokensQueries); return await getTokensData({ - web3ctx, tokens: tokens.map((t) => ({ id: t, address: TOKEN_CONTRACT })), tokensSource: "BLBContract", }); @@ -50,21 +44,18 @@ export const fetchOwnedBLBTokens = async ({ }; export const getTokensData = async ({ - web3ctx, tokens, tokensSource, }: { - web3ctx: MoonstreamWeb3ProviderInterface; tokens: TokenId[]; tokensSource: TokenSource; }) => { - const { tokenContract, gameContract } = getContracts(web3ctx); + const { tokenContract, gameContract } = getContracts(); const stakedQueries = tokens.map((t) => ({ target: gameContract.options.address, callData: gameContract.methods.StakedSession(t.address, t.id).encodeABI(), })); const [stakedSessions] = await getMulticallResults( - web3ctx, FullcountABI, ["StakedSession"], stakedQueries, @@ -76,7 +67,6 @@ export const getTokensData = async ({ })); const [progresses] = await getMulticallResults( - web3ctx, FullcountABI, ["sessionProgress"], progressQueries, @@ -87,7 +77,7 @@ export const getTokensData = async ({ callData: tokenContract.methods.tokenURI(t.id).encodeABI(), })); - const [uris] = await getMulticallResults(web3ctx, TokenABI, ["tokenURI"], uriQueries); + const [uris] = await getMulticallResults(TokenABI, ["tokenURI"], uriQueries); const promises = uris.map(async (uri, idx) => { const { name, image } = await getTokenMetadata(uri); @@ -96,7 +86,6 @@ export const getTokensData = async ({ name: name.split(` - ${tokens[idx].id}`)[0], image: image, address: tokenContract.options.address, - staker: tokensSource === "BLBContract" ? web3ctx.account : "", isStaked: stakedSessions[idx] !== "0", stakedSessionID: Number(stakedSessions[idx]), tokenProgress: Number(progresses[idx]), @@ -118,7 +107,7 @@ export const startSessionBLB = ({ role: number; requireSignature: boolean; }): Promise<{ sessionID: string; sign: string | undefined }> => { - const { gameContract } = getContracts(web3ctx); + const { gameContract } = getContracts(); return sendTransactionWithEstimate( web3ctx.account, @@ -146,7 +135,7 @@ export const joinSessionBLB = ({ sessionID: number; inviteCode: string | undefined; }) => { - const { gameContract } = getContracts(web3ctx); + const { gameContract } = getContracts(); return sendTransactionWithEstimate( web3ctx.account, gameContract.methods.joinSession( @@ -164,7 +153,7 @@ export const unstakeBLBToken = ({ web3ctx: MoonstreamWeb3ProviderInterface; token: OwnedToken; }) => { - const { gameContract } = getContracts(web3ctx); + const { gameContract } = getContracts(); if (token.tokenProgress === 2 && token.stakedSessionID) { return sendTransactionWithEstimate( @@ -189,7 +178,7 @@ export const commitSwingBLBToken = ({ sign: string; sessionID: number; }) => { - const { gameContract } = getContracts(web3ctx); + const { gameContract } = getContracts(); return sendTransactionWithEstimate( web3ctx.account, @@ -212,7 +201,7 @@ export const revealSwingBLBToken = ({ horizontal: number; sessionID: number; }) => { - const { gameContract } = getContracts(web3ctx); + const { gameContract } = getContracts(); return sendTransactionWithEstimate( web3ctx.account, gameContract.methods.revealSwing(sessionID, nonce, actionChoice, vertical, horizontal), @@ -228,7 +217,7 @@ export const commitPitchBLBToken = ({ sign: string; sessionID: number; }) => { - const { gameContract } = getContracts(web3ctx); + const { gameContract } = getContracts(); return sendTransactionWithEstimate( web3ctx.account, @@ -251,7 +240,7 @@ export const revealPitchBLBToken = ({ horizontal: number; sessionID: number; }) => { - const { gameContract } = getContracts(web3ctx); + const { gameContract } = getContracts(); return sendTransactionWithEstimate( web3ctx.account, gameContract.methods.revealPitch(sessionID, nonce, actionChoice, vertical, horizontal), @@ -267,6 +256,6 @@ export const mintBLBToken = ({ name: string; imageIndex: number; }) => { - const { tokenContract } = getContracts(web3ctx); + const { tokenContract } = getContracts(); return sendTransactionWithEstimate(web3ctx.account, tokenContract.methods.mint(name, imageIndex)); }; diff --git a/web/src/tokenInterfaces/FullcountPlayerAPI.ts b/web/src/tokenInterfaces/FullcountPlayerAPI.ts index ba78527a..522cf740 100644 --- a/web/src/tokenInterfaces/FullcountPlayerAPI.ts +++ b/web/src/tokenInterfaces/FullcountPlayerAPI.ts @@ -2,14 +2,9 @@ import { OwnedToken, Token } from "../types"; import { FULLCOUNT_PLAYER_API, GAME_CONTRACT, RPC } from "../constants"; import axios from "axios"; import { getTokensData } from "./BLBTokenAPI"; -import { MoonstreamWeb3ProviderInterface } from "../types/Moonstream"; import Web3 from "web3"; -export async function fetchFullcountPlayerTokens({ - web3ctx, -}: { - web3ctx: MoonstreamWeb3ProviderInterface; -}) { +export async function fetchFullcountPlayerTokens() { try { const headers = getHeaders(); const res = await axios.get(`${FULLCOUNT_PLAYER_API}/nfts`, { @@ -25,7 +20,6 @@ export async function fetchFullcountPlayerTokens({ })); return await getTokensData({ - web3ctx, tokens, tokensSource: "FullcountPlayerAPI", }); diff --git a/web/src/types.d.ts b/web/src/types.d.ts index f18cef1b..795ce37b 100644 --- a/web/src/types.d.ts +++ b/web/src/types.d.ts @@ -61,7 +61,7 @@ interface Token { id: string; name: string; image: string; - staker: string; + staker?: string; source?: TokenSource; } diff --git a/web/src/utils/getWeb3Contracts.ts b/web/src/utils/getWeb3Contracts.ts index 051b959a..ae033a76 100644 --- a/web/src/utils/getWeb3Contracts.ts +++ b/web/src/utils/getWeb3Contracts.ts @@ -18,8 +18,8 @@ const FullcountABI = FullcountABIImported as unknown as AbiItem[]; const TokenABI = TokenABIImported as unknown as AbiItem[]; const MulticallABI = MulticallABIImported as unknown as AbiItem[]; -export const getContracts = (web3ctx: MoonstreamWeb3ProviderInterface) => { - const { web3 } = web3ctx; +export const getContracts = () => { + const web3 = new Web3(RPC); const gameContract = new web3.eth.Contract(FullcountABI) as unknown as FullcountContract; gameContract.options.address = GAME_CONTRACT; const tokenContract = new web3.eth.Contract(TokenABI); @@ -34,7 +34,7 @@ export const getContracts = (web3ctx: MoonstreamWeb3ProviderInterface) => { return { gameContract, tokenContract, multicallContract }; }; -export const getMulticallContract = (web3ctx: MoonstreamWeb3ProviderInterface) => { +export const getMulticallContract = () => { const web3 = new Web3(RPC); const MULTICALL2_CONTRACT_ADDRESS = MULTICALL2_CONTRACT_ADDRESSES[String(CHAIN_ID) as keyof typeof MULTICALL2_CONTRACT_ADDRESSES]; diff --git a/web/src/utils/multicall.ts b/web/src/utils/multicall.ts index 7be4b76a..63496b10 100644 --- a/web/src/utils/multicall.ts +++ b/web/src/utils/multicall.ts @@ -1,9 +1,9 @@ -import { MoonstreamWeb3ProviderInterface } from "../types/Moonstream"; +import Web3 from "web3"; + import { AbiItem } from "web3-utils"; import { getMulticallContract } from "./getWeb3Contracts"; export async function getMulticallResults( - web3ctx: MoonstreamWeb3ProviderInterface, ABI: AbiItem[], functionNames: string[], queries: { target: string; callData: string }[], @@ -16,10 +16,11 @@ export async function getMulticallResults( return result; } - const multicallContract = getMulticallContract(web3ctx); + const multicallContract = getMulticallContract(); const result = []; const response = await multicallContract.methods.tryAggregate(false, queries).call(); const splitResponses = splitArray(response, functionNames.length); + const web3 = new Web3(); for (let i = 0; i < functionNames.length; i++) { const functionName = functionNames[i]; @@ -33,7 +34,7 @@ export async function getMulticallResults( if (result === undefined) { return undefined; } - const decoded = web3ctx.web3.eth.abi.decodeParameters(outputs, result); + const decoded = web3.eth.abi.decodeParameters(outputs, result); if (outputs.length === 1 && outputs[0].type !== "tuple") { // If the output is a primitive type, return the primitive value return decoded[Object.keys(decoded)[0]]; // Extract the first (and only) parameter From 139ec81f95a0d69a1b4ed18df6327224836d44c4 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Mon, 11 Mar 2024 12:45:48 +0300 Subject: [PATCH 014/192] next config for blb images --- web/next.config.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/next.config.js b/web/next.config.js index d1264ada..63d834aa 100644 --- a/web/next.config.js +++ b/web/next.config.js @@ -10,6 +10,12 @@ const nextConfig = { port: "", pathname: "/fullcount/**", }, + { + protocol: "https", + hostname: "badges.moonstream.to", + port: "", + pathname: "/blb/**", + }, ], }, }; From 7b21c24db41b1dc0ab1d3b9a8b71f54b4409f772 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Mon, 11 Mar 2024 12:48:49 +0300 Subject: [PATCH 015/192] CreateCharacter form --- .../components/tokens/CreateCharacterForm.tsx | 106 +++++++++++++++++ .../tokens/CreateNewCharacter.module.css | 110 +++++++----------- web/src/styles/globals.css | 12 ++ 3 files changed, 157 insertions(+), 71 deletions(-) create mode 100644 web/src/components/tokens/CreateCharacterForm.tsx diff --git a/web/src/components/tokens/CreateCharacterForm.tsx b/web/src/components/tokens/CreateCharacterForm.tsx new file mode 100644 index 00000000..a7b97738 --- /dev/null +++ b/web/src/components/tokens/CreateCharacterForm.tsx @@ -0,0 +1,106 @@ +import { Flex } from "@chakra-ui/react"; +import Image from "next/image"; + +import styles from "./CreateNewCharacter.module.css"; +import React, { useState } from "react"; +import { TokenSource } from "../../types"; +import { useMutation, useQueryClient } from "react-query"; +import { mintFullcountPlayerToken } from "../../tokenInterfaces/FullcountPlayerAPI"; +import useMoonToast from "../../hooks/useMoonToast"; +const NUMBER_OF_IMAGES = 8; + +const images: number[] = []; +for (let i = 0; i < NUMBER_OF_IMAGES; i += 1) { + images.push(i); +} + +const CreateCharacterForm = () => { + const [name, setName] = useState(""); + const [imageIndex, setImageIndex] = useState(0); + const source: TokenSource = "FullcountPlayerAPI"; + const queryClient = useQueryClient(); + const toast = useMoonToast(); + + const mintToken = useMutation( + async ({ name, imageIndex, source }: { name: string; imageIndex: number; source: string }) => { + switch (source) { + case "FullcountPlayerAPI": + return mintFullcountPlayerToken({ name, imageIndex }); + default: + return Promise.reject(new Error(`Unknown or unsupported token source: ${source}`)); + } + }, + { + onSuccess: () => { + queryClient.invalidateQueries("owned_tokens"); //TODO data update + }, + onError: (e: Error) => { + console.log(e); + toast("Minting failed: " + e?.message, "error"); + }, + }, + ); + + // useEffect(() => { + // setName(""); + // setImageIndex(-1); + // }, []); + + const handleKeyDown = (event: React.KeyboardEvent) => { + if (event.key === "Enter") { + mintToken.mutate({ name, imageIndex, source }); + } + }; + return ( +
+
Create character
+ +
+ {""} +
+ {images.map((_, idx: number) => ( + {`img${idx}`} setImageIndex(idx)} + /> + ))} +
+
Choose an image.
+ + setName(e.target.value)} + onKeyDown={handleKeyDown} + /> +
+ + {/**/} + + +
+ ); +}; + +export default CreateCharacterForm; diff --git a/web/src/components/tokens/CreateNewCharacter.module.css b/web/src/components/tokens/CreateNewCharacter.module.css index 4d4eb3aa..2ff0c1a8 100644 --- a/web/src/components/tokens/CreateNewCharacter.module.css +++ b/web/src/components/tokens/CreateNewCharacter.module.css @@ -1,96 +1,64 @@ .container { display: flex; - max-width: 650px; - padding: 40px; + width: 100%; + min-height: 100vh; + padding: 20px; flex-direction: column; justify-content: center; align-items: center; - gap: 40px; - border: 1px solid #4D4D4D; - background: rgba(41, 41, 41, 0.70); -} -.message { - color: #FFF; - font-family: Inter; - font-size: 30px; - font-style: normal; - font-weight: 700; - line-height: normal; -} -.text { - color: #BFBFBF; - text-align: center; - font-family: Inter; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: normal; + gap: 20px; + background: #FCECD9; } -.label { - color: #FFF; - font-family: Inter; - font-size: 14px; +.header { + color: #262019; + text-align: center; + font-family: Bangers, cursive; + font-size: 30px; font-style: normal; font-weight: 400; - line-height: normal; + line-height: 100%; /* 30px */ + letter-spacing: 1.5px; } -.input { +.content { display: flex; - padding: 10px 15px; + flex-direction: column; align-items: center; - gap: 10px; - flex: 1 0 0; + gap: 15px; align-self: stretch; - /*border-radius: 10px;*/ - border: 1px solid #4D4D4D; - background-color: #1A1D22; - color: #FFF; - font-size: 16px; - font-style: normal; - font-weight: 400; - line-height: 140%; /* 22.4px */ } -.input:focus-visible { - outline: none; -} -.input::placeholder { - color: #BFBFBF; -} - -.buttons { - display: flex; - align-items: flex-start; - gap: 20px; - width: 100%; -} - -.cancelButton { +.images { display: flex; - padding: 10px 40px; + flex-wrap: wrap; + gap: 15px; + row-gap: 15px; + max-width: 280px; justify-content: center; - align-items: center; - gap: 10px; - flex: 1 0 0; - border: 1px solid #FFF; } -.saveButton { - display: flex; - padding: 10px 40px; - justify-content: center; - align-items: center; - gap: 10px; - flex: 1 0 0; - border: 1px solid #F1E3BF; - background: #00A341; +.image, .selectedImage { + border: 0.5px solid #7E8E7F; + background: lightgray 50% / cover no-repeat; + cursor: pointer; } +.selectedImage { + border: 4px solid #328449; +} +.hint { + margin-top: -5px; + color: #7E8E7F; + text-align: center; + font-family: Pangolin, cursive; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; +} -.saveButton:disabled { - cursor: not-allowed; - opacity: 0.5; +.label { + margin-bottom: -10px; } \ No newline at end of file diff --git a/web/src/styles/globals.css b/web/src/styles/globals.css index 09da2e44..f91940b7 100644 --- a/web/src/styles/globals.css +++ b/web/src/styles/globals.css @@ -102,6 +102,18 @@ input:-moz-placeholder { /* Firefox 18- */ } +label { + color: #262019; + font-family: Pangolin, cursive; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; + text-align: start; + place-self: start; + margin-bottom: 5px; +} + @media (prefers-color-scheme: dark) { :root { --foreground-rgb: 255, 255, 255; From 4f75408fae7eae5922933fe43ef17d9bd1143ffd Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Mon, 11 Mar 2024 12:54:30 +0300 Subject: [PATCH 016/192] moving tokens query up --- web/src/components/Playing.tsx | 35 +++++++++++++++++--- web/src/components/sessions/SessionsView.tsx | 32 +++--------------- 2 files changed, 36 insertions(+), 31 deletions(-) diff --git a/web/src/components/Playing.tsx b/web/src/components/Playing.tsx index cb6bd993..70ac3a4f 100644 --- a/web/src/components/Playing.tsx +++ b/web/src/components/Playing.tsx @@ -4,18 +4,45 @@ import { useGameContext } from "../contexts/GameContext"; import SessionsView from "./sessions/SessionsView"; import PlayView from "./playing/PlayView"; import styles from "./Playing.module.css"; +import { useQuery } from "react-query"; +import { OwnedToken } from "../types"; +import { fetchOwnedBLBTokens } from "../tokenInterfaces/BLBTokenAPI"; +import { fetchFullcountPlayerTokens } from "../tokenInterfaces/FullcountPlayerAPI"; +import queryCacheProps from "../hooks/hookCommon"; +import useUser from "../contexts/UserContext"; +import CreateCharacterForm from "./tokens/CreateCharacterForm"; const Playing = () => { - const { selectedSession, selectedToken, watchingToken } = useGameContext(); + const { selectedSession, selectedToken, watchingToken, updateContext } = useGameContext(); + const { user } = useUser(); + + const ownedTokens = useQuery( + ["owned_tokens", user], + async () => { + console.log("FETCHING TOKENS"); + const ownedTokens = user ? await fetchFullcountPlayerTokens() : []; + updateContext({ ownedTokens: [...ownedTokens] }); + return ownedTokens; + }, + { + ...queryCacheProps, + refetchInterval: 15000, + }, + ); return ( - - {!selectedSession && } + // + <> + {ownedTokens.data && ownedTokens.data.length < 5 && } + {!selectedSession && ownedTokens.data && ownedTokens.data.length > 4 && ( + + )} {selectedSession && watchingToken && } {selectedSession && !watchingToken && selectedToken && ( )} - + + // ); }; diff --git a/web/src/components/sessions/SessionsView.tsx b/web/src/components/sessions/SessionsView.tsx index 56bc7c6e..ca3bca75 100644 --- a/web/src/components/sessions/SessionsView.tsx +++ b/web/src/components/sessions/SessionsView.tsx @@ -17,25 +17,19 @@ import { FullcountContractSession, OwnedToken, Session, Token } from "../../type import { getAtBatOutputs, outputs } from "../../web3/abi/ABIITems"; import { getContracts } from "../../utils/getWeb3Contracts"; -import Image from "next/image"; -import { FULLCOUNT_ASSETS_PATH } from "../../constants"; -import { fetchOwnedBLBTokens } from "../../tokenInterfaces/BLBTokenAPI"; -import { fetchFullcountPlayerTokens } from "../../tokenInterfaces/FullcountPlayerAPI"; -import queryCacheProps from "../../hooks/hookCommon"; import useUser from "../../contexts/UserContext"; const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; -const SessionsView = () => { +const SessionsView = ({ ownedTokens }: { ownedTokens: OwnedToken[] }) => { const { updateContext, contractAddress, progressFilter, tokensCache, sessionOffset } = useGameContext(); const web3ctx = useContext(Web3Context); - const { gameContract, tokenContract, multicallContract } = getContracts(web3ctx); + const { gameContract, tokenContract, multicallContract } = getContracts(); const router = useRouter(); const { isOpen, onOpen, onClose } = useDisclosure(); - const { user } = useUser(); useEffect(() => { if (router.query.invitedBy && router.query.session) { @@ -244,33 +238,17 @@ const SessionsView = () => { return Array.from(uniqueAtBatIDArray.values()); }; - const ownedTokens = useQuery( - ["owned_tokens", web3ctx.account, user], - async () => { - console.log("FETCHING TOKENS"); - const BLBTokens = user ? [] : await fetchOwnedBLBTokens({ web3ctx }); - const fullcountPlayerTokens = user ? await fetchFullcountPlayerTokens({ web3ctx }) : []; - const ownedTokens = BLBTokens.concat(fullcountPlayerTokens); - updateContext({ ownedTokens: [...ownedTokens] }); - return ownedTokens; - }, - { - ...queryCacheProps, - refetchInterval: 3000, - }, - ); - return ( <> - {!ownedTokens.data ? ( + {!ownedTokens ? (
) : ( - {ownedTokens.data && ( + {ownedTokens && ( - + )} From bcb0dc3cc93b628b7e42a1122534d9e1044e9c2f Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Mon, 11 Mar 2024 12:54:42 +0300 Subject: [PATCH 017/192] changing layout --- web/src/components/TitleScreen.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/web/src/components/TitleScreen.tsx b/web/src/components/TitleScreen.tsx index cb808756..71971065 100644 --- a/web/src/components/TitleScreen.tsx +++ b/web/src/components/TitleScreen.tsx @@ -17,9 +17,7 @@ const TitleScreen = () => { return ( <> {user ? ( - - - + ) : (
Date: Mon, 11 Mar 2024 13:44:56 +0300 Subject: [PATCH 018/192] style --- web/src/components/account/LoginForm.tsx | 4 ++++ web/src/components/account/SignUpForm.tsx | 7 +++++++ web/src/styles/globals.css | 1 - 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/web/src/components/account/LoginForm.tsx b/web/src/components/account/LoginForm.tsx index b2145ef0..2e503e98 100644 --- a/web/src/components/account/LoginForm.tsx +++ b/web/src/components/account/LoginForm.tsx @@ -38,6 +38,8 @@ const LoginForm = ({ setIsSuccess }: { setIsSuccess: (isSuccess: boolean) => voi name="username" value={username} className={showInvalid && !isUsernameValid ? "inputError" : ""} + style={{ marginBottom: "10px" }} + spellCheck={false} onChange={(event) => { setShowInvalid(false); setUsername(event.target.value); @@ -50,6 +52,8 @@ const LoginForm = ({ setIsSuccess }: { setIsSuccess: (isSuccess: boolean) => voi value={password} name="password" className={showInvalid && !isPasswordValid ? "inputError" : ""} + style={{ marginBottom: "10px" }} + spellCheck={false} onChange={(event) => { setShowInvalid(false); setPassword(event.target.value); diff --git a/web/src/components/account/SignUpForm.tsx b/web/src/components/account/SignUpForm.tsx index 1300f11d..03fdbd73 100644 --- a/web/src/components/account/SignUpForm.tsx +++ b/web/src/components/account/SignUpForm.tsx @@ -41,7 +41,10 @@ const SignUpForm = ({ setIsSuccess }: { setIsSuccess: (isSuccess: boolean) => vo value={username} className={showErrors && !username ? "inputError" : ""} onChange={(event) => setUsername(event.target.value)} + style={{ marginBottom: "10px" }} + spellCheck={false} /> +
Email
vo name="email" value={email} className={showErrors && !email ? "inputError" : ""} + style={{ marginBottom: "10px" }} onChange={(event) => setEmail(event.target.value)} + spellCheck={false} />
Password
@@ -59,7 +64,9 @@ const SignUpForm = ({ setIsSuccess }: { setIsSuccess: (isSuccess: boolean) => vo value={password} name="password" className={showErrors && !password ? "inputError" : ""} + style={{ marginBottom: "10px" }} onChange={(event) => setPassword(event.target.value)} + spellCheck={false} />
*/} +
+ {onClose && ( + + )} - +
); }; diff --git a/web/src/components/tokens/CreateNewCharacter.module.css b/web/src/components/tokens/CreateNewCharacter.module.css index 2ff0c1a8..3b04ae42 100644 --- a/web/src/components/tokens/CreateNewCharacter.module.css +++ b/web/src/components/tokens/CreateNewCharacter.module.css @@ -61,4 +61,56 @@ .label { margin-bottom: -10px; +} + +.buttonsContainer { + display: flex; + justify-content: center; + align-items: flex-start; + gap: 10px; + align-self: stretch; +} + +.button, .inactiveButton { + display: flex; + padding: 4px 19px; + justify-content: center; + align-items: center; + gap: 10px; + align-self: stretch; + border: 1px solid #262019; + background: #328449; + flex: 1 0 0; + color: #FFF; + text-align: center; + font-family: Bangers, cursive; + font-size: 24px; + font-style: normal; + font-weight: 400; + line-height: normal; + letter-spacing: 1.2px; + min-height: 35.5px; +} + +.inactiveButton { + background: #4D4D4D; +} + +.cancelButton { + display: flex; + padding: 5px 20px; + justify-content: center; + align-items: center; + gap: 10px; + flex: 1 0 0; + align-self: stretch; + border: 1px solid #262019; + color: #262019; + text-align: center; + font-family: Bangers, cursive; + font-size: 24px; + font-style: normal; + font-weight: 400; + line-height: normal; + letter-spacing: 1.2px; } \ No newline at end of file From 8c7c860146e08509288155f94a1a491ca75fd4ef Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Mon, 11 Mar 2024 15:09:54 +0300 Subject: [PATCH 020/192] adding icons --- web/src/components/icons/AccountMobile.tsx | 27 ++++++++++++++ .../components/icons/FullcountLogoSmall.tsx | 32 +++++++++++++++++ web/src/components/icons/MoreHorizontal.tsx | 36 +++++++++++++++++++ web/src/components/icons/VolumeOn.tsx | 33 +++++++++++++++++ 4 files changed, 128 insertions(+) create mode 100644 web/src/components/icons/AccountMobile.tsx create mode 100644 web/src/components/icons/FullcountLogoSmall.tsx create mode 100644 web/src/components/icons/MoreHorizontal.tsx create mode 100644 web/src/components/icons/VolumeOn.tsx diff --git a/web/src/components/icons/AccountMobile.tsx b/web/src/components/icons/AccountMobile.tsx new file mode 100644 index 00000000..ca0857b4 --- /dev/null +++ b/web/src/components/icons/AccountMobile.tsx @@ -0,0 +1,27 @@ +import React from "react"; + +const AccountMobile: React.FC> = (props) => ( + + + + +); + +export default AccountMobile; diff --git a/web/src/components/icons/FullcountLogoSmall.tsx b/web/src/components/icons/FullcountLogoSmall.tsx new file mode 100644 index 00000000..6be31776 --- /dev/null +++ b/web/src/components/icons/FullcountLogoSmall.tsx @@ -0,0 +1,32 @@ +import React from "react"; + +const FullcountLogoSmall: React.FC> = (props) => ( + + + + + + + + + +); + +export default FullcountLogoSmall; diff --git a/web/src/components/icons/MoreHorizontal.tsx b/web/src/components/icons/MoreHorizontal.tsx new file mode 100644 index 00000000..89ee87db --- /dev/null +++ b/web/src/components/icons/MoreHorizontal.tsx @@ -0,0 +1,36 @@ +import React from "react"; + +const MoreHorizontal: React.FC> = (props) => ( + + + + + +); + +export default MoreHorizontal; diff --git a/web/src/components/icons/VolumeOn.tsx b/web/src/components/icons/VolumeOn.tsx new file mode 100644 index 00000000..47bea617 --- /dev/null +++ b/web/src/components/icons/VolumeOn.tsx @@ -0,0 +1,33 @@ +import React from "react"; + +const VolumeOn: React.FC> = (props) => ( + + + + + +); + +export default VolumeOn; From f24872fe43f9f8027ef213893f1f91204c70555e Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Mon, 11 Mar 2024 15:10:10 +0300 Subject: [PATCH 021/192] Loading indicator --- .../components/LoadingIndicator.module.css | 20 +++++++++++++++++++ web/src/components/LoadingIndicator.tsx | 15 ++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 web/src/components/LoadingIndicator.module.css create mode 100644 web/src/components/LoadingIndicator.tsx diff --git a/web/src/components/LoadingIndicator.module.css b/web/src/components/LoadingIndicator.module.css new file mode 100644 index 00000000..1733393e --- /dev/null +++ b/web/src/components/LoadingIndicator.module.css @@ -0,0 +1,20 @@ +.imageRow { + display: flex; + gap: 4px; +} + +@keyframes scaleAnimation { + 0%, 100% { transform: scale(0.3); } + /*40% {transform: scale(0.7);}*/ + 50% { transform: scale(1); } +} + +.animatedImage { + width: 15px; /* Set this to your desired width */ + height: auto; /* Maintain aspect ratio */ + animation: scaleAnimation 1s infinite; /* Change 5s to whatever duration you prefer */ +} + +.image1 { animation-delay: 0s; transform: scale(0.2); } +.image2 { animation-delay: 0.2s; transform: scale(0.2); } +.image3 { animation-delay: 0.5s; transform: scale(0.2); } diff --git a/web/src/components/LoadingIndicator.tsx b/web/src/components/LoadingIndicator.tsx new file mode 100644 index 00000000..23412f79 --- /dev/null +++ b/web/src/components/LoadingIndicator.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import styles from "./LoadingIndicator.module.css"; +import { FULLCOUNT_ASSETS_PATH } from "../constants"; +const src = `${FULLCOUNT_ASSETS_PATH}/ball2.png`; +const LoadingIndicator = () => { + return ( +
+ o + o + o +
+ ); +}; + +export default LoadingIndicator; From 9fab411c66b49d4a634782bdaf66eb2c689e6dbf Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Mon, 11 Mar 2024 15:16:18 +0300 Subject: [PATCH 022/192] new Navbar --- web/src/components/layout/Navbar.module.css | 83 +++++++++++++++++++ web/src/components/layout/Navbar.tsx | 89 +++++++++------------ 2 files changed, 123 insertions(+), 49 deletions(-) create mode 100644 web/src/components/layout/Navbar.module.css diff --git a/web/src/components/layout/Navbar.module.css b/web/src/components/layout/Navbar.module.css new file mode 100644 index 00000000..5a95943c --- /dev/null +++ b/web/src/components/layout/Navbar.module.css @@ -0,0 +1,83 @@ +.container { + display: flex; + padding: 0px 0px 5px 0px; + justify-content: space-between; + align-items: center; + align-self: stretch; +} + +.rightSide { + display: flex; + align-items: center; + gap: 5px; +} + +.account { + display: flex; + padding: 5px 10px 5px 5px; + align-items: center; + gap: 5px; + align-self: stretch; + border: 1px solid #7E8E7F; + background: #FFF; +} + +.username { + overflow: hidden; + color: #262019; + text-overflow: ellipsis; + font-family: Pangolin, cursive; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 100%; +} + +.menu { +position: relative; +} + + +.menuButton { + display: flex; + padding: 5px; + justify-content: center; + align-items: center; + gap: 10px; + border: 1px solid #7E8E7F; + background: #FFF; +} + + +.menuList { + display: flex; + padding: 10px; + flex-direction: column; + align-items: flex-start; + gap: 10px; + border: 1px solid #262019; + background: #FFF; + position: absolute; + right: 0; + margin-top: 5px; +} + +.menuItem { + color: #262019; + font-family: Pangolin, cursive; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 120%; /* 16.8px */ + white-space: nowrap; + cursor: pointer; +} +.menuItem:hover { + font-weight: bold; +} + +.divider { + height: 0.5px; + align-self: stretch; + background: #7E8E7F; +} \ No newline at end of file diff --git a/web/src/components/layout/Navbar.tsx b/web/src/components/layout/Navbar.tsx index 4a690fa2..011bf1fc 100644 --- a/web/src/components/layout/Navbar.tsx +++ b/web/src/components/layout/Navbar.tsx @@ -1,63 +1,54 @@ -import { Flex, useMediaQuery, Text, Link, useDisclosure } from "@chakra-ui/react"; +import { useMediaQuery, useDisclosure } from "@chakra-ui/react"; import Web3Context from "../../contexts/Web3Context/context"; -import { useContext } from "react"; -import styles from "../GlobalStyles.module.css"; -import SoundFxSlider from "./SoundFxSlider"; -import { FEEDBACK_FORM_URL } from "../../constants"; -import About from "./About"; -import Account from "../account/Account"; +import { useContext, useState } from "react"; +import styles from "./Navbar.module.css"; import useUser from "../../contexts/UserContext"; +import FullcountLogoSmall from "../icons/FullcountLogoSmall"; +import AccountMobile from "../icons/AccountMobile"; +import VolumeOn from "../icons/VolumeOn"; +import MoreHorizontal from "../icons/MoreHorizontal"; +import useLogout from "../../hooks/useLogout"; const Navbar = () => { const [isSmallScreen, isMediumScreen] = useMediaQuery([ "(max-width: 767px)", "(min-width: 1024px)", ]); - const { account } = useContext(Web3Context); const { user } = useUser(); - const address = !isMediumScreen ? `${account.slice(0, 6)}...${account.slice(-4)}` : account; - const { onOpen, isOpen, onClose } = useDisclosure(); + const [isMenuOpen, setIsMenuOpen] = useState(false); + const { logout, isLoading: isLoggingOut } = useLogout(); + return ( - - - - Fullcount - - - Give feedback - - - About - - - - - - {address && !user && ( - - - {address} - - - )} - - - +
+ +
+
+ +
{user.username}
+
+
+ +
+
+
setIsMenuOpen(!isMenuOpen)}> + +
+ {isMenuOpen && ( +
+
About
+
Achievements
+
Leaderboards
+
Leave feedback
+
+
logout()}> + {isLoggingOut ? "logging out..." : "Log out"} +
+
+ )} +
+
+
); }; From 9d20f9e4eaba97ef0e27cfacf8958c8cc7dc4fb7 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Mon, 11 Mar 2024 17:01:41 +0300 Subject: [PATCH 023/192] login header --- web/src/components/account/LoginForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/account/LoginForm.tsx b/web/src/components/account/LoginForm.tsx index 2e503e98..dcd21818 100644 --- a/web/src/components/account/LoginForm.tsx +++ b/web/src/components/account/LoginForm.tsx @@ -30,7 +30,7 @@ const LoginForm = ({ setIsSuccess }: { setIsSuccess: (isSuccess: boolean) => voi return (
-
Welcome!
+
Welcome back!
Date: Tue, 12 Mar 2024 15:40:58 +0300 Subject: [PATCH 024/192] New Character Button --- .../tokens/NewCharacterButton.module.css | 27 +++++++++++++++++++ .../components/tokens/NewCharacterButton.tsx | 19 +++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 web/src/components/tokens/NewCharacterButton.module.css create mode 100644 web/src/components/tokens/NewCharacterButton.tsx diff --git a/web/src/components/tokens/NewCharacterButton.module.css b/web/src/components/tokens/NewCharacterButton.module.css new file mode 100644 index 00000000..cb0c56d8 --- /dev/null +++ b/web/src/components/tokens/NewCharacterButton.module.css @@ -0,0 +1,27 @@ +.container { + display: flex; + width: 130px; + height: 170px; + flex-direction: column; + justify-content: center; + align-items: center; + + border: 1.5px solid #328449; + background: rgba(50, 132, 73, 0.15); + color: #328449; + text-align: center; + font-family: Pangolin, cursive; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 120%; /* 16.8px */ +} + +.containerSmall { + display: flex; + width: 50px; + height: 50px; + flex-direction: column; + justify-content: center; + align-items: center; +} \ No newline at end of file diff --git a/web/src/components/tokens/NewCharacterButton.tsx b/web/src/components/tokens/NewCharacterButton.tsx new file mode 100644 index 00000000..39c84a2b --- /dev/null +++ b/web/src/components/tokens/NewCharacterButton.tsx @@ -0,0 +1,19 @@ +import styles from "./NewCharacterButton.module.css"; +import PlusIcon from "../icons/PlusIcon"; +import { useGameContext } from "../../contexts/GameContext"; + +const NewCharacterButton = ({ small }: { small: boolean }) => { + const { updateContext } = useGameContext(); + return ( +
{ + updateContext({ isCreateCharacter: true }); + }} + > + {small ? : "+ Mint new Beer League Baller"} +
+ ); +}; + +export default NewCharacterButton; From 3da6aaed2f5dee8a64adcb3b3b01552ebb8e76ed Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Tue, 12 Mar 2024 15:41:19 +0300 Subject: [PATCH 025/192] plus icon --- web/src/components/icons/PlusIcon.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 web/src/components/icons/PlusIcon.tsx diff --git a/web/src/components/icons/PlusIcon.tsx b/web/src/components/icons/PlusIcon.tsx new file mode 100644 index 00000000..8571126d --- /dev/null +++ b/web/src/components/icons/PlusIcon.tsx @@ -0,0 +1,19 @@ +import React from "react"; + +const PlusIcon: React.FC> = (props) => ( + + + +); + +export default PlusIcon; From bcc26d3340600440d379115255860fba2788c470 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Tue, 12 Mar 2024 15:41:46 +0300 Subject: [PATCH 026/192] token card for choosing --- .../components/tokens/TokenCard.module.css | 34 +++++++++++++++++++ web/src/components/tokens/TokenCard.tsx | 28 +++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 web/src/components/tokens/TokenCard.module.css create mode 100644 web/src/components/tokens/TokenCard.tsx diff --git a/web/src/components/tokens/TokenCard.module.css b/web/src/components/tokens/TokenCard.module.css new file mode 100644 index 00000000..0812ae7f --- /dev/null +++ b/web/src/components/tokens/TokenCard.module.css @@ -0,0 +1,34 @@ +.container, .containerSelected { + display: flex; + height: 170px; + flex-direction: column; + align-items: center; + border: 1px solid #7E8E7F; + background: #262019; +} + + +.containerSelected { + border: 1px solid #262019; + background: #328449; +} + +.image { + width: 130px; + height: 130px; + flex-shrink: 0; +} + +.name, .nameSelected { + display: flex; + height: 100%; + padding: 8px; + align-items: center; + color: #FFF; + text-align: center; + font-family: Bangers, cursive; + font-size: 18px; + font-style: normal; + font-weight: 400; + line-height: 100%; /* 18px */ +} \ No newline at end of file diff --git a/web/src/components/tokens/TokenCard.tsx b/web/src/components/tokens/TokenCard.tsx new file mode 100644 index 00000000..040d5e83 --- /dev/null +++ b/web/src/components/tokens/TokenCard.tsx @@ -0,0 +1,28 @@ +import styles from "./TokenCard.module.css"; +import { OwnedToken } from "../../types"; +import Image from "next/image"; + +const TokenCard = ({ + token, + isSelected, + onSelected, +}: { + token: OwnedToken; + isSelected: boolean; + onSelected: () => void; +}) => { + return ( +
+ {token.name} +
{token.name}
+
+ ); +}; + +export default TokenCard; From 1b24ae7335dfb5d7d5cfb753fa2e0b7302a45975 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Tue, 12 Mar 2024 15:42:47 +0300 Subject: [PATCH 027/192] character creation flag --- web/src/contexts/GameContext.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/src/contexts/GameContext.tsx b/web/src/contexts/GameContext.tsx index 77c35c5a..585d9fe3 100644 --- a/web/src/contexts/GameContext.tsx +++ b/web/src/contexts/GameContext.tsx @@ -25,6 +25,7 @@ interface GameContextProps { sessionOffset: number; soundVolume: number; ownedTokens: OwnedToken[]; + isCreateCharacter: boolean; } interface GameContextType extends GameContextProps { @@ -62,6 +63,7 @@ export const GameContextProvider: FC = ({ children }) => { sessionOffset: 40, soundVolume: 20, ownedTokens: [], + isCreateCharacter: false, }); useEffect(() => { From fc5892d20a82ba157fcae17896896b9d95c1ab57 Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Tue, 12 Mar 2024 15:43:15 +0300 Subject: [PATCH 028/192] choose token form --- .../components/tokens/ChooseToken.module.css | 60 +++++++++++++++++++ web/src/components/tokens/ChooseToken.tsx | 49 +++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 web/src/components/tokens/ChooseToken.module.css create mode 100644 web/src/components/tokens/ChooseToken.tsx diff --git a/web/src/components/tokens/ChooseToken.module.css b/web/src/components/tokens/ChooseToken.module.css new file mode 100644 index 00000000..91d6820d --- /dev/null +++ b/web/src/components/tokens/ChooseToken.module.css @@ -0,0 +1,60 @@ +.container { + display: flex; + height: 100vh; + width: 100vw; + padding: 20px; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 20px; + background: #FCECD9; +} + +.header { + color: #262019; + text-align: center; + font-family: Bangers, cursive; + font-size: 30px; + font-style: normal; + font-weight: 400; + line-height: 100%; /* 30px */ + letter-spacing: 1.5px; +} + +.content { + display: flex; + flex-direction: column; + align-items: center; + gap: 15px; +} + +.title { + color: #262019; + font-family: Bangers, cursive; + font-size: 24px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + +.prompt { + color: #262019; + text-align: center; + font-family: Pangolin, cursive; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: normal; +} + + +.cards { + width: 279px; + display: flex; + justify-content: flex-start; + gap: 15px; + flex-wrap: wrap; + overflow-y: auto; + height: fit-content; + max-height: calc(100vh - 221px); /*console.log(20 + 30 + 20 + 25.5 + 15 + 17.5 + 15 + 20 + 37.5 + 20);*/ +} \ No newline at end of file diff --git a/web/src/components/tokens/ChooseToken.tsx b/web/src/components/tokens/ChooseToken.tsx new file mode 100644 index 00000000..ecd8f5ed --- /dev/null +++ b/web/src/components/tokens/ChooseToken.tsx @@ -0,0 +1,49 @@ +import styles from "./ChooseToken.module.css"; +import parentStyles from "./CreateNewCharacter.module.css"; +import { OwnedToken } from "../../types"; +import TokenCard from "./TokenCard"; +import { useGameContext } from "../../contexts/GameContext"; +import { useState } from "react"; +import NewCharacterButton from "./NewCharacterButton"; + +const ChooseToken = ({ + tokens, + onChoose, + onClose, +}: { + tokens: OwnedToken[]; + onChoose: (token: OwnedToken) => void; + onClose: () => void; +}) => { + const [selectedTokenIdx, setSelectedTokenIdx] = useState(0); + return ( +
+
Choose character
+
+
Play
+
Choose a character to play with.
+
+ {tokens.map((t, idx) => ( + setSelectedTokenIdx(idx)} + /> + ))} + +
+
+
+
+ Cancel +
+
onChoose(tokens[selectedTokenIdx])}> + Play +
+
+
+ ); +}; + +export default ChooseToken; From 0caad7eac32996e1e109eeed0ea1b66f0b54d68b Mon Sep 17 00:00:00 2001 From: Anton Mushnin Date: Tue, 12 Mar 2024 15:45:33 +0300 Subject: [PATCH 029/192] playing layout style --- web/src/components/layout/PlayingLayout.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/src/components/layout/PlayingLayout.tsx b/web/src/components/layout/PlayingLayout.tsx index db5cdd1d..2f3f4cd8 100644 --- a/web/src/components/layout/PlayingLayout.tsx +++ b/web/src/components/layout/PlayingLayout.tsx @@ -20,11 +20,11 @@ const PlayingLayout = ({ children }: { children: ReactNode }) => {