generated from scaffold-eth/scaffold-eth-2
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
885ed46
commit d011454
Showing
6 changed files
with
4,090 additions
and
2 deletions.
There are no files selected for viewing
156 changes: 156 additions & 0 deletions
156
packages/nextjs/app/admin/_components/CreatePollModal.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
} |
Oops, something went wrong.