From 0c2018c471bb7fff0cb18c3df4c035ba728c2622 Mon Sep 17 00:00:00 2001 From: josh Date: Tue, 15 Oct 2019 17:09:49 +1300 Subject: [PATCH 1/4] Add removal of Header component --- src/Header.js | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 src/Header.js diff --git a/src/Header.js b/src/Header.js deleted file mode 100644 index 68d137d..0000000 --- a/src/Header.js +++ /dev/null @@ -1,36 +0,0 @@ -/* @flow weak */ - -/** - * mSupply Mobile - * Sustainable Solutions (NZ) Ltd. 2016 - */ - -import React from 'react'; -import PropTypes from 'prop-types'; -import { - StyleSheet, - View, - ViewPropTypes, -} from 'react-native'; - -export function Header(props) { - const { children, style, ...viewProps } = props; - return ( - - {children} - - ); -} - -Header.propTypes = { - style: ViewPropTypes.style, - children: PropTypes.any, -}; - -const defaultStyles = StyleSheet.create({ - header: { - flexDirection: 'row', - flexWrap: 'nowrap', - backgroundColor: 'grey', - }, -}); From d703c7e4631090c6bbc1472a26fb42eae918a626 Mon Sep 17 00:00:00 2001 From: josh Date: Tue, 15 Oct 2019 17:09:57 +1300 Subject: [PATCH 2/4] Add HeaderRow component --- src/HeaderRow.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/HeaderRow.js diff --git a/src/HeaderRow.js b/src/HeaderRow.js new file mode 100644 index 0000000..9ddb165 --- /dev/null +++ b/src/HeaderRow.js @@ -0,0 +1,25 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import { View } from 'react-native' + +/** + * Renders a row of children as outputted by renderCells render prop + * + * @param {func} renderCells renderProp callBack for rendering cells based on rowData and rowState + * @param {Object} style Style object for the wrapping View component + */ +const HeaderRow = React.memo(({ renderCells, style }) => ( + {renderCells()} +)) + +HeaderRow.propTypes = { + renderCells: PropTypes.func.isRequired, + style: PropTypes.object, +} + +HeaderRow.defaultProps = { + style: {}, +} + +export default HeaderRow From 3da621f493ba266acc71b426a5d0561d6e0ac061 Mon Sep 17 00:00:00 2001 From: josh Date: Tue, 15 Oct 2019 17:10:53 +1300 Subject: [PATCH 3/4] Add HeaderCell component --- src/HeaderCell.js | 180 +++++++++++++++++++++++++--------------------- 1 file changed, 97 insertions(+), 83 deletions(-) diff --git a/src/HeaderCell.js b/src/HeaderCell.js index 95ded2a..18cb552 100644 --- a/src/HeaderCell.js +++ b/src/HeaderCell.js @@ -1,104 +1,118 @@ -/* @flow weak */ - -/** - * mSupply Mobile - * Sustainable Solutions (NZ) Ltd. 2016 - */ - -import React from 'react'; -import PropTypes from 'prop-types'; +/* eslint-disable react/forbid-prop-types */ +import React from 'react' +import PropTypes from 'prop-types' import { - StyleSheet, + TouchableOpacity, Text, View, - ViewPropTypes, - TouchableOpacity, -} from 'react-native'; - -import Icon from 'react-native-vector-icons/FontAwesome'; + TouchableOpacityPropTypes, +} from 'react-native' +import { getAdjustedStyle } from './utilities' /** - * Renders a headerCell that supports being a plain View with Text or being a TouchableOpacity (with - * callback). In the latter case Sort arrows will be rendered and controlled with isSelected and - * isAscending props. - * @param {object} props Properties passed where component was created. - * @prop {boolean} isSelected When false up+down sort arrows renderHeader, otherwise as below - * @prop {boolean} isAscending Sort arrow up if true, down if false. - * @prop {StyleSheet} style Style of the headerCell (View props) - * @prop {StyleSheet} textStyle Style of the text in the HeaderCell - * @prop {number} width flexbox flex property, gives weight to the headerCell width - * @prop {func} onPress CallBack (should change sort order in parent) - * @prop {string} text Text to render in headerCell - * @return {React.Component} Return TouchableOpacity with sort arrows if onPress is given a - * function. Otherwise return a View. + * Simple component to be used in conjunction with HeaderRow component. + * + * Renders a title and if passed, a sorting icon. + * + * @param {String} title Text to display in the cell + * @param {String} columnKey The key for the column the cell heads. + * @param {Func} onPressAction Action for dispatching on press + * @param {Func} dispatch Dispatcher to backing reducer + * @param {ReactElement} SortAscComponent Icon component for ascending sorting + * @param {ReactElement} SortDescComponent Icon component for descending sorting + * @param {ReactElement} SortNeutralComponent Icon component for neutral state, no sort. + * @param {Object} containerStyle Style object for the wrapping Touchable or View. + * @param {Object} textStyle Style object for the inner Text component. + * @param {Number} width Optional flex property to inject into styles. + * @param {Bool} isLastCell Indicator for if this cell is the last + * in a row. Removing the borderRight if true. */ - -export function HeaderCell(props) { - const { - style, +const HeaderCell = React.memo( + ({ + title, + columnKey, + sortDirection, + SortAscComponent, + SortDescComponent, + SortNeutralComponent, + onPressAction, + dispatch, + sortable, + containerStyle, textStyle, width, - onPress, - text, - isSelected, - isAscending, - ...containerProps - } = props; + isLastCell, + ...otherProps + }) => { + const onPress = () => { + dispatch(onPressAction(columnKey)) + } - function renderSortArrow() { - if (isSelected) { - // isAscending = true = a to z - if (isAscending) return ; - return ; + const Icon = () => { + switch (sortDirection) { + case 'ASC': { + return SortAscComponent + } + case 'DESC': { + return SortDescComponent + } + default: { + return SortNeutralComponent + } + } } - return ; - } - if (typeof onPress === 'function') { + const Container = onPressAction ? TouchableOpacity : View + + const internalContainerStyle = getAdjustedStyle( + containerStyle, + width, + isLastCell + ) + return ( - - - {text} - - {renderSortArrow()} - - ); + {title} + {sortable && } + + ) } - return ( - - - {text} - - - ); -} +) HeaderCell.propTypes = { - isSelected: PropTypes.bool, - isAscending: PropTypes.bool, - style: ViewPropTypes.style, - textStyle: Text.propTypes.style, + ...TouchableOpacityPropTypes, + title: PropTypes.string.isRequired, + columnKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) + .isRequired, + onPressAction: PropTypes.func, + dispatch: PropTypes.func, + sortDirection: PropTypes.oneOf(['ASC', 'DESC']), + SortAscComponent: PropTypes.element, + SortDescComponent: PropTypes.element, + SortNeutralComponent: PropTypes.element, + containerStyle: PropTypes.object, + textStyle: PropTypes.object, width: PropTypes.number, - onPress: PropTypes.func, - text: PropTypes.string, -}; + sortable: PropTypes.bool, + isLastCell: PropTypes.bool, +} HeaderCell.defaultProps = { - width: 1, -}; + dispatch: null, + onPressAction: null, + sortDirection: null, + SortAscComponent: null, + SortDescComponent: null, + SortNeutralComponent: null, + containerStyle: {}, + textStyle: {}, + sortable: false, + width: 0, + isLastCell: false, +} -const defaultStyles = StyleSheet.create({ - headerCell: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - }, - icon: { - marginRight: 10, - }, -}); +export default HeaderCell From f088da1be3686ad2e9a93db75207a18c707a8050 Mon Sep 17 00:00:00 2001 From: josh Date: Tue, 15 Oct 2019 18:56:14 +1300 Subject: [PATCH 4/4] Add removal of old tests --- __tests__/Header.spec.js | 35 ------------------------------ __tests__/HeaderCell.spec.js | 41 ------------------------------------ 2 files changed, 76 deletions(-) delete mode 100644 __tests__/Header.spec.js delete mode 100644 __tests__/HeaderCell.spec.js diff --git a/__tests__/Header.spec.js b/__tests__/Header.spec.js deleted file mode 100644 index 6630553..0000000 --- a/__tests__/Header.spec.js +++ /dev/null @@ -1,35 +0,0 @@ -jest.unmock('../Header'); -jest.unmock('enzyme'); -jest.unmock('sinon'); - -import { Header } from '../Header'; -import React from 'react'; -import { View, TouchableOpacity } from 'react-native'; -import sinon from 'sinon'; -import { shallow } from 'enzyme'; - -describe('Header', () => { - it('renders a view', () => { - const wrapper = shallow( -
- ); - expect(wrapper.find(View).length).toBe(1); - }); - it('renders some arbitrary components', () => { - const onBtnPress = sinon.spy(); - const wrapper = shallow( -
- - Foo - - onBtnPress()}> - Bar - -
- ); - expect(wrapper.contains('Foo')).toBe(true, 'Contains Foo'); - expect(wrapper.contains('Bar')).toBe(true, 'Contains Bar'); - wrapper.find(TouchableOpacity).simulate('press'); - expect(onBtnPress.calledOnce).toBe(true, 'Button press'); - }); -}); diff --git a/__tests__/HeaderCell.spec.js b/__tests__/HeaderCell.spec.js deleted file mode 100644 index 8a17d44..0000000 --- a/__tests__/HeaderCell.spec.js +++ /dev/null @@ -1,41 +0,0 @@ -jest.unmock('../HeaderCell'); -jest.unmock('enzyme'); -jest.unmock('sinon'); - -import { HeaderCell } from '../HeaderCell'; -import React from 'react'; -import { View, TouchableOpacity } from 'react-native'; -import sinon from 'sinon'; -import { shallow } from 'enzyme'; -import Icon from 'react-native-vector-icons/FontAwesome'; - -describe('HeaderCell', () => { - it('renders a TouchableOpacity when given onPress prop', () => { - const wrapper = shallow( - - ); - expect(wrapper.find(TouchableOpacity).length).toBe(1); - }); - it('renders a view and not TouchableOpacity when not given onPress prop', () => { - const wrapper = shallow( - - ); - expect(wrapper.find(TouchableOpacity).length).toBe(0); - expect(wrapper.find(View).length).toBe(1); - }); - it('Calls given func when pressed', () => { - const onBtnPress = sinon.spy(); - const wrapper = shallow( onBtnPress()} />); - expect(wrapper.find(TouchableOpacity).length).toBe(1); - wrapper.find(TouchableOpacity).simulate('press'); - expect(onBtnPress.calledOnce).toBe(true, 'Button press'); - }); - it('renders sort arrows when a function is given', () => { - const wrapper = shallow( - - ); - expect(wrapper.find(TouchableOpacity).length).toBe(1); - expect(wrapper.find(Icon).length).toBe(1); - expect(wrapper.find(Icon).props(name)).toEqual('sort'); - }); -});