diff --git a/components/app.js b/components/app.js index 178214c..fd9b61b 100644 --- a/components/app.js +++ b/components/app.js @@ -125,19 +125,12 @@ export default class App extends Component { goBack={this.handleBackButtonPress} /> } - {this.isSymptomView() && -
this.navigate(INFO_SYMPTOM_PAGE, { - symptomView: currentPage, - ...currentProps - })} - />} - + {!this.isSymptomView() && diff --git a/components/cycle-day/symptoms/action-button-footer.js b/components/cycle-day/symptoms/action-button-footer.js index 28b78fb..37526f3 100644 --- a/components/cycle-day/symptoms/action-button-footer.js +++ b/components/cycle-day/symptoms/action-button-footer.js @@ -1,7 +1,6 @@ import React, { Component } from 'react' import { - View, TouchableOpacity, Text, Alert, ToastAndroid -} from 'react-native' + View, TouchableOpacity, Text, Alert} from 'react-native' import Icon from 'react-native-vector-icons/MaterialCommunityIcons' import { saveSymptom } from '../../../db' import styles, {iconStyles} from '../../../styles' @@ -14,10 +13,8 @@ export default class ActionButtonFooter extends Component { symptom, currentSymptomValue, date, - saveAction, - saveDisabled, navigate, - autoShowDayView = true} + } = this.props const navigateToOverView = () => navigate('CycleDay', {date}) const buttons = [ @@ -44,43 +41,19 @@ export default class ActionButtonFooter extends Component { (Object.values(currentSymptomValue).every(x => !x) && currentSymptomValue.constructor === Object) ), icon: 'delete-outline' - }, { - title: labels.save, - action: () => { - if(saveDisabled) { - ToastAndroid.show(labels.disabledInfo, ToastAndroid.LONG) - } else { - saveAction() - if (autoShowDayView) navigateToOverView() - } - - }, - disabledCondition: saveDisabled, - icon: 'content-save-outline' } ] return ( - - {buttons.map(({ title, action, disabledCondition, icon }, i) => { + + {buttons.map(({ title, action, icon }, i) => { const textStyle = [styles.menuText] - if (disabledCondition) { - textStyle.push(styles.menuTextInActive) - } - const iconStyle = disabledCondition ? - Object.assign( - {}, - iconStyles.menuIcon, - iconStyles.menuIconInactive - ) - : - iconStyles.menuIcon return ( - + {title.toLowerCase()} diff --git a/components/cycle-day/symptoms/bleeding.js b/components/cycle-day/symptoms/bleeding.js index 3f7df98..9d94a03 100644 --- a/components/cycle-day/symptoms/bleeding.js +++ b/components/cycle-day/symptoms/bleeding.js @@ -1,29 +1,39 @@ -import React, { Component } from 'react' +import React from 'react' import { - View, Switch, ScrollView } from 'react-native' import styles from '../../../styles' -import { saveSymptom } from '../../../db' import { bleeding } from '../../../i18n/en/cycle-day' -import ActionButtonFooter from './action-button-footer' import SelectTabGroup from '../select-tab-group' import SymptomSection from './symptom-section' +import SymptomView from './symptom-view' -export default class Bleeding extends Component { +export default class Bleeding extends SymptomView { constructor(props) { super(props) const cycleDay = props.cycleDay this.bleeding = cycleDay && cycleDay.bleeding - this.makeActionButtons = props.makeActionButtons this.state = { currentValue: this.bleeding && this.bleeding.value, exclude: this.bleeding ? this.bleeding.exclude : false } } - render() { + symptomName = 'bleeding' + + onBackButtonPress() { + if (typeof this.state.currentValue != 'number') { + this.deleteSymptomEntry() + return + } + this.saveSymptomEntry({ + value: this.state.currentValue, + exclude: this.state.exclude + }) + } + + renderContent() { const bleedingRadioProps = [ { label: bleeding.labels[0], value: 0 }, { label: bleeding.labels[1], value: 1 }, @@ -31,45 +41,30 @@ export default class Bleeding extends Component { { label: bleeding.labels[3], value: 3 }, ] return ( - - - - this.setState({ currentValue: val })} - /> - - - { - this.setState({ exclude: val }) - }} - value={this.state.exclude} - /> - - - { - saveSymptom('bleeding', this.props.date, { - value: this.state.currentValue, - exclude: this.state.exclude - }) - }} - saveDisabled={typeof this.state.currentValue != 'number'} - navigate={this.props.navigate} - /> - + + + this.setState({ currentValue: val })} + /> + + + { + this.setState({ exclude: val }) + }} + value={this.state.exclude} + /> + + ) } } \ No newline at end of file diff --git a/components/cycle-day/symptoms/cervix.js b/components/cycle-day/symptoms/cervix.js index d0e3e07..f58ebf2 100644 --- a/components/cycle-day/symptoms/cervix.js +++ b/components/cycle-day/symptoms/cervix.js @@ -1,27 +1,40 @@ -import React, { Component } from 'react' +import React from 'react' import { - View, Switch, ScrollView } from 'react-native' import styles from '../../../styles' -import { saveSymptom } from '../../../db' import { cervix as labels } from '../../../i18n/en/cycle-day' -import ActionButtonFooter from './action-button-footer' import SelectTabGroup from '../select-tab-group' import SymptomSection from './symptom-section' -import { ActionHint } from '../../app-text' +import SymptomView from './symptom-view' -export default class Cervix extends Component { +export default class Cervix extends SymptomView { constructor(props) { super(props) const cycleDay = props.cycleDay this.cervix = cycleDay && cycleDay.cervix - this.makeActionButtons = props.makeActionButtons this.state = this.cervix ? this.cervix : {} } - render() { + symptomName = 'cervix' + + onBackButtonPress() { + const nothingEntered = ['opening', 'firmness', 'position'].every(val => typeof this.state[val] != 'number') + if (nothingEntered) { + this.deleteSymptomEntry() + return + } + + this.saveSymptomEntry({ + opening: this.state.opening, + firmness: this.state.firmness, + position: this.state.position, + exclude: Boolean(this.state.exclude) + }) + } + + renderContent() { const cervixOpeningRadioProps = [ { label: labels.opening.categories[0], value: 0 }, { label: labels.opening.categories[1], value: 1 }, @@ -36,70 +49,53 @@ export default class Cervix extends Component { { label: labels.position.categories[1], value: 1 }, { label: labels.position.categories[2], value: 2 } ] - const mandatoryNotCompletedYet = typeof this.state.opening != 'number' || typeof this.state.firmness != 'number' + // TODO saving this info for notice when leaving incomplete data + // const mandatoryNotCompleted = typeof this.state.opening != 'number' || typeof this.state.firmness != 'number' return ( - - - - this.setState({ opening: val })} - /> - - - this.setState({ firmness: val })} - /> - - - this.setState({ position: val })} - /> - - - { - this.setState({ exclude: val }) - }} - value={this.state.exclude} - /> - - - {labels.actionHint} - { - saveSymptom('cervix', this.props.date, { - opening: this.state.opening, - firmness: this.state.firmness, - position: this.state.position, - exclude: Boolean(this.state.exclude) - }) - }} - saveDisabled={mandatoryNotCompletedYet} - navigate={this.props.navigate} - /> - + + + this.setState({ opening: val })} + /> + + + this.setState({ firmness: val })} + /> + + + this.setState({ position: val })} + /> + + + { + this.setState({ exclude: val }) + }} + value={this.state.exclude} + /> + + ) } } diff --git a/components/cycle-day/symptoms/desire.js b/components/cycle-day/symptoms/desire.js index cc3b536..5ff9fad 100644 --- a/components/cycle-day/symptoms/desire.js +++ b/components/cycle-day/symptoms/desire.js @@ -1,56 +1,51 @@ -import React, { Component } from 'react' +import React from 'react' import { - View, ScrollView } from 'react-native' import styles from '../../../styles' -import { saveSymptom } from '../../../db' import { intensity, desire } from '../../../i18n/en/cycle-day' -import ActionButtonFooter from './action-button-footer' import SelectTabGroup from '../select-tab-group' import SymptomSection from './symptom-section' +import SymptomView from './symptom-view' -export default class Desire extends Component { +export default class Desire extends SymptomView { constructor(props) { super(props) const cycleDay = props.cycleDay this.desire = cycleDay && cycleDay.desire - this.makeActionButtons = props.makeActionButtons const desireValue = this.desire && this.desire.value this.state = { currentValue: desireValue } } - render() { + symptomName = 'desire' + + onBackButtonPress() { + if (typeof this.state.currentValue != 'number') { + this.deleteSymptomEntry() + return + } + this.saveSymptomEntry({ value: this.state.currentValue }) + } + + renderContent() { const desireRadioProps = [ { label: intensity[0], value: 0 }, { label: intensity[1], value: 1 }, { label: intensity[2], value: 2 } ] return ( - - - - this.setState({ currentValue: val })} - /> - - - { - saveSymptom('desire', this.props.date, { value: this.state.currentValue }) - }} - saveDisabled={typeof this.state.currentValue != 'number'} - navigate={this.props.navigate} - /> - + + + this.setState({ currentValue: val })} + /> + + ) } } diff --git a/components/cycle-day/symptoms/mood.js b/components/cycle-day/symptoms/mood.js index 903d5d9..09f8fbc 100644 --- a/components/cycle-day/symptoms/mood.js +++ b/components/cycle-day/symptoms/mood.js @@ -1,17 +1,14 @@ -import React, { Component } from 'react' +import React from 'react' import { ScrollView, - TextInput, - View -} from 'react-native' -import { saveSymptom } from '../../../db' + TextInput} from 'react-native' import { mood as labels } from '../../../i18n/en/cycle-day' -import ActionButtonFooter from './action-button-footer' import SelectBoxGroup from '../select-box-group' import SymptomSection from './symptom-section' import styles from '../../../styles' +import SymptomView from './symptom-view' -export default class Mood extends Component { +export default class Mood extends SymptomView { constructor(props) { super(props) const cycleDay = props.cycleDay @@ -25,6 +22,21 @@ export default class Mood extends Component { } } + symptomName = "mood" + + onBackButtonPress() { + const nothingEntered = Object.values(this.state).every(val => !val) + if (nothingEntered) { + this.deleteSymptomEntry() + return + } + const copyOfState = Object.assign({}, this.state) + if (!copyOfState.other) { + copyOfState.note = null + } + this.saveSymptomEntry(copyOfState) + } + toggleState = (key) => { const curr = this.state[key] this.setState({[key]: !curr}) @@ -33,19 +45,18 @@ export default class Mood extends Component { } } - render() { + renderContent() { return ( - - - - - { this.state.other && + + + + { this.state.other && - } - - - { - const copyOfState = Object.assign({}, this.state) - if (!copyOfState.other) { - copyOfState.note = null - } - saveSymptom('mood', this.props.date, copyOfState) - }} - saveDisabled={Object.values(this.state).every(value => !value)} - navigate={this.props.navigate} - /> - + } + + ) } } diff --git a/components/cycle-day/symptoms/mucus.js b/components/cycle-day/symptoms/mucus.js index 6e2d2ce..2d7b9d1 100644 --- a/components/cycle-day/symptoms/mucus.js +++ b/components/cycle-day/symptoms/mucus.js @@ -1,28 +1,43 @@ -import React, { Component } from 'react' +import React from 'react' import { - View, Switch, ScrollView } from 'react-native' import styles from '../../../styles' -import { saveSymptom } from '../../../db' import { mucus as labels } from '../../../i18n/en/cycle-day' import computeNfpValue from '../../../lib/nfp-mucus' -import ActionButtonFooter from './action-button-footer' import SelectTabGroup from '../select-tab-group' import SymptomSection from './symptom-section' -import { ActionHint } from '../../app-text' +import SymptomView from './symptom-view' -export default class Mucus extends Component { +export default class Mucus extends SymptomView { constructor(props) { super(props) const cycleDay = props.cycleDay this.mucus = cycleDay && cycleDay.mucus - this.makeActionButtons = props.makeActionButtons this.state = this.mucus ? this.mucus : {} } - render() { + symptomName = 'mucus' + + onBackButtonPress() { + const nothingEntered = ['feeling', 'texture'].every(val => typeof this.state[val] != 'number') + if (nothingEntered) { + this.deleteSymptomEntry() + return + } + + const feeling = this.state.feeling + const texture = this.state.texture + this.saveSymptomEntry({ + feeling, + texture, + value: computeNfpValue(feeling, texture), + exclude: Boolean(this.state.exclude) + }) + } + + renderContent() { const mucusFeeling = [ { label: labels.feeling.categories[0], value: 0 }, { label: labels.feeling.categories[1], value: 1 }, @@ -34,62 +49,43 @@ export default class Mucus extends Component { { label: labels.texture.categories[1], value: 1 }, { label: labels.texture.categories[2], value: 2 } ] - const mandatoryNotCompletedYet = typeof this.state.feeling != 'number' || typeof this.state.texture != 'number' + // TODO leaving this info for notice when leaving incomplete data + // const mandatoryNotCompletedYet = typeof this.state.feeling != 'number' || typeof this.state.texture != 'number' return ( - - - - this.setState({ feeling: val })} - active={this.state.feeling} - /> - - - this.setState({ texture: val })} - active={this.state.texture} - /> - - - { - this.setState({ exclude: val }) - }} - value={this.state.exclude} - /> - - - {labels.actionHint} - { - const feeling = this.state.feeling - const texture = this.state.texture - saveSymptom('mucus', this.props.date, { - feeling, - texture, - value: computeNfpValue(feeling, texture), - exclude: Boolean(this.state.exclude) - }) - }} - saveDisabled={mandatoryNotCompletedYet} - navigate={this.props.navigate} - /> - + + + this.setState({ feeling: val })} + active={this.state.feeling} + /> + + + this.setState({ texture: val })} + active={this.state.texture} + /> + + + { + this.setState({ exclude: val }) + }} + value={this.state.exclude} + /> + + ) } } diff --git a/components/cycle-day/symptoms/note.js b/components/cycle-day/symptoms/note.js index 491061b..c2bed81 100644 --- a/components/cycle-day/symptoms/note.js +++ b/components/cycle-day/symptoms/note.js @@ -1,60 +1,55 @@ -import React, { Component } from 'react' +import React from 'react' import { - View, ScrollView, TextInput, } from 'react-native' import styles from '../../../styles' -import { saveSymptom } from '../../../db' -import ActionButtonFooter from './action-button-footer' import SymptomSection from './symptom-section' import { noteExplainer } from '../../../i18n/en/cycle-day' import { shared as sharedLabels } from '../../../i18n/en/labels' +import SymptomView from './symptom-view' -export default class Note extends Component { +export default class Note extends SymptomView { constructor(props) { super(props) const cycleDay = props.cycleDay this.note = cycleDay && cycleDay.note - this.makeActionButtons = props.makeActionButtons this.state = { currentValue: this.note && this.note.value || '' } } - render() { + symptomName = 'note' + + onBackButtonPress() { + if (!this.state.currentValue) { + this.deleteSymptomEntry() + return + } + this.saveSymptomEntry({ + value: this.state.currentValue + }) + } + + renderContent() { return ( - - - - { - this.setState({ currentValue: val }) - }} - value={this.state.currentValue} - /> - - - { - saveSymptom('note', this.props.date, { - value: this.state.currentValue - }) - }} - saveDisabled={!this.state.currentValue} - navigate={this.props.navigate} - /> - + + + { + this.setState({ currentValue: val }) + }} + value={this.state.currentValue} + /> + + ) } } diff --git a/components/cycle-day/symptoms/pain.js b/components/cycle-day/symptoms/pain.js index 7a2d9e3..30ac355 100644 --- a/components/cycle-day/symptoms/pain.js +++ b/components/cycle-day/symptoms/pain.js @@ -1,18 +1,16 @@ -import React, { Component } from 'react' +import React from 'react' import { ScrollView, TextInput, - View } from 'react-native' -import { saveSymptom } from '../../../db' import { pain as labels } from '../../../i18n/en/cycle-day' import { shared as sharedLabels } from '../../../i18n/en/labels' -import ActionButtonFooter from './action-button-footer' import SelectBoxGroup from '../select-box-group' import SymptomSection from './symptom-section' import styles from '../../../styles' +import SymptomView from './symptom-view' -export default class Pain extends Component { +export default class Pain extends SymptomView { constructor(props) { super(props) const cycleDay = props.cycleDay @@ -26,6 +24,22 @@ export default class Pain extends Component { } } + symptomName = 'pain' + + onBackButtonPress() { + const nothingEntered = Object.values(this.state).every(val => !val) + if (nothingEntered) { + this.deleteSymptomEntry() + return + } + + const copyOfState = Object.assign({}, this.state) + if (!copyOfState.other) { + copyOfState.note = null + } + this.saveSymptomEntry(copyOfState) + } + toggleState = (key) => { const curr = this.state[key] this.setState({[key]: !curr}) @@ -34,19 +48,18 @@ export default class Pain extends Component { } } - render() { + renderContent() { return ( - - - - - { this.state.other && + + + + { this.state.other && - } - - - { - const copyOfState = Object.assign({}, this.state) - if (!copyOfState.other) { - copyOfState.note = null - } - saveSymptom('pain', this.props.date, copyOfState) - }} - saveDisabled={Object.values(this.state).every(value => !value)} - navigate={this.props.navigate} - /> - - ) + } + + ) } } diff --git a/components/cycle-day/symptoms/sex.js b/components/cycle-day/symptoms/sex.js index 0e5649b..9b195da 100644 --- a/components/cycle-day/symptoms/sex.js +++ b/components/cycle-day/symptoms/sex.js @@ -1,18 +1,16 @@ -import React, { Component } from 'react' +import React from 'react' import { TextInput, - View, ScrollView } from 'react-native' import styles from '../../../styles' -import { saveSymptom } from '../../../db' import { sex as sexLabels, contraceptives as contraceptivesLabels } from '../../../i18n/en/cycle-day' import { shared as sharedLabels } from '../../../i18n/en/labels' -import ActionButtonFooter from './action-button-footer' import SelectBoxGroup from '../select-box-group' import SymptomSection from './symptom-section' +import SymptomView from './symptom-view' -export default class Sex extends Component { +export default class Sex extends SymptomView { constructor(props) { super(props) const cycleDay = props.cycleDay @@ -26,6 +24,22 @@ export default class Sex extends Component { if (this.state.note) this.state.other = true } + symptomName = "sex" + + onBackButtonPress() { + const nothingEntered = Object.values(this.state).every(val => !val) + if (nothingEntered) { + this.deleteSymptomEntry() + return + } + + const copyOfState = Object.assign({}, this.state) + if (!copyOfState.other) { + copyOfState.note = null + } + this.saveSymptomEntry(copyOfState) + } + toggleState = (key) => { const curr = this.state[key] this.setState({[key]: !curr}) @@ -34,32 +48,31 @@ export default class Sex extends Component { } } - render() { + renderContent() { return ( - - - - - - - - + + + + + + + - {this.state.other && + {this.state.other && - } - - { - const copyOfState = Object.assign({}, this.state) - if (!copyOfState.other) { - copyOfState.note = null - } - saveSymptom('sex', this.props.date, copyOfState) - }} - saveDisabled={Object.values(this.state).every(value => !value)} - navigate={this.props.navigate} - /> - + } + ) } } diff --git a/components/cycle-day/symptoms/symptom-view.js b/components/cycle-day/symptoms/symptom-view.js new file mode 100644 index 0000000..6a805c8 --- /dev/null +++ b/components/cycle-day/symptoms/symptom-view.js @@ -0,0 +1,47 @@ +import React, { Component } from 'react' +import { BackHandler, View } from 'react-native' +import { saveSymptom } from '../../../db' +import Header from '../../header/symptom-view' +import { headerTitles } from '../../../i18n/en/labels' + +export default class SymptomView extends Component { + constructor(props) { + super() + // every specific symptom view provides their own onBackButtonPress method + this.backHandler = BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPress.bind(this)) + this.globalBackhandler = props.handleBackButtonPress + this.date = props.date + } + + saveSymptomEntry(entry) { + saveSymptom(this.symptomName, this.date, entry) + } + + deleteSymptomEntry() { + saveSymptom(this.symptomName, this.date) + } + + componentWillUnmount() { + this.backHandler.remove() + } + + render() { + return ( + +
{ + this.onBackButtonPress() + this.globalBackhandler() + }} + deleteEntry={() => { + this.deleteSymptomEntry() + this.globalBackhandler() + }} + /> + {this.renderContent()} + + ) + } +} \ No newline at end of file diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index 6ebada9..d053957 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -1,4 +1,4 @@ -import React, { Component } from 'react' +import React from 'react' import { View, Switch, @@ -9,21 +9,21 @@ import { import DateTimePicker from 'react-native-modal-datetime-picker-nevo' import padWithZeros from '../../helpers/pad-time-with-zeros' -import { getPreviousTemperature, saveSymptom } from '../../../db' +import { getPreviousTemperature } from '../../../db' import styles from '../../../styles' import { LocalTime, ChronoUnit } from 'js-joda' import { temperature as labels } from '../../../i18n/en/cycle-day' import { scaleObservable } from '../../../local-storage' import { shared as sharedLabels } from '../../../i18n/en/labels' -import ActionButtonFooter from './action-button-footer' import config from '../../../config' import AppTextInput from '../../app-text-input' import AppText from '../../app-text' import SymptomSection from './symptom-section' +import SymptomView from './symptom-view' const minutes = ChronoUnit.MINUTES -export default class Temp extends Component { +export default class Temp extends SymptomView { constructor(props) { super(props) const cycleDay = props.cycleDay @@ -45,7 +45,7 @@ export default class Temp extends Component { this.state.temperature = `${this.state.temperature}.0` } } else { - const prevTemp = getPreviousTemperature(this.props.date) + const prevTemp = getPreviousTemperature(props.date) if (prevTemp) { this.state.temperature = prevTemp.toString() this.state.isSuggestion = true @@ -53,6 +53,17 @@ export default class Temp extends Component { } } + symptomName = 'temperature' + + onBackButtonPress() { + if (typeof this.state.temperature != 'string' || this.state.temperature === '') { + this.deleteSymptomEntry() + return + } + + this.checkRangeAndSave() + } + saveTemperature = () => { const dataToSave = { value: Number(this.state.temperature), @@ -60,8 +71,8 @@ export default class Temp extends Component { time: this.state.time, note: this.state.note } - saveSymptom('temperature', this.props.date, dataToSave) - this.props.navigate('CycleDay', {date: this.props.date}) + + this.saveSymptomEntry(dataToSave) } checkRangeAndSave = () => { @@ -105,102 +116,78 @@ export default class Temp extends Component { this.setState({ isTimePickerVisible: true }) } - render() { + renderContent() { const inputStyle = [styles.temperatureTextInput] if (this.state.isSuggestion) { inputStyle.push(styles.temperatureTextInputSuggestion) } return ( - - - - - - °C - - - - - - { - this.setState({ - time: padWithZeros(jsDate), - isTimePickerVisible: false - }) - }} - onCancel={() => this.setState({ isTimePickerVisible: false })} - /> - - - + + + - - - { - this.setState({ exclude: val }) + °C + + + + + + { + this.setState({ + time: padWithZeros(jsDate), + isTimePickerVisible: false + }) }} - value={this.state.exclude} + onCancel={() => this.setState({ isTimePickerVisible: false })} /> - - - this.checkRangeAndSave()} - saveDisabled={ - this.state.temperature === '' || - isNaN(Number(this.state.temperature)) || - isInvalidTime(this.state.time) - } - navigate={this.props.navigate} - autoShowDayView={false} - /> - + + + + + + + { + this.setState({ exclude: val }) + }} + value={this.state.exclude} + /> + + ) } } - -function isInvalidTime(timeString) { - try { - LocalTime.parse(timeString) - } catch (err) { - return true - } - return false -} \ No newline at end of file diff --git a/components/header/index.js b/components/header/index.js index 9792d03..3de4034 100644 --- a/components/header/index.js +++ b/components/header/index.js @@ -3,7 +3,6 @@ import { Dimensions } from 'react-native' import CycleDayHeader from './cycle-day' import DefaultHeader from './default' import BackButtonHeader from './back-button' -import SymptomViewHeader from './symptom-view' export default function Header(p) { const middle = Dimensions.get('window').width / 2 @@ -11,11 +10,7 @@ export default function Header(p) { if (props.isCycleDayOverView) { return () - } - else if (props.isSymptomView) { - return () - } - else if (props.showBackButton) { + } else if (props.showBackButton) { return () } else { diff --git a/components/header/symptom-view.js b/components/header/symptom-view.js index 0b4e6d1..6b6e384 100644 --- a/components/header/symptom-view.js +++ b/components/header/symptom-view.js @@ -2,7 +2,8 @@ import React from 'react' import { View, Text, - TouchableOpacity + TouchableOpacity, + Dimensions } from 'react-native' import styles, { iconStyles } from '../../styles' import FeatherIcon from 'react-native-vector-icons/Feather' @@ -10,11 +11,12 @@ import NavigationArrow from './navigation-arrow' import formatDate from '../helpers/format-date' export default function SymptomViewHeader(props) { + const middle = Dimensions.get('window').width / 2 return ( props.goToSymptomInfo()} + onPress={props.deleteEntry} style={styles.infoButton} > { + if (oldRealm.schemaVersion >= 4) return + } +} diff --git a/db/schemas/index.js b/db/schemas/index.js index ed14e67..4530908 100644 --- a/db/schemas/index.js +++ b/db/schemas/index.js @@ -2,5 +2,6 @@ import schema0 from './0.js' import schema1 from './1.js' import schema2 from './2.js' import schema3 from './3.js' +import schema4 from './4.js' -export default [schema0, schema1, schema2, schema3] \ No newline at end of file +export default [schema0, schema1, schema2, schema3, schema4] \ No newline at end of file diff --git a/i18n/en/labels.js b/i18n/en/labels.js index 9443ae3..ddae047 100644 --- a/i18n/en/labels.js +++ b/i18n/en/labels.js @@ -32,15 +32,15 @@ export const headerTitles = { Password: settingsTitles.password, About: settingsTitles.about, License: settingsTitles.license, - BleedingEditView: 'Bleeding', - TemperatureEditView: 'Temperature', - MucusEditView: 'Mucus', - CervixEditView: 'Cervix', - NoteEditView: 'Note', - DesireEditView: 'Desire', - SexEditView: 'Sex', - PainEditView: 'Pain', - MoodEditView: 'Mood', + bleeding: 'Bleeding', + temperature: 'Temperature', + mucus: 'Mucus', + cervix: 'Cervix', + note: 'Note', + desire: 'Desire', + sex: 'Sex', + pain: 'Pain', + mood: 'Mood', InfoSymptom: 'Info' } diff --git a/lib/nfp-mucus.js b/lib/nfp-mucus.js index 27e1590..1a8e8a9 100644 --- a/lib/nfp-mucus.js +++ b/lib/nfp-mucus.js @@ -1,4 +1,7 @@ export default function (feeling, texture) { + + if (typeof feeling != 'number' || typeof texture != 'number') return null + const feelingMapping = { 0: 0, 1: 1, diff --git a/lib/sympto-adapter.js b/lib/sympto-adapter.js index 2991da9..efb6288 100644 --- a/lib/sympto-adapter.js +++ b/lib/sympto-adapter.js @@ -108,7 +108,15 @@ function formatCycleForSympto(cycle) { if (day[symptomName] && day[symptomName].exclude) { delete day[symptomName] } - }); + }) + // remove days with incomplete cervix values + if (hasIncompleteCervixValue(day)) { + delete day.cervix + } + // remove days with incomplete mucus value (because nfp-mucus returns null when that's the case) + if (day.mucus && day.mucus.value === null) { + delete day.mucus + } // change format ['bleeding', 'temperature', 'mucus'].forEach(symptomName => { if (day[symptomName]) day[symptomName] = day[symptomName].value @@ -119,4 +127,8 @@ function formatCycleForSympto(cycle) { // we get earliest last, but sympto wants earliest first formatted.reverse() return formatted +} + +function hasIncompleteCervixValue(day) { + return day.cervix && (typeof day.cervix.opening != 'number' || typeof day.cervix.firmness != 'number') } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7529c9f..66701f9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3229,8 +3229,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -3248,13 +3247,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3267,18 +3264,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -3381,8 +3375,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -3392,7 +3385,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3405,20 +3397,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.3.5", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3435,7 +3424,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -3508,8 +3496,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -3519,7 +3506,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3595,8 +3581,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -3626,7 +3611,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3644,7 +3628,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3683,13 +3666,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -8097,9 +8078,9 @@ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" }, "sympto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sympto/-/sympto-1.0.1.tgz", - "integrity": "sha512-wLDpugvScuXhSBhgJHZTGU9gTd5uDnuZDJuNz7aUSj1N28VOe2RhKwMF4RLwjy3s6i+BG1Lfa3uckNPCFPkUvA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/sympto/-/sympto-1.0.4.tgz", + "integrity": "sha512-FSdSwPeE3BKvnJlPkHzVusGMTz4r6dW2eEEJbgPrgdkmPWmAFWTD7Hf7OhqQSbTLjiZY7jBeWDWuizb4UZMk1g==", "requires": { "js-joda": "^1.9.2" } diff --git a/package.json b/package.json index 5017dfd..374ce70 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "react-native-share": "^1.1.3", "react-native-vector-icons": "^5.0.0", "realm": "^2.22.0", - "sympto": "^1.0.0" + "sympto": "^1.0.4" }, "devDependencies": { "@babel/core": "^7.2.2", diff --git a/test/sensiplan-mucus.spec.js b/test/sensiplan-mucus.spec.js index accbfe3..3cdb8c1 100644 --- a/test/sensiplan-mucus.spec.js +++ b/test/sensiplan-mucus.spec.js @@ -7,6 +7,11 @@ chai.use(dirtyChai) import getSensiplanMucus from '../lib/nfp-mucus' describe('getSensiplanMucus', () => { + it('returns null if there is no value for feeling or texture', () => { + expect(getSensiplanMucus()).to.be.null() + expect(getSensiplanMucus(undefined, 3)).to.be.null() + expect(getSensiplanMucus(2, undefined)).to.be.null() + }) describe('results in t for:', () => { it('dry feeling and no texture', function () {