Skip to content

Commit

Permalink
added a create poll modal
Browse files Browse the repository at this point in the history
  • Loading branch information
yashgo0018 committed Mar 23, 2024
1 parent 885ed46 commit d011454
Show file tree
Hide file tree
Showing 6 changed files with 4,090 additions and 2 deletions.
156 changes: 156 additions & 0 deletions packages/nextjs/app/admin/_components/CreatePollModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import { useEffect, useState } from "react";
import { Dialog } from "@headlessui/react";
import { LuCross } from "react-icons/lu";
import { MdEdit } from "react-icons/md";
import { RxCross2 } from "react-icons/rx";
import Modal from "~~/components/Modal";
import { useScaffoldContractWrite } from "~~/hooks/scaffold-eth";

export default function Example({ show, setOpen }: { show: boolean; setOpen: (value: boolean) => void }) {
const [pollData, setPollData] = useState({ title: "Dummy Title", options: [""] });
const [isEditingTitle, setIsEditingTitle] = useState<boolean>(false);

const handleAddOption = () => {
setPollData({ ...pollData, options: [...pollData.options, ""] });
};

const handleOptionChange = (index: number, value: string) => {
const newOptions = [...pollData.options];
newOptions[index] = value;
setPollData({ ...pollData, options: newOptions });
};

const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setPollData({ ...pollData, title: e.target.value });
};

const handleEditTitleClick = () => {
setIsEditingTitle(true);
};

const handleSaveTitleClick = () => {
setIsEditingTitle(false);
};

function removeOptions(index: number): void {
const newOptions = [...pollData.options];
newOptions.splice(index, 1);
setPollData({ ...pollData, options: newOptions });
}

const { writeAsync, data, isLoading } = useScaffoldContractWrite({
contractName: "PollManager",
functionName: "createPoll",
args: [pollData?.title, pollData?.options || [], "", BigInt(pollData?.options?.length || 0)],
});

console.log(data);

useEffect(() => {
// setIsLoading(isLoading);
}, [isLoading]);

async function onSubmit() {
console.log("A");
try {
await writeAsync();
} catch (err) {
console.log(err);
}

setOpen(false);
}

return (
<Modal show={show} setOpen={setOpen}>
<div className="mt-3 text-center sm:mt-5 mb-6">
<Dialog.Title as="h3" className="font-bold leading-6 text-2xl text-neutral-content">
Create a Poll
</Dialog.Title>
</div>

<div className="flex justify-between items-center mb-4">
{isEditingTitle ? (
<input
type="text"
className="border border-gray-300 rounded-md px-4 py-2 w-full focus:outline-none bg-white text-black"
placeholder="Enter Poll Title"
value={pollData.title}
onChange={handleTitleChange}
/>
) : (
<h2 className="text-xl font-semibold font-mono text-neutral-content mb-0 mt-2">{pollData.title}</h2>
)}

<label className="btn btn-circle swap swap-rotate ml-3 bg-primary hover:bg-primary-content text-primary-content hover:text-primary">
<input
type="checkbox"
onChange={() => {
if (isEditingTitle) {
handleSaveTitleClick();
} else {
handleEditTitleClick();
}
}}
/>

<div className="swap-off fill-current">
<MdEdit size={25} />
</div>

<div className="swap-on fill-current">
<RxCross2 size={25} />
</div>
</label>
</div>

<div className="w-full h-[0.5px] bg-[#3647A4] shadow-2xl my-5" />

<div className="mb-3 text-neutral-content">Create the options</div>

{pollData.options.map((option, index) => (
<div key={index} className="mb-2 flex flex-row">
<input
type="text"
className="border border-[#3647A4] bg-secondary rounded-md px-4 py-2 w-full focus:outline-none "
placeholder={`Candidate ${index + 1}`}
value={option}
onChange={e => handleOptionChange(index, e.target.value)}
/>
{index === pollData.options.length - 1 ? (
<button
className="btn btn-outline ml-4 text-primary hover:bg-primary hover:text-primary-content bg-primary-content"
onClick={handleAddOption}
>
<LuCross size={20} />
</button>
) : (
<button
className="btn btn-outline ml-4 text-primary hover:bg-primary hover:text-primary-content bg-primary-content"
onClick={() => removeOptions(index)}
>
<RxCross2 size={20} />
</button>
)}
</div>
))}

<div className="mt-5 sm:mt-6 sm:grid sm:grid-flow-row-dense sm:grid-cols-2 sm:gap-3">
<button
type="button"
className="inline-flex w-full justify-center rounded-md bg-primary text-primary-content px-3 py-2 font-semibold shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 sm:col-start-2"
onClick={onSubmit}
>
Create
</button>
<button
type="button"
className="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:col-start-1 sm:mt-0"
onClick={() => setOpen(false)}
>
Cancel
</button>
</div>
</Modal>
);
}
47 changes: 47 additions & 0 deletions packages/nextjs/app/admin/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"use client";

import { useEffect, useState } from "react";
import { redirect } from "next/navigation";
import CreatePollModal from "./_components/CreatePollModal";
import { useAccount } from "wagmi";
import { useScaffoldContractRead } from "~~/hooks/scaffold-eth";

export default function AdminPage() {
const { address } = useAccount();
const [openCreatePollModal, setOpenCreatePollModal] = useState(false);

const { data: admin } = useScaffoldContractRead({ contractName: "MACI", functionName: "owner" });

useEffect(() => {
if (!admin || !address) return;
if (address !== admin) {
redirect("/");
}
}, [address, admin]);

const { data: totalPolls } = useScaffoldContractRead({
contractName: "PollManager",
functionName: "totalPolls",
});

const { data: polls } = useScaffoldContractRead({
contractName: "PollManager",
functionName: "paginatePolls",
args: [1n, 10n],
});

console.log(totalPolls);
console.log(polls);

return (
<div className="container mx-auto pt-10">
<div className="flex">
<div className="flex-1 text-2xl">Polls</div>
<button className="bg-primary px-3 py-2 rounded-lg" onClick={() => setOpenCreatePollModal(true)}>
Create Poll
</button>
</div>
<CreatePollModal setOpen={setOpenCreatePollModal} show={openCreatePollModal} />
</div>
);
}
48 changes: 48 additions & 0 deletions packages/nextjs/components/Modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { Fragment } from "react";
import { Dialog, Transition } from "@headlessui/react";

export default function Modal({
show,
setOpen,
children,
}: {
show: boolean;
setOpen: (value: boolean) => void;
children: React.ReactNode;
}) {
return (
<Transition.Root show={show} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={setOpen}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<div className="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity" />
</Transition.Child>

<div className="fixed inset-0 z-10 w-screen overflow-y-auto">
<div className="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0">
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
enterTo="opacity-100 translate-y-0 sm:scale-100"
leave="ease-in duration-200"
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-neutral px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6">
{children}
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition.Root>
);
}
Loading

0 comments on commit d011454

Please sign in to comment.