@bufferapp/report-list
Advanced tools
Comparing version 0.11.1 to 0.12.0
@@ -5,2 +5,15 @@ module.exports = { | ||
{ | ||
test: /\.less$/, | ||
use: [ | ||
'style-loader', | ||
{ | ||
loader: 'css-loader', | ||
options: { | ||
modules: true, | ||
}, | ||
}, | ||
'less-loader', | ||
], | ||
}, | ||
{ | ||
test: /\.css$/, | ||
@@ -7,0 +20,0 @@ use: [ |
@@ -1,13 +0,8 @@ | ||
import React from 'react'; | ||
import React, { Component } from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import { | ||
Text, | ||
Button, | ||
} from '@bufferapp/components'; | ||
import moment from 'moment'; | ||
import styled from 'styled-components'; | ||
import StatelessReport from './StatelessReport'; | ||
const ReportListItem = styled.li` | ||
display: block; | ||
display: flex; | ||
background: #FFFFFF; | ||
@@ -21,39 +16,46 @@ border: 1px solid #D5E3EF; | ||
const ReportText = styled.span` | ||
display: flex; | ||
padding: ${props => (props.small ? '.75rem 1rem' : '1.5rem 1.25rem')}; | ||
justify-content: space-between; | ||
align-items: center; | ||
`; | ||
class Report extends Component { | ||
static propTypes = { | ||
removeReport: PropTypes.func, | ||
}; | ||
const Name = styled.span` | ||
color: #343E47; | ||
`; | ||
static defaultProps = { | ||
removeReport: null, | ||
}; | ||
const Date = styled.span` | ||
color: #c1c1c1; | ||
`; | ||
const Report = ({ _id, updated_at, name, selectReport, small }) => | ||
<ReportListItem> | ||
<Button noStyle fillContainer onClick={() => selectReport(_id)}> | ||
<ReportText small={small}> | ||
<Text size={small ? 'small' : null} weight="bold"><Name>{name}</Name></Text> | ||
<Text size={small ? 'small' : null}><Date>{moment(updated_at, 'x').format('MMMM D, YYYY')}</Date></Text> | ||
</ReportText> | ||
</Button> | ||
</ReportListItem>; | ||
constructor(props) { | ||
super(props); | ||
this.addHover = this.addHover.bind(this); | ||
this.removeHover = this.removeHover.bind(this); | ||
this.state = { | ||
hovered: false, | ||
}; | ||
} | ||
Report.defaultProps = { | ||
small: false, | ||
}; | ||
addHover() { | ||
this.setState({ | ||
hovered: true, | ||
}); | ||
} | ||
Report.propTypes = { | ||
_id: PropTypes.string.isRequired, | ||
updated_at: PropTypes.number.isRequired, | ||
name: PropTypes.string.isRequired, | ||
selectReport: PropTypes.func.isRequired, | ||
small: PropTypes.bool, | ||
}; | ||
removeHover() { | ||
this.setState({ | ||
hovered: false, | ||
}); | ||
} | ||
render() { | ||
const showButtons = this.state.hovered && this.props.removeReport; | ||
return ( | ||
<ReportListItem | ||
onMouseEnter={this.addHover} | ||
onMouseLeave={this.removeHover} | ||
> | ||
<StatelessReport {...this.props} showButtons={showButtons} /> | ||
</ReportListItem> | ||
); | ||
} | ||
} | ||
export default Report; |
@@ -6,2 +6,3 @@ import React from 'react'; | ||
import Report from './index'; | ||
import StatelessReport from './StatelessReport'; | ||
@@ -22,3 +23,11 @@ | ||
/> | ||
)) | ||
.add('can display buttons for viewing and removing the report', () => ( | ||
<StatelessReport | ||
{...report} | ||
showButtons | ||
selectReport={action('select report')} | ||
removeReport={action('remove report')} | ||
/> | ||
)); | ||
@@ -14,7 +14,15 @@ import React from 'react'; | ||
const ReportList = ({ loading, reports, selectReport, small }) => | ||
const ReportList = ({ loading, reports, selectReport, removeReport, small }) => | ||
(loading ? | ||
<Text>Loading...</Text> : | ||
<List> | ||
{reports.map(report => <Report key={report._id} {...report} small={small} selectReport={selectReport} />)} | ||
{reports.map(report => | ||
<Report | ||
key={report._id} | ||
{...report} | ||
small={small} | ||
selectReport={selectReport} | ||
removeReport={removeReport} | ||
/>, | ||
)} | ||
</List>); | ||
@@ -26,2 +34,3 @@ | ||
small: false, | ||
removeReport: null, | ||
}; | ||
@@ -36,2 +45,3 @@ | ||
selectReport: PropTypes.func.isRequired, | ||
removeReport: PropTypes.func, | ||
small: PropTypes.bool, | ||
@@ -38,0 +48,0 @@ }; |
@@ -27,3 +27,4 @@ import React from 'react'; | ||
selectReport={action('select report')} | ||
removeReport={action('remove report')} | ||
/> | ||
)); |
import { push } from 'react-router-redux'; | ||
import { connect } from 'react-redux'; | ||
import ReportList from './components/ReportList'; | ||
import { actions } from './reducer'; | ||
@@ -11,5 +12,4 @@ // default export = container | ||
dispatch => ({ | ||
selectReport: (id) => { | ||
dispatch(push(`/reports/${id}`)); | ||
}, | ||
selectReport: id => dispatch(push(`/reports/${id}`)), | ||
removeReport: id => dispatch(actions.removeReport(id)), | ||
}), | ||
@@ -16,0 +16,0 @@ )(ReportList); |
import React from 'react'; | ||
import { mount, configure } from 'enzyme'; | ||
import { mount, configure, shallow } from 'enzyme'; | ||
import Adapter from 'enzyme-adapter-react-16'; | ||
import { push } from 'react-router-redux'; | ||
import { Provider } from 'react-redux'; | ||
import ReportList, { | ||
import configureMockStore from 'redux-mock-store'; | ||
import ReportListContainer, { | ||
reducer, | ||
@@ -22,12 +24,13 @@ actions, | ||
describe('ReportList', () => { | ||
const state = { | ||
reportList: { | ||
reports: [], | ||
loading: true, | ||
}, | ||
}; | ||
it('should render', () => { | ||
const store = storeFake({ | ||
reportList: { | ||
reports: [], | ||
loading: true, | ||
}, | ||
}); | ||
const store = storeFake(state); | ||
const wrapper = mount( | ||
<Provider store={store}> | ||
<ReportList /> | ||
<ReportListContainer /> | ||
</Provider>, | ||
@@ -58,2 +61,24 @@ ); | ||
}); | ||
it('select report should dispatch a push navigation event', () => { | ||
const mockStore = configureMockStore(); | ||
const store = mockStore(state); | ||
const component = shallow(<ReportListContainer | ||
store={store} | ||
/>); | ||
expect(component.props().selectReport('id')).toEqual(push('/reports/id')); | ||
}); | ||
it('remove report should dispatch removeReport', () => { | ||
const mockStore = configureMockStore(); | ||
const store = mockStore(state); | ||
const component = shallow(<ReportListContainer | ||
store={store} | ||
/>); | ||
expect(component.props().removeReport('id')).toEqual(actions.removeReport('id')); | ||
}); | ||
}); |
import { LOCATION_CHANGE } from 'react-router-redux'; | ||
import { actions, actionTypes } from '@bufferapp/async-data-fetch'; | ||
import { actionTypes as reportListActionTypes } from './reducer'; | ||
@@ -24,2 +25,10 @@ export default store => next => (action) => { // eslint-disable-line no-unused-vars | ||
break; | ||
case reportListActionTypes.REMOVE_REPORT: | ||
store.dispatch(actions.fetch({ | ||
name: 'remove_report', | ||
args: { | ||
id: action.id, | ||
}, | ||
})); | ||
break; | ||
default: | ||
@@ -26,0 +35,0 @@ break; |
import { actions, actionTypes } from '@bufferapp/async-data-fetch'; | ||
import { LOCATION_CHANGE } from 'react-router-redux'; | ||
import { actionTypes as reportListActionTypes } from './reducer'; | ||
import middleware from './middleware'; | ||
@@ -80,3 +81,19 @@ | ||
it('triggers a remove_report RPC on REMOVE_REPORT', () => { | ||
const id = 'report-123'; | ||
const action = { | ||
type: reportListActionTypes.REMOVE_REPORT, | ||
id, | ||
}; | ||
middleware(store)(next)(action); | ||
expect(store.dispatch).toHaveBeenCalledWith(actions.fetch({ | ||
name: 'remove_report', | ||
args: { | ||
id, | ||
}, | ||
})); | ||
expect(next).toHaveBeenCalledWith(action); | ||
}); | ||
beforeEach(() => store.dispatch.mockReset()); | ||
}); |
{ | ||
"name": "@bufferapp/report-list", | ||
"version": "0.11.1", | ||
"version": "0.12.0", | ||
"description": "Report list package for Analyze", | ||
@@ -24,3 +24,3 @@ "main": "index.js", | ||
"dependencies": { | ||
"@bufferapp/analyze-shared-components": "^0.10.0", | ||
"@bufferapp/analyze-shared-components": "^0.12.0", | ||
"styled-components": "^2.2.1" | ||
@@ -27,0 +27,0 @@ }, |
@@ -5,2 +5,3 @@ import { actionTypes as asyncDataFetchActionTypes } from '@bufferapp/async-data-fetch'; | ||
VIEW_REPORT: 'VIEW_REPORT', | ||
REMOVE_REPORT: 'REMOVE_REPORT', | ||
}; | ||
@@ -33,2 +34,7 @@ | ||
}; | ||
case `remove_report_${asyncDataFetchActionTypes.FETCH_SUCCESS}`: | ||
return { | ||
...state, | ||
reports: state.reports.filter(report => report._id !== action.result.id), | ||
}; | ||
default: | ||
@@ -44,2 +50,6 @@ return state; | ||
}), | ||
removeReport: id => ({ | ||
type: actionTypes.REMOVE_REPORT, | ||
id, | ||
}), | ||
}; |
import { actionTypes as asyncDataFetchActions } from '@bufferapp/async-data-fetch'; | ||
import reducer from './reducer'; | ||
import reducer, { actions, actionTypes } from './reducer'; | ||
@@ -52,2 +52,33 @@ describe('reducer', () => { | ||
it('viewReport triggers VIEW_REPORT', () => { | ||
const id = 'report-123'; | ||
expect(actions.viewReport(id)).toEqual({ | ||
type: actionTypes.VIEW_REPORT, | ||
id, | ||
}); | ||
}); | ||
it('removeReport triggers REMOVE_REPORT', () => { | ||
const id = 'report-123'; | ||
expect(actions.removeReport(id)).toEqual({ | ||
type: actionTypes.REMOVE_REPORT, | ||
id, | ||
}); | ||
}); | ||
it('filters out the removed report on remover_report_FETCH_SUCCESS', () => { | ||
const id = 'report-123'; | ||
const reports = [{ _id: 'report-123' }, { _id: 'report-654' }]; | ||
const reportsFilteredState = reducer({ | ||
reports, | ||
}, { | ||
type: `remove_report_${asyncDataFetchActions.FETCH_SUCCESS}`, | ||
result: { | ||
id, | ||
}, | ||
}); | ||
expect(reportsFilteredState.reports).toHaveLength(1); | ||
expect(reportsFilteredState.reports[0]._id).toBe('report-654'); | ||
}); | ||
it('prepends the newly created report on create_report_FETCH_SUCCESS', () => { | ||
@@ -54,0 +85,0 @@ const state = reducer(undefined, { |
Sorry, the diff of this file is not supported yet
131134
40
1075
+ Added@bufferapp/analyze-shared-components@0.12.0(transitive)
- Removed@bufferapp/analyze-shared-components@0.10.0(transitive)