From ea21fc92a25da8e6c583f96692f5519f322ba212 Mon Sep 17 00:00:00 2001 From: tina Date: Wed, 22 Aug 2018 18:21:57 +0200 Subject: [PATCH 1/5] moves getCycleLength to corresponding files, adds function to get next menses (not finished) with first tests --- components/stats.js | 14 +---- lib/cycle-length.js | 14 ++++- lib/cycle.js | 33 +++++++++- test/cycle-length.spec.js | 2 +- test/cycle.spec.js | 123 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 171 insertions(+), 15 deletions(-) diff --git a/components/stats.js b/components/stats.js index f3f136c..6ae0e27 100644 --- a/components/stats.js +++ b/components/stats.js @@ -4,10 +4,10 @@ import { View, ScrollView } from 'react-native' -import { LocalDate, ChronoUnit } from 'js-joda' + import styles from '../styles/index' import cycleModule from '../lib/cycle' -import getCycleInfo from '../lib/cycle-length' +import {getCycleLengthStats as getCycleInfo, getCycleLength} from '../lib/cycle-length' import {stats as labels} from './labels' export default class Stats extends Component { @@ -56,14 +56,4 @@ export default class Stats extends Component { ) } -} - -function getCycleLength(cycleStartDates) { - const cycleLengths = [] - for (let i = 0; i < cycleStartDates.length - 1; i++) { - const nextCycleStart = LocalDate.parse(cycleStartDates[i]) - const cycleStart = LocalDate.parse(cycleStartDates[i + 1]) - cycleLengths.push(cycleStart.until(nextCycleStart, ChronoUnit.DAYS)) - } - return cycleLengths } \ No newline at end of file diff --git a/lib/cycle-length.js b/lib/cycle-length.js index 6f8feb5..1d4ae02 100644 --- a/lib/cycle-length.js +++ b/lib/cycle-length.js @@ -1,6 +1,8 @@ import assert from 'assert' +import { LocalDate, ChronoUnit } from 'js-joda' +import cycleModule from '../lib/cycle' -export default function getCycleLengthStats(cycleLengths) { +export function getCycleLengthStats(cycleLengths) { throwIfArgsAreNotInRequiredFormat(cycleLengths) const cycleLengthStats = {} const sortedCycleLengths = cycleLengths.sort((a, b) => { @@ -46,4 +48,14 @@ function throwIfArgsAreNotInRequiredFormat(cycleLengths) { assert.equal(typeof cycleLength, 'number', 'Elements in the array should be of type number.') assert.ok(!isNaN(cycleLength), 'Elements of array should not be NaN.') }) +} + +export function getCycleLength(cycleStartDates) { + const cycleLengths = [] + for (let i = 0; i < cycleStartDates.length - 1; i++) { + const nextCycleStart = LocalDate.parse(cycleStartDates[i]) + const cycleStart = LocalDate.parse(cycleStartDates[i + 1]) + cycleLengths.push(cycleStart.until(nextCycleStart, ChronoUnit.DAYS)) + } + return cycleLengths } \ No newline at end of file diff --git a/lib/cycle.js b/lib/cycle.js index 23bc3cd..affdee8 100644 --- a/lib/cycle.js +++ b/lib/cycle.js @@ -1,4 +1,5 @@ import * as joda from 'js-joda' +import {getCycleLengthStats, getCycleLength} from './cycle-length' const LocalDate = joda.LocalDate const DAYS = joda.ChronoUnit.DAYS @@ -143,11 +144,41 @@ export default function config(opts) { } } + function getPredictedMenses(maxCycleLength, minCyclesForPrediction) { + maxCycleLength = maxCycleLength || 99 + minCyclesForPrediction = minCyclesForPrediction || 3 + const allMensesStarts = getAllMensesStarts() + + const atLeastOneCycle = allMensesStarts.length > 1 + if (!atLeastOneCycle || + allMensesStarts.length < minCyclesForPrediction || + getCycleDayNumber(LocalDate.now().toString()) > maxCycleLength + ) { + return {} + } + const cycleLengths = getCycleLength(allMensesStarts) + const cycleInfo = getCycleLengthStats(cycleLengths) + const periodDistance = Math.round(cycleInfo.mean) + const periodStartVariation = (cycleInfo.stdDeviation < 1.5) ? 1 : 2 // threshold is choosen a little arbitrarily + var lastStart = allMensesStarts[0] + const predictedMenses = [] + for (let i = 0; i < 3; i++) { + lastStart = LocalDate.parse(lastStart).plusDays(periodDistance).toString() + const nextPredictedRange = { + 'startDate': LocalDate.parse(lastStart).minusDays(periodStartVariation).toString(), + 'endDate': LocalDate.parse(lastStart).plusDays(periodStartVariation).toString() + } + predictedMenses.push(nextPredictedRange) + } + return predictedMenses + } + return { getCycleDayNumber, getCycleForDay, getPreviousCycle, getCyclesBefore, - getAllMensesStarts + getAllMensesStarts, + getPredictedMenses } } \ No newline at end of file diff --git a/test/cycle-length.spec.js b/test/cycle-length.spec.js index 043cf96..3714337 100644 --- a/test/cycle-length.spec.js +++ b/test/cycle-length.spec.js @@ -1,7 +1,7 @@ import chai from 'chai' import { AssertionError } from 'assert' -import cycleInfo from '../lib/cycle-length' +import {getCycleLengthStats as cycleInfo} from '../lib/cycle-length' const expect = chai.expect diff --git a/test/cycle.spec.js b/test/cycle.spec.js index a0efa7d..09df48f 100644 --- a/test/cycle.spec.js +++ b/test/cycle.spec.js @@ -343,4 +343,127 @@ describe('getCycleForDay', () => { }, ]) }) +}) + +describe.only('getPredictedMenses', () => { + describe('cannot predict next menses', () => { + it('if no bleeding is documented', () => { + const cycleDaysSortedByDate = [ {} ] + + const { getPredictedMenses } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const result = getPredictedMenses(99, 1) + expect(result).to.eql({}) + }) + it('if no cycle is completed', () => { + const cycleDaysSortedByDate = [ + { + date: '2018-06-02', + bleeding: { value: 2 } + } + ] + + const { getPredictedMenses } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const result = getPredictedMenses(99, 1) + expect(result).to.eql({}) + }) + it('if number of cycles is below minCyclesForPrediction', () => { + const cycleDaysSortedByDate = [ + { + date: '2018-06-02', + bleeding: { value: 2 } + }, + { + date: '2018-06-01', + bleeding: { value: 2 } + }, + { + date: '2018-05-01', + bleeding: { value: 2 } + }, + ] + + const { getPredictedMenses } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const result = getPredictedMenses() + expect(result).to.eql({}) + }) + it('if last bleeding was more than maxCycleLength days ago', () => { + const cycleDaysSortedByDate = [ + { + date: '2017-07-02', + bleeding: { value: 2 } + }, + { + date: '2017-06-01', + bleeding: { value: 2 } + }, + { + date: '2017-05-01', + bleeding: { value: 2 } + }, + { + date: '2017-04-01', + bleeding: { value: 2 } + } + ] + + const { getPredictedMenses } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const result = getPredictedMenses() + expect(result).to.eql({}) + }) + }) + describe('works', () => { + it('if number of cycles is above minCyclesForPrediction with little standard deviation', () => { + const cycleDaysSortedByDate = [ + { + date: '2018-08-02', + bleeding: { value: 2 } + }, + { + date: '2018-07-02', + bleeding: { value: 2 } + }, + { + date: '2018-06-01', + bleeding: { value: 2 } + }, + { + date: '2018-05-01', + bleeding: { value: 2 } + }, + ] + + const { getPredictedMenses } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const result = getPredictedMenses() + const expectedResult = [ + { + 'startDate': '2018-09-01', + 'endDate': '2018-09-03' + }, + { + 'startDate': '2018-10-02', + 'endDate': '2018-10-04' + }, + { + 'startDate': '2018-11-02', + 'endDate': '2018-11-04' + } + ] + expect(result).to.eql(expectedResult) + }) + }) }) \ No newline at end of file From 497a3a3ff500b10537f1a1d1da26a1a90eb72ba1 Mon Sep 17 00:00:00 2001 From: tina Date: Thu, 23 Aug 2018 11:36:57 +0200 Subject: [PATCH 2/5] adds more tests for period predictions, moves getcycleslength into cycle module --- components/stats.js | 12 ++-- lib/cycle-length.js | 12 ---- lib/cycle.js | 36 +++++++++--- test/cycle.spec.js | 137 +++++++++++++++++++++++++++++++++++++------- 4 files changed, 152 insertions(+), 45 deletions(-) diff --git a/components/stats.js b/components/stats.js index 6ae0e27..ad4b0e6 100644 --- a/components/stats.js +++ b/components/stats.js @@ -7,7 +7,7 @@ import { import styles from '../styles/index' import cycleModule from '../lib/cycle' -import {getCycleLengthStats as getCycleInfo, getCycleLength} from '../lib/cycle-length' +import {getCycleLengthStats as getCycleInfo} from '../lib/cycle-length' import {stats as labels} from './labels' export default class Stats extends Component { @@ -18,7 +18,7 @@ export default class Stats extends Component { let numberOfCycles let cycleInfo if (atLeastOneCycle) { - cycleLengths = getCycleLength(allMensesStarts) + cycleLengths = cycleModule().getCycleLength(allMensesStarts) numberOfCycles = cycleLengths.length if (numberOfCycles > 1) { cycleInfo = getCycleInfo(cycleLengths) @@ -31,10 +31,14 @@ export default class Stats extends Component { {labels.emptyStats} } {atLeastOneCycle && numberOfCycles === 1 && - {labels.oneCycleStats(cycleLengths[0])} + + {labels.oneCycleStats(cycleLengths[0])} + } {atLeastOneCycle && numberOfCycles > 1 && - {labels.getBasisOfStats(numberOfCycles)} + + {labels.getBasisOfStats(numberOfCycles)} + {labels.averageLabel} {cycleInfo.mean + ' ' + labels.daysLabel} diff --git a/lib/cycle-length.js b/lib/cycle-length.js index 1d4ae02..956328d 100644 --- a/lib/cycle-length.js +++ b/lib/cycle-length.js @@ -1,6 +1,4 @@ import assert from 'assert' -import { LocalDate, ChronoUnit } from 'js-joda' -import cycleModule from '../lib/cycle' export function getCycleLengthStats(cycleLengths) { throwIfArgsAreNotInRequiredFormat(cycleLengths) @@ -48,14 +46,4 @@ function throwIfArgsAreNotInRequiredFormat(cycleLengths) { assert.equal(typeof cycleLength, 'number', 'Elements in the array should be of type number.') assert.ok(!isNaN(cycleLength), 'Elements of array should not be NaN.') }) -} - -export function getCycleLength(cycleStartDates) { - const cycleLengths = [] - for (let i = 0; i < cycleStartDates.length - 1; i++) { - const nextCycleStart = LocalDate.parse(cycleStartDates[i]) - const cycleStart = LocalDate.parse(cycleStartDates[i + 1]) - cycleLengths.push(cycleStart.until(nextCycleStart, ChronoUnit.DAYS)) - } - return cycleLengths } \ No newline at end of file diff --git a/lib/cycle.js b/lib/cycle.js index affdee8..5d41855 100644 --- a/lib/cycle.js +++ b/lib/cycle.js @@ -1,5 +1,5 @@ import * as joda from 'js-joda' -import {getCycleLengthStats, getCycleLength} from './cycle-length' +import {getCycleLengthStats} from './cycle-length' const LocalDate = joda.LocalDate const DAYS = joda.ChronoUnit.DAYS @@ -7,6 +7,8 @@ export default function config(opts) { let bleedingDaysSortedByDate let cycleDaysSortedByDate let maxBreakInBleeding + let maxCycleLength + let minCyclesForPrediction if (!opts) { // we only want to require (and run) the db module @@ -14,10 +16,14 @@ export default function config(opts) { bleedingDaysSortedByDate = require('../db').bleedingDaysSortedByDate cycleDaysSortedByDate = require('../db').cycleDaysSortedByDate maxBreakInBleeding = 1 + maxCycleLength = 99 + minCyclesForPrediction = 3 } else { bleedingDaysSortedByDate = opts.bleedingDaysSortedByDate || [] cycleDaysSortedByDate = opts.cycleDaysSortedByDate || [] maxBreakInBleeding = opts.maxBreakInBleeding || 1 + maxCycleLength = opts.maxCycleLength || 99 + minCyclesForPrediction = opts.minCyclesForPrediction || 3 } function getLastMensesStart(targetDateString) { @@ -144,22 +150,37 @@ export default function config(opts) { } } - function getPredictedMenses(maxCycleLength, minCyclesForPrediction) { - maxCycleLength = maxCycleLength || 99 - minCyclesForPrediction = minCyclesForPrediction || 3 + function getCycleLength(cycleStartDates) { + const cycleLengths = [] + for (let i = 0; i < cycleStartDates.length - 1; i++) { + const nextCycleStart = LocalDate.parse(cycleStartDates[i]) + const cycleStart = LocalDate.parse(cycleStartDates[i + 1]) + const cycleLength = cycleStart.until(nextCycleStart, DAYS) + if (cycleLength <= maxCycleLength) { cycleLengths.push(cycleLength) } + } + return cycleLengths + } + + function getPredictedMenses() { const allMensesStarts = getAllMensesStarts() const atLeastOneCycle = allMensesStarts.length > 1 if (!atLeastOneCycle || - allMensesStarts.length < minCyclesForPrediction || - getCycleDayNumber(LocalDate.now().toString()) > maxCycleLength + allMensesStarts.length < minCyclesForPrediction ) { return {} } const cycleLengths = getCycleLength(allMensesStarts) const cycleInfo = getCycleLengthStats(cycleLengths) const periodDistance = Math.round(cycleInfo.mean) - const periodStartVariation = (cycleInfo.stdDeviation < 1.5) ? 1 : 2 // threshold is choosen a little arbitrarily + let periodStartVariation + if (cycleInfo.stdDeviation === null) { + periodStartVariation = 2 + } else if (cycleInfo.stdDeviation < 1.5) { // threshold is choosen a little arbitrarily + periodStartVariation = 1 + } else { + periodStartVariation = 2 + } var lastStart = allMensesStarts[0] const predictedMenses = [] for (let i = 0; i < 3; i++) { @@ -179,6 +200,7 @@ export default function config(opts) { getPreviousCycle, getCyclesBefore, getAllMensesStarts, + getCycleLength, getPredictedMenses } } \ No newline at end of file diff --git a/test/cycle.spec.js b/test/cycle.spec.js index 09df48f..34ed144 100644 --- a/test/cycle.spec.js +++ b/test/cycle.spec.js @@ -345,19 +345,21 @@ describe('getCycleForDay', () => { }) }) -describe.only('getPredictedMenses', () => { +describe('getPredictedMenses', () => { describe('cannot predict next menses', () => { it('if no bleeding is documented', () => { const cycleDaysSortedByDate = [ {} ] const { getPredictedMenses } = cycleModule({ cycleDaysSortedByDate, - bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding), + maxCycleLength: 99, + minCyclesForPrediction: 1 }) - const result = getPredictedMenses(99, 1) + const result = getPredictedMenses() expect(result).to.eql({}) }) - it('if no cycle is completed', () => { + it('if one bleeding is documented (no completed cycle)', () => { const cycleDaysSortedByDate = [ { date: '2018-06-02', @@ -367,9 +369,11 @@ describe.only('getPredictedMenses', () => { const { getPredictedMenses } = cycleModule({ cycleDaysSortedByDate, - bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding), + maxCycleLength: 99, + minCyclesForPrediction: 1 }) - const result = getPredictedMenses(99, 1) + const result = getPredictedMenses() expect(result).to.eql({}) }) it('if number of cycles is below minCyclesForPrediction', () => { @@ -395,36 +399,43 @@ describe.only('getPredictedMenses', () => { const result = getPredictedMenses() expect(result).to.eql({}) }) - it('if last bleeding was more than maxCycleLength days ago', () => { + }) + describe('works', () => { + it('for one completed cycle with minCyclesForPrediction = 1', () => { const cycleDaysSortedByDate = [ { - date: '2017-07-02', + date: '2018-07-15', bleeding: { value: 2 } }, { - date: '2017-06-01', - bleeding: { value: 2 } - }, - { - date: '2017-05-01', - bleeding: { value: 2 } - }, - { - date: '2017-04-01', + date: '2018-07-01', bleeding: { value: 2 } } ] const { getPredictedMenses } = cycleModule({ cycleDaysSortedByDate, - bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding), + minCyclesForPrediction: 1 }) const result = getPredictedMenses() - expect(result).to.eql({}) + const expectedResult = [ + { + 'startDate': '2018-07-27', + 'endDate': '2018-07-31' + }, + { + 'startDate': '2018-08-10', + 'endDate': '2018-08-14' + }, + { + 'startDate': '2018-08-24', + 'endDate': '2018-08-28' + } + ] + expect(result).to.eql(expectedResult) }) - }) - describe('works', () => { - it('if number of cycles is above minCyclesForPrediction with little standard deviation', () => { + it('if number of cycles is above minCyclesForPrediction', () => { const cycleDaysSortedByDate = [ { date: '2018-08-02', @@ -465,5 +476,87 @@ describe.only('getPredictedMenses', () => { ] expect(result).to.eql(expectedResult) }) + it('3 cycles with little standard deviation', () => { + const cycleDaysSortedByDate = [ + { + date: '2018-08-01', + bleeding: { value: 2 } + }, + { + date: '2018-07-18', + bleeding: { value: 2 } + }, + { + date: '2018-07-05', + bleeding: { value: 2 } + }, + { + date: '2018-06-20', + bleeding: { value: 2 } + }, + ] + + const { getPredictedMenses } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const result = getPredictedMenses() + const expectedResult = [ + { + 'startDate': '2018-08-14', + 'endDate': '2018-08-16' + }, + { + 'startDate': '2018-08-28', + 'endDate': '2018-08-30' + }, + { + 'startDate': '2018-09-11', + 'endDate': '2018-09-13' + } + ] + expect(result).to.eql(expectedResult) + }) + it('3 cycles with bigger standard deviation', () => { + const cycleDaysSortedByDate = [ + { + date: '2018-08-01', + bleeding: { value: 2 } + }, + { + date: '2018-07-14', + bleeding: { value: 2 } + }, + { + date: '2018-07-04', + bleeding: { value: 2 } + }, + { + date: '2018-06-20', + bleeding: { value: 2 } + }, + ] + + const { getPredictedMenses } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const result = getPredictedMenses() + const expectedResult = [ + { + 'startDate': '2018-08-13', + 'endDate': '2018-08-17' + }, + { + 'startDate': '2018-08-27', + 'endDate': '2018-08-31' + }, + { + 'startDate': '2018-09-10', + 'endDate': '2018-09-14' + } + ] + expect(result).to.eql(expectedResult) + }) }) }) \ No newline at end of file From e0474400688f8d5f6f551bde662b670eed3933b1 Mon Sep 17 00:00:00 2001 From: tina Date: Thu, 23 Aug 2018 17:28:53 +0200 Subject: [PATCH 3/5] changs output of getpredictedmenses, adds days to calendar --- components/calendar.js | 37 ++++++++++-- lib/cycle.js | 20 ++++--- test/cycle.spec.js | 126 ++++++++++++++++++++++++----------------- 3 files changed, 119 insertions(+), 64 deletions(-) diff --git a/components/calendar.js b/components/calendar.js index 72fb1ba..2e70c4a 100644 --- a/components/calendar.js +++ b/components/calendar.js @@ -1,19 +1,23 @@ import React, { Component } from 'react' import { CalendarList } from 'react-native-calendars' import { getOrCreateCycleDay, bleedingDaysSortedByDate } from '../db' +import cycleModule from '../lib/cycle' export default class CalendarView extends Component { constructor(props) { super(props) + const predictedMenses = cycleModule().getPredictedMenses() this.state = { - bleedingDaysInCalFormat: toCalFormat(bleedingDaysSortedByDate) + bleedingDaysInCalFormat: toCalFormat(bleedingDaysSortedByDate), + predictedBleedingDaysInCalFormat: predictionToCalFormat(predictedMenses) } this.setStateWithCalFormattedDays = (function (CalendarComponent) { - return function(_, changes) { - if (Object.values(changes).every(x => x && !x.length)) return + return function() { + const predictedMenses = cycleModule().getPredictedMenses() CalendarComponent.setState({ - bleedingDaysInCalFormat: toCalFormat(bleedingDaysSortedByDate) + bleedingDaysInCalFormat: toCalFormat(bleedingDaysSortedByDate), + predictedBleedingDaysInCalFormat: predictionToCalFormat(predictedMenses) }) } })(this) @@ -35,7 +39,13 @@ export default class CalendarView extends Component { return ( ) @@ -52,4 +62,21 @@ function toCalFormat(bleedingDaysSortedByDate) { } return acc }, {}) +} + +function predictionToCalFormat(predictedDays) { + if (!predictedDays.length) return {} + const shadesOfGrey = ['#e5e5e5', '#cccccc'] // [lighter, darker] + const middleIndex = (predictedDays[0].length - 1) / 2 + return predictedDays.reduce((acc, setOfDays) => { + setOfDays.reduce((accSet, day, i) => { + accSet[day] = { + startingDay: true, + endingDay: true, + color: (i === middleIndex) ? shadesOfGrey[1] : shadesOfGrey[0] + } + return accSet + }, acc) + return acc + }, {}) } \ No newline at end of file diff --git a/lib/cycle.js b/lib/cycle.js index 5d41855..da91e2d 100644 --- a/lib/cycle.js +++ b/lib/cycle.js @@ -163,12 +163,11 @@ export default function config(opts) { function getPredictedMenses() { const allMensesStarts = getAllMensesStarts() - const atLeastOneCycle = allMensesStarts.length > 1 if (!atLeastOneCycle || allMensesStarts.length < minCyclesForPrediction ) { - return {} + return [] } const cycleLengths = getCycleLength(allMensesStarts) const cycleInfo = getCycleLengthStats(cycleLengths) @@ -181,15 +180,20 @@ export default function config(opts) { } else { periodStartVariation = 2 } - var lastStart = allMensesStarts[0] + if (periodDistance - 5 < periodStartVariation) { // otherwise predictions overlap + return [] + } + let lastStart = LocalDate.parse(allMensesStarts[0]) const predictedMenses = [] for (let i = 0; i < 3; i++) { - lastStart = LocalDate.parse(lastStart).plusDays(periodDistance).toString() - const nextPredictedRange = { - 'startDate': LocalDate.parse(lastStart).minusDays(periodStartVariation).toString(), - 'endDate': LocalDate.parse(lastStart).plusDays(periodStartVariation).toString() + lastStart = lastStart.plusDays(periodDistance) + const nextPredictedDates = [lastStart.toString()] + for (let j = 0; j < periodStartVariation; j++) { + nextPredictedDates.push(lastStart.minusDays(j+1).toString()) + nextPredictedDates.push(lastStart.plusDays(j+1).toString()) } - predictedMenses.push(nextPredictedRange) + nextPredictedDates.sort() + predictedMenses.push(nextPredictedDates) } return predictedMenses } diff --git a/test/cycle.spec.js b/test/cycle.spec.js index 34ed144..2cbbab9 100644 --- a/test/cycle.spec.js +++ b/test/cycle.spec.js @@ -357,7 +357,7 @@ describe('getPredictedMenses', () => { minCyclesForPrediction: 1 }) const result = getPredictedMenses() - expect(result).to.eql({}) + expect(result).to.eql([]) }) it('if one bleeding is documented (no completed cycle)', () => { const cycleDaysSortedByDate = [ @@ -374,7 +374,7 @@ describe('getPredictedMenses', () => { minCyclesForPrediction: 1 }) const result = getPredictedMenses() - expect(result).to.eql({}) + expect(result).to.eql([]) }) it('if number of cycles is below minCyclesForPrediction', () => { const cycleDaysSortedByDate = [ @@ -397,7 +397,7 @@ describe('getPredictedMenses', () => { bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) }) const result = getPredictedMenses() - expect(result).to.eql({}) + expect(result).to.eql([]) }) }) describe('works', () => { @@ -420,18 +420,27 @@ describe('getPredictedMenses', () => { }) const result = getPredictedMenses() const expectedResult = [ - { - 'startDate': '2018-07-27', - 'endDate': '2018-07-31' - }, - { - 'startDate': '2018-08-10', - 'endDate': '2018-08-14' - }, - { - 'startDate': '2018-08-24', - 'endDate': '2018-08-28' - } + [ + '2018-07-27', + '2018-07-28', + '2018-07-29', + '2018-07-30', + '2018-07-31' + ], + [ + '2018-08-10', + '2018-08-11', + '2018-08-12', + '2018-08-13', + '2018-08-14', + ], + [ + '2018-08-24', + '2018-08-25', + '2018-08-26', + '2018-08-27', + '2018-08-28', + ] ] expect(result).to.eql(expectedResult) }) @@ -461,18 +470,21 @@ describe('getPredictedMenses', () => { }) const result = getPredictedMenses() const expectedResult = [ - { - 'startDate': '2018-09-01', - 'endDate': '2018-09-03' - }, - { - 'startDate': '2018-10-02', - 'endDate': '2018-10-04' - }, - { - 'startDate': '2018-11-02', - 'endDate': '2018-11-04' - } + [ + '2018-09-01', + '2018-09-02', + '2018-09-03' + ], + [ + '2018-10-02', + '2018-10-03', + '2018-10-04' + ], + [ + '2018-11-02', + '2018-11-03', + '2018-11-04' + ] ] expect(result).to.eql(expectedResult) }) @@ -502,18 +514,21 @@ describe('getPredictedMenses', () => { }) const result = getPredictedMenses() const expectedResult = [ - { - 'startDate': '2018-08-14', - 'endDate': '2018-08-16' - }, - { - 'startDate': '2018-08-28', - 'endDate': '2018-08-30' - }, - { - 'startDate': '2018-09-11', - 'endDate': '2018-09-13' - } + [ + '2018-08-14', + '2018-08-15', + '2018-08-16' + ], + [ + '2018-08-28', + '2018-08-29', + '2018-08-30' + ], + [ + '2018-09-11', + '2018-09-12', + '2018-09-13' + ] ] expect(result).to.eql(expectedResult) }) @@ -543,18 +558,27 @@ describe('getPredictedMenses', () => { }) const result = getPredictedMenses() const expectedResult = [ - { - 'startDate': '2018-08-13', - 'endDate': '2018-08-17' - }, - { - 'startDate': '2018-08-27', - 'endDate': '2018-08-31' - }, - { - 'startDate': '2018-09-10', - 'endDate': '2018-09-14' - } + [ + '2018-08-13', + '2018-08-14', + '2018-08-15', + '2018-08-16', + '2018-08-17', + ], + [ + '2018-08-27', + '2018-08-28', + '2018-08-29', + '2018-08-30', + '2018-08-31', + ], + [ + '2018-09-10', + '2018-09-11', + '2018-09-12', + '2018-09-13', + '2018-09-14', + ] ] expect(result).to.eql(expectedResult) }) From 432c56c0c6fa20175cfe913a7d5795857a3d40a1 Mon Sep 17 00:00:00 2001 From: tina Date: Wed, 29 Aug 2018 17:29:33 +0200 Subject: [PATCH 4/5] information about bleeding data is shown on home screen --- components/home.js | 40 +- components/labels.js | 9 + package-lock.json | 3090 +++++++++++++++++++++--------------------- 3 files changed, 1588 insertions(+), 1551 deletions(-) diff --git a/components/home.js b/components/home.js index 2962492..6f4ab05 100644 --- a/components/home.js +++ b/components/home.js @@ -5,10 +5,11 @@ import { Text, ScrollView } from 'react-native' -import { LocalDate } from 'js-joda' +import { LocalDate, ChronoUnit } from 'js-joda' import styles from '../styles/index' import cycleModule from '../lib/cycle' import { getOrCreateCycleDay, bleedingDaysSortedByDate, fillWithDummyData, deleteAll } from '../db' +import {bleedingPrediction as labels} from './labels' const getCycleDayNumber = cycleModule().getCycleDayNumber @@ -19,23 +20,25 @@ export default class Home extends Component { const cycleDayNumber = getCycleDayNumber(this.todayDateString) this.state = { - welcomeText: determineWelcomeText(cycleDayNumber) + welcomeText: determineWelcomeText(cycleDayNumber), + predictionText: determinePredictionText() } - this.setStateWithCurrentWelcomeText = (function (HomeComponent) { + this.setStateWithCurrentText = (function (HomeComponent) { return function () { const cycleDayNumber = getCycleDayNumber(HomeComponent.todayDateString) HomeComponent.setState({ - welcomeText: determineWelcomeText(cycleDayNumber) + welcomeText: determineWelcomeText(cycleDayNumber), + predictionText: determinePredictionText() }) } })(this) - bleedingDaysSortedByDate.addListener(this.setStateWithCurrentWelcomeText) + bleedingDaysSortedByDate.addListener(this.setStateWithCurrentText) } componentWillUnmount() { - bleedingDaysSortedByDate.removeListener(this.setStateWithCurrentWelcomeText) + bleedingDaysSortedByDate.removeListener(this.setStateWithCurrentText) } passTodayToDayView() { @@ -49,6 +52,7 @@ export default class Home extends Component { return ( {this.state.welcomeText} + {this.state.predictionText}