Skip to content

Commit

Permalink
feat(notifications): prepare for background notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
epiqueras committed Jan 25, 2019
1 parent 6151029 commit 3481dc9
Show file tree
Hide file tree
Showing 7 changed files with 241 additions and 96 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"react-scripts": "2.1.1",
"react-time-ago": "^3.0.3",
"shallowequal": "^1.1.0",
"styled-components": "^4.1.1"
"styled-components": "^4.1.1",
"web3": "^1.0.0-beta.37"
}
}
33 changes: 2 additions & 31 deletions src/bootstrap/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import React from 'react'
import drizzle from './drizzle'
import { register } from './service-worker'
import styled from 'styled-components/macro'
import useNotifications from './use-notifications'

const MenuItems = [
<Menu.Item key="home">
Expand Down Expand Up @@ -73,36 +74,6 @@ const StyledLayoutContent = styled(Layout.Content)`
background: white;
padding: 0 9.375vw 62px;
`
const notifications = [
{
date: new Date(),
message:
'Congratulations! You have been drawn as a juror to a case on Air Transport court.',
to: '/',
type: 'info'
},
{
date: new Date(),
message:
'Attention! You have 6h to vote on the case number 127464 at Air Transport court.',
to: '/',
type: 'error'
},
{
date: new Date(),
message:
'Attention! You have 24h to vote on the case number 127464 at Air Transport court.',
to: '/',
type: 'warning'
},
{
date: new Date(),
message:
'Congratulations! You have been drawn as a juror to a case on Air Transport court.',
to: '/',
type: 'info'
}
]
const settings = {
appeal: 'When a case I ruled is appealed.',
draw: 'When I am drawn as a juror.',
Expand Down Expand Up @@ -139,7 +110,7 @@ export default () => (
</StyledMenu>
</Col>
<StyledCol md={5} sm={8} xs={24}>
<Notifications notifications={notifications} />
<Notifications useNotifications={useNotifications} />
<NotificationSettings settings={settings} />
<Identicon pinakion />
</StyledCol>
Expand Down
152 changes: 152 additions & 0 deletions src/bootstrap/use-notifications.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { useCallback, useEffect, useState } from 'react'
import KlerosLiquid from '../assets/contracts/kleros-liquid.json'
import Web3 from 'web3'

const networkIDData = {
1: { name: 'MAINNET', provider: 'https://mainnet.infura.io' },
42: { name: 'KOVAN', provider: 'https://kovan.infura.io' }
}
const handlers = {
async AppealDecision(_, klerosLiquid, block, event) {
const dispute = await klerosLiquid.methods
.disputes(event.returnValues._disputeID)
.call()
if (dispute.period !== '4') {
const notification = {
date: new Date(block.timestamp * 1000),
message: `Case #${event.returnValues._disputeID} has been appealed.`,
to: `/cases/${event.returnValues._disputeID}`,
type: 'info'
}
return (await klerosLiquid.getPastEvents('Draw', {
filter: { _disputeID: event.returnValues._disputeID },
fromBlock: 0
})).map(d => ({
...notification,
account: d.returnValues._address,
key: `${event.blockNumber}-${event.transactionIndex}-${
event.logIndex
}-${d.returnValues._address}`
}))
}
},
async Draw(_, klerosLiquid, block, event) {
const dispute = await klerosLiquid.methods
.disputes(event.returnValues._disputeID)
.call()
if (dispute.period !== '4') {
const dispute2 = await klerosLiquid.methods
.getDispute(event.returnValues._disputeID)
.call()
if (
Number(event.returnValues._appeal) ===
dispute2.votesLengths.length - 1
)
return [
{
account: event.returnValues._address,
date: new Date(block.timestamp * 1000),
key: `${event.blockNumber}-${event.transactionIndex}-${
event.logIndex
}-${event.returnValues._address}`,
message: `Congratulations! You have been drawn as a juror on case #${
event.returnValues._disputeID
}.`,
to: `/cases/${event.returnValues._disputeID}`,
type: 'info'
}
]
}
},
async TokenAndETHShift(web3, _, block, event) {
const time = block.timestamp * 1000
if (Date.now() - time < 6.048e8)
return [
{
account: event.returnValues._address,
date: new Date(time),
key: `${event.blockNumber}-${event.transactionIndex}-${
event.logIndex
}-${event.returnValues._address}`,
message: `Case #${
event.returnValues._disputeID
} was executed. ETH: ${Number(
web3.utils.fromWei(event.returnValues._ETHAmount)
).toFixed(4)}, PNK: ${Number(
web3.utils.fromWei(event.returnValues._tokenAmount)
).toFixed(0)}.`,
to: `/cases/${event.returnValues._disputeID}`,
type: 'info'
}
]
}
}
export default networkID => {
const [notifications, setNotifications] = useState()
const onNotificationClick = useCallback(
({ currentTarget: { id } }) =>
setNotifications(notifications => {
localStorage.setItem(id, true)
const index = notifications.findIndex(n => n.key === id)
return [
...notifications.slice(0, index),
...notifications.slice(index + 1)
]
}),
[]
)
useEffect(() => {
const web3 = new Web3(networkIDData[networkID].provider)
const klerosLiquid = new web3.eth.Contract(
KlerosLiquid.abi,
process.env[
`REACT_APP_KLEROS_LIQUID_${networkIDData[networkID].name}_ADDRESS`
]
)
let mounted = true
Promise.all([
klerosLiquid.getPastEvents('AppealDecision', { fromBlock: 0 }),
klerosLiquid.getPastEvents('Draw', { fromBlock: 0 }),
klerosLiquid.getPastEvents('TokenAndETHShift', { fromBlock: 0 })
]).then(async ([events1, events2, events3]) => {
const notifications = []
for (const event of [...events1, ...events2, ...events3]) {
let _notifications = await handlers[event.event](
web3,
klerosLiquid,
await web3.eth.getBlock(event.blockNumber),
event
)
if (_notifications) {
_notifications = _notifications.filter(
n => !localStorage.getItem(n.key)
)
if (_notifications.length !== 0) notifications.push(..._notifications)
}
}
if (mounted) setNotifications(notifications.reverse())
})
const listener = klerosLiquid.events
.allEvents({ fromBlock: 0 })
.on('data', async event => {
if (handlers[event.event]) {
const notifications = handlers[event.event](
web3,
klerosLiquid,
await web3.eth.getBlock(event.blockNumber),
event
)
if (notifications && mounted)
setNotifications(_notifications => [
...notifications.reverse(),
..._notifications
])
}
})
return () => {
listener.unsubscribe()
mounted = false
}
}, [])
return { notifications, onNotificationClick }
}
2 changes: 1 addition & 1 deletion src/components/attachment.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import isVideo from 'is-video'
import styled from 'styled-components/macro'

const StyledPopover = styled(({ className, ...rest }) => (
<Popover overlayClassName={className} {...rest} />
<Popover className={className} overlayClassName={className} {...rest} />
))`
.ant-popover {
&-inner {
Expand Down
59 changes: 27 additions & 32 deletions src/components/case-details-card.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,21 @@ const CaseDetailsCard = ({ ID }) => {
({ currentTarget: { id } }) => send(ID, votesData.voteIDs, id, 0),
[ID, votesData.voteIDs]
)
const metaEvidenceActions = useMemo(
() =>
metaEvidence && [
<Attachment
URI={metaEvidence.metaEvidenceJSON.fileURI}
description="This is the primary file uploaded with the dispute."
extension={metaEvidence.metaEvidenceJSON.fileTypeExtension}
title="Main File"
/>,
<StyledInnerCardActionsTitleDiv className="ternary-color theme-color">
Primary Documents
</StyledInnerCardActionsTitleDiv>
],
[metaEvidence]
)
return (
<StyledCard
actions={useMemo(
Expand Down Expand Up @@ -350,25 +365,7 @@ const CaseDetailsCard = ({ ID }) => {
<>
<Row>
<Col span={24}>
<StyledInnerCard
actions={useMemo(
() => [
<Attachment
URI={metaEvidence.metaEvidenceJSON.fileURI}
description="This is the primary file uploaded with the dispute."
extension={
metaEvidence.metaEvidenceJSON.fileTypeExtension
}
title="Main File"
/>,
<StyledInnerCardActionsTitleDiv className="ternary-color theme-color">
Primary Documents
</StyledInnerCardActionsTitleDiv>
],
[metaEvidence]
)}
hoverable
>
<StyledInnerCard actions={metaEvidenceActions} hoverable>
{metaEvidence.metaEvidenceJSON.description}
</StyledInnerCard>
</Col>
Expand All @@ -379,22 +376,20 @@ const CaseDetailsCard = ({ ID }) => {
{Object.keys(evidenceBySubmitter).map(a => (
<Col key={a} md={12}>
<StyledInnerCard
actions={useMemo(
() => [
...evidenceBySubmitter[a].map(e => (
<Attachment
URI={e.evidenceJSON.fileURI}
description={e.evidenceJSON.description}
extension={e.evidenceJSON.fileTypeExtension}
title={e.evidenceJSON.name}
/>
)),
actions={evidenceBySubmitter[a]
.map(e => (
<Attachment
URI={e.evidenceJSON.fileURI}
description={e.evidenceJSON.description}
extension={e.evidenceJSON.fileTypeExtension}
title={e.evidenceJSON.name}
/>
))
.concat(
<StyledInnerCardActionsTitleDiv className="ternary-color theme-color">
Evidence
</StyledInnerCardActionsTitleDiv>
],
[evidence]
)}
)}
hoverable
title={
<>
Expand Down
Loading

0 comments on commit 3481dc9

Please sign in to comment.