diff --git a/components/calendar.js b/components/calendar.js index 4989d7f662eab21843fe7a63e0f2c220f432c21b..67e52997a831a01fa3d850b0b5c9bd84687e440a 100644 --- a/components/calendar.js +++ b/components/calendar.js @@ -1,27 +1,29 @@ import React, { Component } from 'react' import { View } from 'react-native' import { Calendar } from 'react-native-calendars' -import * as styles from '../styles/index' +import * as styles from '../styles' import { getOrCreateCycleDay, bleedingDaysSortedByDate } from '../db' export default class CalendarView extends Component { constructor(props) { super(props) - this.state = { bleedingDaysInCalFormat: getBleedingDaysInCalFormat(bleedingDaysSortedByDate) } + this.state = { + bleedingDaysInCalFormat: toCalFormat(bleedingDaysSortedByDate) + } - this.setStateWithCalendarFormattedDays = (function (CalendarComponent) { + this.setStateWithCalFormattedDays = (function (CalendarComponent) { return function() { CalendarComponent.setState({ - bleedingDaysInCalFormat: getBleedingDaysInCalFormat(bleedingDaysSortedByDate) + bleedingDaysInCalFormat: toCalFormat(bleedingDaysSortedByDate) }) } })(this) - bleedingDaysSortedByDate.addListener(this.setStateWithCalendarFormattedDays) + bleedingDaysSortedByDate.addListener(this.setStateWithCalFormattedDays) } componentWillUnmount() { - bleedingDaysSortedByDate.removeListener(this.setStateWithCalendarFormattedDays) + bleedingDaysSortedByDate.removeListener(this.setStateWithCalFormattedDays) } passDateToDayView(result) { @@ -43,10 +45,14 @@ export default class CalendarView extends Component { } } -function getBleedingDaysInCalFormat(bleedingDaysSortedByDate) { +function toCalFormat(bleedingDaysSortedByDate) { const shadesOfRed = ['#ffbaba', '#ff7b7b', '#ff5252', '#ff0000'] return bleedingDaysSortedByDate.reduce((acc, day) => { - acc[day.date] = { startingDay: true, endingDay: true, color: shadesOfRed[day.bleeding.value] } + acc[day.date] = { + startingDay: true, + endingDay: true, + color: shadesOfRed[day.bleeding.value] + } return acc }, {}) } \ No newline at end of file diff --git a/components/chart/chart.js b/components/chart/chart.js index 30ed5d7b471a3384a80aa5b28d5058f6213b8704..79bea872cefe9ea3785ea8471071858bfda4ea4d 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -115,7 +115,9 @@ export default class CycleChart extends Component { fill={styles.mucusIconShades[cycleDay.mucus.value]} /> : null} - {y ? this.drawDotAndLines(y, cycleDay.temperature.exclude, index) : null} + {y ? + this.drawDotAndLines(y, cycleDay.temperature.exclude, index) + : null} </G> ) } diff --git a/components/cycle-day/action-buttons.js b/components/cycle-day/action-buttons.js index eb33201da2f48ec182974bf2d1f1f7a03b21ab8d..78e2479337a31f44277cc11a8260cd7e89150001 100644 --- a/components/cycle-day/action-buttons.js +++ b/components/cycle-day/action-buttons.js @@ -5,24 +5,26 @@ import { } from 'react-native' import { saveSymptom } from '../../db' +const dayView = 'DayView' + export default function (showView) { return function ({ symptom, cycleDay, saveAction, saveDisabled}) { const buttons = [ { title: 'Cancel', - action: () => showView('dayView') + action: () => showView(dayView) }, { title: 'Delete', action: () => { saveSymptom(symptom, cycleDay) - showView('dayView') + showView(dayView) } }, { title: 'Save', action: () => { saveAction() - showView('dayView') + showView(dayView) }, disabledCondition: saveDisabled } diff --git a/components/cycle-day/cycle-day-overview.js b/components/cycle-day/cycle-day-overview.js index 0b476f5b2a146392b7b64003766aaf54e050140e..f92934b54305277f47588f56b4087ad296573db2 100644 --- a/components/cycle-day/cycle-day-overview.js +++ b/components/cycle-day/cycle-day-overview.js @@ -29,7 +29,7 @@ export default class DayView extends Component { cycleDayNumber: getCycleDayNumber(this.cycleDay.date), } - this.setStateWithCurrentCycleDayNumber = (function (DayViewComponent) { + this.setStateWithCycleDayNumber = (function (DayViewComponent) { return function () { DayViewComponent.setState({ cycleDayNumber: getCycleDayNumber(DayViewComponent.cycleDay.date) @@ -37,11 +37,11 @@ export default class DayView extends Component { } })(this) - bleedingDaysSortedByDate.addListener(this.setStateWithCurrentCycleDayNumber) + bleedingDaysSortedByDate.addListener(this.setStateWithCycleDayNumber) } componentWillUnmount() { - bleedingDaysSortedByDate.removeListener(this.setStateWithCurrentCycleDayNumber) + bleedingDaysSortedByDate.removeListener(this.setStateWithCycleDayNumber) } render() { @@ -52,7 +52,7 @@ export default class DayView extends Component { <Text style={styles.symptomDayView}>Bleeding</Text> <View style={styles.symptomEditButton}> <Button - onPress={() => this.showView('bleedingEditView')} + onPress={() => this.showView('BleedingEditView')} title={getLabel('bleeding', cycleDay.bleeding)}> </Button> </View> @@ -61,7 +61,7 @@ export default class DayView extends Component { <Text style={styles.symptomDayView}>Temperature</Text> <View style={styles.symptomEditButton}> <Button - onPress={() => this.showView('temperatureEditView')} + onPress={() => this.showView('TemperatureEditView')} title={getLabel('temperature', cycleDay.temperature)}> </Button> </View> @@ -70,7 +70,7 @@ export default class DayView extends Component { <Text style={styles.symptomDayView}>Mucus</Text> <View style={styles.symptomEditButton}> <Button - onPress={() => this.showView('mucusEditView')} + onPress={() => this.showView('MucusEditView')} title={getLabel('mucus', cycleDay.mucus)}> </Button> </View> @@ -79,7 +79,7 @@ export default class DayView extends Component { <Text style={styles.symptomDayView}>Cervix</Text> <View style={styles.symptomEditButton}> <Button - onPress={() => this.showView('cervixEditView')} + onPress={() => this.showView('CervixEditView')} title={getLabel('cervix', cycleDay.cervix)}> </Button> </View> @@ -88,7 +88,7 @@ export default class DayView extends Component { <Text style={styles.symptomDayView}>Note</Text> <View style={styles.symptomEditButton}> <Button - onPress={() => this.showView('noteEditView')} + onPress={() => this.showView('NoteEditView')} title={getLabel('note', cycleDay.note)} > </Button> diff --git a/components/cycle-day/index.js b/components/cycle-day/index.js index 701758340502da22dafdca33975254c5a950b7fc..94bb51e4235958076b46bbc7e512b4799231dc27 100644 --- a/components/cycle-day/index.js +++ b/components/cycle-day/index.js @@ -6,16 +6,11 @@ import { } from 'react-native' import cycleModule from '../../lib/cycle' import { getFertilityStatusStringForDay } from '../../lib/sympto-adapter' -import DayView from './cycle-day-overview' -import BleedingEditView from './symptoms/bleeding' -import TemperatureEditView from './symptoms/temperature' -import MucusEditView from './symptoms/mucus' -import CervixEditView from './symptoms/cervix' -import NoteEditView from './symptoms/note' -import DesireEditView from './symptoms/desire' import { formatDateForViewHeader } from './labels/format' import styles from '../../styles' import actionButtonModule from './action-buttons' +import symptomComponents from './symptoms' +import DayView from './cycle-day-overview' const getCycleDayNumber = cycleModule().getCycleDayNumber @@ -25,14 +20,32 @@ export default class Day extends Component { this.cycleDay = props.navigation.state.params.cycleDay this.state = { - visibleComponent: 'dayView', + visibleComponent: 'DayView', } - this.showView = view => { + const showView = view => { this.setState({visibleComponent: view}) } - this.makeActionButtons = actionButtonModule(this.showView) + const makeActionButtons = actionButtonModule(showView) + + const symptomComponentNames = Object.keys(symptomComponents) + this.cycleDayViews = symptomComponentNames.reduce((acc, curr) => { + acc[curr] = React.createElement( + symptomComponents[curr], + { + cycleDay: this.cycleDay, + makeActionButtons + } + ) + return acc + }, {}) + + // DayView needs showView instead of makeActionButtons + this.cycleDayViews.DayView = React.createElement(DayView, { + cycleDay: this.cycleDay, + showView + }) } render() { @@ -56,16 +69,7 @@ export default class Day extends Component { </Text> </View > <View> - { - { dayView: <DayView cycleDay={this.cycleDay} showView={this.showView} />, - bleedingEditView: <BleedingEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons}/>, - temperatureEditView: <TemperatureEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons}/>, - mucusEditView: <MucusEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons}/>, - cervixEditView: <CervixEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons} />, - noteEditView: <NoteEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons} />, - desireEditView: <DesireEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons} /> - }[this.state.visibleComponent] - } + { this.cycleDayViews[this.state.visibleComponent] } </View > </ScrollView > ) diff --git a/components/cycle-day/symptoms/index.js b/components/cycle-day/symptoms/index.js new file mode 100644 index 0000000000000000000000000000000000000000..617dbab46d2d1d59b522ddc17712a98271c1ed25 --- /dev/null +++ b/components/cycle-day/symptoms/index.js @@ -0,0 +1,15 @@ +import BleedingEditView from './bleeding' +import TemperatureEditView from './temperature' +import MucusEditView from './mucus' +import CervixEditView from './cervix' +import NoteEditView from './note' +import DesireEditView from './desire' + +export default { + BleedingEditView, + TemperatureEditView, + MucusEditView, + CervixEditView, + NoteEditView, + DesireEditView +} \ No newline at end of file diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index 11961a9c151f2cf376c8f13a59b974e8bbb4730f..7296883201ddb475bb2aa0ba5dac3bc0c6513144 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -12,6 +12,8 @@ import { getPreviousTemperature, saveSymptom } from '../../../db' import styles from '../../../styles' import { LocalTime, ChronoUnit } from 'js-joda' +const MINUTES = ChronoUnit.MINUTES + export default class Temp extends Component { constructor(props) { super(props) @@ -32,7 +34,7 @@ export default class Temp extends Component { this.state = { currentValue: initialValue, exclude: temp ? temp.exclude : false, - time: this.time || LocalTime.now().truncatedTo(ChronoUnit.MINUTES).toString(), + time: this.time || LocalTime.now().truncatedTo(MINUTES).toString(), isTimePickerVisible: false } } diff --git a/components/home.js b/components/home.js index 48af5f5d72b19b64727f492a04e78e2ff5d3e86d..735b03aa9f2a64a7fc6c66b539acda22f6a28239 100644 --- a/components/home.js +++ b/components/home.js @@ -24,8 +24,9 @@ export default class Home extends Component { this.setStateWithCurrentWelcomeText = (function (HomeComponent) { return function () { + const cycleDayNumber = getCycleDayNumber(HomeComponent.todayDateString) HomeComponent.setState({ - welcomeText: determineWelcomeText(getCycleDayNumber(HomeComponent.todayDateString)) + welcomeText: determineWelcomeText(cycleDayNumber) }) } })(this) diff --git a/lib/cycle.js b/lib/cycle.js index f60a74f321d040e9937f7726d995ba24cbdec651..f350ff827e0b17e3aeb17c185d48e308e1980f21 100644 --- a/lib/cycle.js +++ b/lib/cycle.js @@ -1,6 +1,6 @@ import * as joda from 'js-joda' const LocalDate = joda.LocalDate - +const DAYS = joda.ChronoUnit.DAYS export default function config(opts) { let bleedingDaysSortedByDate @@ -28,28 +28,32 @@ export default function config(opts) { return day }) - const firstBleedingDayBeforeTargetDayIndex = withWrappedDates.findIndex(day => { + // the index of the first bleeding day before the target day + const index = withWrappedDates.findIndex(day => { return ( day.wrappedDate.isEqual(targetDate) || day.wrappedDate.isBefore(targetDate) ) }) - if (firstBleedingDayBeforeTargetDayIndex < 0) { + if (index < 0) { withWrappedDates.forEach(day => delete day.wrappedDate) return null } - const previousBleedingDays = withWrappedDates.slice(firstBleedingDayBeforeTargetDayIndex) + const prevBleedingDays = withWrappedDates.slice(index) - const lastMensesStart = previousBleedingDays.find((day, i) => { - return thereIsNoPreviousBleedingDayWithinTheThreshold(day, previousBleedingDays.slice(i + 1)) + const lastMensesStart = prevBleedingDays.find((day, i) => { + return noBleedingDayWithinThreshold(day, prevBleedingDays.slice(i + 1)) }) - function thereIsNoPreviousBleedingDayWithinTheThreshold(bleedingDay, previousBleedingDays) { - const periodThreshold = bleedingDay.wrappedDate.minusDays(maxBreakInBleeding + 1) + function noBleedingDayWithinThreshold(day, previousBleedingDays) { + const periodThreshold = day.wrappedDate.minusDays(maxBreakInBleeding + 1) return !previousBleedingDays.some(({ wrappedDate }) => { - return wrappedDate.equals(periodThreshold) || wrappedDate.isAfter(periodThreshold) + return ( + wrappedDate.equals(periodThreshold) || + wrappedDate.isAfter(periodThreshold) + ) }) } @@ -66,9 +70,11 @@ export default function config(opts) { return day }) - const firstBleedingDayAfterTargetDay = withWrappedDates.reverse().find(day => { - return day.wrappedDate.isAfter(targetDate) - }) + const firstBleedingDayAfterTargetDay = withWrappedDates + .reverse() + .find(day => { + return day.wrappedDate.isAfter(targetDate) + }) withWrappedDates.forEach(day => delete day.wrappedDate) @@ -80,7 +86,7 @@ export default function config(opts) { if (!lastMensesStart) return null const targetDate = LocalDate.parse(targetDateString) const lastMensesLocalDate = LocalDate.parse(lastMensesStart.date) - const diffInDays = lastMensesLocalDate.until(targetDate, joda.ChronoUnit.DAYS) + const diffInDays = lastMensesLocalDate.until(targetDate, DAYS) // cycle starts at day 1 return diffInDays + 1 @@ -100,7 +106,11 @@ export default function config(opts) { function getPreviousCycle(dateString) { const startOfCycle = getLastMensesStart(dateString) if (!startOfCycle) return null - const dateBeforeStartOfCycle = LocalDate.parse(startOfCycle.date).minusDays(1).toString() + const dateBeforeStartOfCycle = LocalDate + .parse(startOfCycle.date) + .minusDays(1) + .toString() + return getCycleForDay(dateBeforeStartOfCycle) } diff --git a/lib/sympto/index.js b/lib/sympto/index.js index b9306380b639e9978966612a2ea08a887ca52d00..c85b3ca12bb809a00d35e5995be1ea7da26a9306 100644 --- a/lib/sympto/index.js +++ b/lib/sympto/index.js @@ -4,7 +4,8 @@ import getPreOvulatoryPhase from './pre-ovulatory' import { LocalDate } from 'js-joda' import assert from 'assert' -export default function getSymptoThermalStatus({ cycle, previousCycle, earlierCycles = [] }) { +export default function getSymptoThermalStatus(cycles) { + const { cycle, previousCycle, earlierCycles = [] } = cycles throwIfArgsAreNotInRequiredFormat([cycle, ...earlierCycles]) const status = { diff --git a/test/cycle.spec.js b/test/cycle.spec.js index 3b82c40d271b6cb1d37fc25fdfdef2a7a35c4f03..a0efa7d45cec8b562a0fac6d2df6c36c1ead3f75 100644 --- a/test/cycle.spec.js +++ b/test/cycle.spec.js @@ -5,6 +5,10 @@ import cycleModule from '../lib/cycle' const expect = chai.expect chai.use(dirtyChai) +function useBleedingDays(days) { + return cycleModule({ bleedingDaysSortedByDate: days }).getCycleDayNumber +} + describe('getCycleDay', () => { it('works for a simple example', () => { const bleedingDays = [{ @@ -23,7 +27,7 @@ describe('getCycleDay', () => { value: 2 } }] - const getCycleDayNumber = cycleModule({ bleedingDaysSortedByDate: bleedingDays }).getCycleDayNumber + const getCycleDayNumber = useBleedingDays(bleedingDays) const targetDate = '2018-05-17' const result = getCycleDayNumber(targetDate) expect(result).to.eql(9) @@ -49,7 +53,7 @@ describe('getCycleDay', () => { } }] const targetDate = '2018-05-17' - const getCycleDayNumber = cycleModule({ bleedingDaysSortedByDate: bleedingDays }).getCycleDayNumber + const getCycleDayNumber = useBleedingDays(bleedingDays) const result = getCycleDayNumber(targetDate) expect(result).to.eql(15) }) @@ -73,7 +77,7 @@ describe('getCycleDay', () => { }] const targetDate = '2018-04-27' - const getCycleDayNumber = cycleModule({ bleedingDaysSortedByDate: bleedingDays }).getCycleDayNumber + const getCycleDayNumber = useBleedingDays(bleedingDays) const result = getCycleDayNumber(targetDate) expect(result).to.eql(18) }) @@ -87,7 +91,7 @@ describe('getCycleDay', () => { }] const targetDate = '2018-05-13' - const getCycleDayNumber = cycleModule({ bleedingDaysSortedByDate: bleedingDays }).getCycleDayNumber + const getCycleDayNumber = useBleedingDays(bleedingDays) const result = getCycleDayNumber(targetDate) expect(result).to.eql(1) }) @@ -96,7 +100,7 @@ describe('getCycleDay', () => { it('if there are no bleeding days', function () { const bleedingDays = [] const targetDate = '2018-05-17' - const getCycleDayNumber = cycleModule({ bleedingDaysSortedByDate: bleedingDays }).getCycleDayNumber + const getCycleDayNumber = useBleedingDays(bleedingDays) const result = getCycleDayNumber(targetDate) expect(result).to.be.null() }) @@ -119,7 +123,10 @@ describe('getCycleDay', () => { }] const targetDate = '2018-05-17' - const getCycleDayNumber = cycleModule({ bleedingDaysSortedByDate: bleedingDays, maxBreakInBleeding }).getCycleDayNumber + const getCycleDayNumber = cycleModule({ + bleedingDaysSortedByDate: bleedingDays, + maxBreakInBleeding + }).getCycleDayNumber const result = getCycleDayNumber(targetDate) expect(result).to.eql(8) }) @@ -137,7 +144,10 @@ describe('getCycleDay', () => { } }] const targetDate = '2018-05-17' - const getCycleDayNumber = cycleModule({ bleedingDaysSortedByDate: bleedingDays, maxBreakInBleeding }).getCycleDayNumber + const getCycleDayNumber = cycleModule({ + bleedingDaysSortedByDate: bleedingDays, + maxBreakInBleeding + }).getCycleDayNumber const result = getCycleDayNumber(targetDate) expect(result).to.eql(4) })