diff --git a/components/cycle-day/symptom-edit-view.js b/components/cycle-day/symptom-edit-view.js
index fa03867..a5efaff 100644
--- a/components/cycle-day/symptom-edit-view.js
+++ b/components/cycle-day/symptom-edit-view.js
@@ -23,12 +23,11 @@ import info from '../../i18n/en/symptom-info'
import { Colors, Containers, Sizes, Spacing } from '../../styles'
class SymptomEditView extends Component {
-
static propTypes = {
date: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
symptom: PropTypes.string.isRequired,
- symptomData: PropTypes.object
+ symptomData: PropTypes.object,
}
constructor(props) {
@@ -49,7 +48,7 @@ class SymptomEditView extends Component {
shouldShowInfo: false,
shouldShowNote,
shouldBoxGroup,
- shouldTabGroup
+ shouldTabGroup,
}
}
@@ -97,8 +96,8 @@ class SymptomEditView extends Component {
onSaveTemperature = (value, field) => {
const data = this.getParsedData()
- const dataToSave = field === 'value'
- ? { [field]: Number(value) } : { [field]: value }
+ const dataToSave =
+ field === 'value' ? { [field]: Number(value) } : { [field]: value }
Object.assign(data, { ...dataToSave })
this.setState({ data })
@@ -106,10 +105,10 @@ class SymptomEditView extends Component {
onSelectBox = (key) => {
const data = this.getParsedData()
- if (key === "other") {
+ if (key === 'other') {
Object.assign(data, {
note: null,
- [key]: !this.state.data[key]
+ [key]: !this.state.data[key],
})
} else {
Object.assign(data, { [key]: !this.state.data[key] })
@@ -118,7 +117,7 @@ class SymptomEditView extends Component {
this.setState({ data })
}
- onSelectBoxNote= (value) => {
+ onSelectBoxNote = (value) => {
const data = this.getParsedData()
Object.assign(data, { note: value !== '' ? value : null })
@@ -147,12 +146,13 @@ class SymptomEditView extends Component {
render() {
const { symptom } = this.props
- const { data,
+ const {
+ data,
shouldShowExclude,
shouldShowInfo,
shouldShowNote,
shouldBoxGroup,
- shouldTabGroup
+ shouldTabGroup,
} = this.state
const iconName = shouldShowInfo ? 'chevron-up' : 'chevron-down'
const noteText = symptom === 'note' ? data.value : data.note
@@ -166,73 +166,73 @@ class SymptomEditView extends Component {
- {symptom === 'temperature' &&
+ {symptom === 'temperature' && (
this.onSaveTemperature(value, field)}
/>
- }
- {shouldTabGroup && symtomPage[symptom].selectTabGroups.map(group => {
- return (
-
- {group.title}
- this.onSelectTab(group, value)}
- />
-
- )
- })
- }
- {shouldBoxGroup && symtomPage[symptom].selectBoxGroups.map(group => {
- const isOtherSelected =
- data['other'] !== null
- && data['other'] !== false
- && Object.keys(group.options).includes('other')
-
- return (
-
- {group.title}
- this.onSelectBox(value)}
- optionsState={data}
- />
- {isOtherSelected &&
- this.onSelectBoxNote(value)}
+ )}
+ {shouldTabGroup &&
+ symtomPage[symptom].selectTabGroups.map((group) => {
+ return (
+
+ {group.title}
+ this.onSelectTab(group, value)}
/>
- }
-
- )
- })
- }
- {shouldShowExclude &&
-
+
+ )
+ })}
+ {shouldBoxGroup &&
+ symtomPage[symptom].selectBoxGroups.map((group) => {
+ const isOtherSelected =
+ data['other'] !== null &&
+ data['other'] !== false &&
+ Object.keys(group.options).includes('other')
+
+ return (
+
+ {group.title}
+ this.onSelectBox(value)}
+ optionsState={data}
+ />
+ {isOtherSelected && (
+ this.onSelectBoxNote(value)}
+ />
+ )}
+
+ )
+ })}
+ {shouldShowExclude && (
+
- }
- {shouldShowNote &&
-
+ )}
+ {shouldShowNote && (
+
{symtomPage[symptom].note}
- }
+ )}
- {shouldShowInfo &&
-
+ {shouldShowInfo && (
+
{info[symptom].text}
- }
+ )}
)
@@ -257,7 +257,7 @@ class SymptomEditView extends Component {
const styles = StyleSheet.create({
buttonsContainer: {
- ...Containers.rowContainer
+ ...Containers.rowContainer,
},
headerContainer: {
flexDirection: 'row',
@@ -275,23 +275,20 @@ const styles = StyleSheet.create({
marginVertical: Sizes.huge * 2,
position: 'absolute',
minHeight: '40%',
- maxHeight: Dimensions.get('window').height * 0.7
+ maxHeight: Dimensions.get('window').height * 0.7,
},
segmentBorder: {
- borderBottomColor: Colors.greyLight
+ borderBottomColor: Colors.greyLight,
},
title: {
- fontSize: Sizes.subtitle
- }
+ fontSize: Sizes.subtitle,
+ },
})
const mapStateToProps = (state) => {
- return({
+ return {
date: getDate(state),
- })
+ }
}
-export default connect(
- mapStateToProps,
- null,
-)(SymptomEditView)
+export default connect(mapStateToProps, null)(SymptomEditView)
diff --git a/components/cycle-day/temperature.js b/components/cycle-day/temperature.js
index 4023d38..af1e99e 100644
--- a/components/cycle-day/temperature.js
+++ b/components/cycle-day/temperature.js
@@ -1,4 +1,4 @@
-import React, { Component } from 'react'
+import React, { useEffect, useState } from 'react'
import { Platform, StyleSheet, View } from 'react-native'
import PropTypes from 'prop-types'
import { Keyboard } from 'react-native'
@@ -12,129 +12,92 @@ import Segment from '../common/segment'
import { connect } from 'react-redux'
import { getDate } from '../../slices/date'
import {
- isTemperatureOutOfRange,
+ getTemperatureOutOfRangeMessage,
getPreviousTemperature,
+ formatTemperature,
} from '../helpers/cycle-day'
import { temperature as labels } from '../../i18n/en/cycle-day'
import { Colors, Containers, Sizes, Spacing } from '../../styles'
-const formatTemperature = (value) =>
- value === null ? value : Number.parseFloat(value).toFixed(2)
+const Temperature = ({ data, date, save }) => {
+ const [isTimePickerVisible, setIsTimePickerVisible] = useState(false)
+ const [temperature, setTemperature] = useState(
+ formatTemperature(data.value) || getPreviousTemperature(date)
+ )
-class Temperature extends Component {
- static propTypes = {
- data: PropTypes.object,
- date: PropTypes.string.isRequired,
- save: PropTypes.func,
- }
-
- constructor(props) {
- super(props)
-
- const { data, date } = this.props
- const { value } = data
- const { shouldShowSuggestion, suggestedTemperature } =
- getPreviousTemperature(date)
-
- this.state = {
- isTimePickerVisible: false,
- shouldShowSuggestion,
- suggestedTemperature: formatTemperature(suggestedTemperature),
- value: formatTemperature(value),
+ // update state in parent component once to ensure
+ // that pre-filled values are saved on button click
+ useEffect(() => {
+ if (temperature) {
+ save(temperature, 'value')
}
+ }, [])
+
+ function onChangeTemperature(value) {
+ const formattedValue = value.replace(',', '.').trim()
+ if (!Number(formattedValue) && value !== '') return false
+ setTemperature(formattedValue)
}
- onCancelTimePicker = () => {
- this.setState({ isTimePickerVisible: false })
- }
-
- onChangeTemperature = (value) => {
- if (!Number(value)) return false
-
- this.setState({
- value: value.trim(),
- shouldShowSuggestion: false,
- })
- }
-
- onShowTimePicker = () => {
+ function onShowTimePicker() {
Keyboard.dismiss()
- this.setState({ isTimePickerVisible: true })
+ setIsTimePickerVisible(true)
}
- setTemperature = () => {
- const { value } = this.state
- this.props.save(value, 'value')
- }
-
- setTime = (jsDate) => {
+ function setTime(jsDate) {
const time = moment(jsDate).format('HH:mm')
- const isTimePickerVisible = false
- this.props.save(time, 'time')
- this.setState({ isTimePickerVisible })
+ save(time, 'time')
+ setIsTimePickerVisible(false)
}
- render() {
- const { shouldShowSuggestion, suggestedTemperature, value } = this.state
- const { time } = this.props.data
+ const { time } = data
- const inputStyle =
- shouldShowSuggestion && value === null
- ? { color: Colors.grey }
- : { color: Colors.greyDark }
- const outOfRangeWarning = isTemperatureOutOfRange(value)
- let temperatureToShow = null
+ const inputStyle = { color: Colors.greyDark }
+ const outOfRangeWarning = getTemperatureOutOfRangeMessage(temperature)
- if (value) {
- temperatureToShow = value
- } else if (shouldShowSuggestion) {
- temperatureToShow = suggestedTemperature
- }
-
- return (
-
-
- {labels.temperature.explainer}
-
-
- °C
-
- {outOfRangeWarning !== null && (
-
- {outOfRangeWarning}
-
- )}
-
-
- {labels.time}
+ return (
+
+
+ {labels.temperature.explainer}
+
save(temperature, 'value')}
+ keyboardType="numeric"
+ maxLength={5}
+ style={inputStyle}
+ testID="temperatureInput"
+ underlineColorAndroid="transparent"
/>
-
-
-
- )
- }
+ °C
+
+ {!!outOfRangeWarning && (
+
+ {outOfRangeWarning}
+
+ )}
+
+
+ {labels.time}
+
+ setIsTimePickerVisible(false)}
+ display={Platform.OS === 'ios' ? 'spinner' : 'default'}
+ />
+
+
+ )
}
const styles = StyleSheet.create({
@@ -153,6 +116,12 @@ const styles = StyleSheet.create({
},
})
+Temperature.propTypes = {
+ data: PropTypes.object.isRequired,
+ date: PropTypes.string.isRequired,
+ save: PropTypes.func.isRequired,
+}
+
const mapStateToProps = (state) => {
return {
date: getDate(state),
diff --git a/components/helpers/cycle-day.js b/components/helpers/cycle-day.js
index 37037f0..9e1248f 100644
--- a/components/helpers/cycle-day.js
+++ b/components/helpers/cycle-day.js
@@ -35,22 +35,17 @@ export const getPreviousTemperature = (date) => {
return formatTemperature(previousTemperature)
}
-export const isTemperatureOutOfRange = (temperature) => {
+export const getTemperatureOutOfRangeMessage = (temperature) => {
if (!temperature) return null
const value = Number(temperature)
- const range = { min: TEMP_MIN, max: TEMP_MAX }
const scale = scaleObservable.value
- let warningMsg = null
-
- if (value < range.min || value > range.max) {
- warningMsg = labels.temperature.outOfAbsoluteRangeWarning
- } else if (value < scale.min || value > scale.max) {
- warningMsg = labels.temperature.outOfRangeWarning
- }
-
- return warningMsg
+ return value < TEMP_MIN || value > TEMP_MAX
+ ? labels.temperature.outOfAbsoluteRangeWarning
+ : value < scale.min || value > scale.max
+ ? labels.temperature.outOfRangeWarning
+ : ''
}
export const blank = {