From 4a2b99f9d53d38e1f34139ecb6917ee9ad6a597a Mon Sep 17 00:00:00 2001
From: emelko <ml.kochsiek@mailbox.org>
Date: Fri, 20 Jul 2018 12:25:17 +0200
Subject: [PATCH] Adds cervix to symptoms: has 3 properties: opening, firmness
 and position (which is optional);

---
 components/cervix.js                       | 155 +++++++++++++++++++++
 components/cycle-day/cycle-day-overview.js |  26 ++++
 components/cycle-day/index.js              |   4 +-
 components/cycle-day/labels/labels.js      |   8 +-
 components/cycle-day/symptoms/cervix.js    | 125 +++++++++++++++++
 db.js                                      |  17 ++-
 6 files changed, 332 insertions(+), 3 deletions(-)
 create mode 100644 components/cervix.js
 create mode 100644 components/cycle-day/symptoms/cervix.js

diff --git a/components/cervix.js b/components/cervix.js
new file mode 100644
index 00000000..0d9eb36b
--- /dev/null
+++ b/components/cervix.js
@@ -0,0 +1,155 @@
+import React, { Component } from 'react'
+import {
+  View,
+  Button,
+  Text,
+  Switch
+} from 'react-native'
+import RadioForm from 'react-native-simple-radio-button'
+import { saveCervix } from '../db'
+import styles from '../styles/index'
+import {
+  cervixPosition as positionLabels,
+  cervixConsistency as consistencyLabels
+} from '../labels/labels'
+import computeSensiplanValue from '../lib/sensiplan-cervix'
+
+export default class Cervix extends Component {
+  constructor(props) {
+    super(props)
+    this.cycleDay = props.cycleDay
+    this.showView = props.showView
+
+    let currentPositionValue = this.cycleDay.cervix && this.cycleDay.cervix.position
+    if (typeof currentPositionValue !== 'number') {
+      currentPositionValue = -1
+    }
+    let currentConsistencyValue = this.cycleDay.cervix && this.cycleDay.cervix.consistency
+    if (typeof currentConsistencyValue !== 'number') {
+      currentConsistencyValue = -1
+    }
+
+    this.state = {
+      currentPositionValue,
+      currentConsistencyValue,
+      computeSensiplanValue,
+      exclude: this.cycleDay.cervix ? this.cycleDay.cervix.exclude : false
+    }
+
+  }
+
+  render() {
+    const cervixPositionRadioProps = [
+      {label: positionLabels[0], value: 0 },
+      {label: positionLabels[1], value: 1 },
+      {label: positionLabels[2], value: 2 }
+    ]
+    const cervixConsistencyRadioProps = [
+      {label: consistencyLabels[0], value: 0 },
+      {label: consistencyLabels[1], value: 1 }
+    ]
+    return(
+      <View style={ styles.symptomEditView }>
+        <View style={ styles.symptomEditSplitSymptomsAndLastRowButtons }>
+          <View style={ styles.symptomEditListedSymptomView }>
+
+            <View style={{flex: 1}}>
+              <Text style={styles.symptomDayView}>Cervix</Text>
+            </View>
+
+            <View style={{flex: 1}}>
+              <Text style={styles.symptomDayView}>Position</Text>
+            </View>
+
+            <View style={{flex: 1}}>
+              <RadioForm
+                radio_props={cervixPositionRadioProps}
+                initial={this.state.currentPositionValue}
+                formHorizontal={true}
+                labelHorizontal={false}
+                labelStyle={styles.radioButton}
+                onPress={(itemValue) => {
+                  this.setState({currentPositionValue: itemValue})
+                }}
+              />
+            </View>
+
+            <View style={{flex: 1}}>
+              <Text style={styles.symptomDayView}>Consistency</Text>
+            </View>
+
+            <View style={{flex: 1}}>
+              <RadioForm
+                radio_props={cervixConsistencyRadioProps}
+                initial={this.state.currentConsistencyValue}
+                formHorizontal={true}
+                labelHorizontal={false}
+                labelStyle={styles.radioButton}
+                onPress={(itemValue) => {
+                  this.setState({currentConsistencyValue: itemValue})
+                }}
+              />
+            </View>
+
+          </View>
+
+          <View style={ styles.itemsInRowSeparatedView }>
+
+            <View style={ styles.singleButtonView }>
+              <Text style={ styles.symptomDayView }>Exclude</Text>
+            </View>
+
+            <View style={ styles.singleButtonView }>
+              <Switch
+                onValueChange={(val) => {
+                  this.setState({exclude: val})
+                }}
+                value={this.state.exclude}
+              />
+            </View>
+
+          </View>
+
+        </View>
+
+        <View style={ styles.itemsInRowSeparatedView }>
+
+          <View style={ styles.singleButtonView }>
+            <Button
+              onPress={() => this.showView('dayView')}
+              title="Cancel">
+            </Button>
+          </View>
+
+          <View style={ styles.singleButtonView }>
+            <Button
+              onPress={() => {
+                saveCervix(this.cycleDay)
+                this.showView('dayView')
+              }}
+              title="Delete">
+            </Button>
+          </View>
+
+          <View style={ styles.singleButtonView }>
+            <Button
+              onPress={() => {
+                saveCervix(this.cycleDay, {
+                  position: this.state.currentPositionValue,
+                  consistency: this.state.currentConsistencyValue,
+                  computedNfp: computeSensiplanValue(this.state.currentPositionValue, this.state.currentConsistencyValue),
+                  exclude: this.state.exclude
+                })
+                this.showView('dayView')
+              }}
+              disabled={ this.state.currentPositionValue === -1 || this.state.currentConsistencyValue === -1 }
+              title="Save">
+            </Button>
+          </View>
+
+        </View>
+
+      </View>
+    )
+  }
+}
diff --git a/components/cycle-day/cycle-day-overview.js b/components/cycle-day/cycle-day-overview.js
index 13d43a45..82a2d42c 100644
--- a/components/cycle-day/cycle-day-overview.js
+++ b/components/cycle-day/cycle-day-overview.js
@@ -10,6 +10,9 @@ import {
   mucusFeeling as feelingLabels,
   mucusTexture as textureLabels,
   mucusNFP as computeSensiplanMucusLabels,
+  cervixOpening as openingLabels,
+  cervixFirmness as firmnessLabels,
+  cervixPosition as positionLabels
 } from './labels/labels'
 import cycleDayModule from '../../lib/get-cycle-day-number'
 import { bleedingDaysSortedByDate } from '../../db'
@@ -49,6 +52,7 @@ export default class DayView extends Component {
     } else {
       bleedingLabel = 'edit'
     }
+
     const temperatureValue = this.cycleDay.temperature && this.cycleDay.temperature.value
     let temperatureLabel
     if (typeof temperatureValue === 'number') {
@@ -71,6 +75,17 @@ export default class DayView extends Component {
       mucusLabel = 'edit'
     }
 
+    const cervixOpeningValue = this.cycleDay.cervix && this.cycleDay.cervix.opening
+    const cervixFirmnessValue = this.cycleDay.cervix && this.cycleDay.cervix.firmness
+    const cervixPositionValue = this.cycleDay.cervix && this.cycleDay.cervix.position
+    let cervixLabel
+    if (typeof cervixPositionValue === 'number' && typeof cervixOpeningValue === 'number') {
+      cervixLabel = `${openingLabels[cervixOpeningValue]} + ${firmnessLabels[cervixFirmnessValue]} ( ${positionLabels[cervixPositionValue]} )`
+      if (this.cycleDay.cervix.exclude) cervixLabel = "( " + cervixLabel + " )"
+    } else {
+      cervixLabel = 'edit'
+    }
+
     return (
       <View style={styles.symptomEditView}>
         <View style={styles.symptomViewRowInline}>
@@ -100,6 +115,17 @@ export default class DayView extends Component {
             </Button>
           </View>
         </View>
+        <View style={ styles.itemsInRowSeparatedView }>
+          <View style={{flex: 1}}>
+            <Text style={styles.symptomDayView}>Cervix</Text>
+          </View>
+          <View style={ styles.singleButtonView }>
+            <Button
+              onPress={() => this.showView('cervixEditView')}
+              title={cervixLabel}>
+            </Button>
+          </View>
+        </View>
       </View >
     )
   }
diff --git a/components/cycle-day/index.js b/components/cycle-day/index.js
index 758fa1da..3d2ffde8 100644
--- a/components/cycle-day/index.js
+++ b/components/cycle-day/index.js
@@ -10,6 +10,7 @@ import BleedingEditView from './symptoms/bleeding'
 import TemperatureEditView from './symptoms/temperature'
 import MucusEditView from './symptoms/mucus'
 import { formatDateForViewHeader } from './labels/format'
+import CervixEditView from './symptoms/cervix'
 import styles from '../../styles'
 import actionButtonModule from './action-buttons'
 
@@ -48,7 +49,8 @@ export default class Day extends Component {
             { dayView: <DayView cycleDay={this.cycleDay} showView={this.showView} />,
               bleedingEditView: <BleedingEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons}/>,
               temperatureEditView: <TemperatureEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons}/>,
-              mucusEditView: <MucusEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons}/>
+              mucusEditView: <MucusEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons}/>,
+              cervixEditView: <CervixEditView cycleDay={this.cycleDay} makeActionButtons={this.makeActionButtons} />
             }[this.state.visibleComponent]
           }
         </View >
diff --git a/components/cycle-day/labels/labels.js b/components/cycle-day/labels/labels.js
index 459370b2..25909dfc 100644
--- a/components/cycle-day/labels/labels.js
+++ b/components/cycle-day/labels/labels.js
@@ -2,10 +2,16 @@ 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 {
   bleeding,
   mucusFeeling,
   mucusTexture,
-  mucusNFP
+  mucusNFP,
+  cervixOpening,
+  cervixFirmness,
+  cervixPosition
 }
diff --git a/components/cycle-day/symptoms/cervix.js b/components/cycle-day/symptoms/cervix.js
new file mode 100644
index 00000000..2ba7aa4c
--- /dev/null
+++ b/components/cycle-day/symptoms/cervix.js
@@ -0,0 +1,125 @@
+import React, { Component } from 'react'
+import {
+  View,
+  Text,
+  Switch
+} from 'react-native'
+import RadioForm from 'react-native-simple-radio-button'
+import styles from '../../../styles'
+import { saveSymptom } from '../../../db'
+import {
+  cervixOpening as openingLabels,
+  cervixFirmness as firmnessLabels,
+  cervixPosition as positionLabels
+} from '../labels/labels'
+
+export default class Cervix extends Component {
+  constructor(props) {
+    super(props)
+    this.cycleDay = props.cycleDay
+    this.makeActionButtons = props.makeActionButtons
+    this.state = {
+      exclude: this.cycleDay.cervix ? this.cycleDay.cervix.exclude : false
+    }
+
+    this.state.currentOpeningValue = this.cycleDay.cervix && this.cycleDay.cervix.opening
+    if (typeof this.state.currentOpeningValue !== 'number') {
+      this.state.currentOpeningValue = -1
+    }
+    this.state.currentFirmnessValue = this.cycleDay.cervix && this.cycleDay.cervix.firmness
+    if (typeof this.state.currentFirmnessValue !== 'number') {
+      this.state.currentFirmnessValue = -1
+    }
+    this.state.currentPositionValue = this.cycleDay.cervix && this.cycleDay.cervix.position
+    if (typeof this.state.currentPositionValue !== 'number') {
+      this.state.currentPositionValue = -1
+    }
+  }
+
+  render() {
+    const cervixOpeningRadioProps = [
+      {label: openingLabels[0], value: 0},
+      {label: openingLabels[1], value: 1},
+      {label: openingLabels[2], value: 2}
+    ]
+    const cervixFirmnessRadioProps = [
+      {label: firmnessLabels[0], value: 0 },
+      {label: firmnessLabels[1], value: 1 }
+    ]
+    const cervixPositionRadioProps = [
+      {label: positionLabels[0], value: 0 },
+      {label: positionLabels[1], value: 1 },
+      {label: positionLabels[2], value: 2 }
+    ]
+    return(
+      <View style={ styles.symptomEditView }>
+        <Text style={styles.symptomDayView}>Cervix</Text>
+        <Text style={styles.symptomDayView}>Opening</Text>
+        <View style={styles.radioButtonRow}>
+          <RadioForm
+            radio_props={cervixOpeningRadioProps}
+            initial={this.state.currentOpeningValue}
+            formHorizontal={true}
+            labelHorizontal={false}
+            labelStyle={styles.radioButton}
+            onPress={(itemValue) => {
+              this.setState({currentOpeningValue: itemValue})
+            }}
+          />
+        </View>
+        <Text style={styles.symptomDayView}>Firmness</Text>
+        <View style={styles.radioButtonRow}>
+          <RadioForm
+            radio_props={cervixFirmnessRadioProps}
+            initial={this.state.currentFirmnessValue}
+            formHorizontal={true}
+            labelHorizontal={false}
+            labelStyle={styles.radioButton}
+            onPress={(itemValue) => {
+              this.setState({currentFirmnessValue: itemValue})
+            }}
+          />
+        </View>
+        <Text style={styles.symptomDayView}>Position</Text>
+        <View style={styles.radioButtonRow}>
+          <RadioForm
+            radio_props={cervixPositionRadioProps}
+            initial={this.state.currentPositionValue}
+            formHorizontal={true}
+            labelHorizontal={false}
+            labelStyle={styles.radioButton}
+            onPress={(itemValue) => {
+              this.setState({currentPositionValue: itemValue})
+            }}
+          />
+        </View>
+        <View style={styles.symptomViewRowInline}>
+          <Text style={styles.symptomDayView}>Exclude</Text>
+          <Switch
+            onValueChange={(val) => {
+              this.setState({ exclude: val })
+            }}
+            value={this.state.exclude}
+          />
+        </View>
+        <View style={styles.actionButtonRow}>
+          {this.makeActionButtons(
+            {
+              symptom: 'cervix',
+              cycleDay: this.cycleDay,
+              saveAction: () => {
+                saveSymptom('cervix', this.cycleDay, {
+                  opening: this.state.currentOpeningValue,
+                  firmness: this.state.currentFirmnessValue,
+                  position: this.state.currentPositionValue,
+                  exclude: this.state.exclude
+                })
+              },
+              saveDisabled: this.state.currentOpeningValue === -1 || this.state.currentFirmnessValue === -1
+            }
+          )}
+        </View>
+      </View>
+    )
+  }
+}
diff --git a/db.js b/db.js
index e2cf9408..6fb743d0 100644
--- a/db.js
+++ b/db.js
@@ -32,6 +32,16 @@ const MucusSchema = {
   }
 }
 
+const CervixSchema = {
+  name: 'Cervix',
+  properties: {
+    opening: 'int',
+    firmness: 'int',
+    position: {type: 'int', optional: true },
+    exclude: 'bool'
+  }
+}
+
 const CycleDaySchema = {
   name: 'CycleDay',
   primaryKey: 'date',
@@ -48,6 +58,10 @@ const CycleDaySchema = {
     mucus: {
       type: 'Mucus',
       optional: true
+    },
+    cervix: {
+      type: 'Cervix',
+      optional: true
     }
   }
 }
@@ -57,7 +71,8 @@ const db = new Realm({
     CycleDaySchema,
     TemperatureSchema,
     BleedingSchema,
-    MucusSchema
+    MucusSchema,
+    CervixSchema
   ],
   // we only want this in dev mode
   deleteRealmIfMigrationNeeded: true
-- 
GitLab