Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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 @@ -4,7 +4,7 @@ import { useState } from 'react';
import { ethers } from 'ethers';

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

import Modal from 'react-bootstrap/Modal';

Expand Down
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;
};


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>
Comment on lines 16 to 39
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for explorer.png in common asset locations
fd -t f "explorer.png" anonymousVoting/clientAnonymousVoting/public anonymousVoting/clientAnonymousVoting/src

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 135


🏁 Script executed:

# Also check the directory structure of assets
ls -la anonymousVoting/clientAnonymousVoting/public/assets/ 2>/dev/null || echo "Assets directory structure not found, checking alternative locations"
find anonymousVoting/clientAnonymousVoting -type d -name "assets" -o -name "public" 2>/dev/null | head -20

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 1683


🏁 Script executed:

# Read the full Navbar.js file to understand logout behavior
cat -n anonymousVoting/clientAnonymousVoting/src/components/Navbar.js

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 1439


🏁 Script executed:

# Search for logout handlers and auth context
rg -i "logout|disconnectWallet|clearAuth" anonymousVoting/clientAnonymousVoting/src --type js --type jsx -B 2 -A 5

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 98


🏁 Script executed:

# Check for context providers and auth state management
fd -t f "\.js$|\.jsx$" anonymousVoting/clientAnonymousVoting/src | xargs grep -l "Context\|useContext\|provider" | head -10

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 721


🏁 Script executed:

# Check the settings icon - see if it has any handler in parent or if it's a separate component
rg "settings\.png" anonymousVoting/clientAnonymousVoting/src -B 5 -A 5

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 1005


🏁 Script executed:

# Search for logout logic without file type filter
rg -i "logout|disconnect.*wallet|clear.*auth|signOut" anonymousVoting/clientAnonymousVoting/src -B 2 -A 5

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 880


🏁 Script executed:

# Check how Navbar is used in parent components
rg "Navbar" anonymousVoting/clientAnonymousVoting/src -B 2 -A 2

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 3507


🏁 Script executed:

# Check the Dashboard or main App component for logout handling
cat -n anonymousVoting/clientAnonymousVoting/src/components/Dashboard.js | head -100

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 3659


🏁 Script executed:

# Check if there's any logout or disconnect logic in Dashboard
rg -i "navigate|useNavigate|history" anonymousVoting/clientAnonymousVoting/src/components/Dashboard.js

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 53


🏁 Script executed:

# Check App.js for routing and logout
cat -n anonymousVoting/clientAnonymousVookie/src/App.js | head -80

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 151


🏁 Script executed:

# Search for wallet provider/context to see if there's disconnect logic
rg -i "provider|context|wallet" anonymousVoting/clientAnonymousVoting/src --max-count 20

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 7321


🏁 Script executed:

# Check if there's a ConnectWallet component that might handle disconnection
cat -n anonymousVoting/clientAnonymousVoting/src/components/ConnectWallet.js

Repository: AOSSIE-Org/Agora-Blockchain

Length of output: 4981


Replace the empty explorer.png file with actual icon content.

The /assets/explorer.png file exists but is empty (0 bytes) and will not render. Additionally, the logout link navigates to "/" without performing any logout action such as clearing authentication state or disconnecting the wallet. If logout behavior is intended to be functional, add appropriate state cleanup and wallet disconnection logic; otherwise, the logout link is non-functional as currently implemented.

</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;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix undefined variable usage in error handler.

The variable id is declared on line 29 but never assigned a value. It will be undefined when passed to dangertoast on line 51, which may cause incorrect toast behavior.

🔎 Proposed fix

Either remove the id variable entirely if dangertoast can handle it, or assign it properly:

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

And update the error handler:

     } catch (err) {
-        dangertoast(id, "Candidate Addition Failed");
+        dangertoast(null, "Candidate Addition Failed");
         console.log(err);
     }

Also applies to: 51-51

🤖 Prompt for AI Agents
In
anonymousVoting/clientAnonymousVoting/src/components/modals/AddCandidateModal.js
around line 29 (and error use at line 51), the local variable `id` is declared
but never assigned so it will be undefined when passed to `dangertoast`; either
remove the unused `id` variable and call `dangertoast` with only the message (or
with a valid fallback), or assign `id` an appropriate value before the error
handler runs (for example a generated unique id or an existing candidate/form
id) and then pass that defined value into `dangertoast`; update the error
handler to not rely on an undefined `id` (use a fallback or omit the parameter)
so the toast behaves correctly.

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();
Comment on lines 38 to +44
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Validate candidate name is not empty after trimming.

The code trims the candidate name but doesn't validate that it's non-empty before submission. Users could submit candidates with only whitespace characters, resulting in empty names.

🔎 Proposed fix
     // ✅ ADDED: enforce terms acceptance
     if (!acceptedTerms) {
         toast.error("You must accept the Terms & Conditions");
         return;
     }
+
+    // Validate candidate name is not empty
+    if (!candidateDetail.name.trim()) {
+        toast.error("Candidate name is required");
+        return;
+    }

     try {
📝 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
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();
// ✅ ADDED: enforce terms acceptance
if (!acceptedTerms) {
toast.error("You must accept the Terms & Conditions");
return;
}
// Validate candidate name is not empty
if (!candidateDetail.name.trim()) {
toast.error("Candidate name is required");
return;
}
try {
let tx = await addProposal(
electionId,
ethers.utils.toUtf8Bytes(candidateDetail.name.trim())
);
await tx.wait();
🤖 Prompt for AI Agents
In
anonymousVoting/clientAnonymousVoting/src/components/modals/AddCandidateModal.js
around lines 38 to 44, the code trims the candidate name but doesn't check that
the trimmed value is non-empty before calling addProposal; update the handler to
compute const name = candidateDetail.name?.trim() and if (!name) abort the
submission: show a user-facing validation error (set component state or call the
existing error/toast mechanism) and return early so addProposal is not called;
only pass the validated non-empty name to ethers.utils.toUtf8Bytes and proceed
with the transaction when valid.

console.log(tx);

// successtoast(id, "Candidate Added Successfully")
setIsOpen(false);
setAcceptedTerms(false);
Comment on lines +47 to +49
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Restore success feedback and reset form state.

The success toast on line 47 is commented out, leaving users without confirmation that their candidate was added successfully. Additionally, candidateDetail state is not reset after successful submission, so the form will display previous values when reopened.

🔎 Proposed fix
     await tx.wait();
     console.log(tx);

-    // successtoast(id, "Candidate Added Successfully")
+    successtoast(null, "Candidate Added Successfully");
     setIsOpen(false);
     setAcceptedTerms(false);
+    setCandidateDetail({ name: '', description: '' });
 } catch (err) {
🤖 Prompt for AI Agents
In
anonymousVoting/clientAnonymousVoting/src/components/modals/AddCandidateModal.js
around lines 47 to 49, restore the success feedback and clear form state after a
successful submission: re-enable the success toast call (successtoast or the
app's toast utility) so users receive confirmation, and reset the
candidateDetail state to its initial empty/default values (and any other form
fields) before closing the modal; keep setAcceptedTerms(false) as is and ensure
the toast is called before setIsOpen(false) so the message is visible.

} 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>
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

Fix typo in user-facing labels.

"Canidate" is misspelled on lines 93 and 106. It should be "Candidate".

🔎 Proposed fix
-<b>Canidate Name</b>
+<b>Candidate Name</b>
-<b>Canidate Description</b>
+<b>Candidate Description</b>

Also applies to: 106-106

🤖 Prompt for AI Agents
In
anonymousVoting/clientAnonymousVoting/src/components/modals/AddCandidateModal.js
around lines 93 and 106, there are misspelled user-facing labels ("Canidate") —
change both occurrences to "Candidate" in the rendered text (and any related
aria-labels or test IDs if they use the same string) so the UI displays the
correct spelling.

<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" }}
/>
Comment on lines 109 to +117
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

Correct placeholder text for description field.

The placeholder text on line 111 says "Name of the candidate" but this field is for the candidate's description.

🔎 Proposed fix
 <textarea
     className="form-control"
-    placeholder="Name of the candidate"
+    placeholder="Description of the candidate"
     name="description"
     rows={6}
     value={candidateDetail.description}
     onChange={handleCandidateDetailChange}
     style={{ marginTop: "15px" }}
 />
📝 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
<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" }}
/>
<textarea
className="form-control"
placeholder="Description of the candidate"
name="description"
rows={6}
value={candidateDetail.description}
onChange={handleCandidateDetailChange}
style={{ marginTop: "15px" }}
/>
🤖 Prompt for AI Agents
In
anonymousVoting/clientAnonymousVoting/src/components/modals/AddCandidateModal.js
around lines 109 to 117, the textarea's placeholder incorrectly reads "Name of
the candidate" but this field holds the candidate's description; update the
placeholder to something appropriate (e.g., "Description of the candidate" or
"Candidate description"), and keep the rest of the props unchanged so the value
and onChange continue to work as expected.


<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