diff --git a/lib/cycle.js b/lib/cycle.js index 28f9867..042cff2 100644 --- a/lib/cycle.js +++ b/lib/cycle.js @@ -135,23 +135,45 @@ export default function config(opts) { function isMensesStart(cycleDay) { if (!cycleDay.bleeding || cycleDay.bleeding.exclude) return false - const bleedingDays = bleedingDaysSortedByDate - if (noBleedingDayWithinThreshold(cycleDay)) { - return true - } + if (noBleedingDayWithinThresholdBefore(cycleDay)) return true return false - function noBleedingDayWithinThreshold(day) { - const localDate = LocalDate.parse(day.date) + function noBleedingDayWithinThresholdBefore(cycleDay) { + const localDate = LocalDate.parse(cycleDay.date) const threshold = localDate.minusDays(maxBreakInBleeding + 1).toString() + const bleedingDays = bleedingDaysSortedByDate const index = bleedingDays.findIndex(day => day.date === cycleDay.date) - const previousBleedingDays = bleedingDays.slice(index + 1) - return !previousBleedingDays.some(day => { + const candidates = bleedingDays.slice(index + 1) + return !candidates.some(day => { return day.date >= threshold && !day.bleeding.exclude }) } } + function getMensesDaysAfter(bleedingDay) { + const bleedingDays = bleedingDaysSortedByDate.filter(d => { + return !d.bleeding.exclude + }) + const startIndex = bleedingDays.findIndex(day => { + return day.date === bleedingDay.date + }) + return recurse(bleedingDay, startIndex, []) + + function recurse(day, i, mensesDays) { + if (i === 0) return mensesDays + const next = bleedingDays[i - 1] + if (!isWithinThreshold(day, next)) return mensesDays + mensesDays.unshift(next) + return recurse(next, i - 1, mensesDays) + } + + function isWithinThreshold(cycleDay, nextCycleDay) { + const localDate = LocalDate.parse(cycleDay.date) + const threshold = localDate.plusDays(maxBreakInBleeding + 1).toString() + return nextCycleDay.date <= threshold + } + } + function getCycleLength(cycleStartDates) { const cycleLengths = [] for (let i = 0; i < cycleStartDates.length - 1; i++) { @@ -208,6 +230,7 @@ export default function config(opts) { getAllMensesStarts, getCycleLength, getPredictedMenses, - isMensesStart + isMensesStart, + getMensesDaysAfter } } \ No newline at end of file diff --git a/test/cycle.spec.js b/test/cycle.spec.js index 7a7f393..d51392a 100644 --- a/test/cycle.spec.js +++ b/test/cycle.spec.js @@ -827,4 +827,176 @@ describe('isMensesStart', () => { const start = isMensesStart(cycleDaysSortedByDate[2]) expect(start).to.be.true() }) +}) + +describe('getMensesDaysAfter', () => { + it('works for simple menses start', () => { + 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', + } + ] + + const { getMensesDaysAfter } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const days = getMensesDaysAfter(cycleDaysSortedByDate[3]) + expect(days).to.eql([ + { + date: '2018-05-03', + bleeding: { value: 1 } + }, + { + date: '2018-05-02', + bleeding: { value: 1 } + } + ]) + }) + + it('ignores excluded values', () => { + const cycleDaysSortedByDate = [ + { + date: '2018-05-04', + }, + { + date: '2018-05-03', + bleeding: { value: 1 } + }, + { + date: '2018-05-02', + bleeding: { value: 1, exclude: true } + }, + { + date: '2018-05-01', + bleeding: { value: 1 } + }, + { + date: '2018-04-30', + } + ] + + const { getMensesDaysAfter } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const days = getMensesDaysAfter(cycleDaysSortedByDate[3]) + expect(days).to.eql([ + { + date: '2018-05-03', + bleeding: { value: 1 } + } + ]) + }) + + it('returns empty when there are no bleeding days after', () => { + const cycleDaysSortedByDate = [ + { + date: '2018-05-04', + }, + { + date: '2018-05-03', + }, + { + date: '2018-05-02', + }, + { + date: '2018-05-01', + bleeding: { value: 1 } + }, + { + date: '2018-04-30', + } + ] + + const { getMensesDaysAfter } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const days = getMensesDaysAfter(cycleDaysSortedByDate[3]) + expect(days).to.eql([]) + }) + + it('returns empty when there are no bleeding days within threshold', () => { + const cycleDaysSortedByDate = [ + { + date: '2018-05-04', + bleeding: { value: 1 } + }, + { + date: '2018-05-03', + }, + { + date: '2018-05-02', + }, + { + date: '2018-05-01', + bleeding: { value: 1 } + }, + { + date: '2018-04-30', + } + ] + + const { getMensesDaysAfter } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const days = getMensesDaysAfter(cycleDaysSortedByDate[3]) + expect(days).to.eql([]) + }) + + it('includes days within the treshold', () => { + const cycleDaysSortedByDate = [ + { + date: '2018-05-04', + }, + { + date: '2018-05-05', + bleeding: { value: 1 } + }, + { + date: '2018-05-03', + bleeding: { value: 1 } + }, + { + date: '2018-05-01', + bleeding: { value: 1 } + }, + { + date: '2018-04-30', + } + ] + + const { getMensesDaysAfter } = cycleModule({ + cycleDaysSortedByDate, + bleedingDaysSortedByDate: cycleDaysSortedByDate.filter(d => d.bleeding) + }) + const days = getMensesDaysAfter(cycleDaysSortedByDate[3]) + expect(days).to.eql([ + { + date: '2018-05-05', + bleeding: { value: 1 } + }, + { + date: '2018-05-03', + bleeding: { value: 1 } + } + ]) + }) }) \ No newline at end of file