Merge branch '73-implement-nfp-logic-for-mucus-mode' into 'master'
Resolve "implement NFP logic for mucus mode" Closes #73 See merge request bloodyhealth/drip!20
This commit is contained in:
+117
-9
@@ -11,11 +11,12 @@ import Svg,{
|
||||
} from 'react-native-svg'
|
||||
import { LocalDate } from 'js-joda'
|
||||
import { getCycleDay, getOrCreateCycleDay, cycleDaysSortedByDate } from '../../db'
|
||||
import getCycleDayNumberModule from '../../lib/get-cycle-day-number'
|
||||
import cycleModule from '../../lib/cycle'
|
||||
import styles from './styles'
|
||||
import config from './config'
|
||||
import { getCycleStatusForDay } from '../../lib/sympto-adapter'
|
||||
|
||||
const getCycleDayNumber = getCycleDayNumberModule()
|
||||
const getCycleDayNumber = cycleModule().getCycleDayNumber
|
||||
|
||||
const yAxis = makeYAxis(config)
|
||||
|
||||
@@ -63,13 +64,29 @@ export default class CycleChart extends Component {
|
||||
const cycleDayNumber = getCycleDayNumber(dateString)
|
||||
const label = styles.column.label
|
||||
const dateLabel = dateString.split('-').slice(1).join('-')
|
||||
const getFhmAndLtlInfo = setUpFertilityStatusFunc()
|
||||
const nfpLineInfo = getFhmAndLtlInfo(dateString, cycleDay)
|
||||
|
||||
return (
|
||||
<G onPress={() => this.passDateToDayView(dateString)}>
|
||||
<Rect {...styles.column.rect} />
|
||||
{nfpLineInfo.drawFhmLine ?
|
||||
<Line
|
||||
x1={0 + styles.nfpLine.strokeWidth / 2}
|
||||
y1="20"
|
||||
x2={0 + styles.nfpLine.strokeWidth / 2}
|
||||
y2={config.chartHeight - 20}
|
||||
{...styles.nfpLine}
|
||||
/> : null}
|
||||
|
||||
{this.placeHorizontalGrid()}
|
||||
<Text {...label.number} y={config.cycleDayNumberRowY}>{cycleDayNumber}</Text>
|
||||
<Text {...label.date} y={config.dateRowY}>{dateLabel}</Text>
|
||||
|
||||
<Text {...label.number} y={config.cycleDayNumberRowY}>
|
||||
{cycleDayNumber}
|
||||
</Text>
|
||||
<Text {...label.date} y={config.dateRowY}>
|
||||
{dateLabel}
|
||||
</Text>
|
||||
|
||||
{cycleDay && cycleDay.bleeding ?
|
||||
<Path {...styles.bleedingIcon}
|
||||
@@ -79,10 +96,23 @@ export default class CycleChart extends Component {
|
||||
Q13.5 6.8 15 3z" />
|
||||
: null}
|
||||
|
||||
{nfpLineInfo.drawLtlAt ?
|
||||
<Line
|
||||
x1="0"
|
||||
y1={nfpLineInfo.drawLtlAt}
|
||||
x2={config.columnWidth}
|
||||
y2={nfpLineInfo.drawLtlAt}
|
||||
{...styles.nfpLine}
|
||||
/> : null}
|
||||
|
||||
{y ?
|
||||
this.drawDotAndLines(y, cycleDay.temperature.exclude, index)
|
||||
: null
|
||||
}
|
||||
{cycleDay && cycleDay.mucus ?
|
||||
<Circle
|
||||
{...styles.mucusIcon}
|
||||
fill={styles.mucusIconShades[cycleDay.mucus.computedNfp]}
|
||||
fill={styles.mucusIconShades[cycleDay.mucus.value]}
|
||||
/> : null}
|
||||
|
||||
{y ? this.drawDotAndLines(y, cycleDay.temperature.exclude, index) : null}
|
||||
@@ -181,15 +211,18 @@ function makeColumnInfo(n) {
|
||||
|
||||
function getPreviousDays(n) {
|
||||
const today = new Date()
|
||||
today.setHours(0); today.setMinutes(0); today.setSeconds(0); today.setMilliseconds(0)
|
||||
today.setHours(0)
|
||||
today.setMinutes(0)
|
||||
today.setSeconds(0)
|
||||
today.setMilliseconds(0)
|
||||
const earlierDate = new Date(today - (range.DAY * n))
|
||||
|
||||
return range(earlierDate, today).reverse()
|
||||
}
|
||||
|
||||
function normalizeToScale(temp) {
|
||||
const temperatureScale = config.temperatureScale
|
||||
const valueRelativeToScale = (temperatureScale.high - temp) / (temperatureScale.high - temperatureScale.low)
|
||||
const scale = config.temperatureScale
|
||||
const valueRelativeToScale = (scale.high - temp) / (scale.high - scale.low)
|
||||
const scaleHeight = config.chartHeight
|
||||
return scaleHeight * valueRelativeToScale
|
||||
}
|
||||
@@ -202,7 +235,6 @@ function makeYAxis() {
|
||||
|
||||
const tickPositions = []
|
||||
const labels = []
|
||||
|
||||
// for style reasons, we don't want the first and last tick
|
||||
for (let i = 1; i < numberOfTicks - 1; i++) {
|
||||
const y = tickDistance * i
|
||||
@@ -223,3 +255,79 @@ function makeYAxis() {
|
||||
|
||||
return {labels, tickPositions}
|
||||
}
|
||||
|
||||
function setUpFertilityStatusFunc() {
|
||||
let cycleStatus
|
||||
let cycleStartDate
|
||||
let noMoreCycles = false
|
||||
|
||||
function updateCurrentCycle(dateString) {
|
||||
cycleStatus = getCycleStatusForDay(dateString)
|
||||
if(!cycleStatus) {
|
||||
noMoreCycles = true
|
||||
return
|
||||
}
|
||||
if (cycleStatus.phases.preOvulatory) {
|
||||
cycleStartDate = cycleStatus.phases.preOvulatory.start.date
|
||||
} else {
|
||||
cycleStartDate = cycleStatus.phases.periOvulatory.start.date
|
||||
}
|
||||
}
|
||||
|
||||
function dateIsInPeriOrPostPhase(dateString) {
|
||||
return (
|
||||
dateString >= cycleStatus.phases.periOvulatory.start.date
|
||||
)
|
||||
}
|
||||
|
||||
function precededByAnotherTempValue(dateString) {
|
||||
return (
|
||||
// we are only interested in days that have a preceding
|
||||
// temp
|
||||
Object.keys(cycleStatus.phases).some(phaseName => {
|
||||
return cycleStatus.phases[phaseName].cycleDays.some(day => {
|
||||
return day.temperature && day.date < dateString
|
||||
})
|
||||
})
|
||||
// and also a following temp, so we don't draw the line
|
||||
// longer than necessary
|
||||
&&
|
||||
cycleStatus.phases.postOvulatory.cycleDays.some(day => {
|
||||
return day.temperature && day.date > dateString
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
function isInTempMeasuringPhase(cycleDay, dateString) {
|
||||
return (
|
||||
cycleDay && cycleDay.temperature
|
||||
|| precededByAnotherTempValue(dateString)
|
||||
)
|
||||
}
|
||||
|
||||
return function(dateString, cycleDay) {
|
||||
const ret = {}
|
||||
if (!cycleStatus && !noMoreCycles) updateCurrentCycle(dateString)
|
||||
if (noMoreCycles) return ret
|
||||
|
||||
if (dateString < cycleStartDate) updateCurrentCycle(dateString)
|
||||
if (noMoreCycles) return ret
|
||||
|
||||
const tempShift = cycleStatus.temperatureShift
|
||||
|
||||
if (tempShift) {
|
||||
if (tempShift.firstHighMeasurementDay.date === dateString) {
|
||||
ret.drawFhmLine = true
|
||||
}
|
||||
|
||||
if (
|
||||
dateIsInPeriOrPostPhase(dateString) &&
|
||||
isInTempMeasuringPhase(cycleDay, dateString)
|
||||
) {
|
||||
ret.drawLtlAt = normalizeToScale(tempShift.ltl)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,10 @@ const styles = {
|
||||
horizontalGrid: {
|
||||
stroke: 'lightgrey',
|
||||
strokeWidth: 1
|
||||
},
|
||||
nfpLine: {
|
||||
stroke: '#00b159',
|
||||
strokeWidth: 3
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,10 +14,10 @@ import {
|
||||
cervixFirmness as firmnessLabels,
|
||||
cervixPosition as positionLabels
|
||||
} from './labels/labels'
|
||||
import cycleDayModule from '../../lib/get-cycle-day-number'
|
||||
import cycleDayModule from '../../lib/cycle'
|
||||
import { bleedingDaysSortedByDate } from '../../db'
|
||||
|
||||
const getCycleDayNumber = cycleDayModule()
|
||||
const getCycleDayNumber = cycleDayModule().getCycleDayNumber
|
||||
|
||||
export default class DayView extends Component {
|
||||
constructor(props) {
|
||||
@@ -72,7 +72,7 @@ export default class DayView extends Component {
|
||||
if (this.cycleDay.mucus) {
|
||||
const mucus = this.cycleDay.mucus
|
||||
if (typeof mucus.feeling === 'number' && typeof mucus.texture === 'number') {
|
||||
mucusLabel = `${feelingLabels[mucus.feeling]} + ${textureLabels[mucus.texture]} ( ${computeSensiplanMucusLabels[mucus.computedNfp]} )`
|
||||
mucusLabel = `${feelingLabels[mucus.feeling]} + ${textureLabels[mucus.texture]} ( ${computeSensiplanMucusLabels[mucus.value]} )`
|
||||
if (mucus.exclude) mucusLabel = "( " + mucusLabel + " )"
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -4,7 +4,8 @@ import {
|
||||
Text,
|
||||
ScrollView
|
||||
} from 'react-native'
|
||||
import cycleDayModule from '../../lib/get-cycle-day-number'
|
||||
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'
|
||||
@@ -14,7 +15,7 @@ import CervixEditView from './symptoms/cervix'
|
||||
import styles from '../../styles'
|
||||
import actionButtonModule from './action-buttons'
|
||||
|
||||
const getCycleDayNumber = cycleDayModule()
|
||||
const getCycleDayNumber = cycleModule().getCycleDayNumber
|
||||
|
||||
export default class Day extends Component {
|
||||
constructor(props) {
|
||||
@@ -34,6 +35,7 @@ export default class Day extends Component {
|
||||
|
||||
render() {
|
||||
const cycleDayNumber = getCycleDayNumber(this.cycleDay.date)
|
||||
const fertilityStatus = getFertilityStatusStringForDay(this.cycleDay.date)
|
||||
return (
|
||||
<ScrollView>
|
||||
<View style={ styles.cycleDayDateView }>
|
||||
@@ -42,7 +44,14 @@ export default class Day extends Component {
|
||||
</Text>
|
||||
</View >
|
||||
<View style={ styles.cycleDayNumberView }>
|
||||
{ cycleDayNumber && <Text style={styles.cycleDayNumber} >Cycle day {cycleDayNumber}</Text> }
|
||||
{ cycleDayNumber &&
|
||||
<Text style={styles.cycleDayNumber} >
|
||||
Cycle day {cycleDayNumber}
|
||||
</Text> }
|
||||
|
||||
<Text style={styles.cycleDayNumber} >
|
||||
{fertilityStatus}
|
||||
</Text>
|
||||
</View >
|
||||
<View>
|
||||
{
|
||||
|
||||
@@ -1,17 +1,14 @@
|
||||
const bleeding = ['spotting', 'light', 'medium', 'heavy']
|
||||
const mucusFeeling = ['dry', 'nothing', 'wet', 'slippery']
|
||||
const mucusTexture = ['nothing', 'creamy', 'egg white']
|
||||
const mucusNFP = ['t', 'Ø', 'f', 'S', '+S']
|
||||
const cervixOpening = ['closed', 'medium', 'open']
|
||||
const cervixFirmness = ['hard', 'soft']
|
||||
const cervixPosition = ['low', 'medium', 'high']
|
||||
export const bleeding = ['spotting', 'light', 'medium', 'heavy']
|
||||
export const mucusFeeling = ['dry', 'nothing', 'wet', 'slippery']
|
||||
export const mucusTexture = ['nothing', 'creamy', 'egg white']
|
||||
export const mucusNFP = ['t', 'Ø', 'f', 'S', '+S']
|
||||
export const cervixOpening = ['closed', 'medium', 'open']
|
||||
export const cervixFirmness = ['hard', 'soft']
|
||||
export const cervixPosition = ['low', 'medium', 'high']
|
||||
|
||||
export {
|
||||
bleeding,
|
||||
mucusFeeling,
|
||||
mucusTexture,
|
||||
mucusNFP,
|
||||
cervixOpening,
|
||||
cervixFirmness,
|
||||
cervixPosition
|
||||
}
|
||||
export const fertilityStatus = {
|
||||
fertile: 'fertile',
|
||||
infertile: 'infertile',
|
||||
fertileUntilEvening: 'Fertile phase ends in the evening',
|
||||
unknown: 'We cannot show any cycle information because no menses has been entered'
|
||||
}
|
||||
@@ -94,7 +94,7 @@ export default class Mucus extends Component {
|
||||
saveSymptom('mucus', this.cycleDay, {
|
||||
feeling: this.state.feeling,
|
||||
texture: this.state.texture,
|
||||
computedNfp: computeSensiplanValue(this.state.feeling, this.state.texture),
|
||||
value: computeSensiplanValue(this.state.feeling, this.state.texture),
|
||||
exclude: this.state.exclude
|
||||
})
|
||||
},
|
||||
|
||||
+10
-4
@@ -6,11 +6,11 @@ import {
|
||||
ScrollView
|
||||
} from 'react-native'
|
||||
import { LocalDate } from 'js-joda'
|
||||
import styles from '../styles'
|
||||
import cycleDayModule from '../lib/get-cycle-day-number'
|
||||
import { getOrCreateCycleDay, bleedingDaysSortedByDate, deleteAll } from '../db'
|
||||
import styles from '../styles/index'
|
||||
import cycleModule from '../lib/cycle'
|
||||
import { getOrCreateCycleDay, bleedingDaysSortedByDate, fillWithDummyData, deleteAll } from '../db'
|
||||
|
||||
const getCycleDayNumber = cycleDayModule()
|
||||
const getCycleDayNumber = cycleModule().getCycleDayNumber
|
||||
|
||||
export default class Home extends Component {
|
||||
constructor(props) {
|
||||
@@ -68,6 +68,12 @@ export default class Home extends Component {
|
||||
title="Go to chart">
|
||||
</Button>
|
||||
</View>
|
||||
<View style={styles.homeButton}>
|
||||
<Button
|
||||
onPress={() => fillWithDummyData()}
|
||||
title="fill with example data">
|
||||
</Button>
|
||||
</View>
|
||||
<View style={styles.homeButton}>
|
||||
<Button
|
||||
onPress={() => deleteAll()}
|
||||
|
||||
Reference in New Issue
Block a user