diff --git a/components/bleeding.js b/components/bleeding.js deleted file mode 100644 index 0472c3c73f7f4a4e2b21e236c5e93ea61fe55a1c..0000000000000000000000000000000000000000 --- a/components/bleeding.js +++ /dev/null @@ -1,102 +0,0 @@ -import React, { Component } from 'react' -import { - View, - Button, - Text, - Switch -} from 'react-native' -import RadioForm from 'react-native-simple-radio-button' -import styles from '../styles/index' -import { saveBleeding } from '../db' -import { bleeding as labels } from '../labels/labels' - -export default class Bleeding extends Component { - constructor(props) { - super(props) - this.cycleDay = props.cycleDay - this.showView = props.showView - let bleedingValue = this.cycleDay.bleeding && this.cycleDay.bleeding.value - if (! (typeof bleedingValue === 'number') ){ - bleedingValue = -1 - } - this.state = { - currentValue: bleedingValue, - exclude: this.cycleDay.bleeding ? this.cycleDay.bleeding.exclude : false - } - } - - render() { - const bleedingRadioProps = [ - {label: labels[0], value: 0 }, - {label: labels[1], value: 1 }, - {label: labels[2], value: 2 }, - {label: labels[3], value: 3 }, - ] - return ( - <View style={ styles.symptomEditView }> - <View style={ styles.symptomEditSplitSymptomsAndLastRowButtons }> - <View style={ styles.symptomEditListedSymptomView }> - <View style={{flex: 1}}> - <Text style={styles.symptomDayView}>Bleeding</Text> - </View> - <View style={{flex: 1}}> - <RadioForm - radio_props={bleedingRadioProps} - initial={this.state.currentValue} - formHorizontal={true} - labelHorizontal={false} - labelStyle={styles.radioButton} - onPress={(itemValue) => { - this.setState({currentValue: itemValue}) - }} - /> - </View> - </View> - <View style={ styles.itemsInRowSeparatedView }> - <View style={ styles.singleButtonView }> - <Text style={ styles.symptomDayView }>Exclude</Text> - </View> - <View style={ styles.singleButtonView }> - <Switch - onValueChange={(val) => { - this.setState({exclude: val}) - }} - value={this.state.exclude} - /> - </View> - </View> - </View> - <View style={ styles.itemsInRowSeparatedView }> - <View style={ styles.singleButtonView }> - <Button - onPress={() => this.showView('dayView')} - title="Cancel"> - </Button> - </View> - <View style={ styles.singleButtonView }> - <Button - onPress={() => { - saveBleeding(this.cycleDay) - this.showView('dayView') - }} - title="Delete"> - </Button> - </View> - <View style={ styles.singleButtonView }> - <Button - onPress={() => { - saveBleeding(this.cycleDay, { - value: this.state.currentValue, - exclude: this.state.exclude - }) - this.showView('dayView') - }} - disabled={ this.state.currentValue === -1 } - title="Save"> - </Button> - </View> - </View> - </View> - ) - } -} \ No newline at end of file diff --git a/components/cycle-day-overview.js b/components/cycle-day-overview.js deleted file mode 100644 index 49068fea332eb2aa53c775005442da31934e4734..0000000000000000000000000000000000000000 --- a/components/cycle-day-overview.js +++ /dev/null @@ -1,83 +0,0 @@ -import React, { Component } from 'react' -import { - View, - Button, - Text -} from 'react-native' -import styles from '../styles/index' -import { bleeding as labels} from '../labels/labels' -import cycleModule from '../lib/cycle' -import { bleedingDaysSortedByDate } from '../db' - -const getCycleDayNumber = cycleModule().getCycleDayNumber - -export default class DayView extends Component { - constructor(props) { - super(props) - this.cycleDay = props.cycleDay - this.showView = props.showView - this.state = { - cycleDayNumber: getCycleDayNumber(this.cycleDay.date), - } - - this.setStateWithCurrentCycleDayNumber = (function (DayViewComponent) { - return function () { - DayViewComponent.setState({ - cycleDayNumber: getCycleDayNumber(DayViewComponent.cycleDay.date) - }) - } - })(this) - - bleedingDaysSortedByDate.addListener(this.setStateWithCurrentCycleDayNumber) - } - - componentWillUnmount() { - bleedingDaysSortedByDate.removeListener(this.setStateWithCurrentCycleDayNumber) - } - - render() { - const bleedingValue = this.cycleDay.bleeding && this.cycleDay.bleeding.value - let bleedingLabel - if (typeof bleedingValue === 'number') { - bleedingLabel = `${labels[bleedingValue]}` - if (this.cycleDay.bleeding.exclude) bleedingLabel = "( " + bleedingLabel + " )" - } else { - bleedingLabel = 'edit' - } - const temperatureValue = this.cycleDay.temperature && this.cycleDay.temperature.value - let temperatureLabel - if (typeof temperatureValue === 'number') { - temperatureLabel = `${temperatureValue} °C` - if (this.cycleDay.temperature.exclude) temperatureLabel = "( " + temperatureLabel + " )" - } else { - temperatureLabel = 'edit' - } - - return ( - <View style={ styles.symptomEditListedSymptomView }> - <View style={ styles.itemsInRowSeparatedView }> - <View style={{flex: 1}}> - <Text style={styles.symptomDayView}>Bleeding</Text> - </View> - <View style={ styles.singleButtonView }> - <Button - onPress={() => this.showView('bleedingEditView')} - title={bleedingLabel}> - </Button> - </View> - </View> - <View style={ styles.itemsInRowSeparatedView}> - <View style={{flex: 1}}> - <Text style={styles.symptomDayView}>Temperature</Text> - </View> - <View style={ styles.singleButtonView }> - <Button - onPress={() => this.showView('temperatureEditView')} - title={temperatureLabel}> - </Button> - </View> - </View> - </View > - ) - } -} \ No newline at end of file diff --git a/components/cycle-day/action-buttons.js b/components/cycle-day/action-buttons.js new file mode 100644 index 0000000000000000000000000000000000000000..eb33201da2f48ec182974bf2d1f1f7a03b21ab8d --- /dev/null +++ b/components/cycle-day/action-buttons.js @@ -0,0 +1,46 @@ +import React from 'react' +import { + View, + Button, +} from 'react-native' +import { saveSymptom } from '../../db' + +export default function (showView) { + return function ({ symptom, cycleDay, saveAction, saveDisabled}) { + const buttons = [ + { + title: 'Cancel', + action: () => showView('dayView') + }, + { + title: 'Delete', + action: () => { + saveSymptom(symptom, cycleDay) + showView('dayView') + } + }, { + title: 'Save', + action: () => { + saveAction() + showView('dayView') + }, + disabledCondition: saveDisabled + } + ] + + return buttons.map(({ title, action, disabledCondition }, i) => { + const style = { flex: 1, marginHorizontal: 10 } + if (i === 0) style.marginLeft = 0 + if (i === buttons.length - 1) style.marginRight = 0 + return ( + <View style={style} key={i}> + <Button + onPress={action} + disabled={disabledCondition} + title={title}> + </Button> + </View > + ) + }) + } +} \ No newline at end of file diff --git a/components/cycle-day/cycle-day-overview.js b/components/cycle-day/cycle-day-overview.js new file mode 100644 index 0000000000000000000000000000000000000000..d43aab443d4581ab297502825442072baef88093 --- /dev/null +++ b/components/cycle-day/cycle-day-overview.js @@ -0,0 +1,106 @@ +import React, { Component } from 'react' +import { + View, + Button, + Text +} from 'react-native' +import styles from '../../styles' +import { + bleeding as bleedingLabels, + mucusFeeling as feelingLabels, + mucusTexture as textureLabels, + mucusNFP as computeSensiplanMucusLabels, +} from './labels/labels' +import cycleDayModule from '../../lib/cycle' +import { bleedingDaysSortedByDate } from '../../db' + +const getCycleDayNumber = cycleDayModule().getCycleDayNumber + +export default class DayView extends Component { + constructor(props) { + super(props) + this.cycleDay = props.cycleDay + this.showView = props.showView + this.state = { + cycleDayNumber: getCycleDayNumber(this.cycleDay.date), + } + + this.setStateWithCurrentCycleDayNumber = (function (DayViewComponent) { + return function () { + DayViewComponent.setState({ + cycleDayNumber: getCycleDayNumber(DayViewComponent.cycleDay.date) + }) + } + })(this) + + bleedingDaysSortedByDate.addListener(this.setStateWithCurrentCycleDayNumber) + } + + componentWillUnmount() { + bleedingDaysSortedByDate.removeListener(this.setStateWithCurrentCycleDayNumber) + } + + render() { + const bleedingValue = this.cycleDay.bleeding && this.cycleDay.bleeding.value + let bleedingLabel + if (typeof bleedingValue === 'number') { + bleedingLabel = `${bleedingLabels[bleedingValue]}` + if (this.cycleDay.bleeding.exclude) bleedingLabel = "( " + bleedingLabel + " )" + } else { + bleedingLabel = 'edit' + } + const temperatureValue = this.cycleDay.temperature && this.cycleDay.temperature.value + let temperatureLabel + if (typeof temperatureValue === 'number') { + temperatureLabel = `${temperatureValue} °C - ${this.cycleDay.temperature.time}` + if (this.cycleDay.temperature.exclude) { + temperatureLabel = "( " + temperatureLabel + " )" + } + } else { + temperatureLabel = 'edit' + } + + const mucusFeelingValue = this.cycleDay.mucus && this.cycleDay.mucus.feeling + const mucusTextureValue = this.cycleDay.mucus && this.cycleDay.mucus.texture + const mucusComputedValue = this.cycleDay.mucus && this.cycleDay.mucus.computedNfp + let mucusLabel + if (typeof mucusFeelingValue === 'number' && typeof mucusTextureValue === 'number') { + mucusLabel = `${feelingLabels[mucusFeelingValue]} + ${textureLabels[mucusTextureValue]} ( ${computeSensiplanMucusLabels[mucusComputedValue]} )` + if (this.cycleDay.mucus.exclude) mucusLabel = "( " + mucusLabel + " )" + } else { + mucusLabel = 'edit' + } + + return ( + <View style={styles.symptomEditView}> + <View style={styles.symptomViewRowInline}> + <Text style={styles.symptomDayView}>Bleeding</Text> + <View style={styles.symptomEditButton}> + <Button + onPress={() => this.showView('bleedingEditView')} + title={bleedingLabel}> + </Button> + </View> + </View> + <View style={styles.symptomViewRowInline}> + <Text style={styles.symptomDayView}>Temperature</Text> + <View style={styles.symptomEditButton}> + <Button + onPress={() => this.showView('temperatureEditView')} + title={temperatureLabel}> + </Button> + </View> + </View> + <View style={ styles.symptomViewRowInline }> + <Text style={styles.symptomDayView}>Mucus</Text> + <View style={ styles.symptomEditButton }> + <Button + onPress={() => this.showView('mucusEditView')} + title={mucusLabel}> + </Button> + </View> + </View> + </View > + ) + } +} diff --git a/components/cycle-day.js b/components/cycle-day/index.js similarity index 66% rename from components/cycle-day.js rename to components/cycle-day/index.js index bc3a6746a58b50436e950dc938b6633ad8fd4314..3eeb983b1f784112974de0a947f91d71e0e8c0c6 100644 --- a/components/cycle-day.js +++ b/components/cycle-day/index.js @@ -3,13 +3,15 @@ import { View, Text } from 'react-native' -import cycleModule from '../lib/cycle' -import getFertilityStatus from '../lib/sympto-adapter' +import cycleModule from '../../lib/cycle' +import getFertilityStatus from '../../lib/sympto-adapter' import DayView from './cycle-day-overview' -import BleedingEditView from './bleeding' -import TemperatureEditView from './temperature' -import { formatDateForViewHeader } from '../labels/format' -import styles from '../styles/index' +import BleedingEditView from './symptoms/bleeding' +import TemperatureEditView from './symptoms/temperature' +import MucusEditView from './symptoms/mucus' +import { formatDateForViewHeader } from './labels/format' +import styles from '../../styles' +import actionButtonModule from './action-buttons' const getCycleDayNumber = cycleModule().getCycleDayNumber @@ -25,13 +27,15 @@ export default class Day extends Component { this.showView = view => { this.setState({visibleComponent: view}) } + + this.makeActionButtons = actionButtonModule(this.showView) } render() { const cycleDayNumber = getCycleDayNumber(this.cycleDay.date) const fertilityStatus = getFertilityStatus(this.cycleDay.date) return ( - <View style={ styles.cycleDayOuterView }> + <View> <View style={ styles.cycleDayDateView }> <Text style={styles.dateHeader}> {formatDateForViewHeader(this.cycleDay.date)} @@ -47,15 +51,16 @@ export default class Day extends Component { {fertilityStatus} </Text> </View > - <View style={ styles.cycleDaySymptomsView }> + <View> { { dayView: <DayView cycleDay={this.cycleDay} showView={this.showView} />, - bleedingEditView: <BleedingEditView cycleDay={this.cycleDay} showView={this.showView}/>, - temperatureEditView: <TemperatureEditView cycleDay={this.cycleDay} showView={this.showView}/> + bleedingEditView: <BleedingEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons}/>, + temperatureEditView: <TemperatureEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons}/>, + mucusEditView: <MucusEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons}/> }[this.state.visibleComponent] } </View > </View > ) } -} \ No newline at end of file +} diff --git a/labels/format.js b/components/cycle-day/labels/format.js similarity index 100% rename from labels/format.js rename to components/cycle-day/labels/format.js diff --git a/components/cycle-day/labels/labels.js b/components/cycle-day/labels/labels.js new file mode 100644 index 0000000000000000000000000000000000000000..459370b25504e613605520d48b7bb967a1440624 --- /dev/null +++ b/components/cycle-day/labels/labels.js @@ -0,0 +1,11 @@ +const bleeding = ['spotting', 'light', 'medium', 'heavy'] +const mucusFeeling = ['dry', 'nothing', 'wet', 'slippery'] +const mucusTexture = ['nothing', 'creamy', 'egg white'] +const mucusNFP = ['t', 'Ø', 'f', 'S', '+S'] + +export { + bleeding, + mucusFeeling, + mucusTexture, + mucusNFP +} diff --git a/components/cycle-day/symptoms/bleeding.js b/components/cycle-day/symptoms/bleeding.js new file mode 100644 index 0000000000000000000000000000000000000000..7ec0574b924c6556d82239af59d20efbab21966f --- /dev/null +++ b/components/cycle-day/symptoms/bleeding.js @@ -0,0 +1,76 @@ +import React, { Component } from 'react' +import { + View, + Text, + Switch +} from 'react-native' +import RadioForm from 'react-native-simple-radio-button' +import styles from '../../../styles' +import { saveSymptom } from '../../../db' +import { bleeding as labels } from '../labels/labels' + +export default class Bleeding extends Component { + constructor(props) { + super(props) + this.cycleDay = props.cycleDay + this.makeActionButtons = props.makeActionButtons + let bleedingValue = this.cycleDay.bleeding && this.cycleDay.bleeding.value + if (!(typeof bleedingValue === 'number')) { + bleedingValue = -1 + } + this.state = { + currentValue: bleedingValue, + exclude: this.cycleDay.bleeding ? this.cycleDay.bleeding.exclude : false + } + } + + render() { + const bleedingRadioProps = [ + { label: labels[0], value: 0 }, + { label: labels[1], value: 1 }, + { label: labels[2], value: 2 }, + { label: labels[3], value: 3 }, + ] + return ( + <View style={styles.symptomEditView}> + <Text style={styles.symptomDayView}>Bleeding</Text> + <View style={styles.radioButtonRow}> + <RadioForm + radio_props={bleedingRadioProps} + initial={this.state.currentValue} + formHorizontal={true} + labelHorizontal={false} + labelStyle={styles.radioButton} + onPress={(itemValue) => { + this.setState({ currentValue: itemValue }) + }} + /> + </View> + <View style={styles.symptomViewRowInline}> + <Text style={styles.symptomDayView}>Exclude</Text> + <Switch + onValueChange={(val) => { + this.setState({ exclude: val }) + }} + value={this.state.exclude} + /> + </View> + <View style={styles.actionButtonRow}> + {this.makeActionButtons( + { + symptom: 'bleeding', + cycleDay: this.cycleDay, + saveAction: () => { + saveSymptom('bleeding', this.cycleDay, { + value: this.state.currentValue, + exclude: this.state.exclude + }) + }, + saveDisabled: this.state.currentValue === -1 + } + )} + </View> + </View> + ) + } +} \ No newline at end of file diff --git a/components/cycle-day/symptoms/mucus.js b/components/cycle-day/symptoms/mucus.js new file mode 100644 index 0000000000000000000000000000000000000000..f94a656f1fe09aeaba113fdc19e4697ed3048878 --- /dev/null +++ b/components/cycle-day/symptoms/mucus.js @@ -0,0 +1,109 @@ +import React, { Component } from 'react' +import { + View, + Text, + Switch +} from 'react-native' +import RadioForm from 'react-native-simple-radio-button' +import styles from '../../../styles' +import { saveSymptom } from '../../../db' +import { + mucusFeeling as feelingLabels, + mucusTexture as textureLabels +} from '../labels/labels' +import computeSensiplanValue from '../../../lib/sensiplan-mucus' + + +export default class Mucus extends Component { + constructor(props) { + super(props) + this.cycleDay = props.cycleDay + this.makeActionButtons = props.makeActionButtons + this.state = { + exclude: this.cycleDay.mucus ? this.cycleDay.mucus.exclude : false + } + + this.state.currentFeelingValue = this.cycleDay.mucus && this.cycleDay.mucus.feeling + if (typeof this.state.currentFeelingValue !== 'number') { + this.state.currentFeelingValue = -1 + } + + this.state.currentTextureValue = this.cycleDay.mucus && this.cycleDay.mucus.texture + if (typeof this.state.currentTextureValue !== 'number') { + this.state.currentTextureValue = -1 + } + } + + render() { + const mucusFeelingRadioProps = [ + {label: feelingLabels[0], value: 0 }, + {label: feelingLabels[1], value: 1 }, + {label: feelingLabels[2], value: 2 }, + {label: feelingLabels[3], value: 3 } + ] + const mucusTextureRadioProps = [ + {label: textureLabels[0], value: 0 }, + {label: textureLabels[1], value: 1 }, + {label: textureLabels[2], value: 2 } + ] + return( + <View style={ styles.symptomEditView }> + <Text style={styles.symptomDayView}>Mucus</Text> + <Text style={styles.symptomDayView}>Feeling</Text> + <View style={styles.radioButtonRow}> + <RadioForm + radio_props={mucusFeelingRadioProps} + initial={this.state.currentFeelingValue} + formHorizontal={true} + labelHorizontal={false} + labelStyle={styles.radioButton} + onPress={(itemValue) => { + this.setState({ currentFeelingValue: itemValue }) + }} + /> + </View> + <Text style={styles.symptomDayView}>Texture</Text> + <View style={styles.radioButtonRow}> + <RadioForm + radio_props={mucusTextureRadioProps} + initial={this.state.currentTextureValue} + formHorizontal={true} + labelHorizontal={false} + labelStyle={styles.radioButton} + onPress={(itemValue) => { + this.setState({ currentTextureValue: itemValue }) + }} + /> + </View> + <View style={styles.symptomViewRowInline}> + <Text style={styles.symptomDayView}>Exclude</Text> + <Switch + onValueChange={(val) => { + this.setState({ exclude: val }) + }} + value={this.state.exclude} + /> + </View> + + <View style={styles.actionButtonRow}> + {this.makeActionButtons( + { + symptom: 'mucus', + cycleDay: this.cycleDay, + saveAction: () => { + saveSymptom('mucus', this.cycleDay, { + feeling: this.state.currentFeelingValue, + texture: this.state.currentTextureValue, + computedNfp: computeSensiplanValue(this.state.currentFeelingValue, this.state.currentTextureValue), + exclude: this.state.exclude + }) + }, + saveDisabled: this.state.currentFeelingValue === -1 || this.state.currentTextureValue === -1 + } + )} + </View> + + </View> + ) + } +} diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js new file mode 100644 index 0000000000000000000000000000000000000000..b9a3d5b1de1af5ebf9756465f40a3d0d57b0fc23 --- /dev/null +++ b/components/cycle-day/symptoms/temperature.js @@ -0,0 +1,80 @@ +import React, { Component } from 'react' +import { + View, + Text, + TextInput, + Switch +} from 'react-native' + +import { getPreviousTemperature, saveSymptom } from '../../../db' +import styles from '../../../styles' +import { LocalTime, ChronoUnit } from 'js-joda' + +export default class Temp extends Component { + constructor(props) { + super(props) + this.cycleDay = props.cycleDay + this.makeActionButtons = props.makeActionButtons + let initialValue + + if (this.cycleDay.temperature) { + initialValue = this.cycleDay.temperature.value.toString() + this.time = this.cycleDay.temperature.time + } else { + const prevTemp = getPreviousTemperature(this.cycleDay) + initialValue = prevTemp ? prevTemp.toString() : '' + } + + this.state = { + currentValue: initialValue, + exclude: this.cycleDay.temperature ? this.cycleDay.temperature.exclude : false + } + } + + render() { + const cycleDay = this.cycleDay + return ( + <View style={styles.symptomEditView}> + <View style={styles.symptomViewRowInline}> + <Text style={styles.symptomDayView}>Temperature (°C)</Text> + <TextInput + style={styles.temperatureTextInput} + placeholder="Enter" + onChangeText={(val) => { + this.setState({ currentValue: val }) + }} + keyboardType='numeric' + value={this.state.currentValue} + /> + </View> + <View style={styles.symptomViewRowInline}> + <Text style={styles.symptomDayView}>Exclude</Text> + <Switch + onValueChange={(val) => { + this.setState({ exclude: val }) + }} + value={this.state.exclude} + /> + </View> + <View style={styles.actionButtonRow}> + {this.makeActionButtons({ + symptom: 'temperature', + cycleDay: this.cycleDay, + saveAction: () => { + const dataToSave = { + value: Number(this.state.currentValue), + exclude: this.state.exclude + } + if (!cycleDay.temperature || cycleDay.temperature && !cycleDay.temperature.time) { + const now = LocalTime.now().truncatedTo(ChronoUnit.MINUTES).toString() + dataToSave.time = now + } + saveSymptom('temperature', cycleDay, dataToSave) + }, + saveDisabled: this.state.currentValue === '' + })} + </View> + </View> + ) + } +} diff --git a/components/home.js b/components/home.js index 816a10c63538968280430f8695ce0bd3c89b87ce..6c3795de057cb567613d497db1f19ef1155c6573 100644 --- a/components/home.js +++ b/components/home.js @@ -46,32 +46,28 @@ export default class Home extends Component { render() { const navigate = this.props.navigation.navigate return ( - <View style={ styles.homeContainerView }> - <View style={{flex: 2}}> - <View> - <Text style={styles.welcome}>{this.state.welcomeText}</Text> - </View> - </View> - <View style={ styles.homeButtonsView}> - <View> + <View> + <Text style={styles.welcome}>{this.state.welcomeText}</Text> + <View style={styles.homeButtons}> + <View style={styles.homeButton}> <Button onPress={() => this.passTodayToDayView()} title="Edit symptoms for today"> </Button> </View> - <View> + <View style={styles.homeButton}> <Button onPress={() => navigate('calendar')} title="Go to calendar"> </Button> </View> - <View> + <View style={styles.homeButton}> <Button onPress={() => navigate('chart')} title="Go to chart"> </Button> </View> - <View> + <View style={styles.homeButton}> <Button onPress={() => deleteAll()} title="delete everything"> diff --git a/components/temperature.js b/components/temperature.js deleted file mode 100644 index c6fccfcd8993a399ddf9db1fb61c8b99c8d01b52..0000000000000000000000000000000000000000 --- a/components/temperature.js +++ /dev/null @@ -1,102 +0,0 @@ -import React, { Component } from 'react' -import { - View, - Text, - Button, - TextInput, - Switch -} from 'react-native' - -import { saveTemperature, getPreviousTemperature } from '../db' -import styles from '../styles/index' - -export default class Temp extends Component { - constructor(props) { - super(props) - this.cycleDay = props.cycleDay - this.showView = props.showView - let initialValue - - if(this.cycleDay.temperature) { - initialValue = this.cycleDay.temperature.value.toString() - } else { - const prevTemp = getPreviousTemperature(this.cycleDay) - initialValue = prevTemp ? prevTemp.toString() : '' - } - - this.state = { - currentValue: initialValue, - exclude: this.cycleDay.temperature ? this.cycleDay.temperature.exclude : false - } - } - - render() { - const cycleDay = this.cycleDay - return ( - <View style={ styles.symptomEditView }> - <View style={ styles.symptomEditSplitSymptomsAndLastRowButtons }> - <View style={ styles.itemsInRowView }> - <View style={{flex: 3, margin: 5}}> - <Text style={styles.symptomDayView}>Temperature (°C)</Text> - </View> - <View style={{flex: 1, margin: 5}}> - <TextInput - placeholder="Enter" - onChangeText={(val) => { - this.setState({currentValue: val}) - }} - keyboardType='numeric' - value = {this.state.currentValue} - /> - </View> - </View> - <View style={ styles.itemsInRowSeparatedView }> - <View style={{flex: 1, margin: 5}}> - <Text style={styles.symptomDayView}>Exclude</Text> - </View> - <View style={{flex: 1, margin: 5}}> - <Switch - onValueChange = {(val) => { - this.setState({ exclude: val }) - }} - value = { this.state.exclude } - /> - </View> - </View> - </View> - <View style={ styles.itemsInRowSeparatedView }> - <View style={ styles.singleButtonView }> - <Button - onPress={() => { - this.showView('dayView') - }} - title="Cancel"> - </Button> - </View> - <View style={ styles.singleButtonView }> - <Button - onPress={() => { - saveTemperature(cycleDay) - this.showView('dayView') - }} - title="Delete"> - </Button> - </View> - <View style={ styles.singleButtonView }> - <Button - onPress={() => { - saveTemperature(cycleDay, { - value: Number(this.state.currentValue), - exclude: this.state.exclude - }) - this.showView('dayView') - }} - disabled={ this.state.currentValue === '' } - title="Save"> - </Button> - </View> - </View> - </View> - ) - } -} diff --git a/db.js b/db.js index 3fdd40159eecfb2b7e5aff7136588cdd65215c55..c0533bf307529a29f65c3f3aea2067d62eb76a29 100644 --- a/db.js +++ b/db.js @@ -18,6 +18,16 @@ const BleedingSchema = { } } +const MucusSchema = { + name: 'Mucus', + properties: { + feeling: 'int', + texture: 'int', + computedNfp: 'int', + exclude: 'bool' + } +} + const CycleDaySchema = { name: 'CycleDay', primaryKey: 'date', @@ -30,6 +40,10 @@ const CycleDaySchema = { bleeding: { type: 'Bleeding', optional: true + }, + mucus: { + type: 'Mucus', + optional: true } } } @@ -38,7 +52,8 @@ const db = new Realm({ schema: [ CycleDaySchema, TemperatureSchema, - BleedingSchema + BleedingSchema, + MucusSchema ], // we only want this in dev mode deleteRealmIfMigrationNeeded: true @@ -47,20 +62,14 @@ const db = new Realm({ const bleedingDaysSortedByDate = db.objects('CycleDay').filtered('bleeding != null').sorted('date', true) const temperatureDaysSortedByDate = db.objects('CycleDay').filtered('temperature != null').sorted('date', true) -function saveTemperature(cycleDay, temperature) { +function saveSymptom(symptom, cycleDay, val) { db.write(() => { - cycleDay.temperature = temperature + cycleDay[symptom] = val }) } const cycleDaysSortedByDate = db.objects('CycleDay').sorted('date', true) -function saveBleeding(cycleDay, bleeding) { - db.write(() => { - cycleDay.bleeding = bleeding - }) -} - function getOrCreateCycleDay(localDate) { let result = db.objectForPrimaryKey('CycleDay', localDate) if (!result) { @@ -94,8 +103,7 @@ function getPreviousTemperature(cycleDay) { } export { - saveTemperature, - saveBleeding, + saveSymptom, getOrCreateCycleDay, bleedingDaysSortedByDate, temperatureDaysSortedByDate, diff --git a/lib/sensiplan-mucus.js b/lib/sensiplan-mucus.js new file mode 100644 index 0000000000000000000000000000000000000000..27e1590eb59f9799012f4a841973d90f0107d2a6 --- /dev/null +++ b/lib/sensiplan-mucus.js @@ -0,0 +1,16 @@ +export default function (feeling, texture) { + const feelingMapping = { + 0: 0, + 1: 1, + 2: 2, + 3: 4 + } + const textureMapping = { + 0: 0, + 1: 3, + 2: 4 + } + const nfpFeelingValue = feelingMapping[feeling] + const nfpTextureValue = textureMapping[texture] + return Math.max(nfpFeelingValue, nfpTextureValue) +} diff --git a/styles/index.js b/styles/index.js index 204e13256c3a885de08d117ff81d0b05c81f4980..52fc65d4a18bbcb3a3584afa4ca6069365df00ec 100644 --- a/styles/index.js +++ b/styles/index.js @@ -14,66 +14,41 @@ export default StyleSheet.create({ dateHeader: { fontSize: 20, fontWeight: 'bold', - margin: 20, + margin: 15, color: 'white', textAlign: 'center', textAlignVertical: 'center' }, cycleDayNumber: { fontSize: 18, + margin: 15, textAlign: 'center', textAlignVertical: 'center' }, symptomDayView: { fontSize: 20, - margin: 30, - textAlign: 'left', textAlignVertical: 'center' }, radioButton: { fontSize: 18, - margin: 5, + margin: 8, textAlign: 'center', textAlignVertical: 'center' }, - singleButtonView: { - flex: 1, - margin: 5 - }, - itemsInRowView: { - flex: 1, - flexDirection: 'row', - justifyContent: 'flex-start', - alignItems: 'center' - }, - itemsInRowSeparatedView: { - flex: 1, - flexDirection: 'row', - justifyContent: 'space-evenly', - alignItems: 'center' - }, symptomEditView: { - flex: 1, - flexDirection: 'column', justifyContent: 'space-between', - alignItems: 'flex-start' + marginHorizontal: 15 }, - symptomEditSplitSymptomsAndLastRowButtons: { - flex: 4, - flexDirection: 'column', - justifyContent: 'flex-start', - alignItems: 'flex-start' - }, - symptomEditListedSymptomView: { - flex: 1, - flexDirection: 'column', - justifyContent: 'flex-start', - alignItems: 'flex-start' + symptomEditRow: { + justifyContent: 'space-between', + marginBottom: 10, }, - cycleDayOuterView: { - flex: 1, - flexDirection: 'column', - justifyContent: 'space-around' + symptomViewRowInline: { + flexDirection: 'row', + justifyContent: 'space-between', + marginBottom: 10, + alignItems: 'center', + height: 50 }, cycleDayDateView: { justifyContent: 'center', @@ -82,21 +57,30 @@ export default StyleSheet.create({ cycleDayNumberView: { justifyContent: 'center', backgroundColor: 'skyblue', - padding: 10 - }, - cycleDaySymptomsView: { - flex: 8, - justifyContent: 'center' - }, - homeContainerView: { - flex: 0.5, - flexDirection: 'column', - justifyContent: 'space-around' - }, - homeButtonsView: { - flex: 3, - flexDirection: 'column', - justifyContent: 'space-around', - margin: 5 + marginBottom: 15 + }, + homeButtons: { + marginHorizontal: 15 + }, + homeButton: { + marginBottom: 15 + }, + temperatureTextInput: { + width: 80, + textAlign: 'center', + fontSize: 20 + }, + actionButtonRow: { + flexDirection: 'row', + justifyContent: 'space-evenly', + marginTop: 50 + }, + symptomEditButton: { + width: 130 + }, + radioButtonRow: { + marginTop: 15, + marginLeft: 'auto', + marginRight: 'auto' } }) \ No newline at end of file diff --git a/test/sensiplan-mucus.spec.js b/test/sensiplan-mucus.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..df1c461e8b9cbec78fac968399a63cc38c555a19 --- /dev/null +++ b/test/sensiplan-mucus.spec.js @@ -0,0 +1,80 @@ +import chai from 'chai' +import dirtyChai from 'dirty-chai' + +const expect = chai.expect +chai.use(dirtyChai) + +import getSensiplanMucus from '../lib/sensiplan-mucus' + +describe('getSensiplanMucus', () => { + + describe('results in t for:', () => { + it('dry feeling and no texture', function () { + const sensiplanValue = getSensiplanMucus(0, 0) + expect(sensiplanValue).to.eql(0) + }) + }) + + describe('results in Ø for:', () => { + it('no feeling and no texture', function () { + const sensiplanValue = getSensiplanMucus(1, 0) + expect(sensiplanValue).to.eql(1) + }) + }) + + describe('results in f for:', () => { + it('wet feeling and no texture', function () { + const sensiplanValue = getSensiplanMucus(2, 0) + expect(sensiplanValue).to.eql(2) + }) + }) + + describe('results in S for:', () => { + it('dry feeling and creamy texture', function () { + const sensiplanValue = getSensiplanMucus(0, 1) + expect(sensiplanValue).to.eql(3) + }) + + it('no feeling and creamy texture', function () { + const sensiplanValue = getSensiplanMucus(1, 1) + expect(sensiplanValue).to.eql(3) + }) + + it('wet feeling and creamy texture', function () { + const sensiplanValue = getSensiplanMucus(2, 1) + expect(sensiplanValue).to.eql(3) + }) + }) + + describe('results in +S for:', () => { + it('dry feeling and egg white texture', function () { + const sensiplanValue = getSensiplanMucus(0, 2) + expect(sensiplanValue).to.eql(4) + }) + + it('no feeling and egg white texture', function () { + const sensiplanValue = getSensiplanMucus(1, 2) + expect(sensiplanValue).to.eql(4) + }) + + it('wet feeling and egg white texture', function () { + const sensiplanValue = getSensiplanMucus(2, 2) + expect(sensiplanValue).to.eql(4) + }) + + it('slippery feeling and egg white texture', function () { + const sensiplanValue = getSensiplanMucus(3, 2) + expect(sensiplanValue).to.eql(4) + }) + + it('slippery feeling and creamy texture', function () { + const sensiplanValue = getSensiplanMucus(3, 1) + expect(sensiplanValue).to.eql(4) + }) + + it('slippery feeling and no texture', function () { + const sensiplanValue = getSensiplanMucus(3, 0) + expect(sensiplanValue).to.eql(4) + }) + }) +})