From 2b4903537382649a0582f0dd3dbcc1e4cd83bf81 Mon Sep 17 00:00:00 2001 From: Szymon Szlachtowicz <38212223+Szymx95@users.noreply.github.com> Date: Thu, 16 Sep 2021 14:34:14 +0200 Subject: [PATCH] Refactor proposal modal and mobile (#75) --- .../src/components/Proposal.tsx | 68 +++++++++++--- .../src/components/ProposalHeader.tsx | 44 ++------- .../src/components/VotingEmpty.tsx | 54 ++--------- .../mobile/ProposalHeaderMobile.tsx | 92 ------------------- .../components/mobile/ProposalMainMobile.tsx | 55 ----------- .../src/components/mobile/ProposalMobile.tsx | 4 +- .../components/newVoteModal/NewVoteModal.tsx | 10 +- .../components/newVoteModal/ProposeModal.tsx | 2 +- .../newVoteModal/ProposeVoteModal.tsx | 1 - .../src/hooks/useVotingRooms.ts | 25 +++++ .../src/hooks/useWakuProposal.ts | 13 ++- packages/proposal-hooks/src/index.ts | 3 +- 12 files changed, 121 insertions(+), 250 deletions(-) delete mode 100644 packages/proposal-components/src/components/mobile/ProposalHeaderMobile.tsx delete mode 100644 packages/proposal-components/src/components/mobile/ProposalMainMobile.tsx create mode 100644 packages/proposal-hooks/src/hooks/useVotingRooms.ts diff --git a/packages/proposal-components/src/components/Proposal.tsx b/packages/proposal-components/src/components/Proposal.tsx index 36a5c48..ddf166c 100644 --- a/packages/proposal-components/src/components/Proposal.tsx +++ b/packages/proposal-components/src/components/Proposal.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useCallback, useEffect, useRef, useState } from 'react' import styled from 'styled-components' import { ProposalHeader } from './ProposalHeader' import { blueTheme } from '@status-waku-voting/react-components/dist/esm/src/style/themes' @@ -8,6 +8,11 @@ import { WakuVoting } from '@status-waku-voting/core' import { VotingEmpty } from './VotingEmpty' import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType' import { useTokenBalance } from '@status-waku-voting/react-components' +import { NewVoteModal } from './newVoteModal/NewVoteModal' +import { useEthers } from '@usedapp/core' +import { Modal, Networks, useMobileVersion } from '@status-waku-voting/react-components' +import { useHistory } from 'react-router' +import { useVotingRooms } from '@status-waku-voting/proposal-hooks' type ProposalProps = { wakuVoting: WakuVoting @@ -15,24 +20,56 @@ type ProposalProps = { } export function Proposal({ wakuVoting, account }: ProposalProps) { - const [votes, setVotes] = useState([]) + const votes = useVotingRooms(wakuVoting) const tokenBalance = useTokenBalance(account, wakuVoting) + const [showNewVoteModal, setShowNewVoteModal] = useState(false) + const [showConnectionModal, setShowConnectionModal] = useState(false) - useEffect(() => { - const interval = setInterval(async () => { - setVotes(await wakuVoting.getVotingRooms()) - }, 10000) - wakuVoting.getVotingRooms().then((e) => setVotes(e)) - return () => clearInterval(interval) + const { activateBrowserWallet } = useEthers() + const history = useHistory() + + const ref = useRef(null) + const mobileVersion = useMobileVersion(ref, 600) + + const onCreateClick = useCallback(() => { + mobileVersion ? history.push(`/creation`) : setShowNewVoteModal(true) + }, [mobileVersion]) + + const onConnectClick = useCallback(() => { + if ((window as any).ethereum) { + activateBrowserWallet() + } else setShowConnectionModal(true) }, []) return ( - + + + {showConnectionModal && ( + + + + )} {votes && votes?.length === 0 ? ( - + ) : ( - + )} @@ -51,7 +88,16 @@ const ProposalWrapper = styled.div` padding: 150px 32px 50px; width: 100%; min-height: 100vh; + + @media (max-width: 600px) { + padding: 132px 16px 32px; + } + + @media (max-width: 425px) { + padding: 64px 16px 84px; + } ` + export const ProposalVotesWrapper = styled(ProposalWrapper)` width: 100%; padding: 0; diff --git a/packages/proposal-components/src/components/ProposalHeader.tsx b/packages/proposal-components/src/components/ProposalHeader.tsx index 61c2628..07fc22a 100644 --- a/packages/proposal-components/src/components/ProposalHeader.tsx +++ b/packages/proposal-components/src/components/ProposalHeader.tsx @@ -3,63 +3,32 @@ import styled from 'styled-components' import { useEthers } from '@usedapp/core' import { Modal, Networks, CreateButton } from '@status-waku-voting/react-components' import { Theme } from '@status-waku-voting/react-components/dist/esm/src/style/themes' -import { WakuVoting } from '@status-waku-voting/core' -import { BigNumber } from 'ethers' -import { NewVoteModal } from './newVoteModal/NewVoteModal' type ProposalHeaderProps = { theme: Theme - wakuVoting: WakuVoting - availableAmount: number + account: string | null | undefined + onCreateClick: () => void + onConnectClick: () => void } -export function ProposalHeader({ theme, wakuVoting, availableAmount }: ProposalHeaderProps) { - const { activateBrowserWallet, account, library } = useEthers() - const [selectConnect, setSelectConnect] = useState(false) - const [showModal, setShowModal] = useState(false) - +export function ProposalHeader({ theme, account, onCreateClick, onConnectClick }: ProposalHeaderProps) { return ( -
Your voice has real power Take part in a decentralised governance by voting on proposals provided by community or creating your own.
- {account ? ( - { - setShowModal(true) - }} - > + Create proposal ) : ( - { - if ((window as any).ethereum) { - activateBrowserWallet() - } else setSelectConnect(true) - }} - > + Connect to vote )} - {selectConnect && ( - - - - )}
) } @@ -81,6 +50,7 @@ const Header = styled.div` padding: 12px 16px 0; width: 100%; background: #f8faff; + z-index: 10; } ` diff --git a/packages/proposal-components/src/components/VotingEmpty.tsx b/packages/proposal-components/src/components/VotingEmpty.tsx index d37a6d2..ec4f601 100644 --- a/packages/proposal-components/src/components/VotingEmpty.tsx +++ b/packages/proposal-components/src/components/VotingEmpty.tsx @@ -1,35 +1,17 @@ -import React, { useEffect, useState, useRef } from 'react' -import { useHistory } from 'react-router' -import { useEthers } from '@usedapp/core' +import React from 'react' import styled from 'styled-components' -import { CreateButton, Modal, Networks, Theme, useMobileVersion } from '@status-waku-voting/react-components' -import { WakuVoting } from '@status-waku-voting/core' -import { NewVoteModal } from './newVoteModal/NewVoteModal' +import { CreateButton, Theme } from '@status-waku-voting/react-components' type VotingEmptyProps = { theme: Theme - wakuVoting: WakuVoting - availableAmount: number + account: string | null | undefined + onCreateClick: () => void + onConnectClick: () => void } -export function VotingEmpty({ wakuVoting, theme, availableAmount }: VotingEmptyProps) { - const { account, activateBrowserWallet } = useEthers() - const [selectConnect, setSelectConnect] = useState(false) - const [showModal, setShowModal] = useState(false) - const history = useHistory() - - const ref = useRef(null) - const mobileVersion = useMobileVersion(ref, 600) - +export function VotingEmpty({ theme, account, onCreateClick, onConnectClick }: VotingEmptyProps) { return ( - - + There are no proposals at the moment! @@ -38,32 +20,14 @@ export function VotingEmpty({ wakuVoting, theme, availableAmount }: VotingEmptyP {account ? ( - { - mobileVersion ? history.push(`/creation`) : setShowModal(true) - }} - > + Create proposal ) : ( - { - if ((window as any).ethereum) { - activateBrowserWallet() - } else setSelectConnect(true) - }} - > + Connect to vote )} - - {selectConnect && ( - - - - )} ) } diff --git a/packages/proposal-components/src/components/mobile/ProposalHeaderMobile.tsx b/packages/proposal-components/src/components/mobile/ProposalHeaderMobile.tsx deleted file mode 100644 index 640b3d2..0000000 --- a/packages/proposal-components/src/components/mobile/ProposalHeaderMobile.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import React, { useState } from 'react' -import { useHistory } from 'react-router' -import styled from 'styled-components' -import { useEthers } from '@usedapp/core' -import { Modal, Networks, CreateButton } from '@status-waku-voting/react-components' -import { Theme } from '@status-waku-voting/react-components/dist/esm/src/style/themes' -import { Wrapper } from '../ProposalHeader' - -type ProposalHeaderMobileProps = { - theme: Theme -} - -export function ProposalHeaderMobile({ theme }: ProposalHeaderMobileProps) { - const { activateBrowserWallet, account } = useEthers() - const [selectConnect, setSelectConnect] = useState(false) - const history = useHistory() - - return ( - -
- Your voice has real power - - Take part in a decentralised governance by voting on proposals provided by community or creating your own. - -
- {account ? ( - history.push(`/creation`)}> - Create proposal - - ) : ( - { - if ((window as any).ethereum) { - activateBrowserWallet() - } else setSelectConnect(true) - }} - > - Connect to vote - - )} - {selectConnect && ( - - - - )} -
- ) -} - -const Header = styled.div` - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - max-width: 680px; - - @media (max-width: 425px) { - position: fixed; - padding: 12px 16px 0; - width: 100%; - background: #f8faff; - z-index: 10; - } -` - -const Heading = styled.h1` - font-weight: bold; - font-size: 28px; - line-height: 38px; - letter-spacing: -0.4px; - margin: 0; - margin-bottom: 8px; - - @media (max-width: 425px) { - font-size: 22px; - line-height: 30px; - } -` - -const HeaderText = styled.p` - font-size: 22px; - line-height: 32px; - margin: 0; - margin-bottom: 24px; - - @media (max-width: 425px) { - font-size: 13px; - line-height: 18px; - margin-bottom: 16px; - } -` diff --git a/packages/proposal-components/src/components/mobile/ProposalMainMobile.tsx b/packages/proposal-components/src/components/mobile/ProposalMainMobile.tsx deleted file mode 100644 index 1b7d2f9..0000000 --- a/packages/proposal-components/src/components/mobile/ProposalMainMobile.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import React, { useEffect, useState } from 'react' -import { blueTheme } from '@status-waku-voting/react-components/dist/esm/src/style/themes' -import { ProposalList } from '../ProposalList' -import { VotingEmpty } from '../VotingEmpty' -import { NotificationItem } from '../NotificationItem' -import { ProposalHeaderMobile } from './ProposalHeaderMobile' -import styled from 'styled-components' -import { WakuVoting } from '@status-waku-voting/core' -import { ProposalVotesWrapper } from '../Proposal' -import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType' - -type ProposalMainMobileProps = { - wakuVoting: WakuVoting - availableAmount: number -} - -export function ProposalMainMobile({ wakuVoting, availableAmount }: ProposalMainMobileProps) { - const [votes, setVotes] = useState([]) - - useEffect(() => { - const interval = setInterval(async () => { - setVotes(await wakuVoting.getVotingRooms()) - }, 10000) - return () => clearInterval(interval) - }, []) - - return ( - - {votes && votes?.length === 0 ? ( - - ) : ( - - - - - )} - - - ) -} - -const ProposalWrapper = styled.div` - display: flex; - flex-direction: column; - align-items: center; - max-width: 1000px; - margin: 0 auto; - width: 100%; - min-height: 100vh; - padding: 132px 16px 32px; - - @media (max-width: 425px) { - padding: 64px 16px 84px; - } -` diff --git a/packages/proposal-components/src/components/mobile/ProposalMobile.tsx b/packages/proposal-components/src/components/mobile/ProposalMobile.tsx index 7c0b94a..2b3dbe6 100644 --- a/packages/proposal-components/src/components/mobile/ProposalMobile.tsx +++ b/packages/proposal-components/src/components/mobile/ProposalMobile.tsx @@ -4,7 +4,7 @@ import { BrowserRouter } from 'react-router-dom' import styled from 'styled-components' import { ProposalVoteMobile } from './ProposalVoteMobile' import { ProposeMobile } from './ProposeMobile' -import { ProposalMainMobile } from './ProposalMainMobile' +import { Proposal } from '../Proposal' import { WakuVoting } from '@status-waku-voting/core' import { useTokenBalance } from '@status-waku-voting/react-components' @@ -27,7 +27,7 @@ export function ProposalMobile({ wakuVoting, account }: ProposalMobileProps) { - +
diff --git a/packages/proposal-components/src/components/newVoteModal/NewVoteModal.tsx b/packages/proposal-components/src/components/newVoteModal/NewVoteModal.tsx index 462b62b..9031b04 100644 --- a/packages/proposal-components/src/components/newVoteModal/NewVoteModal.tsx +++ b/packages/proposal-components/src/components/newVoteModal/NewVoteModal.tsx @@ -1,6 +1,6 @@ import { WakuVoting } from '@status-waku-voting/core' import { Modal, Theme } from '@status-waku-voting/react-components' -import React, { useState } from 'react' +import React, { useCallback, useEffect, useState } from 'react' import { ProposeModal } from './ProposeModal' import { ProposeVoteModal } from './ProposeVoteModal' @@ -17,6 +17,14 @@ export function NewVoteModal({ theme, showModal, setShowModal, availableAmount, const [title, setTitle] = useState('') const [text, setText] = useState('') + useEffect(() => { + if (!showModal) { + setScreen(1) + setTitle('') + setText('') + } + }, [showModal]) + if (!showModal) { return null } diff --git a/packages/proposal-components/src/components/newVoteModal/ProposeModal.tsx b/packages/proposal-components/src/components/newVoteModal/ProposeModal.tsx index dec64b8..63e9229 100644 --- a/packages/proposal-components/src/components/newVoteModal/ProposeModal.tsx +++ b/packages/proposal-components/src/components/newVoteModal/ProposeModal.tsx @@ -26,7 +26,7 @@ export function ProposeModal({ return ( - {insufficientFunds && ( + {availableAmount < 10000 && ( ⚠️ You need at least 10,000 ABC to create a proposal! diff --git a/packages/proposal-components/src/components/newVoteModal/ProposeVoteModal.tsx b/packages/proposal-components/src/components/newVoteModal/ProposeVoteModal.tsx index 15eced9..f443b9b 100644 --- a/packages/proposal-components/src/components/newVoteModal/ProposeVoteModal.tsx +++ b/packages/proposal-components/src/components/newVoteModal/ProposeVoteModal.tsx @@ -27,7 +27,6 @@ export function ProposeVoteModal({ setTitle, setText, }: ProposeVoteModalProps) { - const { library } = useEthers() const [proposingAmount, setProposingAmount] = useState(0) return ( diff --git a/packages/proposal-hooks/src/hooks/useVotingRooms.ts b/packages/proposal-hooks/src/hooks/useVotingRooms.ts new file mode 100644 index 0000000..6a9ef96 --- /dev/null +++ b/packages/proposal-hooks/src/hooks/useVotingRooms.ts @@ -0,0 +1,25 @@ +import { id } from '@ethersproject/hash' +import { WakuVoting } from '@status-waku-voting/core' +import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType' +import React, { useEffect, useRef, useState } from 'react' + +export function useVotingRooms(wakuVoting: WakuVoting) { + const [votes, setVotes] = useState([]) + const hash = useRef('') + useEffect(() => { + const interval = setInterval(async () => { + const newRooms = await wakuVoting.getVotingRooms() + const newHash = id(newRooms.map((votingRoom) => votingRoom.id.toString()).join('')) + if (newHash != hash.current) { + setVotes(newRooms) + hash.current = newHash + } + }, 10000) + wakuVoting.getVotingRooms().then((e) => { + setVotes(e) + hash.current = id(e.map((votingRoom) => votingRoom.id.toString()).join('')) + }) + return () => clearInterval(interval) + }, []) + return votes +} diff --git a/packages/proposal-hooks/src/hooks/useWakuProposal.ts b/packages/proposal-hooks/src/hooks/useWakuProposal.ts index 10368de..4fa9ad6 100644 --- a/packages/proposal-hooks/src/hooks/useWakuProposal.ts +++ b/packages/proposal-hooks/src/hooks/useWakuProposal.ts @@ -1,5 +1,5 @@ import { WakuVoting } from '@status-waku-voting/core' -import React, { useEffect, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import { Web3Provider } from '@ethersproject/providers' export function useWakuProposal( @@ -9,16 +9,21 @@ export function useWakuProposal( multicallAddress: string | undefined ) { const [waku, setWaku] = useState(undefined) - + const queuePos = useRef(0) + const queueSize = useRef(0) useEffect(() => { ;(window as any).ethereum.on('chainChanged', () => window.location.reload()) - const createWaku = async () => { + const createWaku = async (queue: number) => { + while (queue != queuePos.current) { + await new Promise((r) => setTimeout(r, 1000)) + } if (provider && multicallAddress) { const wak = await WakuVoting.create(appName, contractAddress, provider, multicallAddress) setWaku(wak) } + queuePos.current++ } - createWaku() + createWaku(queueSize.current++) return () => (window as any).ethereum.removeListener('chainChanged', () => window.location.reload()) }, [provider, multicallAddress, contractAddress]) diff --git a/packages/proposal-hooks/src/index.ts b/packages/proposal-hooks/src/index.ts index ebde47d..318b9e3 100644 --- a/packages/proposal-hooks/src/index.ts +++ b/packages/proposal-hooks/src/index.ts @@ -1,3 +1,4 @@ import { useWakuProposal } from './hooks/useWakuProposal' import { useVotingRoom } from './hooks/useVotingRoom' -export { useWakuProposal, useVotingRoom } +import { useVotingRooms } from './hooks/useVotingRooms' +export { useWakuProposal, useVotingRoom, useVotingRooms }