This repository has been archived by the owner on Apr 15, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 60
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #519 from LiskHQ/486-toaster
Setup React toaster - Closes #486
- Loading branch information
Showing
17 changed files
with
335 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import actionTypes from '../constants/actions'; | ||
|
||
/** | ||
* An action to dispatch to display a toast | ||
* | ||
*/ | ||
export const toastDisplayed = data => ({ | ||
data, | ||
type: actionTypes.toastDisplayed, | ||
}); | ||
|
||
/** | ||
* An action to dispatch to display a success toast | ||
* | ||
*/ | ||
export const successToastDisplayed = ({ type = 'success', ...rest }) => | ||
toastDisplayed({ type, ...rest }); | ||
|
||
|
||
/** | ||
* An action to dispatch to display an error toast | ||
* | ||
*/ | ||
export const errorToastDisplayed = ({ type = 'error', ...rest }) => | ||
toastDisplayed({ type, ...rest }); | ||
|
||
/** | ||
* An action to dispatch to hide a toast | ||
* | ||
*/ | ||
export const toastHidden = data => ({ | ||
data, | ||
type: actionTypes.toastHidden, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import { expect } from 'chai'; | ||
import actionTypes from '../constants/actions'; | ||
import { toastDisplayed, successToastDisplayed, errorToastDisplayed, toastHidden } from './toaster'; | ||
|
||
describe('actions: toaster', () => { | ||
const data = { | ||
label: 'dummy', | ||
}; | ||
|
||
describe('toastDisplayed', () => { | ||
it('should create an action to show toast', () => { | ||
|
||
|
||
const expectedAction = { | ||
data, | ||
type: actionTypes.toastDisplayed, | ||
}; | ||
expect(toastDisplayed(data)).to.be.deep.equal(expectedAction); | ||
}); | ||
}); | ||
|
||
describe('successToastDisplayed', () => { | ||
it('should create an action to show success toast', () => { | ||
const expectedAction = { | ||
data: { ...data, type: 'success' }, | ||
type: actionTypes.toastDisplayed, | ||
}; | ||
expect(successToastDisplayed(data)).to.be.deep.equal(expectedAction); | ||
}); | ||
}); | ||
|
||
describe('errorToastDisplayed', () => { | ||
it('should create an action to show error toast', () => { | ||
const expectedAction = { | ||
data: { ...data, type: 'error' }, | ||
type: actionTypes.toastDisplayed, | ||
}; | ||
expect(errorToastDisplayed(data)).to.be.deep.equal(expectedAction); | ||
}); | ||
}); | ||
|
||
describe('toastHidden', () => { | ||
it('should create an action to hide toast', () => { | ||
const expectedAction = { | ||
data, | ||
type: actionTypes.toastHidden, | ||
}; | ||
expect(toastHidden(data)).to.be.deep.equal(expectedAction); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { connect } from 'react-redux'; | ||
import ToasterComponent from './toasterComponent'; | ||
import { toastHidden } from '../../actions/toaster'; | ||
|
||
const mapStateToProps = state => ({ | ||
toasts: state.toaster || [], | ||
}); | ||
|
||
const mapDispatchToProps = dispatch => ({ | ||
hideToast: data => dispatch(toastHidden(data)), | ||
}); | ||
|
||
const Toaster = connect( | ||
mapStateToProps, | ||
mapDispatchToProps, | ||
)(ToasterComponent); | ||
|
||
export default Toaster; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import React from 'react'; | ||
import chai, { expect } from 'chai'; | ||
import sinonChai from 'sinon-chai'; | ||
import { mount } from 'enzyme'; | ||
import { Provider } from 'react-redux'; | ||
import Toaster from './'; | ||
import store from '../../store'; | ||
|
||
chai.use(sinonChai); | ||
|
||
|
||
describe('Toaster', () => { | ||
let wrapper; | ||
|
||
beforeEach(() => { | ||
wrapper = mount(<Provider store={store}><Toaster /></Provider>); | ||
}); | ||
|
||
it('should render ToasterComponent', () => { | ||
expect(wrapper.find('ToasterComponent')).to.have.lengthOf(1); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import React from 'react'; | ||
|
||
import { storiesOf } from '@storybook/react'; | ||
import { action } from '@storybook/addon-actions'; | ||
import Toaster from './toasterComponent'; | ||
|
||
|
||
storiesOf('Toaster', module) | ||
.add('default', () => ( | ||
<Toaster | ||
label='Test toast' | ||
hideToast={ action('onHide') } | ||
/> | ||
)) | ||
.add('success', () => ( | ||
<Toaster | ||
label='Success toast' | ||
type='success' | ||
hideToast={ action('onHide') } | ||
/> | ||
)) | ||
.add('error', () => ( | ||
<Toaster | ||
label='Error toast' | ||
type='error' | ||
hideToast={ action('onHide') } | ||
/> | ||
)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
.toast { | ||
color: white; | ||
left: initial; | ||
} | ||
|
||
@for $i from 0 to 10 { | ||
@keyframes move-$i { | ||
from { | ||
bottom: -50px; | ||
} | ||
to { | ||
bottom: calc($(i) * 50px + 10px); | ||
} | ||
} | ||
.index-$i { | ||
animation: move-$i 0.5s ease-in; | ||
bottom: calc($(i) * 50px + 10px); | ||
} | ||
} | ||
|
||
|
||
.error { | ||
background-color: #c62828; | ||
} | ||
|
||
.success { | ||
background-color: #7cb342; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import React, { Component } from 'react'; | ||
import { Snackbar } from 'react-toolbox'; | ||
import styles from './toaster.css'; | ||
|
||
class ToasterComponent extends Component { | ||
constructor() { | ||
super(); | ||
this.state = { | ||
hidden: {}, | ||
}; | ||
} | ||
|
||
hideToast(toast) { | ||
setTimeout(() => { | ||
this.props.hideToast(toast); | ||
this.setState({ hidden: { ...this.state.hidden, [toast.index]: false } }); | ||
}, 500); | ||
this.setState({ hidden: { ...this.state.hidden, [toast.index]: true } }); | ||
} | ||
|
||
render() { | ||
return (<span> | ||
{this.props.toasts.map(toast => ( | ||
<Snackbar | ||
active={!!toast.label && !this.state.hidden[toast.index]} | ||
key={toast.index} | ||
label={toast.label} | ||
timeout={4000} | ||
className={`${styles.toast} ${styles[toast.type]} ${styles[`index-${toast.index}`]}`} | ||
onTimeout={this.hideToast.bind(this, toast)} | ||
/> | ||
))} | ||
</span>); | ||
} | ||
} | ||
|
||
export default ToasterComponent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import React from 'react'; | ||
import chai, { expect } from 'chai'; | ||
import sinon from 'sinon'; | ||
import { mount } from 'enzyme'; | ||
import chaiEnzyme from 'chai-enzyme'; | ||
import sinonChai from 'sinon-chai'; | ||
import ToasterComponent from './toasterComponent'; | ||
|
||
chai.use(sinonChai); | ||
chai.use(chaiEnzyme()); // Note the invocation at the end | ||
describe('ToasterComponent', () => { | ||
let wrapper; | ||
const toasts = [{ | ||
label: 'test', | ||
type: 'success', | ||
index: 0, | ||
}]; | ||
const toasterProps = { | ||
toasts, | ||
hideToast: sinon.spy(), | ||
}; | ||
|
||
beforeEach(() => { | ||
wrapper = mount(<ToasterComponent {...toasterProps} />); | ||
}); | ||
|
||
it('renders <Snackbar /> component from react-toolbox', () => { | ||
expect(wrapper.find('Snackbar')).to.have.length(1); | ||
}); | ||
|
||
describe('hideToast', () => { | ||
it('hides the toast and after the animation ends calls this.props.hideToast()', () => { | ||
const clock = sinon.useFakeTimers(); | ||
wrapper.instance().hideToast(toasts[0]); | ||
expect(wrapper.state('hidden')).to.deep.equal({ [toasts[0].index]: true }); | ||
clock.tick(510); | ||
expect(wrapper.state('hidden')).to.deep.equal({ [toasts[0].index]: false }); | ||
clock.restore(); | ||
expect(toasterProps.hideToast).to.have.been.calledWith(toasts[0]); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import actionTypes from '../../constants/actions'; | ||
|
||
/** | ||
* | ||
* @param {Array} state | ||
* @param {Object} action | ||
*/ | ||
const toaster = (state = [], action) => { | ||
switch (action.type) { | ||
case actionTypes.toastDisplayed: | ||
return [ | ||
...state, | ||
{ | ||
...action.data, | ||
index: state.length ? state[state.length - 1].index + 1 : 0, | ||
}, | ||
]; | ||
case actionTypes.toastHidden: | ||
return state.filter(toast => toast.index !== action.data.index); | ||
default: | ||
return state; | ||
} | ||
}; | ||
|
||
export default toaster; |
Oops, something went wrong.