Merge branch 'simplify-temperature-view' into 'master'
Simplifies the temperature edit view See merge request bloodyhealth/drip!243
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { View } from 'react-native'
|
||||
import AppText from '../../app-text'
|
||||
import AppTextInput from '../../app-text-input'
|
||||
|
||||
import { temperature as labels } from '../../../i18n/en/cycle-day'
|
||||
|
||||
import styles from '../../../styles'
|
||||
|
||||
import { getPreviousTemperature } from '../../../db'
|
||||
import { scaleObservable } from '../../../local-storage'
|
||||
import config from '../../../config'
|
||||
|
||||
export default class TemperatureInput extends Component {
|
||||
|
||||
static propTypes = {
|
||||
temperature: PropTypes.string,
|
||||
handleTemperatureChange: PropTypes.func,
|
||||
date: PropTypes.string,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
let shouldShowSuggestion = false
|
||||
let suggestedTemperature = null
|
||||
|
||||
if (!props.temperature) {
|
||||
const prevTemp = getPreviousTemperature(props.date)
|
||||
if (prevTemp) {
|
||||
shouldShowSuggestion = true
|
||||
suggestedTemperature = prevTemp.toString()
|
||||
}
|
||||
}
|
||||
|
||||
this.state = {
|
||||
temperature: props.temperature,
|
||||
shouldShowSuggestion,
|
||||
suggestedTemperature
|
||||
}
|
||||
}
|
||||
|
||||
setTemperature = (temperature) => {
|
||||
this.setState({
|
||||
shouldShowSuggestion: false,
|
||||
temperature
|
||||
})
|
||||
this.props.handleTemperatureChange(Number(temperature))
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
shouldShowSuggestion,
|
||||
suggestedTemperature,
|
||||
temperature
|
||||
} = this.state
|
||||
const inputStyle = [
|
||||
styles.temperatureTextInput,
|
||||
shouldShowSuggestion ? styles.temperatureTextInputSuggestion : null
|
||||
]
|
||||
return (
|
||||
<React.Fragment>
|
||||
<View style={styles.framedSegmentInlineChildren}>
|
||||
<AppTextInput
|
||||
style={inputStyle}
|
||||
autoFocus={true}
|
||||
value={shouldShowSuggestion ? suggestedTemperature : temperature}
|
||||
onChangeText={this.setTemperature}
|
||||
keyboardType='numeric'
|
||||
maxLength={5}
|
||||
/>
|
||||
<AppText style={{ marginLeft: 5 }}>°C</AppText>
|
||||
</View>
|
||||
<OutOfRangeWarning temperature={this.props.temperature} />
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const OutOfRangeWarning = ({ temperature }) => {
|
||||
if (temperature === '') {
|
||||
return false
|
||||
}
|
||||
|
||||
const value = Number(temperature)
|
||||
const { min, max } = config.temperatureScale
|
||||
const range = { min, max }
|
||||
const scale = scaleObservable.value
|
||||
|
||||
let warningMsg
|
||||
|
||||
if (value < range.min || value > range.max) {
|
||||
warningMsg = labels.outOfAbsoluteRangeWarning
|
||||
} else if (value < scale.min || value > scale.max) {
|
||||
warningMsg = labels.outOfRangeWarning
|
||||
} else {
|
||||
warningMsg = null
|
||||
}
|
||||
|
||||
return <AppText style={styles.hint}>{warningMsg}</AppText>
|
||||
}
|
||||
@@ -1,32 +1,31 @@
|
||||
import React from 'react'
|
||||
import {
|
||||
View,
|
||||
Switch,
|
||||
Keyboard,
|
||||
ScrollView
|
||||
} from 'react-native'
|
||||
import { Switch, ScrollView } from 'react-native'
|
||||
import PropTypes from 'prop-types'
|
||||
import { connect } from 'react-redux'
|
||||
|
||||
import { getDate } from '../../../slices/date'
|
||||
|
||||
import DateTimePicker from 'react-native-modal-datetime-picker-nevo'
|
||||
import padWithZeros from '../../helpers/pad-time-with-zeros'
|
||||
|
||||
import { getPreviousTemperature } from '../../../db'
|
||||
import styles from '../../../styles'
|
||||
import { LocalTime, ChronoUnit } from 'js-joda'
|
||||
import { temperature as labels } from '../../../i18n/en/cycle-day'
|
||||
import { scaleObservable } from '../../../local-storage'
|
||||
import { shared as sharedLabels } from '../../../i18n/en/labels'
|
||||
import config from '../../../config'
|
||||
|
||||
import AppTextInput from '../../app-text-input'
|
||||
import AppText from '../../app-text'
|
||||
import SymptomSection from './symptom-section'
|
||||
import SymptomView from './symptom-view'
|
||||
import TimeInput from './time-input'
|
||||
import TemperatureInput from './temperature-input'
|
||||
|
||||
const minutes = ChronoUnit.MINUTES
|
||||
|
||||
class Temp extends SymptomView {
|
||||
class Temperature extends SymptomView {
|
||||
|
||||
static propTypes = {
|
||||
cycleDay: PropTypes.object,
|
||||
handleBackButtonPress: PropTypes.func,
|
||||
date: PropTypes.string,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
const cycleDay = props.cycleDay
|
||||
@@ -37,23 +36,9 @@ class Temp extends SymptomView {
|
||||
this.state = {
|
||||
exclude: temp ? temp.exclude : false,
|
||||
time: temp ? temp.time : LocalTime.now().truncatedTo(minutes).toString(),
|
||||
isTimePickerVisible: false,
|
||||
temperature: temp ? temp.value : null,
|
||||
note: temp ? temp.note : null
|
||||
}
|
||||
|
||||
if (temp) {
|
||||
this.state.temperature = temp.value.toString()
|
||||
if (temp.value === Math.floor(temp.value)) {
|
||||
this.state.temperature = `${this.state.temperature}.0`
|
||||
}
|
||||
this.state.outOfRangeWarning = makeOutOfRangeWarningMessage(this.state.temperature)
|
||||
} else {
|
||||
const prevTemp = getPreviousTemperature(props.date)
|
||||
if (prevTemp) {
|
||||
this.state.suggestedTemperature = prevTemp.toString()
|
||||
this.state.isSuggestion = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
symptomName = 'temperature'
|
||||
@@ -67,13 +52,13 @@ class Temp extends SymptomView {
|
||||
}
|
||||
|
||||
autoSave = () => {
|
||||
if (typeof this.state.temperature != 'string' || this.state.temperature === '') {
|
||||
if (!this.state.temperature) {
|
||||
this.deleteSymptomEntry()
|
||||
return
|
||||
}
|
||||
|
||||
const dataToSave = {
|
||||
value: Number(this.state.temperature),
|
||||
value: this.state.temperature,
|
||||
exclude: this.state.exclude,
|
||||
time: this.state.time,
|
||||
note: this.state.note
|
||||
@@ -82,73 +67,38 @@ class Temp extends SymptomView {
|
||||
this.saveSymptomEntry(dataToSave)
|
||||
}
|
||||
|
||||
setTime = (time) => {
|
||||
this.setState({ time })
|
||||
}
|
||||
|
||||
setTemperature = (temperature) => {
|
||||
if (isNaN(Number(temperature))) return
|
||||
this.setState({
|
||||
temperature, isSuggestion: false,
|
||||
outOfRangeWarning: makeOutOfRangeWarningMessage(temperature)
|
||||
})
|
||||
this.setState({ temperature })
|
||||
}
|
||||
|
||||
setNote = (note) => {
|
||||
this.setState({ note })
|
||||
}
|
||||
|
||||
showTimePicker = () => {
|
||||
Keyboard.dismiss()
|
||||
this.setState({ isTimePickerVisible: true })
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
const inputStyle = [styles.temperatureTextInput]
|
||||
if (this.state.isSuggestion) {
|
||||
inputStyle.push(styles.temperatureTextInputSuggestion)
|
||||
}
|
||||
const { temperature } = this.state
|
||||
|
||||
return (
|
||||
<ScrollView style={styles.page}>
|
||||
<SymptomSection
|
||||
header={labels.temperature.header}
|
||||
explainer={labels.temperature.explainer}
|
||||
>
|
||||
<View style={styles.framedSegmentInlineChildren}>
|
||||
<AppTextInput
|
||||
style={[inputStyle]}
|
||||
autoFocus={true}
|
||||
value={this.state.temperature || this.state.suggestedTemperature}
|
||||
onChangeText={this.setTemperature}
|
||||
keyboardType='numeric'
|
||||
maxLength={5}
|
||||
/>
|
||||
<AppText style={{ marginLeft: 5 }}>°C</AppText>
|
||||
</View>
|
||||
{this.state.outOfRangeWarning &&
|
||||
<AppText style={styles.hint}>
|
||||
{this.state.outOfRangeWarning}
|
||||
</AppText>
|
||||
}
|
||||
<TemperatureInput
|
||||
temperature={temperature ? temperature.toFixed(2) : ''}
|
||||
date={this.props.date}
|
||||
handleTemperatureChange={this.setTemperature}
|
||||
/>
|
||||
</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 header={labels.time}>
|
||||
<TimeInput
|
||||
time={this.state.time}
|
||||
handleTimeChange={this.setTime}
|
||||
/>
|
||||
</SymptomSection>
|
||||
<SymptomSection
|
||||
header={labels.note.header}
|
||||
@@ -188,23 +138,4 @@ const mapStateToProps = (state) => {
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(Temp)
|
||||
|
||||
function makeOutOfRangeWarningMessage(temperature) {
|
||||
if (temperature === '') return
|
||||
const value = Number(temperature)
|
||||
const { min, max } = config.temperatureScale
|
||||
const range = { min, max }
|
||||
const scale = scaleObservable.value
|
||||
let warningMsg
|
||||
|
||||
if (value < range.min || value > range.max) {
|
||||
warningMsg = labels.outOfAbsoluteRangeWarning
|
||||
} else if (value < scale.min || value > scale.max) {
|
||||
warningMsg = labels.outOfRangeWarning
|
||||
} else {
|
||||
warningMsg = null
|
||||
}
|
||||
|
||||
return warningMsg
|
||||
}
|
||||
)(Temperature)
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Keyboard } from 'react-native'
|
||||
|
||||
import AppTextInput from '../../app-text-input'
|
||||
import styles from '../../../styles'
|
||||
|
||||
import DateTimePicker from 'react-native-modal-datetime-picker-nevo'
|
||||
import moment from 'moment'
|
||||
|
||||
export default class TimeInput extends Component {
|
||||
|
||||
static propTypes = {
|
||||
time: PropTypes.string,
|
||||
handleTimeChange: PropTypes.func,
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
isTimePickerVisible: false,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
showTimePicker = () => {
|
||||
Keyboard.dismiss()
|
||||
this.setState({ isTimePickerVisible: true })
|
||||
}
|
||||
|
||||
hideTimePicker = () => {
|
||||
this.setState({ isTimePickerVisible: false })
|
||||
}
|
||||
|
||||
handleConfirm = (jsDate) => {
|
||||
// DateTimePicker also when in mode="time" returns full date (with time)
|
||||
const time = moment(jsDate).format('HH:mm')
|
||||
this.props.handleTimeChange(time)
|
||||
this.setState({
|
||||
isTimePickerVisible: false
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<AppTextInput
|
||||
style={styles.temperatureTextInput}
|
||||
onFocus={this.showTimePicker}
|
||||
value={this.props.time}
|
||||
/>
|
||||
<DateTimePicker
|
||||
mode="time"
|
||||
isVisible={this.state.isTimePickerVisible}
|
||||
onConfirm={this.handleConfirm}
|
||||
onCancel={this.hideTimePicker}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user