diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index aa13634..8a5d6cd 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -89,14 +89,19 @@ class WakuVoting { private async getTimedPolls() { const lastTimestamp = this.timedPollInitMessages?.[0]?.timestamp ?? 0 - + let updated = false const newMessages = await receiveNewWakuMessages(lastTimestamp, this.pollInitTopic, this.waku) const newPollInitMessages = decodeWakuMessages(newMessages, PollInit.decode) if (newPollInitMessages.length > 0) { + updated = true this.timedPollInitMessages = [...newPollInitMessages, ...this.timedPollInitMessages] } + const arrayLen = this.timedPollInitMessages.length this.timedPollInitMessages = this.timedPollInitMessages.filter((e) => e.endTime > Date.now()) - return this.timedPollInitMessages + if (arrayLen != this.timedPollInitMessages.length) { + updated = true + } + return { polls: this.timedPollInitMessages, updatedPolls: updated } } public async sendTimedPollVote( @@ -119,25 +124,29 @@ class WakuVoting { private async getTimedPollsVotes() { const lastTimestamp = this.timedPollVotesMessages?.[0]?.timestamp ?? 0 - + let updated = false const newMessages = await receiveNewWakuMessages(lastTimestamp, this.timedPollVoteTopic, this.waku) const newVoteMessages = decodeWakuMessages(newMessages, TimedPollVote.decode) if (newVoteMessages.length > 0) { + updated = true this.timedPollVotesMessages = [...newVoteMessages, ...this.timedPollVotesMessages] } - return this.timedPollVotesMessages + return { votes: this.timedPollVotesMessages, updatedVotes: updated } } public async getDetailedTimedPolls() { - const polls = await this.getTimedPolls() - const votes = await this.getTimedPollsVotes() - return polls.map( - (poll) => - new DetailedTimedPoll( - poll, - votes.filter((vote) => vote.id === poll.id) - ) - ) + const { polls, updatedPolls } = await this.getTimedPolls() + const { votes, updatedVotes } = await this.getTimedPollsVotes() + return { + DetailedTimedPolls: polls.map( + (poll) => + new DetailedTimedPoll( + poll, + votes.filter((vote) => vote.id === poll.id) + ) + ), + updated: updatedPolls || updatedVotes, + } } } diff --git a/packages/example/tsconfig.json b/packages/example/tsconfig.json index 4bd6269..a71680e 100644 --- a/packages/example/tsconfig.json +++ b/packages/example/tsconfig.json @@ -19,6 +19,7 @@ }, "include": [ "src", + "src/**/*.svg", "src/**/*.json", "test" ] diff --git a/packages/react-components/package.json b/packages/react-components/package.json index ef22380..108fb96 100644 --- a/packages/react-components/package.json +++ b/packages/react-components/package.json @@ -6,7 +6,12 @@ "version": "1.0.0", "license": "MIT", "scripts": { - "build": "yarn run build:esm && yarn run build:cjs", + "clean": "rimraf dist/", + "copy-assets": "yarn copy-files:cjs && yarn copy-files:esm", + "copy-files:cjs": "copyfiles -u 1 src/**/*.svg src/**/*.png dist/cjs/src", + "copy-files:esm": "copyfiles -u 1 src/**/*.svg src/**/*.png dist/esm/src", + "build": "yarn build:all && yarn copy-assets", + "build:all": "yarn run build:esm && yarn run build:cjs", "build:esm": "tsc --module es2020 --target es2017 --outDir dist/esm", "build:cjs": "tsc --outDir dist/cjs", "test": "mocha -r jsdom-global/register", @@ -29,10 +34,12 @@ "@typescript-eslint/eslint-plugin": "^4.29.0", "@typescript-eslint/parser": "^4.29.0", "chai": "^4.3.4", + "copyfiles": "^2.4.1", "eslint": "^7.32.0", "jsdom": "^16.7.0", "jsdom-global": "^3.0.2", "mocha": "^9.0.3", + "rimraf": "^3.0.2", "ts-node": "^10.1.0", "typescript": "^4.3.5" } diff --git a/packages/react-components/src/WakuPolling/Poll.tsx b/packages/react-components/src/WakuPolling/Poll.tsx index 8988869..6fd9c40 100644 --- a/packages/react-components/src/WakuPolling/Poll.tsx +++ b/packages/react-components/src/WakuPolling/Poll.tsx @@ -5,6 +5,8 @@ import React, { useEffect, useState } from 'react' import { JsonRpcSigner } from '@ethersproject/providers' import { PollType } from '@status-waku-voting/core/dist/esm/src/types/PollType' import styled from 'styled-components' +import checkIcon from '../assets/svg/checkIcon.svg' +import { RadioGroup } from '../components/radioGroup' type PollProps = { poll: DetailedTimedPoll @@ -27,25 +29,11 @@ export function Poll({ poll, wakuVoting, signer }: PollProps) { return ( - - {poll.poll.question} - - {poll.poll.pollType === PollType.WEIGHTED ? 'WEIGHTED' : 'NON WEIGHTED'} - {new Date(poll.poll.endTime).toLocaleString()} - - + {poll.poll.question} {!userInVoters && (
-
setSelectedAnswer(Number.parseInt((e.target as any).value ?? 0))}> - {poll.poll.answers.map((answer, idx) => { - return ( - - {answer} - - ) - })} -
+ undefined} /> {poll.poll.pollType === PollType.WEIGHTED && (
Token amount @@ -93,19 +81,6 @@ export function Poll({ poll, wakuVoting, signer }: PollProps) { ) } -const DateWrapper = styled.div` - font-size: 14px; - text-align: right; -` - -const TitleInfo = styled.div` - display: flex; - flex-direction: column; - margin-right: 10px; - margin-left: auto; - margin-top: auto; -` - const VoteButton = styled.button` width: 100px; border-radius: 5px; @@ -121,35 +96,20 @@ const VoteCount = styled.div` const PollWrapper = styled.div` display: flex; + width: 442px; flex-direction: column; box-shadow: 10px 10px 31px -2px #a3a1a1; border-radius: 5px; - background-color: lightgray; - margin: 10px; - padding: 10px; + background-color: #fbfcfe; + margin-bottom: 24px; ` const PollTitle = styled.div` - display: flex; - padding: 10px; - border: 1px solid black; - border-radius: 5px; -` - -const PollQuestion = styled.div` - display: block; - width: 200px; - margin-left: 10px; - margin-top: 0px; - overflow: auto; -` - -const PollTypeWrapper = styled.div` - width: 150px; - text-align: right; - color: green; - font-size: 14px; + margin-top: 32px; + width: 100%; + text-align: center; font-weight: bold; + font-size: 22px; ` const PollAnswersWrapper = styled.div` @@ -162,8 +122,6 @@ const PollAnswer = styled.div` display: flex; margin: 20px; width: 300px; - border-bottom: 1px solid black; - border-radius: 10px; ` const PollAnswerText = styled.div` diff --git a/packages/react-components/src/WakuPolling/PollList.tsx b/packages/react-components/src/WakuPolling/PollList.tsx index a1128f4..76dc9be 100644 --- a/packages/react-components/src/WakuPolling/PollList.tsx +++ b/packages/react-components/src/WakuPolling/PollList.tsx @@ -13,25 +13,53 @@ type PollListProps = { export function PollList({ wakuVoting, signer }: PollListProps) { const [polls, setPolls] = useState([]) - + const [dividedPolls, setDividedPolls] = useState([[], [], []]) useEffect(() => { const interval = setInterval(async () => { if (wakuVoting) { - setPolls(await wakuVoting.getDetailedTimedPolls()) + const { DetailedTimedPolls, updated } = await wakuVoting.getDetailedTimedPolls() + if (updated) { + setPolls(DetailedTimedPolls) + } } }, 1000) return () => clearInterval(interval) }, [wakuVoting]) + useEffect(() => { + let arrayNo = 0 + const newDividedPolls: DetailedTimedPoll[][] = [[], [], []] + polls.forEach((poll) => { + newDividedPolls[arrayNo].push(poll) + arrayNo++ + if (arrayNo > 2) { + arrayNo = 0 + } + }) + setDividedPolls(newDividedPolls) + }, [polls]) + return ( - {polls.map((poll) => { - return + {dividedPolls.map((pollArray, idx) => { + return ( + + {pollArray.map((poll) => { + return + })} + + ) })} ) } const PollListWrapper = styled.div` display: flex; - flex-direction: column; + margin: 10px; +` + +const ColumnWrapper = styled.div` + display: flex; + flex-direction: column; + margin-right: 25px; ` diff --git a/packages/react-components/src/WakuPolling/index.tsx b/packages/react-components/src/WakuPolling/index.tsx index feef01c..723c157 100644 --- a/packages/react-components/src/WakuPolling/index.tsx +++ b/packages/react-components/src/WakuPolling/index.tsx @@ -39,12 +39,8 @@ function WakuPolling({ appName }: WakuPollingProps) { const Wrapper = styled.div` display: flex; flex-direction: column; - height: 600px; - width: 435px; overflow: auto; - border: 2px solid black; - padding 10px; - border-radius: 10px; + min-height: 500px; ` export default WakuPolling diff --git a/packages/react-components/src/assets/svg/checkIcon.svg b/packages/react-components/src/assets/svg/checkIcon.svg new file mode 100644 index 0000000..031b055 --- /dev/null +++ b/packages/react-components/src/assets/svg/checkIcon.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/react-components/src/components/radioGroup/RadioButton.tsx b/packages/react-components/src/components/radioGroup/RadioButton.tsx new file mode 100644 index 0000000..ff806b7 --- /dev/null +++ b/packages/react-components/src/components/radioGroup/RadioButton.tsx @@ -0,0 +1,41 @@ +import React, { useState } from 'react' +import styled from 'styled-components' +import checkIcon from '../../assets/svg/checkIcon.svg' + +type RadioButtonProps = { + text: string + setOption: () => void +} + +export function RadioButton({ text, setOption }: RadioButtonProps) { + const [icon, setIcon] = useState(false) + return ( + setIcon(!icon)}> + + {text} + + ) +} + +const Wrapper = styled.div` + display: flex; + margin-bottom: 48px; +` + +const Circle = styled.div` + border: 1px solid gray; + border-radius: 50%; + width: 24px; + height: 24px; + + &.icon { + border: 1px solid rgba(255, 255, 255, 1); + background-image: url(${checkIcon}); + background-size: cover; + } +` + +const TextWrapper = styled.div` + margin-left: 20px; + font-size: 22px; +` diff --git a/packages/react-components/src/components/radioGroup/RadioGroup.tsx b/packages/react-components/src/components/radioGroup/RadioGroup.tsx new file mode 100644 index 0000000..c876d22 --- /dev/null +++ b/packages/react-components/src/components/radioGroup/RadioGroup.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import styled from 'styled-components' +import { RadioButton } from './RadioButton' + +type RadioGroupProps = { + options: string[] + setSelectedOption: (option: number) => void +} + +export function RadioGroup({ options, setSelectedOption }: RadioGroupProps) { + return ( +
+ {options.map((option, idx) => ( + setSelectedOption(idx)} /> + ))} +
+ ) +} diff --git a/packages/react-components/src/components/radioGroup/index.tsx b/packages/react-components/src/components/radioGroup/index.tsx new file mode 100644 index 0000000..54d6b89 --- /dev/null +++ b/packages/react-components/src/components/radioGroup/index.tsx @@ -0,0 +1,3 @@ +import { RadioGroup } from './RadioGroup' + +export { RadioGroup } diff --git a/packages/react-components/types/assets/index.d.ts b/packages/react-components/types/assets/index.d.ts new file mode 100644 index 0000000..b0cc96b --- /dev/null +++ b/packages/react-components/types/assets/index.d.ts @@ -0,0 +1,14 @@ + declare module '*.svg' { + const url: string + export default url + } + + declare module '*.jpg' { + const url: string + export default url + } + + declare module '*.png' { + const url: string + export default url + } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index baf7e5a..cfee652 100644 --- a/yarn.lock +++ b/yarn.lock @@ -897,6 +897,7 @@ dependencies: eth-sig-util "^3.0.1" ethers "^5.4.4" + js-waku "^0.10.0" protons "^2.0.1" "@status-waku-voting/react-components@link:packages/react-components": @@ -3309,6 +3310,19 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +copyfiles@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5" + integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== + dependencies: + glob "^7.0.5" + minimatch "^3.0.3" + mkdirp "^1.0.4" + noms "0.0.0" + through2 "^2.0.1" + untildify "^4.0.0" + yargs "^16.1.0" + core-js-pure@^3.0.1: version "3.16.1" resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.16.1.tgz#b997df2669c957a5b29f06e95813a171f993592e" @@ -5346,7 +5360,7 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@7.1.7, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@~7.1.7: +glob@7.1.7, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@~7.1.7: version "7.1.7" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== @@ -7761,7 +7775,7 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -minimatch@3.0.4, minimatch@^3.0.4: +minimatch@3.0.4, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -7803,7 +7817,7 @@ mkdirp-promise@^5.0.1: dependencies: mkdirp "*" -mkdirp@*: +mkdirp@*, mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -8140,6 +8154,14 @@ node-releases@^1.1.73: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.73.tgz#dd4e81ddd5277ff846b80b52bb40c49edf7a7b20" integrity sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg== +noms@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" + integrity sha1-2o69nzr51nYJGbJ9nNyAkqczKFk= + dependencies: + inherits "^2.0.1" + readable-stream "~1.0.31" + normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -9275,7 +9297,7 @@ readable-stream@^3.0.6, readable-stream@^3.4.0, readable-stream@^3.5.0, readable string_decoder "^1.1.1" util-deprecate "^1.0.1" -readable-stream@~1.0.15: +readable-stream@~1.0.15, readable-stream@~1.0.31: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= @@ -10596,7 +10618,7 @@ throat@^4.0.0, throat@^4.1.0: resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= -through2@^2.0.3: +through2@^2.0.1, through2@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -11029,6 +11051,11 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + upath@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" @@ -12020,7 +12047,7 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0: +yargs@16.2.0, yargs@^16.1.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==