Refactor components mobile version (#86)

This commit is contained in:
Szymon Szlachtowicz 2021-09-22 03:24:52 +02:00 committed by GitHub
parent e4c30cb3b5
commit 635be29df3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 167 additions and 96 deletions

View File

@ -71,7 +71,6 @@ export class WakuMessaging {
protected async setObserver() {
this.tokenDecimals = await this.token.decimals()
this.tokenSymbol = await this.token.symbol()
console.log(this.tokenSymbol)
this.waku = await createWaku(this.waku)
await Promise.all(
Object.values(this.wakuMessages).map(async (msgObj) => {

View File

@ -1,5 +1,4 @@
import React, { ReactElement, useCallback, useState } from 'react'
import { useHistory } from 'react-router'
import React, { ReactElement, useCallback, useState, useRef, useMemo } from 'react'
import styled from 'styled-components'
import { Theme } from '@status-waku-voting/react-components'
import { ProposalInfo } from './ProposalInfo'
@ -7,15 +6,17 @@ import { ProposalVote } from './ProposalVoteCard/ProposalVote'
import { WakuVoting } from '@status-waku-voting/core'
import { useVotingRoom } from '@status-waku-voting/proposal-hooks'
import { VoteModal, VoteModalProps } from './VoteModal/VoteModal'
import { useRefMobileVersion } from '@status-waku-voting/react-components'
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
interface ProposalCardProps {
votingRoomId: number
mobileVersion?: boolean
theme: Theme
hideModalFunction?: (val: boolean) => void
availableAmount: number
wakuVoting: WakuVoting
account: string | null | undefined
mobileOnClick: (votingRoom: VotingRoom) => void
CustomVoteModal?: (props: VoteModalProps) => ReactElement
customAgainstClick?: () => void
customForClick?: () => void
@ -25,16 +26,21 @@ export function ProposalCard({
account,
theme,
votingRoomId,
mobileVersion,
availableAmount,
wakuVoting,
CustomVoteModal,
customAgainstClick,
customForClick,
mobileOnClick,
}: ProposalCardProps) {
const history = useHistory()
const votingRoom = useVotingRoom(votingRoomId, wakuVoting)
const ref = useRef<HTMLHeadingElement>(null)
const mobileVersion = useRefMobileVersion(ref, 568)
const tabletVersion = useRefMobileVersion(ref, 703)
const className = useMemo(
() => (mobileVersion ? 'mobile' : tabletVersion ? 'tablet' : ''),
[mobileVersion, tabletVersion]
)
const [showVoteModal, setShowVoteModal] = useState(false)
const [selectedVote, setSelectedVote] = useState(0)
@ -53,7 +59,7 @@ export function ProposalCard({
}
return (
<Card onClick={() => mobileVersion && history.push(`/votingRoom/${votingRoom.id.toString()}`)}>
<Card className={className} ref={ref} onClick={() => mobileVersion && mobileOnClick(votingRoom)}>
{CustomVoteModal ? (
<CustomVoteModal
setShowModal={setShowVoteModal}
@ -63,6 +69,7 @@ export function ProposalCard({
selectedVote={selectedVote}
wakuVoting={wakuVoting}
theme={theme}
className={className}
/>
) : (
<VoteModal
@ -73,9 +80,10 @@ export function ProposalCard({
selectedVote={selectedVote}
wakuVoting={wakuVoting}
theme={theme}
className={className}
/>
)}
<ProposalInfo votingRoom={votingRoom} providerName={wakuVoting.providerName} />
<ProposalInfo votingRoom={votingRoom} providerName={wakuVoting.providerName} className={className} />
<ProposalVote
votingRoom={votingRoom}
selectedVote={selectedVote}
@ -83,6 +91,7 @@ export function ProposalCard({
account={account}
againstClick={customAgainstClick ?? againstClick}
forClick={customForClick ?? forClick}
className={className}
/>
</Card>
)
@ -93,19 +102,20 @@ export const Card = styled.div`
align-items: stretch;
margin-bottom: 24px;
@media (max-width: 768px) {
&.tablet {
flex-direction: column;
box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.15);
}
@media (max-width: 600px) {
&.mobile {
flex-direction: column;
padding-bottom: 24px;
box-shadow: none;
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
}
&:not:first-child {
@media (max-width: 768px) {
&.tablet {
border-top: 1px solid #e0e0e0;
}
}

View File

@ -6,15 +6,15 @@ import { ViewLink } from './ViewLink'
type ProposalInfoProps = {
votingRoom: VotingRoom
providerName: string
mobileMode?: boolean
className?: string
}
export function ProposalInfo({ votingRoom, mobileMode, providerName }: ProposalInfoProps) {
export function ProposalInfo({ votingRoom, className, providerName }: ProposalInfoProps) {
return (
<Card>
<CardHeading>{votingRoom.question}</CardHeading>
<CardText className={mobileMode ? 'mobile' : ''}>{votingRoom.description}</CardText>
<CardViewLink className={mobileMode ? 'mobile' : ''}>
<Card className={className}>
<CardHeading className={className}>{votingRoom.question}</CardHeading>
<CardText className={className}>{votingRoom.description}</CardText>
<CardViewLink className={className}>
<ViewLink
address={
votingRoom.transactionHash ? `https://${providerName}.etherscan.io/tx/${votingRoom.transactionHash}` : '#'
@ -35,7 +35,7 @@ export const Card = styled.div`
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.1);
border-radius: 6px 0px 0px 6px;
@media (max-width: 768px) {
&.tablet {
width: 100%;
margin: 0;
border: none;
@ -43,7 +43,12 @@ export const Card = styled.div`
padding-bottom: 0;
}
@media (max-width: 600px) {
&.mobile {
width: 100%;
margin: 0;
border: none;
box-shadow: none;
padding-bottom: 0;
padding: 0;
}
`
@ -55,7 +60,7 @@ export const CardHeading = styled.div`
margin-bottom: 8px;
align-self: flex-start;
@media (max-width: 600px) {
&.mobile {
font-size: 17px;
}
`
@ -65,35 +70,22 @@ export const CardText = styled.div`
line-height: 18px;
margin-bottom: 16px;
@media (max-width: 600px) {
height: 56px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
&.mobile {
@media (max-width: 600px) {
height: 100%;
overflow: unset;
text-overflow: unset;
-webkit-line-clamp: unset;
margin-bottom: 24px;
}
height: 100%;
overflow: unset;
text-overflow: unset;
-webkit-line-clamp: unset;
margin-bottom: 24px;
}
`
const CardViewLink = styled.div`
@media (max-width: 768px) {
&.tablet {
display: none;
}
&.mobile {
@media (max-width: 600px) {
display: block;
margin-bottom: 37px;
}
display: block;
margin-bottom: 37px;
}
`

View File

@ -1,21 +1,22 @@
import React, { useRef } from 'react'
import React from 'react'
import styled from 'styled-components'
import { Theme, useMobileVersion } from '@status-waku-voting/react-components'
import { Theme } from '@status-waku-voting/react-components'
import { ProposalCard } from './ProposalCard'
import { WakuVoting } from '@status-waku-voting/core'
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
type ProposalListProps = {
theme: Theme
wakuVoting: WakuVoting
votes: number[]
availableAmount: number
account: string | null | undefined
mobileOnClick: (votingRoom: VotingRoom) => void
}
export function ProposalList({ theme, wakuVoting, votes, availableAmount, account }: ProposalListProps) {
const ref = useRef<HTMLHeadingElement>(null)
const mobileVersion = useMobileVersion(ref, 600)
export function ProposalList({ theme, wakuVoting, votes, availableAmount, account, mobileOnClick }: ProposalListProps) {
return (
<List ref={ref}>
<List>
{votes.map((votingRoom) => {
return (
<ProposalCard
@ -23,9 +24,9 @@ export function ProposalList({ theme, wakuVoting, votes, availableAmount, accoun
votingRoomId={votingRoom}
theme={theme}
key={votingRoom}
mobileVersion={mobileVersion}
availableAmount={availableAmount}
wakuVoting={wakuVoting}
mobileOnClick={mobileOnClick}
/>
)
})}

View File

@ -14,6 +14,7 @@ interface ProposalVoteProps {
account: string | null | undefined
againstClick: () => void
forClick: () => void
className: string
}
export function ProposalVote({
@ -23,6 +24,7 @@ export function ProposalVote({
wakuVoting,
againstClick,
forClick,
className,
}: ProposalVoteProps) {
const [alreadyVoted, setAlreadyVoted] = useState(false)
@ -35,20 +37,20 @@ export function ProposalVote({
}, [account, votingRoom])
return (
<Card>
<Card className={className}>
{votingRoom.voteWinner ? (
<CardHeading>Proposal {votingRoom.voteWinner == 1 ? 'rejected' : 'passed'}</CardHeading>
<CardHeading className={className}>Proposal {votingRoom.voteWinner == 1 ? 'rejected' : 'passed'}</CardHeading>
) : (
<CardHeading />
<CardHeading className={className} />
)}
<VoteChart votingRoom={votingRoom} selectedVote={selectedVote} wakuVoting={wakuVoting} />
<VoteChart votingRoom={votingRoom} selectedVote={selectedVote} wakuVoting={wakuVoting} className={className} />
<CardButtons>
<CardButtons className={className}>
{votingRoom.voteWinner ? (
<></>
) : (
<VotesBtns>
<VotesBtns className={className}>
<VoteBtnAgainst disabled={!account || alreadyVoted} onClick={againstClick}>
Vote Against
</VoteBtnAgainst>
@ -59,8 +61,8 @@ export function ProposalVote({
)}
</CardButtons>
<CardVoteBottom>
<CardViewLink>
<CardVoteBottom className={className}>
<CardViewLink className={className}>
{' '}
<ViewLink address={'#'} />
</CardViewLink>
@ -85,7 +87,7 @@ export const Card = styled.div`
border-radius: 6px 0px 0px 6px;
background-color: #fbfcfe;
@media (max-width: 768px) {
&.tablet {
width: 100%;
box-shadow: none;
border-radius: unset;
@ -93,7 +95,11 @@ export const Card = styled.div`
padding-top: 0;
}
@media (max-width: 600px) {
&.mobile {
width: 100%;
box-shadow: none;
border-radius: unset;
background-color: unset;
flex-direction: column;
padding: 0;
border-bottom: none;
@ -108,13 +114,16 @@ export const CardHeading = styled.h2`
margin: 0;
margin-bottom: 15px;
@media (max-width: 768px) {
&.tablet {
font-size: 15px;
line-height: 22px;
margin-bottom: 6px;
}
@media (max-width: 600px) {
&.mobile {
font-size: 15px;
line-height: 22px;
margin-bottom: 6px;
display: none;
}
`
@ -122,7 +131,7 @@ export const CardHeading = styled.h2`
const CardButtons = styled.div`
width: 100%;
@media (max-width: 600px) {
&.mobile {
display: none;
}
`
@ -132,7 +141,7 @@ export const VotesBtns = styled.div`
justify-content: space-between;
width: 100%;
@media (max-width: 600px) {
&.mobile {
margin-top: 24px;
}
`
@ -144,18 +153,18 @@ const CardVoteBottom = styled.div`
width: 100%;
margin-top: 24px;
@media (max-width: 768px) {
&.tablet {
justify-content: space-between;
}
@media (max-width: 600px) {
&.mobile {
display: none;
}
`
const CardViewLink = styled.div`
display: none;
@media (max-width: 768px) {
&.tablet {
display: block;
}
`

View File

@ -15,6 +15,7 @@ import { WakuVoting } from '@status-waku-voting/core'
export interface VoteChartProps {
votingRoom: VotingRoom
wakuVoting: WakuVoting
className: string
proposingAmount?: number
selectedVote?: number
isAnimation?: boolean
@ -28,10 +29,8 @@ export function VoteChart({
selectedVote,
isAnimation,
tabletMode,
className,
}: VoteChartProps) {
const ref = useRef<HTMLHeadingElement>(null)
const mobileVersion = useMobileVersion(ref, 600)
const totalVotesFor = useMemo(
() => (isAnimation ? votingRoom.totalVotesFor : votingRoom.wakuTotalVotesFor),
[votingRoom, proposingAmount]
@ -61,11 +60,12 @@ export function VoteChart({
const voteWinner = useMemo(() => votingRoom.voteWinner, [votingRoom.voteWinner])
return (
<Votes ref={ref}>
<VotesChart className={selectedVote || tabletMode ? '' : 'notModal'}>
<Votes className={className}>
<VotesChart className={selectedVote || tabletMode ? '' : `notModal ${className}`}>
<VoteBox
voteType={2}
mobileVersion={mobileVersion}
className={className}
mobileVersion={className === 'mobile'}
totalVotes={totalVotesAgainst.toNumber()}
won={voteWinner === 2}
selected={isAnimation && selectedVote === 0}
@ -73,11 +73,14 @@ export function VoteChart({
wakuVoting={wakuVoting}
/>
{!voteWinner && (
<TimeLeft className={selectedVote ? '' : 'notModal'}>{formatTimeLeft(votingRoom.timeLeft)}</TimeLeft>
<TimeLeft className={selectedVote ? '' : `notModal ${className}`}>
{formatTimeLeft(votingRoom.timeLeft)}
</TimeLeft>
)}
<VoteBox
voteType={1}
mobileVersion={mobileVersion}
className={className}
mobileVersion={className === 'mobile'}
totalVotes={totalVotesFor.toNumber()}
won={voteWinner === 1}
selected={isAnimation && selectedVote === 1}
@ -85,14 +88,14 @@ export function VoteChart({
wakuVoting={wakuVoting}
/>
</VotesChart>
<VoteGraphBarWrap className={selectedVote || tabletMode ? '' : 'notModal'}>
<VoteGraphBarWrap className={selectedVote || tabletMode ? '' : `notModal ${className}`}>
<VoteGraphBar
graphWidth={graphWidth}
balanceWidth={balanceWidth}
voteWinner={voteWinner}
isAnimation={isAnimation}
/>
<TimeLeftMobile className={selectedVote ? '' : 'notModal'}>
<TimeLeftMobile className={selectedVote ? '' : `notModal ${className}`}>
{formatTimeLeft(votingRoom.timeLeft)}
</TimeLeftMobile>
</VoteGraphBarWrap>
@ -106,13 +109,24 @@ type VoteBoxProps = {
voteType: number
totalVotes: number
wakuVoting: WakuVoting
className: string
selected?: boolean
proposingAmount?: number
}
function VoteBox({ won, mobileVersion, voteType, totalVotes, proposingAmount, selected, wakuVoting }: VoteBoxProps) {
function VoteBox({
won,
mobileVersion,
className,
voteType,
totalVotes,
proposingAmount,
selected,
wakuVoting,
}: VoteBoxProps) {
return (
<VoteBoxWrapper
className={className}
style={{
filter: won ? 'grayscale(1)' : 'none',
alignItems: mobileVersion ? (voteType == 1 ? 'flex-end' : 'flex-start') : 'center',
@ -145,11 +159,11 @@ const Votes = styled.div`
width: 100%;
position: relative;
@media (max-width: 768px) {
&.tablet {
margin-bottom: 24px;
}
@media (max-width: 600px) {
&.mobile {
margin-bottom: 0;
}
`
@ -161,7 +175,7 @@ const VotesChart = styled.div`
margin-bottom: 13px;
&.notModal {
@media (max-width: 768px) {
&.tablet {
margin-bottom: 0;
}
}
@ -180,11 +194,11 @@ const VoteBoxWrapper = styled.div`
font-weight: bold;
}
@media (max-width: 768px) {
&.tablet {
min-width: 70px;
}
@media (max-width: 600px) {
&.mobile {
min-width: unset;
}
`
@ -202,11 +216,12 @@ const TimeLeft = styled.div`
color: #939ba1;
&.notModal {
@media (max-width: 768px) {
&.tablet {
top: -27px;
}
@media (max-width: 600px) {
&.mobile {
top: -27px;
display: none;
}
}
@ -222,7 +237,7 @@ const TimeLeftMobile = styled.div`
letter-spacing: 0.1px;
color: #939ba1;
@media (max-width: 600px) {
&.mobile {
font-size: 12px;
}
`
@ -233,7 +248,7 @@ const VoteGraphBarWrap = styled.div`
justify-content: center;
&.notModal {
@media (max-width: 768px) {
&.tablet {
position: absolute;
width: 65%;
top: 4px;
@ -241,7 +256,11 @@ const VoteGraphBarWrap = styled.div`
transform: translateX(-50%);
}
@media (max-width: 600px) {
&.mobile {
position: absolute;
top: 4px;
left: 50%;
transform: translateX(-50%);
width: 70%;
}
}

View File

@ -15,6 +15,7 @@ export interface AmountModalProps {
setShowConfirmModal: (show: boolean) => void
setProposingAmount: (val: number) => void
wakuVoting: WakuVoting
className: string
}
export function AmountModal({
@ -25,6 +26,7 @@ export function AmountModal({
setShowConfirmModal,
setProposingAmount,
wakuVoting,
className,
}: AmountModalProps) {
const disabled = proposingAmount === 0
const funds = availableAmount > 0
@ -39,6 +41,7 @@ export function AmountModal({
proposingAmount={proposingAmount}
selectedVote={selectedVote}
wakuVoting={wakuVoting}
className={className}
/>
<VotePropose
availableAmount={availableAmount}

View File

@ -11,6 +11,7 @@ interface ConfirmModalProps {
selectedVote: number
setShowModal: (val: boolean) => void
wakuVoting: WakuVoting
className: string
}
export function ConfirmModal({
@ -19,6 +20,7 @@ export function ConfirmModal({
proposingAmount,
setShowModal,
wakuVoting,
className,
}: ConfirmModalProps) {
return (
<VoteConfirm>
@ -29,6 +31,7 @@ export function ConfirmModal({
selectedVote={selectedVote}
isAnimation={true}
wakuVoting={wakuVoting}
className={className}
/>
<FinalBtn onClick={() => setShowModal(false)}>Close</FinalBtn>

View File

@ -13,6 +13,7 @@ export interface VoteModalProps {
selectedVote: number
wakuVoting: WakuVoting
theme: Theme
className: string
}
export function VoteModal({
@ -23,6 +24,7 @@ export function VoteModal({
selectedVote,
wakuVoting,
theme,
className,
}: VoteModalProps) {
const [screen, setScreen] = useState(0)
useEffect(() => setScreen(0), [])
@ -44,6 +46,7 @@ export function VoteModal({
setShowConfirmModal={() => setScreen(1)}
setProposingAmount={setProposingAmount}
wakuVoting={wakuVoting}
className={className}
/>
) : (
<ConfirmModal
@ -53,6 +56,7 @@ export function VoteModal({
setShowModal(false)
}}
wakuVoting={wakuVoting}
className={className}
proposingAmount={proposingAmount}
/>
)}

View File

@ -44,7 +44,7 @@ export function VotePropose({ availableAmount, proposingAmount, setProposingAmou
</span>
</VoteProposingInfo>
<VoteProposingAmount
value={inputFocused ? proposingAmount.toString() : addCommas(proposingAmount) + ` wakuVoting.tokenSymbol`}
value={inputFocused ? proposingAmount.toString() : addCommas(proposingAmount) + ` ${wakuVoting.tokenSymbol}`}
onInput={(e) => {
setProposingAmount(Number(e.currentTarget.value))
}}

View File

@ -30,9 +30,9 @@ export function ProposalVoteMobile({ wakuVoting, availableAmount, account }: Pro
return (
<Card>
<ProposalInfo votingRoom={votingRoom} mobileMode={true} providerName={wakuVoting.providerName} />
<ProposalInfo votingRoom={votingRoom} className={'mobile'} providerName={wakuVoting.providerName} />
<VoteChartWrap>
<VoteChart votingRoom={votingRoom} selectedVote={selectedVoted} wakuVoting={wakuVoting} />
<VoteChart votingRoom={votingRoom} selectedVote={selectedVoted} wakuVoting={wakuVoting} className={'mobile'} />
</VoteChartWrap>
{!voteWinner && (
<VotePropose

View File

@ -6,8 +6,9 @@ import { WakuVoting } from '@status-waku-voting/core'
import { useTokenBalance } from '@status-waku-voting/react-components'
import { useEthers } from '@usedapp/core'
import { Modal, Networks, useMobileVersion, Theme } from '@status-waku-voting/react-components'
import { useHistory } from 'react-router'
import { useVotingRoomsId } from '@status-waku-voting/proposal-hooks'
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
import { useHistory } from 'react-router'
type ProposalListHeaderProps = {
votesLength: number
@ -23,7 +24,7 @@ function ProposalListHeader({ votesLength, theme, wakuVoting, tokenBalance, acco
const { activateBrowserWallet } = useEthers()
const history = useHistory()
const ref = useRef<HTMLHeadingElement>(null)
const mobileVersion = useMobileVersion(ref, 600)
const mobileVersion = useMobileVersion(600)
const onCreateClick = useCallback(() => {
mobileVersion ? history.push(`/creation`) : setShowNewVoteModal(true)
@ -66,7 +67,7 @@ type ProposalProps = {
export function Proposal({ wakuVoting, account }: ProposalProps) {
const votes = useVotingRoomsId(wakuVoting)
const tokenBalance = useTokenBalance(account, wakuVoting)
const history = useHistory()
return (
<ProposalWrapper>
<ProposalVotesWrapper>
@ -84,6 +85,7 @@ export function Proposal({ wakuVoting, account }: ProposalProps) {
wakuVoting={wakuVoting}
votes={votes}
availableAmount={tokenBalance}
mobileOnClick={(votingRoom: VotingRoom) => history.push(`/votingRoom/${votingRoom.id.toString()}`)}
/>
)}
</ProposalVotesWrapper>

View File

@ -36,7 +36,7 @@ function Proposals() {
config?.multicallAddresses?.[chainId ?? 1337]
)
const ref = useRef<HTMLHeadingElement>(null)
const mobileVersion = useMobileVersion(ref, 600)
const mobileVersion = useMobileVersion(600)
return (
<Wrapper ref={ref}>

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react'
export function useMobileVersion(myRef: React.RefObject<HTMLHeadingElement>, sizeThreshold: number) {
export function useMobileVersion(sizeThreshold: number) {
const [mobileVersion, setMobileVersion] = useState(false)
useEffect(() => {
@ -21,7 +21,7 @@ export function useMobileVersion(myRef: React.RefObject<HTMLHeadingElement>, siz
return () => {
window.removeEventListener('resize', checkDimensions)
}
}, [myRef, mobileVersion])
}, [mobileVersion])
return mobileVersion
}

View File

@ -0,0 +1,27 @@
import React, { useEffect, useState } from 'react'
export function useRefMobileVersion(myRef: React.RefObject<HTMLHeadingElement>, sizeThreshold: number) {
const [mobileVersion, setMobileVersion] = useState(false)
useEffect(() => {
const checkDimensions = () => {
const width = myRef?.current?.offsetWidth ?? 0
if (width && width < sizeThreshold && width > 0) {
if (mobileVersion === false) {
setMobileVersion(true)
}
} else {
if (mobileVersion === true) {
setMobileVersion(false)
}
}
}
checkDimensions()
window.addEventListener('resize', checkDimensions)
return () => {
window.removeEventListener('resize', checkDimensions)
}
}, [myRef, mobileVersion, myRef?.current?.offsetWidth])
return mobileVersion
}

View File

@ -16,10 +16,12 @@ import statusIcon from './assets/svg/status.svg'
import themes, { Theme } from './style/themes'
import { useRefSize } from './hooks/useRefSize'
import { useMobileVersion } from './hooks/useMobileVersion'
import { useRefMobileVersion } from './hooks/useRefMobileVersion'
import { useTokenBalance } from './hooks/useTokenBalance'
export {
useTokenBalance,
useMobileVersion,
useRefMobileVersion,
useRefSize,
Modal,
Input,