diff --git a/components/calendar.js b/components/calendar.js index 4989d7f..67e5299 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 30ed5d7..79bea87 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} ) } diff --git a/components/cycle-day/action-buttons.js b/components/cycle-day/action-buttons.js index eb33201..78e2479 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 0b476f5..f92934b 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 { Bleeding @@ -61,7 +61,7 @@ export default class DayView extends Component { Temperature @@ -70,7 +70,7 @@ export default class DayView extends Component { Mucus @@ -79,7 +79,7 @@ export default class DayView extends Component { Cervix @@ -88,7 +88,7 @@ export default class DayView extends Component { Note diff --git a/components/cycle-day/index.js b/components/cycle-day/index.js index 7017583..94bb51e 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 { - { - { dayView: , - bleedingEditView: , - temperatureEditView: , - mucusEditView: , - cervixEditView: , - noteEditView: , - desireEditView: - }[this.state.visibleComponent] - } + { this.cycleDayViews[this.state.visibleComponent] } ) diff --git a/components/cycle-day/symptoms/index.js b/components/cycle-day/symptoms/index.js new file mode 100644 index 0000000..617dbab --- /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 11961a9..7296883 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 48af5f5..735b03a 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 f60a74f..f350ff8 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 b930638..c85b3ca 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 3b82c40..a0efa7d 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) })