mirror of
https://github.com/oceanprotocol/commons.git
synced 2023-03-15 18:03:00 +01:00
Merge pull request #202 from oceanprotocol/fix/faucet
Faucet route refactor
This commit is contained in:
commit
2c99d6f9e6
@ -1,170 +0,0 @@
|
|||||||
import React, { PureComponent } from 'react'
|
|
||||||
import { FaucetResponse } from '../ocean'
|
|
||||||
import Route from '../components/templates/Route'
|
|
||||||
import Button from '../components/atoms/Button'
|
|
||||||
import Spinner from '../components/atoms/Spinner'
|
|
||||||
import { User, Market } from '../context'
|
|
||||||
import Web3message from '../components/organisms/Web3message'
|
|
||||||
import styles from './Faucet.module.scss'
|
|
||||||
import Content from '../components/atoms/Content'
|
|
||||||
import withTracker from '../hoc/withTracker'
|
|
||||||
import { showRequestTokens } from '../config'
|
|
||||||
|
|
||||||
interface FaucetState {
|
|
||||||
isLoading: boolean
|
|
||||||
success?: string
|
|
||||||
error?: string
|
|
||||||
trxHash?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
class Faucet extends PureComponent<{}, FaucetState> {
|
|
||||||
public static contextType = User
|
|
||||||
|
|
||||||
public state = {
|
|
||||||
isLoading: false,
|
|
||||||
success: undefined,
|
|
||||||
error: undefined,
|
|
||||||
trxHash: undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
private getTokens = async () => {
|
|
||||||
const { ocean } = this.context
|
|
||||||
const accounts = await ocean.accounts.list()
|
|
||||||
const account = accounts[0]
|
|
||||||
await ocean.accounts.requestTokens(account, 100)
|
|
||||||
}
|
|
||||||
|
|
||||||
private getEther = async (
|
|
||||||
requestFromFaucet: () => Promise<FaucetResponse>
|
|
||||||
) => {
|
|
||||||
this.setState({ isLoading: true })
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await requestFromFaucet()
|
|
||||||
|
|
||||||
if (!response.success) {
|
|
||||||
this.setState({
|
|
||||||
isLoading: false,
|
|
||||||
error: response.message
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { trxHash } = response
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
isLoading: false,
|
|
||||||
success: response.message,
|
|
||||||
trxHash
|
|
||||||
})
|
|
||||||
} catch (error) {
|
|
||||||
this.setState({ isLoading: false, error: error.message })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private reset = () => {
|
|
||||||
this.setState({
|
|
||||||
error: undefined,
|
|
||||||
success: undefined,
|
|
||||||
isLoading: false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private Success = () => {
|
|
||||||
const { network } = this.context
|
|
||||||
const { trxHash } = this.state
|
|
||||||
|
|
||||||
const submarineLink = `https://submarine.${
|
|
||||||
network === 'pacific' ? 'oceanprotocol' : `${network}.dev-ocean`
|
|
||||||
}.com/tx/${trxHash}`
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.success}>
|
|
||||||
<strong>{this.state.success}</strong>
|
|
||||||
<p>
|
|
||||||
<strong>Your Transaction Hash</strong>
|
|
||||||
|
|
||||||
<a href={submarineLink}>
|
|
||||||
<code>{trxHash}</code>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private Error = () => (
|
|
||||||
<div className={styles.error}>
|
|
||||||
<p>{this.state.error}</p>
|
|
||||||
<Button onClick={() => this.reset()}>Try again</Button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
private GetEther = () => (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
primary
|
|
||||||
onClick={() => this.getEther(this.context.requestFromFaucet)}
|
|
||||||
disabled={!this.context.isLogged}
|
|
||||||
name="FaucetEther"
|
|
||||||
>
|
|
||||||
Request Ether
|
|
||||||
</Button>
|
|
||||||
<p>
|
|
||||||
You can only request Ether once every 24 hours for your address.
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
|
|
||||||
private GetTokens = () => (
|
|
||||||
<>
|
|
||||||
<Button
|
|
||||||
primary
|
|
||||||
onClick={() => this.getTokens()}
|
|
||||||
disabled={!this.context.isLogged}
|
|
||||||
name="FaucetTokens"
|
|
||||||
>
|
|
||||||
Request OCEAN Tokens
|
|
||||||
</Button>
|
|
||||||
<p>You can request tokens every once in a while.</p>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { isLogged } = this.context
|
|
||||||
const { isLoading, error, success } = this.state
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Market.Consumer>
|
|
||||||
{market => (
|
|
||||||
<Route
|
|
||||||
title="Faucet"
|
|
||||||
description={`Shower yourself with some Ether for Ocean's ${market.network} network.`}
|
|
||||||
>
|
|
||||||
<Content>
|
|
||||||
<Web3message />
|
|
||||||
|
|
||||||
<div className={styles.action}>
|
|
||||||
{isLoading ? (
|
|
||||||
<Spinner message="Getting Ether..." />
|
|
||||||
) : error ? (
|
|
||||||
<this.Error />
|
|
||||||
) : success ? (
|
|
||||||
<this.Success />
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
{isLogged && <this.GetEther />}
|
|
||||||
{isLogged && showRequestTokens && (
|
|
||||||
<this.GetTokens />
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Content>
|
|
||||||
</Route>
|
|
||||||
)}
|
|
||||||
</Market.Consumer>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withTracker(Faucet)
|
|
12
client/src/routes/Faucet/Action.module.scss
Normal file
12
client/src/routes/Faucet/Action.module.scss
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
@import '../../styles/variables';
|
||||||
|
|
||||||
|
.action {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: $spacer;
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-top: $spacer / 2;
|
||||||
|
color: $brand-grey-light;
|
||||||
|
font-size: $font-size-small;
|
||||||
|
}
|
||||||
|
}
|
98
client/src/routes/Faucet/Action.tsx
Normal file
98
client/src/routes/Faucet/Action.tsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import React, { useContext, useState } from 'react'
|
||||||
|
import { FaucetResponse } from '../../ocean'
|
||||||
|
import Button from '../../components/atoms/Button'
|
||||||
|
import Spinner from '../../components/atoms/Spinner'
|
||||||
|
import { User } from '../../context'
|
||||||
|
|
||||||
|
import styles from './Action.module.scss'
|
||||||
|
import { Ocean } from '@oceanprotocol/squid'
|
||||||
|
import { ActionError, ActionSuccess } from './ActionResponse'
|
||||||
|
|
||||||
|
const ActionMarkup = ({
|
||||||
|
token,
|
||||||
|
handleAction
|
||||||
|
}: {
|
||||||
|
token: string
|
||||||
|
handleAction: () => void
|
||||||
|
}) => {
|
||||||
|
const { isLogged } = useContext(User)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
primary
|
||||||
|
onClick={handleAction}
|
||||||
|
disabled={!isLogged}
|
||||||
|
name={`Faucet${token}`}
|
||||||
|
>
|
||||||
|
{`Request ${token}`}
|
||||||
|
</Button>
|
||||||
|
{token === 'ETH' && (
|
||||||
|
<p>
|
||||||
|
You can only request {token} once every 24 hours for your
|
||||||
|
address.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Action({ token }: { token: string }) {
|
||||||
|
const { ocean, requestFromFaucet } = useContext(User)
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const [success, setSuccess] = useState('')
|
||||||
|
const [error, setError] = useState('')
|
||||||
|
const [trxHash, setTrxHash] = useState('')
|
||||||
|
|
||||||
|
async function getOcean(oceanInstance: Ocean) {
|
||||||
|
const accounts = await oceanInstance.accounts.list()
|
||||||
|
const account = accounts[0]
|
||||||
|
const success = await oceanInstance.accounts.requestTokens(account, 100)
|
||||||
|
|
||||||
|
success
|
||||||
|
? setSuccess('Received 100 Ocean Tokens.')
|
||||||
|
: setError('Failed getting Ocean Tokens.')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getEther(requestFromFaucet: () => Promise<FaucetResponse>) {
|
||||||
|
try {
|
||||||
|
const response = await requestFromFaucet()
|
||||||
|
const { message, success } = response
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
setError(message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { trxHash } = response
|
||||||
|
setSuccess(message)
|
||||||
|
trxHash && setTrxHash(trxHash)
|
||||||
|
} catch (error) {
|
||||||
|
setError(error.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAction = async () => {
|
||||||
|
setIsLoading(true)
|
||||||
|
|
||||||
|
token === 'OCEAN'
|
||||||
|
? await getOcean(ocean as Ocean)
|
||||||
|
: await getEther(requestFromFaucet as () => Promise<FaucetResponse>)
|
||||||
|
|
||||||
|
setIsLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.action}>
|
||||||
|
{isLoading ? (
|
||||||
|
<Spinner message={`Getting ${token}...`} />
|
||||||
|
) : error ? (
|
||||||
|
<ActionError error={error} />
|
||||||
|
) : success ? (
|
||||||
|
<ActionSuccess success={success} trxHash={trxHash} />
|
||||||
|
) : (
|
||||||
|
<ActionMarkup token={token} handleAction={handleAction} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
@ -1,21 +1,8 @@
|
|||||||
@import '../styles/variables';
|
@import '../../styles/variables';
|
||||||
|
|
||||||
.action {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: $spacer * 2;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-top: $spacer;
|
|
||||||
color: $brand-grey-light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.success {
|
.success {
|
||||||
color: $green;
|
color: $green;
|
||||||
|
margin-top: $spacer / 2;
|
||||||
p {
|
|
||||||
margin-top: $spacer / 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
display: block;
|
display: block;
|
37
client/src/routes/Faucet/ActionResponse.tsx
Normal file
37
client/src/routes/Faucet/ActionResponse.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import React, { useContext } from 'react'
|
||||||
|
import { User } from '../../context'
|
||||||
|
import styles from './ActionResponse.module.scss'
|
||||||
|
|
||||||
|
export const ActionSuccess = ({
|
||||||
|
success,
|
||||||
|
trxHash
|
||||||
|
}: {
|
||||||
|
success: string
|
||||||
|
trxHash: string
|
||||||
|
}) => {
|
||||||
|
const { network } = useContext(User)
|
||||||
|
const submarineLink = `https://submarine.${
|
||||||
|
network === 'pacific' ? 'oceanprotocol' : `${network}.dev-ocean`
|
||||||
|
}.com/tx/${trxHash}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.success}>
|
||||||
|
<strong>{success}</strong>
|
||||||
|
{trxHash && (
|
||||||
|
<p>
|
||||||
|
<strong>Your Transaction Hash</strong>
|
||||||
|
|
||||||
|
<a href={submarineLink}>
|
||||||
|
<code>{trxHash}</code>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ActionError = ({ error }: { error: string }) => (
|
||||||
|
<div className={styles.error}>
|
||||||
|
<p>{error}</p>
|
||||||
|
</div>
|
||||||
|
)
|
7
client/src/routes/Faucet/index.module.scss
Normal file
7
client/src/routes/Faucet/index.module.scss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
@import '../../styles/variables';
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: grid;
|
||||||
|
gap: $spacer / 2;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
}
|
@ -2,9 +2,9 @@ import React from 'react'
|
|||||||
import { render, fireEvent } from '@testing-library/react'
|
import { render, fireEvent } from '@testing-library/react'
|
||||||
import { MemoryRouter } from 'react-router'
|
import { MemoryRouter } from 'react-router'
|
||||||
import { createMemoryHistory, createLocation } from 'history'
|
import { createMemoryHistory, createLocation } from 'history'
|
||||||
import Faucet from './Faucet'
|
import Faucet from '.'
|
||||||
import { User } from '../context'
|
import { User, Market } from '../../context'
|
||||||
import { userMockConnected } from '../../__mocks__/user-mock'
|
import { userMockConnected } from '../../../__mocks__/user-mock'
|
||||||
|
|
||||||
const history = createMemoryHistory()
|
const history = createMemoryHistory()
|
||||||
const location = createLocation('/faucet')
|
const location = createLocation('/faucet')
|
||||||
@ -12,16 +12,25 @@ const location = createLocation('/faucet')
|
|||||||
const setup = () => {
|
const setup = () => {
|
||||||
const utils = render(
|
const utils = render(
|
||||||
<User.Provider value={userMockConnected}>
|
<User.Provider value={userMockConnected}>
|
||||||
<MemoryRouter>
|
<Market.Provider
|
||||||
<Faucet
|
value={{
|
||||||
history={history}
|
network: 'pacific',
|
||||||
location={location}
|
totalAssets: 100,
|
||||||
match={{ params: '', path: '', url: '', isExact: true }}
|
categories: [''],
|
||||||
/>
|
networkMatch: true
|
||||||
</MemoryRouter>
|
}}
|
||||||
|
>
|
||||||
|
<MemoryRouter>
|
||||||
|
<Faucet
|
||||||
|
history={history}
|
||||||
|
location={location}
|
||||||
|
match={{ params: '', path: '', url: '', isExact: true }}
|
||||||
|
/>
|
||||||
|
</MemoryRouter>
|
||||||
|
</Market.Provider>
|
||||||
</User.Provider>
|
</User.Provider>
|
||||||
)
|
)
|
||||||
const button = utils.getByText('Request Ether')
|
const button = utils.getByText('Request ETH')
|
||||||
const { container } = utils
|
const { container } = utils
|
||||||
return {
|
return {
|
||||||
button,
|
button,
|
||||||
@ -49,6 +58,6 @@ describe('Faucet', () => {
|
|||||||
fireEvent.click(button)
|
fireEvent.click(button)
|
||||||
expect(userMockConnected.requestFromFaucet).toHaveBeenCalledTimes(1)
|
expect(userMockConnected.requestFromFaucet).toHaveBeenCalledTimes(1)
|
||||||
// check for spinner
|
// check for spinner
|
||||||
expect(getByText('Getting Ether...')).toBeInTheDocument()
|
expect(getByText('Getting ETH...')).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
})
|
})
|
33
client/src/routes/Faucet/index.tsx
Normal file
33
client/src/routes/Faucet/index.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import React, { useContext } from 'react'
|
||||||
|
import Route from '../../components/templates/Route'
|
||||||
|
import { Market } from '../../context'
|
||||||
|
import Web3message from '../../components/organisms/Web3message'
|
||||||
|
import Content from '../../components/atoms/Content'
|
||||||
|
import withTracker from '../../hoc/withTracker'
|
||||||
|
import { showRequestTokens } from '../../config'
|
||||||
|
import Action from './Action'
|
||||||
|
import styles from './index.module.scss'
|
||||||
|
|
||||||
|
function Faucet() {
|
||||||
|
const { network } = useContext(Market)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Route
|
||||||
|
title="Faucet"
|
||||||
|
description={`Shower yourself with some ETH ${
|
||||||
|
showRequestTokens ? 'or OCEAN' : ''
|
||||||
|
} for Ocean's ${network} network.`}
|
||||||
|
>
|
||||||
|
<Content>
|
||||||
|
<Web3message />
|
||||||
|
|
||||||
|
<div className={styles.actions}>
|
||||||
|
<Action token="ETH" />
|
||||||
|
{showRequestTokens && <Action token="OCEAN" />}
|
||||||
|
</div>
|
||||||
|
</Content>
|
||||||
|
</Route>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTracker(Faucet)
|
@ -3,28 +3,28 @@ context('Faucet', () => {
|
|||||||
before(() => {
|
before(() => {
|
||||||
cy.visit('/faucet')
|
cy.visit('/faucet')
|
||||||
// Wait for end of loading
|
// Wait for end of loading
|
||||||
cy.get('button[name="FaucetEther"]', { timeout: 60000 }).should(
|
cy.get('button[name="FaucetETH"]', { timeout: 60000 }).should(
|
||||||
'have.length',
|
'have.length',
|
||||||
1
|
1
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
cy.get('button[name="FaucetEther"]')
|
cy.get('button[name="FaucetETH"]')
|
||||||
.first()
|
.first()
|
||||||
.as('button')
|
.as('button')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Faucet button is clickable when user is connected.', () => {
|
it('Faucet button is clickable when user is connected.', () => {
|
||||||
cy.get('@button')
|
cy.get('@button')
|
||||||
.contains('Request Ether')
|
.contains('Request ETH')
|
||||||
.should('not.be.disabled')
|
.should('not.be.disabled')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Execute faucet call', () => {
|
it('Execute faucet call', () => {
|
||||||
// Execute call
|
// Execute call
|
||||||
cy.get('@button')
|
cy.get('@button')
|
||||||
.contains('Request Ether')
|
.contains('Request ETH')
|
||||||
.click()
|
.click()
|
||||||
// Verify that we got response from server
|
// Verify that we got response from server
|
||||||
cy.contains(/(Successfully added|Already requested)/, {
|
cy.contains(/(Successfully added|Already requested)/, {
|
||||||
|
Loading…
Reference in New Issue
Block a user