Merge branch '268-sympto-respect-max-cycle-length' into 'master'

Resolve "sympto: respect max cycle length"

Closes #268

See merge request bloodyhealth/drip!142
This commit is contained in:
Julia Friesel
2019-01-05 09:50:43 +00:00
3 changed files with 278 additions and 27 deletions
+26 -20
View File
@@ -1,5 +1,5 @@
import * as joda from 'js-joda'
import {getCycleLengthStats} from './cycle-length'
import { getCycleLengthStats } from './cycle-length'
const LocalDate = joda.LocalDate
const DAYS = joda.ChronoUnit.DAYS
@@ -40,7 +40,7 @@ export default function config(opts) {
const lastMensesLocalDate = LocalDate.parse(lastMensesStart.date)
const diffInDays = lastMensesLocalDate.until(targetDate, DAYS)
// take maxCycleLength into account (we don't display cycle day numbers higher than 99 at the moment)
if (diffInDays >= 99) return null
if (diffInDays >= maxCycleLength) return null
// cycle starts at day 1
return diffInDays + 1
}
@@ -61,28 +61,38 @@ export default function config(opts) {
if (startFromHere < 0) return null
return cycleStartsSortedByDate
.slice(startFromHere)
.map(getCycleForCycleStartDay)
.map(start => getCycleForCycleStartDay(start))
// filter the ones exceeding maxCycleLength, those are null
.filter(cycle => cycle)
}
function getCycleForCycleStartDay(startDay) {
function getCycleForCycleStartDay(startDay, todayDate) {
const todayAsLocalDate = todayDate ? LocalDate.parse(todayDate) : LocalDate.now()
const cycleStartIndex = cycleDaysSortedByDate.indexOf(startDay)
const i = cycleStartsSortedByDate.indexOf(startDay)
const startLocalDate = LocalDate.parse(startDay.date)
const nextMensesStart = cycleStartsSortedByDate[i - 1]
let cycle
let cycleLength
if (nextMensesStart) {
return cycleDaysSortedByDate.slice(
cycle = cycleDaysSortedByDate.slice(
cycleDaysSortedByDate.indexOf(nextMensesStart) + 1,
cycleStartIndex + 1,
)
const nextLocalDate = LocalDate.parse(nextMensesStart.date)
cycleLength = startLocalDate.until(nextLocalDate, DAYS)
} else {
return cycleDaysSortedByDate.slice(0, cycleStartIndex + 1)
cycle = cycleDaysSortedByDate.slice(0, cycleStartIndex + 1)
cycleLength = startLocalDate.until(todayAsLocalDate, DAYS)
}
return cycleLength > maxCycleLength ? null : cycle
}
function getCycleForDay(dayOrDate) {
function getCycleForDay(dayOrDate, todayDate) {
const dateString = typeof dayOrDate === 'string' ? dayOrDate : dayOrDate.date
const cycleStart = getLastMensesStartForDay(dateString)
if (!cycleStart) return null
return getCycleForCycleStartDay(cycleStart)
return getCycleForCycleStartDay(cycleStart, todayDate)
}
function isMensesStart(cycleDay) {
@@ -138,24 +148,19 @@ export default function config(opts) {
function getAllCycleLengths() {
return cycleStartsSortedByDate
.map(day => LocalDate.parse(day.date))
.reduce((lengths, cycleStart, i, startsAsLocalDates) => {
if (i === startsAsLocalDates.length - 1) return lengths
.map((cycleStart, i, startsAsLocalDates) => {
if (i === cycleStartsSortedByDate.length - 1) return null
const prevCycleStart = startsAsLocalDates[i + 1]
const cycleLength = prevCycleStart.until(cycleStart, DAYS)
if (cycleLength <= maxCycleLength) { lengths.push(cycleLength) }
return lengths
}, [])
return prevCycleStart.until(cycleStart, DAYS)
})
.filter(length => length && length <= maxCycleLength)
}
function getPredictedMenses() {
const allMensesStarts = cycleStartsSortedByDate
const atLeastOneCycle = allMensesStarts.length > 1
if (!atLeastOneCycle ||
allMensesStarts.length < minCyclesForPrediction
) {
const cycleLengths = getAllCycleLengths()
if (cycleLengths.length < minCyclesForPrediction) {
return []
}
const cycleLengths = getAllCycleLengths()
const cycleInfo = getCycleLengthStats(cycleLengths)
const periodDistance = Math.round(cycleInfo.mean)
let periodStartVariation
@@ -169,6 +174,7 @@ export default function config(opts) {
if (periodDistance - 5 < periodStartVariation) { // otherwise predictions overlap
return []
}
const allMensesStarts = cycleStartsSortedByDate
let lastStart = LocalDate.parse(allMensesStarts[0].date)
const predictedMenses = []
for (let i = 0; i < 3; i++) {