diff --git a/lib/cycle.js b/lib/cycle.js index dcac869..a5bd7d3 100644 --- a/lib/cycle.js +++ b/lib/cycle.js @@ -101,21 +101,23 @@ export default function config(opts) { } } - function getMensesDaysAfter(cycleDay) { - const bleedingDays = bleedingDaysSortedByDate.filter(d => { - return !d.bleeding.exclude + function getMensesDaysRightAfter(cycleDay) { + const bleedingDays = bleedingDaysSortedByDate + .filter(d => { + return !d.bleeding.exclude + }) + .reverse() + const firstFollowingBleedingDayIndex = bleedingDays.findIndex(day => { + return day.date > cycleDay.date }) - const startIndex = bleedingDays.findIndex(day => { - return day.date === cycleDay.date - }) - return recurse(cycleDay, startIndex, []) + return recurse(cycleDay, firstFollowingBleedingDayIndex, []) - function recurse(day, i, mensesDays) { - if (i === 0) return mensesDays - const next = bleedingDays[i - 1] + function recurse(day, nextIndex, mensesDays) { + const next = bleedingDays[nextIndex] + if (!next) return mensesDays if (!isWithinThreshold(day, next)) return mensesDays mensesDays.unshift(next) - return recurse(next, i - 1, mensesDays) + return recurse(next, nextIndex + 1, mensesDays) } function isWithinThreshold(cycleDay, nextCycleDay) { @@ -174,6 +176,37 @@ export default function config(opts) { return predictedMenses } + + // TODO this also needs a test + function maybeSetNewCycleStart(oldCycleDay, newValue) { + // if a bleeding value is deleted, we need to check if + // there are any following bleeding days and if the + // next one of them is now a cycle start + + // in order to get the menses days, the cycle day in question still + // has to have a bleeding value, so we get those days first and only + // then update the cycle day + const mensesDaysAfter = getMensesDaysRightAfter(oldCycleDay) + oldCycleDay.bleeding = newValue + oldCycleDay.isCycleStart = false + + if (!mensesDaysAfter.length) return + + const nextOne = mensesDaysAfter[mensesDaysAfter.length - 1] + if (isMensesStart(nextOne)) { + nextOne.isCycleStart = true + } + } + + function maybeClearOldCycleStartsInThisMenses(cycleDay) { + // if we have a new bleeding day, we need to clear the + // menses start marker from all following days of this + // menses that may have been marked as start before + const mensesDaysAfter = getMensesDaysRightAfter(cycleDay) + mensesDaysAfter.forEach(day => day.isCycleStart = false) + } + + return { getCycleDayNumber, getCycleForDay, @@ -182,6 +215,8 @@ export default function config(opts) { getAllCycleLengths, getPredictedMenses, isMensesStart, - getMensesDaysAfter + getMensesDaysRightAfter, + maybeSetNewCycleStart, + maybeClearOldCycleStartsInThisMenses } } \ No newline at end of file diff --git a/test/cycle.spec.js b/test/cycle.spec.js index 8508748..af07e6d 100644 --- a/test/cycle.spec.js +++ b/test/cycle.spec.js @@ -904,7 +904,7 @@ describe('isMensesStart', () => { }) }) -describe('getMensesDaysAfter', () => { +describe('getMensesDaysRightAfter', () => { it('works for simple menses start', () => { const cycleDaysSortedByDate = [ { @@ -927,11 +927,11 @@ describe('getMensesDaysAfter', () => { } ] - const { getMensesDaysAfter } = cycleModule({ + const { getMensesDaysRightAfter } = cycleModule({ cycleDaysSortedByDate, bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) }) - const days = getMensesDaysAfter(cycleDaysSortedByDate[3]) + const days = getMensesDaysRightAfter(cycleDaysSortedByDate[3]) expect(days).to.eql([ { date: '2018-05-03', @@ -944,6 +944,50 @@ describe('getMensesDaysAfter', () => { ]) }) + it('works when the day is not a bleeding day', () => { + const cycleDaysSortedByDate = [ + { + date: '2018-05-04', + }, + { + date: '2018-05-03', + bleeding: { value: 1 } + }, + { + date: '2018-05-02', + bleeding: { value: 1 } + }, + { + date: '2018-05-01', + bleeding: { value: 1 } + }, + { + date: '2018-04-30', + bleeding: null + } + ] + + const { getMensesDaysRightAfter } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const days = getMensesDaysRightAfter(cycleDaysSortedByDate[4]) + expect(days).to.eql([ + { + date: '2018-05-03', + bleeding: { value: 1 } + }, + { + date: '2018-05-02', + bleeding: { value: 1 } + }, + { + date: '2018-05-01', + bleeding: { value: 1 } + } + ]) + }) + it('ignores excluded values', () => { const cycleDaysSortedByDate = [ { @@ -966,11 +1010,11 @@ describe('getMensesDaysAfter', () => { } ] - const { getMensesDaysAfter } = cycleModule({ + const { getMensesDaysRightAfter } = cycleModule({ cycleDaysSortedByDate, bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) }) - const days = getMensesDaysAfter(cycleDaysSortedByDate[3]) + const days = getMensesDaysRightAfter(cycleDaysSortedByDate[3]) expect(days).to.eql([ { date: '2018-05-03', @@ -999,11 +1043,11 @@ describe('getMensesDaysAfter', () => { } ] - const { getMensesDaysAfter } = cycleModule({ + const { getMensesDaysRightAfter } = cycleModule({ cycleDaysSortedByDate, bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) }) - const days = getMensesDaysAfter(cycleDaysSortedByDate[3]) + const days = getMensesDaysRightAfter(cycleDaysSortedByDate[3]) expect(days).to.eql([]) }) @@ -1028,11 +1072,11 @@ describe('getMensesDaysAfter', () => { } ] - const { getMensesDaysAfter } = cycleModule({ + const { getMensesDaysRightAfter } = cycleModule({ cycleDaysSortedByDate, bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) }) - const days = getMensesDaysAfter(cycleDaysSortedByDate[3]) + const days = getMensesDaysRightAfter(cycleDaysSortedByDate[3]) expect(days).to.eql([]) }) @@ -1058,11 +1102,11 @@ describe('getMensesDaysAfter', () => { } ] - const { getMensesDaysAfter } = cycleModule({ + const { getMensesDaysRightAfter } = cycleModule({ cycleDaysSortedByDate, bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) }) - const days = getMensesDaysAfter(cycleDaysSortedByDate[3]) + const days = getMensesDaysRightAfter(cycleDaysSortedByDate[3]) expect(days).to.eql([ { date: '2018-05-05', @@ -1090,11 +1134,11 @@ describe('getMensesDaysAfter', () => { } }] - const getMensesDaysAfter = cycleModule({ + const getMensesDaysRightAfter = cycleModule({ bleedingDaysSortedByDate: bleedingDays, maxBreakInBleeding - }).getMensesDaysAfter - const result = getMensesDaysAfter(bleedingDays[1]) + }).getMensesDaysRightAfter + const result = getMensesDaysRightAfter(bleedingDays[1]) expect(result).to.eql([bleedingDays[0]]) }) @@ -1111,11 +1155,11 @@ describe('getMensesDaysAfter', () => { } }] - const getMensesDaysAfter = cycleModule({ + const getMensesDaysRightAfter = cycleModule({ bleedingDaysSortedByDate: bleedingDays, maxBreakInBleeding - }).getMensesDaysAfter - const result = getMensesDaysAfter(bleedingDays[1]) + }).getMensesDaysRightAfter + const result = getMensesDaysRightAfter(bleedingDays[1]) expect(result).to.eql([]) }) })