diff --git a/frontend/casino/src/app/components/App/AppLayout/AppLayout.tsx b/frontend/casino/src/app/components/App/AppLayout/AppLayout.tsx index 1300de0..d7be121 100644 --- a/frontend/casino/src/app/components/App/AppLayout/AppLayout.tsx +++ b/frontend/casino/src/app/components/App/AppLayout/AppLayout.tsx @@ -1,5 +1,5 @@ import { observer } from 'mobx-react-lite' -import { type FC } from 'react' +import {type FC} from 'react' import { Outlet } from 'react-router-dom' import { useScrollTop } from '../../../hooks/useScrollTop.ts' diff --git a/frontend/casino/src/app/components/App/AppNav/AppNav.tsx b/frontend/casino/src/app/components/App/AppNav/AppNav.tsx index d56de3f..6c199b3 100644 --- a/frontend/casino/src/app/components/App/AppNav/AppNav.tsx +++ b/frontend/casino/src/app/components/App/AppNav/AppNav.tsx @@ -2,8 +2,12 @@ import CoinIcon from "../../icons/CoinIcon"; import ProfileIcon from "../../icons/ProfileIcon"; import {ConnectStateButton} from "../../../web3/connect"; import chipImg from '../../../../assets/icons/chip.png' +import {useStores} from "../../../hooks/useStores.tsx"; +import {observer} from "mobx-react-lite"; +import {CheckBalanceButton} from "../../../web3/balance/CheckBalanceButton.tsx"; -export const AppNav = () => { +export const AppNav = observer(() => { + const { userStore } = useStores() return (
@@ -20,7 +24,7 @@ export const AppNav = () => {
{/* placeholder for balance */} - 0.000000 + {userStore.balance ? {userStore.balance} : }
@@ -33,4 +37,4 @@ export const AppNav = () => {
) -}; \ No newline at end of file +}) \ No newline at end of file diff --git a/frontend/casino/src/app/components/web3/DicePlayButton.tsx b/frontend/casino/src/app/components/web3/DicePlayButton.tsx index bf7dfe4..ebaa673 100644 --- a/frontend/casino/src/app/components/web3/DicePlayButton.tsx +++ b/frontend/casino/src/app/components/web3/DicePlayButton.tsx @@ -1,7 +1,31 @@ -export const DicePlayButton = () => { +import {usePlayRoulette} from "../../web3/functions/Roulette/usePlayRoulette.ts"; +import {FC, useEffect} from "react"; + +interface DicePlayButtonProps { + value: number + onSuccess: (result: unknown) => void + onLoading: () => void +} + +export const DicePlayButton: FC = ({ value, onSuccess, onLoading }) => { + const { playRoulette, result, isLoading } = usePlayRoulette() + + useEffect(() => { + if (result) onSuccess(result) + }, [result]) + + useEffect(() => { + if (isLoading) onLoading() + }, [isLoading]) + return ( - ) } \ No newline at end of file diff --git a/frontend/casino/src/app/hooks/useIntervalAsync.ts b/frontend/casino/src/app/hooks/useIntervalAsync.ts index 81e1a4e..faf529c 100644 --- a/frontend/casino/src/app/hooks/useIntervalAsync.ts +++ b/frontend/casino/src/app/hooks/useIntervalAsync.ts @@ -1,6 +1,7 @@ import { useCallback, useEffect, useRef, useState } from 'react' +import {IGetResult} from "../web3/functions/utils/useGetResult.ts"; -const useIntervalAsync = (fn: (tx: string) => Promise, ms: number) => { +const useIntervalAsync = (fn: ({tx, notificationKey}: IGetResult) => Promise, ms: number) => { const runningCount = useRef(0) const timeout = useRef() const mountedRef = useRef(false) @@ -17,9 +18,9 @@ const useIntervalAsync = (fn: (tx: string) => Promise, ms: numbe [ms], ) - const run = useCallback(async (tx: string) => { + const run = useCallback(async (tx: string, notificationKey?: string) => { runningCount.current += 1 - const result = await fn(tx) + const result = await fn({tx, notificationKey}) runningCount.current -= 1 next(run) diff --git a/frontend/casino/src/app/hooks/useStatusState.ts b/frontend/casino/src/app/hooks/useStatusState.ts index 07e8911..2185f37 100644 --- a/frontend/casino/src/app/hooks/useStatusState.ts +++ b/frontend/casino/src/app/hooks/useStatusState.ts @@ -1,10 +1,7 @@ import { useCallback, useState } from 'react' -import { useAccount } from 'wagmi' import {stringifyError} from "../utils/error/stringifyError.ts"; export function useStatusState() { - const { isConnected } = useAccount() - const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState() const [result, setResult] = useState() @@ -26,7 +23,7 @@ export function useStatusState() { throw err } } - }, [isConnected]) + }, []) return { statuses: { diff --git a/frontend/casino/src/app/hooks/useStores.tsx b/frontend/casino/src/app/hooks/useStores.tsx new file mode 100644 index 0000000..09b39c4 --- /dev/null +++ b/frontend/casino/src/app/hooks/useStores.tsx @@ -0,0 +1,18 @@ +import { createContext, type PropsWithChildren, useContext } from 'react' + +import { type RootStore, rootStore } from '../stores/RootStore' + +export const StoreContext = createContext(rootStore) + +export function StoreProvider({ + children, +// eslint-disable-next-line @typescript-eslint/ban-types +}: PropsWithChildren): JSX.Element { + return ( + {children} + ) +} + +export function useStores(): RootStore { + return useContext(StoreContext) +} diff --git a/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx b/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx index 56fe64d..38e338e 100644 --- a/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx +++ b/frontend/casino/src/app/pages/DiceGamePage/DiceGamePage.tsx @@ -1,8 +1,29 @@ import ContainerLayout from "../../utils/ContainerLayout" import { DicePlayButton } from "../../components/web3/DicePlayButton" import diceImg from '../../../assets/img/dice-img.png' +import {useState} from "react"; +import {useStores} from "../../hooks/useStores.tsx"; +import {observer} from "mobx-react-lite"; + +export const DiceGamePage = observer(() => { + const [diceValue, setDiceValue] = useState() + const [isLoading, setIsLoading] = useState(false) + const { userStore } = useStores() + + const onSuccess = (result: unknown) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + setDiceValue(result.value) + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + userStore.setBalance(result.balance ?? '0') + setIsLoading(false) + } + + const onLoading = () => { + setIsLoading(true) + } -export const DiceGamePage = () => { return (
@@ -17,16 +38,16 @@ export const DiceGamePage = () => { Dice
{/* Кнопка для бека */} - +
Вы загадали: 5
-
- Выпало число: 5 -
+ {(diceValue && !isLoading) &&
+ Выпало число: {diceValue} +
}
) -} \ No newline at end of file +}) \ No newline at end of file diff --git a/frontend/casino/src/app/stores/RootStore.ts b/frontend/casino/src/app/stores/RootStore.ts new file mode 100644 index 0000000..7f47d60 --- /dev/null +++ b/frontend/casino/src/app/stores/RootStore.ts @@ -0,0 +1,11 @@ +import { UserStore } from './User/UserStore' + +export class RootStore { + userStore: UserStore + + constructor() { + this.userStore = new UserStore() + } +} + +export const rootStore = new RootStore() diff --git a/frontend/casino/src/app/stores/User/UserStore.ts b/frontend/casino/src/app/stores/User/UserStore.ts new file mode 100644 index 0000000..a103eaa --- /dev/null +++ b/frontend/casino/src/app/stores/User/UserStore.ts @@ -0,0 +1,13 @@ +import { makeAutoObservable } from 'mobx' + +export class UserStore { + balance: string | undefined = undefined + constructor() { + makeAutoObservable(this) + } + + setBalance(balance: string) { + this.balance = balance + console.log(balance) + } +} diff --git a/frontend/casino/src/app/web3/balance/CheckBalanceButton.tsx b/frontend/casino/src/app/web3/balance/CheckBalanceButton.tsx new file mode 100644 index 0000000..24d31fd --- /dev/null +++ b/frontend/casino/src/app/web3/balance/CheckBalanceButton.tsx @@ -0,0 +1,18 @@ +import {useCheckBalance} from "./useCheckBalance.ts"; +import {observer} from "mobx-react-lite"; +import {useEffect} from "react"; +import {useStores} from "../../hooks/useStores.tsx"; + +export const CheckBalanceButton = observer(() => { + const { checkBalance, result } = useCheckBalance() + const { userStore } = useStores() + useEffect(() => { + if (result) userStore.setBalance(result.balance) + }, [result]) + + return ( + + ); +}); \ No newline at end of file diff --git a/frontend/casino/src/app/web3/balance/useCheckBalance.ts b/frontend/casino/src/app/web3/balance/useCheckBalance.ts new file mode 100644 index 0000000..dd867ee --- /dev/null +++ b/frontend/casino/src/app/web3/balance/useCheckBalance.ts @@ -0,0 +1,36 @@ +import {useWalletConnect} from "@cityofzion/wallet-connect-sdk-react"; +import {useCallback} from "react"; +import {useGetResult} from "../functions/utils/useGetResult.ts"; +import {config} from "../functions/config/config.ts"; + +export const useCheckBalance = () => { + const wcSdk = useWalletConnect() + const { getResult, ...statuses } = useGetResult() + + const checkBalance = useCallback(async () => { + console.log(config.zaCoin.contractAddress) + const address = wcSdk.getAccountAddress() + + if (!address) return + + const resp = await wcSdk.invokeFunction({ + invocations: [{ + scriptHash: config.zaCoin.contractAddress, + operation: 'balanceOf', + args: [ + { type: 'Hash160', value: address }, + ] + }], + signers: [{ + scopes: 'Global', + }] + }) + console.log(resp) + await getResult(resp, 'balance') + }, [wcSdk, getResult]) + + return { + checkBalance, + ...statuses + } +} \ No newline at end of file diff --git a/frontend/casino/src/app/web3/functions/Roulette/usePlayRoulette.ts b/frontend/casino/src/app/web3/functions/Roulette/usePlayRoulette.ts index a6ef32b..1e95dad 100644 --- a/frontend/casino/src/app/web3/functions/Roulette/usePlayRoulette.ts +++ b/frontend/casino/src/app/web3/functions/Roulette/usePlayRoulette.ts @@ -1,15 +1,13 @@ import {useWalletConnect} from "@cityofzion/wallet-connect-sdk-react"; import {useCallback} from "react"; import {useGetResult} from "../utils/useGetResult.ts"; -import {useStatusState} from "../../../hooks/useStatusState.ts"; import {config} from "../config/config.ts"; export const usePlayRoulette = () => { const wcSdk = useWalletConnect() - const { getResult } = useGetResult() - const { statuses, wrapPromise } = useStatusState() + const { getResult, ...statuses } = useGetResult() - const playRoulette = useCallback(wrapPromise(async () => { + const playRoulette = useCallback(async (value: number) => { // const resp = await wcSdk.invokeFunction({ // invocations: [{ // scriptHash: '270c825a5ac041e18be45074bbb942255164a214', @@ -22,13 +20,14 @@ export const usePlayRoulette = () => { // scopes: 'Global', // }] // }) + console.log(config.roulette.contractAddress) const resp = await wcSdk.invokeFunction({ invocations: [{ scriptHash: config.roulette.contractAddress, operation: 'playRoulette', args: [ { type: 'Integer', value: '40' }, - { type: 'Integer', value: '3' }, + { type: 'Integer', value: value.toString() }, ] }], signers: [{ @@ -36,9 +35,8 @@ export const usePlayRoulette = () => { }] }) console.log(resp) - const result = await getResult(resp) - console.log(result) - }), [wcSdk, getResult, wrapPromise]) + await getResult(resp, 'rouletteNumber') + }, [wcSdk, getResult]) return { playRoulette, diff --git a/frontend/casino/src/app/web3/functions/config/config.ts b/frontend/casino/src/app/web3/functions/config/config.ts index acd1174..f620989 100644 --- a/frontend/casino/src/app/web3/functions/config/config.ts +++ b/frontend/casino/src/app/web3/functions/config/config.ts @@ -3,9 +3,12 @@ export const config = { contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c' }, roulette: { - contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c' + contractAddress: '9a8e8297364f134f29bafe1322323af73e5ab434' }, slotMachine: { contractAddress: '13f7312810758d0e2271e2c620ba93f3568e0e8c' + }, + zaCoin: { + contractAddress: 'fdfb5c2974779e9cb9347e083a80054feae55a2d' } } \ No newline at end of file diff --git a/frontend/casino/src/app/web3/functions/utils/useGetResult.ts b/frontend/casino/src/app/web3/functions/utils/useGetResult.ts index 3ab4106..6af0a99 100644 --- a/frontend/casino/src/app/web3/functions/utils/useGetResult.ts +++ b/frontend/casino/src/app/web3/functions/utils/useGetResult.ts @@ -1,36 +1,57 @@ import {useCallback} from "react"; import axios from "axios"; import useIntervalAsync from "../../../hooks/useIntervalAsync.ts"; +import {useStatusState} from "../../../hooks/useStatusState.ts"; + +export interface IGetResult { + tx: string; + notificationKey?: string +} const baseUrlToGet = 'https://dora.coz.io/api/v2/neo3/testnet/log/' export const useGetResult = () => { + const { statuses, wrapPromise } = useStatusState<{ value: string, balance: string} | undefined, IGetResult>() const getResultReq = useCallback(async (tx: string | undefined) => { const result = await axios.get(baseUrlToGet + tx) console.log(result) return result }, []) - const { run: runIsApprovedRefetch } = useIntervalAsync(async (tx) => { + const { run: runIsApprovedRefetch } = useIntervalAsync(wrapPromise(async ({tx, notificationKey}) => { if (!tx) return try { const result = await getResultReq(tx) if (!result) setTimeout(() => { runIsApprovedRefetch(tx) }, 3000) - return result - } catch (e) { setTimeout(() => { - runIsApprovedRefetch(tx) - }, 3000) } - }, 3000) - const getResult = useCallback(async (tx: string | undefined) => { + let balance; + + if (notificationKey === 'balance') { + balance = result.data?.stack[0].value + } else { + balance = result.data?.notifications?.find((item: { event_name: string | undefined; }) => item?.event_name === 'playerBalance')?.state?.value[0].value + } + const value = result.data?.notifications?.find((item: { event_name: string | undefined; }) => item?.event_name === notificationKey)?.state?.value[0].value + + return { + value, + balance + } + } catch (e) { setTimeout(() => { + runIsApprovedRefetch(tx, notificationKey) + }, 3000) } + }), 3000) + + const getResult = useCallback(async (tx: string | undefined, notificationKey?: string) => { if (!tx) return console.log(tx) - const result = await runIsApprovedRefetch(tx) + const result = await runIsApprovedRefetch(tx, notificationKey) console.log(result) }, [runIsApprovedRefetch]) return { - getResult + getResult, + ...statuses } } \ No newline at end of file