diff --git a/.eslintrc b/.eslintrc index 761d7076d9eb728c74fc62ed66cd8ed3821a6f99..7fb97d884d338ddfa1a4b3df9f16f8922b4d5ea1 100644 --- a/.eslintrc +++ b/.eslintrc @@ -44,7 +44,7 @@ "no-var": "error", "prefer-const": "error", "no-trailing-spaces": "error", - "react/prop-types": 0, + "react/prop-types": 2, "max-len": [ 1, { diff --git a/components/app-text-input.js b/components/app-text-input.js index 50bf3f139dfca358bf572a418c925c63b7bfab22..54e4a19d82a41f7ae5f510847f05a8dcf31f7449 100644 --- a/components/app-text-input.js +++ b/components/app-text-input.js @@ -18,7 +18,11 @@ export default function AppTextInput({ style, ...props }) { } AppTextInput.propTypes = { - secureTextEntry: PropTypes.bool + autoFocus: PropTypes.bool, + onChangeText: PropTypes.func, + placeholder: PropTypes.string, + style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]), + value: PropTypes.string, } AppTextInput.defaultProps = { diff --git a/components/app-text.js b/components/app-text.js index 83e87814fc88927eef4fabf97f61e2860921e8c0..e2c621004cb640ed21dbb11cf5ae2ae1349ff375 100644 --- a/components/app-text.js +++ b/components/app-text.js @@ -1,27 +1,26 @@ import React from 'react' +import PropTypes from 'prop-types' import { Text } from 'react-native' import styles from "../styles" import Link from './link' -export default function AppText(props) { +export default function AppText({ children, onPress, numberOfLines, style}) { // we parse for links in case the text contains any return ( <Link> - <Text - style={[styles.appText, props.style]} - onPress={props.onPress} - numberOfLines={props.numberOfLines} + <Text style={[styles.appText, style]} + onPress={onPress} + numberOfLines={numberOfLines} > - {props.children} + {children} </Text> </Link> ) } -export function SymptomSectionHeader(props) { - return ( - <AppText style={styles.symptomViewHeading}> - {props.children} - </AppText> - ) -} \ No newline at end of file +AppText.propTypes = { + children: PropTypes.node, + onPress: PropTypes.func, + numberOfLines: PropTypes.number, + style: PropTypes.oneOfType([PropTypes.array, PropTypes.object]), +} diff --git a/components/button.js b/components/button.js index 41d5344967269ef96827b18e4f797047bb1004e6..be06408152cfc2095d3e9c5a17e85163d89a52aa 100644 --- a/components/button.js +++ b/components/button.js @@ -1,22 +1,31 @@ import React from 'react' +import PropTypes from 'prop-types' import { TouchableOpacity } from 'react-native' import AppText from './app-text' import styles from '../styles' -export default function Button(props) { +export default function Button({ + backgroundColor, + children, + onPress, + style, + testID +}) { return ( <TouchableOpacity - onPress={props.onPress} - style={[ - styles.button, - props.style, - {backgroundColor: props.backgroundColor} - ]} - testID={props.testID} + onPress={onPress} + style={[styles.button, style, { backgroundColor }]} + testID={testID} > - <AppText style={styles.homeButtonText}> - {props.children} - </AppText> + <AppText style={styles.homeButtonText}>{children}</AppText> </TouchableOpacity> ) -} \ No newline at end of file +} + +Button.propTypes = { + backgroundColor: PropTypes.string, + children: PropTypes.node, + onPress: PropTypes.func, + style: PropTypes.object, + testID: PropTypes.string +} diff --git a/components/calendar.js b/components/calendar.js index 9387e0c83707f1fa39ebbfee246f1ba97b49f753..2340168d3ec28aa30b255334add4b6219540127f 100644 --- a/components/calendar.js +++ b/components/calendar.js @@ -1,4 +1,5 @@ import React, { Component } from 'react' +import PropTypes from 'prop-types' import { CalendarList } from 'react-native-calendars' import { connect } from 'react-redux' @@ -13,6 +14,11 @@ import styles from '../styles/index' import nothingChanged from '../db/db-unchanged' class CalendarView extends Component { + static propTypes = { + setDate: PropTypes.func.isRequired, + navigate: PropTypes.func.isRequired + } + constructor(props) { super(props) this.bleedingDays = getBleedingDaysSortedByDate() diff --git a/components/chart/chart.js b/components/chart/chart.js index 95985522d030396da9e0240cbdbdfaff6561d79e..d11131ad9236f196c0d1012b359f76864cfcf7f9 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -1,4 +1,5 @@ import React, { Component } from 'react' +import PropTypes from 'prop-types' import { View, FlatList, ActivityIndicator } from 'react-native' import AppLoadingView from '../app-loading' @@ -17,6 +18,11 @@ import config from '../../config' import styles from './styles' export default class CycleChart extends Component { + static propTypes = { + navigate: PropTypes.func, + end: PropTypes.bool + } + constructor(props) { super(props) this.state = {} @@ -147,12 +153,14 @@ export default class CycleChart extends Component { } } -function LoadingMoreView(props) { +function LoadingMoreView({ end }) { return ( <View style={styles.loadingMore}> - {!props.end && - <ActivityIndicator size={'large'} color={'white'}/> - } + {!end && <ActivityIndicator size={'large'} color={'white'}/>} </View> ) } + +LoadingMoreView.propTypes = { + end: PropTypes.bool +} diff --git a/components/chart/day-column.js b/components/chart/day-column.js index fffc1fcb4ba5756fe82b1aabb881c5c2c53020d2..687b993818e08ab37e9f90a5261282293b2f883a 100644 --- a/components/chart/day-column.js +++ b/components/chart/day-column.js @@ -1,4 +1,5 @@ import React, { Component } from 'react' +import PropTypes from 'prop-types' import { TouchableOpacity } from 'react-native' import { connect } from 'react-redux' @@ -18,6 +19,18 @@ import { } from '../helpers/chart' class DayColumn extends Component { + static propTypes = { + dateString: PropTypes.string.isRequired, + chartSymptoms: PropTypes.array, + columnHeight: PropTypes.number.isRequired, + getFhmAndLtlInfo: PropTypes.func.isRequired, + navigate: PropTypes.func.isRequired, + setDate: PropTypes.func.isRequired, + symptomHeight: PropTypes.number.isRequired, + symptomRowSymptoms: PropTypes.array, + xAxisHeight: PropTypes.number + } + constructor(props) { super() diff --git a/components/chart/dot-and-line.js b/components/chart/dot-and-line.js index 21e9eeb2c48f26603655168807b5006123638568..be5be85271bc2305c37c0762c33abefdd75f2e98 100644 --- a/components/chart/dot-and-line.js +++ b/components/chart/dot-and-line.js @@ -1,10 +1,20 @@ import React, { Component } from 'react' +import PropTypes from 'prop-types' import { Path, Shape } from 'react-native/Libraries/ART/ReactNativeART' import styles from './styles' import config from '../../config' export default class DotAndLine extends Component { + static propTypes = { + exclude: PropTypes.bool, + leftY: PropTypes.number, + leftTemperatureExclude: PropTypes.bool, + rightY: PropTypes.number, + rightTemperatureExclude: PropTypes.bool, + y: PropTypes.number.isRequired + } + shouldComponentUpdate(newProps) { return Object.keys(newProps).some(key => newProps[key] != this.props[key]) } diff --git a/components/cycle-day/SymptomBox.js b/components/cycle-day/SymptomBox.js index b4af7c3e8320a233d93238ccaf6d6ba31ac1e3be..62f5df0a96a3bd49db859a19c09236f2cb01322f 100644 --- a/components/cycle-day/SymptomBox.js +++ b/components/cycle-day/SymptomBox.js @@ -1,4 +1,5 @@ -import React, { Component } from 'react' +import React from 'react' +import PropTypes from 'prop-types' import { View, TouchableOpacity } from 'react-native' import AppText from '../app-text' @@ -124,47 +125,50 @@ const l = { } } -export default class SymptomBox extends Component { - getLabel = () => { - const { symptom, symptomData } = this.props - return symptomData && l[symptom](symptomData) - } +const getLabel = (symptom, symptomData) => { + return symptomData && l[symptom](symptomData) +} - render() { - const { symptom, onPress, disabled } = this.props - const data = this.getLabel() - const iconName = `drip-icon-${symptom}` +export default function SymptomBox( + { disabled, onPress, symptom, symptomData }) { - const disabledStyle = disabled ? styles.symptomInFuture : null - const containerStyle = [ - styles.symptomBox, - data && styles.symptomBoxActive, - disabledStyle - ] - const titleStyle = [ - data && styles.symptomTextActive, - disabledStyle, - {fontSize: 15} - ] - const dataBoxStyle = [styles.symptomDataBox, disabledStyle] + const data = getLabel(symptom, symptomData) + const iconName = `drip-icon-${symptom}` - return ( - <TouchableOpacity onPress={onPress} disabled={disabled} testID={iconName}> - <View style={containerStyle}> - <Icon name={iconName} isActive={data} /> - <AppText style={titleStyle} numberOfLines={1}> - {symptomTitles[symptom].toLowerCase()} - </AppText> - </View> - <View style={dataBoxStyle}> - <AppText style={styles.symptomDataText} numberOfLines={3}> - {data} - </AppText> - </View> - </TouchableOpacity> - ) - } + const disabledStyle = disabled ? styles.symptomInFuture : null + const containerStyle = [ + styles.symptomBox, + data && styles.symptomBoxActive, + disabledStyle + ] + const titleStyle = [ + data && styles.symptomTextActive, + disabledStyle, + {fontSize: 15} + ] + const dataBoxStyle = [styles.symptomDataBox, disabledStyle] + const iconColor = data ? 'white' : 'black' + + return ( + <TouchableOpacity onPress={onPress} disabled={disabled} testID={iconName}> + <View style={containerStyle}> + <DripIcon name={iconName} size={50} color={iconColor} /> + <AppText style={titleStyle} numberOfLines={1}> + {symptomTitles[symptom].toLowerCase()} + </AppText> + </View> + <View style={dataBoxStyle}> + <AppText style={styles.symptomDataText} numberOfLines={3}> + {data} + </AppText> + </View> + </TouchableOpacity> + ) } -const Icon = ({name, isActive}) => - <DripIcon name={name} size={50} color={isActive ? 'white' : 'black'} /> \ No newline at end of file +SymptomBox.propTypes = { + disabled: PropTypes.bool.isRequired, + onPress: PropTypes.func.isRequired, + symptom: PropTypes.string.isRequired, + symptomData: PropTypes.object +} \ No newline at end of file diff --git a/components/cycle-day/select-box-group.js b/components/cycle-day/select-box-group.js index 3ff1f58c83332cfe712877cf23cf989b12583030..ee64d00e7547db46b4491afa79cc3a16ed82c1e4 100644 --- a/components/cycle-day/select-box-group.js +++ b/components/cycle-day/select-box-group.js @@ -1,34 +1,38 @@ -import React, { Component } from 'react' -import { - View, - TouchableOpacity, -} from 'react-native' -import styles from '../../styles' +import React from 'react' +import PropTypes from 'prop-types' +import { View, TouchableOpacity } from 'react-native' + import AppText from '../app-text' -export default class SelectBoxGroup extends Component { - render() { - return ( - <View style={styles.selectBoxSection}> - {Object.keys(this.props.labels).map(key => { - const style = [styles.selectBox] - const textStyle = [] - if (this.props.optionsState[key]) { - style.push(styles.selectBoxActive) - textStyle.push(styles.selectBoxTextActive) - } - return ( - <TouchableOpacity - onPress={() => this.props.onSelect(key)} - key={key} - > - <View style={style}> - <AppText style={textStyle}>{this.props.labels[key]}</AppText> - </View> - </TouchableOpacity> - ) - })} - </View> - ) - } -} \ No newline at end of file +import styles from '../../styles' + +export default function SelectBoxGroup({ labels, onSelect, optionsState }) { + return ( + <View style={styles.selectBoxSection}> + {Object.keys(labels).map(key => { + const style = [styles.selectBox] + const textStyle = [] + if (optionsState[key]) { + style.push(styles.selectBoxActive) + textStyle.push(styles.selectBoxTextActive) + } + return ( + <TouchableOpacity + onPress={() => onSelect(key)} + key={key} + > + <View style={style}> + <AppText style={textStyle}>{labels[key]}</AppText> + </View> + </TouchableOpacity> + ) + })} + </View> + ) +} + +SelectBoxGroup.propTypes = { + labels: PropTypes.object.isRequired, + onSelect: PropTypes.func.isRequired, + optionsState: PropTypes.object.isRequired +} diff --git a/components/cycle-day/select-tab-group.js b/components/cycle-day/select-tab-group.js index 63c05368843ea9efe9d9e563093b5e3b879024fa..a8fffc64202e633458440825d7647c96f2138045 100644 --- a/components/cycle-day/select-tab-group.js +++ b/components/cycle-day/select-tab-group.js @@ -1,47 +1,50 @@ -import React, { Component } from 'react' -import { - View, - TouchableOpacity, -} from 'react-native' -import styles from '../../styles' +import React from 'react' +import PropTypes from 'prop-types' +import { View, TouchableOpacity } from 'react-native' + import AppText from '../app-text' -export default class SelectTabGroup extends Component { - render() { - const { buttons, onSelect } = this.props - return ( - <View style={styles.selectTabGroup}> - { - buttons.map(({ label, value }, i) => { - let firstOrLastStyle - if (i === buttons.length - 1) { - firstOrLastStyle = styles.selectTabLast - } else if (i === 0) { - firstOrLastStyle = styles.selectTabFirst - } - let activeStyle - const isActive = value === this.props.active - if (isActive) activeStyle = styles.selectTabActive - return ( - <TouchableOpacity - onPress={() => onSelect(isActive ? null : value)} - key={i} - activeOpacity={1} - > - <View> - <View style={[ - styles.selectTab, - firstOrLastStyle, - activeStyle - ]}> - <AppText style={activeStyle}>{label}</AppText> - </View> +import styles from '../../styles' + +export default function SelectTabGroup({ active, buttons, onSelect }) { + return ( + <View style={styles.selectTabGroup}> + { + buttons.map(({ label, value }, i) => { + let firstOrLastStyle + if (i === buttons.length - 1) { + firstOrLastStyle = styles.selectTabLast + } else if (i === 0) { + firstOrLastStyle = styles.selectTabFirst + } + let activeStyle + const isActive = value === active + if (isActive) activeStyle = styles.selectTabActive + return ( + <TouchableOpacity + onPress={() => onSelect(isActive ? null : value)} + key={i} + activeOpacity={1} + > + <View> + <View style={[ + styles.selectTab, + firstOrLastStyle, + activeStyle + ]}> + <AppText style={activeStyle}>{label}</AppText> </View> - </TouchableOpacity> - ) - }) - } - </View> - ) - } + </View> + </TouchableOpacity> + ) + }) + } + </View> + ) +} + +SelectTabGroup.propTypes = { + active: PropTypes.number, + buttons: PropTypes.array.isRequired, + onSelect: PropTypes.func.isRequired } \ No newline at end of file diff --git a/components/cycle-day/symptoms/desire.js b/components/cycle-day/symptoms/desire.js index 189836694f8a9850e419c0ec4b7aad9bb11bfa4a..de05f5296a20a1e2f4849f764e7acc2d0e77f7d4 100644 --- a/components/cycle-day/symptoms/desire.js +++ b/components/cycle-day/symptoms/desire.js @@ -21,7 +21,7 @@ class Desire extends Component { const symptom = 'desire' const { cycleDay } = props - const defaultSymptomData = { value: '' } + const defaultSymptomData = { value: null } const symptomData = cycleDay && cycleDay[symptom] ? cycleDay[symptom] : defaultSymptomData diff --git a/components/cycle-day/symptoms/info-symptom.js b/components/cycle-day/symptoms/info-symptom.js index 887b22910b8dc541452a5a743c44a3cda20a9ea3..93820e2e328b41a06c909b3b6e7831fa579f0c1a 100644 --- a/components/cycle-day/symptoms/info-symptom.js +++ b/components/cycle-day/symptoms/info-symptom.js @@ -1,22 +1,28 @@ import React from 'react' +import PropTypes from 'prop-types' import { ScrollView, View, TouchableOpacity } from 'react-native' import Icon from 'react-native-vector-icons/SimpleLineIcons' import AppText from '../../app-text' import labels from '../../../i18n/en/symptom-info.js' import styles, {iconStyles} from '../../../styles/index' -export default function InfoSymptom(props) { +export default function InfoSymptom({ close, symptom }) { return ( <View style={styles.infoPopUpWrapper}> <View style={styles.dimmed}></View> <View style={styles.infoPopUp} testID="symptomInfoPopup"> - <TouchableOpacity onPress={props.close} style={styles.infoSymptomClose}> + <TouchableOpacity onPress={close} style={styles.infoSymptomClose}> <Icon name='close' {...iconStyles.infoPopUpClose}/> </TouchableOpacity> <ScrollView style={styles.infoSymptomText}> - <AppText>{labels[props.symptom].text}</AppText> + <AppText>{labels[symptom].text}</AppText> </ScrollView> </View> </View> ) } + +InfoSymptom.propTypes = { + close: PropTypes.func.isRequired, + symptom: PropTypes.string.isRequired +} diff --git a/components/cycle-day/symptoms/note.js b/components/cycle-day/symptoms/note.js index 17cfef17169cebb709bec93766f24f1fce9ee249..4dd78666fddaafaa6dc1bae0d31b9b3fddd458dc 100644 --- a/components/cycle-day/symptoms/note.js +++ b/components/cycle-day/symptoms/note.js @@ -1,4 +1,5 @@ import React, { Component } from 'react' +import PropTypes from 'prop-types' import { TextInput } from 'react-native' import SymptomSection from './symptom-section' @@ -9,6 +10,11 @@ import SymptomView from './symptom-view' import { saveSymptom } from '../../../db' class Note extends Component { + static propTypes = { + cycleDay: PropTypes.object.isRequired, + date: PropTypes.string.isRequired + } + constructor(props) { super(props) const symptom = 'note' @@ -41,16 +47,12 @@ class Note extends Component { values={this.state} date={this.props.date} > - <SymptomSection - explainer={noteExplainer} - > + <SymptomSection explainer={noteExplainer} > <TextInput autoFocus={true} multiline={true} placeholder={sharedLabels.enter} - onChangeText={(val) => { - this.setState({ value: val }) - }} + onChangeText={(val) => { this.setState({ value: val })}} value={this.state.value} testID='noteInput' /> diff --git a/components/cycle-day/symptoms/symptom-section.js b/components/cycle-day/symptoms/symptom-section.js index 0728454b3864d7a37fbf88af87ccacb902445ddc..92192dfaf2a5d253aaa8585475a4bf561e7d472b 100644 --- a/components/cycle-day/symptoms/symptom-section.js +++ b/components/cycle-day/symptoms/symptom-section.js @@ -1,6 +1,6 @@ import React, { Component } from 'react' import { View } from 'react-native' -import AppText, { SymptomSectionHeader } from '../../app-text' +import AppText from '../../app-text' import styles from '../../../styles' export default class SymptomSection extends Component { @@ -16,7 +16,7 @@ export default class SymptomSection extends Component { return ( <View style={[placeHeadingInline, styles.symptomSection]}> { p.header && - <SymptomSectionHeader flex={1}>{p.header}</SymptomSectionHeader> + <AppText style={styles.symptomViewHeading}>{p.header}</AppText> } <View flexDirection={p.inline ? 'row' : null} diff --git a/components/cycle-day/symptoms/symptom-view.js b/components/cycle-day/symptoms/symptom-view.js index 82bb86bf9fb16922fd97824fa278b36805c8ec60..a02ca83f5120bed3b9ede542f802b74d67f3d562 100644 --- a/components/cycle-day/symptoms/symptom-view.js +++ b/components/cycle-day/symptoms/symptom-view.js @@ -77,15 +77,16 @@ class SymptomView extends Component { render() { const { symptom, date, goBack } = this.props + const { shouldShowDelete } = this.state + const handleDelete = shouldShowDelete ? this.showConfirmationAlert : null + return ( <View style={{flex: 1}}> <Header title={headerTitles[symptom]} subtitle={formatDate(date)} handleBack={goBack} - handleDelete={ - this.state.shouldShowDelete && this.showConfirmationAlert - } + handleDelete={handleDelete} /> <View flex={1}> <ScrollView style={styles.page}> diff --git a/components/cycle-day/symptoms/temperature-input.js b/components/cycle-day/symptoms/temperature-input.js index 2bcc39e5467794bc065dacb87d2f01ecdd3a9778..cc0dbd90be1844b37ad128275169d934e7c3323e 100644 --- a/components/cycle-day/symptoms/temperature-input.js +++ b/components/cycle-day/symptoms/temperature-input.js @@ -102,3 +102,7 @@ const OutOfRangeWarning = ({ temperature }) => { return <AppText style={styles.hint}>{warningMsg}</AppText> } + +OutOfRangeWarning.propTypes = { + temperature: PropTypes.string.isRequired +} diff --git a/components/framed-segment.js b/components/framed-segment.js index 800c564749646efb2831509f6e3c3df93d73d508..49bce23203045b476de0e3351721723bc574f6c9 100644 --- a/components/framed-segment.js +++ b/components/framed-segment.js @@ -5,21 +5,24 @@ import { View } from 'react-native' import AppText from './app-text' import styles from '../styles' -const FramedSegment = ({children, ...props}) => { - const style = [styles.framedSegment, props.style] - if (props.last) style.push(styles.framedSegmentLast) +const FramedSegment = ({ children, last, style, title }) => { + const viewStyle = [styles.framedSegment, style] + if (last) viewStyle.push(styles.framedSegmentLast) return ( - <View style={[style]}> - { - props.title - && <AppText style={styles.framedSegmentTitle}>{props.title}</AppText> - } + <View style={[viewStyle]}> + {title && <AppText style={styles.framedSegmentTitle}>{title}</AppText>} {children} </View> ) } FramedSegment.propTypes = { + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node + ]), + last: PropTypes.bool, + style: PropTypes.object, title: PropTypes.string } diff --git a/components/header/index.js b/components/header/index.js index d96856ac28abeb177e0f25be55ea3ff7a0d7fbff..885eec3631d21bd2dea1591f0ddb6f6681bf3a57 100644 --- a/components/header/index.js +++ b/components/header/index.js @@ -29,7 +29,8 @@ export default function Header({ Header.propTypes = { handleBack: PropTypes.func, + handleDelete: PropTypes.func, handleNext: PropTypes.func, - title: PropTypes.string, subtitle: PropTypes.string, + title: PropTypes.string.isRequired } diff --git a/components/license.js b/components/license.js index 5a95ad1407856502ac9153edf9980dbf55c64276..b433063f079072b43dea99929309de2bd5dcd122 100644 --- a/components/license.js +++ b/components/license.js @@ -1,4 +1,5 @@ import React from 'react' +import PropTypes from 'prop-types' import { ScrollView, View, BackHandler } from 'react-native' import AppText from './app-text' import { shared } from '../i18n/en/labels' @@ -36,4 +37,8 @@ export default function License({setLicense}) { </View> </ScrollView> ) -} \ No newline at end of file +} + +License.propTypes = { + setLicense: PropTypes.func.isRequired +} diff --git a/components/link.js b/components/link.js index d0b9a8354c07677083f99f193aca751229899e6f..caea7925a99af1491a5233b905bf33584e1eb3be 100644 --- a/components/link.js +++ b/components/link.js @@ -1,4 +1,5 @@ import React from 'react' +import PropTypes from 'prop-types' import Hyperlink from 'react-native-hyperlink' import styles from '../styles' import links from '../i18n/en/links' @@ -15,6 +16,13 @@ export default function Link(props) { ) } +Link.propTypes = { + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node + ]) +} + function replaceUrlWithText(url) { const link = Object.values(links).find(l => l.url === url) return (link && link.text) || url diff --git a/components/menu/menu-item.js b/components/menu/menu-item.js index cf59c0e32acdd08803ea18ad6837d6f818507d13..8dc1bcdc689821e6567dca1cb7529e3c2b50158f 100644 --- a/components/menu/menu-item.js +++ b/components/menu/menu-item.js @@ -1,4 +1,5 @@ import React from 'react' +import PropTypes from 'prop-types' import { Text, TouchableOpacity } from 'react-native' import styles, { iconStyles, secondaryColor } from '../../styles' @@ -11,13 +12,11 @@ const menuTitlesLowerCase = Object.keys(menuTitles).reduce((acc, curr) => { return acc }, {}) -const MenuItem = ({ icon, label, active, onPress }) => { +export default function MenuItem({ active, icon, label, onPress }) { const styleActive = active ? { color: secondaryColor } : null + return ( - <TouchableOpacity - style={styles.menuItem} - onPress={onPress} - > + <TouchableOpacity style={styles.menuItem} onPress={onPress} > <Icon name={icon} {...iconStyles.menuIcon} {...styleActive} /> <Text testID={active ? 'activeMenuItem' : `menuItem${label}`} @@ -29,4 +28,9 @@ const MenuItem = ({ icon, label, active, onPress }) => { ) } -export default MenuItem \ No newline at end of file +MenuItem.propTypes = { + active: PropTypes.bool, + icon: PropTypes.string.isRequired, + label: PropTypes.string.isRequired, + onPress: PropTypes.func.isRequired +} \ No newline at end of file diff --git a/components/password-prompt.js b/components/password-prompt.js index 356a699aea564ba77293712d489f3a161e8ab7a8..b2b7af4d0a7e4f75c9eed0a4062caa4f8b18cc27 100644 --- a/components/password-prompt.js +++ b/components/password-prompt.js @@ -1,4 +1,5 @@ import React, { Component } from 'react' +import PropTypes from 'prop-types' import { View, TextInput, TouchableOpacity, Alert } from 'react-native' import nodejs from 'nodejs-mobile-react-native' import { saveEncryptionFlag } from '../local-storage' @@ -9,6 +10,10 @@ import { passwordPrompt as labels, shared, menuTitles } from '../i18n/en/labels' import { requestHash, deleteDbAndOpenNew, openDb } from '../db' export default class PasswordPrompt extends Component { + static propTypes = { + enableShowApp: PropTypes.func.isRequired + } + constructor(props) { super(props) this.state = { diff --git a/components/settings/settings-menu.js b/components/settings/settings-menu.js index a622a1d69388fc717d3e767e6ce61d4b3e4846c2..f6b6bc2f115e711e2e5e901c189c773a8a51246d 100644 --- a/components/settings/settings-menu.js +++ b/components/settings/settings-menu.js @@ -1,4 +1,5 @@ import React from 'react' +import PropTypes from 'prop-types' import { TouchableOpacity, ScrollView } from 'react-native' import { connect } from 'react-redux' @@ -21,7 +22,7 @@ const menu = [ {title: labels.license, component: 'License'} ] -const SettingsMenu = (props) => { +const SettingsMenu = ({ navigate }) => { return ( <ScrollView> { menu.map(menuItem)} @@ -33,7 +34,7 @@ const SettingsMenu = (props) => { <TouchableOpacity style={styles.framedSegment} key={item.title} - onPress={() => props.navigate(item.component)} + onPress={() => navigate(item.component)} > <AppText>{item.title.toLowerCase()}</AppText> </TouchableOpacity> @@ -41,6 +42,10 @@ const SettingsMenu = (props) => { } } +SettingsMenu.propTypes = { + navigate: PropTypes.func.isRequired +} + const mapDispatchToProps = (dispatch) => { return({ navigate: (page) => dispatch(navigate(page)), diff --git a/components/settings/shared/settings-button.js b/components/settings/shared/settings-button.js index 00bc8ed51ac5edcc935806d27542c53994354ac8..94aa2104207914c338bb8044d21bcc9fe943c642 100644 --- a/components/settings/shared/settings-button.js +++ b/components/settings/shared/settings-button.js @@ -28,8 +28,11 @@ const SettingsButton = ({ children, style, secondary, ...props }) => { } SettingsButton.propTypes = { + children: PropTypes.node, + disabled: PropTypes.bool, onPress: PropTypes.func.isRequired, - disabled: PropTypes.bool + secondary: PropTypes.bool, + style: PropTypes.object } export default SettingsButton \ No newline at end of file diff --git a/styles/index.js b/styles/index.js index 1b9bb4f8ed06d27568d7cefadd2d6a80563b0ccb..e54b8bbe9e85658827d23410cbdc7096726ccdbc 100644 --- a/styles/index.js +++ b/styles/index.js @@ -157,7 +157,8 @@ export default StyleSheet.create({ }, symptomViewHeading: { fontWeight: 'bold', - fontFamily: textFontBold + fontFamily: textFontBold, + flex: 1 }, symptomSection: { marginBottom: 10