mirror of
https://github.com/alexgo-io/ballot.git
synced 2026-01-12 17:12:41 +08:00
Initial setup
This commit is contained in:
35
README.md
35
README.md
@@ -1 +1,34 @@
|
||||
# ballot
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
|
||||
|
||||
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
|
||||
|
||||
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||
|
||||
191
clarity/ballot.clar
Normal file
191
clarity/ballot.clar
Normal file
@@ -0,0 +1,191 @@
|
||||
;; ballot
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Constants
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define-constant CONTRACT-OWNER tx-sender)
|
||||
;; Errors
|
||||
(define-constant ERR-NOT-OWNER (err u1403))
|
||||
(define-constant ERR-NOT-STARTED (err u1001))
|
||||
(define-constant ERR-ENDED (err u1002))
|
||||
(define-constant ERR-ALREADY-VOTED (err u1003))
|
||||
(define-constant ERR-INVALID-VOTING-SYSTEM (err u1004))
|
||||
(define-constant ERR-NOT-HOLDING-BNS (err u1005))
|
||||
(define-constant ERR-FAILED-STRATEGY (err u1006))
|
||||
(define-constant ERR-NOT-VOTED (err u1007))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; data maps and vars
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define-data-var title (string-utf8 512) u"")
|
||||
(define-data-var description (string-utf8 512) u"")
|
||||
(define-data-var voting-system (string-ascii 10) "")
|
||||
(define-data-var start uint u0)
|
||||
(define-data-var end uint u0)
|
||||
(define-data-var should-be-a-bns-holder bool false)
|
||||
(define-map results {id: (string-ascii 36)} {count: uint, name: (string-utf8 512)} )
|
||||
(define-map users {id: principal} {count: uint, vote: (list 2 (string-ascii 36)), volume: (list 2 uint)})
|
||||
(define-map register {id: uint} {user: principal, bns: (string-ascii 256), vote: (list 2 (string-ascii 36)), volume: (list 2 uint)})
|
||||
(define-data-var total uint u0)
|
||||
(define-data-var options (list 2 (string-ascii 36)) (list))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; private functions
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; (define-private (am-i-bns-holder (domain (buff 20)) (namespace (buff 48)))
|
||||
;; (let
|
||||
;; (
|
||||
;; (dns-owner (get owner (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.bns name-resolve domain namespace))))
|
||||
;; )
|
||||
|
||||
;; (if (is-eq tx-sender dns-owner)
|
||||
;; true
|
||||
;; false
|
||||
;; )
|
||||
;; )
|
||||
;; )
|
||||
|
||||
(define-private (have-i-voted)
|
||||
(match (map-get? users {id: tx-sender})
|
||||
success true
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
(define-private (voting-system-validation (length uint))
|
||||
(if (is-eq (var-get voting-system) "single")
|
||||
(if (is-eq length u1)
|
||||
true
|
||||
false
|
||||
)
|
||||
true
|
||||
)
|
||||
)
|
||||
|
||||
;; (define-private (validate-strategy (token-id uint))
|
||||
;; (let
|
||||
;; (
|
||||
;; (nft-owner-optional (unwrap-panic (contract-call? 'ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.contract get-owner token-id)))
|
||||
;; )
|
||||
|
||||
;; (match nft-owner-optional
|
||||
;; nft-owner
|
||||
;; (if (is-eq tx-sender nft-owner)
|
||||
;; true
|
||||
;; false
|
||||
;; )
|
||||
;; false
|
||||
;; )
|
||||
;; )
|
||||
;; )
|
||||
|
||||
(define-private (fold-boolean (left bool) (right bool))
|
||||
(and (is-eq left true) (is-eq right true))
|
||||
)
|
||||
|
||||
(define-private (check-volume (each-volume uint))
|
||||
(> each-volume u0)
|
||||
)
|
||||
|
||||
(define-private (validate-vote-volume (volume (list 2 uint)))
|
||||
(begin
|
||||
(fold fold-boolean (map check-volume volume) true)
|
||||
)
|
||||
)
|
||||
|
||||
(define-private (process-my-vote (option-id (string-ascii 36)) (volume uint))
|
||||
(match (map-get? results {id: option-id})
|
||||
result (let
|
||||
(
|
||||
(new-count-tuple {count: (+ volume (get count result))})
|
||||
)
|
||||
|
||||
;; Capture the vote
|
||||
(map-set results {id: option-id} (merge result new-count-tuple))
|
||||
|
||||
;; Return
|
||||
true
|
||||
)
|
||||
(begin
|
||||
(map-set results {id: option-id} {count: u1, name: u""})
|
||||
|
||||
;; Return
|
||||
true
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(define-private (get-single-result (option-id (string-ascii 36)))
|
||||
(let
|
||||
(
|
||||
(volume (default-to u0 (get count (map-get? results {id: option-id}))))
|
||||
)
|
||||
|
||||
;; Return volume
|
||||
volume
|
||||
)
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; public functions for all
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define-public (cast-my-vote (vote (list 2 (string-ascii 36))) (volume (list 2 uint))
|
||||
(bns (string-ascii 256)) (domain (buff 20)) (namespace (buff 48)) (token-id uint)
|
||||
)
|
||||
(let
|
||||
(
|
||||
(next-total (+ u1 (var-get total)))
|
||||
)
|
||||
;; Validation
|
||||
(asserts! (and (> (len vote) u0) (is-eq (len vote) (len volume)) (validate-vote-volume volume)) ERR-NOT-VOTED)
|
||||
(asserts! (voting-system-validation (len vote)) ERR-INVALID-VOTING-SYSTEM)
|
||||
(asserts! (>= block-height (var-get start)) ERR-NOT-STARTED)
|
||||
(asserts! (<= block-height (var-get end)) ERR-ENDED)
|
||||
(asserts! (not (have-i-voted)) ERR-ALREADY-VOTED)
|
||||
;; (asserts! (validate-strategy token-id) ERR-FAILED-STRATEGY)
|
||||
;; (asserts! (or (not (var-get should-be-a-bns-holder)) (am-i-bns-holder domain namespace)) ERR-NOT-HOLDING-BNS)
|
||||
|
||||
;; Register the vote
|
||||
(map process-my-vote vote volume)
|
||||
(map-set users {id: tx-sender} {count: u1, vote: vote, volume: volume})
|
||||
(map-set register {id: next-total} {user: tx-sender, bns: bns, vote: vote, volume: volume})
|
||||
|
||||
;; Increase the total
|
||||
(var-set total next-total)
|
||||
|
||||
;; Return
|
||||
(ok true)
|
||||
)
|
||||
)
|
||||
|
||||
(define-read-only (get-results)
|
||||
(begin
|
||||
(ok {total: (var-get total),options: (var-get options), results: (map get-single-result (var-get options))})
|
||||
)
|
||||
)
|
||||
|
||||
(define-read-only (get-result-at-position (position uint))
|
||||
(ok (map-get? register {id: position}))
|
||||
)
|
||||
|
||||
(define-read-only (get-result-by-user (user principal))
|
||||
(ok (map-get? users {id: user}))
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; public functions for contract owner
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Default assignments
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(var-set title u"BlockSurvey Poll")
|
||||
(var-set description u"Description")
|
||||
(var-set voting-system "single")
|
||||
(var-set options (list "option1" "option2"))
|
||||
(var-set start u0)
|
||||
(var-set end u0)
|
||||
(map-set results {id: "option1"} {count: u0, name: u"Yes"})
|
||||
(map-set results {id: "option2"} {count: u0, name: u"No"})
|
||||
;; (var-set should-be-a-bns-holder true)
|
||||
40
clarity/nft.clar
Normal file
40
clarity/nft.clar
Normal file
@@ -0,0 +1,40 @@
|
||||
;; (impl-trait 'SP2PABAF9FTAJYNFZH93XENAJ8FVY99RRM50D2JG9.nft-trait.nft-trait)
|
||||
|
||||
(define-constant contract-owner tx-sender)
|
||||
(define-constant err-owner-only (err u100))
|
||||
(define-constant err-not-token-owner (err u101))
|
||||
|
||||
(define-non-fungible-token stacksies uint)
|
||||
|
||||
(define-data-var last-token-id uint u0)
|
||||
|
||||
(define-read-only (get-last-token-id)
|
||||
(ok (var-get last-token-id))
|
||||
)
|
||||
|
||||
(define-read-only (get-token-uri (token-id uint))
|
||||
(ok none)
|
||||
)
|
||||
|
||||
(define-read-only (get-owner (token-id uint))
|
||||
(ok (nft-get-owner? stacksies token-id))
|
||||
)
|
||||
|
||||
(define-public (transfer (token-id uint) (sender principal) (recipient principal))
|
||||
(begin
|
||||
(asserts! (is-eq tx-sender sender) err-not-token-owner)
|
||||
(nft-transfer? stacksies token-id sender recipient)
|
||||
)
|
||||
)
|
||||
|
||||
(define-public (mint (recipient principal))
|
||||
(let
|
||||
(
|
||||
(token-id (+ (var-get last-token-id) u1))
|
||||
)
|
||||
(asserts! (is-eq tx-sender contract-owner) err-owner-only)
|
||||
(try! (nft-mint? stacksies token-id recipient))
|
||||
(var-set last-token-id token-id)
|
||||
(ok token-id)
|
||||
)
|
||||
)
|
||||
8
common/constants.js
Normal file
8
common/constants.js
Normal file
@@ -0,0 +1,8 @@
|
||||
export const Constants = {
|
||||
// Stacks mainnet network flag
|
||||
STACKS_MAINNET_FLAG:
|
||||
process.env.NEXT_PUBLIC_STACKS_MAINNET_FLAG === "false" ? false : true,
|
||||
|
||||
// IPFS gateway
|
||||
IPFS_GATEWAY: "https://ipfs.owl.link/ipfs/"
|
||||
};
|
||||
334
common/contract.js
Normal file
334
common/contract.js
Normal file
@@ -0,0 +1,334 @@
|
||||
import { openContractCall, openContractDeploy } from "@stacks/connect";
|
||||
import { AnchorMode, bufferCV, listCV, stringAsciiCV, uintCV } from "@stacks/transactions";
|
||||
import { getNetworkType } from "../services/auth";
|
||||
|
||||
export async function deployContract(pollObject, contractName, callbackFunction) {
|
||||
const contract = getContract(pollObject);
|
||||
|
||||
// Transaction options
|
||||
const txOptions = {
|
||||
contractName: contractName,
|
||||
codeBody: contract,
|
||||
network: getNetworkType(),
|
||||
anchorMode: AnchorMode.Any,
|
||||
appDetails: {
|
||||
name: "Ballot",
|
||||
icon: window.location.origin + "/images/logo/ballot.png"
|
||||
},
|
||||
onFinish: callbackFunction,
|
||||
};
|
||||
|
||||
// Call contract function
|
||||
await openContractDeploy(txOptions);
|
||||
}
|
||||
|
||||
function getContract(pollObject) {
|
||||
let contract = getRawContract();
|
||||
|
||||
let optionIds;
|
||||
let optionResults;
|
||||
pollObject?.options?.forEach(option => {
|
||||
if (!optionIds) {
|
||||
optionIds = `"${option?.id}"`
|
||||
optionResults = `(map-set results {id: "${option?.id}"} {count: u0, name: u"${getStringByLength(option?.value, 512)}"})`
|
||||
} else {
|
||||
optionIds = optionIds + ` "${option?.id}"`;
|
||||
optionResults = optionResults + ` (map-set results {id: "${option?.id}"} {count: u0, name: u"${getStringByLength(option?.value, 512)}"})`
|
||||
}
|
||||
});
|
||||
|
||||
// Strategy
|
||||
let strategyContractFunction = "";
|
||||
let validateStrategy = "";
|
||||
if (pollObject?.strategyContractName) {
|
||||
strategyContractFunction = getStrategyContractFunction(pollObject?.strategyContractName);
|
||||
validateStrategy = `(asserts! (validate-strategy token-id) ERR-FAILED-STRATEGY)`;
|
||||
}
|
||||
|
||||
// .btc dns holder validation
|
||||
let btcDnsHolderContractFunction = "";
|
||||
let validateBtcDnsHolder = "";
|
||||
if (pollObject?.votingStrategyTemplate == "btcholders") {
|
||||
strategyContractFunction = getBtcDnsHolderContractFunction();
|
||||
validateStrategy = `(asserts! (am-i-btc-dns-holder domain namespace) ERR-NOT-HOLDING-BTC-DNS)`;
|
||||
}
|
||||
|
||||
const placeholder = {
|
||||
"noOfOptions": pollObject?.options?.length,
|
||||
"title": getStringByLength(pollObject?.title, 512),
|
||||
"description": getStringByLength(pollObject?.description, 512),
|
||||
"votingSystem": pollObject?.votingSystem,
|
||||
"startAtBlock": pollObject?.startAtBlock,
|
||||
"endAtBlock": pollObject?.endAtBlock,
|
||||
"optionIds": optionIds,
|
||||
"optionResults": optionResults,
|
||||
"strategyContractFunction": strategyContractFunction,
|
||||
"validateStrategy": validateStrategy,
|
||||
"btcDnsHolderContractFunction": btcDnsHolderContractFunction,
|
||||
"validateBtcDnsHolder": validateBtcDnsHolder
|
||||
|
||||
}
|
||||
|
||||
for (let key in placeholder) {
|
||||
const searchRegExp = new RegExp(`&{${key}}`, 'gi')
|
||||
const replaceWith = placeholder[key];
|
||||
contract = contract.replace(searchRegExp, replaceWith);
|
||||
}
|
||||
|
||||
return contract;
|
||||
}
|
||||
|
||||
function getStringByLength(text, length) {
|
||||
// Make it single line string
|
||||
let finalText = text.replace(/\n/g, "");
|
||||
|
||||
// Cut shot by string length
|
||||
finalText = finalText.slice(0, length);
|
||||
|
||||
return finalText;
|
||||
}
|
||||
|
||||
function getRawContract() {
|
||||
return `;; ballot
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Constants
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define-constant CONTRACT-OWNER tx-sender)
|
||||
;; Errors
|
||||
(define-constant ERR-NOT-OWNER (err u1403))
|
||||
(define-constant ERR-NOT-STARTED (err u1001))
|
||||
(define-constant ERR-ENDED (err u1002))
|
||||
(define-constant ERR-ALREADY-VOTED (err u1003))
|
||||
(define-constant ERR-INVALID-VOTING-SYSTEM (err u1004))
|
||||
(define-constant ERR-NOT-HOLDING-BTC-DNS (err u1005))
|
||||
(define-constant ERR-FAILED-STRATEGY (err u1006))
|
||||
(define-constant ERR-NOT-VOTED (err u1007))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; data maps and vars
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define-data-var title (string-utf8 512) u"")
|
||||
(define-data-var description (string-utf8 512) u"")
|
||||
(define-data-var voting-system (string-ascii 10) "")
|
||||
(define-data-var start uint u0)
|
||||
(define-data-var end uint u0)
|
||||
(define-data-var should-be-a-bns-holder bool false)
|
||||
(define-map results {id: (string-ascii 36)} {count: uint, name: (string-utf8 512)} )
|
||||
(define-map users {id: principal} {count: uint, vote: (list &{noOfOptions} (string-ascii 36)), volume: (list &{noOfOptions} uint)})
|
||||
(define-map register {id: uint} {user: principal, bns: (string-ascii 256), vote: (list &{noOfOptions} (string-ascii 36)), volume: (list &{noOfOptions} uint)})
|
||||
(define-data-var total uint u0)
|
||||
(define-data-var options (list &{noOfOptions} (string-ascii 36)) (list))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; private functions
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
&{btcDnsHolderContractFunction}
|
||||
|
||||
(define-private (have-i-voted)
|
||||
(match (map-get? users {id: tx-sender})
|
||||
success true
|
||||
false
|
||||
)
|
||||
)
|
||||
|
||||
(define-private (voting-system-validation (length uint))
|
||||
(if (is-eq (var-get voting-system) "single")
|
||||
(if (is-eq length u1)
|
||||
true
|
||||
false
|
||||
)
|
||||
true
|
||||
)
|
||||
)
|
||||
|
||||
&{strategyContractFunction}
|
||||
|
||||
(define-private (fold-boolean (left bool) (right bool))
|
||||
(and (is-eq left true) (is-eq right true))
|
||||
)
|
||||
|
||||
(define-private (check-volume (each-volume uint))
|
||||
(> each-volume u0)
|
||||
)
|
||||
|
||||
(define-private (validate-vote-volume (volume (list &{noOfOptions} uint)))
|
||||
(begin
|
||||
(fold fold-boolean (map check-volume volume) true)
|
||||
)
|
||||
)
|
||||
|
||||
(define-private (process-my-vote (option-id (string-ascii 36)) (volume uint))
|
||||
(match (map-get? results {id: option-id})
|
||||
result (let
|
||||
(
|
||||
(new-count-tuple {count: (+ volume (get count result))})
|
||||
)
|
||||
|
||||
;; Capture the vote
|
||||
(map-set results {id: option-id} (merge result new-count-tuple))
|
||||
|
||||
;; Return
|
||||
true
|
||||
)
|
||||
(begin
|
||||
(map-set results {id: option-id} {count: u1, name: u""})
|
||||
|
||||
;; Return
|
||||
true
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(define-private (get-single-result (option-id (string-ascii 36)))
|
||||
(let
|
||||
(
|
||||
(volume (default-to u0 (get count (map-get? results {id: option-id}))))
|
||||
)
|
||||
|
||||
;; Return volume
|
||||
volume
|
||||
)
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; public functions for all
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define-public (cast-my-vote (vote (list &{noOfOptions} (string-ascii 36))) (volume (list &{noOfOptions} uint))
|
||||
(bns (string-ascii 256)) (domain (buff 20)) (namespace (buff 48)) (token-id uint)
|
||||
)
|
||||
(let
|
||||
(
|
||||
(next-total (+ u1 (var-get total)))
|
||||
)
|
||||
;; Validation
|
||||
(asserts! (and (> (len vote) u0) (is-eq (len vote) (len volume)) (validate-vote-volume volume)) ERR-NOT-VOTED)
|
||||
(asserts! (voting-system-validation (len vote)) ERR-INVALID-VOTING-SYSTEM)
|
||||
(asserts! (>= block-height (var-get start)) ERR-NOT-STARTED)
|
||||
(asserts! (<= block-height (var-get end)) ERR-ENDED)
|
||||
(asserts! (not (have-i-voted)) ERR-ALREADY-VOTED)
|
||||
&{validateStrategy}
|
||||
&{validateBtcDnsHolder}
|
||||
|
||||
;; Register the vote
|
||||
(map process-my-vote vote volume)
|
||||
(map-set users {id: tx-sender} {count: u1, vote: vote, volume: volume})
|
||||
(map-set register {id: next-total} {user: tx-sender, bns: bns, vote: vote, volume: volume})
|
||||
|
||||
;; Increase the total
|
||||
(var-set total next-total)
|
||||
|
||||
;; Return
|
||||
(ok true)
|
||||
)
|
||||
)
|
||||
|
||||
(define-read-only (get-results)
|
||||
(begin
|
||||
(ok {total: (var-get total),options: (var-get options), results: (map get-single-result (var-get options))})
|
||||
)
|
||||
)
|
||||
|
||||
(define-read-only (get-result-at-position (position uint))
|
||||
(ok (map-get? register {id: position}))
|
||||
)
|
||||
|
||||
(define-read-only (get-result-by-user (user principal))
|
||||
(ok (map-get? users {id: user}))
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; public functions for contract owner
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Default assignments
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(var-set title u"&{title}")
|
||||
(var-set description u"&{description}")
|
||||
(var-set voting-system "&{votingSystem}")
|
||||
(var-set options (list &{optionIds}))
|
||||
(var-set start u&{startAtBlock})
|
||||
(var-set end u&{endAtBlock})
|
||||
&{optionResults}`;
|
||||
}
|
||||
|
||||
function getStrategyContractFunction(strategyContractName) {
|
||||
return `(define-private (validate-strategy (token-id uint))
|
||||
(let
|
||||
(
|
||||
(nft-owner-optional (unwrap-panic (contract-call? '${strategyContractName} get-owner token-id)))
|
||||
)
|
||||
|
||||
(match nft-owner-optional
|
||||
nft-owner
|
||||
(if (is-eq tx-sender nft-owner)
|
||||
true
|
||||
false
|
||||
)
|
||||
false
|
||||
)
|
||||
)
|
||||
)`;
|
||||
}
|
||||
|
||||
function getBtcDnsHolderContractFunction() {
|
||||
return `(define-private (am-i-btc-dns-holder (domain (buff 20)) (namespace (buff 48)))
|
||||
(let
|
||||
(
|
||||
(dns-owner (get owner (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.bns name-resolve domain namespace))))
|
||||
)
|
||||
|
||||
(if (and (is-eq domain 0x627463) (is-eq tx-sender dns-owner))
|
||||
true
|
||||
false
|
||||
)
|
||||
)
|
||||
)`;
|
||||
}
|
||||
|
||||
export async function castMyVoteContractCall(contractAddress, contractName, voteObj, dns, tokenId, callbackFunction) {
|
||||
// Parse vote
|
||||
let voteStringAsciiArr = [], volumeUIntArr = [];
|
||||
for (let key in voteObj) {
|
||||
voteStringAsciiArr.push(stringAsciiCV(key));
|
||||
volumeUIntArr.push(uintCV(voteObj[key]));
|
||||
}
|
||||
|
||||
// Parse dns
|
||||
let domain, namespace;
|
||||
if (dns && dns.split(".").length <= 1) {
|
||||
// Parse dns
|
||||
let splittedDns = dns.split(".");
|
||||
domain = splittedDns.pop();
|
||||
namespace = splittedDns.join(".");
|
||||
}
|
||||
|
||||
const functionArgs = [
|
||||
listCV(voteStringAsciiArr),
|
||||
listCV(volumeUIntArr),
|
||||
stringAsciiCV(dns ? dns : ""),
|
||||
bufferCV(Buffer.from(domain ? domain : "")),
|
||||
bufferCV(Buffer.from(namespace ? namespace : "")),
|
||||
uintCV(tokenId ? tokenId : 0)
|
||||
];
|
||||
|
||||
// Contract function details to be called
|
||||
const options = {
|
||||
contractAddress: contractAddress,
|
||||
contractName: contractName,
|
||||
functionName: "cast-my-vote",
|
||||
functionArgs: functionArgs,
|
||||
postConditions: [],
|
||||
network: getNetworkType(),
|
||||
appDetails: {
|
||||
name: "Ballot",
|
||||
icon: window.location.origin + "/images/logo/owllink.png",
|
||||
},
|
||||
onFinish: callbackFunction,
|
||||
};
|
||||
|
||||
// Call contract function
|
||||
await openContractCall(options);
|
||||
}
|
||||
25
common/utils.js
Normal file
25
common/utils.js
Normal file
@@ -0,0 +1,25 @@
|
||||
import { getStacksAPIPrefix } from "../services/auth";
|
||||
import { Constants } from "./constants";
|
||||
|
||||
export async function getRecentBlock() {
|
||||
// Get btc domain for logged in user
|
||||
const response = await fetch(
|
||||
getStacksAPIPrefix() + "/extended/v1/block?limit=1"
|
||||
);
|
||||
const responseObject = await response.json();
|
||||
|
||||
return responseObject?.results?.[0];
|
||||
}
|
||||
|
||||
export function formStacksExplorerUrl(txId) {
|
||||
return (
|
||||
"https://explorer.stacks.co/txid/" +
|
||||
txId +
|
||||
"?chain=" +
|
||||
(Constants.STACKS_MAINNET_FLAG ? "mainnet" : "testnet")
|
||||
);
|
||||
}
|
||||
|
||||
export function convertToDisplayDateFormat(date) {
|
||||
return new Date(date).toLocaleDateString('general', { month: 'short', day: 'numeric', year: 'numeric', hour: 'numeric', hour12: true, minute: 'numeric' })
|
||||
}
|
||||
577
components/builder/BuilderComponent.js
Normal file
577
components/builder/BuilderComponent.js
Normal file
@@ -0,0 +1,577 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Col, Container, Row, Button, Form } from "react-bootstrap";
|
||||
import styles from "../../styles/Builder.module.css";
|
||||
import { getFileFromGaia, getMyStxAddress, getUserData, putFileToGaia } from "../../services/auth.js"
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { nanoid } from 'nanoid';
|
||||
import Link from "next/link";
|
||||
import Router from 'next/router'
|
||||
import PreviewComponent from "./Preview.component";
|
||||
import { getRecentBlock } from "../../common/utils";
|
||||
import { deployContract } from "../../common/contract";
|
||||
|
||||
export default function BuilderComponent(props) {
|
||||
// Variables
|
||||
|
||||
// Poll id and Gaia address
|
||||
const { pathParams } = props;
|
||||
|
||||
// Poll id
|
||||
const [pollId, setPollId] = useState();
|
||||
|
||||
// Draft mode or not
|
||||
const [mode, setMode] = useState();
|
||||
|
||||
// Poll object
|
||||
const [pollObject, setPollObject] = useState();
|
||||
|
||||
// Processing flag
|
||||
const [isProcessing, setIsProcessing] = useState(false);
|
||||
|
||||
// Error message
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
|
||||
// Show preview
|
||||
const [show, setShow] = useState(false);
|
||||
const handleShow = () => setShow(true);
|
||||
const handleClose = () => setShow(false);
|
||||
|
||||
const [currentProgressMessage, setCurrentProgressMessage] = useState();
|
||||
|
||||
// Default strategy templates
|
||||
const strategyTemplates = {
|
||||
"satoshibles": {
|
||||
"strategyNFTName": "Satoshibles",
|
||||
"strategyContractName": "SP6P4EJF0VG8V0RB3TQQKJBHDQKEF6NVRD1KZE3C.satoshibles"
|
||||
}, "crashpunks": {
|
||||
"strategyNFTName": "crashpunks-v2",
|
||||
"strategyContractName": "SP3QSAJQ4EA8WXEDSRRKMZZ29NH91VZ6C5X88FGZQ.crashpunks-v2"
|
||||
}, "theexplorerguild": {
|
||||
"strategyNFTName": "The-Explorer-Guild",
|
||||
"strategyContractName": "SP2X0TZ59D5SZ8ACQ6YMCHHNR2ZN51Z32E2CJ173.the-explorer-guild"
|
||||
}, "stacksparrots": {
|
||||
"strategyNFTName": "stacks-parrots",
|
||||
"strategyContractName": "SP2KAF9RF86PVX3NEE27DFV1CQX0T4WGR41X3S45C.byzantion-stacks-parrots"
|
||||
}, "blocksurvey": {
|
||||
"strategyNFTName": "blocksurvey",
|
||||
"strategyContractName": "https://explorer.stacks.co/txid/SPNWZ5V2TPWGQGVDR6T7B6RQ4XMGZ4PXTEE0VQ0S.blocksurvey"
|
||||
}, "btcholders": {
|
||||
"strategyNFTName": "",
|
||||
"strategyContractName": ""
|
||||
}
|
||||
}
|
||||
|
||||
// Functions
|
||||
useEffect(() => {
|
||||
if (pathParams && pathParams?.[0]) {
|
||||
setPollId(pathParams[0]);
|
||||
}
|
||||
|
||||
if (pathParams && pathParams?.[1]) {
|
||||
setMode(pathParams[1]);
|
||||
} else {
|
||||
setMode("");
|
||||
}
|
||||
|
||||
// Fetch from Gaia
|
||||
if (pollId) {
|
||||
if (pollId === "new") {
|
||||
// Initialize new poll
|
||||
setPollObject(initializeNewPoll());
|
||||
} else if (mode === "draft") {
|
||||
getFileFromGaia(pollId + ".json", {}).then(
|
||||
(response) => {
|
||||
if (response) {
|
||||
setPollObject(JSON.parse(response));
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
// File does not exit in gaia
|
||||
if (error && error.code == "does_not_exist") {
|
||||
// Initialize new poll
|
||||
setPollObject(initializeNewPoll());
|
||||
}
|
||||
});
|
||||
} else if (pollId) {
|
||||
// Fetch from IPFS
|
||||
fetch(`https://owllink.mypinata.cloud/ipfs/${pollId}`)
|
||||
.then(response => response.json())
|
||||
.then(data => setPollObject(data));
|
||||
}
|
||||
}
|
||||
}, [pathParams, pollId, mode]);
|
||||
|
||||
function initializeNewPoll() {
|
||||
return {
|
||||
title: "",
|
||||
description: "",
|
||||
votingSystem: "single",
|
||||
options: [
|
||||
{
|
||||
id: uuidv4(),
|
||||
value: "Choice 1"
|
||||
},
|
||||
{
|
||||
id: uuidv4(),
|
||||
value: "Choice 2"
|
||||
}
|
||||
],
|
||||
strategyContractName: "",
|
||||
startAtBlock: 0,
|
||||
endAtBlock: 0,
|
||||
startAtDate: 0,
|
||||
endAtDate: 0,
|
||||
|
||||
id: uuidv4(),
|
||||
status: "draft",
|
||||
createdAt: new Date(),
|
||||
username: getUserData().identityAddress,
|
||||
userStxAddress: getMyStxAddress()
|
||||
}
|
||||
}
|
||||
|
||||
const handleChange = e => {
|
||||
const { name, value } = e.target;
|
||||
|
||||
// Switch box component
|
||||
if (name == "votingStrategyFlag") {
|
||||
value = e.target.checked;
|
||||
|
||||
// Reset the values
|
||||
if (value == false) {
|
||||
pollObject["votingStrategyTemplate"] = "";
|
||||
pollObject["strategyNFTName"] = "";
|
||||
pollObject["strategyContractName"] = "";
|
||||
}
|
||||
} else if (name == "votingStrategyTemplate") {
|
||||
if (strategyTemplates[value]) {
|
||||
pollObject["strategyNFTName"] = strategyTemplates[value]["strategyNFTName"];
|
||||
pollObject["strategyContractName"] = strategyTemplates[value]["strategyContractName"];
|
||||
} else {
|
||||
pollObject["strategyNFTName"] = "";
|
||||
pollObject["strategyContractName"] = "";
|
||||
}
|
||||
}
|
||||
|
||||
// If value is empty, then delete key from previous state
|
||||
if (!value && pollObject) {
|
||||
// Delete key from JSON
|
||||
delete pollObject[name];
|
||||
} else {
|
||||
// Update the value
|
||||
pollObject[name] = value;
|
||||
}
|
||||
|
||||
setPollObject({ ...pollObject });
|
||||
};
|
||||
|
||||
const addOption = () => {
|
||||
if (pollObject?.options) {
|
||||
pollObject.options.push({
|
||||
id: uuidv4(),
|
||||
value: `Choice ${pollObject.options.length + 1}`
|
||||
})
|
||||
}
|
||||
setPollObject({ ...pollObject });
|
||||
}
|
||||
|
||||
const deleteOption = (index) => {
|
||||
if (pollObject?.options && index < pollObject?.options?.length) {
|
||||
pollObject.options.splice(index, 1);
|
||||
setPollObject({ ...pollObject });
|
||||
}
|
||||
}
|
||||
|
||||
const handleOptionChange = (e, option) => {
|
||||
option.value = e.target.value
|
||||
setPollObject({ ...pollObject });
|
||||
}
|
||||
|
||||
const savePollToGaia = (encrypt = true) => {
|
||||
if (pollObject?.id) {
|
||||
// Start processing
|
||||
setIsProcessing(true);
|
||||
|
||||
setCurrentProgressMessage("Saving ...");
|
||||
|
||||
// Reset message
|
||||
setErrorMessage("");
|
||||
|
||||
// Save to gaia
|
||||
putFileToGaia(`${pollObject.id}.json`, JSON.stringify(pollObject), (encrypt ? {} : { "encrypt": false })).then(response => {
|
||||
// Fetch and Update poll index
|
||||
fetchAndUpdatePollIndex();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const fetchAndUpdatePollIndex = () => {
|
||||
getFileFromGaia("pollIndex.json", {}).then(
|
||||
(response) => {
|
||||
if (response) {
|
||||
updatePollIndex(JSON.parse(response));
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
// File does not exit in gaia
|
||||
if (error && error.code == "does_not_exist") {
|
||||
// Initialize new
|
||||
const newPollIndexObj = {
|
||||
list: [],
|
||||
ref: {}
|
||||
};
|
||||
|
||||
updatePollIndex(newPollIndexObj);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const updatePollIndex = (currentPollIndexObj) => {
|
||||
if (currentPollIndexObj?.list && currentPollIndexObj?.ref) {
|
||||
// Insert to list
|
||||
if (!currentPollIndexObj.ref[pollObject.id]) {
|
||||
// New index
|
||||
currentPollIndexObj.list.push(pollObject.id);
|
||||
}
|
||||
|
||||
// Create/Update index
|
||||
currentPollIndexObj.ref[pollObject.id] = {
|
||||
"id": pollObject.id,
|
||||
"title": pollObject.title,
|
||||
"description": pollObject.description,
|
||||
"username": pollObject.username,
|
||||
"createdAt": pollObject.createdAt,
|
||||
"updatedAt": new Date(),
|
||||
"status": pollObject.status,
|
||||
"startAt": pollObject.startAtDate,
|
||||
"endAt": pollObject.endAtDate,
|
||||
"publishedInfo": pollObject?.publishedInfo,
|
||||
"ipfsLocation": pollObject?.ipfsLocation
|
||||
};
|
||||
|
||||
putFileToGaia("pollIndex.json", JSON.stringify(currentPollIndexObj), {}).then(response => {
|
||||
if (pollObject?.ipfsLocation) {
|
||||
const gaiaAddress = getUserData()?.gaiaHubConfig?.address;
|
||||
Router.replace("/p/" + pollObject?.id + "/" + gaiaAddress + "/results");
|
||||
} else if (pollId === "new") {
|
||||
Router.replace("/builder/" + pollObject.id + "/draft");
|
||||
setPollId(pollObject.id);
|
||||
}
|
||||
|
||||
// Stop processing
|
||||
setIsProcessing(false);
|
||||
|
||||
setCurrentProgressMessage("");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const validatePoll = () => {
|
||||
if (!pollObject) return "Poll is not yet created.";
|
||||
|
||||
if (!pollObject?.title || !pollObject?.description ||
|
||||
!pollObject?.options || pollObject?.options?.length == 0) {
|
||||
return "Please fill all required fields."
|
||||
}
|
||||
|
||||
if (!pollObject?.startAtDate || !pollObject?.endAtDate) {
|
||||
return "Please select poll start and end date."
|
||||
} else if (new Date() > new Date(pollObject?.startAtDate)) {
|
||||
return "Start date should be a future date."
|
||||
} else if (new Date() > new Date(pollObject?.endAtDate) ||
|
||||
new Date(pollObject?.startAtDate) > new Date(pollObject?.endAtDate)) {
|
||||
return "End date should be greater than start date."
|
||||
}
|
||||
|
||||
if (pollObject?.votingStrategyTemplate == "other" && (!pollObject?.strategyNFTName || !pollObject?.strategyContractName)) {
|
||||
return "Please enter strategy NFT name or Contract Address"
|
||||
}
|
||||
}
|
||||
|
||||
const calculateBlockTime = (targetTimestamp, currentBlockHeight) => {
|
||||
const currentTimestamp = new Date().getTime();
|
||||
|
||||
if (targetTimestamp && targetTimestamp > currentTimestamp && currentBlockHeight > 0) {
|
||||
const diff = Math.abs(new Date(targetTimestamp) - new Date(currentTimestamp));
|
||||
const minutes = Math.floor((diff / 1000) / 60);
|
||||
|
||||
const blockTime = Math.round((1 / 10) * minutes);
|
||||
|
||||
return currentBlockHeight + blockTime;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const publishPoll = async () => {
|
||||
// Start processing
|
||||
setIsProcessing(true);
|
||||
|
||||
// Reset message
|
||||
setErrorMessage("");
|
||||
|
||||
// Validation
|
||||
const _errorMessage = validatePoll();
|
||||
if (_errorMessage) {
|
||||
setErrorMessage(_errorMessage);
|
||||
|
||||
// Start processing
|
||||
setIsProcessing(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show message
|
||||
setCurrentProgressMessage("Publishing contract ...");
|
||||
|
||||
// Get current Block
|
||||
const currentBlock = await getRecentBlock();
|
||||
|
||||
// Calculate block time
|
||||
if (pollObject?.startAtDate) {
|
||||
pollObject['startAtBlock'] = calculateBlockTime(new Date(pollObject?.startAtDate).getTime(), currentBlock?.height);
|
||||
}
|
||||
if (pollObject?.endAtDate) {
|
||||
pollObject['endAtBlock'] = calculateBlockTime(new Date(pollObject?.endAtDate).getTime(), currentBlock?.height);
|
||||
}
|
||||
|
||||
const contractName = "ballot-" + getTitleWithOutSpecialChar();
|
||||
pollObject["publishedInfo"] = {
|
||||
"contractAddress": getMyStxAddress(),
|
||||
"contractName": contractName
|
||||
}
|
||||
|
||||
publishContract(contractName);
|
||||
}
|
||||
|
||||
const publishContract = (contractName) => {
|
||||
// Publish contract
|
||||
deployContract(pollObject, contractName, callbackFunction);
|
||||
}
|
||||
|
||||
const callbackFunction = (data) => {
|
||||
if (data?.txId) {
|
||||
// Update the contract deployed information
|
||||
pollObject.publishedInfo["txId"] = data?.txId;
|
||||
|
||||
// Update the status
|
||||
pollObject["status"] = "live";
|
||||
|
||||
publishPollToIPFS();
|
||||
}
|
||||
}
|
||||
|
||||
const publishPollToIPFS = async () => {
|
||||
setCurrentProgressMessage("Publishing to IPFS ...");
|
||||
|
||||
// Publish JSON to IPFS
|
||||
const data = JSON.stringify({
|
||||
"pinataOptions": {
|
||||
"cidVersion": 1
|
||||
},
|
||||
"pinataMetadata": {
|
||||
"name": pollObject?.title,
|
||||
"keyvalues": {
|
||||
"id": pollObject?.id
|
||||
}
|
||||
},
|
||||
"pinataContent": pollObject
|
||||
});
|
||||
|
||||
fetch('https://api.pinata.cloud/pinning/pinJSONToIPFS', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySW5mb3JtYXRpb24iOnsiaWQiOiI0MDgzMzAwOC0wNWE2LTQxNzYtYjZlNy01ZGZjYzliOTg0NTYiLCJlbWFpbCI6InJhamFAYmxvY2tzdXJ2ZXkub3JnIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsInBpbl9wb2xpY3kiOnsicmVnaW9ucyI6W3siaWQiOiJGUkExIiwiZGVzaXJlZFJlcGxpY2F0aW9uQ291bnQiOjF9XSwidmVyc2lvbiI6MX0sIm1mYV9lbmFibGVkIjpmYWxzZSwic3RhdHVzIjoiQUNUSVZFIn0sImF1dGhlbnRpY2F0aW9uVHlwZSI6InNjb3BlZEtleSIsInNjb3BlZEtleUtleSI6ImIwOWMzZjVjMTQ1ZWMxMjIwNGIxIiwic2NvcGVkS2V5U2VjcmV0IjoiMGUxMWNhZGZhMDFiMmQ3MGQ4YTJiZWMwZTRmNzBkMWJiN2I2NWZlYTA3OWQzZjNkNGI1YmQ5ODk0M2U4MTk3ZiIsImlhdCI6MTY2MTc4NjY4N30.qmkn_YrtU1jJExIpqZLN3FfMqbIzciuerWIUUutCayc'
|
||||
},
|
||||
body: data
|
||||
}).then(async (response) => {
|
||||
const responseBody = await response.json();
|
||||
|
||||
// Update the IPFS location
|
||||
pollObject["ipfsLocation"] = responseBody?.IpfsHash
|
||||
setPollObject({ ...pollObject });
|
||||
|
||||
// Save poll to gaia
|
||||
savePollToGaia(false);
|
||||
});
|
||||
}
|
||||
|
||||
const getTitleWithOutSpecialChar = () => {
|
||||
return pollObject?.title?.replace(/[^a-zA-Z0-9]/g, '');
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container fluid>
|
||||
<Row className="justify-content-md-center">
|
||||
<Col lg={8} md={12}>
|
||||
<div className={styles.builder_container}>
|
||||
|
||||
{/* Title */}
|
||||
<h4>{pollId && pollId === "new" ? "New" : "Edit"} Poll</h4>
|
||||
|
||||
{pollObject && pollObject.id ?
|
||||
<Form style={{ marginTop: "20px" }}>
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>Title</Form.Label>
|
||||
<Form.Control type="text" name="title" value={pollObject.title} onChange={handleChange} />
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>Description</Form.Label>
|
||||
<Form.Control as="textarea" name="description" value={pollObject.description} rows={5} onChange={handleChange} />
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>Voting system</Form.Label>
|
||||
<div>
|
||||
{['Single', 'Multiple'].map((option, index) => (
|
||||
<Form.Check
|
||||
inline
|
||||
key={index}
|
||||
type='radio'
|
||||
name="votingSystem"
|
||||
value={option.toLowerCase()}
|
||||
checked={pollObject.votingSystem === option.toLowerCase()}
|
||||
id={`voting_system_${option}`}
|
||||
label={option}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* List of options */}
|
||||
<div style={{ margin: "10px 0 0 10px" }}>
|
||||
{pollObject?.options &&
|
||||
pollObject.options.map((option, index) => (
|
||||
<div key={index} style={{ margin: "5px 0", display: "flex", alignItems: "center" }}>
|
||||
|
||||
{pollObject?.votingSystem === "single" ?
|
||||
<Form.Check style={{ marginRight: "10px" }}
|
||||
type='radio'
|
||||
disabled
|
||||
/>
|
||||
:
|
||||
<Form.Check style={{ marginRight: "10px" }}
|
||||
type='checkbox'
|
||||
disabled
|
||||
/>
|
||||
}
|
||||
|
||||
<Form.Control type="text" placeholder="" value={option?.value} onChange={e => handleOptionChange(e, option)} />
|
||||
|
||||
<Button variant="secondary" style={{ marginLeft: "10px", width: "80px" }} onClick={() => { deleteOption(index); }}>Delete</Button>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
||||
<Button variant="secondary" style={{ width: "75px" }} onClick={() => { addOption(); }}>Add</Button>
|
||||
</div>
|
||||
</Form.Group>
|
||||
|
||||
{/* Voting Period */}
|
||||
<div>
|
||||
<Form.Label>Voting period</Form.Label>
|
||||
<Form.Group className="mb-3" style={{ display: "flex", alignItems: "center" }}>
|
||||
<Form.Label style={{ marginRight: "10px", width: "50px" }}>Start</Form.Label>
|
||||
<Form.Control type="datetime-local" name="startAtDate" value={pollObject.startAtDate} style={{ width: "250px" }}
|
||||
min={new Date().toISOString().slice(0, 16)}
|
||||
onChange={handleChange} />
|
||||
</Form.Group>
|
||||
|
||||
<Form.Group className="mb-3" style={{ display: "flex", alignItems: "center" }}>
|
||||
<Form.Label style={{ marginRight: "10px", width: "50px" }}>End</Form.Label>
|
||||
<Form.Control type="datetime-local" name="endAtDate" value={pollObject.endAtDate} style={{ width: "250px" }}
|
||||
onChange={handleChange} disabled={!pollObject?.startAtDate} min={pollObject?.startAtDate} />
|
||||
</Form.Group>
|
||||
</div>
|
||||
|
||||
{/* Voting Strategy */}
|
||||
<div>
|
||||
<div style={{ display: "flex", alignItems: "center", padding: "10px 0" }}>
|
||||
<Form.Label>Voting strategy</Form.Label>
|
||||
<Form.Check style={{ marginLeft: "10px" }}
|
||||
inline
|
||||
type="switch"
|
||||
id="voting-strategy-id"
|
||||
name="votingStrategyFlag"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{pollObject?.votingStrategyFlag &&
|
||||
<>
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>Default strategy</Form.Label>
|
||||
<Form.Select id="voting-strategy-template" name="votingStrategyTemplate" defaultValue={""} onChange={handleChange}>
|
||||
<option disabled value="">Select</option>
|
||||
<option value="satoshibles">Satoshibles</option>
|
||||
<option value="crashpunks">CrashPunks</option>
|
||||
<option value="theexplorerguild">The Explorer Guild</option>
|
||||
<option value="stacksparrots">Stacks Parrots</option>
|
||||
<option value="blocksurvey">BlockSurvey</option>
|
||||
<option value="btcholders">.btc holders</option>
|
||||
<option value="other">Other</option>
|
||||
</Form.Select>
|
||||
</Form.Group>
|
||||
|
||||
{/* Only for other */}
|
||||
{pollObject?.votingStrategyTemplate && pollObject?.votingStrategyTemplate == "other" &&
|
||||
<>
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>NFT name</Form.Label>
|
||||
<Form.Control type="text" name="strategyNFTName" value={pollObject.strategyNFTName}
|
||||
onChange={handleChange} />
|
||||
</Form.Group>
|
||||
<Form.Group className="mb-3">
|
||||
<Form.Label>Contract name</Form.Label>
|
||||
<Form.Control type="text" name="strategyContractName" value={pollObject.strategyContractName}
|
||||
onChange={handleChange}
|
||||
placeholder="ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM.contract" />
|
||||
</Form.Group>
|
||||
</>
|
||||
}
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* Error Message */}
|
||||
{errorMessage &&
|
||||
<div style={{ margin: "10px 0" }}>
|
||||
<span style={{ fontSize: "14px" }}>{errorMessage}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* CTA */}
|
||||
{
|
||||
pollId !== "new" &&
|
||||
<Button variant="secondary" onClick={() => { handleShow() }}>Preview</Button>
|
||||
}
|
||||
{' '}
|
||||
<Button variant="secondary" onClick={() => { savePollToGaia() }} disabled={isProcessing || pollObject?.status != "draft"}>
|
||||
Save
|
||||
</Button>
|
||||
{' '}
|
||||
<Button variant="secondary" onClick={() => { publishPoll() }} disabled={isProcessing || pollObject?.status != "draft"}>
|
||||
Publish
|
||||
</Button>
|
||||
{' '}
|
||||
{currentProgressMessage &&
|
||||
<span>{currentProgressMessage}</span>
|
||||
}
|
||||
</Form>
|
||||
:
|
||||
<>Loading...</>
|
||||
}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
|
||||
{/* Preview popup */}
|
||||
<PreviewComponent pollObject={pollObject} show={show} handleClose={handleClose} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
19
components/builder/Preview.component.js
Normal file
19
components/builder/Preview.component.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Modal } from "react-bootstrap";
|
||||
import PollComponent from "../poll/PollComponent";
|
||||
|
||||
export default function PreviewComponent(props) {
|
||||
const { show, handleClose, pollObject } = props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal size="xl" show={show} onHide={handleClose}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Preview</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<PollComponent isPreview="true" pollObject={pollObject} resultsByPosition={{}} />
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
}
|
||||
55
components/common/HeaderComponent.js
Normal file
55
components/common/HeaderComponent.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import { formStacksExplorerUrl } from "../../common/utils";
|
||||
|
||||
|
||||
export default function HeaderComponent(props) {
|
||||
// Variables
|
||||
const { pollObject } = props;
|
||||
|
||||
// Function
|
||||
|
||||
// Design
|
||||
return (
|
||||
<>
|
||||
{pollObject && pollObject.id &&
|
||||
<>
|
||||
{/* Title */}
|
||||
<h4>{pollObject?.title}</h4>
|
||||
|
||||
{/* Info Bar */}
|
||||
<div style={{ fontSize: "14px" }}>
|
||||
{pollObject?.status == "draft" ? "Draft" : "Active"} {' '}
|
||||
{pollObject?.userStxAddress &&
|
||||
<a target="_blank" rel="noreferrer" href={formStacksExplorerUrl(pollObject?.userStxAddress)}>
|
||||
<span>
|
||||
{pollObject?.userStxAddress?.substring(0, 10)} { }
|
||||
<svg
|
||||
width="10"
|
||||
height="10"
|
||||
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="#0d6efd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<div style={{ margin: "20px 0", whiteSpace: "pre-wrap" }}>
|
||||
<h5>Description</h5>
|
||||
<p>
|
||||
{pollObject?.description}
|
||||
</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
132
components/common/InformationComponent.js
Normal file
132
components/common/InformationComponent.js
Normal file
@@ -0,0 +1,132 @@
|
||||
import { convertToDisplayDateFormat, formStacksExplorerUrl } from "../../common/utils";
|
||||
|
||||
|
||||
export default function InformationComponent(props) {
|
||||
// Variables
|
||||
const { pollObject, resultsByOption } = props;
|
||||
|
||||
// Function
|
||||
|
||||
// Design
|
||||
return (
|
||||
<>
|
||||
{pollObject && pollObject.id &&
|
||||
<>
|
||||
<div style={{ padding: "10px", border: "1px solid #cccccc", borderRadius: "5px", width: "100%" }}>
|
||||
{/* Title */}
|
||||
<h6>Information</h6>
|
||||
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
{
|
||||
pollObject?.publishedInfo?.contractAddress && pollObject?.publishedInfo?.contractName &&
|
||||
pollObject?.publishedInfo?.txId &&
|
||||
<div>
|
||||
Contract
|
||||
<a target="_blank" rel="noreferrer" href={formStacksExplorerUrl(pollObject?.publishedInfo?.txId)}>
|
||||
<span style={{ float: "right", fontWeight: "bold" }}>
|
||||
{pollObject?.publishedInfo?.contractName.substring(0, 10)} { }
|
||||
<svg
|
||||
width="10"
|
||||
height="10"
|
||||
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="#0d6efd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
pollObject?.ipfsLocation &&
|
||||
<div>
|
||||
IPFS
|
||||
<a target="_blank" rel="noreferrer" href={`https://owllink.mypinata.cloud/ipfs/${pollObject?.ipfsLocation}`}>
|
||||
<span style={{ float: "right", fontWeight: "bold" }}>
|
||||
#{pollObject?.ipfsLocation.substring(0, 8)} { }
|
||||
<svg
|
||||
width="10"
|
||||
height="10"
|
||||
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="#0d6efd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
pollObject?.strategyContractName &&
|
||||
<div>
|
||||
Strategy
|
||||
<a target="_blank" rel="noreferrer" href={formStacksExplorerUrl(pollObject?.strategyContractName)}>
|
||||
<span style={{ float: "right", fontWeight: "bold" }}>
|
||||
{pollObject?.strategyContractName.substring(0, 10)} { }
|
||||
<svg
|
||||
width="10"
|
||||
height="10"
|
||||
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="#0d6efd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
System <span style={{ float: "right", fontWeight: "bold", textTransform: "capitalize" }}>{pollObject?.votingSystem} Choice</span>
|
||||
</div>
|
||||
<div>
|
||||
Start Date <span style={{ float: "right", fontWeight: "bold" }}>{convertToDisplayDateFormat(pollObject?.startAtDate)}</span>
|
||||
</div>
|
||||
<div>
|
||||
End Date <span style={{ float: "right", fontWeight: "bold" }}>{convertToDisplayDateFormat(pollObject?.endAtDate)}</span>
|
||||
</div>
|
||||
{pollObject?.contractAddress &&
|
||||
<div>
|
||||
Contract Address <span style={{ float: "right", fontWeight: "bold" }}>{pollObject?.contractAddress}</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style={{ padding: "10px", marginTop: "10px", border: "1px solid #cccccc", borderRadius: "5px", width: "100%" }}>
|
||||
{/* Title */}
|
||||
<h6>Current results</h6>
|
||||
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
{pollObject?.options?.map((option, index) => (
|
||||
<div key={index}>
|
||||
{option?.value}
|
||||
<span style={{ float: "right", fontWeight: "bold", textTransform: "capitalize" }}>
|
||||
{resultsByOption && resultsByOption[option.id] ? resultsByOption[option.id] : "-"}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
121
components/dashboard/DashboardAllPollsComponent.js
Normal file
121
components/dashboard/DashboardAllPollsComponent.js
Normal file
@@ -0,0 +1,121 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { Col, Container, Row, Button } from "react-bootstrap";
|
||||
import styles from "../../styles/Dashboard.module.css";
|
||||
import { getFileFromGaia, getUserData } from "../../services/auth.js"
|
||||
import Link from "next/link";
|
||||
import { convertToDisplayDateFormat } from "../../common/utils";
|
||||
|
||||
export default function DashboardAllPollsComponent() {
|
||||
// Variables
|
||||
|
||||
// All polls
|
||||
const [allPolls, setAllPolls] = useState();
|
||||
|
||||
// Functions
|
||||
useEffect(() => {
|
||||
getFileFromGaia("pollIndex.json", {}).then(
|
||||
(response) => {
|
||||
if (response) {
|
||||
setAllPolls(JSON.parse(response));
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
// File does not exit in gaia
|
||||
if (error && error.code == "does_not_exist") {
|
||||
setAllPolls({
|
||||
list: [],
|
||||
ref: {}
|
||||
});
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
// Function
|
||||
function getEachRow(pollObj) {
|
||||
const gaiaAddress = getUserData()?.gaiaHubConfig?.address;
|
||||
|
||||
return (
|
||||
<Link href={pollObj?.status == "draft" ? `/builder/${pollObj.id}/draft` : `/p/${pollObj.id}/${gaiaAddress}/results`}>
|
||||
<div style={{ border: "1px solid black", borderRadius: "4px", padding: "10px", marginBottom: "10px", cursor: "pointer" }}>
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||
<div>
|
||||
<div style={{ fontSize: "16px", fontWeight: "bold" }}>
|
||||
{pollObj?.title ? pollObj?.title : "..."}
|
||||
</div>
|
||||
|
||||
<div style={{ fontSize: "14px" }}>
|
||||
<span>
|
||||
Status : {pollObj?.status == "draft" ? "Draft" : "Active"}
|
||||
</span>
|
||||
{', '}
|
||||
<span>
|
||||
Last Modified : {convertToDisplayDateFormat(pollObj?.updatedAt)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{/*
|
||||
<div>
|
||||
{pollObj?.status == "draft" &&
|
||||
<Link href={`/builder/${pollObj.id}/draft`}>
|
||||
<Button style={{ marginRight: "5px" }}>
|
||||
Edit
|
||||
</Button>
|
||||
</Link>
|
||||
}
|
||||
|
||||
{pollObj?.status == "live" &&
|
||||
<Link href={`/results/${pollObj.ipfsLocation}`}>
|
||||
<Button style={{ marginRight: "5px" }}>
|
||||
View
|
||||
</Button>
|
||||
</Link>
|
||||
}
|
||||
|
||||
<Button>
|
||||
Preview
|
||||
</Button>
|
||||
</div> */}
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
// Design
|
||||
return (
|
||||
<>
|
||||
<Container fluid>
|
||||
<Row className="justify-content-md-center">
|
||||
<Col lg={8} md={12}>
|
||||
|
||||
<div className={styles.dashboard_container}>
|
||||
{/* Welcome */}
|
||||
|
||||
{/* Title */}
|
||||
<h4>All Polls</h4>
|
||||
|
||||
{/* List of all polls */}
|
||||
<div style={{ padding: "10px 0" }}>
|
||||
{allPolls?.list && allPolls?.ref ?
|
||||
allPolls?.list?.length > 0 ?
|
||||
allPolls?.list.map(
|
||||
(pollId, i) => (
|
||||
<div key={i}>
|
||||
{getEachRow(allPolls.ref[pollId])}
|
||||
</div>
|
||||
)
|
||||
)
|
||||
:
|
||||
<>No data found</>
|
||||
:
|
||||
<>Loading...</>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
33
components/dashboard/DashboardMenuComponent.js
Normal file
33
components/dashboard/DashboardMenuComponent.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import Link from "next/link";
|
||||
import { Container, Row, Col, Button } from "react-bootstrap";
|
||||
|
||||
export default function DashboardMenuComponent() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Container>
|
||||
<Row>
|
||||
<Col md={12} style={{ paddingTop: "10px" }}>
|
||||
<h4>Ballot</h4>
|
||||
|
||||
<div style={{ margin: "10px 0" }}>
|
||||
<Link href="/builder/new">
|
||||
<Button>
|
||||
+ New Poll
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Link href="/all-polls">
|
||||
<Button>
|
||||
All Polls
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
234
components/poll/PollComponent.js
Normal file
234
components/poll/PollComponent.js
Normal file
@@ -0,0 +1,234 @@
|
||||
import { useState } from "react";
|
||||
import { Button, Col, Container, Form, Modal, Row, Table } from "react-bootstrap";
|
||||
import { castMyVoteContractCall } from "../../common/contract";
|
||||
import { formStacksExplorerUrl } from "../../common/utils";
|
||||
import { authenticate, userSession } from "../../services/auth";
|
||||
import styles from "../../styles/Poll.module.css";
|
||||
import HeaderComponent from "../common/HeaderComponent";
|
||||
import InformationComponent from "../common/InformationComponent";
|
||||
|
||||
export default function PollComponent(props) {
|
||||
// Variables
|
||||
|
||||
// Poll id and Gaia address
|
||||
const {
|
||||
pollObject,
|
||||
isPreview,
|
||||
optionsMap,
|
||||
resultsByOption,
|
||||
resultsByPosition,
|
||||
total,
|
||||
dns,
|
||||
alreadyVoted,
|
||||
noHoldingToken,
|
||||
holdingTokenArr,
|
||||
holdingTokenIdArr,
|
||||
votingPower } = props;
|
||||
|
||||
// Capture the vote
|
||||
const [voteObject, setVoteObject] = useState({});
|
||||
|
||||
const [txId, setTxId] = useState();
|
||||
|
||||
// Show popup
|
||||
const [show, setShow] = useState(false);
|
||||
const handleShow = () => setShow(true);
|
||||
const handleClose = () => setShow(false);
|
||||
|
||||
// Functions
|
||||
const handleChange = e => {
|
||||
const { name, value } = e.target;
|
||||
|
||||
if (pollObject?.votingSystem == "single") {
|
||||
voteObject = {
|
||||
[value]: votingPower
|
||||
};
|
||||
setVoteObject(voteObject);
|
||||
} else {
|
||||
if (voteObject?.[value]) {
|
||||
delete voteObject[value];
|
||||
} else {
|
||||
voteObject[value] = votingPower;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const callbackFunction = (data) => {
|
||||
if (data?.txId) {
|
||||
setTxId(data.txId);
|
||||
handleShow();
|
||||
}
|
||||
}
|
||||
|
||||
const castMyVote = () => {
|
||||
if (pollObject?.publishedInfo?.contractAddress && pollObject?.publishedInfo?.contractName) {
|
||||
const contractAddress = pollObject?.publishedInfo?.contractAddress;
|
||||
const contractName = pollObject?.publishedInfo?.contractName;
|
||||
castMyVoteContractCall(contractAddress, contractName, voteObject, dns, holdingTokenIdArr?.[0], callbackFunction);
|
||||
}
|
||||
}
|
||||
|
||||
// Design
|
||||
return (
|
||||
<>
|
||||
<Container fluid>
|
||||
<Row className="justify-content-md-center">
|
||||
<Col lg={isPreview ? 12 : 8} md={12}>
|
||||
<div className={styles.results_container}>
|
||||
|
||||
{pollObject && pollObject.id ?
|
||||
<>
|
||||
<div className="row">
|
||||
{/* Left Side */}
|
||||
<div className="col-sm-12 col-md-8">
|
||||
{/* Header */}
|
||||
<HeaderComponent pollObject={pollObject} />
|
||||
|
||||
{/* Cast your vote */}
|
||||
<div style={{ marginTop: "20px" }}>
|
||||
<h5>Cast your vote</h5>
|
||||
<div>
|
||||
<Form>
|
||||
<Form.Group className="mb-3">
|
||||
{pollObject?.options.map((option, index) => (
|
||||
<Form.Check
|
||||
key={index}
|
||||
type={pollObject?.votingSystem == "single" ? "radio" : "checkbox"}
|
||||
name="vote"
|
||||
value={option.id}
|
||||
label={option.value}
|
||||
id={option.id}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
))}
|
||||
|
||||
{userSession && userSession.isUserSignedIn() ?
|
||||
<Button style={{ marginTop: "10px" }}
|
||||
disabled={(isPreview || !holdingTokenArr || alreadyVoted) ? true : false}
|
||||
onClick={() => { castMyVote() }}>
|
||||
Vote
|
||||
</Button>
|
||||
:
|
||||
<Button style={{ marginTop: "10px" }}
|
||||
onClick={() => { authenticate() }}>
|
||||
Vote
|
||||
</Button>
|
||||
}
|
||||
|
||||
{/* Holdings Required */}
|
||||
{noHoldingToken &&
|
||||
<div style={{ fontSize: "14px", color: "red" }}>
|
||||
Holdings required to vote this poll.
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* Already voted */}
|
||||
{alreadyVoted &&
|
||||
<div style={{ fontSize: "14px", color: "red" }}>
|
||||
You have already cast your vote.
|
||||
</div>
|
||||
}
|
||||
</Form.Group>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Results */}
|
||||
<div style={{ marginTop: "20px" }}>
|
||||
<h5>Votes ({total})</h5>
|
||||
<Table striped bordered hover>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Address</th>
|
||||
<th>Option</th>
|
||||
<th>Voting Power</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{Object.keys(resultsByPosition).map((position, index) => (
|
||||
<tr key={index}>
|
||||
<td>{resultsByPosition[position]?.address &&
|
||||
<a target="_blank" rel="noreferrer" href={formStacksExplorerUrl(resultsByPosition[position]?.address)}>
|
||||
<span>
|
||||
{resultsByPosition[position]?.address} { }
|
||||
<svg
|
||||
width="10"
|
||||
height="10"
|
||||
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="#0d6efd"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</a>
|
||||
|
||||
}</td>
|
||||
<td>
|
||||
{Object.keys(resultsByPosition[position]?.vote).map((optionId, voteIndex) => (
|
||||
<div key={voteIndex}>
|
||||
{optionsMap[optionId] ? optionsMap[optionId] : "-"}
|
||||
</div>
|
||||
))}
|
||||
</td>
|
||||
<td>1</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Right Side */}
|
||||
<div className="col-sm-12 col-md-4">
|
||||
{/* Information */}
|
||||
<InformationComponent pollObject={pollObject} resultsByOption={resultsByOption} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
:
|
||||
<>Loading...</>
|
||||
}
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
|
||||
<Modal show={show} onHide={handleClose}>
|
||||
<Modal.Header closeButton>
|
||||
<Modal.Title>Information</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
Successfully! You have cast your vote. Check your transaction status on explorer
|
||||
<a
|
||||
style={{ textDecoration: "underline", color: "#000" }}
|
||||
href={formStacksExplorerUrl(txId)}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{" here "}
|
||||
<svg
|
||||
width="10"
|
||||
height="10"
|
||||
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="#000"
|
||||
/>
|
||||
</svg>
|
||||
</a>
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
7
next.config.js
Normal file
7
next.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
swcMinify: true,
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
1
node_modules/.bin/acorn
generated
vendored
Symbolic link
1
node_modules/.bin/acorn
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../acorn/bin/acorn
|
||||
1
node_modules/.bin/eslint
generated
vendored
Symbolic link
1
node_modules/.bin/eslint
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../eslint/bin/eslint.js
|
||||
1
node_modules/.bin/js-yaml
generated
vendored
Symbolic link
1
node_modules/.bin/js-yaml
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../js-yaml/bin/js-yaml.js
|
||||
1
node_modules/.bin/json5
generated
vendored
Symbolic link
1
node_modules/.bin/json5
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../json5/lib/cli.js
|
||||
1
node_modules/.bin/loose-envify
generated
vendored
Symbolic link
1
node_modules/.bin/loose-envify
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../loose-envify/cli.js
|
||||
1
node_modules/.bin/nanoid
generated
vendored
Symbolic link
1
node_modules/.bin/nanoid
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../nanoid/bin/nanoid.js
|
||||
1
node_modules/.bin/next
generated
vendored
Symbolic link
1
node_modules/.bin/next
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../next/dist/bin/next
|
||||
1
node_modules/.bin/node-which
generated
vendored
Symbolic link
1
node_modules/.bin/node-which
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../which/bin/node-which
|
||||
1
node_modules/.bin/prettier
generated
vendored
Symbolic link
1
node_modules/.bin/prettier
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../prettier/bin-prettier.js
|
||||
1
node_modules/.bin/resolve
generated
vendored
Symbolic link
1
node_modules/.bin/resolve
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../resolve/bin/resolve
|
||||
1
node_modules/.bin/rimraf
generated
vendored
Symbolic link
1
node_modules/.bin/rimraf
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../rimraf/bin.js
|
||||
1
node_modules/.bin/semver
generated
vendored
Symbolic link
1
node_modules/.bin/semver
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../semver/bin/semver.js
|
||||
1
node_modules/.bin/sha.js
generated
vendored
Symbolic link
1
node_modules/.bin/sha.js
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../sha.js/bin.js
|
||||
1
node_modules/.bin/stencil
generated
vendored
Symbolic link
1
node_modules/.bin/stencil
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../@stencil/core/bin/stencil
|
||||
1
node_modules/.bin/uuid
generated
vendored
Symbolic link
1
node_modules/.bin/uuid
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../uuid/dist/bin/uuid
|
||||
3944
node_modules/.package-lock.json
generated
vendored
Normal file
3944
node_modules/.package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
22
node_modules/@babel/runtime-corejs3/LICENSE
generated
vendored
Normal file
22
node_modules/@babel/runtime-corejs3/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2014-present Sebastian McKenzie and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
19
node_modules/@babel/runtime-corejs3/README.md
generated
vendored
Normal file
19
node_modules/@babel/runtime-corejs3/README.md
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# @babel/runtime-corejs3
|
||||
|
||||
> babel's modular runtime helpers with core-js@3 polyfilling
|
||||
|
||||
See our website [@babel/runtime-corejs3](https://babeljs.io/docs/en/babel-runtime-corejs3) for more information.
|
||||
|
||||
## Install
|
||||
|
||||
Using npm:
|
||||
|
||||
```sh
|
||||
npm install --save @babel/runtime-corejs3
|
||||
```
|
||||
|
||||
or using yarn:
|
||||
|
||||
```sh
|
||||
yarn add @babel/runtime-corejs3
|
||||
```
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/from.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/from.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/array/from");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/is-array.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/is-array.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/array/is-array");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/of.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/array/of.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/array/of");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/clear-immediate.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/clear-immediate.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/clear-immediate");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/date/now.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/date/now.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/date/now");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/bind.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/bind.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/bind");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/code-point-at.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/code-point-at.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/code-point-at");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/concat.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/concat.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/concat");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/copy-within.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/copy-within.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/copy-within");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/ends-with.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/ends-with.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/ends-with");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/entries.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/entries.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/entries");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/every.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/every.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/every");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/fill.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/fill.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/fill");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/filter.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/filter.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/filter");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/find-index.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/find-index.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/find-index");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/find.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/find.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/find");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flags.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flags.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/flags");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flat-map.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flat-map.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/flat-map");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flat.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/flat.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/flat");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/for-each.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/for-each.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/for-each");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/includes");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/index-of.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/index-of.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/index-of");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/keys.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/keys.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/keys");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/last-index-of.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/last-index-of.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/last-index-of");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/map.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/map.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/map");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/pad-end.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/pad-end.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/pad-end");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/pad-start.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/pad-start.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/pad-start");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce-right.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce-right.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/reduce-right");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reduce.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/reduce");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/repeat.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/repeat.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/repeat");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reverse.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/reverse.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/reverse");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/slice.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/slice.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/slice");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/some.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/some.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/some");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/sort.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/sort.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/sort");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/splice.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/splice.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/splice");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/starts-with.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/starts-with.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/starts-with");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-end.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-end.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/trim-end");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-left.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-left.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/trim-left");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-right.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-right.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/trim-right");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-start.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim-start.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/trim-start");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/trim.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/trim");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/values.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/instance/values.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/instance/values");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/json/stringify.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/json/stringify.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/json/stringify");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/map.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/map.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/map");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/acosh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/acosh.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/acosh");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/asinh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/asinh.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/asinh");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/atanh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/atanh.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/atanh");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/cbrt.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/cbrt.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/cbrt");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/clz32.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/clz32.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/clz32");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/cosh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/cosh.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/cosh");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/expm1.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/expm1.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/expm1");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/fround.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/fround.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/fround");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/hypot.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/hypot.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/hypot");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/imul.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/imul.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/imul");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log10.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log10.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/log10");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log1p.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log1p.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/log1p");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log2.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/log2.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/log2");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/sign.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/sign.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/sign");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/sinh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/sinh.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/sinh");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/tanh.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/tanh.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/tanh");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/trunc.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/math/trunc.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/math/trunc");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/epsilon.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/epsilon.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/number/epsilon");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/is-finite.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/is-finite.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/number/is-finite");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/is-integer.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/is-integer.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/number/is-integer");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/is-nan.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/is-nan.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/number/is-nan");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/is-safe-integer.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/is-safe-integer.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/number/is-safe-integer");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/max-safe-integer.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/max-safe-integer.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/number/max-safe-integer");
|
||||
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/min-safe-integer.js
generated
vendored
Normal file
1
node_modules/@babel/runtime-corejs3/core-js-stable/number/min-safe-integer.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("core-js-pure/stable/number/min-safe-integer");
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user