Add empty state (#57)
This commit is contained in:
parent
024c9ac1f5
commit
06bfb01ffc
|
@ -89,3 +89,24 @@ export const FinalBtn = styled(Btn)`
|
||||||
margin-top: 32px;
|
margin-top: 32px;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const ProposingBtn = styled(Btn)`
|
||||||
|
width: 100%;
|
||||||
|
background-color: #5d7be2;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 24px;
|
||||||
|
|
||||||
|
&:not(:disabled):hover {
|
||||||
|
background: #0f3595;
|
||||||
|
}
|
||||||
|
&:not(:disabled):active {
|
||||||
|
background: #7e98f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
background: #888888;
|
||||||
|
filter: grayscale(1);
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
|
@ -4,7 +4,34 @@ export const Input = styled.input`
|
||||||
max-width: 420px;
|
max-width: 420px;
|
||||||
padding: 11px 20px;
|
padding: 11px 20px;
|
||||||
background: #f0f1f3;
|
background: #f0f1f3;
|
||||||
color: #00000;
|
color: #000;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid #eef2f5;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&:focus {
|
||||||
|
border: 1px solid #5d7be2;
|
||||||
|
caret-color: #5d7be2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
export const TextArea = styled.textarea`
|
||||||
|
width: 100%;
|
||||||
|
resize: none;
|
||||||
|
padding: 11px 20px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
margin-top: 10px;
|
||||||
|
font-family: Inter;
|
||||||
|
font-style: normal;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: left;
|
||||||
|
background: #f0f1f3;
|
||||||
|
color: #000;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid #eef2f5;
|
border: 1px solid #eef2f5;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|
|
@ -3,10 +3,12 @@ import styled from 'styled-components'
|
||||||
import { ProposalHeader } from './ProposalHeader'
|
import { ProposalHeader } from './ProposalHeader'
|
||||||
import { blueTheme } from '@status-waku-voting/react-components/dist/esm/src/style/themes'
|
import { blueTheme } from '@status-waku-voting/react-components/dist/esm/src/style/themes'
|
||||||
import { ProposalList } from './ProposalList'
|
import { ProposalList } from './ProposalList'
|
||||||
|
import { VotingEmpty } from './VotingEmpty'
|
||||||
|
|
||||||
export function Proposal() {
|
export function Proposal() {
|
||||||
return (
|
return (
|
||||||
<ProposalWrapper>
|
<ProposalWrapper>
|
||||||
|
<VotingEmpty theme={blueTheme} />
|
||||||
<ProposalHeader theme={blueTheme} />
|
<ProposalHeader theme={blueTheme} />
|
||||||
<ProposalList theme={blueTheme} />
|
<ProposalList theme={blueTheme} />
|
||||||
</ProposalWrapper>
|
</ProposalWrapper>
|
||||||
|
@ -18,7 +20,7 @@ const ProposalWrapper = styled.div`
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
max-width: 1000px;
|
max-width: 1000px;
|
||||||
position: relative;
|
// position: relative;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 150px 32px 50px;
|
padding: 150px 32px 50px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -43,7 +43,7 @@ export const Card = styled.div`
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const CardHeading = styled.div`
|
export const CardHeading = styled.div`
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 22px;
|
font-size: 22px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
|
@ -55,7 +55,7 @@ const CardHeading = styled.div`
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
const CardText = styled.div`
|
export const CardText = styled.div`
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
import React from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
import { ProposingBtn } from './Buttons'
|
||||||
|
import { TextArea } from './Input'
|
||||||
|
import { blueTheme } from '@status-waku-voting/react-components/dist/esm/src/style/themes'
|
||||||
|
|
||||||
|
interface ProposeModalProps {
|
||||||
|
availableAmount: number
|
||||||
|
title: string
|
||||||
|
text: string
|
||||||
|
setShowProposeVoteModal: (val: boolean) => void
|
||||||
|
setTitle: (val: string) => void
|
||||||
|
setText: (val: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ProposeModal({
|
||||||
|
availableAmount,
|
||||||
|
title,
|
||||||
|
text,
|
||||||
|
setShowProposeVoteModal,
|
||||||
|
setTitle,
|
||||||
|
setText,
|
||||||
|
}: ProposeModalProps) {
|
||||||
|
const insufficientFunds = availableAmount < 10000
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProposingData>
|
||||||
|
{insufficientFunds && (
|
||||||
|
<ProposingInfo>
|
||||||
|
<span>⚠️</span>
|
||||||
|
<InfoText>You need at least 10,000 ABC to create a proposal!</InfoText>
|
||||||
|
</ProposingInfo>
|
||||||
|
)}
|
||||||
|
<Label>
|
||||||
|
Title
|
||||||
|
<ProposingInput
|
||||||
|
cols={2}
|
||||||
|
maxLength={90}
|
||||||
|
placeholder="E.g. Change the rate of the token issuance"
|
||||||
|
value={title}
|
||||||
|
onInput={(e) => {
|
||||||
|
setTitle(e.currentTarget.value)
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</Label>
|
||||||
|
|
||||||
|
<Label>
|
||||||
|
Description
|
||||||
|
<ProposingTextInput
|
||||||
|
maxLength={440}
|
||||||
|
placeholder="Describe your proposal as detailed as you can in 440 characters."
|
||||||
|
value={text}
|
||||||
|
onInput={(e) => {
|
||||||
|
setText(e.currentTarget.value)
|
||||||
|
}}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</Label>
|
||||||
|
|
||||||
|
<ProposingBtn
|
||||||
|
disabled={!text || !title || insufficientFunds}
|
||||||
|
theme={blueTheme}
|
||||||
|
onClick={() => setShowProposeVoteModal(true)}
|
||||||
|
>
|
||||||
|
Continue
|
||||||
|
</ProposingBtn>
|
||||||
|
</ProposingData>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VoteProposeWrap = styled.div`
|
||||||
|
margin-top: 32px;
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const ProposingData = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 32px;
|
||||||
|
`
|
||||||
|
|
||||||
|
export const ProposingInfo = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 16px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
background: #ffeff2;
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
max-width: 525px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 32px;
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const InfoText = styled.div`
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
letter-spacing: 0.1px;
|
||||||
|
`
|
||||||
|
|
||||||
|
const ProposingInput = styled(TextArea)`
|
||||||
|
height: 68px;
|
||||||
|
`
|
||||||
|
const ProposingTextInput = styled(ProposingInput)`
|
||||||
|
height: 222px;
|
||||||
|
`
|
||||||
|
const Label = styled.label`
|
||||||
|
width: 100%;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 22px;
|
||||||
|
align-self: flex-start;
|
||||||
|
`
|
|
@ -0,0 +1,60 @@
|
||||||
|
import React, { useState } from 'react'
|
||||||
|
import styled from 'styled-components'
|
||||||
|
import { ProposingBtn } from './Buttons'
|
||||||
|
import { Card, CardHeading, CardText } from './ProposalInfo'
|
||||||
|
import { ProposingData } from './ProposeModal'
|
||||||
|
import { VotePropose } from './VotePropose'
|
||||||
|
|
||||||
|
interface ProposeVoteModalProps {
|
||||||
|
availableAmount: number
|
||||||
|
title: string
|
||||||
|
text: string
|
||||||
|
setShowModal: (val: boolean) => void
|
||||||
|
setTitle: (val: string) => void
|
||||||
|
setText: (val: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ProposeVoteModal({
|
||||||
|
availableAmount,
|
||||||
|
title,
|
||||||
|
text,
|
||||||
|
setShowModal,
|
||||||
|
setTitle,
|
||||||
|
setText,
|
||||||
|
}: ProposeVoteModalProps) {
|
||||||
|
const [proposingAmount, setProposingAmount] = useState(0)
|
||||||
|
return (
|
||||||
|
<ProposingData>
|
||||||
|
<ProposingCardHeading>{title}</ProposingCardHeading>
|
||||||
|
<ProposingCardText>{text}</ProposingCardText>
|
||||||
|
|
||||||
|
<VoteProposeWrap>
|
||||||
|
<VotePropose
|
||||||
|
availableAmount={availableAmount}
|
||||||
|
setProposingAmount={setProposingAmount}
|
||||||
|
proposingAmount={proposingAmount}
|
||||||
|
/>
|
||||||
|
</VoteProposeWrap>
|
||||||
|
|
||||||
|
<ProposingBtn
|
||||||
|
onClick={() => {
|
||||||
|
setShowModal(false), setTitle(''), setText('')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Create proposal
|
||||||
|
</ProposingBtn>
|
||||||
|
</ProposingData>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VoteProposeWrap = styled.div`
|
||||||
|
margin-bottom: 32px;
|
||||||
|
width: 100%;
|
||||||
|
`
|
||||||
|
|
||||||
|
const ProposingCardHeading = styled(CardHeading)`
|
||||||
|
margin-bottom: 16px;
|
||||||
|
`
|
||||||
|
const ProposingCardText = styled(CardText)`
|
||||||
|
margin-bottom: 0;
|
||||||
|
`
|
|
@ -0,0 +1,163 @@
|
||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { useEthers } from '@usedapp/core'
|
||||||
|
|
||||||
|
import styled from 'styled-components'
|
||||||
|
import { CreateButton, Modal, Theme } from '@status-waku-voting/react-components'
|
||||||
|
import { ProposeModal } from './ProposeModal'
|
||||||
|
import { ProposeVoteModal } from './ProposeVoteModal'
|
||||||
|
|
||||||
|
type VotingEmptyProps = {
|
||||||
|
theme: Theme
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VotingEmpty({ theme }: VotingEmptyProps) {
|
||||||
|
const { account, activateBrowserWallet } = useEthers()
|
||||||
|
const [selectConnect, setSelectConnect] = useState(false)
|
||||||
|
const [showProposeModal, setShowProposeModal] = useState(false)
|
||||||
|
const [showProposeVoteModal, setShowProposeVoteModal] = useState(false)
|
||||||
|
const [mobileVersion, setMobileVersion] = useState(false)
|
||||||
|
const [title, setTitle] = useState('')
|
||||||
|
const [text, setText] = useState('')
|
||||||
|
|
||||||
|
const setNext = (val: boolean) => {
|
||||||
|
setShowProposeVoteModal(val)
|
||||||
|
setShowProposeModal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleResize = () => {
|
||||||
|
if (window.innerWidth < 600) {
|
||||||
|
setMobileVersion(true)
|
||||||
|
} else {
|
||||||
|
setMobileVersion(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handleResize()
|
||||||
|
window.addEventListener('resize', handleResize)
|
||||||
|
return () => window.removeEventListener('resize', handleResize)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<VotingEmptyWrap>
|
||||||
|
<EmptyWrap>
|
||||||
|
<EmptyHeading>There are no proposals at the moment!</EmptyHeading>
|
||||||
|
<EmptyText>
|
||||||
|
Any worthwhile idea going on on your mind? Feel free to smash that button and see find out if the community
|
||||||
|
likes it!
|
||||||
|
</EmptyText>
|
||||||
|
</EmptyWrap>
|
||||||
|
{showProposeModal && (
|
||||||
|
<Modal heading="Create proposal" theme={theme} setShowModal={setShowProposeModal}>
|
||||||
|
<ProposeModal
|
||||||
|
title={title}
|
||||||
|
text={text}
|
||||||
|
setText={setText}
|
||||||
|
setTitle={setTitle}
|
||||||
|
availableAmount={6524}
|
||||||
|
setShowProposeVoteModal={setNext}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
{showProposeVoteModal && (
|
||||||
|
<Modal heading="Create proposal" theme={theme} setShowModal={setShowProposeVoteModal}>
|
||||||
|
<ProposeVoteModal
|
||||||
|
title={title}
|
||||||
|
text={text}
|
||||||
|
availableAmount={6524}
|
||||||
|
setShowModal={setShowProposeVoteModal}
|
||||||
|
setText={setText}
|
||||||
|
setTitle={setTitle}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!mobileVersion && (
|
||||||
|
<div>
|
||||||
|
{account ? (
|
||||||
|
<CreateButton theme={theme} onClick={() => setShowProposeModal(true)}>
|
||||||
|
Create proposal
|
||||||
|
</CreateButton>
|
||||||
|
) : (
|
||||||
|
<CreateButton
|
||||||
|
theme={theme}
|
||||||
|
onClick={() => {
|
||||||
|
if ((window as any).ethereum) {
|
||||||
|
activateBrowserWallet()
|
||||||
|
} else setSelectConnect(true)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Connect to vote
|
||||||
|
</CreateButton>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</VotingEmptyWrap>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const VotingEmptyWrap = styled.div`
|
||||||
|
position: absolute;
|
||||||
|
top: 96px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
padding: 0 32px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100vh - 96px);
|
||||||
|
background: #fffff;
|
||||||
|
z-index: 99;
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
height: 250px;
|
||||||
|
top: 50vh;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const EmptyWrap = styled.div`
|
||||||
|
width: 100%;
|
||||||
|
max-width: 800px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
`
|
||||||
|
|
||||||
|
const EmptyHeading = styled.h1`
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 28px;
|
||||||
|
line-height: 38px;
|
||||||
|
letter-spacing: -0.4px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
font-size: 22px;
|
||||||
|
line-height: 22px;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
@media (max-width: 375px) {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const EmptyText = styled.p`
|
||||||
|
font-size: 22px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 32px;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 18px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 340px) {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
`
|
Loading…
Reference in New Issue