feature: Summary Page can be created with list of published polls.

This commit is contained in:
Raja Ilayaperumal
2022-11-11 23:49:32 +05:30
parent 7d72b5013d
commit 5fd2f44312
7 changed files with 834 additions and 0 deletions

View File

@@ -86,6 +86,10 @@ export function DashboardNavBarComponent() {
>
My votes
</Dropdown.Item>
<Dropdown.Item
href="/summary">
Summary page
</Dropdown.Item>
<Dropdown.Item
onClick={() => {
switchAccount(window?.location?.href);

View File

@@ -0,0 +1,302 @@
import Link from "next/link";
import { useEffect, useState } from "react";
import { Button, Form } from "react-bootstrap";
import { Constants } from "../../common/constants";
import { getFileFromGaia, getMyStxAddress, getStacksAPIPrefix, getUserData, putFileToGaia, userSession } from "../../services/auth";
import { convertToDisplayDateFormat } from "../../services/utils";
import styles from "../../styles/Builder.module.css";
import dashboardStyles from "../../styles/Dashboard.module.css";
import ChoosePollsPopup from "./ChoosePollsPopup";
export default function SummaryBuilderComponent(props) {
// Variables
// Gaia address
const [gaiaAddress, setGaiaAddress] = useState();
// Summary object
const [summaryObject, setSummaryObject] = useState();
// Processing flag
const [isProcessing, setIsProcessing] = useState(false);
// Error message
const [errorMessage, setErrorMessage] = useState("");
// Show/Hide ChoosePolls Popup
const [showChoosePollsPopupFlag, setShowChoosePollsPopupFlag] = useState(false);
const [urlSuffix, setUrlSuffix] = useState();
// Functions
useEffect(() => {
let isCancelled = false;
// Get Summary object
getFileFromGaia("summary.json", { decrypt: false }).then(
(response) => {
if (response && !isCancelled) {
setSummaryObject(JSON.parse(response));
}
},
(error) => {
// File does not exit in gaia
if (error && error.code == "does_not_exist" && !isCancelled) {
// Initialize new poll
setSummaryObject(initializeNewSummary());
}
});
// Get gaia address
if (userSession && userSession.isUserSignedIn()) {
setGaiaAddress(getUserData()?.gaiaHubConfig?.address);
}
// Get .btc address
getBTCDomainFromBlockchain();
return () => {
isCancelled = true;
}
}, []);
const getBTCDomainFromBlockchain = async () => {
// Get btc domain for logged in user
const response = await fetch(
getStacksAPIPrefix() + "/v1/addresses/stacks/" + getMyStxAddress()
);
const responseObject = await response.json();
// Testnet code
if (Constants.STACKS_MAINNET_FLAG == false) {
setUrlSuffix(getUserData()?.gaiaHubConfig?.address);
return;
}
// Get btc dns
if (responseObject?.names?.length > 0) {
const btcDNS = responseObject.names.filter((bns) =>
bns.endsWith(".btc")
);
// Check does BTC dns is available
if (btcDNS && btcDNS.length > 0) {
const _dns = btcDNS[0];
setUrlSuffix(_dns);
} else {
setUrlSuffix(getUserData()?.gaiaHubConfig?.address);
}
} else {
setUrlSuffix(getUserData()?.gaiaHubConfig?.address);
}
};
function initializeNewSummary() {
return {
"title": "",
"description": "",
"polls": {
"list": [],
"ref": {}
}
}
}
const handleChange = e => {
const { name, value } = e.target;
// If value is empty, then delete key from previous state
if (!value && summaryObject) {
// Delete key from JSON
delete summaryObject[name];
} else {
// Update the value
summaryObject[name] = value;
}
setSummaryObject({ ...summaryObject });
};
function openChoosePollsPopup() {
setShowChoosePollsPopupFlag(true);
}
function publishSummary() {
// Start processing
setIsProcessing(true);
// Clear message
setErrorMessage("");
// Save to gaia
putFileToGaia("summary.json", JSON.stringify(summaryObject), { "encrypt": false }).then(response => {
// Saved successfully message
setErrorMessage("Summary page is published.");
// Stop processing
setIsProcessing(false);
});
}
function getEachRow(pollIndexObject) {
const gaiaAddress = getUserData()?.gaiaHubConfig?.address;
return (
<div>
{/* Title */}
<div className="d-flex align-items-center" style={{ marginBottom: "10px", columnGap: "10px", width: "100%" }}>
<div className="text-truncate" style={{ fontSize: "18px", fontWeight: 600 }}>
{pollIndexObject?.title ? pollIndexObject?.title : "..."}
</div>
{/* Status */}
<div className={pollIndexObject?.status == "draft" ? dashboardStyles.all_polls_status_box_draft : ((pollIndexObject?.endAt && (new Date(pollIndexObject?.endAt) < new Date()))) ? dashboardStyles.all_polls_status_box_closed : dashboardStyles.all_polls_status_box_active}>
{
pollIndexObject?.status == "draft" ? "Draft" :
((pollIndexObject?.endAt && (new Date(pollIndexObject?.endAt) < new Date())) ?
"Closed" : "Active")
}
</div>
</div>
{/* Description */}
{
pollIndexObject?.description ?
<p className={"text_truncate_2" + ' ' + dashboardStyles.all_polls_description}>
{pollIndexObject?.description ? pollIndexObject?.description : "..."}
</p>
: <></>
}
<div style={{ fontSize: "14px", color: "#737373" }}>
<span>
Last Modified : {convertToDisplayDateFormat(pollIndexObject?.updatedAt)}
</span>
</div>
{/* <div>
<Button variant="danger" onClick={(event) => { event.stopPropagation(); deletePoll(pollIndexObject, setAllPolls) }}
disabled={isDeleting}>
Delete
</Button>
</div> */}
</div>
)
}
// Design
return (
<>
{summaryObject ?
<>
<div className={styles.builder_container}>
{/* Left side */}
<div className={styles.builder_left} style={{ marginBottom: "100px" }}>
{/* Title */}
<h5 style={{ fontSize: "20px", fontWeight: "600" }}>Summary</h5>
{/* Fields */}
<Form style={{ margin: "20px 0 20px 0" }}>
<Form.Group className="mb-3">
<Form.Label className='ballot_labels'>Title</Form.Label>
<Form.Control type="text" name="title" value={summaryObject.title} onChange={handleChange}
className="ballot_input" />
</Form.Group>
<Form.Group className="mb-3">
<Form.Label className='ballot_labels'>Description</Form.Label>
<Form.Control as="textarea" name="description" value={summaryObject.description} rows={5} onChange={handleChange} className="ballot_input" />
</Form.Group>
<Form.Group>
<div style={{ display: "flex", marginTop: "10px" }}>
<Button style={{ width: "100%" }} className="action_dashed_btn" onClick={() => { openChoosePollsPopup(); }}>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#ECEFF1" />
<path d="M12 8V12M12 16V12M12 12H16M12 12H8" stroke="black" strokeWidth="1.2" strokeLinecap="round" strokeLinejoin="round" />
</svg>
Choose polls
</Button>
</div>
</Form.Group>
</Form>
{/* List of polls */}
<div className={dashboardStyles.all_polls_list_outline_box}>
{summaryObject?.polls?.list.map(
(pollId, i) => (
<div key={i} className={dashboardStyles.all_polls_list_box}>
{getEachRow(summaryObject?.polls?.ref[pollId])}
</div>
)
)}
</div>
</div>
{/* Right side */}
<div className={styles.builder_right}>
<div style={{ position: "sticky", top: "119px" }}>
<div className={styles.builder_right_section}>
<a href={"/" + urlSuffix} target="_blank" style={{ textDecoration: "none" }}>
<Button style={{ width: "100%", marginBottom: "10px" }} className="action_secondary_btn">
Preview
<svg style={{ marginLeft: "6px" }}
width="8"
height="8"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
clipRule="evenodd"
d="M3.5044 0.743397C3.5044 0.33283 3.83723 -6.71395e-08 4.2478 0L11.2566 6.60206e-07C11.6672 6.60206e-07 12 0.33283 12 0.743397L12 7.7522C12 8.16277 11.6672 8.4956 11.2566 8.4956C10.846 8.4956 10.5132 8.16277 10.5132 7.7522V2.53811L1.26906 11.7823C0.978742 12.0726 0.50805 12.0726 0.217736 11.7823C-0.0725787 11.4919 -0.0725784 11.0213 0.217736 10.7309L9.46189 1.48679L4.2478 1.48679C3.83723 1.48679 3.5044 1.15396 3.5044 0.743397Z"
fill="initial"
/>
</svg>
</Button>
</a>
<Button variant="dark" style={{ width: "100%" }}
onClick={() => { publishSummary() }} disabled={isProcessing}>
Publish
</Button>
{/* Error Message */}
{errorMessage &&
<div style={{ marginTop: "10px" }}>
<span style={{ fontSize: "14px" }}>{errorMessage}</span>
</div>
}
</div>
</div>
</div>
</div>
</>
:
<>
<div style={{ width: "100%", maxWidth: "52px", height: "17px", marginBottom: "20px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "100px", height: "22px", marginBottom: "8px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "100%", height: "36px", marginBottom: "16px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "130px", height: "22px", marginBottom: "8px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "100%", height: "132px", marginBottom: "16px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "150px", height: "22px", marginBottom: "8px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "100%", height: "36px", marginBottom: "16px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "170px", height: "22px", marginBottom: "8px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "100%", height: "36px", marginBottom: "16px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
</>
}
{/* Choose polls popup */}
<ChoosePollsPopup summaryObject={summaryObject} handleSummaryChange={handleChange}
showChoosePollsPopupFlag={showChoosePollsPopupFlag} setShowChoosePollsPopupFlag={setShowChoosePollsPopupFlag} />
</>
);
}

View File

@@ -0,0 +1,210 @@
import { useEffect, useState } from "react";
import { Modal, Spinner, Form, Button } from "react-bootstrap";
import { getFileFromGaia } from "../../services/auth";
import { convertToDisplayDateFormat } from "../../services/utils";
import styles from "../../styles/ChoosePollsPopup.module.css";
export default function ChoosePollsPopup(props) {
// Parent parameters
const { showChoosePollsPopupFlag, summaryObject, handleSummaryChange } = props;
// Variables
// Handle close popup
const handleCloseChoosePollsPopup = () => {
props.setShowChoosePollsPopupFlag(false);
};
// Summary polls
const [summaryPolls, setSummaryPolls] = useState();
// All polls
const [allPolls, setAllPolls] = useState();
// Loading
const [isLoading, setIsLoading] = useState(false);
// Functions
useEffect(() => {
if (showChoosePollsPopupFlag) {
// Take summary polls
setSummaryPolls(JSON.parse(JSON.stringify(summaryObject?.polls)));
// Start loading
setIsLoading(true);
getFileFromGaia("pollIndex.json", {}).then(
(response) => {
if (response) {
setAllPolls(JSON.parse(response));
}
// Stop loading
setIsLoading(false);
},
(error) => {
// File does not exit in gaia
if (error && error.code == "does_not_exist") {
setAllPolls({
list: [],
ref: {}
});
}
// Stop loading
setIsLoading(false);
});
}
}, [showChoosePollsPopupFlag]);
function getEachRow(pollIndexObject) {
return (
<div>
{/* Title */}
<div className="d-flex align-items-center" style={{ marginBottom: "10px", columnGap: "10px", width: "100%" }}>
<div className="text-truncate" style={{ fontSize: "18px", fontWeight: 600 }}>
{pollIndexObject?.title ? pollIndexObject?.title : "..."}
</div>
{/* Status */}
<div className={pollIndexObject?.status == "draft" ? styles.all_polls_status_box_draft : ((pollIndexObject?.endAt && (new Date(pollIndexObject?.endAt) < new Date()))) ? styles.all_polls_status_box_closed : styles.all_polls_status_box_active}>
{
pollIndexObject?.status == "draft" ? "Draft" :
((pollIndexObject?.endAt && (new Date(pollIndexObject?.endAt) < new Date())) ?
"Closed" : "Active")
}
</div>
</div>
{/* Description */}
{
pollIndexObject?.description ?
<p className={"text_truncate_2" + ' ' + styles.all_polls_description}>
{pollIndexObject?.description ? pollIndexObject?.description : "..."}
</p>
: <></>
}
<div style={{ fontSize: "14px", color: "#737373" }}>
<span>
Last Modified : {convertToDisplayDateFormat(pollIndexObject?.updatedAt)}
</span>
</div>
</div>
)
}
function onClickOfPolls(pollId) {
if (!summaryPolls?.ref[pollId]) {
summaryPolls.list.push(pollId);
summaryPolls.ref[pollId] = allPolls?.ref?.[pollId];
} else {
const summaryIndex = summaryPolls.list.findIndex(item => item == pollId);
if (summaryIndex >= 0) {
summaryPolls.list.splice(summaryIndex, 1);
}
delete summaryPolls.ref[pollId];
}
setSummaryPolls({ ...summaryPolls });
}
function saveSummaryPolls() {
handleSummaryChange({
target: {
name: "polls",
value: { ...summaryPolls }
}
});
handleCloseChoosePollsPopup();
}
const handleChange = e => {
const { name, value } = e.target;
}
// View
return (
<>
{/* QR code */}
<Modal
show={showChoosePollsPopupFlag}
onHide={handleCloseChoosePollsPopup}
keyboard={false}
centered
size="xl"
>
{/* Header */}
<div className={styles.summary_modal_header_box}>
<div>Choose polls</div>
<button
className={styles.summary_modal_close_icon_btn_box}
onClick={handleCloseChoosePollsPopup}
>
<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.summary_modal_body_box} >
{
// Loading
isLoading ? (
<div style={{ textAlign: "center", padding: "10px" }}>
<Spinner animation="border" variant="secondary" size="md" />
</div>
) : // Once data found
(allPolls && allPolls?.list?.length > 0) ? (
<div className={styles.all_polls_list_outline_box}>
{allPolls?.list.map(
(pollId, i) => (
(allPolls?.ref?.[pollId] && allPolls?.ref?.[pollId]?.status != "draft") &&
<div key={i} style={{ display: "flex" }} className={styles.all_polls_list_box} onClick={() => { onClickOfPolls(pollId) }}>
<div>
<Form.Group className="mb-3">
<Form.Check
inline
type="checkbox"
name={pollId}
onChange={handleChange}
checked={summaryPolls?.ref?.[pollId] ? true : false}
/>
</Form.Group>
</div>
<div >
{getEachRow(allPolls.ref[pollId])}
</div>
</div>
)
)}
</div>
) : (
<div style={{ padding: "0px 20px 10px", fontSize: "14px" }}>
Only published polls will be listed here.
</div>
)
}
</div>
{/* Footer */}
<Modal.Footer>
<Button className="action_secondary_btn" onClick={handleCloseChoosePollsPopup}>Close</Button>
<Button variant="dark" onClick={() => { saveSummaryPolls() }} disabled={isLoading}>Done</Button>
</Modal.Footer>
</Modal>
</>
);
}

View File

@@ -0,0 +1,101 @@
import Link from "next/link";
import { convertToDisplayDateFormat } from "../../services/utils";
import styles from "../../styles/Dashboard.module.css";
export default function SummaryComponent(props) {
// Variables
const {
summaryObject,
gaiaAddress,
allPolls } = props;
// Function
function getEachRow(pollIndexObject) {
return (
<Link href={pollIndexObject?.status == "draft" ? `/builder/${pollIndexObject.id}/draft` : `/${pollIndexObject.id}/${gaiaAddress}`}>
<div>
{/* Title */}
<div className="d-flex align-items-center" style={{ marginBottom: "10px", columnGap: "10px", width: "100%" }}>
<div className="text-truncate" style={{ fontSize: "18px", fontWeight: 600 }}>
{pollIndexObject?.title ? pollIndexObject?.title : "..."}
</div>
{/* Status */}
<div className={pollIndexObject?.status == "draft" ? styles.all_polls_status_box_draft : ((pollIndexObject?.endAt && (new Date(pollIndexObject?.endAt) < new Date()))) ? styles.all_polls_status_box_closed : styles.all_polls_status_box_active}>
{
pollIndexObject?.status == "draft" ? "Draft" :
((pollIndexObject?.endAt && (new Date(pollIndexObject?.endAt) < new Date())) ?
"Closed" : "Active")
}
</div>
</div>
{/* Description */}
{
pollIndexObject?.description ?
<p className={"text_truncate_2" + ' ' + styles.all_polls_description}>
{pollIndexObject?.description ? pollIndexObject?.description : "..."}
</p>
: <></>
}
<div style={{ fontSize: "14px", color: "#737373" }}>
<span>
Last Modified : {convertToDisplayDateFormat(pollIndexObject?.updatedAt)}
</span>
</div>
</div>
</Link>
)
}
// Design
return (
<>
{summaryObject &&
<section>
<div className={styles.dashboard_container}>
<div style={{ padding: "10px 0 100px 0", maxWidth: "700px", width: "100%" }}>
{/* Title */}
<h1 style={{ fontSize: "24px", fontWeight: "600" }}>{summaryObject?.title}</h1>
{/* Description */}
<div style={{ marginBottom: "24px", whiteSpace: "pre-wrap" }}>
<p style={{ lineHeight: "1.7" }}
dangerouslySetInnerHTML={{ __html: summaryObject?.description }}>
</p>
</div>
{/* List of all polls */}
{allPolls?.list && allPolls?.ref ?
(allPolls?.list?.length > 0) &&
<>
{/* List of polls */}
<div className={styles.all_polls_list_outline_box}>
{allPolls?.list.map(
(pollId, i) => (
<div key={i} className={styles.all_polls_list_box}>
{getEachRow(allPolls.ref[pollId])}
</div>
)
)}
</div>
</>
:
<>
{/* Loading */}
<div style={{ width: "100%", maxWidth: "100px", height: "24px", marginBottom: "40px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "100%", height: "110px", marginBottom: "10px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "100%", height: "110px", marginBottom: "10px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
<div style={{ width: "100%", height: "110px", backgroundColor: "#eceff1", borderRadius: "4px" }}></div>
</>
}
</div>
</div>
</section>
}
</>
);
}

125
pages/[param].js Normal file
View File

@@ -0,0 +1,125 @@
import Head from "next/head";
import { Col, Container, Row } from "react-bootstrap";
import { Constants } from "../common/constants";
import SummaryComponent from "../components/summary/SummaryComponent";
import { getStacksAPIPrefix } from "../services/auth";
export default function SummaryPage(props) {
// Variables
const { summaryObject, gaiaAddress, allPolls } = props;
const title = `${summaryObject?.title} | Ballot`;
const description = summaryObject?.description?.substr(0, 160);
const metaImage = "https://ballot.gg/images/ballot-meta.png";
const displayURL = "";
// Functions
// Design
return (
<>
<Head>
<title>{title}</title>
<meta name="description" content={description} />
<meta name="robots" content="index,follow" />
{/* Favicon */}
<link rel="icon" href={"/favicon.ico"} />
{/* Facebook Meta Tags */}
<meta property="og:type" content="website" />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:url" content={displayURL} />
<meta property="og:image" content={metaImage} />
<meta property="og:site_name" content="ballot.gg" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
{/* Twitter Meta Tags */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:url" content={displayURL} />
<meta name="twitter:image" content={metaImage} />
{/* <meta name="twitter:site" content="@ballot_gg" /> */}
</Head>
{/* Outer layer */}
<Container className="ballot_container">
<Row>
<Col md={12}>
{/* Body */}
<SummaryComponent summaryObject={summaryObject} gaiaAddress={gaiaAddress} allPolls={allPolls} />
</Col>
</Row>
</Container>
</>
);
}
// This gets called on every request
export async function getServerSideProps(context) {
// Get path param
const { params } = context;
const { param } = params;
let summaryObject = null;
let gaiaAddress = null;
let allPolls = null;
// If it is .btc address
if (param?.toString().endsWith(".btc")) {
try {
// Get name details
const getZoneFileUrl = `${getStacksAPIPrefix()}/v1/names/${param}/zonefile`;
const response = await fetch(getZoneFileUrl);
const zoneFile = await response.json();
// Get profile details
if (zoneFile && zoneFile["zonefile"]) {
const urlRegex = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
const profileUrl = zoneFile["zonefile"].match(urlRegex)[0];
const response = await fetch(profileUrl);
const profileObject = await response.json();
// Get gaia address
if (profileObject[0]['decodedToken']?.['payload']?.["claim"]?.['apps']?.["https://ballot.gg"]) {
const gaiaPrefixUrl = profileObject[0]['decodedToken']?.['payload']?.["claim"]?.['apps']?.["https://ballot.gg"];
const splittedArray = gaiaPrefixUrl.split("/");
gaiaAddress = splittedArray.pop();
while (splittedArray.length > 0 && !gaiaAddress) {
gaiaAddress = splittedArray.pop();
}
}
}
} catch (error) {
}
} else if (param) {
gaiaAddress = param;
}
if (gaiaAddress) {
// Form gaia url
let summaryGaiaUrl = Constants.GAIA_HUB_PREFIX + gaiaAddress + "/summary.json";
try {
const response = await fetch(summaryGaiaUrl);
summaryObject = await response.json();
allPolls = summaryObject?.polls ? summaryObject?.polls : null;
} catch (error) {
// Summary not found
summaryObject = null;
allPolls = null;
}
}
// Pass data to the page via props
return {
props: {
summaryObject,
gaiaAddress,
allPolls
},
};
}

23
pages/summary/index.js Normal file
View File

@@ -0,0 +1,23 @@
import { Col, Container, Row } from "react-bootstrap";
import { DashboardNavBarComponent } from "../../components/common/DashboardNavBarComponent";
import SummaryBuilderComponent from "../../components/summary/BuilderComponent";
export default function SummaryBuilder() {
// Design
return (
<>
{/* Outer layer */}
<Container className="ballot_container">
<Row>
<Col md={12}>
{/* Dashboard nav bar */}
<DashboardNavBarComponent />
{/* Body */}
<SummaryBuilderComponent />
</Col>
</Row>
</Container>
</>
);
}

View File

@@ -0,0 +1,69 @@
/* Modal */
.summary_modal_header_box {
position: relative;
padding: 20px;
font-size: 18px;
font-weight: 500;
}
.summary_modal_close_icon_btn_box {
position: absolute;
right: 20px;
top: 20px;
width: 24px;
height: 24px;
border-radius: 50%;
border: none;
display: flex;
align-items: center;
justify-content: center;
transition: 0.3s all ease;
}
.summary_modal_body_box {
padding: 0 20px 20px 20px;
max-height: 75vh;
overflow: auto;
}
.all_polls_list_outline_box {
display: flex;
align-items: flex-start;
flex-direction: column;
row-gap: 10px;
}
.all_polls_list_box {
border-radius: 6px;
padding: 16px;
cursor: pointer;
background-color: rgba(236, 239, 241, 0.3);
width: 100%;
transition: 0.2s ease all;
}
.all_polls_list_box:hover {
background-color: rgba(236, 239, 241, 0.6);
}
.all_polls_status_box_active {
padding: 1px 8px;
background-color: #21b66f;
font-size: 12px;
color: white;
border-radius: 24px;
}
.all_polls_status_box_draft {
padding: 1px 8px;
background-color: #fca43e;
font-size: 12px;
color: white;
border-radius: 24px;
}
.all_polls_status_box_closed {
padding: 1px 8px;
background-color: #fa4949;
font-size: 12px;
color: white;
border-radius: 24px;
}
.all_polls_description {
font-size: 15px;
color: rgba(0, 0, 0, 0.8);
line-height: 1.6;
}