diff --git a/client/.env.example b/client/.env.example index 16d49007..be1741bf 100644 --- a/client/.env.example +++ b/client/.env.example @@ -1,4 +1,4 @@ -NEXT_PUBLIC_SEPOLIA_RPC_URL = ENTER_RPC_URL +NEXT_PUBLIC_SEPOLIA_RPC_URL = http://127.0.0.1:8545 NEXT_PUBLIC_AMOY_RPC_URL = ENTER_RPC_URL NEXT_PUBLIC_FUJI_RPC_URL = ENTER_RPC_URL NEXT_PUBLIC_PINATA_JWT = ENTER_PINATA_API_KEY \ No newline at end of file diff --git a/client/app/components/Hooks/GetElectionInformation.ts b/client/app/components/Hooks/GetElectionInformation.ts index e981f09c..aaa2b0fd 100644 --- a/client/app/components/Hooks/GetElectionInformation.ts +++ b/client/app/components/Hooks/GetElectionInformation.ts @@ -14,7 +14,7 @@ export const useElectionInformation = ({ const electionContract = { abi: Election, address: electionAddress, - chainId: sepolia.id, + // chainId: sepolia.id, }; const CCIPContract = { abi: CCIPSender, diff --git a/client/app/components/Hooks/GetMiniElectionInfo.ts b/client/app/components/Hooks/GetMiniElectionInfo.ts index f7ac89c8..251c3d1f 100644 --- a/client/app/components/Hooks/GetMiniElectionInfo.ts +++ b/client/app/components/Hooks/GetMiniElectionInfo.ts @@ -8,7 +8,7 @@ export const useMiniElectionInfo = ({ electionAddress: `0x${string}`; }) => { const { data: electionInfo, isLoading } = useReadContract({ - chainId: sepolia.id, + // chainId: sepolia.id, abi: Election, address: electionAddress, functionName: "electionInfo", @@ -22,7 +22,7 @@ export const useMiniOwnerInfo = ({ electionAddress: `0x${string}`; }) => { const { data: owner, isLoading: loadingOwner } = useReadContract({ - chainId: sepolia.id, + // chainId: sepolia.id, abi: Election, address: electionAddress, functionName: "owner", diff --git a/client/app/components/Hooks/GetOpenElections.ts b/client/app/components/Hooks/GetOpenElections.ts index 0c3d6efb..717ee4cb 100644 --- a/client/app/components/Hooks/GetOpenElections.ts +++ b/client/app/components/Hooks/GetOpenElections.ts @@ -5,7 +5,7 @@ import { useReadContract } from "wagmi"; export const useOpenElection = () => { const { data: elections, isLoading } = useReadContract({ - chainId: sepolia.id, + // chainId: sepolia.id, abi: ElectionFactory, address: ELECTION_FACTORY_ADDRESS, functionName: "getOpenElections", diff --git a/client/app/components/Hooks/GetUserElections.ts b/client/app/components/Hooks/GetUserElections.ts index d5ebbd01..88d6b32e 100644 --- a/client/app/components/Hooks/GetUserElections.ts +++ b/client/app/components/Hooks/GetUserElections.ts @@ -5,7 +5,7 @@ import { useReadContract } from "wagmi"; export const useUserElections = () => { const { data: elections, isLoading } = useReadContract({ - chainId: sepolia.id, + // chainId: sepolia.id, abi: ElectionFactory, address: ELECTION_FACTORY_ADDRESS, functionName: "getOpenElections", diff --git a/client/app/constants.ts b/client/app/constants.ts index 7f18203b..9a2e850b 100644 --- a/client/app/constants.ts +++ b/client/app/constants.ts @@ -1,8 +1,8 @@ -// export const ELECTION_FACTORY_ADDRESS = -// "0x64c720eBD5227bba57a5E8282893e71087cCcBb8"; -export const ELECTION_FACTORY_ADDRESS = - "0x2F432d25CceD9442882188801F47c596Eaaf176d"; -// export const CCIP_FUJI_ADDRESS = "0xf267f0603672E791779E52B153BD9A39C9928767"; +export const ELECTION_FACTORY_ADDRESS = + process.env.NODE_ENV === "development" + ? "0x5FbDB2315678afecb367f032d93F642f64180aa3" // Local Hardhat Address + : "0x64c720eBD5227bba57a5E8282893e71087cCcBb8"; // Production Sepolia Address + export const CCIP_FUJI_ADDRESS = "0xca2d3fc837b349caf17cbd965856fc33120b1c0f"; export const SEPOLIA_CHAIN_SELECTOR = BigInt("16015286601757825753"); export const LINK_FUJI = "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846"; @@ -11,4 +11,4 @@ export const AVATARS = [ "/avatar1.png", "/avatar2.png", "/avatar3.png", -]; +]; \ No newline at end of file diff --git a/client/app/create/page.tsx b/client/app/create/page.tsx index d8f62dad..ffdb5dac 100644 --- a/client/app/create/page.tsx +++ b/client/app/create/page.tsx @@ -9,8 +9,8 @@ import { DatePicker } from "rsuite"; import toast, { Toaster } from "react-hot-toast"; import { ErrorMessage } from "../helpers/ErrorMessage"; import { CalendarIcon } from "@heroicons/react/24/outline"; -import { sepolia } from "viem/chains"; -import { ArrowPathIcon , PlusIcon, TrashIcon} from "@heroicons/react/24/solid"; +import { sepolia, hardhat } from "viem/chains"; +import { ArrowPathIcon, PlusIcon, TrashIcon } from "@heroicons/react/24/solid"; import { useRouter } from "next/navigation"; import ElectionInfoPopup from "../components/Modal/ElectionInfoPopup"; @@ -20,12 +20,15 @@ const CreatePage: React.FC = () => { const { switchChain } = useSwitchChain(); const { chain } = useAccount(); const { writeContractAsync } = useWriteContract(); + const isDevelopment = process.env.NODE_ENV === 'development'; const [startTime, setStartTime] = useState(new Date()); const [endTime, setEndTime] = useState(new Date()); - const [candidates,setCandidates] = useState([]) + const [candidates, setCandidates] = useState([]) const changeChain = () => { - switchChain({ chainId: sepolia.id }); - } + switchChain({ + chainId: process.env.NODE_ENV === 'development' ? hardhat.id : sepolia.id + }); +} interface Candidate { name: string; description: string; @@ -33,12 +36,12 @@ const CreatePage: React.FC = () => { const addCandidate = () => { setCandidates([...candidates, { name: "", description: "" }]); }; - + const removeCandidate = (index: number) => { const newCandidates = candidates.filter((_, i) => i !== index); setCandidates(newCandidates); }; - + const updateCandidate = (index: number, field: keyof Candidate, value: string) => { const newCandidates = candidates.map((candidate, i) => { if (i === index) { @@ -55,10 +58,10 @@ const CreatePage: React.FC = () => { const description = formData.get("description") as string; const ballotType = BigInt(selectedBallot); - if (candidates.length<2){ + if (candidates.length < 2) { toast.error("At least 2 candidates are required!"); return; - + } if (!startTime || !endTime) { @@ -73,11 +76,17 @@ const CreatePage: React.FC = () => { toast.error("Invalid timing. End time must be after start time."); return; } - if(candidates.length>0 && candidates.some(candidate=>!candidate.name || !candidate.description)){ + const normalizedCandidates = candidates.map((candidate) => ({ + ...candidate, + name: candidate.name.trim(), + description: candidate.description.trim(), + })); + + if (normalizedCandidates.some(candidate => !candidate.name || !candidate.description)) { toast.error("please enter all candidate information or remove empty candidates.") - return + return } - // passed candidates to the create election function + // passed candidates to the create election function try { await writeContractAsync({ address: ELECTION_FACTORY_ADDRESS, @@ -85,7 +94,11 @@ const CreatePage: React.FC = () => { functionName: "createElection", args: [ { startTime: start, endTime: end, name, description }, // ElectionInfo object - candidates.map((c, index) => ({ candidateID: BigInt(index), name: c.name, description: c.description })), + normalizedCandidates.map((candidate, index) => ({ + candidateID: BigInt(index), + name: candidate.name, + description: candidate.description, + })), ballotType, ballotType, ], @@ -104,17 +117,17 @@ const CreatePage: React.FC = () => { return ( - +

Create New Election

@@ -129,7 +142,7 @@ const CreatePage: React.FC = () => { label="Description" placeholder="Describe the election" /> - {/* candidate section shows placeholder if empty candidate and allows to add cnadidates*/ } + {/* candidate section shows placeholder if empty candidate and allows to add cnadidates*/}

Candidates

@@ -144,7 +157,7 @@ const CreatePage: React.FC = () => { Add Candidate
- + {candidates.length === 0 ? (

No candidates added yet. Click "Add Candidate" to begin adding candidates. @@ -233,7 +246,7 @@ const CreatePage: React.FC = () => { - {chain?.id !== sepolia.id && } + {chain?.id !== sepolia.id && (!isDevelopment || chain?.id !== hardhat.id) && } ); @@ -341,7 +354,7 @@ const ChainSwitchModal: React.FC = ({ onSwitch }) => ( className="bg-white rounded-lg p-8 shadow-xl text-center" >

- Creating Elections is supported only on Sepolia + Creating Elections is supported only on Sepolia (or Hardhat in development).