1
0
mirror of https://github.com/oceanprotocol/commons.git synced 2023-03-15 18:03:00 +01:00

Merge pull request #25 from oceanprotocol/feature/account-popup

Account & Faucet UI
This commit is contained in:
Jernej Pregelj 2019-03-05 15:36:13 +01:00 committed by GitHub
commit 214c5358eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 579 additions and 123 deletions

105
package-lock.json generated
View File

@ -2402,8 +2402,7 @@
"asap": { "asap": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
"dev": true
}, },
"asn1": { "asn1": {
"version": "0.2.4", "version": "0.2.4",
@ -5048,6 +5047,15 @@
"sha.js": "^2.4.8" "sha.js": "^2.4.8"
} }
}, },
"create-react-context": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.2.2.tgz",
"integrity": "sha512-KkpaLARMhsTsgp0d2NA/R94F/eDLbhXERdIq3LvX2biCAXcDvHYoOqHfWCHf1+OLj+HKBotLG3KqaOOf+C1C+A==",
"requires": {
"fbjs": "^0.8.0",
"gud": "^1.0.0"
}
},
"cross-spawn": { "cross-spawn": {
"version": "6.0.5", "version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
@ -6274,6 +6282,14 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
}, },
"encoding": {
"version": "0.1.12",
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
"integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
"requires": {
"iconv-lite": "~0.4.13"
}
},
"end-of-stream": { "end-of-stream": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
@ -7474,6 +7490,35 @@
"bser": "^2.0.0" "bser": "^2.0.0"
} }
}, },
"fbjs": {
"version": "0.8.17",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz",
"integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=",
"requires": {
"core-js": "^1.0.0",
"isomorphic-fetch": "^2.1.1",
"loose-envify": "^1.0.0",
"object-assign": "^4.1.0",
"promise": "^7.1.1",
"setimmediate": "^1.0.5",
"ua-parser-js": "^0.7.18"
},
"dependencies": {
"core-js": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
"integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
},
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
}
}
},
"fd-slicer": { "fd-slicer": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
@ -8982,6 +9027,11 @@
"integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
"dev": true "dev": true
}, },
"gud": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz",
"integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw=="
},
"gzip-size": { "gzip-size": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.0.0.tgz",
@ -10476,6 +10526,26 @@
"isarray": "1.0.0" "isarray": "1.0.0"
} }
}, },
"isomorphic-fetch": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz",
"integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=",
"requires": {
"node-fetch": "^1.0.1",
"whatwg-fetch": ">=0.10.0"
},
"dependencies": {
"node-fetch": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz",
"integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==",
"requires": {
"encoding": "^0.1.11",
"is-stream": "^1.0.1"
}
}
}
},
"isstream": { "isstream": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@ -13404,6 +13474,11 @@
"ts-pnp": "^1.0.0" "ts-pnp": "^1.0.0"
} }
}, },
"popper.js": {
"version": "1.14.7",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.7.tgz",
"integrity": "sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ=="
},
"portfinder": { "portfinder": {
"version": "1.0.20", "version": "1.0.20",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.20.tgz",
@ -17233,6 +17308,19 @@
"resolved": "https://registry.npmjs.org/react-moment/-/react-moment-0.8.4.tgz", "resolved": "https://registry.npmjs.org/react-moment/-/react-moment-0.8.4.tgz",
"integrity": "sha512-QhI19OcfhiAn60/O6bMR0w8ApXrPFCjv6+eV0I/P9/AswzjgEAx4L7VxMBCpS/jrythLa12Q9v88req+ys4YpA==" "integrity": "sha512-QhI19OcfhiAn60/O6bMR0w8ApXrPFCjv6+eV0I/P9/AswzjgEAx4L7VxMBCpS/jrythLa12Q9v88req+ys4YpA=="
}, },
"react-popper": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.3.tgz",
"integrity": "sha512-ynMZBPkXONPc5K4P5yFWgZx5JGAUIP3pGGLNs58cfAPgK67olx7fmLp+AdpZ0+GoQ+ieFDa/z4cdV6u7sioH6w==",
"requires": {
"@babel/runtime": "^7.1.2",
"create-react-context": "<=0.2.2",
"popper.js": "^1.14.4",
"prop-types": "^15.6.1",
"typed-styles": "^0.0.7",
"warning": "^4.0.2"
}
},
"react-router": { "react-router": {
"version": "4.3.1", "version": "4.3.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz", "resolved": "https://registry.npmjs.org/react-router/-/react-router-4.3.1.tgz",
@ -21343,6 +21431,11 @@
"mime-types": "~2.1.18" "mime-types": "~2.1.18"
} }
}, },
"typed-styles": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz",
"integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q=="
},
"typedarray": { "typedarray": {
"version": "0.0.6", "version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@ -21363,6 +21456,11 @@
"integrity": "sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==", "integrity": "sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==",
"dev": true "dev": true
}, },
"ua-parser-js": {
"version": "0.7.19",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz",
"integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ=="
},
"uglify-js": { "uglify-js": {
"version": "3.4.9", "version": "3.4.9",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
@ -23384,8 +23482,7 @@
"whatwg-fetch": { "whatwg-fetch": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz",
"integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==", "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q=="
"dev": true
}, },
"whatwg-mimetype": { "whatwg-mimetype": {
"version": "2.3.0", "version": "2.3.0",

View File

@ -25,6 +25,7 @@
"react-dom": "^16.8.3", "react-dom": "^16.8.3",
"react-helmet": "^5.2.0", "react-helmet": "^5.2.0",
"react-moment": "^0.8.4", "react-moment": "^0.8.4",
"react-popper": "^1.3.3",
"react-router-dom": "^4.3.1", "react-router-dom": "^4.3.1",
"react-transition-group": "^2.6.0", "react-transition-group": "^2.6.0",
"slugify": "^1.3.4", "slugify": "^1.3.4",

View File

@ -1,6 +1,7 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import Web3 from 'web3' import Web3 from 'web3'
import { BrowserRouter as Router } from 'react-router-dom' import { BrowserRouter as Router } from 'react-router-dom'
import { Logger } from '@oceanprotocol/squid'
import Header from './components/Header' import Header from './components/Header'
import Footer from './components/Footer' import Footer from './components/Footer'
import Spinner from './components/atoms/Spinner' import Spinner from './components/atoms/Spinner'
@ -31,6 +32,11 @@ interface AppState {
isLoading: boolean isLoading: boolean
isWeb3: boolean isWeb3: boolean
account: string account: string
balance: {
eth: number
ocn: number
}
network: string
web3: Web3 web3: Web3
ocean: {} ocean: {}
startLogin: () => void startLogin: () => void
@ -62,7 +68,7 @@ class App extends Component<{}, AppState> {
} }
) )
} catch (error) { } catch (error) {
// show error Logger.log('requestFromFaucet', error)
} }
} else { } else {
// no account found // no account found
@ -73,6 +79,11 @@ class App extends Component<{}, AppState> {
isLogged: false, isLogged: false,
isLoading: true, isLoading: true,
isWeb3: false, isWeb3: false,
balance: {
eth: 0,
ocn: 0
},
network: '',
web3: new Web3( web3: new Web3(
new Web3.providers.HttpProvider( new Web3.providers.HttpProvider(
`${nodeScheme}://${nodeHost}:${nodePort}` `${nodeScheme}://${nodeHost}:${nodePort}`
@ -140,7 +151,7 @@ class App extends Component<{}, AppState> {
}) })
} }
} catch (e) { } catch (e) {
// continue with default Logger.log('web3 error', e)
} }
} }
try { try {
@ -149,8 +160,13 @@ class App extends Component<{}, AppState> {
isLoading: false, isLoading: false,
ocean ocean
}) })
// TODO: squid-js balance retrieval fix
const accounts = await ocean.getAccounts()
const balance = await accounts[0].getBalance()
this.setState({ balance })
// TODO: squid-js expose keeper for getNetworkName
} catch (e) { } catch (e) {
// show loading error / unable to initialize ocean Logger.log('ocean/balance error', e)
this.setState({ this.setState({
isLoading: false isLoading: false
}) })

View File

@ -7,6 +7,7 @@ import Home from './routes/Home'
import NotFound from './routes/NotFound' import NotFound from './routes/NotFound'
import Publish from './routes/Publish/' import Publish from './routes/Publish/'
import Search from './routes/Search' import Search from './routes/Search'
import Faucet from './routes/Faucet'
import Styleguide from './routes/Styleguide' import Styleguide from './routes/Styleguide'
const Routes = () => ( const Routes = () => (
@ -17,6 +18,7 @@ const Routes = () => (
<Route component={Publish} path="/publish" /> <Route component={Publish} path="/publish" />
<Route component={Search} path="/search" /> <Route component={Search} path="/search" />
<Route component={Details} path="/asset/:did" /> <Route component={Details} path="/asset/:did" />
<Route component={Faucet} path="/faucet" />
<Route component={NotFound} /> <Route component={NotFound} />
</Switch> </Switch>
) )

View File

@ -1,9 +1,6 @@
@import '../styles/variables'; @import '../styles/variables';
.header { .header {
// background: $brand-black
// url('@oceanprotocol/art/mantaray/mantaray-back.svg') no-repeat center -6rem;
// background-size: cover;
width: 100%; width: 100%;
padding: $spacer / 2 0; padding: $spacer / 2 0;
} }
@ -94,3 +91,8 @@
color: $brand-pink; color: $brand-pink;
pointer-events: none; pointer-events: none;
} }
.accountStatus {
margin-left: $spacer;
margin-bottom: .2rem;
}

View File

@ -1,6 +1,7 @@
import React from 'react' import React from 'react'
import { NavLink } from 'react-router-dom' import { NavLink } from 'react-router-dom'
import { ReactComponent as Logo } from '@oceanprotocol/art/logo/logo.svg' import { ReactComponent as Logo } from '@oceanprotocol/art/logo/logo.svg'
import AccountStatus from './molecules/AccountStatus/'
import styles from './Header.module.scss' import styles from './Header.module.scss'
import menu from '../data/menu.json' import menu from '../data/menu.json'
@ -27,6 +28,7 @@ const Header = () => (
</NavLink> </NavLink>
))} ))}
</nav> </nav>
<AccountStatus className={styles.accountStatus} />
</div> </div>
</header> </header>
) )

View File

@ -1,48 +0,0 @@
@import '../styles/variables';
.message {
margin-bottom: $spacer;
color: $brand-grey;
padding-left: 1.5rem;
position: relative;
border-bottom: .1rem solid $brand-grey-lighter;
border-top: .1rem solid $brand-grey-lighter;
padding-top: $spacer / 2;
padding-bottom: $spacer / 2;
}
// default: red square
.indicator {
display: inline-block;
width: $font-size-small;
height: $font-size-small;
background: $red;
margin-right: $spacer / 8;
position: absolute;
left: 0;
top: ($spacer / 2) + .3rem;
}
// yellow triangle
.indicatorCloseEnough {
composes: indicator;
background: none;
width: 0;
height: 0;
border-left: $font-size-small / 1.75 solid transparent;
border-right: $font-size-small / 1.75 solid transparent;
border-bottom: $font-size-small solid $yellow;
}
// green circle
.indicatorActive {
composes: indicator;
border-radius: 50%;
background: $green;
}
.account {
display: inline-block;
margin-left: $spacer / 8;
background: none;
}

View File

@ -1,62 +0,0 @@
import React, { PureComponent } from 'react'
import Button from '../components/atoms/Button'
import styles from './Web3message.module.scss'
import { User } from '../context/User'
export default class Web3message extends PureComponent {
public render() {
return (
<>
<User.Consumer>
{states =>
!states.isWeb3
? this.noWeb3()
: !states.isLogged
? this.unlockAccount(states)
: states.isLogged
? this.haveAccount(states.account)
: null
}
</User.Consumer>
</>
)
}
public noWeb3() {
return (
<div className={styles.message}>
<span className={styles.indicator} /> No Web3 Browser. For
publishing an asset you need to use a Web3-capable plugin or
browser, like{' '}
<a href="https://docs.oceanprotocol.com/tutorials/wallets/#how-to-setup-metamask">
MetaMask
</a>
.
</div>
)
}
public unlockAccount(states: any) {
return (
<div className={styles.message}>
<span className={styles.indicatorCloseEnough} /> Account locked.
For publishing an asset you need to unlock your Web3 account.
<Button link onClick={states.startLogin}>
Unlock account
</Button>
</div>
)
}
public haveAccount(account: string) {
return (
<div className={styles.message}>
<span className={styles.indicatorActive} /> Connected with
account
<code className={styles.account} title={account && account}>
{`${account && account.substring(0, 20)}...`}
</code>
</div>
)
}
}

View File

@ -3,8 +3,8 @@
.spinner { .spinner {
position: relative; position: relative;
text-align: center; text-align: center;
margin-bottom: $spacer; margin-top: $spacer * $line-height;
margin-top: $spacer * 2; margin-bottom: $spacer / 2;
&:before { &:before {
content: ''; content: '';

View File

@ -0,0 +1,33 @@
@import '../../../styles/variables';
.status {
display: inline-block;
position: relative;
cursor: help;
}
// default: red square
.statusIndicator {
width: $font-size-small;
height: $font-size-small;
display: block;
background: $red;
}
// yellow triangle
.statusIndicatorCloseEnough {
composes: statusIndicator;
background: none;
width: 0;
height: 0;
border-left: $font-size-small / 1.7 solid transparent;
border-right: $font-size-small / 1.7 solid transparent;
border-bottom: $font-size-small solid $yellow;
}
// green circle
.statusIndicatorActive {
composes: statusIndicator;
border-radius: 50%;
background: $green;
}

View File

@ -0,0 +1,35 @@
import React from 'react'
import cx from 'classnames'
import { User } from '../../../context/User'
import styles from './Indicator.module.scss'
const Indicator = ({
className,
togglePopover,
forwardedRef
}: {
className?: string
togglePopover: () => void
forwardedRef: (ref: HTMLElement | null) => void
}) => (
<div
className={cx(styles.status, className)}
onMouseOver={togglePopover}
onMouseOut={togglePopover}
ref={forwardedRef}
>
<User.Consumer>
{states =>
!states.isWeb3 ? (
<span className={styles.statusIndicator} />
) : !states.isLogged ? (
<span className={styles.statusIndicatorCloseEnough} />
) : states.isLogged ? (
<span className={styles.statusIndicatorActive} />
) : null
}
</User.Consumer>
</div>
)
export default Indicator

View File

@ -0,0 +1,62 @@
@import '../../../styles/variables';
$popoverWidth: 18rem;
.popover {
position: relative;
width: $popoverWidth;
padding: $spacer / 2;
background: $brand-black;
border-radius: .1rem;
border: .1rem solid $brand-grey-light;
box-shadow: 0 6px 16px 0 rgba($brand-black, .3);
color: $brand-grey-light;
font-size: $font-size-small;
animation: showPopup .2s ease-in forwards;
}
@keyframes showPopup {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.popoverInfoline {
border-bottom: .05rem solid $brand-grey;
padding: $spacer / 3 0;
&:first-child {
padding-top: 0;
}
&:last-child {
padding-bottom: 0;
border-bottom: 0;
}
button {
font-size: $font-size-small;
}
}
.address {
width: 15rem;
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.balance {
font-size: $font-size-small;
margin-left: $spacer / 2;
white-space: nowrap;
&:first-child {
margin-left: 0;
}
}

View File

@ -0,0 +1,59 @@
import React from 'react'
import { User } from '../../../context/User'
import styles from './Popover.module.scss'
const Popover = ({
forwardedRef,
style
}: {
forwardedRef: (ref: HTMLElement | null) => void
style: React.CSSProperties
}) => (
<div className={styles.popover} ref={forwardedRef} style={style}>
<User.Consumer>
{states =>
states.account &&
states.balance && (
<div className={styles.popoverInfoline}>
<span
className={styles.balance}
title={(states.balance.eth / 1e18).toFixed(10)}
>
<strong>
{(states.balance.eth / 1e18)
.toFixed(3)
.slice(0, -1)}
</strong>{' '}
ETH
</span>
<span className={styles.balance}>
<strong>{states.balance.ocn}</strong> OCEAN
</span>
</div>
)
}
</User.Consumer>
<div className={styles.popoverInfoline}>
<User.Consumer>
{states =>
states.account ? (
<span className={styles.address} title={states.account}>
{states.account}
</span>
) : (
<em>No account selected</em>
)
}
</User.Consumer>
</div>
<div className={styles.popoverInfoline}>
<User.Consumer>
{states => states.network && states.network}
</User.Consumer>
</div>
</div>
)
export default Popover

View File

@ -0,0 +1,54 @@
import React, { PureComponent } from 'react'
import { Manager, Reference, Popper } from 'react-popper'
import AccountPopover from './Popover'
import AccountIndicator from './Indicator'
interface AccountStatusProps {
className?: string
}
interface AccountStatusState {
isPopoverOpen: boolean
}
export default class AccountStatus extends PureComponent<
AccountStatusProps,
AccountStatusState
> {
public state = {
isPopoverOpen: false
}
public togglePopover() {
this.setState(prevState => ({
isPopoverOpen: !prevState.isPopoverOpen
}))
}
public render() {
return (
<Manager>
<Reference>
{({ ref }) => (
<AccountIndicator
togglePopover={() => this.togglePopover()}
className={this.props.className}
forwardedRef={ref}
/>
)}
</Reference>
{this.state.isPopoverOpen && (
<Popper placement="auto">
{({ ref, style, placement }) => (
<AccountPopover
forwardedRef={ref}
style={style}
data-placement={placement}
/>
)}
</Popper>
)}
</Manager>
)
}
}

View File

@ -0,0 +1,23 @@
@import '../../styles/variables';
.message {
margin-bottom: $spacer;
color: $brand-grey;
padding-left: 2rem;
position: relative;
border-bottom: .1rem solid $brand-grey-lighter;
border-top: .1rem solid $brand-grey-lighter;
padding-top: $spacer / 2;
padding-bottom: $spacer / 2;
}
.account {
display: inline-block;
margin-left: $spacer / 8;
background: none;
}
.status {
margin-left: -($spacer);
margin-right: $spacer / 3;
}

View File

@ -0,0 +1,60 @@
import React, { PureComponent } from 'react'
import Button from '../atoms/Button'
import AccountStatus from './AccountStatus/'
import styles from './Web3message.module.scss'
import { User } from '../../context/User'
export default class Web3message extends PureComponent {
public render() {
return (
<User.Consumer>
{states =>
!states.isWeb3
? this.noWeb3()
: !states.isLogged
? this.unlockAccount(states)
: states.isLogged
? this.haveAccount(states.account)
: null
}
</User.Consumer>
)
}
public noWeb3() {
return (
<div className={styles.message}>
<AccountStatus className={styles.status} /> No Web3 Browser. For
publishing an asset you need to{' '}
<a href="https://docs.oceanprotocol.com/tutorials/metamask-setup/">
setup MetaMask
</a>{' '}
or use any other Web3-capable plugin or browser.
</div>
)
}
public unlockAccount(states: any) {
return (
<div className={styles.message}>
<AccountStatus className={styles.status} /> Account locked. For
publishing an asset you need to unlock your Web3 account.
<Button link onClick={states.startLogin}>
Unlock account
</Button>
</div>
)
}
public haveAccount(account: string) {
return (
<div className={styles.message}>
<AccountStatus className={styles.status} /> Connected with
account
<code className={styles.account} title={account && account}>
{`${account && account.substring(0, 20)}...`}
</code>
</div>
)
}
}

View File

@ -7,6 +7,11 @@ export const User = React.createContext({
account: '', account: '',
web3: {}, web3: {},
ocean: {}, ocean: {},
balance: {
eth: 0,
ocn: 0
},
network: '',
startLogin: () => { startLogin: () => {
/* empty */ /* empty */
}, },

View File

@ -3,6 +3,10 @@
"title": "Publish", "title": "Publish",
"link": "/publish" "link": "/publish"
}, },
{
"title": "Faucet",
"link": "/faucet"
},
{ {
"title": "About", "title": "About",
"link": "/about" "link": "/about"

View File

@ -0,0 +1,15 @@
@import '../styles/variables';
.action {
text-align: center;
margin-top: $spacer * 2;
p {
margin-top: $spacer;
color: $brand-grey-light;
}
}
.success {
color: $green;
}

96
src/routes/Faucet.tsx Normal file
View File

@ -0,0 +1,96 @@
import React, { PureComponent } from 'react'
import Route from '../components/templates/Route'
import Button from '../components/atoms/Button'
import Spinner from '../components/atoms/Spinner'
import { User } from '../context/User'
import Web3message from '../components/molecules/Web3message'
import styles from './Faucet.module.scss'
interface FaucetState {
isLoading: boolean
success?: string
error?: string
eth?: string
}
export default class Faucet extends PureComponent<{}, FaucetState> {
public state = {
isLoading: false,
success: undefined,
error: undefined,
eth: 'xx'
}
private getTokens = async (requestFromFaucet: () => void) => {
this.setState({ isLoading: true })
try {
await requestFromFaucet()
this.setState({
isLoading: false,
success: `Successfully added ${
this.state.eth
} ETH to your account.`
})
} catch (error) {
this.setState({ isLoading: false, error })
}
}
private RequestMarkup = () => (
<User.Consumer>
{states => (
<Button
primary
onClick={() => this.getTokens(states.requestFromFaucet)}
>
Request Ether
</Button>
)}
</User.Consumer>
)
private ActionMarkup = () => (
<div className={styles.action}>
{this.state.isLoading ? (
<Spinner message="Getting Ether..." />
) : this.state.error ? (
<div className={styles.error}>
{this.state.error}{' '}
<Button link onClick={this.reset}>
Try again
</Button>
</div>
) : this.state.success ? (
<div className={styles.success}>{this.state.success}</div>
) : (
<this.RequestMarkup />
)}
<p>
You can only request Ether once every 24 hours for your address.
</p>
</div>
)
private reset = () => {
this.setState({
error: undefined,
success: undefined,
isLoading: false
})
}
public render() {
return (
<Route
title="Faucet"
description="Shower yourself with some Ether for the Ocean POA network."
>
<Web3message />
<this.ActionMarkup />
</Route>
)
}
}

View File

@ -1,5 +1,5 @@
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import Web3message from '../../components/Web3message' import Web3message from '../../components/molecules/Web3message'
import Spinner from '../../components/atoms/Spinner' import Spinner from '../../components/atoms/Spinner'
import styles from './StepRegisterContent.module.scss' import styles from './StepRegisterContent.module.scss'