Merge branch '363-alert-for-cervix-and-mucus-when-trying-to-navigate-away-and-one-value-is-missing' into 'master'
Basic auto save Closes #363 See merge request bloodyhealth/drip!214
This commit is contained in:
+5
-12
@@ -125,19 +125,12 @@ export default class App extends Component {
|
|||||||
goBack={this.handleBackButtonPress}
|
goBack={this.handleBackButtonPress}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
{this.isSymptomView() &&
|
|
||||||
<Header
|
|
||||||
title={title}
|
|
||||||
isSymptomView={true}
|
|
||||||
goBack={this.handleBackButtonPress}
|
|
||||||
date={currentProps.date}
|
|
||||||
goToSymptomInfo={() => this.navigate(INFO_SYMPTOM_PAGE, {
|
|
||||||
symptomView: currentPage,
|
|
||||||
...currentProps
|
|
||||||
})}
|
|
||||||
/>}
|
|
||||||
|
|
||||||
<Page navigate={this.navigate} {...currentProps} />
|
<Page
|
||||||
|
navigate={this.navigate}
|
||||||
|
{...currentProps}
|
||||||
|
handleBackButtonPress={this.handleBackButtonPress}
|
||||||
|
/>
|
||||||
|
|
||||||
{!this.isSymptomView() &&
|
{!this.isSymptomView() &&
|
||||||
<Menu navigate={this.navigate} currentPage={currentPage} />
|
<Menu navigate={this.navigate} currentPage={currentPage} />
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { Component } from 'react'
|
import React, { Component } from 'react'
|
||||||
import {
|
import {
|
||||||
View, TouchableOpacity, Text, Alert, ToastAndroid
|
View, TouchableOpacity, Text, Alert} from 'react-native'
|
||||||
} from 'react-native'
|
|
||||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
|
||||||
import { saveSymptom } from '../../../db'
|
import { saveSymptom } from '../../../db'
|
||||||
import styles, {iconStyles} from '../../../styles'
|
import styles, {iconStyles} from '../../../styles'
|
||||||
@@ -14,10 +13,8 @@ export default class ActionButtonFooter extends Component {
|
|||||||
symptom,
|
symptom,
|
||||||
currentSymptomValue,
|
currentSymptomValue,
|
||||||
date,
|
date,
|
||||||
saveAction,
|
|
||||||
saveDisabled,
|
|
||||||
navigate,
|
navigate,
|
||||||
autoShowDayView = true}
|
}
|
||||||
= this.props
|
= this.props
|
||||||
const navigateToOverView = () => navigate('CycleDay', {date})
|
const navigateToOverView = () => navigate('CycleDay', {date})
|
||||||
const buttons = [
|
const buttons = [
|
||||||
@@ -44,43 +41,19 @@ export default class ActionButtonFooter extends Component {
|
|||||||
(Object.values(currentSymptomValue).every(x => !x) && currentSymptomValue.constructor === Object)
|
(Object.values(currentSymptomValue).every(x => !x) && currentSymptomValue.constructor === Object)
|
||||||
),
|
),
|
||||||
icon: 'delete-outline'
|
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 (
|
return (
|
||||||
<View style={styles.actionButtonFooter}>
|
<View style={styles.menu}>
|
||||||
{buttons.map(({ title, action, disabledCondition, icon }, i) => {
|
{buttons.map(({ title, action, icon }, i) => {
|
||||||
const textStyle = [styles.menuText]
|
const textStyle = [styles.menuText]
|
||||||
if (disabledCondition) {
|
|
||||||
textStyle.push(styles.menuTextInActive)
|
|
||||||
}
|
|
||||||
const iconStyle = disabledCondition ?
|
|
||||||
Object.assign(
|
|
||||||
{},
|
|
||||||
iconStyles.menuIcon,
|
|
||||||
iconStyles.menuIconInactive
|
|
||||||
)
|
|
||||||
:
|
|
||||||
iconStyles.menuIcon
|
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={action}
|
onPress={action}
|
||||||
style={styles.actionButtonItem}
|
style={styles.actionButtonItem}
|
||||||
key={i.toString()}
|
key={i.toString()}
|
||||||
>
|
>
|
||||||
<Icon name={icon} {...iconStyle} />
|
<Icon name={icon} {...iconStyles.menuIcon} />
|
||||||
<Text style={textStyle}>
|
<Text style={textStyle}>
|
||||||
{title.toLowerCase()}
|
{title.toLowerCase()}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -1,29 +1,39 @@
|
|||||||
import React, { Component } from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
View,
|
|
||||||
Switch,
|
Switch,
|
||||||
ScrollView
|
ScrollView
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import styles from '../../../styles'
|
import styles from '../../../styles'
|
||||||
import { saveSymptom } from '../../../db'
|
|
||||||
import { bleeding } from '../../../i18n/en/cycle-day'
|
import { bleeding } from '../../../i18n/en/cycle-day'
|
||||||
import ActionButtonFooter from './action-button-footer'
|
|
||||||
import SelectTabGroup from '../select-tab-group'
|
import SelectTabGroup from '../select-tab-group'
|
||||||
import SymptomSection from './symptom-section'
|
import SymptomSection from './symptom-section'
|
||||||
|
import SymptomView from './symptom-view'
|
||||||
|
|
||||||
export default class Bleeding extends Component {
|
export default class Bleeding extends SymptomView {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
const cycleDay = props.cycleDay
|
const cycleDay = props.cycleDay
|
||||||
this.bleeding = cycleDay && cycleDay.bleeding
|
this.bleeding = cycleDay && cycleDay.bleeding
|
||||||
this.makeActionButtons = props.makeActionButtons
|
|
||||||
this.state = {
|
this.state = {
|
||||||
currentValue: this.bleeding && this.bleeding.value,
|
currentValue: this.bleeding && this.bleeding.value,
|
||||||
exclude: this.bleeding ? this.bleeding.exclude : false
|
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 = [
|
const bleedingRadioProps = [
|
||||||
{ label: bleeding.labels[0], value: 0 },
|
{ label: bleeding.labels[0], value: 0 },
|
||||||
{ label: bleeding.labels[1], value: 1 },
|
{ label: bleeding.labels[1], value: 1 },
|
||||||
@@ -31,45 +41,30 @@ export default class Bleeding extends Component {
|
|||||||
{ label: bleeding.labels[3], value: 3 },
|
{ label: bleeding.labels[3], value: 3 },
|
||||||
]
|
]
|
||||||
return (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<ScrollView style={styles.page}>
|
||||||
<ScrollView style={styles.page}>
|
<SymptomSection
|
||||||
<SymptomSection
|
header={bleeding.heaviness.header}
|
||||||
header={bleeding.heaviness.header}
|
explainer={bleeding.heaviness.explainer}
|
||||||
explainer={bleeding.heaviness.explainer}
|
>
|
||||||
>
|
<SelectTabGroup
|
||||||
<SelectTabGroup
|
buttons={bleedingRadioProps}
|
||||||
buttons={bleedingRadioProps}
|
active={this.state.currentValue}
|
||||||
active={this.state.currentValue}
|
onSelect={val => this.setState({ currentValue: val })}
|
||||||
onSelect={val => this.setState({ currentValue: val })}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
<SymptomSection
|
||||||
<SymptomSection
|
header={bleeding.exclude.header}
|
||||||
header={bleeding.exclude.header}
|
explainer={bleeding.exclude.explainer}
|
||||||
explainer={bleeding.exclude.explainer}
|
inline={true}
|
||||||
inline={true}
|
>
|
||||||
>
|
<Switch
|
||||||
<Switch
|
onValueChange={(val) => {
|
||||||
onValueChange={(val) => {
|
this.setState({ exclude: val })
|
||||||
this.setState({ exclude: val })
|
}}
|
||||||
}}
|
value={this.state.exclude}
|
||||||
value={this.state.exclude}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
</ScrollView>
|
||||||
</ScrollView>
|
|
||||||
<ActionButtonFooter
|
|
||||||
symptom='bleeding'
|
|
||||||
date={this.props.date}
|
|
||||||
currentSymptomValue={this.bleeding}
|
|
||||||
saveAction={() => {
|
|
||||||
saveSymptom('bleeding', this.props.date, {
|
|
||||||
value: this.state.currentValue,
|
|
||||||
exclude: this.state.exclude
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
saveDisabled={typeof this.state.currentValue != 'number'}
|
|
||||||
navigate={this.props.navigate}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,27 +1,40 @@
|
|||||||
import React, { Component } from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
View,
|
|
||||||
Switch,
|
Switch,
|
||||||
ScrollView
|
ScrollView
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import styles from '../../../styles'
|
import styles from '../../../styles'
|
||||||
import { saveSymptom } from '../../../db'
|
|
||||||
import { cervix as labels } from '../../../i18n/en/cycle-day'
|
import { cervix as labels } from '../../../i18n/en/cycle-day'
|
||||||
import ActionButtonFooter from './action-button-footer'
|
|
||||||
import SelectTabGroup from '../select-tab-group'
|
import SelectTabGroup from '../select-tab-group'
|
||||||
import SymptomSection from './symptom-section'
|
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) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
const cycleDay = props.cycleDay
|
const cycleDay = props.cycleDay
|
||||||
this.cervix = cycleDay && cycleDay.cervix
|
this.cervix = cycleDay && cycleDay.cervix
|
||||||
this.makeActionButtons = props.makeActionButtons
|
|
||||||
this.state = this.cervix ? this.cervix : {}
|
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 = [
|
const cervixOpeningRadioProps = [
|
||||||
{ label: labels.opening.categories[0], value: 0 },
|
{ label: labels.opening.categories[0], value: 0 },
|
||||||
{ label: labels.opening.categories[1], value: 1 },
|
{ 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[1], value: 1 },
|
||||||
{ label: labels.position.categories[2], value: 2 }
|
{ 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 (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<ScrollView style={styles.page}>
|
||||||
<ScrollView style={styles.page}>
|
<SymptomSection
|
||||||
<SymptomSection
|
header="Opening"
|
||||||
header="Opening"
|
explainer={labels.opening.explainer}
|
||||||
explainer={labels.opening.explainer}
|
>
|
||||||
>
|
<SelectTabGroup
|
||||||
<SelectTabGroup
|
buttons={cervixOpeningRadioProps}
|
||||||
buttons={cervixOpeningRadioProps}
|
active={this.state.opening}
|
||||||
active={this.state.opening}
|
onSelect={val => this.setState({ opening: val })}
|
||||||
onSelect={val => this.setState({ opening: val })}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
<SymptomSection
|
||||||
<SymptomSection
|
header="Firmness"
|
||||||
header="Firmness"
|
explainer={labels.firmness.explainer}
|
||||||
explainer={labels.firmness.explainer}
|
>
|
||||||
>
|
<SelectTabGroup
|
||||||
<SelectTabGroup
|
buttons={cervixFirmnessRadioProps}
|
||||||
buttons={cervixFirmnessRadioProps}
|
active={this.state.firmness}
|
||||||
active={this.state.firmness}
|
onSelect={val => this.setState({ firmness: val })}
|
||||||
onSelect={val => this.setState({ firmness: val })}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
<SymptomSection
|
||||||
<SymptomSection
|
header="Position"
|
||||||
header="Position"
|
explainer={labels.position.explainer}
|
||||||
explainer={labels.position.explainer}
|
>
|
||||||
>
|
<SelectTabGroup
|
||||||
<SelectTabGroup
|
buttons={cervixPositionRadioProps}
|
||||||
buttons={cervixPositionRadioProps}
|
active={this.state.position}
|
||||||
active={this.state.position}
|
onSelect={val => this.setState({ position: val })}
|
||||||
onSelect={val => this.setState({ position: val })}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
<SymptomSection
|
||||||
<SymptomSection
|
header="Exclude"
|
||||||
header="Exclude"
|
explainer="You can exclude this value if you don't want to use it for fertility detection"
|
||||||
explainer="You can exclude this value if you don't want to use it for fertility detection"
|
inline={true}
|
||||||
inline={true}
|
>
|
||||||
>
|
<Switch
|
||||||
<Switch
|
onValueChange={(val) => {
|
||||||
onValueChange={(val) => {
|
this.setState({ exclude: val })
|
||||||
this.setState({ exclude: val })
|
}}
|
||||||
}}
|
value={this.state.exclude}
|
||||||
value={this.state.exclude}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
</ScrollView>
|
||||||
</ScrollView>
|
|
||||||
<ActionHint isVisible={mandatoryNotCompletedYet}>{labels.actionHint}</ActionHint>
|
|
||||||
<ActionButtonFooter
|
|
||||||
symptom='cervix'
|
|
||||||
date={this.props.date}
|
|
||||||
currentSymptomValue={this.cervix}
|
|
||||||
saveAction={() => {
|
|
||||||
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}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,56 +1,51 @@
|
|||||||
import React, { Component } from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
View,
|
|
||||||
ScrollView
|
ScrollView
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import styles from '../../../styles'
|
import styles from '../../../styles'
|
||||||
import { saveSymptom } from '../../../db'
|
|
||||||
import { intensity, desire } from '../../../i18n/en/cycle-day'
|
import { intensity, desire } from '../../../i18n/en/cycle-day'
|
||||||
import ActionButtonFooter from './action-button-footer'
|
|
||||||
import SelectTabGroup from '../select-tab-group'
|
import SelectTabGroup from '../select-tab-group'
|
||||||
import SymptomSection from './symptom-section'
|
import SymptomSection from './symptom-section'
|
||||||
|
import SymptomView from './symptom-view'
|
||||||
|
|
||||||
export default class Desire extends Component {
|
export default class Desire extends SymptomView {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
const cycleDay = props.cycleDay
|
const cycleDay = props.cycleDay
|
||||||
this.desire = cycleDay && cycleDay.desire
|
this.desire = cycleDay && cycleDay.desire
|
||||||
this.makeActionButtons = props.makeActionButtons
|
|
||||||
const desireValue = this.desire && this.desire.value
|
const desireValue = this.desire && this.desire.value
|
||||||
this.state = { currentValue: desireValue }
|
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 = [
|
const desireRadioProps = [
|
||||||
{ label: intensity[0], value: 0 },
|
{ label: intensity[0], value: 0 },
|
||||||
{ label: intensity[1], value: 1 },
|
{ label: intensity[1], value: 1 },
|
||||||
{ label: intensity[2], value: 2 }
|
{ label: intensity[2], value: 2 }
|
||||||
]
|
]
|
||||||
return (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<ScrollView style={styles.page}>
|
||||||
<ScrollView style={styles.page}>
|
<SymptomSection
|
||||||
<SymptomSection
|
header={desire.header}
|
||||||
header={desire.header}
|
explainer={desire.explainer}
|
||||||
explainer={desire.explainer}
|
>
|
||||||
>
|
<SelectTabGroup
|
||||||
<SelectTabGroup
|
buttons={desireRadioProps}
|
||||||
buttons={desireRadioProps}
|
active={this.state.currentValue}
|
||||||
active={this.state.currentValue}
|
onSelect={val => this.setState({ currentValue: val })}
|
||||||
onSelect={val => this.setState({ currentValue: val })}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
</ScrollView>
|
||||||
</ScrollView>
|
|
||||||
<ActionButtonFooter
|
|
||||||
symptom='desire'
|
|
||||||
date={this.props.date}
|
|
||||||
currentSymptomValue={this.desire}
|
|
||||||
saveAction={() => {
|
|
||||||
saveSymptom('desire', this.props.date, { value: this.state.currentValue })
|
|
||||||
}}
|
|
||||||
saveDisabled={typeof this.state.currentValue != 'number'}
|
|
||||||
navigate={this.props.navigate}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
import React, { Component } from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
ScrollView,
|
ScrollView,
|
||||||
TextInput,
|
TextInput} from 'react-native'
|
||||||
View
|
|
||||||
} from 'react-native'
|
|
||||||
import { saveSymptom } from '../../../db'
|
|
||||||
import { mood as labels } from '../../../i18n/en/cycle-day'
|
import { mood as labels } from '../../../i18n/en/cycle-day'
|
||||||
import ActionButtonFooter from './action-button-footer'
|
|
||||||
import SelectBoxGroup from '../select-box-group'
|
import SelectBoxGroup from '../select-box-group'
|
||||||
import SymptomSection from './symptom-section'
|
import SymptomSection from './symptom-section'
|
||||||
import styles from '../../../styles'
|
import styles from '../../../styles'
|
||||||
|
import SymptomView from './symptom-view'
|
||||||
|
|
||||||
export default class Mood extends Component {
|
export default class Mood extends SymptomView {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
const cycleDay = props.cycleDay
|
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) => {
|
toggleState = (key) => {
|
||||||
const curr = this.state[key]
|
const curr = this.state[key]
|
||||||
this.setState({[key]: !curr})
|
this.setState({[key]: !curr})
|
||||||
@@ -33,19 +45,18 @@ export default class Mood extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderContent() {
|
||||||
return (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<ScrollView style={styles.page}>
|
||||||
<ScrollView style={styles.page}>
|
<SymptomSection
|
||||||
<SymptomSection
|
explainer={labels.explainer}
|
||||||
explainer={labels.explainer}
|
>
|
||||||
>
|
<SelectBoxGroup
|
||||||
<SelectBoxGroup
|
labels={labels.categories}
|
||||||
labels={labels.categories}
|
onSelect={this.toggleState}
|
||||||
onSelect={this.toggleState}
|
optionsState={this.state}
|
||||||
optionsState={this.state}
|
/>
|
||||||
/>
|
{ this.state.other &&
|
||||||
{ this.state.other &&
|
|
||||||
<TextInput
|
<TextInput
|
||||||
autoFocus={this.state.focusTextArea}
|
autoFocus={this.state.focusTextArea}
|
||||||
multiline={true}
|
multiline={true}
|
||||||
@@ -55,24 +66,9 @@ export default class Mood extends Component {
|
|||||||
this.setState({note: val})
|
this.setState({note: val})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</SymptomSection>
|
</SymptomSection>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
<ActionButtonFooter
|
|
||||||
symptom='mood'
|
|
||||||
date={this.props.date}
|
|
||||||
currentSymptomValue={this.state}
|
|
||||||
saveAction={() => {
|
|
||||||
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}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,43 @@
|
|||||||
import React, { Component } from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
View,
|
|
||||||
Switch,
|
Switch,
|
||||||
ScrollView
|
ScrollView
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import styles from '../../../styles'
|
import styles from '../../../styles'
|
||||||
import { saveSymptom } from '../../../db'
|
|
||||||
import { mucus as labels } from '../../../i18n/en/cycle-day'
|
import { mucus as labels } from '../../../i18n/en/cycle-day'
|
||||||
import computeNfpValue from '../../../lib/nfp-mucus'
|
import computeNfpValue from '../../../lib/nfp-mucus'
|
||||||
import ActionButtonFooter from './action-button-footer'
|
|
||||||
import SelectTabGroup from '../select-tab-group'
|
import SelectTabGroup from '../select-tab-group'
|
||||||
import SymptomSection from './symptom-section'
|
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) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
const cycleDay = props.cycleDay
|
const cycleDay = props.cycleDay
|
||||||
this.mucus = cycleDay && cycleDay.mucus
|
this.mucus = cycleDay && cycleDay.mucus
|
||||||
this.makeActionButtons = props.makeActionButtons
|
|
||||||
this.state = this.mucus ? this.mucus : {}
|
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 = [
|
const mucusFeeling = [
|
||||||
{ label: labels.feeling.categories[0], value: 0 },
|
{ label: labels.feeling.categories[0], value: 0 },
|
||||||
{ label: labels.feeling.categories[1], value: 1 },
|
{ 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[1], value: 1 },
|
||||||
{ label: labels.texture.categories[2], value: 2 }
|
{ 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 (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<ScrollView style={styles.page}>
|
||||||
<ScrollView style={styles.page}>
|
<SymptomSection
|
||||||
<SymptomSection
|
header='Feeling'
|
||||||
header='Feeling'
|
explainer={labels.feeling.explainer}
|
||||||
explainer={labels.feeling.explainer}
|
>
|
||||||
>
|
<SelectTabGroup
|
||||||
<SelectTabGroup
|
buttons={mucusFeeling}
|
||||||
buttons={mucusFeeling}
|
onSelect={val => this.setState({ feeling: val })}
|
||||||
onSelect={val => this.setState({ feeling: val })}
|
active={this.state.feeling}
|
||||||
active={this.state.feeling}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
<SymptomSection
|
||||||
<SymptomSection
|
header='Texture'
|
||||||
header='Texture'
|
explainer={labels.texture.explainer}
|
||||||
explainer={labels.texture.explainer}
|
>
|
||||||
>
|
<SelectTabGroup
|
||||||
<SelectTabGroup
|
buttons={mucusTexture}
|
||||||
buttons={mucusTexture}
|
onSelect={val => this.setState({ texture: val })}
|
||||||
onSelect={val => this.setState({ texture: val })}
|
active={this.state.texture}
|
||||||
active={this.state.texture}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
<SymptomSection
|
||||||
<SymptomSection
|
header="Exclude"
|
||||||
header="Exclude"
|
explainer={labels.excludeExplainer}
|
||||||
explainer={labels.excludeExplainer}
|
inline={true}
|
||||||
inline={true}
|
>
|
||||||
>
|
<Switch
|
||||||
<Switch
|
onValueChange={(val) => {
|
||||||
onValueChange={(val) => {
|
this.setState({ exclude: val })
|
||||||
this.setState({ exclude: val })
|
}}
|
||||||
}}
|
value={this.state.exclude}
|
||||||
value={this.state.exclude}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
</ScrollView>
|
||||||
</ScrollView>
|
|
||||||
<ActionHint isVisible={mandatoryNotCompletedYet}>{labels.actionHint}</ActionHint>
|
|
||||||
<ActionButtonFooter
|
|
||||||
symptom='mucus'
|
|
||||||
date={this.props.date}
|
|
||||||
currentSymptomValue={this.mucus}
|
|
||||||
saveAction={() => {
|
|
||||||
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}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,60 +1,55 @@
|
|||||||
import React, { Component } from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
View,
|
|
||||||
ScrollView,
|
ScrollView,
|
||||||
TextInput,
|
TextInput,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
|
|
||||||
import styles from '../../../styles'
|
import styles from '../../../styles'
|
||||||
import { saveSymptom } from '../../../db'
|
|
||||||
import ActionButtonFooter from './action-button-footer'
|
|
||||||
import SymptomSection from './symptom-section'
|
import SymptomSection from './symptom-section'
|
||||||
import { noteExplainer } from '../../../i18n/en/cycle-day'
|
import { noteExplainer } from '../../../i18n/en/cycle-day'
|
||||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
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) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
const cycleDay = props.cycleDay
|
const cycleDay = props.cycleDay
|
||||||
this.note = cycleDay && cycleDay.note
|
this.note = cycleDay && cycleDay.note
|
||||||
this.makeActionButtons = props.makeActionButtons
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
currentValue: this.note && this.note.value || ''
|
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 (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<ScrollView style={styles.page}>
|
||||||
<ScrollView style={styles.page}>
|
<SymptomSection
|
||||||
<SymptomSection
|
explainer={noteExplainer}
|
||||||
explainer={noteExplainer}
|
>
|
||||||
>
|
<TextInput
|
||||||
<TextInput
|
autoFocus={!this.state.currentValue}
|
||||||
autoFocus={!this.state.currentValue}
|
multiline={true}
|
||||||
multiline={true}
|
placeholder={sharedLabels.enter}
|
||||||
placeholder={sharedLabels.enter}
|
onChangeText={(val) => {
|
||||||
onChangeText={(val) => {
|
this.setState({ currentValue: val })
|
||||||
this.setState({ currentValue: val })
|
}}
|
||||||
}}
|
value={this.state.currentValue}
|
||||||
value={this.state.currentValue}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
</ScrollView>
|
||||||
</ScrollView>
|
|
||||||
<ActionButtonFooter
|
|
||||||
symptom='note'
|
|
||||||
date={this.props.date}
|
|
||||||
currentSymptomValue={this.note}
|
|
||||||
saveAction={() => {
|
|
||||||
saveSymptom('note', this.props.date, {
|
|
||||||
value: this.state.currentValue
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
saveDisabled={!this.state.currentValue}
|
|
||||||
navigate={this.props.navigate}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
import React, { Component } from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
ScrollView,
|
ScrollView,
|
||||||
TextInput,
|
TextInput,
|
||||||
View
|
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import { saveSymptom } from '../../../db'
|
|
||||||
import { pain as labels } from '../../../i18n/en/cycle-day'
|
import { pain as labels } from '../../../i18n/en/cycle-day'
|
||||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
||||||
import ActionButtonFooter from './action-button-footer'
|
|
||||||
import SelectBoxGroup from '../select-box-group'
|
import SelectBoxGroup from '../select-box-group'
|
||||||
import SymptomSection from './symptom-section'
|
import SymptomSection from './symptom-section'
|
||||||
import styles from '../../../styles'
|
import styles from '../../../styles'
|
||||||
|
import SymptomView from './symptom-view'
|
||||||
|
|
||||||
export default class Pain extends Component {
|
export default class Pain extends SymptomView {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
const cycleDay = props.cycleDay
|
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) => {
|
toggleState = (key) => {
|
||||||
const curr = this.state[key]
|
const curr = this.state[key]
|
||||||
this.setState({[key]: !curr})
|
this.setState({[key]: !curr})
|
||||||
@@ -34,19 +48,18 @@ export default class Pain extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderContent() {
|
||||||
return (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<ScrollView style={styles.page}>
|
||||||
<ScrollView style={styles.page}>
|
<SymptomSection
|
||||||
<SymptomSection
|
explainer={labels.explainer}
|
||||||
explainer={labels.explainer}
|
>
|
||||||
>
|
<SelectBoxGroup
|
||||||
<SelectBoxGroup
|
labels={labels.categories}
|
||||||
labels={labels.categories}
|
onSelect={this.toggleState}
|
||||||
onSelect={this.toggleState}
|
optionsState={this.state}
|
||||||
optionsState={this.state}
|
/>
|
||||||
/>
|
{ this.state.other &&
|
||||||
{ this.state.other &&
|
|
||||||
<TextInput
|
<TextInput
|
||||||
autoFocus={this.state.focusTextArea}
|
autoFocus={this.state.focusTextArea}
|
||||||
multiline={true}
|
multiline={true}
|
||||||
@@ -56,24 +69,8 @@ export default class Pain extends Component {
|
|||||||
this.setState({note: val})
|
this.setState({note: val})
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</SymptomSection>
|
</SymptomSection>
|
||||||
</ScrollView>
|
</ScrollView>)
|
||||||
<ActionButtonFooter
|
|
||||||
symptom='pain'
|
|
||||||
date={this.props.date}
|
|
||||||
currentSymptomValue={this.state}
|
|
||||||
saveAction={() => {
|
|
||||||
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}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,16 @@
|
|||||||
import React, { Component } from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
TextInput,
|
TextInput,
|
||||||
View,
|
|
||||||
ScrollView
|
ScrollView
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import styles from '../../../styles'
|
import styles from '../../../styles'
|
||||||
import { saveSymptom } from '../../../db'
|
|
||||||
import { sex as sexLabels, contraceptives as contraceptivesLabels } from '../../../i18n/en/cycle-day'
|
import { sex as sexLabels, contraceptives as contraceptivesLabels } from '../../../i18n/en/cycle-day'
|
||||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
||||||
import ActionButtonFooter from './action-button-footer'
|
|
||||||
import SelectBoxGroup from '../select-box-group'
|
import SelectBoxGroup from '../select-box-group'
|
||||||
import SymptomSection from './symptom-section'
|
import SymptomSection from './symptom-section'
|
||||||
|
import SymptomView from './symptom-view'
|
||||||
|
|
||||||
export default class Sex extends Component {
|
export default class Sex extends SymptomView {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
const cycleDay = props.cycleDay
|
const cycleDay = props.cycleDay
|
||||||
@@ -26,6 +24,22 @@ export default class Sex extends Component {
|
|||||||
if (this.state.note) this.state.other = true
|
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) => {
|
toggleState = (key) => {
|
||||||
const curr = this.state[key]
|
const curr = this.state[key]
|
||||||
this.setState({[key]: !curr})
|
this.setState({[key]: !curr})
|
||||||
@@ -34,32 +48,31 @@ export default class Sex extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderContent() {
|
||||||
return (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<ScrollView style={styles.page}>
|
||||||
<ScrollView style={styles.page}>
|
<SymptomSection
|
||||||
<SymptomSection
|
header={sexLabels.header}
|
||||||
header={sexLabels.header}
|
explainer={sexLabels.explainer}
|
||||||
explainer={sexLabels.explainer}
|
>
|
||||||
>
|
<SelectBoxGroup
|
||||||
<SelectBoxGroup
|
labels={sexLabels.categories}
|
||||||
labels={sexLabels.categories}
|
onSelect={this.toggleState}
|
||||||
onSelect={this.toggleState}
|
optionsState={this.state}
|
||||||
optionsState={this.state}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
<SymptomSection
|
||||||
<SymptomSection
|
header={contraceptivesLabels.header}
|
||||||
header={contraceptivesLabels.header}
|
explainer={contraceptivesLabels.explainer}
|
||||||
explainer={contraceptivesLabels.explainer}
|
>
|
||||||
>
|
<SelectBoxGroup
|
||||||
<SelectBoxGroup
|
labels={contraceptivesLabels.categories}
|
||||||
labels={contraceptivesLabels.categories}
|
onSelect={this.toggleState}
|
||||||
onSelect={this.toggleState}
|
optionsState={this.state}
|
||||||
optionsState={this.state}
|
/>
|
||||||
/>
|
</SymptomSection>
|
||||||
</SymptomSection>
|
|
||||||
|
|
||||||
{this.state.other &&
|
{this.state.other &&
|
||||||
<TextInput
|
<TextInput
|
||||||
autoFocus={this.state.focusTextArea}
|
autoFocus={this.state.focusTextArea}
|
||||||
multiline={true}
|
multiline={true}
|
||||||
@@ -69,23 +82,8 @@ export default class Sex extends Component {
|
|||||||
this.setState({ note: val })
|
this.setState({ note: val })
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
<ActionButtonFooter
|
|
||||||
symptom='sex'
|
|
||||||
date={this.props.date}
|
|
||||||
currentSymptomValue={this.state}
|
|
||||||
saveAction={() => {
|
|
||||||
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}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
<View style={{flex: 1}}>
|
||||||
|
<Header
|
||||||
|
title={headerTitles[this.symptomName].toLowerCase()}
|
||||||
|
date={this.date}
|
||||||
|
goBack={() => {
|
||||||
|
this.onBackButtonPress()
|
||||||
|
this.globalBackhandler()
|
||||||
|
}}
|
||||||
|
deleteEntry={() => {
|
||||||
|
this.deleteSymptomEntry()
|
||||||
|
this.globalBackhandler()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{this.renderContent()}
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { Component } from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
View,
|
View,
|
||||||
Switch,
|
Switch,
|
||||||
@@ -9,21 +9,21 @@ import {
|
|||||||
import DateTimePicker from 'react-native-modal-datetime-picker-nevo'
|
import DateTimePicker from 'react-native-modal-datetime-picker-nevo'
|
||||||
import padWithZeros from '../../helpers/pad-time-with-zeros'
|
import padWithZeros from '../../helpers/pad-time-with-zeros'
|
||||||
|
|
||||||
import { getPreviousTemperature, saveSymptom } from '../../../db'
|
import { getPreviousTemperature } from '../../../db'
|
||||||
import styles from '../../../styles'
|
import styles from '../../../styles'
|
||||||
import { LocalTime, ChronoUnit } from 'js-joda'
|
import { LocalTime, ChronoUnit } from 'js-joda'
|
||||||
import { temperature as labels } from '../../../i18n/en/cycle-day'
|
import { temperature as labels } from '../../../i18n/en/cycle-day'
|
||||||
import { scaleObservable } from '../../../local-storage'
|
import { scaleObservable } from '../../../local-storage'
|
||||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
||||||
import ActionButtonFooter from './action-button-footer'
|
|
||||||
import config from '../../../config'
|
import config from '../../../config'
|
||||||
import AppTextInput from '../../app-text-input'
|
import AppTextInput from '../../app-text-input'
|
||||||
import AppText from '../../app-text'
|
import AppText from '../../app-text'
|
||||||
import SymptomSection from './symptom-section'
|
import SymptomSection from './symptom-section'
|
||||||
|
import SymptomView from './symptom-view'
|
||||||
|
|
||||||
const minutes = ChronoUnit.MINUTES
|
const minutes = ChronoUnit.MINUTES
|
||||||
|
|
||||||
export default class Temp extends Component {
|
export default class Temp extends SymptomView {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props)
|
super(props)
|
||||||
const cycleDay = props.cycleDay
|
const cycleDay = props.cycleDay
|
||||||
@@ -45,7 +45,7 @@ export default class Temp extends Component {
|
|||||||
this.state.temperature = `${this.state.temperature}.0`
|
this.state.temperature = `${this.state.temperature}.0`
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const prevTemp = getPreviousTemperature(this.props.date)
|
const prevTemp = getPreviousTemperature(props.date)
|
||||||
if (prevTemp) {
|
if (prevTemp) {
|
||||||
this.state.temperature = prevTemp.toString()
|
this.state.temperature = prevTemp.toString()
|
||||||
this.state.isSuggestion = true
|
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 = () => {
|
saveTemperature = () => {
|
||||||
const dataToSave = {
|
const dataToSave = {
|
||||||
value: Number(this.state.temperature),
|
value: Number(this.state.temperature),
|
||||||
@@ -60,8 +71,8 @@ export default class Temp extends Component {
|
|||||||
time: this.state.time,
|
time: this.state.time,
|
||||||
note: this.state.note
|
note: this.state.note
|
||||||
}
|
}
|
||||||
saveSymptom('temperature', this.props.date, dataToSave)
|
|
||||||
this.props.navigate('CycleDay', {date: this.props.date})
|
this.saveSymptomEntry(dataToSave)
|
||||||
}
|
}
|
||||||
|
|
||||||
checkRangeAndSave = () => {
|
checkRangeAndSave = () => {
|
||||||
@@ -105,102 +116,78 @@ export default class Temp extends Component {
|
|||||||
this.setState({ isTimePickerVisible: true })
|
this.setState({ isTimePickerVisible: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderContent() {
|
||||||
const inputStyle = [styles.temperatureTextInput]
|
const inputStyle = [styles.temperatureTextInput]
|
||||||
if (this.state.isSuggestion) {
|
if (this.state.isSuggestion) {
|
||||||
inputStyle.push(styles.temperatureTextInputSuggestion)
|
inputStyle.push(styles.temperatureTextInputSuggestion)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<View style={{ flex: 1 }}>
|
<ScrollView style={styles.page}>
|
||||||
<ScrollView style={styles.page}>
|
<SymptomSection
|
||||||
<SymptomSection
|
header={labels.temperature.header}
|
||||||
header={labels.temperature.header}
|
explainer={labels.temperature.explainer}
|
||||||
explainer={labels.temperature.explainer}
|
>
|
||||||
>
|
<View style={styles.framedSegmentInlineChildren}>
|
||||||
<View style={styles.framedSegmentInlineChildren}>
|
|
||||||
<AppTextInput
|
|
||||||
style={[inputStyle]}
|
|
||||||
autoFocus={true}
|
|
||||||
placeholder={this.state.temperature}
|
|
||||||
value={this.state.temperature}
|
|
||||||
onChangeText={this.setTemperature}
|
|
||||||
keyboardType='numeric'
|
|
||||||
maxLength={5}
|
|
||||||
onBlur={this.checkRange}
|
|
||||||
/>
|
|
||||||
<AppText style={{ marginLeft: 5 }}>°C</AppText>
|
|
||||||
</View>
|
|
||||||
</SymptomSection>
|
|
||||||
<SymptomSection
|
|
||||||
header={labels.time}
|
|
||||||
>
|
|
||||||
<View style={styles.framedSegmentInlineChildren}>
|
|
||||||
<AppTextInput
|
|
||||||
style={[styles.temperatureTextInput]}
|
|
||||||
onFocus={this.showTimePicker}
|
|
||||||
value={this.state.time}
|
|
||||||
/>
|
|
||||||
<DateTimePicker
|
|
||||||
mode="time"
|
|
||||||
isVisible={this.state.isTimePickerVisible}
|
|
||||||
onConfirm={jsDate => {
|
|
||||||
this.setState({
|
|
||||||
time: padWithZeros(jsDate),
|
|
||||||
isTimePickerVisible: false
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
onCancel={() => this.setState({ isTimePickerVisible: false })}
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</SymptomSection>
|
|
||||||
<SymptomSection
|
|
||||||
header={labels.note.header}
|
|
||||||
explainer={labels.note.explainer}
|
|
||||||
>
|
|
||||||
<AppTextInput
|
<AppTextInput
|
||||||
multiline={true}
|
style={[inputStyle]}
|
||||||
autoFocus={this.state.focusTextArea}
|
autoFocus={true}
|
||||||
placeholder={sharedLabels.enter}
|
placeholder={this.state.temperature}
|
||||||
value={this.state.note}
|
value={this.state.temperature}
|
||||||
onChangeText={this.setNote}
|
onChangeText={this.setTemperature}
|
||||||
|
keyboardType='numeric'
|
||||||
|
maxLength={5}
|
||||||
|
onBlur={this.checkRange}
|
||||||
/>
|
/>
|
||||||
</SymptomSection>
|
<AppText style={{ marginLeft: 5 }}>°C</AppText>
|
||||||
<SymptomSection
|
</View>
|
||||||
header={labels.exclude.header}
|
</SymptomSection>
|
||||||
explainer={labels.exclude.explainer}
|
<SymptomSection
|
||||||
inline={true}
|
header={labels.time}
|
||||||
>
|
>
|
||||||
<Switch
|
<View style={styles.framedSegmentInlineChildren}>
|
||||||
onValueChange={(val) => {
|
<AppTextInput
|
||||||
this.setState({ exclude: val })
|
style={[styles.temperatureTextInput]}
|
||||||
|
onFocus={this.showTimePicker}
|
||||||
|
value={this.state.time}
|
||||||
|
/>
|
||||||
|
<DateTimePicker
|
||||||
|
mode="time"
|
||||||
|
isVisible={this.state.isTimePickerVisible}
|
||||||
|
onConfirm={jsDate => {
|
||||||
|
this.setState({
|
||||||
|
time: padWithZeros(jsDate),
|
||||||
|
isTimePickerVisible: false
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
value={this.state.exclude}
|
onCancel={() => this.setState({ isTimePickerVisible: false })}
|
||||||
/>
|
/>
|
||||||
</SymptomSection>
|
</View>
|
||||||
</ScrollView>
|
</SymptomSection>
|
||||||
<ActionButtonFooter
|
<SymptomSection
|
||||||
symptom='temperature'
|
header={labels.note.header}
|
||||||
date={this.props.date}
|
explainer={labels.note.explainer}
|
||||||
currentSymptomValue={this.temperature}
|
>
|
||||||
saveAction={() => this.checkRangeAndSave()}
|
<AppTextInput
|
||||||
saveDisabled={
|
multiline={true}
|
||||||
this.state.temperature === '' ||
|
autoFocus={this.state.focusTextArea}
|
||||||
isNaN(Number(this.state.temperature)) ||
|
placeholder={sharedLabels.enter}
|
||||||
isInvalidTime(this.state.time)
|
value={this.state.note}
|
||||||
}
|
onChangeText={this.setNote}
|
||||||
navigate={this.props.navigate}
|
/>
|
||||||
autoShowDayView={false}
|
</SymptomSection>
|
||||||
/>
|
<SymptomSection
|
||||||
</View>
|
header={labels.exclude.header}
|
||||||
|
explainer={labels.exclude.explainer}
|
||||||
|
inline={true}
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
onValueChange={(val) => {
|
||||||
|
this.setState({ exclude: val })
|
||||||
|
}}
|
||||||
|
value={this.state.exclude}
|
||||||
|
/>
|
||||||
|
</SymptomSection>
|
||||||
|
</ScrollView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInvalidTime(timeString) {
|
|
||||||
try {
|
|
||||||
LocalTime.parse(timeString)
|
|
||||||
} catch (err) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,6 @@ import { Dimensions } from 'react-native'
|
|||||||
import CycleDayHeader from './cycle-day'
|
import CycleDayHeader from './cycle-day'
|
||||||
import DefaultHeader from './default'
|
import DefaultHeader from './default'
|
||||||
import BackButtonHeader from './back-button'
|
import BackButtonHeader from './back-button'
|
||||||
import SymptomViewHeader from './symptom-view'
|
|
||||||
|
|
||||||
export default function Header(p) {
|
export default function Header(p) {
|
||||||
const middle = Dimensions.get('window').width / 2
|
const middle = Dimensions.get('window').width / 2
|
||||||
@@ -11,11 +10,7 @@ export default function Header(p) {
|
|||||||
|
|
||||||
if (props.isCycleDayOverView) {
|
if (props.isCycleDayOverView) {
|
||||||
return (<CycleDayHeader {...props} />)
|
return (<CycleDayHeader {...props} />)
|
||||||
}
|
} else if (props.showBackButton) {
|
||||||
else if (props.isSymptomView) {
|
|
||||||
return (<SymptomViewHeader {...props} />)
|
|
||||||
}
|
|
||||||
else if (props.showBackButton) {
|
|
||||||
return (<BackButtonHeader {...props} />)
|
return (<BackButtonHeader {...props} />)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import React from 'react'
|
|||||||
import {
|
import {
|
||||||
View,
|
View,
|
||||||
Text,
|
Text,
|
||||||
TouchableOpacity
|
TouchableOpacity,
|
||||||
|
Dimensions
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import styles, { iconStyles } from '../../styles'
|
import styles, { iconStyles } from '../../styles'
|
||||||
import FeatherIcon from 'react-native-vector-icons/Feather'
|
import FeatherIcon from 'react-native-vector-icons/Feather'
|
||||||
@@ -10,11 +11,12 @@ import NavigationArrow from './navigation-arrow'
|
|||||||
import formatDate from '../helpers/format-date'
|
import formatDate from '../helpers/format-date'
|
||||||
|
|
||||||
export default function SymptomViewHeader(props) {
|
export default function SymptomViewHeader(props) {
|
||||||
|
const middle = Dimensions.get('window').width / 2
|
||||||
return (
|
return (
|
||||||
<View style={[styles.header, styles.headerCycleDay, styles.headerSymptom]}>
|
<View style={[styles.header, styles.headerCycleDay, styles.headerSymptom]}>
|
||||||
<View
|
<View
|
||||||
style={styles.accentCircle}
|
style={styles.accentCircle}
|
||||||
left={props.middle - styles.accentCircle.width / 2}
|
left={middle - styles.accentCircle.width / 2}
|
||||||
/>
|
/>
|
||||||
<NavigationArrow
|
<NavigationArrow
|
||||||
direction='left'
|
direction='left'
|
||||||
@@ -29,7 +31,7 @@ export default function SymptomViewHeader(props) {
|
|||||||
</Text>
|
</Text>
|
||||||
</View >
|
</View >
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => props.goToSymptomInfo()}
|
onPress={props.deleteEntry}
|
||||||
style={styles.infoButton}
|
style={styles.infoButton}
|
||||||
>
|
>
|
||||||
<FeatherIcon
|
<FeatherIcon
|
||||||
|
|||||||
+171
@@ -0,0 +1,171 @@
|
|||||||
|
const TemperatureSchema = {
|
||||||
|
name: 'Temperature',
|
||||||
|
properties: {
|
||||||
|
value: 'double',
|
||||||
|
exclude: 'bool',
|
||||||
|
time: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
note: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BleedingSchema = {
|
||||||
|
name: 'Bleeding',
|
||||||
|
properties: {
|
||||||
|
value: 'int',
|
||||||
|
exclude: 'bool'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MucusSchema = {
|
||||||
|
name: 'Mucus',
|
||||||
|
properties: {
|
||||||
|
feeling: { type: 'int', optional: true },
|
||||||
|
texture: { type: 'int', optional: true },
|
||||||
|
value: { type: 'int', optional: true },
|
||||||
|
exclude: 'bool'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CervixSchema = {
|
||||||
|
name: 'Cervix',
|
||||||
|
properties: {
|
||||||
|
opening: { type: 'int', optional: true },
|
||||||
|
firmness: { type: 'int', optional: true },
|
||||||
|
position: {type: 'int', optional: true },
|
||||||
|
exclude: 'bool'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NoteSchema = {
|
||||||
|
name: 'Note',
|
||||||
|
properties: {
|
||||||
|
value: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const DesireSchema = {
|
||||||
|
name: 'Desire',
|
||||||
|
properties: {
|
||||||
|
value: 'int'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const SexSchema = {
|
||||||
|
name: 'Sex',
|
||||||
|
properties: {
|
||||||
|
solo: { type: 'bool', optional: true },
|
||||||
|
partner: { type: 'bool', optional: true },
|
||||||
|
condom: { type: 'bool', optional: true },
|
||||||
|
pill: { type: 'bool', optional: true },
|
||||||
|
iud: { type: 'bool', optional: true },
|
||||||
|
patch: { type: 'bool', optional: true },
|
||||||
|
ring: { type: 'bool', optional: true },
|
||||||
|
implant: { type: 'bool', optional: true },
|
||||||
|
diaphragm: { type: 'bool', optional: true },
|
||||||
|
none: { type: 'bool', optional: true },
|
||||||
|
other: { type: 'bool', optional: true },
|
||||||
|
note: { type: 'string', optional: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const PainSchema = {
|
||||||
|
name: 'Pain',
|
||||||
|
properties: {
|
||||||
|
cramps: { type: 'bool', optional: true },
|
||||||
|
ovulationPain: { type: 'bool', optional: true },
|
||||||
|
headache: { type: 'bool', optional: true },
|
||||||
|
backache: { type: 'bool', optional: true },
|
||||||
|
nausea: { type: 'bool', optional: true },
|
||||||
|
tenderBreasts: { type: 'bool', optional: true },
|
||||||
|
migraine: { type: 'bool', optional: true },
|
||||||
|
other: { type: 'bool', optional: true },
|
||||||
|
note: { type: 'string', optional: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const MoodSchema = {
|
||||||
|
name: 'Mood',
|
||||||
|
properties: {
|
||||||
|
happy: { type: 'bool', optional: true },
|
||||||
|
sad: { type: 'bool', optional: true },
|
||||||
|
stressed: { type: 'bool', optional: true },
|
||||||
|
balanced: { type: 'bool', optional: true },
|
||||||
|
fine: { type: 'bool', optional: true },
|
||||||
|
anxious: { type: 'bool', optional: true },
|
||||||
|
energetic: { type: 'bool', optional: true },
|
||||||
|
fatigue: { type: 'bool', optional: true },
|
||||||
|
angry: { type: 'bool', optional: true },
|
||||||
|
other: { type: 'bool', optional: true },
|
||||||
|
note: { type: 'string', optional: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CycleDaySchema = {
|
||||||
|
name: 'CycleDay',
|
||||||
|
primaryKey: 'date',
|
||||||
|
properties: {
|
||||||
|
date: 'string',
|
||||||
|
temperature: {
|
||||||
|
type: 'Temperature',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
isCycleStart: 'bool',
|
||||||
|
bleeding: {
|
||||||
|
type: 'Bleeding',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
mucus: {
|
||||||
|
type: 'Mucus',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
cervix: {
|
||||||
|
type: 'Cervix',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
note: {
|
||||||
|
type: 'Note',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
desire: {
|
||||||
|
type: 'Desire',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
sex: {
|
||||||
|
type: 'Sex',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
pain: {
|
||||||
|
type: 'Pain',
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
mood: {
|
||||||
|
type: 'Mood',
|
||||||
|
optional: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
schema: [
|
||||||
|
CycleDaySchema,
|
||||||
|
TemperatureSchema,
|
||||||
|
BleedingSchema,
|
||||||
|
MucusSchema,
|
||||||
|
CervixSchema,
|
||||||
|
NoteSchema,
|
||||||
|
DesireSchema,
|
||||||
|
SexSchema,
|
||||||
|
PainSchema,
|
||||||
|
MoodSchema
|
||||||
|
],
|
||||||
|
schemaVersion: 4,
|
||||||
|
migration: (oldRealm) => {
|
||||||
|
if (oldRealm.schemaVersion >= 4) return
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-1
@@ -2,5 +2,6 @@ import schema0 from './0.js'
|
|||||||
import schema1 from './1.js'
|
import schema1 from './1.js'
|
||||||
import schema2 from './2.js'
|
import schema2 from './2.js'
|
||||||
import schema3 from './3.js'
|
import schema3 from './3.js'
|
||||||
|
import schema4 from './4.js'
|
||||||
|
|
||||||
export default [schema0, schema1, schema2, schema3]
|
export default [schema0, schema1, schema2, schema3, schema4]
|
||||||
+9
-9
@@ -32,15 +32,15 @@ export const headerTitles = {
|
|||||||
Password: settingsTitles.password,
|
Password: settingsTitles.password,
|
||||||
About: settingsTitles.about,
|
About: settingsTitles.about,
|
||||||
License: settingsTitles.license,
|
License: settingsTitles.license,
|
||||||
BleedingEditView: 'Bleeding',
|
bleeding: 'Bleeding',
|
||||||
TemperatureEditView: 'Temperature',
|
temperature: 'Temperature',
|
||||||
MucusEditView: 'Mucus',
|
mucus: 'Mucus',
|
||||||
CervixEditView: 'Cervix',
|
cervix: 'Cervix',
|
||||||
NoteEditView: 'Note',
|
note: 'Note',
|
||||||
DesireEditView: 'Desire',
|
desire: 'Desire',
|
||||||
SexEditView: 'Sex',
|
sex: 'Sex',
|
||||||
PainEditView: 'Pain',
|
pain: 'Pain',
|
||||||
MoodEditView: 'Mood',
|
mood: 'Mood',
|
||||||
InfoSymptom: 'Info'
|
InfoSymptom: 'Info'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
export default function (feeling, texture) {
|
export default function (feeling, texture) {
|
||||||
|
|
||||||
|
if (typeof feeling != 'number' || typeof texture != 'number') return null
|
||||||
|
|
||||||
const feelingMapping = {
|
const feelingMapping = {
|
||||||
0: 0,
|
0: 0,
|
||||||
1: 1,
|
1: 1,
|
||||||
|
|||||||
+13
-1
@@ -108,7 +108,15 @@ function formatCycleForSympto(cycle) {
|
|||||||
if (day[symptomName] && day[symptomName].exclude) {
|
if (day[symptomName] && day[symptomName].exclude) {
|
||||||
delete day[symptomName]
|
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
|
// change format
|
||||||
['bleeding', 'temperature', 'mucus'].forEach(symptomName => {
|
['bleeding', 'temperature', 'mucus'].forEach(symptomName => {
|
||||||
if (day[symptomName]) day[symptomName] = day[symptomName].value
|
if (day[symptomName]) day[symptomName] = day[symptomName].value
|
||||||
@@ -120,3 +128,7 @@ function formatCycleForSympto(cycle) {
|
|||||||
formatted.reverse()
|
formatted.reverse()
|
||||||
return formatted
|
return formatted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasIncompleteCervixValue(day) {
|
||||||
|
return day.cervix && (typeof day.cervix.opening != 'number' || typeof day.cervix.firmness != 'number')
|
||||||
|
}
|
||||||
Generated
+14
-33
@@ -3229,8 +3229,7 @@
|
|||||||
},
|
},
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"aproba": {
|
"aproba": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
@@ -3248,13 +3247,11 @@
|
|||||||
},
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
@@ -3267,18 +3264,15 @@
|
|||||||
},
|
},
|
||||||
"code-point-at": {
|
"code-point-at": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"core-util-is": {
|
"core-util-is": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
@@ -3381,8 +3375,7 @@
|
|||||||
},
|
},
|
||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.5",
|
||||||
@@ -3392,7 +3385,6 @@
|
|||||||
"is-fullwidth-code-point": {
|
"is-fullwidth-code-point": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"number-is-nan": "^1.0.0"
|
"number-is-nan": "^1.0.0"
|
||||||
}
|
}
|
||||||
@@ -3405,20 +3397,17 @@
|
|||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"minipass": {
|
"minipass": {
|
||||||
"version": "2.3.5",
|
"version": "2.3.5",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"safe-buffer": "^5.1.2",
|
"safe-buffer": "^5.1.2",
|
||||||
"yallist": "^3.0.0"
|
"yallist": "^3.0.0"
|
||||||
@@ -3435,7 +3424,6 @@
|
|||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.1",
|
"version": "0.5.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "0.0.8"
|
"minimist": "0.0.8"
|
||||||
}
|
}
|
||||||
@@ -3508,8 +3496,7 @@
|
|||||||
},
|
},
|
||||||
"number-is-nan": {
|
"number-is-nan": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
@@ -3519,7 +3506,6 @@
|
|||||||
"once": {
|
"once": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
@@ -3595,8 +3581,7 @@
|
|||||||
},
|
},
|
||||||
"safe-buffer": {
|
"safe-buffer": {
|
||||||
"version": "5.1.2",
|
"version": "5.1.2",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"safer-buffer": {
|
"safer-buffer": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
@@ -3626,7 +3611,6 @@
|
|||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"code-point-at": "^1.0.0",
|
"code-point-at": "^1.0.0",
|
||||||
"is-fullwidth-code-point": "^1.0.0",
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
@@ -3644,7 +3628,6 @@
|
|||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"bundled": true,
|
"bundled": true,
|
||||||
"optional": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^2.0.0"
|
"ansi-regex": "^2.0.0"
|
||||||
}
|
}
|
||||||
@@ -3683,13 +3666,11 @@
|
|||||||
},
|
},
|
||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"yallist": {
|
"yallist": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"bundled": true,
|
"bundled": true
|
||||||
"optional": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -8097,9 +8078,9 @@
|
|||||||
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
|
||||||
},
|
},
|
||||||
"sympto": {
|
"sympto": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/sympto/-/sympto-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/sympto/-/sympto-1.0.4.tgz",
|
||||||
"integrity": "sha512-wLDpugvScuXhSBhgJHZTGU9gTd5uDnuZDJuNz7aUSj1N28VOe2RhKwMF4RLwjy3s6i+BG1Lfa3uckNPCFPkUvA==",
|
"integrity": "sha512-FSdSwPeE3BKvnJlPkHzVusGMTz4r6dW2eEEJbgPrgdkmPWmAFWTD7Hf7OhqQSbTLjiZY7jBeWDWuizb4UZMk1g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"js-joda": "^1.9.2"
|
"js-joda": "^1.9.2"
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -46,7 +46,7 @@
|
|||||||
"react-native-share": "^1.1.3",
|
"react-native-share": "^1.1.3",
|
||||||
"react-native-vector-icons": "^5.0.0",
|
"react-native-vector-icons": "^5.0.0",
|
||||||
"realm": "^2.22.0",
|
"realm": "^2.22.0",
|
||||||
"sympto": "^1.0.0"
|
"sympto": "^1.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.2.2",
|
"@babel/core": "^7.2.2",
|
||||||
|
|||||||
@@ -7,6 +7,11 @@ chai.use(dirtyChai)
|
|||||||
import getSensiplanMucus from '../lib/nfp-mucus'
|
import getSensiplanMucus from '../lib/nfp-mucus'
|
||||||
|
|
||||||
describe('getSensiplanMucus', () => {
|
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:', () => {
|
describe('results in t for:', () => {
|
||||||
it('dry feeling and no texture', function () {
|
it('dry feeling and no texture', function () {
|
||||||
|
|||||||
Reference in New Issue
Block a user