Skip to content
This repository has been archived by the owner on Sep 4, 2020. It is now read-only.

Commit

Permalink
A lot of changes, among of them:
Browse files Browse the repository at this point in the history
- Added the balances section
- Added more information to Ticker
- SCSS changes for the ticker
- Made some information in Ticker to be optional.
- Added some tests (but only some)
- Changed the way utils.js was done
- Removed 'api' folder and moved its logic to utils.js
- Better API error handling
- And probably more that I don't remember now 😛
  • Loading branch information
elboletaire committed Dec 6, 2017
1 parent eb36ee7 commit dc776f7
Show file tree
Hide file tree
Showing 25 changed files with 463 additions and 70 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,10 @@
},
"devDependencies": {
"@types/axios": "^0.14.0",
"@types/axios-mock-adapter": "^1.9.0",
"@types/react": "^16.0.25",
"@types/react-router-dom": "^4.2.2",
"axios-mock-adapter": "^1.10.0",
"babel-eslint": "^8.0.2",
"babel-jest": "^21.2.0",
"babel-runtime": "^6.26.0",
Expand Down
2 changes: 1 addition & 1 deletion src/actions/api.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as actions from './api'
const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)

describe('api actions', () => {
describe('actions::api', () => {
it('setKey calls API_KEY_SET', () => {
const expectedActions = [
{
Expand Down
30 changes: 30 additions & 0 deletions src/actions/balances.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import axios from 'axios'
import {
BALANCES_GET,
BALANCES_GET_SUCCESS,
BALANCES_GET_ERROR,
} from '../constants/actionTypes'
import { uri, parseResponse } from '../utils'

export const balancesGet = () => ({
type: BALANCES_GET,
})

export const balancesGetSuccess = (balances) => ({
type: BALANCES_GET_SUCCESS,
balances,
})

export const balancesGetError = (error) => ({
typep: BALANCES_GET_ERROR,
error,
})

export const get = () => (dispatch) => {
dispatch(balancesGet())

return axios.get(uri('balances'))
.then(parseResponse)
.then((balances) => dispatch(balancesGetSuccess(balances)))
.catch((error) => dispatch(balancesGetError(error)))
}
59 changes: 59 additions & 0 deletions src/actions/balances.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import configureMockStore from 'redux-mock-store'
import axiosCore from 'axios'
import MockAdapter from 'axios-mock-adapter'
import thunk from 'redux-thunk'

import {
BALANCES_GET,
BALANCES_GET_SUCCESS,
} from '../constants/actionTypes'
import * as actions from './balances'

const axios = new MockAdapter(axiosCore)

const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)

const defaultState = {
all: {},
ids: [],
error: false,
}

const balances = [
{
Currency: 'ADA',
Balance: 0,
Available: 0,
Pending: 0,
CryptoAddress: null,
},
{
Currency: 'BAT',
Balance: 200,
Available: 0,
Pending: 0,
CryptoAddress: null,
},
]

describe('actions::balances', () => {
it('get() fires BALANCES_GET && BALANCES_GET_SUCCESS', () => {
axios.onGet(/balances$/).reply(200, balances)
const expectedActions = [
{
type: BALANCES_GET,
},
{
type: BALANCES_GET_SUCCESS,
balances,
},
]

const store = mockStore({ balances: defaultState })

return store.dispatch(actions.get()).then(() =>
expect(store.getActions()).toEqual(expectedActions)
)
})
})
42 changes: 30 additions & 12 deletions src/actions/markets.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
import axios from 'axios'
import {
MARKETS_GET,
MARKETS_GET_SUCCESS,
MARKETS_GET_ERROR,
MARKETS_FILTER,
MARKETS_GET,
MARKETS_GET_SUCCESS,
MARKETS_GET_ERROR,
MARKETS_FILTER,
} from '../constants/actionTypes'
import { uri, parseResponse } from '../utils'

import {
get as getMarkets,
} from '../api/markets'
const marketsGet = () => ({
type: MARKETS_GET,
})

const marketsGetSuccess = (markets) => ({
type: MARKETS_GET_SUCCESS,
markets,
})

const marketsGetError = (error) => ({
type: MARKETS_GET_ERROR,
error,
})

const marketsFilter = (keyword) => ({
type: MARKETS_FILTER,
keyword,
})

export const get = () => (dispatch) => {
dispatch({ type: MARKETS_GET })
dispatch(marketsGet())

return getMarkets()
.then((data) => dispatch({ type: MARKETS_GET_SUCCESS, data }))
.catch((error) => dispatch({ type: MARKETS_GET_ERROR, error }))
return axios.get(uri('markets'))
.then(parseResponse)
.then((markets) => dispatch(marketsGetSuccess(markets)))
.catch((error) => dispatch(marketsGetError(error)))
}

export const filter = (keyword) => (dispatch) =>
dispatch({ type: MARKETS_FILTER, keyword })
dispatch(marketsFilter(keyword))
64 changes: 64 additions & 0 deletions src/actions/markets.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import configureMockStore from 'redux-mock-store'
import axiosCore from 'axios'
import MockAdapter from 'axios-mock-adapter'
import thunk from 'redux-thunk'

import {
MARKETS_GET,
MARKETS_GET_SUCCESS,
} from '../constants/actionTypes'
import * as actions from './markets'

const axios = new MockAdapter(axiosCore)

const middlewares = [thunk]
const mockStore = configureMockStore(middlewares)

const defaultState = {
all: {},
ids: [],
visible: {},
error: false,
}

const markets = [
{
name: 'StartCoin',
base: 'BTC',
key: 'BTC-START',
ticker: 'START',
logo: 'https://bittrexblobstorage.blob.core.windows.net/public/2b596cad-231b-4252-8b50-0a5895a8a6b4.png',
id: '5a26e508597a4609068baee2',
active: true,
},
{
name: 'Monero',
base: 'BTC',
key: 'BTC-XMR',
ticker: 'XMR',
logo: 'https://bittrexblobstorage.blob.core.windows.net/public/efcda24e-c6c3-4029-982c-15af2915fb08.png',
id: '5a26e508597a4609068baee0',
active: true,
},
]

describe('actions::markets', () => {
it('get() fires MARKETS_GET && MARKETS_GET_SUCCESS', () => {
axios.onGet(/markets$/).reply(200, markets)
const expectedActions = [
{
type: MARKETS_GET,
},
{
type: MARKETS_GET_SUCCESS,
markets,
},
]

const store = mockStore({ markets: defaultState })

return store.dispatch(actions.get()).then(() =>
expect(store.getActions()).toEqual(expectedActions)
)
})
})
15 changes: 0 additions & 15 deletions src/api/index.js

This file was deleted.

5 changes: 0 additions & 5 deletions src/api/markets.js

This file was deleted.

51 changes: 51 additions & 0 deletions src/components/Balances/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import _ from 'lodash'

import { get as getBalances } from '../../actions/balances'
import { get as getMarkets } from '../../actions/markets'
import Ticker from '../Ticker'

export default class Balances extends Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
markets: PropTypes.object.isRequired,
balances: PropTypes.object.isRequired,
}

componentWillMount() {
this.props.dispatch(getMarkets())
this.props.dispatch(getBalances())
}

render() {
const { markets, balances } = this.props
if (!markets.ids.length || !balances.ids.length) {
return null
}

return (
<div className='balances-index'>
{
_.map(balances.all, (balance) => {
const market = markets.all[balance.Currency]
if (!market) {
console.error('Currency not found:', balance)
return null
}
if (!balance.Balance) {
return null
}
return (
<Ticker
logo={markets.all[balance.Currency].logo}
key={balance.Currency}
amount={`${balance.Balance} ${balance.Currency}`}
/>
)
})
}
</div>
)
}
}
7 changes: 5 additions & 2 deletions src/components/Navbar/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ export default class Navbar extends Component {
<Link to="/" className="navbar-brand">
Goby
</Link>
<Link to="/ticker-add" className="btn btn-default navbar-btn">
Add
<Link to="/balances" className="btn btn-link navbar-btn">
Your balances
</Link>
<Link to="/ticker-add" className="btn btn-link navbar-btn">
Add event
</Link>
</div>
</nav>
Expand Down
7 changes: 6 additions & 1 deletion src/components/Root.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {
import _ from 'lodash'

import Error from '../containers/Error'
import Selector from '../containers/Selector'
import Balances from '../containers/Balances'
import Dashboard from '../containers/Dashboard'
import Selector from '../containers/Selector'
import Container from './Container'
import Navbar from './Navbar'

Expand All @@ -21,6 +22,10 @@ const routes = [
path: '/ticker-add',
component: Selector,
},
{
path: '/balances',
component: Balances,
},
]

export default class Root extends Component {
Expand Down
11 changes: 9 additions & 2 deletions src/components/Selector/Search.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,19 @@ export default class Search extends Component {
}).isRequired,
}

sample = ''

onSearch(e) {
this.props.dispatch(filter(e.target.value))
}

render() {
const sample = _.sample(this.props.markets.all)
if (!this.sample.length) {
const sample = _.sample(this.props.markets.all)
if (sample && sample.name) {
this.sample = sample.name
}
}

return (
<div className="form-group">
Expand All @@ -27,7 +34,7 @@ export default class Search extends Component {
type="text"
onKeyUp={this.onSearch.bind(this)}
autoFocus={true}
placeholder={sample ? sample.name : ''}
placeholder={this.sample}
/>
</div>
)
Expand Down
12 changes: 6 additions & 6 deletions src/components/Selector/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default class Selector extends Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
markets: PropTypes.shape({
visible: PropTypes.object.isRequired,
visible: PropTypes.array.isRequired,
}).isRequired,
}

Expand All @@ -25,11 +25,11 @@ export default class Selector extends Component {
<div className="ticker selector">
<Search {...this.props} />
<div className="row">
{
_.map(visible, (market) => {
return <Ticker {...market} key={market.id} orientation="horizontal" />
})
}
{
_.map(visible, (market) => {
return <Ticker {...market} key={market.id} orientation="horizontal" />
})
}
</div>
</div>
)
Expand Down
Loading

0 comments on commit dc776f7

Please sign in to comment.