diff --git a/frontend/.env.example b/frontend/.env.example index 8355651..cb4b21f 100644 --- a/frontend/.env.example +++ b/frontend/.env.example @@ -1,3 +1,4 @@ NEXT_PUBLIC_GRAPHQL_URL=http://127.0.0.1:8080/graphql +NEXT_PUBLIC_INSPECT_URL=http://127.0.0.1:8080/inspect NEXT_PUBLIC_TOKEN_ADDRESS=0xae7f61eCf06C65405560166b259C54031428A9C4 NEXT_PUBLIC_DAPP_ADDRESS=0x70ac08179605AF2D9e75782b8DEcDD3c22aA4D0C diff --git a/frontend/package.json b/frontend/package.json index 7037fcf..c1d0432 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -29,6 +29,7 @@ "react-icons": "^4", "react-jazzicon": "^1", "react-use-downloader": "^1.2.4", + "swr": "^2", "urql": "^4", "viem": "^1", "wagmi": "^1" diff --git a/frontend/src/app/create/page.tsx b/frontend/src/app/create/page.tsx index dc35488..a8f1815 100644 --- a/frontend/src/app/create/page.tsx +++ b/frontend/src/app/create/page.tsx @@ -22,7 +22,7 @@ import { useErc20PortalDepositErc20Tokens, usePrepareErc20PortalDepositErc20Tokens, } from "../../hooks/contracts"; -import { DifficultyLevel } from "../../components/DifficultyLevel"; +import { DifficultyLevelPicker } from "../../components/DifficultyLevelPicker"; import { GameLevel } from "../../components/GameLevel"; const parseIfNeeded = (setter: (v: number) => void) => { @@ -159,7 +159,7 @@ const CreateGame: FC = () => { onChange={parseIfNeeded(setSubmissionTime)} description="Amount of time players will have to submit their gameplay" /> - diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 0c60c35..60c3704 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -1,26 +1,70 @@ "use client"; - import React, { FC } from "react"; -import { Button, Center, Stack } from "@mantine/core"; +import { Button, Center, Stack, Text, Title } from "@mantine/core"; import Image from "next/image"; import Link from "next/link"; +import { useInspect } from "../hooks/inspect"; +import { Contest } from "../model"; +import { DifficultyLevel } from "../components/DifficultyLevel"; +import { formatUnits, Hex, hexToBigInt } from "viem"; + const Home: FC = () => { + const { + report: contest, + error, + data, + } = useInspect(`/active_contest`); + const c = { + contest_id: 1, + name: "Contest", + host: "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92261", + ticket_price: "0x8ac7230489e80000", + level: 1, + difficulty: 3, + play_time: 3600, + submission_time: 3600, + creation_timestamp: 1695505002, + state: "finalized", + players: [ + { + wallet: "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + score: 123, + reward: null, + }, + { + wallet: "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92267", + score: null, + reward: null, + }, + ], + prize_pool: "0x32d26d12e980b600000", + }; + return (
- banner - - - - - - + {!c && ( + <> + banner + + + + + )} + {c.name} + Hosted by {c.host} + + + {formatUnits(hexToBigInt(c.ticket_price as Hex), 18)} APE to + signup + +
); diff --git a/frontend/src/components/DifficultyLevel.tsx b/frontend/src/components/DifficultyLevel.tsx index 0c8194d..c57537b 100644 --- a/frontend/src/components/DifficultyLevel.tsx +++ b/frontend/src/components/DifficultyLevel.tsx @@ -1,4 +1,4 @@ -import { Image, SegmentedControl, Stack, Text } from "@mantine/core"; +import { Image, Overlay, SegmentedControl, Stack, Text } from "@mantine/core"; import { FC } from "react"; export const difficultyLevels = [ @@ -9,30 +9,25 @@ export const difficultyLevels = [ ]; export type DifficultyLevelProps = { - onChange(value: number): void; value: number; }; -export const DifficultyLevel: FC = ({ - onChange, - value, -}) => { +export const DifficultyLevel: FC = ({ value }) => { return ( onChange(parseInt(value))} value={value.toString()} data={difficultyLevels.map((level, index) => ({ value: index.toString(), label: ( {level.label} + {index != value && } {level.label} event.target} /> ), diff --git a/frontend/src/components/DifficultyLevelPicker.tsx b/frontend/src/components/DifficultyLevelPicker.tsx new file mode 100644 index 0000000..8ea157e --- /dev/null +++ b/frontend/src/components/DifficultyLevelPicker.tsx @@ -0,0 +1,41 @@ +import { Image, Overlay, SegmentedControl, Stack, Text } from "@mantine/core"; +import { FC } from "react"; + +export const difficultyLevels = [ + { label: "I'm Too Young to Die", image: "/img/difficulty1.png" }, + { label: "Hurt Me Plenty", image: "/img/difficulty2.png" }, + { label: "Ultra Violence", image: "/img/difficulty3.png" }, + { label: "Nightmare", image: "/img/difficulty4.png" }, +]; + +export type DifficultyLevelPickerProps = { + onChange(value: number): void; + value: number; +}; + +export const DifficultyLevelPicker: FC = ({ + onChange, + value, +}) => { + return ( + onChange(parseInt(value))} + value={value.toString()} + data={difficultyLevels.map((level, index) => ({ + value: index.toString(), + label: ( + + {level.label} + {level.label} + + ), + }))} + /> + ); +}; diff --git a/frontend/src/hooks/inspect.ts b/frontend/src/hooks/inspect.ts new file mode 100644 index 0000000..26978fd --- /dev/null +++ b/frontend/src/hooks/inspect.ts @@ -0,0 +1,56 @@ +import useSWR, { Key, SWRResponse } from "swr"; +import { bytesToString, toBytes } from "viem"; + +const baseURL = process.env.NEXT_PUBLIC_INSPECT_URL; + +export enum InspectStatus { + Accepted = "Accepted", + Rejected = "Rejected", + Exception = "Exception", + MachineHalted = "MachineHalted", + CycleLimitExceeded = "CycleLimitExceeded", + TimeLimitExceeded = "TimeLimitExceeded", +} + +export interface InspectReport { + payload: string; +} + +export interface InspectMetadata { + active_epoch_index: number; + current_input_index: number; +} + +export interface InspectResponse { + status: InspectStatus; + exception_payload: string; + reports: InspectReport[]; + metadata: InspectMetadata; +} + +type ReportResponse = { + report?: TReport; +}; + +export type UseInspect = SWRResponse & + ReportResponse; + +export const useInspect = (key: Key): UseInspect => { + const swr = useSWR(() => + key ? `${baseURL}${key}` : false + ); + + const response = swr.data; + let report = undefined; + if ( + response && + response.status == InspectStatus.Accepted && + response.reports.length > 0 + ) { + const r = response.reports[0]; + const data = bytesToString(toBytes(r.payload)); + report = JSON.parse(data) as TReport; + } + + return { ...swr, report }; +}; diff --git a/frontend/src/model/index.ts b/frontend/src/model/index.ts new file mode 100644 index 0000000..6bf7527 --- /dev/null +++ b/frontend/src/model/index.ts @@ -0,0 +1,20 @@ +export interface Player { + wallet: string; + score: number; + reward: string; +} + +export interface Contest { + contest_id: number; + name: string; + host: string; + ticket_price: string; + prize_pool: string; + level: number; + difficulty: number; + creation_timestamp: number; + play_time: number; + submission_time: number; + state: "ready_to_play" | "gameplay_submission" | "finalized"; + players: Player[]; +}