diff --git a/components/cycle-day/FillerBoxes.js b/components/cycle-day/FillerBoxes.js new file mode 100644 index 0000000000000000000000000000000000000000..f0e0c024ac1c125de35efcbbca942f141761e5e1 --- /dev/null +++ b/components/cycle-day/FillerBoxes.js @@ -0,0 +1,20 @@ +import React, { Component } from 'react' +import { View, Dimensions } from 'react-native' +import styles from '../../styles' + +export default class FillerBoxes extends Component { + render() { + const n = Dimensions.get('window').width / styles.symptomBox.width + const fillerBoxes = [] + for (let i = 0; i < Math.ceil(n); i++) { + fillerBoxes.push( + <View + width={styles.symptomBox.width} + height={0} + key={i.toString()} + /> + ) + } + return fillerBoxes + } +} \ No newline at end of file diff --git a/components/cycle-day/SymptomBox.js b/components/cycle-day/SymptomBox.js new file mode 100644 index 0000000000000000000000000000000000000000..b4af7c3e8320a233d93238ccaf6d6ba31ac1e3be --- /dev/null +++ b/components/cycle-day/SymptomBox.js @@ -0,0 +1,170 @@ +import React, { Component } from 'react' +import { View, TouchableOpacity } from 'react-native' + +import AppText from '../app-text' +import DripIcon from '../../assets/drip-icons' + +import styles from '../../styles' + +import { headerTitles as symptomTitles } from '../../i18n/en/labels' +import * as labels from '../../i18n/en/cycle-day' +const bleedingLabels = labels.bleeding.labels +const intensityLabels = labels.intensity +const sexLabels = labels.sex.categories +const contraceptiveLabels = labels.contraceptives.categories +const painLabels = labels.pain.categories +const moodLabels = labels.mood.categories + +function isNumber(val) { + return typeof val === 'number' +} + +const l = { + bleeding: ({ value, exclude }) => { + if (isNumber(value)) { + const bleedingLabel = bleedingLabels[value] + return exclude ? `(${bleedingLabel})` : bleedingLabel + } + }, + temperature: ({ value, time, exclude }) => { + if (isNumber(value)) { + let temperatureLabel = `${value} °C` + if (time) { + temperatureLabel += ` - ${time}` + } + if (exclude) { + temperatureLabel = `(${temperatureLabel})` + } + return temperatureLabel + } + }, + mucus: mucus => { + const filledCategories = ['feeling', 'texture'].filter(c => isNumber(mucus[c])) + 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 (mucus.exclude) label = `(${label})` + + return label + }, + cervix: cervix => { + const filledCategories = ['opening', 'firmness', 'position'].filter(c => isNumber(cervix[c])) + let label = filledCategories.map(category => { + return labels.cervix.subcategories[category] + ': ' + labels.cervix[category].categories[cervix[category]] + }).join(', ') + + if (cervix.exclude) label = `(${label})` + + return label + }, + note: note => note.value, + desire: ({ value }) => { + if (isNumber(value)) { + return intensityLabels[value] + } + }, + sex: sex => { + const sexLabel = [] + if (sex && Object.values({...sex}).some(val => val)){ + Object.keys(sex).forEach(key => { + if(sex[key] && key !== 'other' && key !== 'note') { + sexLabel.push( + sexLabels[key] || + contraceptiveLabels[key] + ) + } + if(key === 'other' && sex.other) { + let label = contraceptiveLabels[key] + if(sex.note) { + label = `${label} (${sex.note})` + } + sexLabel.push(label) + } + }) + return sexLabel.join(', ') + } + }, + pain: pain => { + const painLabel = [] + if (pain && Object.values({...pain}).some(val => val)){ + Object.keys(pain).forEach(key => { + if(pain[key] && key !== 'other' && key !== 'note') { + painLabel.push(painLabels[key]) + } + if(key === 'other' && pain.other) { + let label = painLabels[key] + if(pain.note) { + label = `${label} (${pain.note})` + } + painLabel.push(label) + } + }) + return painLabel.join(', ') + } + }, + mood: mood => { + const moodLabel = [] + if (mood && Object.values({...mood}).some(val => val)){ + Object.keys(mood).forEach(key => { + if(mood[key] && key !== 'other' && key !== 'note') { + moodLabel.push(moodLabels[key]) + } + if(key === 'other' && mood.other) { + let label = moodLabels[key] + if(mood.note) { + label = `${label} (${mood.note})` + } + moodLabel.push(label) + } + }) + return moodLabel.join(', ') + } + } +} + +export default class SymptomBox extends Component { + getLabel = () => { + const { symptom, symptomData } = this.props + return symptomData && l[symptom](symptomData) + } + + render() { + const { symptom, onPress, disabled } = this.props + const data = this.getLabel() + const iconName = `drip-icon-${symptom}` + + const disabledStyle = disabled ? styles.symptomInFuture : null + const containerStyle = [ + styles.symptomBox, + data && styles.symptomBoxActive, + disabledStyle + ] + const titleStyle = [ + data && styles.symptomTextActive, + disabledStyle, + {fontSize: 15} + ] + const dataBoxStyle = [styles.symptomDataBox, disabledStyle] + + return ( + <TouchableOpacity onPress={onPress} disabled={disabled} testID={iconName}> + <View style={containerStyle}> + <Icon name={iconName} isActive={data} /> + <AppText style={titleStyle} numberOfLines={1}> + {symptomTitles[symptom].toLowerCase()} + </AppText> + </View> + <View style={dataBoxStyle}> + <AppText style={styles.symptomDataText} numberOfLines={3}> + {data} + </AppText> + </View> + </TouchableOpacity> + ) + } +} + +const Icon = ({name, isActive}) => + <DripIcon name={name} size={50} color={isActive ? 'white' : 'black'} /> \ No newline at end of file diff --git a/components/cycle-day/cycle-day-overview.js b/components/cycle-day/cycle-day-overview.js index 407aac2b1280d8b2102cb7a27899425e53d86d25..2961f815194fdd547b62b35f6916362fd9d5be20 100644 --- a/components/cycle-day/cycle-day-overview.js +++ b/components/cycle-day/cycle-day-overview.js @@ -1,33 +1,21 @@ import React, { Component } from 'react' -import { - ScrollView, - View, - TouchableOpacity, - Dimensions -} from 'react-native' +import { ScrollView, View } from 'react-native' import { LocalDate } from 'js-joda' import Header from '../header' +import FillerBoxes from './FillerBoxes' +import SymptomBox from './SymptomBox' + import { getCycleDay } from '../../db' import cycleModule from '../../lib/cycle' import styles from '../../styles' -import * as labels from '../../i18n/en/cycle-day' -import { headerTitles as symptomTitles } from '../../i18n/en/labels' -import AppText from '../app-text' -import DripIcon from '../../assets/drip-icons' - -const bleedingLabels = labels.bleeding.labels -const intensityLabels = labels.intensity -const sexLabels = labels.sex.categories -const contraceptiveLabels = labels.contraceptives.categories -const painLabels = labels.pain.categories -const moodLabels = labels.mood.categories export default class CycleDayOverView extends Component { constructor(props) { super(props) + const { date } = this.props this.state = { - date: this.props.date, - cycleDay: getCycleDay(this.props.date) + date, + cycleDay: getCycleDay(date) } } @@ -46,216 +34,54 @@ export default class CycleDayOverView extends Component { this.props.navigate(symptom, this.state) } - getLabel(symptomName) { - const cycleDay = this.state.cycleDay - if (!cycleDay || !cycleDay[symptomName]) return - - const l = { - bleeding: bleeding => { - if (isNumber(bleeding.value)) { - let bleedingLabel = bleedingLabels[bleeding.value] - if (bleeding.exclude) bleedingLabel = "( " + bleedingLabel + " )" - return bleedingLabel - } - }, - temperature: temperature => { - if (isNumber(temperature.value)) { - let temperatureLabel = `${temperature.value} °C` - if (temperature.time) { - temperatureLabel = `${temperatureLabel} - ${temperature.time}` - } - if (temperature.exclude) { - temperatureLabel = "( " + temperatureLabel + " )" - } - return temperatureLabel - } - }, - mucus: mucus => { - const filledCategories = ['feeling', 'texture'].filter(c => isNumber(mucus[c])) - 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 (mucus.exclude) label = `(${label})` - - return label - }, - cervix: cervix => { - const filledCategories = ['opening', 'firmness', 'position'].filter(c => isNumber(cervix[c])) - let label = filledCategories.map(category => { - return labels.cervix.subcategories[category] + ': ' + labels.cervix[category].categories[cervix[category]] - }).join(', ') - - if (cervix.exclude) label = `(${label})` - - return label - }, - note: note => { - return note.value - }, - desire: desire => { - if (isNumber(desire.value)) { - const desireLabel = `${intensityLabels[desire.value]}` - return desireLabel - } - }, - sex: sex => { - let sexLabel = [] - if (sex && Object.values({...sex}).some(val => val)){ - Object.keys(sex).forEach(key => { - if(sex[key] && key !== 'other' && key !== 'note') { - sexLabel.push( - sexLabels[key] || - contraceptiveLabels[key] - ) - } - if(key === 'other' && sex.other) { - let label = contraceptiveLabels[key] - if(sex.note) { - label = `${label} (${sex.note})` - } - sexLabel.push(label) - } - }) - sexLabel = sexLabel.join(', ') - return sexLabel - } - }, - pain: pain => { - let painLabel = [] - if (pain && Object.values({...pain}).some(val => val)){ - Object.keys(pain).forEach(key => { - if(pain[key] && key !== 'other' && key !== 'note') { - painLabel.push(painLabels[key]) - } - if(key === 'other' && pain.other) { - let label = painLabels[key] - if(pain.note) { - label = `${label} (${pain.note})` - } - painLabel.push(label) - } - }) - painLabel = painLabel.join(', ') - return painLabel - } - }, - mood: mood => { - let moodLabel = [] - if (mood && Object.values({...mood}).some(val => val)){ - Object.keys(mood).forEach(key => { - if(mood[key] && key !== 'other' && key !== 'note') { - moodLabel.push(moodLabels[key]) - } - if(key === 'other' && mood.other) { - let label = moodLabels[key] - if(mood.note) { - label = `${label} (${mood.note})` - } - moodLabel.push(label) - } - }) - moodLabel = moodLabel.join(', ') - return moodLabel - } - } - } - - const symptomValue = cycleDay[symptomName] - return l[symptomName](symptomValue) - } - render() { - const getCycleDayNumber = cycleModule().getCycleDayNumber - const cycleDayNumber = getCycleDayNumber(this.state.date) - const dateInFuture = LocalDate - .now() - .isBefore(LocalDate.parse(this.state.date)) + const { date, cycleDay } = this.state + const { getCycleDayNumber } = cycleModule() + const cycleDayNumber = getCycleDayNumber(date) + const dateInFuture = LocalDate.now().isBefore(LocalDate.parse(date)) + + const symptomBoxesList = [ + 'bleeding', + 'temperature', + 'mucus', + 'cervix', + 'desire', + 'sex', + 'pain', + 'mood', + 'note', + ] return ( <View style={{ flex: 1 }}> <Header isCycleDayOverView={true} cycleDayNumber={cycleDayNumber} - date={this.state.date} + date={date} goToCycleDay={this.goToCycleDay} /> <ScrollView> <View style={styles.symptomBoxesView}> - <SymptomBox - title={symptomTitles.bleeding} - onPress={() => this.navigate('BleedingEditView')} - data={this.getLabel('bleeding')} - disabled={dateInFuture} - iconName='drip-icon-bleeding' - > - </SymptomBox> - <SymptomBox - title={symptomTitles.temperature} - onPress={() => this.navigate('TemperatureEditView')} - data={this.getLabel('temperature')} - disabled={dateInFuture} - iconName='drip-icon-temperature' - > - </SymptomBox> - <SymptomBox - title={symptomTitles.mucus} - onPress={() => this.navigate('MucusEditView')} - data={this.getLabel('mucus')} - disabled={dateInFuture} - iconName='drip-icon-mucus' - > - </SymptomBox> - <SymptomBox - title={symptomTitles.cervix} - onPress={() => this.navigate('CervixEditView')} - data={this.getLabel('cervix')} - disabled={dateInFuture} - iconName='drip-icon-cervix' - > - </SymptomBox> - <SymptomBox - title={symptomTitles.desire} - onPress={() => this.navigate('DesireEditView')} - data={this.getLabel('desire')} - disabled={dateInFuture} - iconName='drip-icon-desire' - > - </SymptomBox> - <SymptomBox - title={symptomTitles.sex} - onPress={() => this.navigate('SexEditView')} - data={this.getLabel('sex')} - disabled={dateInFuture} - iconName='drip-icon-sex' - > - </SymptomBox> - <SymptomBox - title={symptomTitles.pain} - onPress={() => this.navigate('PainEditView')} - data={this.getLabel('pain')} - disabled={dateInFuture} - iconName='drip-icon-pain' - > - </SymptomBox> - <SymptomBox - title={symptomTitles.mood} - onPress={() => this.navigate('MoodEditView')} - data={this.getLabel('mood')} - disabled={dateInFuture} - iconName='drip-icon-mood' - > - </SymptomBox> - <SymptomBox - title={symptomTitles.note} - onPress={() => this.navigate('NoteEditView')} - data={this.getLabel('note')} - iconName='drip-icon-note' - > - </SymptomBox> - {/* this is just to make the last row adhere to the grid - (and) because there are no pseudo properties in RN */} + { + symptomBoxesList.map(symptom => { + const symptomEditView = + `${symptom[0].toUpperCase() + symptom.substring(1)}EditView` + const symptomData = + cycleDay && cycleDay[symptom] ? cycleDay[symptom] : null + return( + <SymptomBox + key={symptom} + symptom={symptom} + symptomData={symptomData} + onPress={() => this.navigate(symptomEditView)} + disabled={dateInFuture} + />) + }) + } + { + // this is just to make the last row adhere to the grid + // (and) because there are no pseudo properties in RN + } <FillerBoxes /> </View> </ScrollView> @@ -263,60 +89,3 @@ export default class CycleDayOverView extends Component { ) } } - - - - -class SymptomBox extends Component { - render() { - const hasData = this.props.data - const boxActive = hasData ? styles.symptomBoxActive : {} - const textActive = hasData ? styles.symptomTextActive : {} - const disabledStyle = this.props.disabled ? styles.symptomInFuture : {} - - return ( - <TouchableOpacity - onPress={this.props.onPress} - disabled={this.props.disabled} - testID={this.props.iconName} - > - <View style={[styles.symptomBox, boxActive, disabledStyle]}> - <DripIcon name={this.props.iconName} size={50} color={hasData ? 'white' : 'black'}/> - <AppText - style={[textActive, disabledStyle, {fontSize: 15}]} - numberOfLines={1} - > - {this.props.title.toLowerCase()} - </AppText> - </View> - <View style={[styles.symptomDataBox, disabledStyle]}> - <AppText - style={styles.symptomDataText} - numberOfLines={3} - >{this.props.data}</AppText> - </View> - </TouchableOpacity> - ) - } -} - -class FillerBoxes extends Component { - render() { - const n = Dimensions.get('window').width / styles.symptomBox.width - const fillerBoxes = [] - for (let i = 0; i < Math.ceil(n); i++) { - fillerBoxes.push( - <View - width={styles.symptomBox.width} - height={0} - key={i.toString()} - /> - ) - } - return fillerBoxes - } -} - -function isNumber(val) { - return typeof val === 'number' -}