feature: My votes will be stored and shown in the popup.

This commit is contained in:
Raja Ilayaperumal
2022-09-09 00:07:28 +05:30
parent 69174602ff
commit 578e0b132a
5 changed files with 269 additions and 228 deletions

View File

@@ -1,28 +1,22 @@
import Link from "next/link";
import { useEffect, useRef, useState } from "react";
import { Button, Modal, Spinner } from "react-bootstrap";
import { Button } from "react-bootstrap";
import Dropdown from 'react-bootstrap/Dropdown';
import DropdownButton from 'react-bootstrap/DropdownButton';
import { authenticate, getFileFromGaia, signOut, userSession } from "../../services/auth";
import { convertToDisplayDateFormat, formStacksExplorerUrl, getDomainNamesFromBlockchain } from "../../services/utils";
import styles from "../../styles/Dashboard.module.css";
import { authenticate, signOut, switchAccount, userSession } from "../../services/auth";
import { getDomainNamesFromBlockchain } from "../../services/utils";
import MyVotePopup from "./MyVotesPopup";
export function DashboardNavBarComponent() {
// Variables
const [displayUsername, setDisplayUsername] = useState();
const [isUserSignedIn, setIsUserSignedIn] = useState(false);
// Add transaction confirmation popup
const [showMyTransactionsPopup, setShowMyTransactionsPopup] = useState(false);
const handleCloseMyTransactionsPopup = () =>
setShowMyTransactionsPopup(false);
const handleShowMyTransactionsPopup = () => setShowMyTransactionsPopup(true);
// List of transactions
const [transactions, setTransactions] = useState();
// Loading
const [isLoading, setIsLoading] = useState(false);
// My votes popup
const [showMyVotesPopup, setShowMyVotesPopup] = useState(false);
const handleCloseMyVotesPopup = () =>
setShowMyVotesPopup(false);
const handleShowMyVotesPopup = () => setShowMyVotesPopup(true);
// Feedback hidden button
const feedbackButton = useRef(null);
@@ -41,51 +35,6 @@ export function DashboardNavBarComponent() {
setDisplayUsername(_username);
}
// Show my transactions
const showMyTransactions = () => {
// Show transaction popup
handleShowMyTransactionsPopup();
// Start loading
setIsLoading(true);
// Store transaction to Gaia
getFileFromGaia("transactions_ballot.json").then(
(response) => {
if (response) {
const transactionsObj = JSON.parse(response);
if (
transactionsObj &&
transactionsObj.transactions &&
transactionsObj.transactions.length > 0
) {
setTransactions(transactionsObj.transactions.reverse());
} else {
// Show empty list
setTransactions([]);
}
} else {
// Show empty list
setTransactions([]);
}
// Stop loading
setIsLoading(false);
},
(error) => {
// File does not exit in gaia
if (error && error.code == "does_not_exist") {
// Show empty list
setTransactions([]);
}
// Stop loading
setIsLoading(false);
}
);
};
const loadBlockSurveyWidgetScript = () => {
// If script is not loaded, load first
if (!window.blocksurvey) {
@@ -149,11 +98,19 @@ export function DashboardNavBarComponent() {
>
<Dropdown.Item
onClick={() => {
showMyTransactions();
handleShowMyVotesPopup();
}}
>
My transactions
My Votes
</Dropdown.Item>
<Dropdown.Item
onClick={() => {
switchAccount();
}}
>
Switch account
</Dropdown.Item>
<Dropdown.Divider />
<Dropdown.Item
onClick={() => {
loadBlockSurveyWidgetScript();
@@ -172,88 +129,13 @@ export function DashboardNavBarComponent() {
</Button>
</div>
}
</div>
{/* My transactions popup */}
<Modal
show={showMyTransactionsPopup}
onHide={handleCloseMyTransactionsPopup}
keyboard={false}
centered
size="md"
>
{/* Header */}
<div className={styles.dashboard_modal_header_box}>
<div>My transactions</div>
<button
className={styles.dashboard_modal_close_icon_btn_box}
onClick={handleCloseMyTransactionsPopup}
>
<svg
width="10"
height="10"
viewBox="0 0 10 10"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M0.898377 0.898804C1.2108 0.586385 1.71733 0.586385 2.02975 0.898804L4.9996 3.86865L7.96945 0.898804C8.28186 0.586385 8.7884 0.586385 9.10082 0.898804C9.41324 1.21122 9.41324 1.71776 9.10082 2.03018L6.13097 5.00002L9.10082 7.96987C9.41324 8.28229 9.41324 8.78882 9.10082 9.10124C8.7884 9.41366 8.28186 9.41366 7.96945 9.10124L4.9996 6.13139L2.02975 9.10124C1.71733 9.41366 1.2108 9.41366 0.898377 9.10124C0.585958 8.78882 0.585958 8.28229 0.898377 7.96987L3.86823 5.00002L0.898377 2.03018C0.585958 1.71776 0.585958 1.21122 0.898377 0.898804Z"
fill="black"
/>
</svg>
</button>
</div>
{/* Body */}
<div
className={
styles.dashboard_modal_body_box +
" " +
styles.dashboard_transactions_modal_body_box
}
style={{ padding: "0px", marginBottom: "20px" }}
>
{
// Loading
isLoading ? (
<div style={{ textAlign: "center", padding: "10px" }}>
<Spinner animation="border" variant="secondary" size="md" />
</div>
) : // Once data found
transactions && transactions.length > 0 ? (
transactions.map((transaction, index) => (
<a
className={styles.dashboard_my_transactions_box}
key={index}
href={formStacksExplorerUrl(transaction.txId)}
target="_blank"
rel="noreferrer"
>
{/* Transactions id and date */}
<div style={{ display: "grid" }}>
{/* Tx id */}
<div className={styles.dashboard_transactions_id}>
{transaction.txId}
</div>
{/* Date */}
<div className={styles.dashboard_transactions_date}>
{convertToDisplayDateFormat(transaction.date)}
</div>
</div>
</a>
))
) : (
<div style={{ padding: "0px 20px 10px", fontSize: "14px" }}>
No transactions has been done yet.
</div>
)
}
</div>
</Modal>
{/* My votes popup */}
<MyVotePopup showMyVotesPopup={showMyVotesPopup}
handleCloseMyVotesPopup={handleCloseMyVotesPopup}
handleShowMyVotesPopup={handleShowMyVotesPopup}
/>
{/* Adding BlockSurvey script */}
<blocksurvey-widget

View File

@@ -0,0 +1,180 @@
import { useEffect, useState } from "react";
import { Modal, Spinner, Table } from "react-bootstrap";
import { getFileFromGaia } from "../../services/auth";
import { convertToDisplayDateFormat, formStacksExplorerUrl } from "../../services/utils";
import styles from "../../styles/Dashboard.module.css";
export default function MyVotePopup(props) {
const { showMyVotesPopup, handleCloseMyVotesPopup } = props;
// List of votes
const [votes, setVotes] = useState();
// Loading
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
getMyVotes();
}, []);
// Show my polls
const getMyVotes = () => {
// Start loading
setIsLoading(true);
// Store transaction to Gaia
getFileFromGaia("my_votes_ballot.json").then(
(response) => {
if (response) {
const myVotesObj = JSON.parse(response);
if (
myVotesObj &&
myVotesObj.votes &&
myVotesObj.votes.length > 0
) {
setVotes(myVotesObj.votes.reverse());
} else {
// Show empty list
setVotes([]);
}
} else {
// Show empty list
setVotes([]);
}
// Stop loading
setIsLoading(false);
},
(error) => {
// File does not exit in gaia
if (error && error.code == "does_not_exist") {
// Show empty list
setVotes([]);
}
// Stop loading
setIsLoading(false);
}
);
};
const getEachRow = (vote) => {
if (vote?.voteObject && vote?.optionsMap) {
return (
Object.keys(vote?.voteObject).map((optionId, optionIndex) => (
<div key={optionId}>
{vote?.optionsMap[optionId]}
</div>
))
);
}
return (<></>);
}
return (
<>
{/* My transactions popup */}
<Modal
show={showMyVotesPopup}
onHide={handleCloseMyVotesPopup}
keyboard={false}
centered
size="xl"
>
{/* Header */}
<div className={styles.dashboard_modal_header_box}>
<div>My votes</div>
<button
className={styles.dashboard_modal_close_icon_btn_box}
onClick={handleCloseMyVotesPopup}
>
<svg
width="10"
height="10"
viewBox="0 0 10 10"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M0.898377 0.898804C1.2108 0.586385 1.71733 0.586385 2.02975 0.898804L4.9996 3.86865L7.96945 0.898804C8.28186 0.586385 8.7884 0.586385 9.10082 0.898804C9.41324 1.21122 9.41324 1.71776 9.10082 2.03018L6.13097 5.00002L9.10082 7.96987C9.41324 8.28229 9.41324 8.78882 9.10082 9.10124C8.7884 9.41366 8.28186 9.41366 7.96945 9.10124L4.9996 6.13139L2.02975 9.10124C1.71733 9.41366 1.2108 9.41366 0.898377 9.10124C0.585958 8.78882 0.585958 8.28229 0.898377 7.96987L3.86823 5.00002L0.898377 2.03018C0.585958 1.71776 0.585958 1.21122 0.898377 0.898804Z"
fill="black"
/>
</svg>
</button>
</div>
{/* Body */}
<div
className={
styles.dashboard_modal_body_box +
" " +
styles.dashboard_transactions_modal_body_box
}
style={{ padding: "0px", marginBottom: "20px" }}
>
{
// Loading
isLoading ? (
<div style={{ textAlign: "center", padding: "10px" }}>
<Spinner animation="border" variant="secondary" size="md" />
</div>
) : // Once data found
votes && votes.length > 0 ? (
<div style={{ padding: "0px 20px 10px", fontSize: "14px" }}>
<Table striped bordered hover>
<thead>
<tr>
<th>Title</th>
<th>Voted Option</th>
<th>Voting Power</th>
<th>Voted At</th>
<th>Transaction</th>
</tr>
</thead>
<tbody>
{
votes && votes.length > 0 ? (
votes.map((vote, index) => (
<tr key={index}>
<td>
<a
className="ballot_link"
href={vote?.url}
target="_blank"
rel="noreferrer">
{vote?.title}
</a>
</td>
<td>{getEachRow(vote)}</td>
<td>{Object.values(vote?.voteObject)?.[0]}</td>
<td>{convertToDisplayDateFormat(vote.votedAt)}</td>
<td>
<a
className="ballot_link"
href={formStacksExplorerUrl(vote?.txId)}
target="_blank"
rel="noreferrer">
{vote?.txId?.substr(0, 10) + "..."}
</a>
</td>
</tr>
))
) : ""
}
</tbody>
</Table>
</div>
) : (
<div style={{ padding: "0px 20px 10px", fontSize: "14px" }}>
You have not cast your vote yet.
</div>
)
}
</div>
</Modal>
</>);
}

View File

@@ -69,56 +69,61 @@ export default function PollComponent(props) {
if (data?.txId) {
setTxId(data.txId);
// Store transaction to Gaia
getFileFromGaia("transactions_ballot.json").then(
(response) => {
if (response) {
const transactionsObj = JSON.parse(response);
if (transactionsObj && transactionsObj.transactions) {
transactionsObj.transactions.push({
txId: data.txId,
txRaw: data.txRaw,
date: Date.now(),
});
// Store on gaia
putFileToGaia(
"transactions_ballot.json",
JSON.stringify(transactionsObj),
{ dangerouslyIgnoreEtag: true }
);
}
}
},
(error) => {
// File does not exit in gaia
if (error && error.code == "does_not_exist") {
const transactionsObj = {
transactions: [
{
txId: data.txId,
txRaw: data.txRaw,
date: Date.now(),
},
],
};
// Store on gaia
putFileToGaia(
"transactions_ballot.json",
JSON.stringify(transactionsObj),
{ dangerouslyIgnoreEtag: true }
);
}
}
);
// Store my vote to Gaia
processMyVote(data);
// Show information popup
handleShow();
}
}
const processMyVote = (data) => {
// Store my vote to Gaia
getFileFromGaia("my_votes_ballot.json").then(
(response) => {
if (response) {
const myVotesObj = JSON.parse(response);
if (myVotesObj && myVotesObj.votes) {
saveMyVoteToGaia(myVotesObj, data);
}
}
},
(error) => {
// File does not exit in gaia
if (error && error.code == "does_not_exist") {
const myVotesObj = {
votes: [
],
};
saveMyVoteToGaia(myVotesObj, data);
}
}
);
}
const saveMyVoteToGaia = (myVotesObj, data) => {
myVotesObj.votes.push({
title: pollObject?.title,
url: publicUrl,
voteObject: voteObject,
optionsMap: optionsMap,
votedAt: Date.now(),
txId: data.txId,
txRaw: data.txRaw
});
// Store on gaia
putFileToGaia(
"my_votes_ballot.json",
JSON.stringify(myVotesObj),
{ dangerouslyIgnoreEtag: true }
);
}
const castMyVote = () => {
if (pollObject?.publishedInfo?.contractAddress && pollObject?.publishedInfo?.contractName) {
// Start processing

View File

@@ -56,6 +56,21 @@ export function authenticate(redirectTo) {
}
}
export function switchAccount() {
showConnect({
appDetails: {
name: "Ballot",
icon: window.location.origin + "/images/logo/ballot.png",
},
redirectTo: "/",
onFinish: () => {
// Redirect to dashboard
window.location.replace("/all-polls");
},
userSession: userSession,
});
}
/**
* Sign out
*/

View File

@@ -33,48 +33,7 @@
overflow: auto;
}
/* My transactions */
.dashboard_my_transactions_box {
display: flex;
align-items: center;
column-gap: 16px;
padding: 14px 20px;
background-color: transparent;
cursor: pointer;
transition: 0.3s all ease;
text-decoration: none;
}
.dashboard_my_transactions_box:hover {
background-color: rgba(30, 39, 46, 0.05);
}
.dashboard_my_transactions_round_box {
min-width: 44px;
min-height: 44px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background-color: #ff793f;
}
.dashboard_transactions_id {
font-size: 14px;
font-weight: 400;
color: #1e272e;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.dashboard_transactions_date {
margin-top: 2px;
font-size: 14px;
font-weight: 400;
color: rgba(30, 39, 46, 0.6);
}
/* My votes */
.dashboard_transactions_modal_body_box {
max-height: 360px;
overflow: auto;