mirror of
https://github.com/alexgo-io/ballot.git
synced 2026-01-12 17:12:41 +08:00
feature: My votes will be stored and shown in the popup.
This commit is contained in:
@@ -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
|
||||
|
||||
180
components/common/MyVotesPopup.js
Normal file
180
components/common/MyVotesPopup.js
Normal 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>
|
||||
</>);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user