Skip to content

Commit

Permalink
feat: add organizer dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
kittybest committed Aug 23, 2024
1 parent e2e6968 commit 3fe14f4
Show file tree
Hide file tree
Showing 16 changed files with 428 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 => <div className="h-[1px] w-9 bg-gray-300" />;

const StepCategory = ({ title, progress, isLast = false }: IStepCategoryProps): JSX.Element => (
<div className="flex items-center gap-3">
{progress === EStepState.ACTIVE && (
<Image alt="circle-check-blue" height="22" src="/circle-check-blue.svg" width="22" />
Expand All @@ -29,21 +33,15 @@ const StepCategory = ({ title, progress }: IStepCategoryProps): JSX.Element => (
{progress === EStepState.DEFAULT && <div className="h-4 w-4 rounded-full border-2 border-gray-300" />}

<p className={clsx("text-md", progress === EStepState.ACTIVE ? "text-blue-400" : "text-gray-300")}>{title}</p>

{!isLast && <Interline />}
</div>
);

const Interline = (): JSX.Element => <div className="h-[1px] w-9 bg-gray-300" />;

export const ApplicationSteps = ({ step }: IApplicationStepsProps): JSX.Element => (
export const Steps = ({ step, stepNames }: IStepsProps): JSX.Element => (
<div className="mb-4 flex items-center gap-4">
<StepCategory progress={step} title="Project Profile" />

<Interline />

<StepCategory progress={step - 1} title="Contribution & Impact" />

<Interline />

<StepCategory progress={step - 2} title="Review & Submit" />
{stepNames.map((name, i) => (
<StepCategory key={name} isLast={i === stepNames.length - 1} progress={step - i} title={name} />
))}
</div>
);
7 changes: 7 additions & 0 deletions packages/interface/src/components/ui/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<typeof Input>, ref) => (
<InputWrapper>
<Input ref={ref} {...props} type="date" />
</InputWrapper>
));

export const SearchInput = forwardRef(({ ...props }: ComponentPropsWithRef<typeof Input>, ref) => (
<InputWrapper>
<InputIcon>
Expand Down
8 changes: 5 additions & 3 deletions packages/interface/src/contexts/Round.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ export const RoundProvider: React.FC<RoundProviderProps> = ({ children }: RoundP
{
roundId: "open-rpgf-1",
description: "This is the description of this round, please add your own description.",
startsAt: 1723477832000,
registrationEndsAt: 1723487832000,
votingEndsAt: 1724009826000,
startsAt: "1723497832000",
registrationEndsAt: "1724312488000",
votingStartsAt: "1726259160000",
votingEndsAt: "1726259170000",
votingStrategy: "non-qv",
tallyURL: "https://upblxu2duoxmkobt.public.blob.vercel-storage.com/tally.json",
},
];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const DeployContracts = (): JSX.Element => <div>This is Deploy Contracts</div>;
147 changes: 147 additions & 0 deletions packages/interface/src/features/admin/components/DeployRounds.tsx
Original file line number Diff line number Diff line change
@@ -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>(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 (
<div>
<Heading size="4xl">Deploy Round Contracts</Heading>

<p className="text-gray-400">These round contracts specify the features for this round.</p>

<div className="dark:border-lighterBlack rounded-lg border border-gray-200 p-4">
<Steps step={step} stepNames={["Configure Contracts", "Review & Deploy"]} />

<Form
defaultValues={{}}
schema={RoundSchema}
onSubmit={(round) => {
create.mutate(round);
}}
>
<FormSection
className={step === EDeployRoundsStep.CONFIGURE ? "block" : "hidden"}
description="Please select from the available options to configure the deployment of this round."
title="Configure Contracts"
>
<FormControl required hint="This is the name of your round" label="Round Name" name="roundId">
<Input placeholder="Type the name of your round" />
</FormControl>

<div className="w-full gap-4 md:flex">
<FormControl required className="w-full" label="Round Description" name="description">
<Textarea
className="h-48"
placeholder="Briefly describe your round in a sentence or two (200 characters max)"
/>
</FormControl>

<FormControl required hint="png or jpg file size 500x500 px" label="Round Logo" name="roundLogo">
<ImageUpload className="h-48 w-48" />
</FormControl>
</div>

<div className="gap-4 md:flex">
<FormControl required label="Round Starts At" name="startsAt">
<DateInput />
</FormControl>

<FormControl required label="Registration Ends At" name="registrationEndsAt">
<DateInput />
</FormControl>

<FormControl required label="Poll Starts At" name="votingStartsAt">
<DateInput />
</FormControl>

<FormControl required label="Poll Ends At" name="votingEndsAt">
<DateInput />
</FormControl>
</div>

<FormControl required hint="Choose a voting strategy" label="Voting Strategy" name="votingStrategy">
<Select>
{Object.entries(votingStrategyTypes).map(([value, label]) => (
<option key={value} value={value}>
{label}
</option>
))}
</Select>
</FormControl>
</FormSection>

{step === EDeployRoundsStep.REVIEW && <ReviewDeployRoundDetails />}

{step === EDeployRoundsStep.REVIEW && (
<div className="mb-2 w-full text-right text-sm italic text-blue-400">
{!address && <p>You must connect wallet to create an application</p>}

{!isCorrectNetwork && <p className="gap-2">You must be connected to {correctNetwork.name}</p>}

{createError && (
<p>
Make sure you&apos;re not connected to a VPN since this can cause problems with the RPC and your
wallet.
</p>
)}
</div>
)}

<DeployRoundsButtons
isPending={create.isPending}
isUploading={create.isPending}
step={step}
onBackStep={handleBackStep}
onNextStep={handleNextStep}
/>
</Form>
</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { useMemo, useCallback, useState } from "react";
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";

export enum EDeployRoundsStep {
CONFIGURE,
REVIEW,
}

interface IDeployRoundsButtonsProps {
step: EDeployRoundsStep;
isUploading: boolean;
isPending: boolean;
onNextStep: () => void;
onBackStep: () => void;
}

export const DeployRoundsButtons = ({
step,
isUploading,
isPending,
onNextStep,
onBackStep,
}: IDeployRoundsButtonsProps): JSX.Element => {
const { isCorrectNetwork } = useIsCorrectNetwork();

const { address } = useAccount();

const [showDialog, setShowDialog] = useState<boolean>(false);

const stepComplete = useMemo((): boolean => {
if (step === EDeployRoundsStep.CONFIGURE) {
return true;
}

return true;
}, []);

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 (
<div className="flex justify-end gap-2">
<Dialog
description="There are still some inputs not fulfilled, please complete all the required information."
isOpen={showDialog}
size="sm"
title="Please complete all the required information"
onOpenChange={handleOnOpenChange}
/>

{step !== EDeployRoundsStep.CONFIGURE && (
<Button className="text-gray-300 underline" size="auto" variant="ghost" onClick={handleOnClickBackStep}>
Back
</Button>
)}

{step !== EDeployRoundsStep.REVIEW && (
<Button size="auto" variant="primary" onClick={handleOnClickNextStep}>
Next
</Button>
)}

{step === EDeployRoundsStep.REVIEW && (
<IconButton
disabled={isPending || !address || !isCorrectNetwork}
icon={isPending ? Spinner : null}
isLoading={isPending}
size="auto"
type="submit"
variant="primary"
>
{isUploading ? "Uploading..." : "Submit"}
</IconButton>
)}
</div>
);
};
Loading

0 comments on commit 3fe14f4

Please sign in to comment.