1
0
mirror of https://github.com/kremalicious/blog.git synced 2024-12-22 09:13:35 +01:00

web3 interaction

This commit is contained in:
Matthias Kretschmann 2018-10-09 23:48:25 +02:00
parent bde652533e
commit 2e85f7e24b
Signed by: m
GPG Key ID: 606EEEF3C479A91F
6 changed files with 234 additions and 89 deletions

View File

@ -48,10 +48,12 @@ export default class PostActions extends PureComponent {
</p>
</article>
{this.state.showModal && (
<ModalThanks
isOpen={this.state.showModal}
handleCloseModal={this.toggleModal}
/>
)}
</aside>
)
}

View File

@ -0,0 +1,180 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import Web3 from 'web3'
import styles from './Web3Donation.module.scss'
const ONE_SECOND = 1000
const ONE_MINUTE = ONE_SECOND * 60
export default class Web3Donation extends PureComponent {
state = {
web3Connected: false,
networkError: null,
networkId: null,
accounts: [],
selectedAccount: null,
receipt: '',
loading: false,
error: null
}
static propTypes = {
address: PropTypes.string
}
web3 = new Web3(Web3.givenProvider || 'ws://localhost:8546')
interval = null
networkInterval = null
componentDidMount() {
const { web3 } = this
if (web3 && web3.eth) {
this.setState({ web3Connected: true })
this.fetchAccounts()
this.fetchNetwork()
this.initPoll()
this.initNetworkPoll()
}
}
componentWillUnmount() {
clearInterval(this.interval)
clearInterval(this.networkInterval)
this.setState({ web3Connected: false })
}
initPoll() {
if (!this.interval) {
this.interval = setInterval(this.fetchAccounts, ONE_SECOND)
}
}
initNetworkPoll() {
if (!this.networkInterval) {
this.networkInterval = setInterval(this.fetchNetwork, ONE_MINUTE)
}
}
fetchNetwork = () => {
const { web3 } = this
web3 &&
web3.eth &&
web3.eth.net.getId((err, netId) => {
if (err) {
this.setState({
networkError: err
})
} else {
if (netId != this.state.networkId) {
this.setState({
networkError: null,
networkId: netId
})
}
}
})
}
fetchAccounts = () => {
const { web3 } = this
web3 &&
web3.eth &&
web3.eth.getAccounts((err, accounts) => {
if (err) {
this.setState({
accountsError: err
})
} else {
this.setState({
accounts,
selectedAccount: accounts[0]
})
}
})
}
handleWeb3Button = () => {
const { web3 } = this
this.setState({ loading: true })
web3.eth
.sendTransaction({
from: this.state.selectedAccount,
to: this.props.address,
value: '10000000000000000'
})
.then(receipt => {
this.setState({ receipt, loading: false })
})
.catch(error => {
this.setState({ error, loading: false })
})
}
render() {
if (this.state.web3Connected) {
return (
<div className={styles.web3}>
<h4>web3</h4>
<p>Send a donation with your MetaMask or Mist account.</p>
{this.state.web3Connected && (
<div>
{this.state.loading ? (
'Hang on...'
) : (
<button
className="btn btn-primary"
onClick={this.handleWeb3Button}
disabled={
!(this.state.networkId === 1) || !this.state.selectedAccount
}
>
Make it rain 0.01 Ξ
</button>
)}
{this.state.accounts.length === 0 && (
<div className={styles.alert}>
Web3 detected, but no account. Are you logged into your
MetaMask account?
</div>
)}
{this.state.networkId !== 1 && (
<div className={styles.alert}>
Please connect to Main network
</div>
)}
{this.state.error && (
<div className={styles.alert}>{this.state.error.message}</div>
)}
{this.state.receipt.status && (
<div className={styles.success}>
You are awesome, thanks!
<br />
<a
href={`https://etherscan.io/tx/${
this.state.receipt.transactionHash
}`}
>
See your transaction on etherscan.io.
</a>
</div>
)}
</div>
)}
</div>
)
} else {
return null
}
}
}

View File

@ -0,0 +1,39 @@
@import 'variables';
@import 'mixins';
.web3 {
@include divider;
width: 100%;
text-align: center;
margin-top: $spacer / 2;
margin-bottom: $spacer;
padding-bottom: $spacer * 1.5;
button {
margin: auto;
}
h4 {
font-size: $font-size-large;
margin-top: 0;
margin-bottom: $spacer / 4;
color: $brand-grey;
text-align: center;
}
p {
color: $brand-grey-light;
}
}
.alert {
margin-top: $spacer / 2;
font-size: $font-size-small;
color: darken($alert-error, 60%);
}
.success {
composes: alert;
color: darken($alert-success, 60%);
}

View File

@ -2,8 +2,7 @@ import React, { PureComponent } from 'react'
import { StaticQuery, graphql } from 'gatsby'
import { QRCode } from 'react-qr-svg'
import Clipboard from 'react-clipboard.js'
import Web3 from 'web3'
import Web3Donation from '../atoms/Web3Donation'
import Modal from '../atoms/Modal'
import { ReactComponent as IconClipboard } from '../../images/clipboard.svg'
import styles from './ModalThanks.module.scss'
@ -22,67 +21,6 @@ const query = graphql`
`
class ModalThanks extends PureComponent {
state = {
minimal: false,
web3Connected: false,
balance: '',
network: '',
accounts: [],
receipt: ''
}
web3 = new Web3(Web3.givenProvider || 'ws://localhost:8546')
componentDidMount() {
this.getWeb3Account()
}
getWeb3Account() {
if (this.web3 && this.web3.eth.net.isListening()) {
this.setState({ web3Connected: true })
this.web3.eth.net.getId((err, netId) => {
switch (netId) {
case '1':
this.setState({ network: 'Main' })
break
case '2':
this.setState({ network: 'Morden' })
break
case '3':
this.setState({ network: 'Ropsten' })
break
case '4':
this.setState({ network: 'Rinkeby' })
break
case '42':
this.setState({ network: 'Kovan' })
break
default:
this.setState({ network: 'unknown' })
}
})
this.web3.eth.getAccounts((error, accounts) => {
this.setState({ accounts })
this.web3.eth.getBalance(accounts[0]).then(balance => {
this.setState({ balance })
})
})
}
}
handleWeb3Button = () => {
this.web3.eth
.sendTransaction({
from: this.state.accounts[0],
to: '0x339dbC44d39bf1961E385ed0Ae88FC6069b87Ea1',
value: '1000000000000000'
})
.then(receipt => this.setState({ receipt }))
.catch(err => console.error(err))
}
render() {
return (
<StaticQuery
@ -97,19 +35,7 @@ class ModalThanks extends PureComponent {
title="Say thanks"
>
<div className={styles.modalThanks}>
{this.state.web3Connected && (
<div>
<button
className="btn btn-primary"
onClick={this.handleWeb3Button}
>
Make it rain
</button>
{this.state.receipt.status && (
<div>{this.state.receipt.transactionHash}</div>
)}
</div>
)}
<Web3Donation address={author.ether} />
{Object.keys(author).map((address, i) => (
<div key={i} className={styles.coin}>
@ -118,7 +44,7 @@ class ModalThanks extends PureComponent {
bgColor="transparent"
fgColor="#6b7f88"
level="Q"
style={{ width: 150 }}
style={{ width: 120 }}
value={author[address]}
/>
<pre>

View File

@ -5,10 +5,6 @@
display: flex;
justify-content: space-between;
flex-wrap: wrap;
> div:first-child {
width: 100%;
}
}
}

View File

@ -74,10 +74,12 @@ export default class Footer extends PureComponent {
</button>
</p>
{this.state.showModal && (
<ModalThanks
isOpen={this.state.showModal}
handleCloseModal={this.toggleModal}
/>
)}
</section>
</Container>
</footer>