Merge branch '540-Temperature-value-cannot-be-entered-with-comma' into 'master'

Resolve "Bug: Temperature value cannot be entered with comma"

Closes #540

See merge request bloodyhealth/drip!390
This commit is contained in:
bl00dymarie
2022-04-15 19:23:04 +00:00
4 changed files with 324 additions and 324 deletions
+40 -43
View File
@@ -23,12 +23,11 @@ import info from '../../i18n/en/symptom-info'
import { Colors, Containers, Sizes, Spacing } from '../../styles' import { Colors, Containers, Sizes, Spacing } from '../../styles'
class SymptomEditView extends Component { class SymptomEditView extends Component {
static propTypes = { static propTypes = {
date: PropTypes.string.isRequired, date: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
symptom: PropTypes.string.isRequired, symptom: PropTypes.string.isRequired,
symptomData: PropTypes.object symptomData: PropTypes.object,
} }
constructor(props) { constructor(props) {
@@ -49,7 +48,7 @@ class SymptomEditView extends Component {
shouldShowInfo: false, shouldShowInfo: false,
shouldShowNote, shouldShowNote,
shouldBoxGroup, shouldBoxGroup,
shouldTabGroup shouldTabGroup,
} }
} }
@@ -97,8 +96,8 @@ class SymptomEditView extends Component {
onSaveTemperature = (value, field) => { onSaveTemperature = (value, field) => {
const data = this.getParsedData() const data = this.getParsedData()
const dataToSave = field === 'value' const dataToSave =
? { [field]: Number(value) } : { [field]: value } field === 'value' ? { [field]: Number(value) } : { [field]: value }
Object.assign(data, { ...dataToSave }) Object.assign(data, { ...dataToSave })
this.setState({ data }) this.setState({ data })
@@ -106,10 +105,10 @@ class SymptomEditView extends Component {
onSelectBox = (key) => { onSelectBox = (key) => {
const data = this.getParsedData() const data = this.getParsedData()
if (key === "other") { if (key === 'other') {
Object.assign(data, { Object.assign(data, {
note: null, note: null,
[key]: !this.state.data[key] [key]: !this.state.data[key],
}) })
} else { } else {
Object.assign(data, { [key]: !this.state.data[key] }) Object.assign(data, { [key]: !this.state.data[key] })
@@ -147,12 +146,13 @@ class SymptomEditView extends Component {
render() { render() {
const { symptom } = this.props const { symptom } = this.props
const { data, const {
data,
shouldShowExclude, shouldShowExclude,
shouldShowInfo, shouldShowInfo,
shouldShowNote, shouldShowNote,
shouldBoxGroup, shouldBoxGroup,
shouldTabGroup shouldTabGroup,
} = this.state } = this.state
const iconName = shouldShowInfo ? 'chevron-up' : 'chevron-down' const iconName = shouldShowInfo ? 'chevron-up' : 'chevron-down'
const noteText = symptom === 'note' ? data.value : data.note const noteText = symptom === 'note' ? data.value : data.note
@@ -166,52 +166,52 @@ class SymptomEditView extends Component {
<View style={styles.headerContainer}> <View style={styles.headerContainer}>
<CloseIcon onClose={this.closeView} /> <CloseIcon onClose={this.closeView} />
</View> </View>
{symptom === 'temperature' && {symptom === 'temperature' && (
<Temperature <Temperature
data={data} data={data}
save={(value, field) => this.onSaveTemperature(value, field)} save={(value, field) => this.onSaveTemperature(value, field)}
/> />
} )}
{shouldTabGroup && symtomPage[symptom].selectTabGroups.map(group => { {shouldTabGroup &&
symtomPage[symptom].selectTabGroups.map((group) => {
return ( return (
<Segment key={group.key} style={styles.segmentBorder}> <Segment key={group.key} style={styles.segmentBorder}>
<AppText style={styles.title}>{group.title}</AppText> <AppText style={styles.title}>{group.title}</AppText>
<SelectTabGroup <SelectTabGroup
activeButton={data[group.key]} activeButton={data[group.key]}
buttons={group.options} buttons={group.options}
onSelect={value => this.onSelectTab(group, value)} onSelect={(value) => this.onSelectTab(group, value)}
/> />
</Segment> </Segment>
) )
}) })}
} {shouldBoxGroup &&
{shouldBoxGroup && symtomPage[symptom].selectBoxGroups.map(group => { symtomPage[symptom].selectBoxGroups.map((group) => {
const isOtherSelected = const isOtherSelected =
data['other'] !== null data['other'] !== null &&
&& data['other'] !== false data['other'] !== false &&
&& Object.keys(group.options).includes('other') Object.keys(group.options).includes('other')
return ( return (
<Segment key={group.key} style={styles.segmentBorder}> <Segment key={group.key} style={styles.segmentBorder}>
<AppText style={styles.title}>{group.title}</AppText> <AppText style={styles.title}>{group.title}</AppText>
<SelectBoxGroup <SelectBoxGroup
labels={group.options} labels={group.options}
onSelect={value => this.onSelectBox(value)} onSelect={(value) => this.onSelectBox(value)}
optionsState={data} optionsState={data}
/> />
{isOtherSelected && {isOtherSelected && (
<AppTextInput <AppTextInput
multiline={true} multiline={true}
placeholder={sharedLabels.enter} placeholder={sharedLabels.enter}
value={data.note} value={data.note}
onChangeText={value => this.onSelectBoxNote(value)} onChangeText={(value) => this.onSelectBoxNote(value)}
/> />
} )}
</Segment> </Segment>
) )
}) })}
} {shouldShowExclude && (
{shouldShowExclude &&
<Segment style={styles.segmentBorder}> <Segment style={styles.segmentBorder}>
<AppSwitch <AppSwitch
onToggle={this.onExcludeToggle} onToggle={this.onExcludeToggle}
@@ -219,8 +219,8 @@ class SymptomEditView extends Component {
value={data.exclude} value={data.exclude}
/> />
</Segment> </Segment>
} )}
{shouldShowNote && {shouldShowNote && (
<Segment style={styles.segmentBorder}> <Segment style={styles.segmentBorder}>
<AppText>{symtomPage[symptom].note}</AppText> <AppText>{symtomPage[symptom].note}</AppText>
<AppTextInput <AppTextInput
@@ -228,11 +228,11 @@ class SymptomEditView extends Component {
numberOfLines={3} numberOfLines={3}
onChangeText={this.onEditNote} onChangeText={this.onEditNote}
placeholder={sharedLabels.enter} placeholder={sharedLabels.enter}
testID='noteInput' testID="noteInput"
value={noteText !== null ? noteText : ''} value={noteText !== null ? noteText : ''}
/> />
</Segment> </Segment>
} )}
<View style={styles.buttonsContainer}> <View style={styles.buttonsContainer}>
<Button iconName={iconName} isSmall onPress={this.onPressLearnMore}> <Button iconName={iconName} isSmall onPress={this.onPressLearnMore}>
{sharedLabels.learnMore} {sharedLabels.learnMore}
@@ -244,11 +244,11 @@ class SymptomEditView extends Component {
{sharedLabels.save} {sharedLabels.save}
</Button> </Button>
</View> </View>
{shouldShowInfo && {shouldShowInfo && (
<Segment last style={styles.segmentBorder}> <Segment last style={styles.segmentBorder}>
<AppText>{info[symptom].text}</AppText> <AppText>{info[symptom].text}</AppText>
</Segment> </Segment>
} )}
</ScrollView> </ScrollView>
</AppModal> </AppModal>
) )
@@ -257,7 +257,7 @@ class SymptomEditView extends Component {
const styles = StyleSheet.create({ const styles = StyleSheet.create({
buttonsContainer: { buttonsContainer: {
...Containers.rowContainer ...Containers.rowContainer,
}, },
headerContainer: { headerContainer: {
flexDirection: 'row', flexDirection: 'row',
@@ -275,23 +275,20 @@ const styles = StyleSheet.create({
marginVertical: Sizes.huge * 2, marginVertical: Sizes.huge * 2,
position: 'absolute', position: 'absolute',
minHeight: '40%', minHeight: '40%',
maxHeight: Dimensions.get('window').height * 0.7 maxHeight: Dimensions.get('window').height * 0.7,
}, },
segmentBorder: { segmentBorder: {
borderBottomColor: Colors.greyLight borderBottomColor: Colors.greyLight,
}, },
title: { title: {
fontSize: Sizes.subtitle fontSize: Sizes.subtitle,
} },
}) })
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return({ return {
date: getDate(state), date: getDate(state),
}) }
} }
export default connect( export default connect(mapStateToProps, null)(SymptomEditView)
mapStateToProps,
null,
)(SymptomEditView)
+54 -87
View File
@@ -1,4 +1,4 @@
import React, { Component } from 'react' import React, { useEffect, useState } from 'react'
import { Platform, StyleSheet, View } from 'react-native' import { Platform, StyleSheet, View } from 'react-native'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Keyboard } from 'react-native' import { Keyboard } from 'react-native'
@@ -11,86 +11,52 @@ import Segment from '../common/segment'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { getDate } from '../../slices/date' import { getDate } from '../../slices/date'
import { isTemperatureOutOfRange, isPreviousTemperature } from '../helpers/cycle-day' import {
getTemperatureOutOfRangeMessage,
getPreviousTemperature,
formatTemperature,
} from '../helpers/cycle-day'
import { temperature as labels } from '../../i18n/en/cycle-day' import { temperature as labels } from '../../i18n/en/cycle-day'
import { Colors, Containers, Sizes, Spacing } from '../../styles' import { Colors, Containers, Sizes, Spacing } from '../../styles'
const formatTemperature = value => value === null const Temperature = ({ data, date, save }) => {
? value const [isTimePickerVisible, setIsTimePickerVisible] = useState(false)
: Number.parseFloat(value).toFixed(2) const [temperature, setTemperature] = useState(
formatTemperature(data.value) || getPreviousTemperature(date)
)
class Temperature extends Component { // update state in parent component once to ensure
// that pre-filled values are saved on button click
useEffect(() => {
if (temperature) {
save(temperature, 'value')
}
}, [])
static propTypes = { function onChangeTemperature(value) {
data: PropTypes.object, const formattedValue = value.replace(',', '.').trim()
date: PropTypes.string.isRequired, if (!Number(formattedValue) && value !== '') return false
save: PropTypes.func setTemperature(formattedValue)
} }
constructor(props) { function onShowTimePicker() {
super(props)
const { data, date } = this.props
const { value } = data
const { shouldShowSuggestion, suggestedTemperature } =
isPreviousTemperature(date)
this.state = {
isTimePickerVisible: false,
shouldShowSuggestion,
suggestedTemperature: formatTemperature(suggestedTemperature),
value: formatTemperature(value)
}
}
onCancelTimePicker = () => {
this.setState({ isTimePickerVisible: false })
}
onChangeTemperature = (value) => {
if (!Number(value)) return false
this.setState({
value: value.trim(),
shouldShowSuggestion: false
})
}
onShowTimePicker = () => {
Keyboard.dismiss() Keyboard.dismiss()
this.setState({ isTimePickerVisible: true }) setIsTimePickerVisible(true)
} }
setTemperature = () => { function setTime(jsDate) {
const { value } = this.state
this.props.save(value, 'value')
}
setTime = (jsDate) => {
const time = moment(jsDate).format('HH:mm') const time = moment(jsDate).format('HH:mm')
const isTimePickerVisible = false
this.props.save(time, 'time') save(time, 'time')
this.setState({ isTimePickerVisible }) setIsTimePickerVisible(false)
} }
render() { const { time } = data
const { shouldShowSuggestion, suggestedTemperature, value } = this.state
const { time } = this.props.data
const inputStyle = (shouldShowSuggestion && value === null) const inputStyle = { color: Colors.greyDark }
? { color: Colors.grey } const outOfRangeWarning = getTemperatureOutOfRangeMessage(temperature)
: {color: Colors.greyDark}
const outOfRangeWarning = isTemperatureOutOfRange(value)
let temperatureToShow = null
if (value) {
temperatureToShow = value
} else if (shouldShowSuggestion) {
temperatureToShow = suggestedTemperature
}
return ( return (
<React.Fragment> <React.Fragment>
@@ -98,9 +64,9 @@ class Temperature extends Component {
<AppText style={styles.title}>{labels.temperature.explainer}</AppText> <AppText style={styles.title}>{labels.temperature.explainer}</AppText>
<View style={styles.container}> <View style={styles.container}>
<AppTextInput <AppTextInput
value={temperatureToShow === null ? '' : temperatureToShow} value={temperature}
onChangeText={this.onChangeTemperature} onChangeText={onChangeTemperature}
onEndEditing={this.setTemperature} onEndEditing={() => save(temperature, 'value')}
keyboardType="numeric" keyboardType="numeric"
maxLength={5} maxLength={5}
style={inputStyle} style={inputStyle}
@@ -109,56 +75,57 @@ class Temperature extends Component {
/> />
<AppText>°C</AppText> <AppText>°C</AppText>
</View> </View>
{ outOfRangeWarning !== null && {!!outOfRangeWarning && (
<View style={styles.hintContainer}> <View style={styles.hintContainer}>
<AppText style={styles.hint}>{outOfRangeWarning}</AppText> <AppText style={styles.hint}>{outOfRangeWarning}</AppText>
</View> </View>
} )}
</Segment> </Segment>
<Segment> <Segment>
<AppText style={styles.title}>{labels.time}</AppText> <AppText style={styles.title}>{labels.time}</AppText>
<AppTextInput <AppTextInput
onFocus={this.onShowTimePicker} onFocus={onShowTimePicker}
testID='timeInput' testID="timeInput"
value={time} value={time}
/> />
<DateTimePicker <DateTimePicker
isVisible={this.state.isTimePickerVisible} isVisible={isTimePickerVisible}
mode="time" mode="time"
onConfirm={this.setTime} onConfirm={setTime}
onCancel={this.onCancelTimePicker} onCancel={() => setIsTimePickerVisible(false)}
display={Platform.OS === "ios" ? "spinner" : "default"} display={Platform.OS === 'ios' ? 'spinner' : 'default'}
/> />
</Segment> </Segment>
</React.Fragment> </React.Fragment>
) )
} }
}
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
...Containers.rowContainer ...Containers.rowContainer,
}, },
hint: { hint: {
fontStyle: 'italic', fontStyle: 'italic',
fontSize: Sizes.small fontSize: Sizes.small,
}, },
hintContainer: { hintContainer: {
marginVertical: Spacing.tiny marginVertical: Spacing.tiny,
}, },
title: { title: {
fontSize: Sizes.subtitle fontSize: Sizes.subtitle,
} },
}) })
Temperature.propTypes = {
data: PropTypes.object.isRequired,
date: PropTypes.string.isRequired,
save: PropTypes.func.isRequired,
}
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return({ return {
date: getDate(state), date: getDate(state),
}) }
} }
export default connect( export default connect(mapStateToProps, null)(Temperature)
mapStateToProps,
null,
)(Temperature)
+118 -93
View File
@@ -1,6 +1,6 @@
import { ChronoUnit, LocalDate, LocalTime } from 'js-joda' import { ChronoUnit, LocalDate, LocalTime } from 'js-joda'
import { getPreviousTemperature, saveSymptom } from '../../db' import { getPreviousTemperatureForDate, saveSymptom } from '../../db'
import { scaleObservable } from '../../local-storage' import { scaleObservable } from '../../local-storage'
import * as labels from '../../i18n/en/cycle-day' import * as labels from '../../i18n/en/cycle-day'
@@ -23,39 +23,35 @@ const temperatureLabels = labels.temperature
const minutes = ChronoUnit.MINUTES const minutes = ChronoUnit.MINUTES
const isNumber = (value) => typeof value === 'number' const isNumber = (value) => typeof value === 'number'
export const shouldShow = (value) => value !== null ? true : false export const shouldShow = (value) => (value !== null ? true : false)
export const isPreviousTemperature = (temperature) => { export const formatTemperature = (temperature) =>
const previousTemperature = getPreviousTemperature(temperature) !temperature
const shouldShowSuggestion = previousTemperature ? true : false ? temperature
const suggestedTemperature = previousTemperature ? : Number.parseFloat(temperature.toString()).toFixed(2)
previousTemperature.toString() : null
return { shouldShowSuggestion, suggestedTemperature } export const getPreviousTemperature = (date) => {
const previousTemperature = getPreviousTemperatureForDate(date)
return formatTemperature(previousTemperature)
} }
export const isTemperatureOutOfRange = (temperature) => { export const getTemperatureOutOfRangeMessage = (temperature) => {
if (!temperature) return null if (!temperature) return null
const value = Number(temperature) const value = Number(temperature)
const range = { min: TEMP_MIN, max: TEMP_MAX }
const scale = scaleObservable.value const scale = scaleObservable.value
let warningMsg = null return value < TEMP_MIN || value > TEMP_MAX
? labels.temperature.outOfAbsoluteRangeWarning
if (value < range.min || value > range.max) { : value < scale.min || value > scale.max
warningMsg = labels.temperature.outOfAbsoluteRangeWarning ? labels.temperature.outOfRangeWarning
} else if (value < scale.min || value > scale.max) { : ''
warningMsg = labels.temperature.outOfRangeWarning
}
return warningMsg
} }
export const blank = { export const blank = {
bleeding: { bleeding: {
exclude: false, exclude: false,
value: null value: null,
}, },
cervix: { cervix: {
exclude: false, exclude: false,
@@ -64,7 +60,7 @@ export const blank = {
position: null, position: null,
}, },
desire: { desire: {
value: null value: null,
}, },
mood: { mood: {
happy: null, happy: null,
@@ -77,16 +73,16 @@ export const blank = {
fatigue: null, fatigue: null,
angry: null, angry: null,
other: null, other: null,
note: null note: null,
}, },
mucus: { mucus: {
exclude: false, exclude: false,
feeling: null, feeling: null,
texture: null, texture: null,
value: null value: null,
}, },
note: { note: {
value: null value: null,
}, },
pain: { pain: {
cramps: null, cramps: null,
@@ -97,7 +93,7 @@ export const blank = {
tenderBreasts: null, tenderBreasts: null,
migraine: null, migraine: null,
other: null, other: null,
note: null note: null,
}, },
sex: { sex: {
solo: null, solo: null,
@@ -111,14 +107,14 @@ export const blank = {
diaphragm: null, diaphragm: null,
none: null, none: null,
other: null, other: null,
note: null note: null,
}, },
temperature: { temperature: {
exclude: false, exclude: false,
note: null, note: null,
time: LocalTime.now().truncatedTo(minutes).toString(), time: LocalTime.now().truncatedTo(minutes).toString(),
value: null value: null,
} },
} }
export const symtomPage = { export const symtomPage = {
@@ -126,11 +122,13 @@ export const symtomPage = {
excludeText: labels.bleeding.exclude.explainer, excludeText: labels.bleeding.exclude.explainer,
note: null, note: null,
selectBoxGroups: null, selectBoxGroups: null,
selectTabGroups: [{ selectTabGroups: [
{
key: 'value', key: 'value',
options: getLabelsList(bleedingLabels), options: getLabelsList(bleedingLabels),
title: labels.bleeding.heaviness.explainer, title: labels.bleeding.heaviness.explainer,
}] },
],
}, },
cervix: { cervix: {
excludeText: cervixLabels.excludeExplainer, excludeText: cervixLabels.excludeExplainer,
@@ -151,18 +149,20 @@ export const symtomPage = {
key: 'position', key: 'position',
options: getLabelsList(cervixLabels.position.categories), options: getLabelsList(cervixLabels.position.categories),
title: cervixLabels.position.explainer, title: cervixLabels.position.explainer,
} },
] ],
}, },
desire: { desire: {
excludeText: null, excludeText: null,
note: null, note: null,
selectBoxGroups: null, selectBoxGroups: null,
selectTabGroups: [{ selectTabGroups: [
{
key: 'value', key: 'value',
options: getLabelsList(intensityLabels), options: getLabelsList(intensityLabels),
title: labels.desire.explainer title: labels.desire.explainer,
}] },
],
}, },
mucus: { mucus: {
excludeText: mucusLabels.excludeExplainer, excludeText: mucusLabels.excludeExplainer,
@@ -178,34 +178,38 @@ export const symtomPage = {
key: 'texture', key: 'texture',
options: getLabelsList(mucusLabels.texture.categories), options: getLabelsList(mucusLabels.texture.categories),
title: mucusLabels.texture.explainer, title: mucusLabels.texture.explainer,
} },
] ],
}, },
mood: { mood: {
excludeText: null, excludeText: null,
note: null, note: null,
selectBoxGroups: [{ selectBoxGroups: [
{
key: 'mood', key: 'mood',
options: moodLabels, options: moodLabels,
title: labels.mood.explainer title: labels.mood.explainer,
}], },
selectTabGroups: null ],
selectTabGroups: null,
}, },
note: { note: {
excludeText: null, excludeText: null,
note: noteDescription, note: noteDescription,
selectBoxGroups: null, selectBoxGroups: null,
selectTabGroups: null selectTabGroups: null,
}, },
pain: { pain: {
excludeText: null, excludeText: null,
note: null, note: null,
selectBoxGroups: [{ selectBoxGroups: [
{
key: 'pain', key: 'pain',
options: painLabels, options: painLabels,
title: labels.pain.explainer title: labels.pain.explainer,
}], },
selectTabGroups: null ],
selectTabGroups: null,
}, },
sex: { sex: {
excludeText: null, excludeText: null,
@@ -220,40 +224,42 @@ export const symtomPage = {
key: 'contraceptives', key: 'contraceptives',
options: contraceptiveLabels, options: contraceptiveLabels,
title: labels.contraceptives.explainer, title: labels.contraceptives.explainer,
} },
], ],
selectTabGroups: null selectTabGroups: null,
}, },
temperature: { temperature: {
excludeText: temperatureLabels.exclude.explainer, excludeText: temperatureLabels.exclude.explainer,
note: temperatureLabels.note.explainer, note: temperatureLabels.note.explainer,
selectBoxGroups: null, selectBoxGroups: null,
selectTabGroups: null selectTabGroups: null,
} },
} }
export const save = { export const save = {
bleeding: (data, date, shouldDeleteData) => { bleeding: (data, date, shouldDeleteData) => {
const { exclude, value } = data const { exclude, value } = data
const isDataEntered = isNumber(value) const isDataEntered = isNumber(value)
const valuesToSave = shouldDeleteData || !isDataEntered const valuesToSave =
? null : { value, exclude } shouldDeleteData || !isDataEntered ? null : { value, exclude }
saveSymptom('bleeding', date, valuesToSave) saveSymptom('bleeding', date, valuesToSave)
}, },
cervix: (data, date, shouldDeleteData) => { cervix: (data, date, shouldDeleteData) => {
const { opening, firmness, position, exclude } = data const { opening, firmness, position, exclude } = data
const isDataEntered = ['opening', 'firmness', 'position'].some( const isDataEntered = ['opening', 'firmness', 'position'].some((value) =>
value => isNumber(data[value])) isNumber(data[value])
const valuesToSave = shouldDeleteData || !isDataEntered )
? null : { opening, firmness, position, exclude } const valuesToSave =
shouldDeleteData || !isDataEntered
? null
: { opening, firmness, position, exclude }
saveSymptom('cervix', date, valuesToSave) saveSymptom('cervix', date, valuesToSave)
}, },
desire: (data, date, shouldDeleteData) => { desire: (data, date, shouldDeleteData) => {
const { value } = data const { value } = data
const valuesToSave = shouldDeleteData || !isNumber(value) const valuesToSave = shouldDeleteData || !isNumber(value) ? null : { value }
? null : { value }
saveSymptom('desire', date, valuesToSave) saveSymptom('desire', date, valuesToSave)
}, },
@@ -262,11 +268,18 @@ export const save = {
}, },
mucus: (data, date, shouldDeleteData) => { mucus: (data, date, shouldDeleteData) => {
const { feeling, texture, exclude } = data const { feeling, texture, exclude } = data
const isDataEntered = ['feeling', 'texture'].some( const isDataEntered = ['feeling', 'texture'].some((value) =>
value => isNumber(data[value])) isNumber(data[value])
const valuesToSave = shouldDeleteData || !isDataEntered )
const valuesToSave =
shouldDeleteData || !isDataEntered
? null ? null
: { feeling, texture, value: computeNfpValue(feeling, texture), exclude } : {
feeling,
texture,
value: computeNfpValue(feeling, texture),
exclude,
}
saveSymptom('mucus', date, valuesToSave) saveSymptom('mucus', date, valuesToSave)
}, },
@@ -289,21 +302,20 @@ export const save = {
exclude, exclude,
note, note,
time, time,
value: Number(value) value: Number(value),
} }
saveSymptom( saveSymptom(
'temperature', 'temperature',
date, date,
(shouldDeleteData || value === null) ? null : valuesToSave shouldDeleteData || value === null ? null : valuesToSave
) )
} },
} }
const saveBoxSymptom = (data, date, shouldDeleteData, symptom) => { const saveBoxSymptom = (data, date, shouldDeleteData, symptom) => {
const isDataEntered = Object.keys(data).some(key => data[key] !== null) const isDataEntered = Object.keys(data).some((key) => data[key] !== null)
const valuesToSave = shouldDeleteData || !isDataEntered const valuesToSave = shouldDeleteData || !isDataEntered ? null : data
? null : data
saveSymptom(symptom, date, valuesToSave) saveSymptom(symptom, date, valuesToSave)
} }
@@ -327,42 +339,55 @@ const label = {
return temperatureLabel return temperatureLabel
} }
}, },
mucus: mucus => { mucus: (mucus) => {
const filledCategories = ['feeling', 'texture'].filter(c => isNumber(mucus[c])) const filledCategories = ['feeling', 'texture'].filter((c) =>
let label = filledCategories.map(category => { isNumber(mucus[c])
return labels.mucus.subcategories[category] + ': ' + labels.mucus[category].categories[mucus[category]] )
}).join(', ') let label = filledCategories
.map((category) => {
return (
labels.mucus.subcategories[category] +
': ' +
labels.mucus[category].categories[mucus[category]]
)
})
.join(', ')
if (isNumber(mucus.value)) label += `\n => ${labels.mucusNFP[mucus.value]}` if (isNumber(mucus.value)) label += `\n => ${labels.mucusNFP[mucus.value]}`
if (mucus.exclude) label = `(${label})` if (mucus.exclude) label = `(${label})`
return label return label
}, },
cervix: cervix => { cervix: (cervix) => {
const filledCategories = ['opening', 'firmness', 'position'].filter(c => isNumber(cervix[c])) const filledCategories = ['opening', 'firmness', 'position'].filter((c) =>
let label = filledCategories.map(category => { isNumber(cervix[c])
return labels.cervix.subcategories[category] + ': ' + labels.cervix[category].categories[cervix[category]] )
}).join(', ') let label = filledCategories
.map((category) => {
return (
labels.cervix.subcategories[category] +
': ' +
labels.cervix[category].categories[cervix[category]]
)
})
.join(', ')
if (cervix.exclude) label = `(${label})` if (cervix.exclude) label = `(${label})`
return label return label
}, },
note: note => note.value, note: (note) => note.value,
desire: ({ value }) => { desire: ({ value }) => {
if (isNumber(value)) { if (isNumber(value)) {
return intensityLabels[value] return intensityLabels[value]
} }
}, },
sex: sex => { sex: (sex) => {
const sexLabel = [] const sexLabel = []
if (sex && Object.values({...sex}).some(val => val)){ if (sex && Object.values({ ...sex }).some((val) => val)) {
Object.keys(sex).forEach(key => { Object.keys(sex).forEach((key) => {
if (sex[key] && key !== 'other' && key !== 'note') { if (sex[key] && key !== 'other' && key !== 'note') {
sexLabel.push( sexLabel.push(sexLabels[key] || contraceptiveLabels[key])
sexLabels[key] ||
contraceptiveLabels[key]
)
} }
if (key === 'other' && sex.other) { if (key === 'other' && sex.other) {
let label = contraceptiveLabels[key] let label = contraceptiveLabels[key]
@@ -375,10 +400,10 @@ const label = {
return sexLabel.join(', ') return sexLabel.join(', ')
} }
}, },
pain: pain => { pain: (pain) => {
const painLabel = [] const painLabel = []
if (pain && Object.values({...pain}).some(val => val)){ if (pain && Object.values({ ...pain }).some((val) => val)) {
Object.keys(pain).forEach(key => { Object.keys(pain).forEach((key) => {
if (pain[key] && key !== 'other' && key !== 'note') { if (pain[key] && key !== 'other' && key !== 'note') {
painLabel.push(painLabels[key]) painLabel.push(painLabels[key])
} }
@@ -393,10 +418,10 @@ const label = {
return painLabel.join(', ') return painLabel.join(', ')
} }
}, },
mood: mood => { mood: (mood) => {
const moodLabel = [] const moodLabel = []
if (mood && Object.values({...mood}).some(val => val)){ if (mood && Object.values({ ...mood }).some((val) => val)) {
Object.keys(mood).forEach(key => { Object.keys(mood).forEach((key) => {
if (mood[key] && key !== 'other' && key !== 'note') { if (mood[key] && key !== 'other' && key !== 'note') {
moodLabel.push(moodLabels[key]) moodLabel.push(moodLabels[key])
} }
@@ -410,7 +435,7 @@ const label = {
}) })
return moodLabel.join(', ') return moodLabel.join(', ')
} }
} },
} }
export const getData = (symptom, symptomData) => { export const getData = (symptom, symptomData) => {
+30 -19
View File
@@ -36,20 +36,16 @@ export async function openDb (hash) {
let nextSchemaIndex = Realm.schemaVersion(Realm.defaultPath) let nextSchemaIndex = Realm.schemaVersion(Realm.defaultPath)
tempConnection.close() tempConnection.close()
while (nextSchemaIndex < schemas.length - 1) { while (nextSchemaIndex < schemas.length - 1) {
const tempConfig = Object.assign( const tempConfig = Object.assign(realmConfig, schemas[nextSchemaIndex++])
realmConfig,
schemas[nextSchemaIndex++]
)
const migratedRealm = new Realm(tempConfig) const migratedRealm = new Realm(tempConfig)
migratedRealm.close() migratedRealm.close()
} }
// open the Realm with the latest schema // open the Realm with the latest schema
realmConfig.schema = schemas[schemas.length - 1] realmConfig.schema = schemas[schemas.length - 1]
const connection = await Realm.open(Object.assign( const connection = await Realm.open(
realmConfig, Object.assign(realmConfig, schemas[schemas.length - 1])
schemas[schemas.length - 1] )
))
db = connection db = connection
const cycle = cycleModule() const cycle = cycleModule()
@@ -63,17 +59,26 @@ export function closeDb() {
} }
export function getBleedingDaysSortedByDate() { export function getBleedingDaysSortedByDate() {
return db.objects('CycleDay').filtered('bleeding != null').sorted('date', true) return db
.objects('CycleDay')
.filtered('bleeding != null')
.sorted('date', true)
} }
export function getTemperatureDaysSortedByDate() { export function getTemperatureDaysSortedByDate() {
return db.objects('CycleDay').filtered('temperature != null').sorted('date', true) return db
.objects('CycleDay')
.filtered('temperature != null')
.sorted('date', true)
} }
export function getCycleDaysSortedByDate() { export function getCycleDaysSortedByDate() {
return db.objects('CycleDay').sorted('date', true) return db.objects('CycleDay').sorted('date', true)
} }
export function getCycleStartsSortedByDate() { export function getCycleStartsSortedByDate() {
return db.objects('CycleDay').filtered('isCycleStart = true').sorted('date', true) return db
.objects('CycleDay')
.filtered('isCycleStart = true')
.sorted('date', true)
} }
export function saveSymptom(symptom, date, val) { export function saveSymptom(symptom, date, val) {
let cycleDay = getCycleDay(date) let cycleDay = getCycleDay(date)
@@ -83,7 +88,10 @@ export function saveSymptom(symptom, date, val) {
if (symptom === 'bleeding') { if (symptom === 'bleeding') {
const mensesDaysAfter = getMensesDaysRightAfter(cycleDay) const mensesDaysAfter = getMensesDaysRightAfter(cycleDay)
maybeSetNewCycleStart({ maybeSetNewCycleStart({
val, cycleDay, mensesDaysAfter, checkIsMensesStart val,
cycleDay,
mensesDaysAfter,
checkIsMensesStart,
}) })
} else { } else {
cycleDay[symptom] = val cycleDay[symptom] = val
@@ -93,7 +101,7 @@ export function saveSymptom(symptom, date, val) {
export function updateCycleStartsForAllCycleDays() { export function updateCycleStartsForAllCycleDays() {
db.write(() => { db.write(() => {
getBleedingDaysSortedByDate().forEach(day => { getBleedingDaysSortedByDate().forEach((day) => {
if (checkIsMensesStart(day)) { if (checkIsMensesStart(day)) {
day.isCycleStart = true day.isCycleStart = true
} }
@@ -106,7 +114,7 @@ export function createCycleDay(dateString) {
db.write(() => { db.write(() => {
result = db.create('CycleDay', { result = db.create('CycleDay', {
date: dateString, date: dateString,
isCycleStart: false isCycleStart: false,
}) })
}) })
return result return result
@@ -116,9 +124,9 @@ export function getCycleDay(dateString) {
return db.objectForPrimaryKey('CycleDay', dateString) return db.objectForPrimaryKey('CycleDay', dateString)
} }
export function getPreviousTemperature(date) { export function getPreviousTemperatureForDate(date) {
const targetDate = LocalDate.parse(date) const targetDate = LocalDate.parse(date)
const winner = getTemperatureDaysSortedByDate().find(candidate => { const winner = getTemperatureDaysSortedByDate().find((candidate) => {
return LocalDate.parse(candidate.date).isBefore(targetDate) return LocalDate.parse(candidate.date).isBefore(targetDate)
}) })
if (!winner) return null if (!winner) return null
@@ -171,10 +179,13 @@ export function tryToImportWithoutDelete(cycleDays) {
} }
export function requestHash(type, pw) { export function requestHash(type, pw) {
nodejs.channel.post('request-SHA512', JSON.stringify({ nodejs.channel.post(
'request-SHA512',
JSON.stringify({
type: type, type: type,
message: pw message: pw,
})) })
)
} }
export async function changeEncryptionAndRestartApp(hash) { export async function changeEncryptionAndRestartApp(hash) {