From 93c3ca81fae6f1dbafca497cb270b05d3c323255 Mon Sep 17 00:00:00 2001 From: yu-zhen Date: Wed, 21 Aug 2024 01:08:00 +0800 Subject: [PATCH] feat: add organizer dashboard --- packages/interface/public/arbitrum.svg | 9 ++ packages/interface/public/base.svg | 6 + packages/interface/public/baseSepolia.svg | 6 + packages/interface/public/constant.svg | 4 + packages/interface/public/eas.svg | 9 ++ packages/interface/public/ethereum.svg | 1 + packages/interface/public/freeforall.svg | 3 + packages/interface/public/linea.svg | 12 ++ packages/interface/public/localhost.svg | 20 +++ packages/interface/public/optimism.svg | 9 ++ packages/interface/public/optimismSepolia.svg | 9 ++ packages/interface/public/qf.svg | 3 + packages/interface/public/scroll.svg | 1 + packages/interface/public/scrollSepolia.svg | 1 + packages/interface/public/semaphore.svg | 11 ++ packages/interface/public/sepolia.svg | 24 +++ packages/interface/public/token.svg | 3 + packages/interface/public/zupass.svg | 10 ++ .../interface/src/components/ImageUpload.tsx | 14 +- packages/interface/src/components/Info.tsx | 2 +- .../interface/src/components/RoundInfo.tsx | 8 +- .../Steps.tsx} | 26 ++-- packages/interface/src/components/ui/Form.tsx | 7 + .../src/components/ui/RadioSelect.tsx | 59 +++++++ packages/interface/src/contexts/Round.tsx | 54 +++++-- packages/interface/src/contexts/types.ts | 5 +- packages/interface/src/env.js | 2 +- .../admin/components/DeployContracts.tsx | 99 ++++++++++++ .../components/DeployContractsButtons.tsx | 113 ++++++++++++++ .../admin/components/DeployRounds.tsx | 147 ++++++++++++++++++ .../admin/components/DeployRoundsButtons.tsx | 131 ++++++++++++++++ .../ReviewDeployContractsDetails.tsx | 69 ++++++++ .../components/ReviewDeployRoundDetails.tsx | 69 ++++++++ .../components/VoiceCreditProxySelect.tsx | 53 +++++++ .../features/admin/hooks/useDeployRound.ts | 44 ++++++ .../src/features/admin/types/index.ts | 0 .../components/ApplicationForm.tsx | 4 +- .../features/rounds/components/RoundsList.tsx | 4 +- .../src/features/rounds/types/index.ts | 53 ++++++- .../interface/src/layouts/DefaultLayout.tsx | 4 +- packages/interface/src/pages/admin/index.tsx | 18 +++ .../interface/src/pages/coordinator/index.tsx | 5 - packages/interface/src/pages/index.tsx | 8 +- .../rounds/[roundId]/applications/new.tsx | 7 + packages/interface/tailwind.config.ts | 4 + 45 files changed, 1088 insertions(+), 62 deletions(-) create mode 100644 packages/interface/public/arbitrum.svg create mode 100644 packages/interface/public/base.svg create mode 100644 packages/interface/public/baseSepolia.svg create mode 100644 packages/interface/public/constant.svg create mode 100644 packages/interface/public/eas.svg create mode 100644 packages/interface/public/ethereum.svg create mode 100644 packages/interface/public/freeforall.svg create mode 100644 packages/interface/public/linea.svg create mode 100644 packages/interface/public/localhost.svg create mode 100644 packages/interface/public/optimism.svg create mode 100644 packages/interface/public/optimismSepolia.svg create mode 100644 packages/interface/public/qf.svg create mode 100644 packages/interface/public/scroll.svg create mode 100644 packages/interface/public/scrollSepolia.svg create mode 100644 packages/interface/public/semaphore.svg create mode 100644 packages/interface/public/sepolia.svg create mode 100644 packages/interface/public/token.svg create mode 100644 packages/interface/public/zupass.svg rename packages/interface/src/{features/applications/components/ApplicationSteps.tsx => components/Steps.tsx} (68%) create mode 100644 packages/interface/src/components/ui/RadioSelect.tsx create mode 100644 packages/interface/src/features/admin/components/DeployContracts.tsx create mode 100644 packages/interface/src/features/admin/components/DeployContractsButtons.tsx create mode 100644 packages/interface/src/features/admin/components/DeployRounds.tsx create mode 100644 packages/interface/src/features/admin/components/DeployRoundsButtons.tsx create mode 100644 packages/interface/src/features/admin/components/ReviewDeployContractsDetails.tsx create mode 100644 packages/interface/src/features/admin/components/ReviewDeployRoundDetails.tsx create mode 100644 packages/interface/src/features/admin/components/VoiceCreditProxySelect.tsx create mode 100644 packages/interface/src/features/admin/hooks/useDeployRound.ts create mode 100644 packages/interface/src/features/admin/types/index.ts create mode 100644 packages/interface/src/pages/admin/index.tsx delete mode 100644 packages/interface/src/pages/coordinator/index.tsx diff --git a/packages/interface/public/arbitrum.svg b/packages/interface/public/arbitrum.svg new file mode 100644 index 00000000..1e518ab1 --- /dev/null +++ b/packages/interface/public/arbitrum.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/interface/public/base.svg b/packages/interface/public/base.svg new file mode 100644 index 00000000..e924ffde --- /dev/null +++ b/packages/interface/public/base.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/interface/public/baseSepolia.svg b/packages/interface/public/baseSepolia.svg new file mode 100644 index 00000000..e924ffde --- /dev/null +++ b/packages/interface/public/baseSepolia.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/interface/public/constant.svg b/packages/interface/public/constant.svg new file mode 100644 index 00000000..afa5082a --- /dev/null +++ b/packages/interface/public/constant.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/interface/public/eas.svg b/packages/interface/public/eas.svg new file mode 100644 index 00000000..1f072996 --- /dev/null +++ b/packages/interface/public/eas.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/interface/public/ethereum.svg b/packages/interface/public/ethereum.svg new file mode 100644 index 00000000..b5224357 --- /dev/null +++ b/packages/interface/public/ethereum.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/interface/public/freeforall.svg b/packages/interface/public/freeforall.svg new file mode 100644 index 00000000..5ae0f0a0 --- /dev/null +++ b/packages/interface/public/freeforall.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/interface/public/linea.svg b/packages/interface/public/linea.svg new file mode 100644 index 00000000..63103311 --- /dev/null +++ b/packages/interface/public/linea.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/packages/interface/public/localhost.svg b/packages/interface/public/localhost.svg new file mode 100644 index 00000000..6fa85a34 --- /dev/null +++ b/packages/interface/public/localhost.svg @@ -0,0 +1,20 @@ + + + + + + + + + + \ No newline at end of file diff --git a/packages/interface/public/optimism.svg b/packages/interface/public/optimism.svg new file mode 100644 index 00000000..c1144428 --- /dev/null +++ b/packages/interface/public/optimism.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/interface/public/optimismSepolia.svg b/packages/interface/public/optimismSepolia.svg new file mode 100644 index 00000000..e929f803 --- /dev/null +++ b/packages/interface/public/optimismSepolia.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/packages/interface/public/qf.svg b/packages/interface/public/qf.svg new file mode 100644 index 00000000..5c6272bf --- /dev/null +++ b/packages/interface/public/qf.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/interface/public/scroll.svg b/packages/interface/public/scroll.svg new file mode 100644 index 00000000..d7f63b39 --- /dev/null +++ b/packages/interface/public/scroll.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/interface/public/scrollSepolia.svg b/packages/interface/public/scrollSepolia.svg new file mode 100644 index 00000000..d7f63b39 --- /dev/null +++ b/packages/interface/public/scrollSepolia.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/interface/public/semaphore.svg b/packages/interface/public/semaphore.svg new file mode 100644 index 00000000..d8e60c76 --- /dev/null +++ b/packages/interface/public/semaphore.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/packages/interface/public/sepolia.svg b/packages/interface/public/sepolia.svg new file mode 100644 index 00000000..1669c499 --- /dev/null +++ b/packages/interface/public/sepolia.svg @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/packages/interface/public/token.svg b/packages/interface/public/token.svg new file mode 100644 index 00000000..2e52d222 --- /dev/null +++ b/packages/interface/public/token.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/interface/public/zupass.svg b/packages/interface/public/zupass.svg new file mode 100644 index 00000000..78c2b42b --- /dev/null +++ b/packages/interface/public/zupass.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/packages/interface/src/components/ImageUpload.tsx b/packages/interface/src/components/ImageUpload.tsx index a914a0fb..c4dee714 100644 --- a/packages/interface/src/components/ImageUpload.tsx +++ b/packages/interface/src/components/ImageUpload.tsx @@ -1,7 +1,7 @@ import { useMutation } from "@tanstack/react-query"; import clsx from "clsx"; import { ImageIcon } from "lucide-react"; -import { type ComponentProps, useRef } from "react"; +import { type ComponentProps, useRef, useCallback } from "react"; import { Controller, useFormContext } from "react-hook-form"; import { toast } from "sonner"; @@ -33,17 +33,18 @@ export const ImageUpload = ({ }, }); + const onClick = useCallback(() => { + ref.current?.click(); + }, []); + return ( ( // eslint-disable-next-line jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events -
ref.current?.click()} - > - +
+
{ const [file] = event.target.files ?? []; if (file) { diff --git a/packages/interface/src/components/Info.tsx b/packages/interface/src/components/Info.tsx index 983ffc53..90886680 100644 --- a/packages/interface/src/components/Info.tsx +++ b/packages/interface/src/components/Info.tsx @@ -65,7 +65,7 @@ export const Info = ({ size, roundId, showVotingInfo = false }: IInfoProps): JSX {showVotingInfo && (
- + {roundState === ERoundState.VOTING && }
diff --git a/packages/interface/src/components/RoundInfo.tsx b/packages/interface/src/components/RoundInfo.tsx index 6281c17b..5448fbf2 100644 --- a/packages/interface/src/components/RoundInfo.tsx +++ b/packages/interface/src/components/RoundInfo.tsx @@ -1,18 +1,16 @@ -import Image from "next/image"; - import { Heading } from "~/components/ui/Heading"; -import { config } from "~/config"; interface IRoundInfoProps { roundId: string; + roundLogo?: string; } -export const RoundInfo = ({ roundId }: IRoundInfoProps): JSX.Element => ( +export const RoundInfo = ({ roundId, roundLogo = undefined }: IRoundInfoProps): JSX.Element => (

Round

- {config.roundLogo && round logo} + {roundLogo && round logo} {roundId} diff --git a/packages/interface/src/features/applications/components/ApplicationSteps.tsx b/packages/interface/src/components/Steps.tsx similarity index 68% rename from packages/interface/src/features/applications/components/ApplicationSteps.tsx rename to packages/interface/src/components/Steps.tsx index 6f5cd096..126d7ada 100644 --- a/packages/interface/src/features/applications/components/ApplicationSteps.tsx +++ b/packages/interface/src/components/Steps.tsx @@ -10,13 +10,17 @@ export enum EStepState { interface IStepCategoryProps { title: string; progress: EStepState; + isLast?: boolean; } -interface IApplicationStepsProps { +interface IStepsProps { step: number; + stepNames: string[]; } -const StepCategory = ({ title, progress }: IStepCategoryProps): JSX.Element => ( +const Interline = (): JSX.Element =>
; + +const StepCategory = ({ title, progress, isLast = false }: IStepCategoryProps): JSX.Element => (
{progress === EStepState.ACTIVE && ( circle-check-blue @@ -29,21 +33,15 @@ const StepCategory = ({ title, progress }: IStepCategoryProps): JSX.Element => ( {progress === EStepState.DEFAULT &&
}

{title}

+ + {!isLast && }
); -const Interline = (): JSX.Element =>
; - -export const ApplicationSteps = ({ step }: IApplicationStepsProps): JSX.Element => ( +export const Steps = ({ step, stepNames }: IStepsProps): JSX.Element => (
- - - - - - - - - + {stepNames.map((name, i) => ( + + ))}
); diff --git a/packages/interface/src/components/ui/Form.tsx b/packages/interface/src/components/ui/Form.tsx index 133f72eb..4025208f 100644 --- a/packages/interface/src/components/ui/Form.tsx +++ b/packages/interface/src/components/ui/Form.tsx @@ -66,6 +66,13 @@ export const ErrorMessage = createComponent("div", tv({ base: "pt-1 text-xs text export const Textarea = createComponent("textarea", tv({ base: [...inputBase, "w-full"] })); +// eslint-disable-next-line react/display-name +export const DateInput = forwardRef(({ ...props }: ComponentPropsWithRef, ref) => ( + + + +)); + export const SearchInput = forwardRef(({ ...props }: ComponentPropsWithRef, ref) => ( diff --git a/packages/interface/src/components/ui/RadioSelect.tsx b/packages/interface/src/components/ui/RadioSelect.tsx new file mode 100644 index 00000000..49a60899 --- /dev/null +++ b/packages/interface/src/components/ui/RadioSelect.tsx @@ -0,0 +1,59 @@ +import clsx from "clsx"; +import Image from "next/image"; +import React, { useCallback } from "react"; +import { useFormContext } from "react-hook-form"; + +import { Label } from "~/components/ui/Form"; +import { Input } from "~/components/ui/Input"; +import { Tooltip } from "~/components/ui/Tooltip"; + +interface IRadioSelectProps { + label: string; + name: string; + hint?: string; + required?: boolean; + options: string[]; +} + +export const RadioSelect = ({ label, name, required = false, hint = "", options }: IRadioSelectProps): JSX.Element => { + const form = useFormContext(); + + const handleOnClick = useCallback( + (e: React.ChangeEvent) => { + form.setValue(name, e.target.id); + }, + [form], + ); + + return ( +
+
+ {label && ( + + )} + + {hint && } +
+ +
+ {options.map((option) => ( + + ))} +
+
+ ); +}; diff --git a/packages/interface/src/contexts/Round.tsx b/packages/interface/src/contexts/Round.tsx index a5415337..ad578714 100644 --- a/packages/interface/src/contexts/Round.tsx +++ b/packages/interface/src/contexts/Round.tsx @@ -1,4 +1,4 @@ -import React, { createContext, useContext, useMemo, useCallback } from "react"; +import React, { createContext, useContext, useMemo, useCallback, useState, useEffect } from "react"; import type { RoundContextType, RoundProviderProps } from "./types"; import type { Round } from "~/features/rounds/types"; @@ -6,28 +6,56 @@ import type { Round } from "~/features/rounds/types"; export const RoundContext = createContext(undefined); export const RoundProvider: React.FC = ({ children }: RoundProviderProps) => { - const rounds = [ - { - roundId: "open-rpgf-1", - description: "This is the description of this round, please add your own description.", - startsAt: 1723477832000, - registrationEndsAt: 1723487832000, - votingEndsAt: 1724009826000, - tallyURL: "https://upblxu2duoxmkobt.public.blob.vercel-storage.com/tally.json", - }, - ]; + const [rounds, setRounds] = useState(undefined); + + const [isContractsDeployed, setContractsDeployed] = useState(false); const getRound = useCallback( - (roundId: string): Round | undefined => rounds.find((round) => round.roundId === roundId), + (roundId: string): Round | undefined => (rounds ? rounds.find((round) => round.roundId === roundId) : undefined), [rounds], ); + const addRound = useCallback( + (round: Round): void => { + if (!rounds) { + setRounds([round]); + } else { + setRounds([...rounds, round]); + } + }, + [rounds, setRounds], + ); + + const deployContracts = useCallback(() => { + setContractsDeployed(true); + }, [setContractsDeployed]); + + useEffect(() => { + const storageData = localStorage.getItem("rounds"); + + if (storageData) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const storedRounds = JSON.parse(storageData); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + setRounds(storedRounds); + } + }, []); + + useEffect(() => { + if (rounds) { + localStorage.setItem("rounds", JSON.stringify(rounds)); + } + }, [rounds]); + const value = useMemo( () => ({ + isContractsDeployed, rounds, getRound, + addRound, + deployContracts, }), - [rounds, getRound], + [rounds, getRound, addRound], ); return {children}; diff --git a/packages/interface/src/contexts/types.ts b/packages/interface/src/contexts/types.ts index 2637d0b8..2475594b 100644 --- a/packages/interface/src/contexts/types.ts +++ b/packages/interface/src/contexts/types.ts @@ -50,8 +50,11 @@ export interface BallotProviderProps { } export interface RoundContextType { - rounds: Round[]; + isContractsDeployed: boolean; + rounds: Round[] | undefined; getRound: (roundId: string) => Round | undefined; + addRound: (round: Round) => void; + deployContracts: () => void; } export interface RoundProviderProps { diff --git a/packages/interface/src/env.js b/packages/interface/src/env.js index 5ff03102..da42dd1d 100644 --- a/packages/interface/src/env.js +++ b/packages/interface/src/env.js @@ -44,7 +44,7 @@ module.exports = createEnv({ NEXT_PUBLIC_WALLETCONNECT_ID: z.string().optional(), NEXT_PUBLIC_ALCHEMY_ID: z.string().optional(), - NEXT_PUBLIC_MACI_ADDRESS: z.string().startsWith("0x"), + NEXT_PUBLIC_MACI_ADDRESS: z.string().startsWith("0x").optional(), NEXT_PUBLIC_MACI_START_BLOCK: z.string().optional(), NEXT_PUBLIC_MACI_SUBGRAPH_URL: z.string().url().optional(), diff --git a/packages/interface/src/features/admin/components/DeployContracts.tsx b/packages/interface/src/features/admin/components/DeployContracts.tsx new file mode 100644 index 00000000..d6238fb3 --- /dev/null +++ b/packages/interface/src/features/admin/components/DeployContracts.tsx @@ -0,0 +1,99 @@ +import { useRouter } from "next/router"; +import { useState, useCallback } from "react"; +import { useAccount } from "wagmi"; + +import { Steps } from "~/components/Steps"; +import { Form, FormSection } from "~/components/ui/Form"; +import { Heading } from "~/components/ui/Heading"; +import { RadioSelect } from "~/components/ui/RadioSelect"; +import { useRound } from "~/contexts/Round"; +import { DeploymentSchema, chainTypes, gatingStrategyTypes } from "~/features/rounds/types"; +import { useIsCorrectNetwork } from "~/hooks/useIsCorrectNetwork"; + +import { EDeployContractsStep, DeployContractsButtons } from "./DeployContractsButtons"; +import { ReviewDeployContractsDetails } from "./ReviewDeployContractsDetails"; +import { VoiceCreditProxySelect } from "./VoiceCreditProxySelect"; + +export const DeployContracts = (): JSX.Element => { + const router = useRouter(); + const [step, setStep] = useState(EDeployContractsStep.CONFIGURE); + + const { isCorrectNetwork, correctNetwork } = useIsCorrectNetwork(); + + const { address } = useAccount(); + + const { deployContracts } = useRound(); + + const handleNextStep = useCallback(() => { + if (step === EDeployContractsStep.CONFIGURE) { + setStep(EDeployContractsStep.REVIEW); + } + }, [step, setStep]); + + const handleBackStep = useCallback(() => { + if (step === EDeployContractsStep.REVIEW) { + setStep(EDeployContractsStep.CONFIGURE); + } + }, [step, setStep]); + + const onSubmit = () => { + deployContracts(); + router.push("/"); + }; + + return ( +
+ Deploy Core Contracts + +

These initial MACI core contracts configuration will apply to all future rounds.

+ +
+ + +
+ + + + + + + + + {step === EDeployContractsStep.REVIEW && } + + {step === EDeployContractsStep.REVIEW && ( +
+ {!address &&

You must connect wallet to create an application

} + + {!isCorrectNetwork &&

You must be connected to {correctNetwork.name}

} +
+ )} + + + +
+
+ ); +}; diff --git a/packages/interface/src/features/admin/components/DeployContractsButtons.tsx b/packages/interface/src/features/admin/components/DeployContractsButtons.tsx new file mode 100644 index 00000000..dd367987 --- /dev/null +++ b/packages/interface/src/features/admin/components/DeployContractsButtons.tsx @@ -0,0 +1,113 @@ +import { useMemo, useCallback, useState } from "react"; +import { useFormContext } from "react-hook-form"; +import { useAccount } from "wagmi"; + +import { Button, IconButton } from "~/components/ui/Button"; +import { Dialog } from "~/components/ui/Dialog"; +import { Spinner } from "~/components/ui/Spinner"; +import { useIsCorrectNetwork } from "~/hooks/useIsCorrectNetwork"; + +import type { Deployment } from "~/features/rounds/types"; + +export enum EDeployContractsStep { + CONFIGURE, + REVIEW, +} + +interface IDeployContractsButtonsProps { + step: EDeployContractsStep; + isUploading: boolean; + isPending: boolean; + onNextStep: () => void; + onBackStep: () => void; +} + +export const DeployContractsButtons = ({ + step, + isUploading, + isPending, + onNextStep, + onBackStep, +}: IDeployContractsButtonsProps): JSX.Element => { + const { isCorrectNetwork } = useIsCorrectNetwork(); + + const { address } = useAccount(); + + const [showDialog, setShowDialog] = useState(false); + const form = useFormContext(); + + const [chain, gatingStrategy, creditStrategy] = useMemo( + () => form.watch(["chain", "gatingStrategy", "creditStrategy"]), + [form], + ); + + const stepComplete = useMemo((): boolean => { + if (step === EDeployContractsStep.CONFIGURE) { + return true; + } + + return true; + }, [chain, gatingStrategy, creditStrategy]); + + const handleOnClickNextStep = useCallback( + (event: UIEvent) => { + event.preventDefault(); + + if (stepComplete) { + onNextStep(); + } else { + setShowDialog(true); + } + }, + [onNextStep, setShowDialog, stepComplete], + ); + + const handleOnClickBackStep = useCallback( + (event: UIEvent) => { + event.preventDefault(); + onBackStep(); + }, + [onBackStep], + ); + + const handleOnOpenChange = useCallback(() => { + setShowDialog(false); + }, [setShowDialog]); + + return ( +
+ + + {step !== EDeployContractsStep.CONFIGURE && ( + + )} + + {step !== EDeployContractsStep.REVIEW && ( + + )} + + {step === EDeployContractsStep.REVIEW && ( + + {isUploading ? "Uploading..." : "Submit"} + + )} +
+ ); +}; diff --git a/packages/interface/src/features/admin/components/DeployRounds.tsx b/packages/interface/src/features/admin/components/DeployRounds.tsx new file mode 100644 index 00000000..db795ef0 --- /dev/null +++ b/packages/interface/src/features/admin/components/DeployRounds.tsx @@ -0,0 +1,147 @@ +import { useRouter } from "next/router"; +import { useState, useCallback } from "react"; +import { toast } from "sonner"; +import { useAccount } from "wagmi"; + +import { ImageUpload } from "~/components/ImageUpload"; +import { Steps } from "~/components/Steps"; +import { Form, FormSection, FormControl, Textarea, Select, DateInput } from "~/components/ui/Form"; +import { Heading } from "~/components/ui/Heading"; +import { Input } from "~/components/ui/Input"; +import { RoundSchema, votingStrategyTypes } from "~/features/rounds/types"; +import { useIsCorrectNetwork } from "~/hooks/useIsCorrectNetwork"; + +import { useDeployRound } from "../hooks/useDeployRound"; + +import { DeployRoundsButtons, EDeployRoundsStep } from "./DeployRoundsButtons"; +import { ReviewDeployRoundDetails } from "./ReviewDeployRoundDetails"; + +export const DeployRounds = (): JSX.Element => { + const router = useRouter(); + + const { isCorrectNetwork, correctNetwork } = useIsCorrectNetwork(); + + const { address } = useAccount(); + + const [step, setStep] = useState(EDeployRoundsStep.CONFIGURE); + + const handleNextStep = useCallback(() => { + if (step === EDeployRoundsStep.CONFIGURE) { + setStep(EDeployRoundsStep.REVIEW); + } + }, [step, setStep]); + + const handleBackStep = useCallback(() => { + if (step === EDeployRoundsStep.REVIEW) { + setStep(EDeployRoundsStep.CONFIGURE); + } + }, [step, setStep]); + + const create = useDeployRound({ + onSuccess: () => { + router.push(`/`); + }, + onError: (err: Error) => + toast.error("Round deploy error", { + description: err.message, + }), + }); + + const { error: createError } = create; + + return ( +
+ Deploy Round Contracts + +

These round contracts specify the features for this round.

+ +
+ + +
{ + create.mutate(round); + }} + > + + + + + +
+ +