Skip to content
Snippets Groups Projects
day-column.js 7.78 KiB
Newer Older
import React, { Component } from 'react'
  Text, View, TouchableOpacity
import {
  Surface,
  Group as G,
  Path,
  Shape
} from 'react-native/Libraries/ART/ReactNativeART'
import { connect } from 'react-redux'

import { setDate } from '../../slices/date'

tina's avatar
tina committed
import { LocalDate } from 'js-joda'
import moment from 'moment'
import styles from './styles'
Julia Friesel's avatar
Julia Friesel committed
import config from '../../config'
import cycleModule from '../../lib/cycle'
import { getCycleDay } from '../../db'
import DotAndLine from './dot-and-line'
import { normalizeToScale } from './y-axis'
const label = styles.column.label
class DayColumn extends Component {

    const { dateString, columnHeight, chartSymptoms } = props
    const cycleDayData = getCycleDay(dateString)

    if (cycleDayData) {
      this.data = chartSymptoms.reduce((symptomDataToDisplay, symptom) => {
        const symptomData = cycleDayData[symptom]

        if (symptomData && !this.isSymptomExcluded(symptomData)) {
          symptomDataToDisplay[symptom] = {}
          switch (symptom) {
          case 'temperature': {
            symptomDataToDisplay[symptom].data = symptomData.value
            symptomDataToDisplay.y =
              normalizeToScale(symptomData.value, columnHeight)
            const neighbourTemperatureValue =
              getInfoForNeighborColumns(dateString, columnHeight)
            for (const key in neighbourTemperatureValue) {
              symptomDataToDisplay[key] = neighbourTemperatureValue[key]
            break
          }
          case 'cervix':
            symptomDataToDisplay[symptom].data =
              (symptomData.opening + symptomData.firmness) > 0 ? 2 : 0
            symptomDataToDisplay[symptom].isComplete =
              this.isCervixDataComplete(symptomData)
            break
          case 'mucus':
            symptomDataToDisplay[symptom].data =
              (symptomData.feeling + symptomData.texture) > 0 ? 2 : 0
            symptomDataToDisplay[symptom].isComplete =
              this.isMucusDataComplete(symptomData)
            break
          case 'sex':
            symptomDataToDisplay[symptom].data =
              symptomData.solo + 2 * symptomData.partner - 1
            break
          case 'bleeding':
          case 'desire':
            symptomDataToDisplay[symptom].data = symptomData.value
            break
          default: // pain, mood, note
            symptomDataToDisplay[symptom].data = 0

        return symptomDataToDisplay
      }, this.data)
    }

    this.fhmAndLtl = props.getFhmAndLtlInfo(
      props.dateString,
      this.data.temperature,
  isSymptomExcluded = (symptomData) => {
    return symptomData && symptomData.exclude ? symptomData.exclude : false
  }

  isCervixDataComplete = (symptomData) =>
    (symptomData.opening != null) && (symptomData.firmness != null)

  isMucusDataComplete = (symptomData) =>
    (symptomData.feeling != null) && (symptomData.texture != null)

  onDaySelect = (date) => {
    this.props.setDate(date)
    this.props.navigate('CycleDay')
  }

  shouldComponentUpdate() {
    return false
  drawSypmtom = (symptom) => {

    const { symptomHeight } = this.props
    const shouldDrawSymptom = this.data.hasOwnProperty(symptom)
    const styleParent = [styles.symptomRow, {height: symptomHeight}]

    if (shouldDrawSymptom) {
      const styleSymptom = styles.iconShades[symptom]
      const symptomData = this.data[symptom]

      const isDataIncomplete = !symptomData.isComplete
      const isMucusOrCervix = (symptom === 'mucus') || (symptom === 'cervix')

      const backgroundColor = ( isMucusOrCervix && isDataIncomplete) ?
        'white' : styleSymptom[symptomData.data]
      const borderWidth = ( isMucusOrCervix && isDataIncomplete) ? 2 : 0
      const borderColor = styleSymptom[0]

      const styleChild = [styles.symptomIcon, {
        backgroundColor,
        borderColor,
        borderWidth
      }]

      return (
        <View style={styleParent} key={symptom}>
          {shouldDrawSymptom && <View style={styleChild} />}
        </View>
      )
    } else {
      return (
        <View style={styleParent} key={symptom} />
      )
    }
  }

  render() {
    const columnElements = []
    const { dateString,
      symptomRowSymptoms,
      chartHeight,
      columnHeight,
      xAxisHeight } = this.props

      const ltlLine = (<Shape
Julia Friesel's avatar
Julia Friesel committed
        stroke={styles.nfpLine.stroke}
        strokeWidth={styles.nfpLine.strokeWidth}
        d={new Path()
          .moveTo(0, this.fhmAndLtl.drawLtlAt)
          .lineTo(config.columnWidth, this.fhmAndLtl.drawLtlAt)
        }
Julia Friesel's avatar
Julia Friesel committed
      />)
      columnElements.push(ltlLine)
    }
    if (this.fhmAndLtl.drawFhmLine) {
Julia Friesel's avatar
Julia Friesel committed
      const x = styles.nfpLine.strokeWidth / 2
      const fhmLine = (<Shape
        fill="red"
Julia Friesel's avatar
Julia Friesel committed
        stroke={styles.nfpLine.stroke}
        strokeWidth={styles.nfpLine.strokeWidth}
        d={new Path().moveTo(x, x).lineTo(x, columnHeight)}
Julia Friesel's avatar
Julia Friesel committed
      />)
      columnElements.push(fhmLine)
    }

      columnElements.push(
        <DotAndLine
          y={this.data.y}
          exclude={this.data.temperatureExclude}
          rightY={this.data.rightY}
          rightTemperatureExclude={this.data.rightTemperatureExclude}
          leftY={this.data.leftY}
          leftTemperatureExclude={this.data.leftTemperatureExclude}
    const cycleDayNumber = cycleModule().getCycleDayNumber(dateString)
tina's avatar
tina committed
    const dayDate = LocalDate.parse(dateString)
    const shortDate = dayDate.dayOfMonth() === 1 ?
      moment(dateString, "YYYY-MM-DD").format('MMM')
      :
      moment(dateString, "YYYY-MM-DD").format('Do')
    const boldDateLabel = dayDate.dayOfMonth() === 1 ? {fontWeight: 'bold'} : {}
    const cycleDayLabel = (
      <Text style = {label.number}>
        {cycleDayNumber ? cycleDayNumber : ' '}
      </Text>)
    const dateLabel = (
tina's avatar
tina committed
      <Text style = {[label.date, boldDateLabel]}>
        {shortDate}
      </Text>
    )
    const column = (
        <Shape
          stroke={styles.column.stroke.color}
          strokeWidth={styles.column.stroke.width}
          d={new Path().lineTo(0, chartHeight)}
        />
        { columnElements }
      </G>
      <TouchableOpacity
        onPress={() => this.onDaySelect(dateString)}
        activeOpacity={1}
      >
          {symptomRowSymptoms.map(symptom => this.drawSypmtom(symptom))}
        </View>
        <Surface width={config.columnWidth} height={columnHeight}>
        </Surface>
        <View style={{height: xAxisHeight}}>
          {cycleDayLabel}
          {dateLabel}
        </View>
      </TouchableOpacity>
emelko's avatar
emelko committed
}
const mapDispatchToProps = (dispatch) => {
  return({
    setDate: (date) => dispatch(setDate(date)),
  })
}

export default connect(
  null,
  mapDispatchToProps,
)(DayColumn)


function getInfoForNeighborColumns(dateString, columnHeight) {
  const ret = {
    rightY: null,
    rightTemperatureExclude: null,
    leftY: null,
    leftTemperatureExclude: null
  }
  const target = LocalDate.parse(dateString)
  const dayBefore = target.minusDays(1).toString()
  const dayAfter = target.plusDays(1).toString()
  const cycleDayBefore = getCycleDay(dayBefore)
  const cycleDayAfter = getCycleDay(dayAfter)
  if (cycleDayAfter && cycleDayAfter.temperature) {
    ret.rightY = normalizeToScale(cycleDayAfter.temperature.value, columnHeight)
    ret.rightTemperatureExclude = cycleDayAfter.temperature.exclude
  }
  if (cycleDayBefore && cycleDayBefore.temperature) {
    ret.leftY = normalizeToScale(cycleDayBefore.temperature.value, columnHeight)
    ret.leftTemperatureExclude = cycleDayBefore.temperature.exclude
  }

  return ret
}