diff --git a/components/Home.js b/components/Home.js index 3a65aed..507024d 100644 --- a/components/Home.js +++ b/components/Home.js @@ -12,14 +12,16 @@ import Button from './common/button' import cycleModule from '../lib/cycle' import { getFertilityStatusForDay } from '../lib/sympto-adapter' -import { determinePredictionText, formatWithOrdinalSuffix } from './helpers/home' +import { + determinePredictionText, + formatWithOrdinalSuffix, +} from './helpers/home' import { Colors, Fonts, Sizes, Spacing } from '../styles' import { LocalDate } from 'js-joda' import { useTranslation } from 'react-i18next' const Home = ({ navigate, setDate }) => { - const { t } = useTranslation() function navigateToCycleDayView() { @@ -34,22 +36,26 @@ const Home = ({ navigate, setDate }) => { getFertilityStatusForDay(todayDateString) const prediction = determinePredictionText(getPredictedMenses(), t) - const cycleDayText = cycleDayNumber ? formatWithOrdinalSuffix(cycleDayNumber) : '' + const cycleDayText = cycleDayNumber + ? formatWithOrdinalSuffix(cycleDayNumber) + : '' return ( - {moment().format("MMM Do YYYY")} + {moment().format('MMM Do YYYY')} - {cycleDayNumber && + {cycleDayNumber && ( {cycleDayText} - {t('labels.home.cycleDay')} + + {t('labels.home.cycleDay')} + - } - {phase && + )} + {phase && ( {formatWithOrdinalSuffix(phase)} @@ -60,7 +66,7 @@ const Home = ({ navigate, setDate }) => { {status} - } + )} {prediction} @@ -128,28 +134,25 @@ const styles = StyleSheet.create({ greyText: { color: Colors.greyLight, paddingLeft: Spacing.base, - } + }, }) const mapStateToProps = (state) => { - return ({ + return { date: getDate(state), - }) + } } const mapDispatchToProps = (dispatch) => { - return ({ + return { navigate: (page) => dispatch(navigate(page)), setDate: (date) => dispatch(setDate(date)), - }) + } } Home.propTypes = { navigate: PropTypes.func, - setDate: PropTypes.func + setDate: PropTypes.func, } -export default connect( - mapStateToProps, - mapDispatchToProps, -)(Home) +export default connect(mapStateToProps, mapDispatchToProps)(Home) diff --git a/components/helpers/chart.js b/components/helpers/chart.js index 0a68a1b..73b1408 100644 --- a/components/helpers/chart.js +++ b/components/helpers/chart.js @@ -45,7 +45,6 @@ export function getTickList(columnHeight) { const tickHeight = columnHeight / numberOfTicks return getTickPositions(columnHeight).map((tickPosition, i) => { - const tick = scaleMax - i * unit const isBold = Number.isInteger(tick) ? true : false const label = tick.toFixed(1) @@ -56,14 +55,14 @@ export function getTickList(columnHeight) { if (unit === 0.1) { // show label with step 0.2 - shouldShowLabel = !(label * 10 % 2) + shouldShowLabel = !((label * 10) % 2) } else { // show label with step 0.5 - shouldShowLabel = !(label * 10 % 5) + shouldShowLabel = !((label * 10) % 5) } // don't show label, if first or last tick - if ( i === 0 || i === (numberOfTicks - 1) ) { + if (i === 0 || i === numberOfTicks - 1) { shouldShowLabel = false } @@ -72,7 +71,7 @@ export function getTickList(columnHeight) { label, isBold, shouldShowLabel, - tickHeight + tickHeight, } }) } @@ -84,17 +83,17 @@ export function isSymptomDataComplete(symptom, dateString) { const symptomData = cycleDayData[symptom] const dataCompletenessCheck = { - 'cervix': () => { + cervix: () => { const { opening, firmness } = symptomData - return (opening !== null) && (firmness !== null) + return opening !== null && firmness !== null }, - 'mucus': () => { + mucus: () => { const { feeling, texture } = symptomData - return (feeling !== null) && (texture !== null) + return feeling !== null && texture !== null }, - 'default': () => { + default: () => { return true - } + }, } return (dataCompletenessCheck[symptom] || dataCompletenessCheck['default'])() } @@ -104,7 +103,7 @@ function getInfoForNeighborColumns(dateString, columnHeight) { rightY: null, rightTemperatureExclude: null, leftY: null, - leftTemperatureExclude: null + leftTemperatureExclude: null, } const target = LocalDate.parse(dateString) const dayBefore = target.minusDays(1).toString() @@ -127,53 +126,57 @@ function getInfoForNeighborColumns(dateString, columnHeight) { export function getTemperatureProps(symptomData, columnHeight, dateString) { const extractedData = {} const { value, exclude } = symptomData - const neighborTemperatureGraphPoints = - getInfoForNeighborColumns(dateString, columnHeight) + const neighborTemperatureGraphPoints = getInfoForNeighborColumns( + dateString, + columnHeight + ) for (const key in neighborTemperatureGraphPoints) { extractedData[key] = neighborTemperatureGraphPoints[key] } - return Object.assign({ - value, - y: normalizeToScale(value, columnHeight), - temperatureExclude: exclude, - }, extractedData) + return Object.assign( + { + value, + y: normalizeToScale(value, columnHeight), + temperatureExclude: exclude, + }, + extractedData + ) } export const symptomColorMethods = { - 'mucus': (symptomData) => { + mucus: (symptomData) => { const { feeling, texture } = symptomData const colorIndex = feeling + texture return colorIndex }, - 'cervix': (symptomData) => { + cervix: (symptomData) => { const { opening, firmness } = symptomData const isDataComplete = opening !== null && firmness !== null - const isClosedAndHard = - isDataComplete && - (opening === 0 && firmness === 0) + const isClosedAndHard = isDataComplete && opening === 0 && firmness === 0 const colorIndex = isClosedAndHard ? 0 : 2 return colorIndex }, - 'sex': (symptomData) => { + sex: (symptomData) => { const { solo, partner } = symptomData - const colorIndex = (solo !== null && partner !== null) ? - (solo + 2 * partner - 1) : 0 + const colorIndex = + solo !== null && partner !== null ? solo + 2 * partner - 1 : 0 return colorIndex }, - 'bleeding': (symptomData) => { + bleeding: (symptomData) => { const { value } = symptomData const colorIndex = value return colorIndex }, - 'desire': (symptomData) => { + desire: (symptomData) => { const { value } = symptomData const colorIndex = value return colorIndex }, - 'default': () => { //pain, mood, note + default: () => { + //pain, mood, note return 0 - } + }, } // Chart helpers @@ -188,7 +191,7 @@ export function makeColumnInfo() { amountOfCycleDays += 5 } const localDates = getTodayAndPreviousDays(amountOfCycleDays) - return localDates.map(localDate => localDate.toString()) + return localDates.map((localDate) => localDate.toString()) } function getTodayAndPreviousDays(n) { @@ -210,17 +213,17 @@ function getTodayAndPreviousDays(n) { export function nfpLines() { const cycle = { - status: null + status: null, } function updateCurrentCycle(dateString) { // for the NFP lines, we don't care about potentially extending the // preOvu phase, so we don't include all earlier cycles, as that is // an expensive db operation at the moment - cycle.status = getCycleStatusForDay( - dateString, { excludeEarlierCycles: true } - ) - if(!cycle.status) { + cycle.status = getCycleStatusForDay(dateString, { + excludeEarlierCycles: true, + }) + if (!cycle.status) { cycle.noMoreCycles = true return } @@ -232,39 +235,34 @@ export function nfpLines() { } function dateIsInPeriOrPostPhase(dateString) { - return ( - dateString >= cycle.status.phases.periOvulatory.start.date - ) + return dateString >= cycle.status.phases.periOvulatory.start.date } function precededByAnotherTempValue(dateString) { return ( // we are only interested in days that have a preceding // temp - Object.keys(cycle.status.phases).some(phaseName => { - return cycle.status.phases[phaseName].cycleDays.some(day => { + Object.keys(cycle.status.phases).some((phaseName) => { + return cycle.status.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 - && - cycle.status.phases.postOvulatory.cycleDays.some(day => { + cycle.status.phases.postOvulatory.cycleDays.some((day) => { return day.temperature && day.date > dateString }) ) } function isInTempMeasuringPhase(temperature, dateString) { - return ( - temperature || precededByAnotherTempValue(dateString) - ) + return temperature || precededByAnotherTempValue(dateString) } - return function(dateString, temperature, columnHeight) { + return function (dateString, temperature, columnHeight) { const ret = { drawLtlAt: null, - drawFhmLine: false + drawFhmLine: false, } if (!cycle.status && !cycle.noMoreCycles) updateCurrentCycle(dateString) if (cycle.noMoreCycles) return ret diff --git a/components/helpers/home.js b/components/helpers/home.js index 3034023..a1a697f 100644 --- a/components/helpers/home.js +++ b/components/helpers/home.js @@ -11,20 +11,18 @@ function getTimes(prediction) { const todayDate = LocalDate.now() const predictedBleedingStart = LocalDate.parse(prediction[0][0]) /* the range of predicted bleeding days can be either 3 or 5 */ - const predictedBleedingEnd = - LocalDate.parse(prediction[0][prediction[0].length - 1]) + const predictedBleedingEnd = LocalDate.parse( + prediction[0][prediction[0].length - 1] + ) const daysToEnd = todayDate.until(predictedBleedingEnd, ChronoUnit.DAYS) return { todayDate, predictedBleedingStart, predictedBleedingEnd, daysToEnd } } export function determinePredictionText(bleedingPrediction, t) { - if (!bleedingPrediction.length) return t('labels.bleedingPrediction.noPrediction') - const { - todayDate, - predictedBleedingStart, - predictedBleedingEnd, - daysToEnd - } = getTimes(bleedingPrediction) + if (!bleedingPrediction.length) + return t('labels.bleedingPrediction.noPrediction') + const { todayDate, predictedBleedingStart, predictedBleedingEnd, daysToEnd } = + getTimes(bleedingPrediction) if (todayDate.isBefore(predictedBleedingStart)) { return predictLabels.predictionInFuture( todayDate.until(predictedBleedingStart, ChronoUnit.DAYS), @@ -48,19 +46,18 @@ export function determinePredictionText(bleedingPrediction, t) { export function getBleedingPredictionRange(prediction) { if (!prediction.length) return labels.unknown - const { - todayDate, - predictedBleedingStart, - predictedBleedingEnd, - daysToEnd - } = getTimes(prediction) + const { todayDate, predictedBleedingStart, predictedBleedingEnd, daysToEnd } = + getTimes(prediction) if (todayDate.isBefore(predictedBleedingStart)) { - return `${todayDate.until(predictedBleedingStart, ChronoUnit.DAYS)}-${todayDate.until(predictedBleedingEnd, ChronoUnit.DAYS)}` + return `${todayDate.until( + predictedBleedingStart, + ChronoUnit.DAYS + )}-${todayDate.until(predictedBleedingEnd, ChronoUnit.DAYS)}` } if (todayDate.isAfter(predictedBleedingEnd)) { return labels.unknown } - return (daysToEnd === 0 ? '0' : `0 - ${daysToEnd}`) + return daysToEnd === 0 ? '0' : `0 - ${daysToEnd}` } export function getOrdinalSuffix(num) { diff --git a/lib/cycle.js b/lib/cycle.js index d171398..1e5f75a 100644 --- a/lib/cycle.js +++ b/lib/cycle.js @@ -30,7 +30,9 @@ export default function config(opts) { } function getLastMensesStartForDay(targetDateString) { - return cycleStartsSortedByDate.find(start => start.date <= targetDateString) + return cycleStartsSortedByDate.find( + (start) => start.date <= targetDateString + ) } function getCycleDayNumber(targetDateString) { @@ -55,25 +57,25 @@ export default function config(opts) { } function getCyclesBefore(targetCycleStartDay) { - const startFromHere = cycleStartsSortedByDate.findIndex(start => { + const startFromHere = cycleStartsSortedByDate.findIndex((start) => { return start.date < targetCycleStartDay.date }) if (startFromHere < 0) return null - return cycleStartsSortedByDate - .slice(startFromHere) - .map(start => getCycleByStartDay(start)) - // filter the ones exceeding maxCycleLength, those are null - .filter(cycle => cycle) + return ( + cycleStartsSortedByDate + .slice(startFromHere) + .map((start) => getCycleByStartDay(start)) + // filter the ones exceeding maxCycleLength, those are null + .filter((cycle) => cycle) + ) } function findIndexOfDay(day, daysSortedByDate) { - return daysSortedByDate.findIndex(d => d.date === day.date) + return daysSortedByDate.findIndex((d) => d.date === day.date) } function getNextCycleStartDay(startDay, cycleStartsSortedByDate) { - const cycleStartIndex = findIndexOfDay( - startDay, - cycleStartsSortedByDate) + const cycleStartIndex = findIndexOfDay(startDay, cycleStartsSortedByDate) return cycleStartsSortedByDate[cycleStartIndex - 1] } @@ -82,8 +84,7 @@ export default function config(opts) { } function getCycleLength(startDate, endDate) { - return LocalDate.parse(startDate) - .until(LocalDate.parse(endDate), DAYS) + return LocalDate.parse(startDate).until(LocalDate.parse(endDate), DAYS) } function isValidCycle(startDate, endDate) { @@ -109,19 +110,16 @@ export default function config(opts) { } if (isValidCycle(startDay.date, cycleEndDate)) { - const cycleStartIndex = findIndexOfDay( - startDay, - cycleDaysSortedByDate - ) - return cycleDaysSortedByDate - .slice(cycleEndIndex, cycleStartIndex + 1) + const cycleStartIndex = findIndexOfDay(startDay, cycleDaysSortedByDate) + return cycleDaysSortedByDate.slice(cycleEndIndex, cycleStartIndex + 1) } return null } function getCycleForDay(dayOrDate, todayDate) { - const dateString = typeof dayOrDate === 'string' ? dayOrDate : dayOrDate.date + const dateString = + typeof dayOrDate === 'string' ? dayOrDate : dayOrDate.date const cycleStart = getLastMensesStartForDay(dateString) if (!cycleStart) return null return getCycleByStartDay(cycleStart, todayDate) @@ -138,9 +136,9 @@ export default function config(opts) { 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 index = bleedingDays.findIndex((day) => day.date === cycleDay.date) const candidates = bleedingDays.slice(index + 1) - return !candidates.some(day => { + return !candidates.some((day) => { return day.date >= threshold && !day.bleeding.exclude }) } @@ -151,9 +149,9 @@ export default function config(opts) { // changes function getMensesDaysRightAfter(cycleDay) { const bleedingDays = bleedingDaysSortedByDate - .filter(d => !d.bleeding.exclude) + .filter((d) => !d.bleeding.exclude) .reverse() - const firstFollowingBleedingDayIndex = bleedingDays.findIndex(day => { + const firstFollowingBleedingDayIndex = bleedingDays.findIndex((day) => { return day.date > cycleDay.date }) return recurse(cycleDay, firstFollowingBleedingDayIndex, []) @@ -179,13 +177,13 @@ export default function config(opts) { function getAllCycleLengths() { return cycleStartsSortedByDate - .map(day => LocalDate.parse(day.date)) + .map((day) => LocalDate.parse(day.date)) .map((cycleStart, i, startsAsLocalDates) => { if (i === cycleStartsSortedByDate.length - 1) return null const prevCycleStart = startsAsLocalDates[i + 1] return prevCycleStart.until(cycleStart, DAYS) }) - .filter(length => length && length <= maxCycleLength) + .filter((length) => length && length <= maxCycleLength) } function getPredictedMenses() { @@ -198,12 +196,14 @@ export default function config(opts) { let periodStartVariation if (cycleInfo.stdDeviation === null) { periodStartVariation = 2 - } else if (cycleInfo.stdDeviation < 1.5) { // threshold is chosen a little arbitrarily + } else if (cycleInfo.stdDeviation < 1.5) { + // threshold is chosen a little arbitrarily periodStartVariation = 1 } else { periodStartVariation = 2 } - if (periodDistance - 5 < periodStartVariation) { // otherwise predictions overlap + if (periodDistance - 5 < periodStartVariation) { + // otherwise predictions overlap return [] } const allMensesStarts = cycleStartsSortedByDate @@ -222,7 +222,6 @@ export default function config(opts) { return predictedMenses } - return { getCycleDayNumber, getCycleForDay, diff --git a/lib/import-export/import-from-csv.js b/lib/import-export/import-from-csv.js index 1bdc8d8..3619ad0 100644 --- a/lib/import-export/import-from-csv.js +++ b/lib/import-export/import-from-csv.js @@ -4,7 +4,7 @@ import { getSchema, tryToImportWithDelete, tryToImportWithoutDelete, - updateCycleStartsForAllCycleDays + updateCycleStartsForAllCycleDays, } from '../../db' import getColumnNamesForCsv from './get-csv-column-names' import { LocalDate } from 'js-joda' @@ -12,7 +12,7 @@ import labels from '../../i18n/en/settings' export default async function importCsv(csv, deleteFirst) { const parseFuncs = { - bool: val => { + bool: (val) => { if (val.toLowerCase() === 'true') return true if (val.toLowerCase() === 'false') return false return val @@ -20,7 +20,7 @@ export default async function importCsv(csv, deleteFirst) { int: parseNumberIfPossible, float: parseNumberIfPossible, double: parseNumberIfPossible, - string: val => val + string: (val) => val, } function parseNumberIfPossible(val) { @@ -36,12 +36,12 @@ export default async function importCsv(csv, deleteFirst) { colParser: getColumnNamesForCsv().reduce((acc, colName) => { const path = colName.split('.') const dbType = getDbType(schema.CycleDay, path) - acc[colName] = item => { + acc[colName] = (item) => { if (item === '') return null return parseFuncs[dbType](item) } return acc - }, {}) + }, {}), } const cycleDays = await csvParser(config) @@ -62,9 +62,11 @@ export default async function importCsv(csv, deleteFirst) { function validateHeaders(headers) { const expectedHeaders = getColumnNamesForCsv() - if (!headers.every(header => { - return expectedHeaders.indexOf(header) > -1 - })) { + if ( + !headers.every((header) => { + return expectedHeaders.indexOf(header) > -1 + }) + ) { const msg = `Expected CSV column titles to be ${expectedHeaders.join()}` throw new Error(msg) } @@ -76,7 +78,7 @@ function putNullForEmptySymptoms(data) { function replaceWithNullIfAllPropertiesAreNull(obj) { Object.keys(obj).forEach((key) => { if (!isObject(obj[key])) return - if (Object.values(obj[key]).every(val => val === null)) { + if (Object.values(obj[key]).every((val) => val === null)) { obj[key] = null return } @@ -97,8 +99,11 @@ function throwIfFutureData(cycleDays) { for (const i in cycleDays) { const day = cycleDays[i] // notes are allowed for future dates but everything else isn't - if (day.date > today && Object.keys(day).some(symptom => symptom != 'date' && symptom != 'note')) { + if ( + day.date > today && + Object.keys(day).some((symptom) => symptom != 'date' && symptom != 'note') + ) { throw new Error(labels.import.errors.futureEdit) } } -} \ No newline at end of file +} diff --git a/slices/date.js b/slices/date.js index 49dfa70..9e529e0 100644 --- a/slices/date.js +++ b/slices/date.js @@ -5,8 +5,8 @@ const dateSlice = createSlice({ slice: 'date', initialState: LocalDate.now().toString(), reducers: { - setDate: (state, action) => action.payload - } + setDate: (state, action) => action.payload, + }, }) // Extract the action creators object and the reducer