mirror of
https://github.com/kremalicious/blog.git
synced 2024-12-22 17:23:50 +01:00
web3 interaction
This commit is contained in:
parent
bde652533e
commit
2e85f7e24b
@ -48,10 +48,12 @@ export default class PostActions extends PureComponent {
|
|||||||
</p>
|
</p>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
{this.state.showModal && (
|
||||||
<ModalThanks
|
<ModalThanks
|
||||||
isOpen={this.state.showModal}
|
isOpen={this.state.showModal}
|
||||||
handleCloseModal={this.toggleModal}
|
handleCloseModal={this.toggleModal}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</aside>
|
</aside>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
180
src/components/atoms/Web3Donation.jsx
Normal file
180
src/components/atoms/Web3Donation.jsx
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
src/components/atoms/Web3Donation.module.scss
Normal file
39
src/components/atoms/Web3Donation.module.scss
Normal 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%);
|
||||||
|
}
|
@ -2,8 +2,7 @@ import React, { PureComponent } from 'react'
|
|||||||
import { StaticQuery, graphql } from 'gatsby'
|
import { StaticQuery, graphql } from 'gatsby'
|
||||||
import { QRCode } from 'react-qr-svg'
|
import { QRCode } from 'react-qr-svg'
|
||||||
import Clipboard from 'react-clipboard.js'
|
import Clipboard from 'react-clipboard.js'
|
||||||
import Web3 from 'web3'
|
import Web3Donation from '../atoms/Web3Donation'
|
||||||
|
|
||||||
import Modal from '../atoms/Modal'
|
import Modal from '../atoms/Modal'
|
||||||
import { ReactComponent as IconClipboard } from '../../images/clipboard.svg'
|
import { ReactComponent as IconClipboard } from '../../images/clipboard.svg'
|
||||||
import styles from './ModalThanks.module.scss'
|
import styles from './ModalThanks.module.scss'
|
||||||
@ -22,67 +21,6 @@ const query = graphql`
|
|||||||
`
|
`
|
||||||
|
|
||||||
class ModalThanks extends PureComponent {
|
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() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<StaticQuery
|
<StaticQuery
|
||||||
@ -97,19 +35,7 @@ class ModalThanks extends PureComponent {
|
|||||||
title="Say thanks"
|
title="Say thanks"
|
||||||
>
|
>
|
||||||
<div className={styles.modalThanks}>
|
<div className={styles.modalThanks}>
|
||||||
{this.state.web3Connected && (
|
<Web3Donation address={author.ether} />
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
className="btn btn-primary"
|
|
||||||
onClick={this.handleWeb3Button}
|
|
||||||
>
|
|
||||||
Make it rain
|
|
||||||
</button>
|
|
||||||
{this.state.receipt.status && (
|
|
||||||
<div>{this.state.receipt.transactionHash}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{Object.keys(author).map((address, i) => (
|
{Object.keys(author).map((address, i) => (
|
||||||
<div key={i} className={styles.coin}>
|
<div key={i} className={styles.coin}>
|
||||||
@ -118,7 +44,7 @@ class ModalThanks extends PureComponent {
|
|||||||
bgColor="transparent"
|
bgColor="transparent"
|
||||||
fgColor="#6b7f88"
|
fgColor="#6b7f88"
|
||||||
level="Q"
|
level="Q"
|
||||||
style={{ width: 150 }}
|
style={{ width: 120 }}
|
||||||
value={author[address]}
|
value={author[address]}
|
||||||
/>
|
/>
|
||||||
<pre>
|
<pre>
|
||||||
|
@ -5,10 +5,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|
||||||
> div:first-child {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,10 +74,12 @@ export default class Footer extends PureComponent {
|
|||||||
</button>
|
</button>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
{this.state.showModal && (
|
||||||
<ModalThanks
|
<ModalThanks
|
||||||
isOpen={this.state.showModal}
|
isOpen={this.state.showModal}
|
||||||
handleCloseModal={this.toggleModal}
|
handleCloseModal={this.toggleModal}
|
||||||
/>
|
/>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
</Container>
|
</Container>
|
||||||
</footer>
|
</footer>
|
||||||
|
Loading…
Reference in New Issue
Block a user