Merge branch 'master' into review
This commit is contained in:
commit
546992c612
|
@ -1,14 +1,10 @@
|
|||
{
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true,
|
||||
"mocha": true,
|
||||
"browser": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"eslint:recommended"
|
||||
],
|
||||
"extends": ["plugin:@typescript-eslint/recommended", "eslint:recommended"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json",
|
||||
|
@ -19,7 +15,7 @@
|
|||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"no-redeclare": "off",
|
||||
"no-unused-vars": "off",
|
||||
"prefer-const": ["error", {"destructuring": "all"}],
|
||||
"prefer-const": ["error", { "destructuring": "all" }],
|
||||
"semi": ["error", "never"],
|
||||
"no-extra-semi": "off",
|
||||
"@typescript-eslint/no-extra-semi": "off"
|
||||
|
|
|
@ -15,10 +15,6 @@
|
|||
"test": "wsrun -e -c -s --exclude-missing test",
|
||||
"clean": "wsrun -e -c -s clean && rimraf node_modules"
|
||||
},
|
||||
"resolutions": {
|
||||
"js-waku": "0.30.0",
|
||||
"protons-runtime": "3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"prettier": "^2.3.1",
|
||||
"wsrun": "^5.2.4"
|
||||
|
|
|
@ -21,15 +21,18 @@
|
|||
"clean": "rimraf dist node_modules"
|
||||
},
|
||||
"dependencies": {
|
||||
"@status-im/js": "0.2.0",
|
||||
"@libp2p/bootstrap": "^9.0.10",
|
||||
"@status-im/js": "0.4.3",
|
||||
"@usedapp/core": "^1.2.8",
|
||||
"@waku/core": "^0.0.25",
|
||||
"@waku/message-encryption": "^0.0.23",
|
||||
"@waku/sdk": "^0.0.21",
|
||||
"assert": "^2.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"eth-sig-util": "^3.0.1",
|
||||
"ethers": "5.4.1",
|
||||
"humanize-duration": "^3.27.0",
|
||||
"js-waku": "0.30.0",
|
||||
"protons": "^2.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
@ -58,6 +61,7 @@
|
|||
"@types/uuid": "^8.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.26.0",
|
||||
"@typescript-eslint/parser": "^4.26.0",
|
||||
"@waku/interfaces": "^0.0.20",
|
||||
"babel-loader": "^8.2.2",
|
||||
"babel-preset-minify": "^0.5.1",
|
||||
"chai": "^4.3.4",
|
||||
|
@ -65,6 +69,8 @@
|
|||
"eslint": "^7.27.0",
|
||||
"eslint-plugin-hooks": "^0.2.0",
|
||||
"eslint-plugin-react": "^7.24.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.3.4",
|
||||
"ethereum-waffle": "^3.4.0",
|
||||
"file-loader": "^6.2.0",
|
||||
"fork-ts-checker-webpack-plugin": "^6.2.10",
|
||||
|
@ -79,11 +85,6 @@
|
|||
"typescript": "^4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^4.7.0",
|
||||
"webpack-dev-server": "^3.11.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"eslint-plugin-react-refresh": "^0.3.4"
|
||||
},
|
||||
"resolutions": {
|
||||
"ethers": "5.4.1"
|
||||
"webpack-dev-server": "^3.11.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import styled from 'styled-components'
|
|||
import { GlobalStyle } from './providers/GlobalStyle'
|
||||
import { MobileRouter } from './pagesMobile/MobileRouter'
|
||||
import { DesktopRouter } from './pages/DesktopRouter'
|
||||
import { NotificationsList } from './components/NotificationsList'
|
||||
|
||||
export function App() {
|
||||
const [mobileVersion, setMobileVersion] = useState(false)
|
||||
|
@ -24,6 +25,7 @@ export function App() {
|
|||
<Page>
|
||||
<GlobalStyle />
|
||||
{mobileVersion ? <MobileRouter /> : <DesktopRouter />}
|
||||
<NotificationsList />
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M12 6.25C16.2802 6.25 19.75 9.71979 19.75 14C19.75 18.2802 16.2802 21.75 12 21.75C7.71979 21.75 4.25 18.2802 4.25 14C4.25 13.5858 4.58579 13.25 5 13.25C5.41421 13.25 5.75 13.5858 5.75 14C5.75 17.4518 8.54822 20.25 12 20.25C15.4518 20.25 18.25 17.4518 18.25 14C18.25 10.5482 15.4518 7.75 12 7.75H11.0178C10.5723 7.75 10.3492 8.28857 10.6642 8.60355L12.5303 10.4697C12.8232 10.7626 12.8232 11.2374 12.5303 11.5303C12.2374 11.8232 11.7626 11.8232 11.4697 11.5303L7.46967 7.53033C7.17678 7.23744 7.17678 6.76256 7.46967 6.46967L11.4697 2.46967C11.7626 2.17678 12.2374 2.17678 12.5303 2.46967C12.8232 2.76256 12.8232 3.23744 12.5303 3.53033L10.6642 5.39645C10.3492 5.71143 10.5723 6.25 11.0178 6.25H12Z"
|
||||
fill="#8C21BA"
|
||||
/>
|
||||
</svg>
|
After Width: | Height: | Size: 841 B |
|
@ -2,6 +2,7 @@ import React, { ReactNode, useEffect } from 'react'
|
|||
import styled from 'styled-components'
|
||||
import { Colors } from '../constants/styles'
|
||||
import closeIcon from '../assets/images/close.svg'
|
||||
import refreshIcon from '../assets/images/refresh.svg'
|
||||
|
||||
type ModalProps = {
|
||||
heading?: string
|
||||
|
@ -92,3 +93,13 @@ export const CloseButton = styled.button`
|
|||
height: 24px;
|
||||
background-image: url(${closeIcon});
|
||||
`
|
||||
|
||||
export const RetryButton = styled.button`
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
background-image: url(${refreshIcon});
|
||||
`
|
||||
|
|
|
@ -5,7 +5,7 @@ import styled from 'styled-components'
|
|||
import { Colors } from '../constants/styles'
|
||||
import { useCommunities } from '../hooks/useCommunities'
|
||||
import { LinkExternal } from './Link'
|
||||
import { CloseButton } from './Modal'
|
||||
import { CloseButton, RetryButton } from './Modal'
|
||||
import { getExplorerTransactionLink } from '@usedapp/core'
|
||||
|
||||
interface NotificationItemProps {
|
||||
|
@ -37,33 +37,34 @@ export function NotificationItem({ publicKey, text, transaction }: NotificationI
|
|||
View on Etherscan
|
||||
</NotificationLink>
|
||||
</NotificationContent>
|
||||
|
||||
<NotificationCloseButton onClick={() => setShow(false)} />
|
||||
</NotificationBlock>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
interface NotificationItemPlainProps {
|
||||
text: string
|
||||
export function NotificationInfoItem({ text }: { text: string }) {
|
||||
return (
|
||||
<NotificationBlock>
|
||||
<NotificationContent>
|
||||
<NotificationText>{text}</NotificationText>
|
||||
</NotificationContent>
|
||||
</NotificationBlock>
|
||||
)
|
||||
}
|
||||
|
||||
export function NotificationItemPlain({ text }: NotificationItemPlainProps) {
|
||||
const [show, setShow] = useState(true)
|
||||
export function NotificationErrorItem({ text, action }: { text: string; action: () => void }) {
|
||||
return (
|
||||
<NotificationBlock>
|
||||
<NotificationContent>
|
||||
<NotificationText>{text}</NotificationText>
|
||||
</NotificationContent>
|
||||
|
||||
if (show) {
|
||||
return (
|
||||
<NotificationBlock>
|
||||
<NotificationContent>
|
||||
<NotificationText>{text}</NotificationText>
|
||||
</NotificationContent>
|
||||
<NotificationCloseButton onClick={() => setShow(false)} />
|
||||
</NotificationBlock>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
<NotificationRetryButton onClick={() => action()} />
|
||||
</NotificationBlock>
|
||||
)
|
||||
}
|
||||
|
||||
const NotificationBlock = styled.div`
|
||||
|
@ -73,7 +74,6 @@ const NotificationBlock = styled.div`
|
|||
width: 345px;
|
||||
border-radius: 16px;
|
||||
filter: drop-shadow(0px 4px 6px rgba(0, 0, 0, 0.15));
|
||||
z-index: 9999;
|
||||
`
|
||||
|
||||
const NotificationLogoWrap = styled.div`
|
||||
|
@ -116,3 +116,10 @@ const NotificationCloseButton = styled(CloseButton)`
|
|||
bottom: 50%;
|
||||
transform: translateY(50%);
|
||||
`
|
||||
|
||||
const NotificationRetryButton = styled(RetryButton)`
|
||||
top: unset;
|
||||
right: 13px;
|
||||
bottom: 50%;
|
||||
transform: translateY(50%);
|
||||
`
|
||||
|
|
|
@ -3,83 +3,54 @@ import React from 'react'
|
|||
import styled from 'styled-components'
|
||||
import { AnimationNotification, AnimationNotificationMobile } from '../constants/animation'
|
||||
import { useContracts } from '../hooks/useContracts'
|
||||
import { NotificationItem, NotificationItemPlain } from './NotificationItem'
|
||||
import { NotificationItem, NotificationInfoItem, NotificationErrorItem } from './NotificationItem'
|
||||
import { useWaku } from '../providers/waku/provider'
|
||||
|
||||
interface Props {
|
||||
type: 'votes' | 'featured'
|
||||
}
|
||||
|
||||
export function NotificationsList({ type }: Props) {
|
||||
export function NotificationsList() {
|
||||
const { notifications } = useNotifications()
|
||||
const { votingContract, featuredVotingContract } = useContracts()
|
||||
|
||||
const getParsedLog = (log: any, type: 'votes' | 'featured') => {
|
||||
switch (type) {
|
||||
case 'votes': {
|
||||
return votingContract.interface.parseLog(log)
|
||||
}
|
||||
case 'featured': {
|
||||
return featuredVotingContract.interface.parseLog(log)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const parseVoting = (parsedLog: any) => {
|
||||
let text = ''
|
||||
if (parsedLog.name === 'VotingRoomStarted') {
|
||||
text = ' voting room started.'
|
||||
}
|
||||
if (parsedLog.name === 'VotingRoomFinalized') {
|
||||
if (parsedLog.args.passed == true) {
|
||||
if (parsedLog.args.voteType === 1) {
|
||||
text = ' is now in the communities directory!'
|
||||
}
|
||||
|
||||
if (parsedLog.args.voteType === 0) {
|
||||
text = ' is now removed from communities directory!'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
const parseFeatured = (parsedLog: any) => {
|
||||
let text = ''
|
||||
if (parsedLog.name === 'VotingStarted') {
|
||||
text = 'Featured voting started.'
|
||||
}
|
||||
if (parsedLog.name === 'VotingFinalized') {
|
||||
text = 'Featured voting was finalized.'
|
||||
}
|
||||
|
||||
return text
|
||||
}
|
||||
const { votingContract } = useContracts()
|
||||
const { isLoading, isError, restart } = useWaku()
|
||||
|
||||
return (
|
||||
<NotificationsWrapper>
|
||||
{isLoading && <NotificationInfoItem text="Connecting to a Waku node." />}
|
||||
|
||||
{!isLoading && isError && <NotificationErrorItem text="Failed connect to a Waku node." action={restart} />}
|
||||
|
||||
{notifications.map((notification) => {
|
||||
if ('receipt' in notification) {
|
||||
return notification.receipt.logs.map((log) => {
|
||||
const parsedLog = getParsedLog(log, type)
|
||||
|
||||
let res = ''
|
||||
if (type === 'votes') {
|
||||
res = parseVoting(parsedLog)
|
||||
} else if (type === 'featured') {
|
||||
res = parseFeatured(parsedLog)
|
||||
if (log.address !== votingContract.address) {
|
||||
return
|
||||
}
|
||||
if (res && type === 'votes') {
|
||||
|
||||
// this needs to be updated so it takes into account also interface of featuredVotingContract
|
||||
const parsedLog = votingContract.interface.parseLog(log)
|
||||
|
||||
let text
|
||||
if (parsedLog.name === 'VotingRoomStarted') {
|
||||
text = ' voting room started.'
|
||||
}
|
||||
if (parsedLog.name === 'VotingRoomFinalized') {
|
||||
if (parsedLog.args.passed == true) {
|
||||
if (parsedLog.args.voteType === 1) {
|
||||
text = ' is now in the communities directory!'
|
||||
}
|
||||
|
||||
if (parsedLog.args.voteType === 0) {
|
||||
text = ' is now removed from communities directory!'
|
||||
}
|
||||
}
|
||||
}
|
||||
if (text) {
|
||||
return (
|
||||
<NotificationItem
|
||||
key={log.transactionHash}
|
||||
publicKey={parsedLog.args.publicKey}
|
||||
text={res}
|
||||
text={text}
|
||||
transaction={notification.transaction}
|
||||
/>
|
||||
)
|
||||
} else if (res && type === 'featured') {
|
||||
return <NotificationItemPlain key={log.transactionHash} text={res} />
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -97,6 +68,7 @@ const NotificationsWrapper = styled.div`
|
|||
flex-direction: column;
|
||||
transition: all 0.3s;
|
||||
animation: ${AnimationNotification} 2s ease;
|
||||
z-index: 100;
|
||||
|
||||
@media (max-width: 600px) {
|
||||
top: unset;
|
||||
|
|
|
@ -9,6 +9,7 @@ import { useSendWakuFeature } from '../../hooks/useSendWakuFeature'
|
|||
import { useContractFunction } from '@usedapp/core'
|
||||
import { useContracts } from '../../hooks/useContracts'
|
||||
import { useFeaturedVotes } from '../../hooks/useFeaturedVotes'
|
||||
import { useWaku } from '../../providers/waku/provider'
|
||||
|
||||
interface FeatureModalProps {
|
||||
community: CommunityDetail
|
||||
|
@ -17,11 +18,12 @@ interface FeatureModalProps {
|
|||
|
||||
export function FeatureModal({ community, setShowConfirmModal }: FeatureModalProps) {
|
||||
const [proposingAmount, setProposingAmount] = useState(0)
|
||||
const { isConnected } = useWaku()
|
||||
const sendWaku = useSendWakuFeature()
|
||||
const { featuredVotingContract } = useContracts()
|
||||
const { send } = useContractFunction(featuredVotingContract, 'initializeVoting')
|
||||
const { activeVoting } = useFeaturedVotes()
|
||||
const disabled = proposingAmount === 0
|
||||
const disabled = !isConnected || proposingAmount === 0
|
||||
|
||||
return (
|
||||
<ColumnFlexDiv>
|
||||
|
|
|
@ -8,6 +8,7 @@ import { VoteType } from '../../constants/voteTypes'
|
|||
import { useSendWakuVote } from '../../hooks/useSendWakuVote'
|
||||
import { ColumnFlexDiv } from '../../constants/styles'
|
||||
import { DetailedVotingRoom } from '../../models/smartContract'
|
||||
import { useWaku } from '../../providers/waku/provider'
|
||||
|
||||
export interface VoteModalProps {
|
||||
vote: CurrentVoting
|
||||
|
@ -33,7 +34,7 @@ export function VoteModal({
|
|||
votesFor,
|
||||
votesAgainst,
|
||||
}: VoteModalProps) {
|
||||
const disabled = proposingAmount === 0
|
||||
const { isConnected } = useWaku()
|
||||
const sendWakuVote = useSendWakuVote()
|
||||
|
||||
return (
|
||||
|
@ -61,7 +62,7 @@ export function VoteModal({
|
|||
|
||||
setShowConfirmModal(true)
|
||||
}}
|
||||
disabled={disabled}
|
||||
disabled={!isConnected || proposingAmount === 0}
|
||||
>{`Vote ${selectedVote.verb} community ${selectedVote.icon}`}</VoteConfirmBtn>
|
||||
</ColumnFlexDiv>
|
||||
)
|
||||
|
|
|
@ -7,9 +7,12 @@ import { CommunityDetail } from '../../models/community'
|
|||
import { ProposeButton } from '../Button'
|
||||
import { ConnectionNetwork } from '../ConnectionNetwork'
|
||||
import { useAccount } from '../../hooks/useAccount'
|
||||
import { useWaku } from '../../providers/waku/provider'
|
||||
|
||||
export function VotesInfo() {
|
||||
const { isActive } = useAccount()
|
||||
const { isConnected } = useWaku()
|
||||
|
||||
const [showProposeModal, setShowProposeModal] = useState(false)
|
||||
const [showConfirmModal, setShowConfirmModal] = useState(false)
|
||||
const [communityFound, setCommunityFound] = useState<undefined | CommunityDetail>(undefined)
|
||||
|
@ -44,7 +47,11 @@ export function VotesInfo() {
|
|||
</Modal>
|
||||
)}
|
||||
|
||||
{isActive && <ProposeButton onClick={() => setShowProposeModal(true)}>Propose community</ProposeButton>}
|
||||
{isActive && (
|
||||
<ProposeButton onClick={() => setShowProposeModal(true)} disabled={!isConnected}>
|
||||
Propose community
|
||||
</ProposeButton>
|
||||
)}
|
||||
<ConnectionNetwork />
|
||||
</InfoWrap>
|
||||
)
|
||||
|
|
|
@ -9,9 +9,11 @@ import { ConnectionNetwork } from '../ConnectionNetwork'
|
|||
import styled from 'styled-components'
|
||||
import { Colors, ColumnFlexDiv } from '../../constants/styles'
|
||||
import { useAccount } from '../../hooks/useAccount'
|
||||
import { useWaku } from '../../providers/waku/provider'
|
||||
|
||||
export function VotingEmpty() {
|
||||
const { isActive } = useAccount()
|
||||
const { isConnected } = useWaku()
|
||||
const [showProposeModal, setShowProposeModal] = useState(false)
|
||||
const [showConfirmModal, setShowConfirmModal] = useState(false)
|
||||
const [communityFound, setCommunityFound] = useState<undefined | CommunityDetail>(undefined)
|
||||
|
@ -68,7 +70,11 @@ export function VotingEmpty() {
|
|||
|
||||
{!mobileVersion && (
|
||||
<>
|
||||
{isActive && <ProposeButton onClick={() => setShowProposeModal(true)}>Propose community</ProposeButton>}
|
||||
{isActive && (
|
||||
<ProposeButton onClick={() => setShowProposeModal(true)} disabled={!isConnected}>
|
||||
Propose community
|
||||
</ProposeButton>
|
||||
)}
|
||||
<ConnectionNetwork />
|
||||
</>
|
||||
)}
|
||||
|
|
|
@ -23,6 +23,7 @@ import { WrapperBottom, WrapperTop } from '../constants/styles'
|
|||
import { useUnverifiedVotes } from '../hooks/useUnverifiedVotes'
|
||||
import { useVotingBatches } from '../hooks/useVotingBatches'
|
||||
import { useAccount } from '../hooks/useAccount'
|
||||
import { useWaku } from '../providers/waku/provider'
|
||||
|
||||
interface CardVoteMobileProps {
|
||||
room: DetailedVotingRoom
|
||||
|
@ -84,6 +85,7 @@ export const CardVoteMobile = ({ room }: CardVoteMobileProps) => {
|
|||
|
||||
const [showHistory, setShowHistory] = useState(false)
|
||||
const isDisabled = room.details.votingHistory.length === 0
|
||||
const { isConnected } = useWaku()
|
||||
const sendWakuVote = useSendWakuVote()
|
||||
|
||||
const includeUnverifiedVotes = !winner || verificationPeriod
|
||||
|
@ -158,7 +160,7 @@ export const CardVoteMobile = ({ room }: CardVoteMobileProps) => {
|
|||
{!verificationPeriod && !finalizationPeriod && (
|
||||
<VotesBtns>
|
||||
<VoteBtn
|
||||
disabled={!canVote}
|
||||
disabled={!isConnected || !canVote}
|
||||
onClick={async () => {
|
||||
await sendWakuVote(proposingAmount, room.roomNumber, 0)
|
||||
setVoted(true)
|
||||
|
@ -168,7 +170,7 @@ export const CardVoteMobile = ({ room }: CardVoteMobileProps) => {
|
|||
{voteConstants.against.text} <span>{voteConstants.against.icon}</span>
|
||||
</VoteBtn>
|
||||
<VoteBtn
|
||||
disabled={!canVote}
|
||||
disabled={!isConnected || !canVote}
|
||||
onClick={async () => {
|
||||
await sendWakuVote(proposingAmount, room.roomNumber, 1)
|
||||
setVoted(true)
|
||||
|
|
|
@ -23,12 +23,14 @@ import { useContracts } from '../hooks/useContracts'
|
|||
import { useSendWakuFeature } from '../hooks/useSendWakuFeature'
|
||||
import { useFeaturedVotingState } from '../hooks/useFeaturedVotingState'
|
||||
import { useAccount } from '../hooks/useAccount'
|
||||
import { useWaku } from '../providers/waku/provider'
|
||||
|
||||
export function FeatureMobile() {
|
||||
const { publicKey } = useParams<{ publicKey: string }>()
|
||||
const [community] = useCommunities([publicKey])
|
||||
const [proposingAmount, setProposingAmount] = useState(0)
|
||||
const { account, isActive } = useAccount()
|
||||
const { isConnected } = useWaku()
|
||||
const sendWaku = useSendWakuFeature()
|
||||
const { activeVoting } = useFeaturedVotes()
|
||||
const { featuredVotingContract } = useContracts()
|
||||
|
@ -66,6 +68,7 @@ export function FeatureMobile() {
|
|||
<VotePropose setProposingAmount={setProposingAmount} proposingAmount={proposingAmount} />
|
||||
<FeatureBtn
|
||||
disabled={
|
||||
!isConnected ||
|
||||
!account ||
|
||||
!isActive ||
|
||||
inFeatured ||
|
||||
|
|
|
@ -3,7 +3,7 @@ import lodash from 'lodash'
|
|||
import { BigNumber, utils } from 'ethers'
|
||||
import { recoverAddress } from './ethMessage'
|
||||
|
||||
import type { WakuLight } from 'js-waku/lib/interfaces'
|
||||
import type { LightNode } from '@waku/interfaces'
|
||||
import { FeaturedVoting } from '../models/smartContract'
|
||||
import { TypedFeature } from '../models/TypedData'
|
||||
import { WakuFeatureData } from '../models/waku'
|
||||
|
@ -43,7 +43,7 @@ function sumVotes(map: CommunitiesFeatureVotes) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function receiveWakuFeature(waku: WakuLight | undefined, topic: string, activeVoting: FeaturedVoting) {
|
||||
export async function receiveWakuFeature(waku: LightNode | undefined, topic: string, activeVoting: FeaturedVoting) {
|
||||
const messages = await receiveWakuFeatureMsg(waku, topic)
|
||||
const featureVotes: CommunitiesFeatureVotes = {}
|
||||
const validatedMessages = []
|
||||
|
|
|
@ -2,13 +2,13 @@ import { WakuFeatureData } from '../models/waku'
|
|||
import { utils, BigNumber } from 'ethers'
|
||||
import { JsonRpcSigner } from '@ethersproject/providers'
|
||||
import proto from './loadProtons'
|
||||
import { DecoderV0 } from 'js-waku/lib/waku_message/version_0'
|
||||
import { createDecoder } from '@waku/core'
|
||||
|
||||
import type { WakuLight } from 'js-waku/lib/interfaces'
|
||||
import type { MessageV0 as WakuMessage } from 'js-waku/lib/waku_message/version_0'
|
||||
import type { LightNode } from '@waku/interfaces'
|
||||
import type { DecodedMessage } from '@waku/core'
|
||||
import { getContractParameters } from './receiveWakuFeature'
|
||||
|
||||
function decodeWakuFeature(msg: WakuMessage): WakuFeatureData | undefined {
|
||||
function decodeWakuFeature(msg: DecodedMessage): WakuFeatureData | undefined {
|
||||
try {
|
||||
if (!msg.payload) {
|
||||
return undefined
|
||||
|
@ -29,11 +29,11 @@ export function decodeWakuFeatures(messages: any[] | null) {
|
|||
return messages?.map(decodeWakuFeature).filter((e): e is WakuFeatureData => !!e)
|
||||
}
|
||||
|
||||
export async function receiveWakuFeatureMsg(waku: WakuLight | undefined, topic: string) {
|
||||
export async function receiveWakuFeatureMsg(waku: LightNode | undefined, topic: string) {
|
||||
if (waku) {
|
||||
const messages: WakuMessage[] = []
|
||||
const messages: DecodedMessage[] = []
|
||||
// todo: init decoder once
|
||||
await waku.store.queryOrderedCallback([new DecoderV0(topic)], (wakuMessage: WakuMessage) => {
|
||||
await waku.store.queryWithOrderedCallback([createDecoder(topic)], (wakuMessage: DecodedMessage) => {
|
||||
messages.push(wakuMessage)
|
||||
})
|
||||
|
||||
|
|
|
@ -5,10 +5,10 @@ import { utils } from 'ethers'
|
|||
import proto from './loadProtons'
|
||||
import { WakuVoteData } from '../models/waku'
|
||||
import { TypedVote } from '../models/TypedData'
|
||||
import { DecoderV0 } from 'js-waku/lib/waku_message/version_0'
|
||||
import { createDecoder } from '@waku/core'
|
||||
|
||||
import type { WakuLight } from 'js-waku/lib/interfaces'
|
||||
import type { MessageV0 as WakuMessage } from 'js-waku/lib/waku_message/version_0'
|
||||
import type { DecodedMessage } from '@waku/core'
|
||||
import type { LightNode } from '@waku/interfaces'
|
||||
|
||||
function getContractParameters(
|
||||
address: string,
|
||||
|
@ -51,7 +51,7 @@ export function filterVerifiedVotes(
|
|||
return verified
|
||||
}
|
||||
|
||||
function decodeWakuVote(msg: WakuMessage): WakuVoteData | undefined {
|
||||
function decodeWakuVote(msg: DecodedMessage): WakuVoteData | undefined {
|
||||
try {
|
||||
if (!msg.payload) {
|
||||
return undefined
|
||||
|
@ -72,10 +72,10 @@ export function decodeWakuVotes(messages: any[] | null) {
|
|||
}
|
||||
|
||||
// todo?: pass complete topic
|
||||
export async function receiveWakuVotes(waku: WakuLight, topic: string, room: number) {
|
||||
const messages: WakuMessage[] = []
|
||||
export async function receiveWakuVotes(waku: LightNode, topic: string, room: number) {
|
||||
const messages: DecodedMessage[] = []
|
||||
// todo: init decoder once
|
||||
await waku.store.queryOrderedCallback([new DecoderV0(topic + room.toString())], (wakuMessage: WakuMessage) => {
|
||||
await waku.store.queryWithOrderedCallback([createDecoder(topic + room.toString())], (wakuMessage: DecodedMessage) => {
|
||||
messages.push(wakuMessage)
|
||||
})
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import { useWaku } from '../providers/waku/provider'
|
|||
import { useEthers, useSigner } from '@usedapp/core'
|
||||
import { config } from '../config'
|
||||
import { createWakuFeatureMsg } from '../helpers/wakuFeature'
|
||||
import { EncoderV0 } from 'js-waku/lib/waku_message/version_0'
|
||||
import { createEncoder } from '@waku/core'
|
||||
import { useTypedFeatureVote } from './useTypedFeatureVote'
|
||||
|
||||
export function useSendWakuFeature() {
|
||||
|
@ -18,7 +18,9 @@ export function useSendWakuFeature() {
|
|||
const msg = await createWakuFeatureMsg(account, signer, voteAmount, publicKey, timestamp, getTypedFeatureVote)
|
||||
if (msg) {
|
||||
if (waku) {
|
||||
await waku.lightPush.push(new EncoderV0(config.wakuConfig.wakuFeatureTopic), { payload: msg })
|
||||
await waku.lightPush.send(createEncoder({ contentTopic: config.wakuConfig.wakuFeatureTopic }), {
|
||||
payload: msg,
|
||||
})
|
||||
} else {
|
||||
alert('error sending feature vote please try again')
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { useEthers, useSigner } from '@usedapp/core'
|
|||
import { config } from '../config'
|
||||
import { createWakuVote } from '../helpers/wakuVote'
|
||||
import { useTypedVote } from './useTypedVote'
|
||||
import { EncoderV0 } from 'js-waku/lib/waku_message/version_0'
|
||||
import { createEncoder } from '@waku/core'
|
||||
|
||||
export function useSendWakuVote() {
|
||||
const { waku } = useWaku()
|
||||
|
@ -18,7 +18,9 @@ export function useSendWakuVote() {
|
|||
const msg = await createWakuVote(account, signer, room, voteAmount, type, timestamp, getTypedVote)
|
||||
if (msg) {
|
||||
if (waku) {
|
||||
await waku.lightPush.push(new EncoderV0(config.wakuConfig.wakuTopic + room.toString()), { payload: msg })
|
||||
await waku.lightPush.send(createEncoder({ contentTopic: config.wakuConfig.wakuTopic + room.toString() }), {
|
||||
payload: msg,
|
||||
})
|
||||
} else {
|
||||
alert('error sending vote please try again')
|
||||
}
|
||||
|
|
|
@ -8,10 +8,11 @@ import { DAppProvider } from '@usedapp/core'
|
|||
import { WakuProvider } from './providers/waku/provider'
|
||||
import { CommunitiesProvider } from './providers/communities/provider'
|
||||
import { config } from './config'
|
||||
import { peers } from './constants/peers'
|
||||
|
||||
render(
|
||||
<React.StrictMode>
|
||||
<WakuProvider>
|
||||
<WakuProvider peers={peers[config.wakuConfig.environment]}>
|
||||
<DAppProvider config={config.daapConfig}>
|
||||
<CommunitiesProvider>
|
||||
<App />
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
import React from 'react'
|
||||
import { VotingCards } from '../components/votes/VotingCards'
|
||||
import { VotesInfo } from '../components/votes/VotesInfo'
|
||||
import { NotificationsList } from '../components/NotificationsList'
|
||||
|
||||
export function Votes() {
|
||||
return (
|
||||
<div>
|
||||
<VotesInfo />
|
||||
<VotingCards />
|
||||
<NotificationsList type="votes" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -16,9 +16,11 @@ import { ConnectionNetwork } from '../components/ConnectionNetwork'
|
|||
import { VotingSkeletonMobile } from '../componentsMobile/VotingSkeletonMobile'
|
||||
import { DetailedVotingRoom } from '../models/smartContract'
|
||||
import { useAccount } from '../hooks/useAccount'
|
||||
import { useWaku } from '../providers/waku/provider'
|
||||
|
||||
export function VotesMobile() {
|
||||
const { isActive } = useAccount()
|
||||
const { isConnected } = useWaku()
|
||||
const [sortedBy, setSortedBy] = useState(VotingSortingEnum.EndingSoonest)
|
||||
const [voteType, setVoteType] = useState('')
|
||||
const [filterKeyword, setFilterKeyword] = useState('')
|
||||
|
@ -62,7 +64,11 @@ export function VotesMobile() {
|
|||
<VotingCardsWrapper>{renderCommunities()}</VotingCardsWrapper>
|
||||
|
||||
<ProposeButtonWrapper>
|
||||
{isActive && <ProposeButton onClick={() => history.push('/propose')}>Propose community</ProposeButton>}
|
||||
{isActive && (
|
||||
<ProposeButton onClick={() => history.push('/propose')} disabled={!isConnected}>
|
||||
Propose community
|
||||
</ProposeButton>
|
||||
)}
|
||||
<ConnectionNetwork />
|
||||
</ProposeButtonWrapper>
|
||||
</div>
|
||||
|
|
|
@ -1,30 +1,53 @@
|
|||
// note: pull on restart/reconnect
|
||||
// note: !waku and waku && conditions to use isConnected when implementing detection of dicsonnections
|
||||
|
||||
import React, { ReactNode, createContext, useContext, useEffect, useState } from 'react'
|
||||
import { Protocols } from 'js-waku'
|
||||
import { createLightNode } from 'js-waku/lib/create_waku'
|
||||
import { PeerDiscoveryStaticPeers } from 'js-waku/lib/peer_discovery_static_list'
|
||||
import { waitForRemotePeer } from 'js-waku/lib/wait_for_remote_peer'
|
||||
import type { WakuLight } from 'js-waku/lib/interfaces'
|
||||
import { peers } from '../../constants/peers'
|
||||
import { config } from '../../config'
|
||||
import { bootstrap } from '@libp2p/bootstrap'
|
||||
import { Protocols } from '@waku/interfaces'
|
||||
import { createLightNode, waitForRemotePeer } from '@waku/sdk'
|
||||
import type { LightNode } from '@waku/interfaces'
|
||||
|
||||
const WakuContext = createContext<WakuLight | undefined>(undefined)
|
||||
type Context = {
|
||||
waku: LightNode | undefined
|
||||
isLoading: boolean
|
||||
isConnected: boolean
|
||||
isError: boolean
|
||||
restart: () => Promise<void>
|
||||
}
|
||||
|
||||
interface Props {
|
||||
const WakuContext = createContext<Context | null>(null)
|
||||
|
||||
type Props = {
|
||||
peers: string[]
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export function WakuProvider({ children }: Props) {
|
||||
const [waku, setWaku] = useState<WakuLight>()
|
||||
export function WakuProvider({ peers, children }: Props) {
|
||||
const [waku, setWaku] = useState<LightNode>()
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true)
|
||||
const [isConnected, setIsConnected] = useState<boolean>(false)
|
||||
const [isError, setIsError] = useState<boolean>(false)
|
||||
|
||||
const start = async () => {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
|
||||
useEffect(() => {
|
||||
const start = async () => {
|
||||
const waku = await createLightNode({
|
||||
defaultBootstrap: false,
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
emitSelf: true,
|
||||
libp2p: {
|
||||
peerDiscovery: [new PeerDiscoveryStaticPeers(peers[config.wakuConfig.environment], { maxPeers: 1 })],
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore icorrectly types from @libp2p/boostrap#package.json; patched only in @status-im/js for now
|
||||
peerDiscovery: [
|
||||
bootstrap({
|
||||
list: peers,
|
||||
timeout: 0,
|
||||
// note: Infinity prevents connection
|
||||
// tagTTL: Infinity,
|
||||
}),
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
|
@ -32,16 +55,52 @@ export function WakuProvider({ children }: Props) {
|
|||
await waitForRemotePeer(waku, [Protocols.Store, Protocols.LightPush], 15 * 1000)
|
||||
|
||||
setWaku(waku)
|
||||
setIsLoading(false)
|
||||
setIsConnected(true)
|
||||
} catch (error) {
|
||||
setIsError(true)
|
||||
setIsLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const restart = async () => {
|
||||
if (isLoading) {
|
||||
throw new Error('Cannot restart while loading')
|
||||
}
|
||||
|
||||
await waku?.stop()
|
||||
await start()
|
||||
}
|
||||
|
||||
const stop = async () => {
|
||||
if (!waku) {
|
||||
return
|
||||
}
|
||||
|
||||
await waku.stop()
|
||||
|
||||
setIsConnected(false)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
start()
|
||||
|
||||
return () => {
|
||||
stop()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return <WakuContext.Provider value={waku}>{children}</WakuContext.Provider>
|
||||
return (
|
||||
<WakuContext.Provider value={{ waku, isLoading, isConnected, isError, restart }}>{children}</WakuContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export function useWaku() {
|
||||
const waku = useContext(WakuContext)
|
||||
const context = useContext(WakuContext)
|
||||
|
||||
return { waku }
|
||||
if (!context) {
|
||||
throw new Error('useWaku must be used within a WakuProvider')
|
||||
}
|
||||
|
||||
return context
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import { JsonRpcSigner } from '@ethersproject/providers'
|
|||
import proto from '../../../src/helpers/loadProtons'
|
||||
import { BigNumber, utils } from 'ethers'
|
||||
import protons from 'protons'
|
||||
import { EncoderV0 } from 'js-waku/lib/waku_message/version_0'
|
||||
import { createEncoder } from '@waku/core'
|
||||
|
||||
const proto2 = protons(`
|
||||
message WakuVote {
|
||||
|
@ -22,7 +22,7 @@ describe('wakuMessage', () => {
|
|||
|
||||
describe('decode waku vote', () => {
|
||||
it('success', async () => {
|
||||
const encoder = new EncoderV0('/test2/')
|
||||
const encoder = createEncoder({ contentTopic: '/test2/' })
|
||||
|
||||
const payload = proto.WakuVote.encode({
|
||||
address: '0x0',
|
||||
|
@ -69,7 +69,7 @@ describe('wakuMessage', () => {
|
|||
})
|
||||
|
||||
it('wrong data', async () => {
|
||||
const encoder = new EncoderV0('/test/')
|
||||
const encoder = createEncoder({ contentTopic: '/test2/' })
|
||||
|
||||
const payload = proto2.WakuVote.encode({
|
||||
address: '0x0',
|
||||
|
@ -101,7 +101,7 @@ describe('wakuMessage', () => {
|
|||
|
||||
describe('decode waku feature', () => {
|
||||
it('success', async () => {
|
||||
const encoder = new EncoderV0('/test/')
|
||||
const encoder = createEncoder({ contentTopic: '/test2/' })
|
||||
|
||||
const payload = proto2.WakuFeature.encode({
|
||||
voter: '0x0',
|
||||
|
@ -136,7 +136,7 @@ describe('wakuMessage', () => {
|
|||
|
||||
describe('create', () => {
|
||||
it('success', async () => {
|
||||
const encoder = new EncoderV0('/test/')
|
||||
const encoder = createEncoder({ contentTopic: '/test2/' })
|
||||
const payload = await wakuMessage.create(
|
||||
alice.address,
|
||||
alice as unknown as JsonRpcSigner,
|
||||
|
@ -147,7 +147,7 @@ describe('wakuMessage', () => {
|
|||
() => [],
|
||||
'0x01'
|
||||
)
|
||||
const msg = await encoder.toProtoObj({ payload })
|
||||
const msg = await encoder.toProtoObj({ payload: payload! })
|
||||
|
||||
expect(msg?.payload).to.not.be.undefined
|
||||
if (msg?.payload) {
|
||||
|
@ -161,7 +161,7 @@ describe('wakuMessage', () => {
|
|||
})
|
||||
|
||||
it('different payload', async () => {
|
||||
const encoder = new EncoderV0('/test/')
|
||||
const encoder = createEncoder({ contentTopic: '/test2/' })
|
||||
const payload = await wakuMessage.create(
|
||||
alice.address,
|
||||
alice as unknown as JsonRpcSigner,
|
||||
|
@ -172,7 +172,7 @@ describe('wakuMessage', () => {
|
|||
() => [],
|
||||
'0x01'
|
||||
)
|
||||
const msg = await encoder.toProtoObj({ payload })
|
||||
const msg = await encoder.toProtoObj({ payload: payload! })
|
||||
|
||||
expect(msg?.payload).to.not.be.undefined
|
||||
if (msg?.payload) {
|
||||
|
@ -186,23 +186,23 @@ describe('wakuMessage', () => {
|
|||
})
|
||||
|
||||
it('no address', async () => {
|
||||
const encoder = new EncoderV0('/test/')
|
||||
const encoder = createEncoder({ contentTopic: '/test2/' })
|
||||
const payload = await wakuMessage.create(undefined, alice as unknown as JsonRpcSigner, 1, 100, 1, 1, () => [])
|
||||
const msg = await encoder.toProtoObj({ payload })
|
||||
const msg = await encoder.toProtoObj({ payload: payload! })
|
||||
expect(msg?.payload).to.be.undefined
|
||||
})
|
||||
|
||||
it('no signer', async () => {
|
||||
const encoder = new EncoderV0('/test/')
|
||||
const encoder = createEncoder({ contentTopic: '/test2/' })
|
||||
const payload = await wakuMessage.create(alice.address, undefined, 1, 100, 1, 1, () => [])
|
||||
const msg = await encoder.toProtoObj({ payload })
|
||||
const msg = await encoder.toProtoObj({ payload: payload! })
|
||||
expect(msg?.payload).to.be.undefined
|
||||
})
|
||||
|
||||
it('different signer', async () => {
|
||||
const encoder = new EncoderV0('/test/')
|
||||
const encoder = createEncoder({ contentTopic: '/test2/' })
|
||||
const payload = await wakuMessage.create(alice.address, bob as unknown as JsonRpcSigner, 1, 100, 1, 1, () => [])
|
||||
const msg = await encoder.toProtoObj({ payload })
|
||||
const msg = await encoder.toProtoObj({ payload: payload! })
|
||||
expect(msg?.payload).to.be.undefined
|
||||
})
|
||||
})
|
||||
|
|
|
@ -28,6 +28,7 @@ module.exports = () => {
|
|||
crypto: require.resolve('crypto-browserify'),
|
||||
stream: require.resolve('stream-browserify'),
|
||||
assert: require.resolve('assert'),
|
||||
zlib: false,
|
||||
},
|
||||
},
|
||||
module: {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
"strict": true,
|
||||
"sourceMap": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"target": "es6",
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue