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');
- });
-});
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',
- },
-});
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
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