diff --git a/client/src/App.tsx b/client/src/App.tsx
index 981b889..87d5ccd 100644
--- a/client/src/App.tsx
+++ b/client/src/App.tsx
@@ -1,273 +1,44 @@
import React, { Component } from 'react'
-import Web3 from 'web3'
import { BrowserRouter as Router } from 'react-router-dom'
-import { Logger } from '@oceanprotocol/squid'
import Header from './components/organisms/Header'
import Footer from './components/organisms/Footer'
import Spinner from './components/atoms/Spinner'
-import { User } from './context/User'
-import { provideOcean } from './ocean'
+import { User } from './context'
+import UserProvider from './context/UserProvider'
import Routes from './Routes'
import './styles/global.scss'
import styles from './App.module.scss'
-import {
- nodeHost,
- nodePort,
- nodeScheme,
- faucetHost,
- faucetPort,
- faucetScheme
-} from './config/config'
-
-const POLL_ACCOUNTS = 1000 // every 1s
-const POLL_NETWORK = POLL_ACCOUNTS * 60 // every 1 min
-
-declare global {
- interface Window {
- web3: Web3
- ethereum: any
- }
-}
-
-interface AppState {
- isLogged: boolean
- isLoading: boolean
- isWeb3: boolean
- isNile: boolean
- account: string
- balance: {
- eth: number
- ocn: number
- }
- network: string
- web3: Web3
- ocean: any
- requestFromFaucet(): void
- message: string
-}
-
-class App extends Component<{}, AppState> {
- private accountsInterval: any = null
- private networkInterval: any = null
-
- private requestFromFaucet = async () => {
- try {
- const url = `${faucetScheme}://${faucetHost}:${faucetPort}/faucet`
- const response = await fetch(url, {
- method: 'POST',
- headers: {
- Accept: 'application/json',
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- address: this.state.account,
- agent: 'commons'
- })
- })
- return response.json()
- } catch (error) {
- Logger.log('requestFromFaucet', error)
- }
- }
-
- public state = {
- isLogged: false,
- isLoading: true,
- isWeb3: false,
- isNile: false,
- balance: {
- eth: 0,
- ocn: 0
- },
- network: '',
- web3: new Web3(
- new Web3.providers.HttpProvider(
- `${nodeScheme}://${nodeHost}:${nodePort}`
- )
- ),
- account: '',
- ocean: {} as any,
- requestFromFaucet: this.requestFromFaucet,
- message: 'Connecting to Ocean...'
- }
-
- public async componentDidMount() {
- await this.bootstrap()
-
- this.initAccountsPoll()
- this.initNetworkPoll()
- }
-
- private bootstrap = async () => {
- try {
- //
- // Start with Web3 detection
- //
- this.setState({ message: 'Setting up Web3...' })
-
- // Modern dapp browsers
- if (window.ethereum) {
- window.web3 = new Web3(window.ethereum)
- this.setState({ isWeb3: true })
- }
- // Legacy dapp browsers
- else if (window.web3) {
- window.web3 = new Web3(window.web3.currentProvider)
- this.setState({ isWeb3: true })
- }
- // Non-dapp browsers
- else {
- this.setState({ isWeb3: false })
- }
-
- // Modern & legacy dapp browsers
- if (this.state.isWeb3) {
- //
- // Detecting network with window.web3
- //
- let isNile
-
- await window.web3.eth.net.getId((err, netId) => {
- if (err) return
-
- isNile = netId === 8995
- const network = isNile ? 'Nile' : netId.toString()
-
- if (
- isNile !== this.state.isNile ||
- network !== this.state.network
- ) {
- this.setState({ isNile, network })
- }
- })
-
- if (!isNile) {
- window.web3 = this.state.web3
- }
-
- //
- // Provide the Ocean
- //
- this.setState({ message: 'Connecting to Ocean...' })
-
- const { ocean } = await provideOcean(window.web3)
- this.setState({ ocean, isLoading: false })
-
- // Set proper network names now that we have Ocean
- this.fetchNetwork()
-
- // Get accounts
- this.fetchAccounts()
- }
- // Non-dapp browsers
- else {
- this.setState({ message: 'Connecting to Ocean...' })
- const { ocean } = await provideOcean(this.state.web3)
- this.setState({ ocean, isLoading: false })
-
- this.fetchNetwork()
- }
- } catch (e) {
- // error in bootstrap process
- // show error connecting to ocean
- Logger.log('web3 error', e)
- this.setState({ isLoading: false })
- }
- }
-
- private initAccountsPoll() {
- if (!this.accountsInterval) {
- this.accountsInterval = setInterval(
- this.fetchAccounts,
- POLL_ACCOUNTS
- )
- }
- }
-
- private initNetworkPoll() {
- if (!this.networkInterval) {
- this.networkInterval = setInterval(this.fetchNetwork, POLL_NETWORK)
- }
- }
-
- private fetchAccounts = async () => {
- const { ocean, isWeb3, isLogged, isNile } = this.state
-
- if (isWeb3) {
- // Modern dapp browsers
- if (window.ethereum) {
- if (!isLogged && isNile) {
- try {
- await window.ethereum.enable()
- } catch (error) {
- // User denied account access...
- this.accountsInterval = null
- return
- }
- }
- }
-
- const accounts = await ocean.accounts.list()
-
- if (accounts.length > 0) {
- const account = accounts[0].getId()
-
- if (account !== this.state.account) {
- this.setState({ account, isLogged: true })
- }
-
- const balance = await accounts[0].getBalance()
-
- if (
- balance.eth !== this.state.balance.eth ||
- balance.ocn !== this.state.balance.ocn
- ) {
- this.setState({ balance })
- }
- } else {
- isLogged !== false &&
- this.setState({ isLogged: false, account: '' })
- }
- }
- }
-
- private fetchNetwork = async () => {
- const { ocean, isWeb3 } = this.state
-
- if (isWeb3) {
- const network = await ocean.keeper.getNetworkName()
- const isNile = network === 'Nile'
-
- network !== this.state.network && this.setState({ isNile, network })
- }
- }
-
+export default class App extends Component {
public render() {
return (
-
+
<>
- {this.state.isLoading ? (
-
-
-
- ) : (
-
- )}
+
+ {states =>
+ states.isLoading ? (
+
+
+
+ ) : (
+
+ )
+ }
+
>
-
+
)
}
}
-
-export default App
diff --git a/client/src/components/molecules/AccountStatus/Indicator.tsx b/client/src/components/molecules/AccountStatus/Indicator.tsx
index 5bfa917..dd7c88a 100644
--- a/client/src/components/molecules/AccountStatus/Indicator.tsx
+++ b/client/src/components/molecules/AccountStatus/Indicator.tsx
@@ -1,6 +1,6 @@
import React from 'react'
import cx from 'classnames'
-import { User } from '../../../context/User'
+import { User } from '../../../context'
import styles from './Indicator.module.scss'
const Indicator = ({
diff --git a/client/src/components/molecules/AccountStatus/Popover.tsx b/client/src/components/molecules/AccountStatus/Popover.tsx
index 82b4dbc..5ae2041 100644
--- a/client/src/components/molecules/AccountStatus/Popover.tsx
+++ b/client/src/components/molecules/AccountStatus/Popover.tsx
@@ -1,6 +1,6 @@
import React, { PureComponent } from 'react'
import Dotdotdot from 'react-dotdotdot'
-import { User } from '../../../context/User'
+import { User } from '../../../context'
import styles from './Popover.module.scss'
export default class Popover extends PureComponent<{
diff --git a/client/src/components/organisms/AssetsUser.tsx b/client/src/components/organisms/AssetsUser.tsx
index d2058e8..e839262 100644
--- a/client/src/components/organisms/AssetsUser.tsx
+++ b/client/src/components/organisms/AssetsUser.tsx
@@ -1,7 +1,7 @@
import React, { PureComponent } from 'react'
import { Link } from 'react-router-dom'
import { Logger } from '@oceanprotocol/squid'
-import { User } from '../../context/User'
+import { User } from '../../context'
import Spinner from '../atoms/Spinner'
import Asset from '../molecules/Asset'
import styles from './AssetsUser.module.scss'
diff --git a/client/src/components/organisms/Header.tsx b/client/src/components/organisms/Header.tsx
index b3b0d9a..06d6935 100644
--- a/client/src/components/organisms/Header.tsx
+++ b/client/src/components/organisms/Header.tsx
@@ -1,7 +1,7 @@
import React, { PureComponent } from 'react'
import { NavLink } from 'react-router-dom'
import { ReactComponent as Logo } from '@oceanprotocol/art/logo/logo.svg'
-import { User } from '../../context/User'
+import { User } from '../../context'
import AccountStatus from '../molecules/AccountStatus'
import styles from './Header.module.scss'
diff --git a/client/src/components/organisms/Web3message.tsx b/client/src/components/organisms/Web3message.tsx
index 1bc3cb6..9765013 100644
--- a/client/src/components/organisms/Web3message.tsx
+++ b/client/src/components/organisms/Web3message.tsx
@@ -1,64 +1,36 @@
import React, { PureComponent } from 'react'
import Dotdotdot from 'react-dotdotdot'
-import Button from '../atoms/Button'
import AccountStatus from '../molecules/AccountStatus'
import styles from './Web3message.module.scss'
-import { User } from '../../context/User'
+import { User } from '../../context'
+import content from '../../data/web3message.json'
export default class Web3message extends PureComponent {
- private noWeb3 = () => (
+ private message = (message: string, account?: string) => (
-
Not a Web3 Browser. For
- publishing and downloading an asset you need to{' '}
-
- setup MetaMask
- {' '}
- or use any other Web3-capable plugin or browser.
-
- )
-
- private unlockAccount = () => (
-
-
No accounts detected.
- For publishing and downloading an asset you need to unlock your Web3
- account.
-
- )
-
- private haveAccount = (account: string) => (
-
-
-
- Connected with account
- {account}
-
-
- )
-
- private wrongNetwork = (network: string) => (
-
-
Not connected to Nile
- network, but to {network}.
- Please connect in MetaMask with Custom RPC{' '}
-
{`https://nile.dev-ocean.com`}
+
{' '}
+ {account ? (
+
+ {message}
+ {account}
+
+ ) : (
+
+ )}
)
public render() {
- const { isWeb3, isNile, isLogged, network, account } = this.context
+ const { isWeb3, isNile, isLogged, account } = this.context
return !isWeb3
- ? this.noWeb3()
+ ? this.message(content.noweb3)
: !isNile
- ? this.wrongNetwork(network)
+ ? this.message(content.wrongNetwork)
: !isLogged
- ? this.unlockAccount()
+ ? this.message(content.noAccount)
: isLogged
- ? this.haveAccount(account)
+ ? this.message(content.hasAccount, account)
: null
}
}
diff --git a/client/src/context/UserProvider.tsx b/client/src/context/UserProvider.tsx
new file mode 100644
index 0000000..60a6507
--- /dev/null
+++ b/client/src/context/UserProvider.tsx
@@ -0,0 +1,254 @@
+import React, { Component } from 'react'
+import Web3 from 'web3'
+import { Logger } from '@oceanprotocol/squid'
+import { User } from '.'
+import { provideOcean } from '../ocean'
+
+import {
+ nodeHost,
+ nodePort,
+ nodeScheme,
+ faucetHost,
+ faucetPort,
+ faucetScheme
+} from '../config/config'
+
+const POLL_ACCOUNTS = 1000 // every 1s
+const POLL_NETWORK = POLL_ACCOUNTS * 60 // every 1 min
+
+declare global {
+ interface Window {
+ web3: Web3
+ ethereum: {
+ enable(): void
+ host: string
+ supportsSubscriptions(): boolean
+ send(method: string, parameters: any[]): Promise
+ sendBatch(methods: any[], moduleInstance: any): Promise
+ }
+ }
+}
+
+interface UserProviderState {
+ isLogged: boolean
+ isLoading: boolean
+ isWeb3: boolean
+ isNile: boolean
+ account: string
+ balance: {
+ eth: number
+ ocn: number
+ }
+ network: string
+ web3: Web3
+ ocean: any
+ requestFromFaucet(): Promise<{}>
+ message: string
+}
+
+export default class UserProvider extends Component<{}, UserProviderState> {
+ private accountsInterval: any = null
+ private networkInterval: any = null
+
+ private requestFromFaucet = async () => {
+ try {
+ const url = `${faucetScheme}://${faucetHost}:${faucetPort}/faucet`
+ const response = await fetch(url, {
+ method: 'POST',
+ headers: {
+ Accept: 'application/json',
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ address: this.state.account,
+ agent: 'commons'
+ })
+ })
+ return response.json()
+ } catch (error) {
+ Logger.log('requestFromFaucet', error)
+ }
+ }
+
+ public state = {
+ isLogged: false,
+ isLoading: true,
+ isWeb3: false,
+ isNile: false,
+ balance: {
+ eth: 0,
+ ocn: 0
+ },
+ network: '',
+ web3: new Web3(
+ new Web3.providers.HttpProvider(
+ `${nodeScheme}://${nodeHost}:${nodePort}`
+ )
+ ),
+ account: '',
+ ocean: {} as any,
+ requestFromFaucet: this.requestFromFaucet,
+ message: 'Connecting to Ocean...'
+ }
+
+ public async componentDidMount() {
+ await this.bootstrap()
+
+ this.initAccountsPoll()
+ this.initNetworkPoll()
+ }
+
+ private bootstrap = async () => {
+ try {
+ //
+ // Start with Web3 detection only
+ //
+ this.setState({ message: 'Setting up Web3...' })
+
+ // Modern dapp browsers
+ if (window.ethereum) {
+ window.web3 = new Web3(window.ethereum)
+ this.setState({ isWeb3: true })
+ }
+ // Legacy dapp browsers
+ else if (window.web3) {
+ window.web3 = new Web3(window.web3.currentProvider)
+ this.setState({ isWeb3: true })
+ }
+ // Non-dapp browsers
+ else {
+ this.setState({ isWeb3: false })
+ }
+
+ // Modern & legacy dapp browsers
+ if (this.state.isWeb3) {
+ //
+ // Detecting network with window.web3
+ //
+ let isNile
+
+ await window.web3.eth.net.getId((err, netId) => {
+ if (err) return
+
+ isNile = netId === 8995
+ const network = isNile ? 'Nile' : netId.toString()
+
+ if (
+ isNile !== this.state.isNile ||
+ network !== this.state.network
+ ) {
+ this.setState({ isNile, network })
+ }
+ })
+
+ if (!isNile) {
+ window.web3 = this.state.web3
+ }
+
+ //
+ // Provide the Ocean
+ //
+ this.setState({ message: 'Connecting to Ocean...' })
+
+ const { ocean } = await provideOcean(window.web3)
+ this.setState({ ocean })
+
+ // Set proper network names now that we have Ocean
+ await this.fetchNetwork()
+
+ // Get accounts
+ await this.fetchAccounts()
+
+ this.setState({ isLoading: false })
+ }
+ // Non-dapp browsers
+ else {
+ this.setState({ message: 'Connecting to Ocean...' })
+ const { ocean } = await provideOcean(this.state.web3)
+ this.setState({ ocean, isLoading: false })
+
+ this.fetchNetwork()
+ }
+ } catch (e) {
+ // error in bootstrap process
+ // show error connecting to ocean
+ Logger.log('web3 error', e)
+ this.setState({ isLoading: false })
+ }
+ }
+
+ private initAccountsPoll() {
+ if (!this.accountsInterval) {
+ this.accountsInterval = setInterval(
+ this.fetchAccounts,
+ POLL_ACCOUNTS
+ )
+ }
+ }
+
+ private initNetworkPoll() {
+ if (!this.networkInterval) {
+ this.networkInterval = setInterval(this.fetchNetwork, POLL_NETWORK)
+ }
+ }
+
+ private fetchAccounts = async () => {
+ const { ocean, isWeb3, isLogged, isNile } = this.state
+
+ if (isWeb3) {
+ // Modern dapp browsers
+ if (window.ethereum) {
+ if (!isLogged && isNile) {
+ try {
+ await window.ethereum.enable()
+ } catch (error) {
+ // User denied account access...
+ this.accountsInterval = null
+ return
+ }
+ }
+ }
+
+ const accounts = await ocean.accounts.list()
+
+ if (accounts.length > 0) {
+ const account = accounts[0].getId()
+
+ if (account !== this.state.account) {
+ this.setState({ account, isLogged: true })
+ }
+
+ const balance = await accounts[0].getBalance()
+
+ if (
+ balance.eth !== this.state.balance.eth ||
+ balance.ocn !== this.state.balance.ocn
+ ) {
+ this.setState({ balance })
+ }
+ } else {
+ isLogged !== false &&
+ this.setState({ isLogged: false, account: '' })
+ }
+ }
+ }
+
+ private fetchNetwork = async () => {
+ const { ocean, isWeb3 } = this.state
+
+ if (isWeb3) {
+ const network = await ocean.keeper.getNetworkName()
+ const isNile = network === 'Nile'
+
+ network !== this.state.network && this.setState({ isNile, network })
+ }
+ }
+
+ public render() {
+ return (
+
+ {this.props.children}
+
+ )
+ }
+}
diff --git a/client/src/context/User.ts b/client/src/context/index.tsx
similarity index 93%
rename from client/src/context/User.ts
rename to client/src/context/index.tsx
index d4d5f34..b9e8712 100644
--- a/client/src/context/User.ts
+++ b/client/src/context/index.tsx
@@ -15,5 +15,6 @@ export const User = React.createContext({
network: '',
requestFromFaucet: () => {
/* empty */
- }
+ },
+ message: ''
})
diff --git a/client/src/data/web3message.json b/client/src/data/web3message.json
new file mode 100644
index 0000000..db9dc81
--- /dev/null
+++ b/client/src/data/web3message.json
@@ -0,0 +1,6 @@
+{
+ "noweb3": "Not a Web3 Browser. For publishing and downloading an asset you need to setup MetaMask or use any other Web3-capable plugin or browser.",
+ "noAccount": "No accounts detected. For publishing and downloading an asset you need to unlock your Web3 account.",
+ "hasAccount": "Connected with account ",
+ "wrongNetwork": "Not connected to Nile network.
Please connect in MetaMask with Custom RPC https://nile.dev-ocean.com
"
+}
diff --git a/client/src/routes/Details/AssetFile.tsx b/client/src/routes/Details/AssetFile.tsx
index 698ddf7..32f7374 100644
--- a/client/src/routes/Details/AssetFile.tsx
+++ b/client/src/routes/Details/AssetFile.tsx
@@ -3,7 +3,7 @@ import { Logger } from '@oceanprotocol/squid'
import filesize from 'filesize'
import Button from '../../components/atoms/Button'
import Spinner from '../../components/atoms/Spinner'
-import { User } from '../../context/User'
+import { User } from '../../context'
import styles from './AssetFile.module.scss'
import ReactGA from 'react-ga'
diff --git a/client/src/routes/Details/AssetFilesDetails.tsx b/client/src/routes/Details/AssetFilesDetails.tsx
index 9497920..4c5bdc7 100644
--- a/client/src/routes/Details/AssetFilesDetails.tsx
+++ b/client/src/routes/Details/AssetFilesDetails.tsx
@@ -1,6 +1,6 @@
import React, { PureComponent } from 'react'
import AssetFile from './AssetFile'
-import { User } from '../../context/User'
+import { User } from '../../context'
import Web3message from '../../components/organisms/Web3message'
import styles from './AssetFilesDetails.module.scss'
diff --git a/client/src/routes/Details/index.tsx b/client/src/routes/Details/index.tsx
index f54552f..b8131e0 100644
--- a/client/src/routes/Details/index.tsx
+++ b/client/src/routes/Details/index.tsx
@@ -1,7 +1,7 @@
import React, { Component } from 'react'
import Route from '../../components/templates/Route'
import Spinner from '../../components/atoms/Spinner'
-import { User } from '../../context/User'
+import { User } from '../../context'
import AssetDetails from './AssetDetails'
import stylesApp from '../../App.module.scss'
diff --git a/client/src/routes/Faucet.tsx b/client/src/routes/Faucet.tsx
index a4c7299..6590098 100644
--- a/client/src/routes/Faucet.tsx
+++ b/client/src/routes/Faucet.tsx
@@ -2,7 +2,7 @@ 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 { User } from '../context'
import Web3message from '../components/organisms/Web3message'
import styles from './Faucet.module.scss'
diff --git a/client/src/routes/History.tsx b/client/src/routes/History.tsx
index 329f640..a895287 100644
--- a/client/src/routes/History.tsx
+++ b/client/src/routes/History.tsx
@@ -2,7 +2,7 @@ import React, { Component } from 'react'
import Route from '../components/templates/Route'
import AssetsUser from '../components/organisms/AssetsUser'
import Web3message from '../components/organisms/Web3message'
-import { User } from '../context/User'
+import { User } from '../context'
export default class History extends Component {
public render() {
diff --git a/client/src/routes/Publish/Step.tsx b/client/src/routes/Publish/Step.tsx
index 06d25b2..ec940f5 100644
--- a/client/src/routes/Publish/Step.tsx
+++ b/client/src/routes/Publish/Step.tsx
@@ -3,7 +3,7 @@ import Input from '../../components/atoms/Form/Input'
import Label from '../../components/atoms/Form/Label'
import Row from '../../components/atoms/Form/Row'
import Button from '../../components/atoms/Button'
-import { User } from '../../context/User'
+import { User } from '../../context'
import Files from './Files/'
import StepRegisterContent from './StepRegisterContent'
import styles from './Step.module.scss'
diff --git a/client/src/routes/Publish/index.tsx b/client/src/routes/Publish/index.tsx
index 70670d0..eac62f3 100644
--- a/client/src/routes/Publish/index.tsx
+++ b/client/src/routes/Publish/index.tsx
@@ -3,7 +3,7 @@ import { Logger } from '@oceanprotocol/squid'
import Route from '../../components/templates/Route'
import Form from '../../components/atoms/Form/Form'
import AssetModel from '../../models/AssetModel'
-import { User } from '../../context/User'
+import { User } from '../../context'
import Web3message from '../../components/organisms/Web3message'
import Step from './Step'
import Progress from './Progress'
diff --git a/client/src/routes/Search.tsx b/client/src/routes/Search.tsx
index e8be6fb..0424e03 100644
--- a/client/src/routes/Search.tsx
+++ b/client/src/routes/Search.tsx
@@ -3,7 +3,7 @@ import queryString from 'query-string'
import { Logger } from '@oceanprotocol/squid'
import Spinner from '../components/atoms/Spinner'
import Route from '../components/templates/Route'
-import { User } from '../context/User'
+import { User } from '../context'
import Asset from '../components/molecules/Asset'
import Pagination from '../components/molecules/Pagination'
import styles from './Search.module.scss'