Add modal propose community (#36)

This commit is contained in:
Maria Rushkova 2021-06-17 11:39:07 +02:00 committed by GitHub
parent 371864a4f1
commit 532b9596b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 339 additions and 156 deletions

View File

@ -152,17 +152,18 @@ export const Card = styled.div`
display: flex;
align-items: stretch;
`
const CardInfoBlock = styled.div`
export const CardCommunityWrap = styled.div`
width: 50%;
margin: 13px 0;
display: flex;
flex-direction: column;
align-items: center;
padding: 24px 24px 16px;
box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.1);
border-radius: 6px 0px 0px 6px;
`
const CardInfoBlock = styled.div`
display: flex;
flex-direction: column;
align-items: center;
`
const Community = styled.div`
display: flex;

View File

@ -38,13 +38,14 @@ const PopUpOverlay = styled.div`
background-color: rgba(0, 0, 0, 0.4);
z-index: 9999;
transition: all 0.3s;
overflow: auto;
`
const PopUpWindow = styled.div`
display: flex;
flex-direction: column;
max-width: 475px;
margin: 205px auto 0;
margin: 20vh auto 2vh;
padding: 24px;
background-color: ${Colors.GrayLight};
box-shadow: 0px 6px 12px rgba(0, 0, 0, 0.1);

View File

@ -15,8 +15,12 @@ export const PageInfo = ({ heading, text }: PageInfoProps) => (
</InfoBlock>
)
export function ProposeButton() {
return <ProposeButtonStyled>Propose community</ProposeButtonStyled>
interface ProposeButtonProps {
onClick: () => void
}
export function ProposeButton({ onClick }: ProposeButtonProps) {
return <ProposeButtonStyled onClick={onClick}>Propose community</ProposeButtonStyled>
}
export function ConnectButton() {

View File

@ -0,0 +1,106 @@
import React from 'react'
import styled from 'styled-components'
import { getCommunityDetails } from '../../helpers/apiMock'
import { ButtonPrimary } from '../Button'
import { CardCommunity } from '../Card'
import { Input } from '../Input'
import { VotePropose } from '../votes/VotePropose'
interface ProposeModalProps {
availableAmount: number
setShowConfirmModal: (val: boolean) => void
setPublicKey: (publicKey: string) => void
publicKey: string
}
export function ProposeModal({ availableAmount, setShowConfirmModal, setPublicKey, publicKey }: ProposeModalProps) {
const communityFound = getCommunityDetails(publicKey)
return (
<CommunityProposing>
<CommunityKeyLabel>
Community public key
<CommunityKey
value={publicKey}
placeholder="E.g. 0xbede83eef5d82c4dd5d82c4dd5fa837ad"
onChange={(e) => {
setPublicKey(e.currentTarget.value)
}}
></CommunityKey>
</CommunityKeyLabel>
{publicKey && communityFound && (
<div>
<CardCommunity community={communityFound} />
<VoteProposeWrap>
<VotePropose availableAmount={availableAmount} />
</VoteProposeWrap>
</div>
)}
{!communityFound && (
<ProposingInfo>
<span></span>
<InfoText>To propose a community, it must have at least 42 members and have a ENS domain.</InfoText>
</ProposingInfo>
)}
<ProposingBtn
type="submit"
disabled={!communityFound}
onSubmit={() => setShowConfirmModal(true)}
onClick={() => setShowConfirmModal(true)}
>
Confirm vote to add community
</ProposingBtn>
</CommunityProposing>
)
}
const CommunityProposing = styled.form`
display: flex;
flex-direction: column;
align-items: center;
`
const CommunityKey = styled(Input)`
width: 100%;
margin-top: 10px;
margin-bottom: 32px;
font-size: 15px;
line-height: 22px;
`
const CommunityKeyLabel = styled.label`
width: 100%;
font-size: 15px;
line-height: 22px;
`
const VoteProposeWrap = styled.div`
margin-top: 32px;
`
const ProposingInfo = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin-bottom: 32px;
& > span {
font-size: 24px;
line-height: 32px;
margin-right: 16px;
}
`
const InfoText = styled.div`
font-size: 12px;
line-height: 16px;
letter-spacing: 0.1px;
`
const ProposingBtn = styled(ButtonPrimary)`
width: 100%;
padding: 11px 0;
`

View File

@ -1,11 +1,9 @@
import React, { useState } from 'react'
import React from 'react'
import styled from 'styled-components'
import { Colors } from '../../constants/styles'
import { VoteChart } from '../votes/VoteChart'
import { Input } from '../Input'
import { ButtonSecondary } from '../Button'
import { addCommas } from '../../helpers/addCommas'
import { CurrentVoting } from '../../models/community'
import { VotePropose } from '../votes/VotePropose'
export interface VoteModalProps {
vote: CurrentVoting
@ -20,63 +18,10 @@ export interface VoteModalProps {
}
export function VoteModal({ vote, selectedVote, availableAmount, setShowConfirmModal }: VoteModalProps) {
const [proposingAmount, setProposingAmount] = useState(0)
const [displayAmount, setDisplayAmount] = useState('0 SNT')
let step = 10 ** (Math.floor(Math.log10(availableAmount)) - 2)
if (availableAmount < 100) {
step = 1
}
const sliderChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (Number(e.target.value) == step * Math.floor(availableAmount / step)) {
setProposingAmount(availableAmount)
setDisplayAmount(addCommas(availableAmount) + ' SNT')
} else {
setProposingAmount(Number(e.target.value))
setDisplayAmount(addCommas(Number(e.target.value)) + ' SNT')
}
}
const progress = (proposingAmount / availableAmount) * 100 + '%'
return (
<CardProposing>
<VoteChart vote={vote} />
<VoteProposing>
<VoteProposingInfo>
<p>My vote</p>
<span>Available {addCommas(availableAmount)} SNT</span>
</VoteProposingInfo>
<VoteProposingAmount
value={displayAmount}
onInput={(e) => {
setProposingAmount(Number(e.currentTarget.value))
setDisplayAmount(e.currentTarget.value)
}}
onBlur={() => setDisplayAmount(addCommas(proposingAmount) + ' SNT')}
onFocus={() => setDisplayAmount(proposingAmount.toString())}
/>
<VoteProposingRangeWrap>
<VoteProposingRange
type="range"
min={0}
max={availableAmount}
step={step}
value={proposingAmount}
onChange={sliderChange}
style={{
background: `linear-gradient(90deg, ${Colors.VioletDark} 0% ${progress}, ${Colors.VioletSecondary} ${progress} 100%)`,
}}
/>
</VoteProposingRangeWrap>
</VoteProposing>
{vote?.type === 'Remove' && Number(proposingAmount) > 2000000 && vote.timeLeft / 3600 > 24 && (
<VoteWarning>
<span></span>
<WarningText>{`Your vote will shorten vote duration! Votes over 2,000,000 SNT for ${selectedVote.noun} of the community shortens the vote duration to 24 hours.`}</WarningText>
</VoteWarning>
)}
<VotePropose vote={vote} selectedVote={selectedVote} availableAmount={availableAmount} />
<VoteConfirmBtn
onClick={() => setShowConfirmModal(true)}
@ -91,90 +36,6 @@ const CardProposing = styled.div`
align-items: center;
`
const VoteProposing = styled.div`
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
`
const VoteProposingInfo = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
margin-bottom: 10px;
& > span {
font-size: 12px;
line-height: 16px;
color: ${Colors.GreyText};
}
`
const VoteProposingAmount = styled(Input)`
width: 100%;
margin-bottom: 16px;
font-size: 15px;
line-height: 22px;
`
const VoteProposingRangeWrap = styled.div`
width: 294px;
margin-bottom: 32px;
`
const VoteProposingRange = styled.input`
appearance: none;
width: 100%;
height: 4px;
padding: 0;
margin: 10px 0;
border-radius: 2px;
outline: none;
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: ${Colors.Violet};
cursor: pointer;
}
&::-moz-range-thumb {
width: 20px;
height: 20px;
background: ${Colors.Violet};
border: 0.5px solid rgba(0, 0, 0, 0);
border-radius: 50px;
cursor: pointer;
}
`
const VoteWarning = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 16px;
background: #ffeff2;
border-radius: 6px;
margin-bottom: 32px;
& > span {
font-size: 24px;
line-height: 32px;
}
`
const WarningText = styled.div`
max-width: 353px;
font-size: 12px;
line-height: 16px;
letter-spacing: 0.1px;
`
const VoteConfirmBtn = styled(ButtonSecondary)`
width: 100%;
padding: 11px 0;

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react'
import { Card, CardCommunity } from '../Card'
import { Card, CardCommunity, CardCommunityWrap } from '../Card'
import { CardFeature } from '../card/CardFeature'
import styled from 'styled-components'
import { CommunityDetail, DirectorySortingEnum } from '../../models/community'
@ -26,7 +26,10 @@ function DirectoryCard({ community }: DirectoryCardProps) {
}
return (
<Card>
<CardCommunity community={community} />
<CardCommunityWrap>
{' '}
<CardCommunity community={community} />
</CardCommunityWrap>
<CardFeature
heading="Feature this community?"
text={timeLeft ? 'This community has to wait until it can be featured again' : 'Weekly Feature vote'}

View File

@ -0,0 +1,159 @@
import React from 'react'
import { useState } from 'react'
import styled from 'styled-components'
import { Colors } from '../../constants/styles'
import { addCommas } from '../../helpers/addCommas'
import { CurrentVoting } from '../../models/community'
import { Input } from '../Input'
export interface VoteProposingProps {
vote?: CurrentVoting
selectedVote?: {
noun: string
}
availableAmount: number
}
export function VotePropose({ vote, selectedVote, availableAmount }: VoteProposingProps) {
const [proposingAmount, setProposingAmount] = useState(0)
const [displayAmount, setDisplayAmount] = useState('0 SNT')
let step = 10 ** (Math.floor(Math.log10(availableAmount)) - 2)
if (availableAmount < 100) {
step = 1
}
const sliderChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (Number(e.target.value) == step * Math.floor(availableAmount / step)) {
setProposingAmount(availableAmount)
setDisplayAmount(addCommas(availableAmount) + ' SNT')
} else {
setProposingAmount(Number(e.target.value))
setDisplayAmount(addCommas(Number(e.target.value)) + ' SNT')
}
}
const progress = (proposingAmount / availableAmount) * 100 + '%'
return (
<VoteProposing>
<VoteProposingInfo>
<p>My vote</p>
<span>Available {addCommas(availableAmount)} SNT</span>
</VoteProposingInfo>
<VoteProposingAmount
value={displayAmount}
onInput={(e) => {
setProposingAmount(Number(e.currentTarget.value))
setDisplayAmount(e.currentTarget.value)
}}
onBlur={() => setDisplayAmount(addCommas(proposingAmount) + ' SNT')}
onFocus={() => setDisplayAmount(proposingAmount.toString())}
/>
<VoteProposingRangeWrap>
<VoteProposingRange
type="range"
min={0}
max={availableAmount}
step={step}
value={proposingAmount}
onChange={sliderChange}
style={{
background: `linear-gradient(90deg, ${Colors.VioletDark} 0% ${progress}, ${Colors.VioletSecondary} ${progress} 100%)`,
}}
/>
</VoteProposingRangeWrap>
{vote?.type === 'Remove' && Number(proposingAmount) > 2000000 && vote.timeLeft / 3600 > 24 && (
<VoteWarning>
<span></span>
<WarningText>{`Your vote will shorten vote duration! Votes over 2,000,000 SNT for ${selectedVote?.noun} of the community shortens the vote duration to 24 hours.`}</WarningText>
</VoteWarning>
)}
</VoteProposing>
)
}
export const VoteProposing = styled.div`
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
`
const VoteProposingInfo = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
margin-bottom: 10px;
& > span {
font-size: 12px;
line-height: 16px;
color: ${Colors.GreyText};
}
`
const VoteProposingAmount = styled(Input)`
width: 100%;
margin-bottom: 16px;
font-size: 15px;
line-height: 22px;
`
const VoteProposingRangeWrap = styled.div`
width: 294px;
margin-bottom: 32px;
`
const VoteProposingRange = styled.input`
appearance: none;
width: 100%;
height: 4px;
padding: 0;
margin: 10px 0;
border-radius: 2px;
outline: none;
&::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: ${Colors.Violet};
cursor: pointer;
}
&::-moz-range-thumb {
width: 20px;
height: 20px;
background: ${Colors.Violet};
border: 0.5px solid rgba(0, 0, 0, 0);
border-radius: 50px;
cursor: pointer;
}
`
const VoteWarning = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
padding: 16px;
background: #ffeff2;
border-radius: 6px;
margin-bottom: 32px;
& > span {
font-size: 24px;
line-height: 32px;
}
`
const WarningText = styled.div`
max-width: 353px;
font-size: 12px;
line-height: 16px;
letter-spacing: 0.1px;
`

View File

@ -1,16 +1,60 @@
import React from 'react'
import React, { useState } from 'react'
import { InfoWrap, ConnectButton, ProposeButton, PageInfo } from '../PageInfo'
import { useEthers } from '@usedapp/core'
import { Modal } from '../Modal'
import { ProposeModal } from '../card/ProposeModal'
import { VoteConfirmModal } from '../card/VoteConfirmModal'
import { getCommunityDetails } from '../../helpers/apiMock'
export function VotesInfo() {
const { account } = useEthers()
const [showProposeModal, setShowProposeModal] = useState(false)
const [showConfirmModal, setShowConfirmModal] = useState(false)
const [publicKey, setPublicKey] = useState('')
const setNext = (val: boolean) => {
setShowConfirmModal(val)
setShowProposeModal(false)
}
const clearKey = (val: boolean) => {
setShowConfirmModal(val)
setPublicKey('')
}
return (
<InfoWrap>
<PageInfo
heading="Ongoing Votes"
text="Help curate the Status Communities directory by voting which communities should be included"
/>
{account ? <ProposeButton /> : <ConnectButton />}
{showProposeModal && (
<Modal
heading="Add community to directory"
setShowModal={(val: boolean) => {
setShowProposeModal(val)
setPublicKey('')
}}
>
<ProposeModal
availableAmount={65245346}
setShowConfirmModal={setNext}
setPublicKey={setPublicKey}
publicKey={publicKey}
/>{' '}
</Modal>
)}
{showConfirmModal && (
<Modal setShowModal={clearKey}>
<VoteConfirmModal
community={getCommunityDetails(publicKey)}
selectedVote={{ verb: 'to add' }}
setShowModal={clearKey}
/>
</Modal>
)}
{account ? <ProposeButton onClick={() => setShowProposeModal(true)} /> : <ConnectButton />}
</InfoWrap>
)
}

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react'
import { Card, CardCommunity, CardVote } from '../Card'
import { Card, CardCommunity, CardCommunityWrap, CardVote } from '../Card'
import { getCommunitiesUnderVote } from '../../helpers/apiMock'
import { CommunityDetail, VotingSortingEnum } from '../../models/community'
import styled from 'styled-components'
@ -20,7 +20,11 @@ interface VotingCardProps {
function VotingCard({ community }: VotingCardProps) {
return (
<Card>
<CardCommunity community={community} />
<CardCommunityWrap>
{' '}
<CardCommunity community={community} />
</CardCommunityWrap>
<CardVote community={community} />
</Card>
)