Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions anonymousVoting/clientAnonymousVoting/src/App.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Navbar from './components/Navbar';
import Explorer from "./components/Explorer";
import { BrowserRouter as Router, Route, Routes,Navigate } from 'react-router-dom'
import 'bootstrap/dist/css/bootstrap.css';

Expand Down Expand Up @@ -31,6 +32,7 @@ function App() {
// }else{
ret =
<Routes>
<Route path="/explorer" element={<Explorer />} />
<Route path="/" element={<Navigate to="/auth" />} />
<Route path="/auth" element={<Register/>} />
<Route path="/voting/:id" element={<VotingPage/>} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { ethers } from 'ethers';

import { useDispatch, useSelector } from 'react-redux'
import { selectNetwork, selectCorrectNetwork, setNetwork, setCorrectNetwork } from '../store/home.slice';

import Modal from 'react-bootstrap/Modal';


Expand Down Expand Up @@ -124,4 +123,4 @@ const ConnectWallet = () => {
);
}

export default ConnectWallet;
export default ConnectWallet;
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import styles from './CreateProcessPage.module.css';
import {ethers} from 'ethers';

//web3 imports
import { deployVotingProcess, deployTestContract, getTestContract } from '../web3/contracts'
import { useState, useEffect, useRef } from 'react';
import { deployVotingProcess} from '../web3/contracts'
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';


Expand All @@ -27,35 +27,44 @@ const CreateProcess = () => {
const [open, setOpen] = useState(false);
const [transactionResult, setTransactionResult] = useState(null);

const refValue = useRef(false);
// const refValue = useRef(false);

const createProcess = async (e) => {
e.preventDefault();
console.log("name: ", name);
//format proposals
let proposalArray = formatProposals(proposals);
//check form inputs
if(!isFormValid()){
window.alert("Form is not valid");
return;
}
const createProcess = async (e) => {
e.preventDefault();

if (!isFormValid()) {
window.alert("Form is not valid");
return;
}

try {
setPending(true);
refValue.current = true;
//deploy new process contract
const result = await deployVotingProcess(name, description, proposalArray,1000000,1000000);

const proposalArray = formatProposals(proposals);
const result = await deployVotingProcess(
name,
description,
proposalArray,
1000000,
1000000
);

setTransactionResult(result);
setShow(true);

refValue.current = false;
} catch (err) {
console.error(err);
window.alert("Transaction failed");
} finally {
setPending(false);

setShow(true);
}
};


const isFormValid = () => {
if(proposals < 2)
return false;
return true;
}
return proposals.split(',').length >= 2;
};
Comment on lines 64 to +66
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Validation doesn't reject empty proposals after trimming.

The validation only counts commas but doesn't verify that trimmed proposals are non-empty. Input like "proposal1, , , proposal2" or " , , " would pass validation but result in empty proposal strings.

Filter and validate trimmed proposals.

🔎 Proposed fix
 const isFormValid = () => {
-    return proposals.split(',').length >= 2;
+    const trimmedProposals = proposals.split(',').map(p => p.trim()).filter(p => p.length > 0);
+    return trimmedProposals.length >= 2;
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const isFormValid = () => {
if(proposals < 2)
return false;
return true;
}
return proposals.split(',').length >= 2;
};
const isFormValid = () => {
const trimmedProposals = proposals.split(',').map(p => p.trim()).filter(p => p.length > 0);
return trimmedProposals.length >= 2;
};
🤖 Prompt for AI Agents
In anonymousVoting/clientAnonymousVoting/src/components/CreateProcessPage.js
around lines 64 to 66, the isFormValid function currently counts commas and can
treat empty or whitespace-only entries as valid; change the validation to split
proposals on commas, map over parts and trim each one, filter out any empty
strings, and then require that the resulting array has length >= 2 so only
non-empty trimmed proposals count as valid.



const formatProposals = (input) => {
let proposals = input.split(',');
Expand All @@ -67,9 +76,6 @@ const CreateProcess = () => {
}


useEffect(() => {
// setPending(!pending);
}, [pending])

return (
<div >
Expand Down Expand Up @@ -105,11 +111,27 @@ const CreateProcess = () => {
/>
</div>
<div>
<button className="baseButton">Create new process</button>
<button
className="baseButton"
type="submit"
disabled={pending}
>
{pending ? (
<>
<Spinner
animation="border"
size="sm"
style={{ marginRight: "8px" }}
/>
Creating...
</>
) : (
"Create new process"
)}
</button>

</div>
{refValue.current == true && <div style={{marginTop: "2em"}}>
<Spinner animation="border" />
</div>}

</form>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
Expand Down
10 changes: 10 additions & 0 deletions anonymousVoting/clientAnonymousVoting/src/components/Explorer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
function Explorer() {
return (
<div style={{ padding: "20px" }}>
<h2>Explorer</h2>
<p>Blockchain explorer coming soon.</p>
</div>
);
}

export default Explorer;
25 changes: 22 additions & 3 deletions anonymousVoting/clientAnonymousVoting/src/components/Navbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,28 @@ function Navbar({header, infoText, pictureUrl}) {
</div>

<div className="navbarMenuOption">
<img src="/assets/settings.png" className="navbarMenuIcon navbarMenuLeft" alt="settings"/>
<Link to="/"><img src="/assets/logout.png" className="navbarMenuIcon" alt="logout"/></Link>
</div>
<img
src="/assets/settings.png"
className="navbarMenuIcon navbarMenuLeft"
alt="settings"
/>

<Link to="/explorer">
<img
src="/assets/explorer.png"
className="navbarMenuIcon"
alt="explorer"
/>
</Link>

<Link to="/">
<img
src="/assets/logout.png"
className="navbarMenuIcon"
alt="logout"
/>
</Link>
</div>
</nav>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,52 +2,61 @@ import { useState } from 'react';
import { Flex, Modal, Button, Card } from "rimble-ui";
import { ethers } from "ethers";
import ElectionOrganiser from "../../build/ElectionOrganizer.json";
import {successtoast, dangertoast } from '../utilities/Toasts';
import { successtoast, dangertoast } from '../utilities/Toasts';
import { toast } from "react-toastify";
import {addProposal} from '../../web3/contracts';
import { addProposal } from '../../web3/contracts';

export function AddCandidateModal({ electionId }) {
const [isOpen, setIsOpen] = useState(false);

const [candidateDetail, setCandidateDetail] = useState({
name: '',
description: ''
});

// ADDED: terms acceptance state
const [acceptedTerms, setAcceptedTerms] = useState(false);

const handleCandidateDetailChange = (e) => {
const { name, value } = e.target;
setCandidateDetail({
...candidateDetail,
[name]: value
});
}

};

const handleSubmitCandidate = async (e) => {
let id ;
let id;
e.preventDefault();

// ✅ ADDED: enforce terms acceptance
if (!acceptedTerms) {
toast.error("You must accept the Terms & Conditions");
return;
}

try {


let tx = await addProposal(electionId,ethers.utils.toUtf8Bytes(candidateDetail.name.trim()));

await tx.wait();
console.log(tx);
// successtoast(id, "Candidate Added Successfully")


} catch(err) {
dangertoast(id ,"Candidate Addition Failed")
let tx = await addProposal(
electionId,
ethers.utils.toUtf8Bytes(candidateDetail.name.trim())
);

await tx.wait();
console.log(tx);

// successtoast(id, "Candidate Added Successfully")
setIsOpen(false);
setAcceptedTerms(false);
} catch (err) {
dangertoast(id, "Candidate Addition Failed");
console.log(err);
}

}
}
};

const closeModal = e => {
e.preventDefault();
setIsOpen(false);
setAcceptedTerms(false); // ✅ reset
};

const openModal = e => {
Expand All @@ -57,14 +66,14 @@ export function AddCandidateModal({ electionId }) {

return (
<div>
<div onClick={openModal} style={{cursor: "pointer"}}>
<font size = '2'>Add Candidate</font>
<div onClick={openModal} style={{ cursor: "pointer" }}>
<font size='2'>Add Candidate</font>
</div>

<Modal isOpen={isOpen}>
<Card width={"90%"} height={"max-content"} p={0} style={{maxWidth: "500px"}}>
<Card width={"90%"} height={"max-content"} p={0} style={{ maxWidth: "500px" }}>
<Button.Text
style={{margin: "0px"}}
style={{ margin: "0px" }}
icononly
icon={"Close"}
color={"moon-gray"}
Expand All @@ -76,49 +85,64 @@ export function AddCandidateModal({ electionId }) {
onClick={closeModal}
/>

<div style={{margin: "10px", maxWidth: "700px", width: "90%"}}>
<div style={{ margin: "10px", maxWidth: "700px", width: "90%" }}>
<h5>Add candidates</h5>

<br/>
<br />

<div>
<b>Canidate Name</b>
<br/>
<input
className="form-control"
<br />

<input
className="form-control"
placeholder="Name of the candidate"
name="name"
value={candidateDetail.name}
onChange={handleCandidateDetailChange}
style={{marginTop: "15px"}}
style={{ marginTop: "15px" }}
/>
<br /><br />

<b>Canidate Description</b>
<br/>
<br />

<textarea
className="form-control"
className="form-control"
placeholder="Name of the candidate"
name="description"
rows={6}
value={candidateDetail.description}
onChange={handleCandidateDetailChange}
style={{marginTop: "15px"}}
/>
style={{ marginTop: "15px" }}
/>

<br /><br />

{/* ADDED: Terms & Conditions checkbox */}
<div>
<label style={{ cursor: "pointer" }}>
<input
type="checkbox"
checked={acceptedTerms}
onChange={(e) => setAcceptedTerms(e.target.checked)}
style={{ marginRight: "8px" }}
/>
I accept the Terms & Conditions
</label>
</div>
</div>
</div>

<Flex
px={4}
py={3}
justifyContent={"flex-end"}
>

<Flex px={4} py={3} justifyContent={"flex-end"}>
<Button.Outline onClick={closeModal}>Cancel</Button.Outline>
<Button ml={3} type="submit" onClick={handleSubmitCandidate}>Confirm</Button>
<Button
ml={3}
type="submit"
onClick={handleSubmitCandidate}
disabled={!acceptedTerms} // ✅ ADDED
>
Confirm
</Button>
</Flex>
</Card>
</Modal>
Expand Down
Loading