From 7a1ef388d3f5aa7a0f32b3fb68e979fdc77c8c98 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Tue, 21 Aug 2018 14:26:13 +0200 Subject: [PATCH 01/26] Move config to app level --- components/chart/day-column.js | 2 +- components/chart/dot-and-line.js | 2 +- components/chart/styles.js | 2 +- components/chart/y-axis.js | 2 +- components/chart/config.js => config.js | 2 ++ 5 files changed, 6 insertions(+), 4 deletions(-) rename components/chart/config.js => config.js (86%) diff --git a/components/chart/day-column.js b/components/chart/day-column.js index 88eb44e..a8d1562 100644 --- a/components/chart/day-column.js +++ b/components/chart/day-column.js @@ -4,7 +4,7 @@ import { } from 'react-native' import Icon from 'react-native-vector-icons/Entypo' import styles from './styles' -import config from './config' +import config from '../../config' import { getOrCreateCycleDay } from '../../db' import cycleModule from '../../lib/cycle' import DotAndLine from './dot-and-line' diff --git a/components/chart/dot-and-line.js b/components/chart/dot-and-line.js index 626cf02..418457f 100644 --- a/components/chart/dot-and-line.js +++ b/components/chart/dot-and-line.js @@ -1,7 +1,7 @@ import React, { Component } from 'react' import { View } from 'react-native' import styles from './styles' -import config from './config' +import config from '../../config' export default class DotAndLine extends Component { shouldComponentUpdate(newProps) { diff --git a/components/chart/styles.js b/components/chart/styles.js index c018eb1..8ee5a30 100644 --- a/components/chart/styles.js +++ b/components/chart/styles.js @@ -1,4 +1,4 @@ -import config from './config' +import config from '../../config' const styles = { curve: { diff --git a/components/chart/y-axis.js b/components/chart/y-axis.js index ccc9404..997dfba 100644 --- a/components/chart/y-axis.js +++ b/components/chart/y-axis.js @@ -1,6 +1,6 @@ import React from 'react' import { Text, View } from 'react-native' -import config from './config' +import config from '../../config' import styles from './styles' function makeYAxis() { diff --git a/components/chart/config.js b/config.js similarity index 86% rename from components/chart/config.js rename to config.js index ec3509e..13b5f49 100644 --- a/components/chart/config.js +++ b/config.js @@ -4,6 +4,8 @@ const config = { temperatureScale: { low: 35, high: 38, + min: 34, + max: 40, units: 0.1 } } From c6b490b2a4c87a87dece2ee21def654fccb961fb Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Tue, 21 Aug 2018 14:26:54 +0200 Subject: [PATCH 02/26] Add slider and save value in LocalStorage --- components/labels.js | 5 ++++ components/settings.js | 62 ++++++++++++++++++++++++++++++++++++++++-- local-storage/index.js | 11 ++++++++ package-lock.json | 46 +++++++++++++++++++++++-------- package.json | 1 + styles/index.js | 5 ++++ 6 files changed, 116 insertions(+), 14 deletions(-) create mode 100644 local-storage/index.js diff --git a/components/labels.js b/components/labels.js index 99400a2..bd294b6 100644 --- a/components/labels.js +++ b/components/labels.js @@ -29,5 +29,10 @@ export const settings = { success: { message: 'Data successfully imported' } + }, + tempScale: { + segmentTitle: 'Change temperature scale', + min: 'Min', + max: 'Max' } } \ No newline at end of file diff --git a/components/settings.js b/components/settings.js index 97907b1..0f8f76a 100644 --- a/components/settings.js +++ b/components/settings.js @@ -3,21 +3,28 @@ import { View, Button, ScrollView, - Alert + Alert, + Text } from 'react-native' - +import Slider from '@ptomasroos/react-native-multi-slider' import Share from 'react-native-share' import { DocumentPicker, DocumentPickerUtil } from 'react-native-document-picker' import rnfs from 'react-native-fs' import styles from '../styles/index' +import config from '../config' import { settings as labels } from './labels' import getDataAsCsvDataUri from '../lib/import-export/export-to-csv' import importCsv from '../lib/import-export/import-from-csv' +import { getTempScale, saveTempScale } from '../local-storage' export default class Settings extends Component { render() { return ( + + {labels.tempScale.segmentTitle} + + - - - - + + {labels.export.button} + {labels.export.segmentExplainer} + + {labels.export.button} + + + + {labels.import.button} + {labels.import.segmentExplainer} + + {labels.import.button} + ) diff --git a/styles/index.js b/styles/index.js index 7d5af98..c0995ed 100644 --- a/styles/index.js +++ b/styles/index.js @@ -92,6 +92,15 @@ export default StyleSheet.create({ settingsSegment: { backgroundColor: 'lightgrey', padding: 10, - marginTop: 10 + marginTop: 10, + }, + settingsSegmentTitle: { + fontWeight: 'bold' + }, + settingsButton: { + backgroundColor: 'darkgrey', + padding: 10, + alignItems: 'center', + margin: 10 } }) \ No newline at end of file From b4120d99d6b4b771faa50f45630ee9c9d5aa24c0 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Tue, 21 Aug 2018 15:05:52 +0200 Subject: [PATCH 04/26] Stylin' --- components/settings.js | 22 +++++++++++++++++++--- styles/index.js | 5 ++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/components/settings.js b/components/settings.js index 4278838..118dafb 100644 --- a/components/settings.js +++ b/components/settings.js @@ -32,7 +32,7 @@ export default class Settings extends Component { - {labels.export.button} + {labels.export.button} @@ -41,7 +41,7 @@ export default class Settings extends Component { - {labels.import.button} + {labels.import.button} @@ -82,7 +82,7 @@ class TempSlider extends Component { render() { return ( - + {`${labels.tempScale.min} ${this.state.min}`} {`${labels.tempScale.max} ${this.state.max}`} ) diff --git a/styles/index.js b/styles/index.js index c0995ed..44ea90d 100644 --- a/styles/index.js +++ b/styles/index.js @@ -98,9 +98,12 @@ export default StyleSheet.create({ fontWeight: 'bold' }, settingsButton: { - backgroundColor: 'darkgrey', + backgroundColor: '#351c4d', padding: 10, alignItems: 'center', margin: 10 + }, + settingsButtonText: { + color: 'white' } }) \ No newline at end of file From 8ccbd399d8f9530ccac8727a09c6b00583401c01 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Tue, 21 Aug 2018 15:22:35 +0200 Subject: [PATCH 05/26] Alert user about temp scale settings storage problem --- components/labels.js | 4 +++- components/settings.js | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/components/labels.js b/components/labels.js index 2d2d045..893062b 100644 --- a/components/labels.js +++ b/components/labels.js @@ -36,6 +36,8 @@ export const settings = { segmentTitle: 'Temperature scale', segmentExplainer: 'Change the minimum and maximum value for entered temperatures', min: 'Min', - max: 'Max' + max: 'Max', + loadError: 'Could not load saved temperature scale settings', + saveError: 'Could not save temperature scale settings' } } \ No newline at end of file diff --git a/components/settings.js b/components/settings.js index 118dafb..0c879aa 100644 --- a/components/settings.js +++ b/components/settings.js @@ -60,7 +60,13 @@ class TempSlider extends Component { } async getStoredScale() { - const storedScale = await getTempScale() + let storedScale + try { + storedScale = await getTempScale() + } catch(err) { + alertError(labels.tempScale.loadError) + return + } if (!storedScale) return this.setState(storedScale) } @@ -77,7 +83,11 @@ class TempSlider extends Component { min: values[0], max: values[1] }) - saveTempScale(this.state) + try { + saveTempScale(this.state) + } catch(err) { + alertError(labels.tempScale.saveError) + } } render() { From 76c47a96c54c14f06b17fb773d5b2dacc9a733a5 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Tue, 21 Aug 2018 15:24:00 +0200 Subject: [PATCH 06/26] Shorten line lengths --- components/settings.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/components/settings.js b/components/settings.js index 0c879aa..dca3484 100644 --- a/components/settings.js +++ b/components/settings.js @@ -22,26 +22,36 @@ export default class Settings extends Component { return ( - {labels.tempScale.segmentTitle} + + {labels.tempScale.segmentTitle} + {labels.tempScale.segmentExplainer} - {labels.export.button} + + {labels.export.button} + {labels.export.segmentExplainer} - {labels.export.button} + + {labels.export.button} + - {labels.import.button} + + {labels.import.button} + {labels.import.segmentExplainer} - {labels.import.button} + + {labels.import.button} + From 896f407f46feef954faf0f5c998925842f72c488 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Tue, 21 Aug 2018 21:23:29 +0200 Subject: [PATCH 07/26] Rename default low and high --- components/settings.js | 4 ++-- config.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/settings.js b/components/settings.js index dca3484..f92ff33 100644 --- a/components/settings.js +++ b/components/settings.js @@ -63,8 +63,8 @@ class TempSlider extends Component { constructor(props) { super(props) this.state = { - min: config.temperatureScale.low, - max: config.temperatureScale.high + min: config.temperatureScale.defaultLow, + max: config.temperatureScale.defaultHigh } this.getStoredScale() } diff --git a/config.js b/config.js index 13b5f49..d44ba54 100644 --- a/config.js +++ b/config.js @@ -2,8 +2,8 @@ const config = { chartHeight: 350, columnWidth: 25, temperatureScale: { - low: 35, - high: 38, + defaultLow: 35, + defaultHigh: 38, min: 34, max: 40, units: 0.1 From d5f9e6c6399737c52ec1fbc1ad0da4887821e1a6 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Tue, 21 Aug 2018 21:50:47 +0200 Subject: [PATCH 08/26] Export temp scale settings as observable --- local-storage/index.js | 12 ++++++++--- package-lock.json | 46 +++++++++++++++--------------------------- package.json | 1 + 3 files changed, 26 insertions(+), 33 deletions(-) diff --git a/local-storage/index.js b/local-storage/index.js index 5fff233..e64bc18 100644 --- a/local-storage/index.js +++ b/local-storage/index.js @@ -1,11 +1,17 @@ import { AsyncStorage } from 'react-native' +import Observable from 'obv' -export async function getTempScale() { +export const tempScaleObservable = Observable() +getTempScale() + +async function getTempScale() { const result = await AsyncStorage.getItem('tempScale') if (!result) return result - return JSON.parse(result) + tempScaleObservable.set(JSON.parse(result)) } export async function saveTempScale(scale) { - return AsyncStorage.setItem('tempScale', JSON.stringify(scale)) + await AsyncStorage.setItem('tempScale', JSON.stringify(scale)) + tempScaleObservable.set(scale) } + diff --git a/package-lock.json b/package-lock.json index 66bd9e7..2df2c48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3732,8 +3732,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -3751,13 +3750,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3770,18 +3767,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -3884,8 +3878,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -3895,7 +3888,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3908,20 +3900,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.2.4", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -3938,7 +3927,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -4011,8 +3999,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -4022,7 +4009,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4098,8 +4084,7 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -4129,7 +4114,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4147,7 +4131,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -4186,13 +4169,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.2", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -6033,6 +6014,11 @@ } } }, + "obv": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/obv/-/obv-0.0.1.tgz", + "integrity": "sha1-yyNhBjQVNvDaxIFeBnCCIcrX+14=" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", diff --git a/package.json b/package.json index d1c38e5..d35c6b1 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "js-joda": "^1.8.2", "moment": "^2.22.1", "object-path": "^0.11.4", + "obv": "0.0.1", "react": "16.4.1", "react-native": "^0.56.0", "react-native-calendars": "^1.19.3", From c597a654d8e1e36c59f94449a8ab52b80a4f7e92 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 08:43:41 +0200 Subject: [PATCH 09/26] Use settings from observable in chart --- components/chart/chart.js | 8 ++--- components/chart/y-axis.js | 62 +++++++++++++++++++++----------------- components/settings.js | 20 ++---------- local-storage/index.js | 17 ++++++++--- 4 files changed, 53 insertions(+), 54 deletions(-) diff --git a/components/chart/chart.js b/components/chart/chart.js index ded01cf..dd2c29b 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -2,13 +2,12 @@ import React, { Component } from 'react' import { View, FlatList } from 'react-native' import range from 'date-range' import { LocalDate } from 'js-joda' -import { yAxis, normalizeToScale, horizontalGrid } from './y-axis' +import { makeYAxisLabels, normalizeToScale, makeHorizontalGrid } from './y-axis' import setUpFertilityStatusFunc from './nfp-lines' import DayColumn from './day-column' import { getCycleDay, cycleDaysSortedByDate, getAmountOfCycleDays } from '../../db' import styles from './styles' -const yAxisView = {yAxis.labels} export default class CycleChart extends Component { constructor(props) { @@ -25,6 +24,7 @@ export default class CycleChart extends Component { /> ) } + this.yAxisView = {makeYAxisLabels()} this.reCalculateChartInfo = (function(Chart) { return function() { @@ -42,8 +42,8 @@ export default class CycleChart extends Component { render() { return ( - {yAxisView} - {horizontalGrid} + {this.yAxisView} + {makeHorizontalGrid()} { { const style = styles.yAxisLabel // this eyeballing is sadly necessary because RN does not // support percentage values for transforms, which we'd need // to reliably place the label vertically centered to the grid style.top = y - 8 - labels.push( + return ( - {scaleMax - i * scale.units} + {scaleMax - i * units} ) - tickPositions.push(y) - } - - return {labels, tickPositions} + }) } -export const yAxis = makeYAxis() +export function makeHorizontalGrid() { + return getTickPositions().map(tick => { + return ( + + ) + }) +} -export const horizontalGrid = yAxis.tickPositions.map(tick => { - return ( - - ) -}) +function getTickPositions() { + const units = config.temperatureScale.units + const scaleMin = tempScaleObservable.value.min + const scaleMax = tempScaleObservable.value.max + const numberOfTicks = (scaleMax - scaleMin) * (1 / units) + const tickDistance = config.chartHeight / numberOfTicks + + const tickPositions = [] + // for style reasons, we don't want the first and last tick + for (let i = 1; i < numberOfTicks - 1; i++) { + tickPositions.push(tickDistance * i) + } + return tickPositions +} export function normalizeToScale(temp) { const scale = config.temperatureScale diff --git a/components/settings.js b/components/settings.js index f92ff33..f5fa29f 100644 --- a/components/settings.js +++ b/components/settings.js @@ -15,7 +15,7 @@ import config from '../config' import { settings as labels } from './labels' import getDataAsCsvDataUri from '../lib/import-export/export-to-csv' import importCsv from '../lib/import-export/import-from-csv' -import { getTempScale, saveTempScale } from '../local-storage' +import { tempScaleObservable, saveTempScale } from '../local-storage' export default class Settings extends Component { render() { @@ -62,23 +62,7 @@ export default class Settings extends Component { class TempSlider extends Component { constructor(props) { super(props) - this.state = { - min: config.temperatureScale.defaultLow, - max: config.temperatureScale.defaultHigh - } - this.getStoredScale() - } - - async getStoredScale() { - let storedScale - try { - storedScale = await getTempScale() - } catch(err) { - alertError(labels.tempScale.loadError) - return - } - if (!storedScale) return - this.setState(storedScale) + this.state = Object.assign({}, tempScaleObservable.value) } onValuesChange = (values) => { diff --git a/local-storage/index.js b/local-storage/index.js index e64bc18..21ac57c 100644 --- a/local-storage/index.js +++ b/local-storage/index.js @@ -1,13 +1,22 @@ import { AsyncStorage } from 'react-native' import Observable from 'obv' +import config from '../config' export const tempScaleObservable = Observable() -getTempScale() +setTempScaleInitially() -async function getTempScale() { +async function setTempScaleInitially() { const result = await AsyncStorage.getItem('tempScale') - if (!result) return result - tempScaleObservable.set(JSON.parse(result)) + let value + if (result) { + value = JSON.parse(result) + } else { + value = { + min: config.temperatureScale.defaultLow, + max: config.temperatureScale.defaultHigh + } + } + tempScaleObservable.set(value) } export async function saveTempScale(scale) { From 7538dbdccc0014dc84785bcffef299655fc9d5de Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 10:17:32 +0200 Subject: [PATCH 10/26] Rerender chart on scale observable change --- components/chart/chart.js | 7 ++++--- components/chart/day-column.js | 2 +- components/chart/y-axis.js | 12 ++++++------ components/settings.js | 4 ++-- local-storage/index.js | 6 +++--- 5 files changed, 16 insertions(+), 15 deletions(-) diff --git a/components/chart/chart.js b/components/chart/chart.js index dd2c29b..da19f2c 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -7,7 +7,7 @@ import setUpFertilityStatusFunc from './nfp-lines' import DayColumn from './day-column' import { getCycleDay, cycleDaysSortedByDate, getAmountOfCycleDays } from '../../db' import styles from './styles' - +import { scaleObservable } from '../../local-storage' export default class CycleChart extends Component { constructor(props) { @@ -24,7 +24,6 @@ export default class CycleChart extends Component { /> ) } - this.yAxisView = {makeYAxisLabels()} this.reCalculateChartInfo = (function(Chart) { return function() { @@ -33,16 +32,18 @@ export default class CycleChart extends Component { })(this) cycleDaysSortedByDate.addListener(this.reCalculateChartInfo) + this.removeObvListener = scaleObservable(this.reCalculateChartInfo, false) } componentWillUnmount() { cycleDaysSortedByDate.removeListener(this.reCalculateChartInfo) + this.removeObvListener() } render() { return ( - {this.yAxisView} + {makeYAxisLabels()} {makeHorizontalGrid()} { { const style = styles.yAxisLabel @@ -38,8 +38,8 @@ export function makeHorizontalGrid() { function getTickPositions() { const units = config.temperatureScale.units - const scaleMin = tempScaleObservable.value.min - const scaleMax = tempScaleObservable.value.max + const scaleMin = scaleObservable.value.min + const scaleMax = scaleObservable.value.max const numberOfTicks = (scaleMax - scaleMin) * (1 / units) const tickDistance = config.chartHeight / numberOfTicks @@ -52,8 +52,8 @@ function getTickPositions() { } export function normalizeToScale(temp) { - const scale = config.temperatureScale - const valueRelativeToScale = (scale.high - temp) / (scale.high - scale.low) + const scale = scaleObservable.value + const valueRelativeToScale = (scale.max - temp) / (scale.max - scale.min) const scaleHeight = config.chartHeight return scaleHeight * valueRelativeToScale } \ No newline at end of file diff --git a/components/settings.js b/components/settings.js index f5fa29f..49172db 100644 --- a/components/settings.js +++ b/components/settings.js @@ -15,7 +15,7 @@ import config from '../config' import { settings as labels } from './labels' import getDataAsCsvDataUri from '../lib/import-export/export-to-csv' import importCsv from '../lib/import-export/import-from-csv' -import { tempScaleObservable, saveTempScale } from '../local-storage' +import { scaleObservable, saveTempScale } from '../local-storage' export default class Settings extends Component { render() { @@ -62,7 +62,7 @@ export default class Settings extends Component { class TempSlider extends Component { constructor(props) { super(props) - this.state = Object.assign({}, tempScaleObservable.value) + this.state = Object.assign({}, scaleObservable.value) } onValuesChange = (values) => { diff --git a/local-storage/index.js b/local-storage/index.js index 21ac57c..50d886f 100644 --- a/local-storage/index.js +++ b/local-storage/index.js @@ -2,7 +2,7 @@ import { AsyncStorage } from 'react-native' import Observable from 'obv' import config from '../config' -export const tempScaleObservable = Observable() +export const scaleObservable = Observable() setTempScaleInitially() async function setTempScaleInitially() { @@ -16,11 +16,11 @@ async function setTempScaleInitially() { max: config.temperatureScale.defaultHigh } } - tempScaleObservable.set(value) + scaleObservable.set(value) } export async function saveTempScale(scale) { await AsyncStorage.setItem('tempScale', JSON.stringify(scale)) - tempScaleObservable.set(scale) + scaleObservable.set(scale) } From 0878135aed7b827fda126520470f345ece61fc9f Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 13:17:12 +0200 Subject: [PATCH 11/26] Warn when user enters an out-of-range temperature --- components/cycle-day/action-buttons.js | 4 +- components/cycle-day/labels/labels.js | 5 + components/cycle-day/symptoms/temperature.js | 96 ++++++++++++++------ components/labels.js | 12 ++- styles/index.js | 5 +- 5 files changed, 84 insertions(+), 38 deletions(-) diff --git a/components/cycle-day/action-buttons.js b/components/cycle-day/action-buttons.js index 78e2479..9ddb036 100644 --- a/components/cycle-day/action-buttons.js +++ b/components/cycle-day/action-buttons.js @@ -22,8 +22,8 @@ export default function (showView) { } }, { title: 'Save', - action: () => { - saveAction() + action: async () => { + await saveAction() showView(dayView) }, disabledCondition: saveDisabled diff --git a/components/cycle-day/labels/labels.js b/components/cycle-day/labels/labels.js index ee88428..c2e185b 100644 --- a/components/cycle-day/labels/labels.js +++ b/components/cycle-day/labels/labels.js @@ -26,3 +26,8 @@ export const fertilityStatus = { fertileUntilEvening: 'Fertile phase ends in the evening', unknown: 'We cannot show any cycle information because no menses has been entered' } + +export const temperature = { + outOfRangeWarning: 'This temperature value is out of the current range for the temperature chart. You can change the range in the settings.', + saveAnyway: 'Save anyway' +} diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index 7296883..6d3a372 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -4,56 +4,89 @@ import { Text, TextInput, Switch, - Keyboard + Keyboard, + Alert } from 'react-native' import DateTimePicker from 'react-native-modal-datetime-picker-nevo' import { getPreviousTemperature, saveSymptom } from '../../../db' import styles from '../../../styles' import { LocalTime, ChronoUnit } from 'js-joda' +import { temperature as tempLabels } from '../labels/labels' +import { scaleObservable } from '../../../local-storage' +import { shared } from '../../labels' -const MINUTES = ChronoUnit.MINUTES +const minutes = ChronoUnit.MINUTES export default class Temp extends Component { constructor(props) { super(props) this.cycleDay = props.cycleDay this.makeActionButtons = props.makeActionButtons - let initialValue const temp = this.cycleDay.temperature - if (temp) { - initialValue = temp.value.toString() - this.time = temp.time - } else { - const prevTemp = getPreviousTemperature(this.cycleDay) - initialValue = prevTemp ? prevTemp.toString() : '' + this.state = { + exclude: temp ? temp.exclude : false, + time: temp ? temp.time : LocalTime.now().truncatedTo(minutes).toString(), + isTimePickerVisible: false, + integer: '', + fractional: '', + outOfRange: null } - this.state = { - currentValue: initialValue, - exclude: temp ? temp.exclude : false, - time: this.time || LocalTime.now().truncatedTo(MINUTES).toString(), - isTimePickerVisible: false + if (temp) { + const [integer, fractional] = temp.value.toString().split('.') + this.state.integer = integer + this.state.fractional = fractional + } else { + const prevTemp = getPreviousTemperature(this.cycleDay) + if (prevTemp) { + const [integer, fractional] = prevTemp.toString().split('.') + this.state.integer = integer + this.state.fractional = fractional + } + } + } + + checkRange = () => { + const value = Number(`${this.state.integer}.${this.state.fractional}`) + if (isNaN(value)) return + const scale = scaleObservable.value + if (value < scale.min || value > scale.max) { + Alert.alert( + shared.warning, + tempLabels.outOfRangeWarning, + ) } } render() { - const cycleDay = this.cycleDay return ( Temperature (°C) - { - this.setState({ currentValue: val }) - }} - keyboardType='numeric' - value={this.state.currentValue} - /> + + { + this.setState({ integer: val }) + }} + keyboardType='numeric' + value={this.state.integer} + onBlur={this.checkRange} + /> + . + { + this.setState({ fractional: val }) + }} + keyboardType='numeric' + value={this.state.fractional} + onBlur={this.checkRange} + /> + Time @@ -71,7 +104,7 @@ export default class Temp extends Component { isVisible={this.state.isTimePickerVisible} onConfirm={jsDate => { this.setState({ - time: `${jsDate.getHours()}:${jsDate.getMinutes()}`, + time: `${jsDate.getinteger()}:${jsDate.getfractional()}`, isTimePickerVisible: false }) }} @@ -90,15 +123,20 @@ export default class Temp extends Component { {this.makeActionButtons({ symptom: 'temperature', cycleDay: this.cycleDay, - saveAction: () => { + saveAction: async () => { + const v = Number(`${this.state.integer}.${this.state.fractional}`) const dataToSave = { - value: Number(this.state.currentValue), + value: v, exclude: this.state.exclude, time: this.state.time } - saveSymptom('temperature', cycleDay, dataToSave) + saveSymptom('temperature', this.cycleDay, dataToSave) }, - saveDisabled: this.state.currentValue === '' || isInvalidTime(this.state.time) + saveDisabled: + this.state.integer === '' || + isNaN(Number(this.state.integer)) || + isNaN(Number(this.state.fractional)) || + isInvalidTime(this.state.time) })} diff --git a/components/labels.js b/components/labels.js index 893062b..27cef63 100644 --- a/components/labels.js +++ b/components/labels.js @@ -1,9 +1,11 @@ +export const shared = { + cancel: 'Cancel', + errorTitle: 'Error', + successTitle: 'Success', + warning: 'Warning' +} + export const settings = { - shared: { - cancel: 'Cancel', - errorTitle: 'Error', - successTitle: 'Success' - }, export: { errors: { noData: 'There is no data to export', diff --git a/styles/index.js b/styles/index.js index 44ea90d..69ef0c2 100644 --- a/styles/index.js +++ b/styles/index.js @@ -66,8 +66,6 @@ export default StyleSheet.create({ marginBottom: 15 }, temperatureTextInput: { - width: 80, - textAlign: 'center', fontSize: 20 }, actionButtonRow: { @@ -105,5 +103,8 @@ export default StyleSheet.create({ }, settingsButtonText: { color: 'white' + }, + warning: { + color: 'red' } }) \ No newline at end of file From 7725f1be1445eb318b56a655c1d40906f43d3c45 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 14:05:08 +0200 Subject: [PATCH 12/26] Limit length --- components/cycle-day/symptoms/temperature.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index 6d3a372..9a5efc2 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -70,21 +70,25 @@ export default class Temp extends Component { { + if (isNaN(Number(val))) return this.setState({ integer: val }) }} keyboardType='numeric' value={this.state.integer} - onBlur={this.checkRange} + maxLength={2} /> . { + if (isNaN(Number(val))) return this.setState({ fractional: val }) }} keyboardType='numeric' value={this.state.fractional} onBlur={this.checkRange} + maxLength={2} + autoFocus={true} /> From 3a162ca0ccf9f9c79d4e4274bcd3e77d94c166a8 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 14:07:12 +0200 Subject: [PATCH 13/26] Add '.0' for integers --- components/cycle-day/symptoms/temperature.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index 9a5efc2..f8d2bcb 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -38,7 +38,7 @@ export default class Temp extends Component { if (temp) { const [integer, fractional] = temp.value.toString().split('.') this.state.integer = integer - this.state.fractional = fractional + this.state.fractional = fractional || '0' } else { const prevTemp = getPreviousTemperature(this.cycleDay) if (prevTemp) { From e9c4256661af0199613f95d7889047ea05dbf3b0 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 15:53:36 +0200 Subject: [PATCH 14/26] Extract temp input into component --- components/cycle-day/symptoms/temperature.js | 94 ++++++++++++-------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index f8d2bcb..966a227 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -49,48 +49,16 @@ export default class Temp extends Component { } } - checkRange = () => { - const value = Number(`${this.state.integer}.${this.state.fractional}`) - if (isNaN(value)) return - const scale = scaleObservable.value - if (value < scale.min || value > scale.max) { - Alert.alert( - shared.warning, - tempLabels.outOfRangeWarning, - ) - } - } - render() { return ( Temperature (°C) - - { - if (isNaN(Number(val))) return - this.setState({ integer: val }) - }} - keyboardType='numeric' - value={this.state.integer} - maxLength={2} - /> - . - { - if (isNaN(Number(val))) return - this.setState({ fractional: val }) - }} - keyboardType='numeric' - value={this.state.fractional} - onBlur={this.checkRange} - maxLength={2} - autoFocus={true} - /> - + this.setState(val)} + /> Time @@ -148,6 +116,58 @@ export default class Temp extends Component { } } +class TempInputPair extends Component { + render() { + return ( + + + . + + + ) + } +} +class TempInput extends Component { + checkRange = () => { + const value = Number(`${this.props.integer}.${this.props.fractional}`) + if (isNaN(value)) return + const scale = scaleObservable.value + if (value < scale.min || value > scale.max) { + Alert.alert( + shared.warning, + tempLabels.outOfRangeWarning, + ) + } + } + + render() { + return ( + { + if (isNaN(Number(val))) return + this.props.setState({ [this.props.type]: val }) + }} + keyboardType='numeric' + value={this.props[this.props.type]} + onBlur={this.checkRange} + maxLength={2} + autoFocus={this.props.type === 'fractional'} + /> + ) + } +} + function isInvalidTime(timeString) { try { LocalTime.parse(timeString) From eedd6070cf4335acb557b84fdd3272f18d3c21f2 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 16:23:09 +0200 Subject: [PATCH 15/26] Make temperature suggestion grey --- components/cycle-day/symptoms/temperature.js | 12 ++++++++++-- styles/index.js | 6 +++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index 966a227..9c0fb7a 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -45,6 +45,7 @@ export default class Temp extends Component { const [integer, fractional] = prevTemp.toString().split('.') this.state.integer = integer this.state.fractional = fractional + this.state.isSuggestion = true } } } @@ -58,6 +59,7 @@ export default class Temp extends Component { integer={this.state.integer} fractional={this.state.fractional} setState={(val) => this.setState(val)} + isSuggestion={this.state.isSuggestion} /> @@ -125,6 +127,7 @@ class TempInputPair extends Component { integer={this.props.integer} fractional={this.props.fractional} setState={this.props.setState} + isSuggestion={this.props.isSuggestion} /> . ) @@ -151,12 +155,16 @@ class TempInput extends Component { } render() { + const style = [styles.temperatureTextInput] + if (this.props.isSuggestion) { + style.push(styles.temperatureTextInputSuggestion) + } return ( { if (isNaN(Number(val))) return - this.props.setState({ [this.props.type]: val }) + this.props.setState({ [this.props.type]: val, isSuggestion: false }) }} keyboardType='numeric' value={this.props[this.props.type]} diff --git a/styles/index.js b/styles/index.js index 69ef0c2..a8844b1 100644 --- a/styles/index.js +++ b/styles/index.js @@ -66,7 +66,11 @@ export default StyleSheet.create({ marginBottom: 15 }, temperatureTextInput: { - fontSize: 20 + fontSize: 20, + color: 'black' + }, + temperatureTextInputSuggestion: { + color: '#939393' }, actionButtonRow: { flexDirection: 'row', From 0e77a2f6135c142a5cd8b7526375c8dff111e04b Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 17:03:36 +0200 Subject: [PATCH 16/26] Re-simplify the input --- components/cycle-day/symptoms/temperature.js | 62 ++++++-------------- 1 file changed, 17 insertions(+), 45 deletions(-) diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index 9c0fb7a..955fe16 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -30,21 +30,19 @@ export default class Temp extends Component { exclude: temp ? temp.exclude : false, time: temp ? temp.time : LocalTime.now().truncatedTo(minutes).toString(), isTimePickerVisible: false, - integer: '', - fractional: '', outOfRange: null } if (temp) { - const [integer, fractional] = temp.value.toString().split('.') - this.state.integer = integer - this.state.fractional = fractional || '0' + this.state.temperature = temp.value.toString() + if (temp.value === Math.floor(temp.value)) { + this.state.temperature = `${this.state.temperature}.0` + } } else { const prevTemp = getPreviousTemperature(this.cycleDay) + console.log(prevTemp) if (prevTemp) { - const [integer, fractional] = prevTemp.toString().split('.') - this.state.integer = integer - this.state.fractional = fractional + this.state.temperature = prevTemp.toString() this.state.isSuggestion = true } } @@ -55,9 +53,8 @@ export default class Temp extends Component { Temperature (°C) - this.setState(val)} isSuggestion={this.state.isSuggestion} /> @@ -78,7 +75,7 @@ export default class Temp extends Component { isVisible={this.state.isTimePickerVisible} onConfirm={jsDate => { this.setState({ - time: `${jsDate.getinteger()}:${jsDate.getfractional()}`, + time: `${jsDate.getHours()}:${jsDate.getMinutes()}`, isTimePickerVisible: false }) }} @@ -98,18 +95,16 @@ export default class Temp extends Component { symptom: 'temperature', cycleDay: this.cycleDay, saveAction: async () => { - const v = Number(`${this.state.integer}.${this.state.fractional}`) const dataToSave = { - value: v, + value: Number(this.state.temperature), exclude: this.state.exclude, time: this.state.time } saveSymptom('temperature', this.cycleDay, dataToSave) }, saveDisabled: - this.state.integer === '' || - isNaN(Number(this.state.integer)) || - isNaN(Number(this.state.fractional)) || + this.state.temperature === '' || + isNaN(Number(this.state.temperature)) || isInvalidTime(this.state.time) })} @@ -118,32 +113,10 @@ export default class Temp extends Component { } } -class TempInputPair extends Component { - render() { - return ( - - - . - - - ) - } -} class TempInput extends Component { checkRange = () => { - const value = Number(`${this.props.integer}.${this.props.fractional}`) + const value = Number(this.props.value) + console.log(value) if (isNaN(value)) return const scale = scaleObservable.value if (value < scale.min || value > scale.max) { @@ -164,13 +137,12 @@ class TempInput extends Component { style={style} onChangeText={(val) => { if (isNaN(Number(val))) return - this.props.setState({ [this.props.type]: val, isSuggestion: false }) + this.props.setState({ temperature: val, isSuggestion: false }) }} keyboardType='numeric' - value={this.props[this.props.type]} + value={this.props.value} onBlur={this.checkRange} - maxLength={2} - autoFocus={this.props.type === 'fractional'} + autoFocus={true} /> ) } From c6d61320e7aea17cc4e673f9b3b7191aefc1fbd4 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 17:41:23 +0200 Subject: [PATCH 17/26] Fix explainer text --- components/labels.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/labels.js b/components/labels.js index 6abed86..28cd393 100644 --- a/components/labels.js +++ b/components/labels.js @@ -36,7 +36,7 @@ export const settings = { }, tempScale: { segmentTitle: 'Temperature scale', - segmentExplainer: 'Change the minimum and maximum value for entered temperatures', + segmentExplainer: 'Change the minimum and maximum value for the temperature chart', min: 'Min', max: 'Max', loadError: 'Could not load saved temperature scale settings', From 15ad708a9c4fedb45adc359a0c9b309e044eef55 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 17:44:54 +0200 Subject: [PATCH 18/26] Use color variables --- components/settings.js | 4 ++-- styles/index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/settings.js b/components/settings.js index 49172db..7b0d047 100644 --- a/components/settings.js +++ b/components/settings.js @@ -10,7 +10,7 @@ import Slider from '@ptomasroos/react-native-multi-slider' import Share from 'react-native-share' import { DocumentPicker, DocumentPickerUtil } from 'react-native-document-picker' import rnfs from 'react-native-fs' -import styles from '../styles/index' +import styles, { secondaryColor } from '../styles/index' import config from '../config' import { settings as labels } from './labels' import getDataAsCsvDataUri from '../lib/import-export/export-to-csv' @@ -106,7 +106,7 @@ class TempSlider extends Component { height:10, }} markerStyle={{ - backgroundColor: '#351c4d', + backgroundColor: secondaryColor, height: 20, width: 20, borderRadius: 100, diff --git a/styles/index.js b/styles/index.js index 2019b9c..43a5599 100644 --- a/styles/index.js +++ b/styles/index.js @@ -163,13 +163,13 @@ export default StyleSheet.create({ fontWeight: 'bold' }, settingsButton: { - backgroundColor: '#351c4d', + backgroundColor: secondaryColor, padding: 10, alignItems: 'center', margin: 10 }, settingsButtonText: { - color: 'white' + color: fontOnPrimaryColor }, statsRow: { flexDirection: 'row', From 654dbf5e9816c49eefd28049199b963133ef3fd9 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Wed, 22 Aug 2018 18:33:00 +0200 Subject: [PATCH 19/26] Fix labels --- components/settings.js | 52 +++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/components/settings.js b/components/settings.js index 7b0d047..f03aec9 100644 --- a/components/settings.js +++ b/components/settings.js @@ -12,7 +12,7 @@ import { DocumentPicker, DocumentPickerUtil } from 'react-native-document-picker import rnfs from 'react-native-fs' import styles, { secondaryColor } from '../styles/index' import config from '../config' -import { settings as labels } from './labels' +import { settings as settingsLabels, shared as sharedLabels } from './labels' import getDataAsCsvDataUri from '../lib/import-export/export-to-csv' import importCsv from '../lib/import-export/import-from-csv' import { scaleObservable, saveTempScale } from '../local-storage' @@ -23,34 +23,34 @@ export default class Settings extends Component { - {labels.tempScale.segmentTitle} + {settingsLabels.tempScale.segmentTitle} - {labels.tempScale.segmentExplainer} + {settingsLabels.tempScale.segmentExplainer} - {labels.export.button} + {settingsLabels.export.button} - {labels.export.segmentExplainer} + {settingsLabels.export.segmentExplainer} - {labels.export.button} + {settingsLabels.export.button} - {labels.import.button} + {settingsLabels.import.button} - {labels.import.segmentExplainer} + {settingsLabels.import.segmentExplainer} - {labels.import.button} + {settingsLabels.import.button} @@ -80,15 +80,15 @@ class TempSlider extends Component { try { saveTempScale(this.state) } catch(err) { - alertError(labels.tempScale.saveError) + alertError(settingsLabels.tempScale.saveError) } } render() { return ( - {`${labels.tempScale.min} ${this.state.min}`} - {`${labels.tempScale.max} ${this.state.max}`} + {`${settingsLabels.tempScale.min} ${this.state.min}`} + {`${settingsLabels.tempScale.max} ${this.state.max}`} getFileContentAndImport({ deleteExisting: false }) }, { - text: labels.import.deleteOption, + text: settingsLabels.import.deleteOption, onPress: () => getFileContentAndImport({ deleteExisting: true }) }, { - text: labels.shared.cancel, style: 'cancel', onPress: () => { } + text: sharedLabels.cancel, style: 'cancel', onPress: () => { } }] ) } @@ -180,22 +180,22 @@ async function getFileContentAndImport({ deleteExisting }) { try { fileContent = await rnfs.readFile(fileInfo.uri, 'utf8') } catch (err) { - return importError(labels.import.errors.couldNotOpenFile) + return importError(settingsLabels.import.errors.couldNotOpenFile) } try { await importCsv(fileContent, deleteExisting) - Alert.alert(labels.import.success.title, labels.import.success.message) + Alert.alert(sharedLabels.successTitle, settingsLabels.import.success.message) } catch(err) { importError(err.message) } } function alertError(msg) { - Alert.alert(labels.shared.errorTitle, msg) + Alert.alert(sharedLabels.errorTitle, msg) } function importError(msg) { - const postFixed = `${msg}\n\n${labels.import.errors.postFix}` + const postFixed = `${msg}\n\n${settingsLabels.import.errors.postFix}` alertError(postFixed) } From 2471b92eaf2ea05f90afd68239739d65a39ca7e5 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Fri, 24 Aug 2018 09:53:57 +0200 Subject: [PATCH 20/26] Determine chart height dynamically and fill the window --- .eslintrc | 9 +- components/chart/chart.js | 129 +++++++++++-------- components/chart/day-column.js | 27 ++-- components/chart/nfp-lines.js | 4 +- components/chart/styles.js | 5 +- components/chart/y-axis.js | 30 ++--- components/cycle-day/symptoms/temperature.js | 2 - config.js | 8 +- styles/index.js | 10 +- 9 files changed, 126 insertions(+), 98 deletions(-) diff --git a/.eslintrc b/.eslintrc index fb7b984..028ba73 100644 --- a/.eslintrc +++ b/.eslintrc @@ -49,6 +49,13 @@ "prefer-const": "error", "no-trailing-spaces": "error", "react/prop-types": 0, - "max-len": [1, {"ignoreStrings": true}] + "max-len": [ + 1, + { + "ignoreStrings": true, + "ignoreComments": true, + "ignoreTemplateLiterals": true + } + ] } } \ No newline at end of file diff --git a/components/chart/chart.js b/components/chart/chart.js index 09bcf44..d8a9713 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -1,9 +1,9 @@ import React, { Component } from 'react' -import { View, FlatList, ScrollView } from 'react-native' +import { View, FlatList, Text } from 'react-native' import range from 'date-range' import { LocalDate } from 'js-joda' import { makeYAxisLabels, normalizeToScale, makeHorizontalGrid } from './y-axis' -import setUpFertilityStatusFunc from './nfp-lines' +import nfpLines from './nfp-lines' import DayColumn from './day-column' import { getCycleDay, cycleDaysSortedByDate, getAmountOfCycleDays } from '../../db' import styles from './styles' @@ -12,24 +12,27 @@ import { scaleObservable } from '../../local-storage' export default class CycleChart extends Component { constructor(props) { super(props) - this.state = { - columns: makeColumnInfo(setUpFertilityStatusFunc()), - } + this.state = {} this.renderColumn = ({item, index}) => { return ( ) } + } - this.reCalculateChartInfo = (function(Chart) { - return function() { - Chart.setState({columns: makeColumnInfo(setUpFertilityStatusFunc())}) - } - })(this) + onLayout = ({ nativeEvent }) => { + if (this.state.chartHeight) return + + const height = nativeEvent.layout.height + this.setState({ chartHeight: height }) + this.reCalculateChartInfo = () => { + this.setState({ columns: this.makeColumnInfo(nfpLines(height)) }) + } cycleDaysSortedByDate.addListener(this.reCalculateChartInfo) this.removeObvListener = scaleObservable(this.reCalculateChartInfo, false) @@ -40,13 +43,65 @@ export default class CycleChart extends Component { this.removeObvListener() } + makeColumnInfo(getFhmAndLtlInfo) { + let amountOfCycleDays = getAmountOfCycleDays() + // if there's not much data yet, we want to show at least 30 days on the chart + if (amountOfCycleDays < 30) { + amountOfCycleDays = 30 + } else { + // we don't want the chart to end abruptly before the first data day + amountOfCycleDays += 5 + } + const jsDates = getTodayAndPreviousDays(amountOfCycleDays) + const xAxisDates = jsDates.map(jsDate => { + return LocalDate.of( + jsDate.getFullYear(), + jsDate.getMonth() + 1, + jsDate.getDate() + ).toString() + }) + + const columns = xAxisDates.map(dateString => { + const cycleDay = getCycleDay(dateString) + const symptoms = ['temperature', 'mucus', 'bleeding'].reduce((acc, symptom) => { + acc[symptom] = cycleDay && cycleDay[symptom] && cycleDay[symptom].value + acc[`${symptom}Exclude`] = cycleDay && cycleDay[symptom] && cycleDay[symptom].exclude + return acc + }, {}) + + const temp = symptoms.temperature + return { + dateString, + y: temp ? normalizeToScale(temp, this.state.chartHeight) : null, + ...symptoms, + ...getFhmAndLtlInfo(dateString, temp) + } + }) + + return columns.map((col, i) => { + const info = getInfoForNeighborColumns(i, columns) + return Object.assign(col, info) + }) + } + render() { return ( - - - {makeYAxisLabels()} - {makeHorizontalGrid()} - { + {!this.state.chartHeight && Loading...} + {this.state.chartHeight && + + {makeYAxisLabels(this.state.chartHeight)} + } + + {this.state.chartHeight && makeHorizontalGrid(this.state.chartHeight)} + + {this.state.chartHeight && + - } - - + + } + ) } } -function makeColumnInfo(getFhmAndLtlInfo) { - let amountOfCycleDays = getAmountOfCycleDays() - // if there's not much data yet, we want to show at least 30 days on the chart - if (amountOfCycleDays < 30) { - amountOfCycleDays = 30 - } else { - // we don't want the chart to end abruptly before the first data day - amountOfCycleDays += 5 - } - const xAxisDates = getTodayAndPreviousDays(amountOfCycleDays).map(jsDate => { - return LocalDate.of( - jsDate.getFullYear(), - jsDate.getMonth() + 1, - jsDate.getDate() - ).toString() - }) - - const columns = xAxisDates.map(dateString => { - const cycleDay = getCycleDay(dateString) - const symptoms = ['temperature', 'mucus', 'bleeding'].reduce((acc, symptom) => { - acc[symptom] = cycleDay && cycleDay[symptom] && cycleDay[symptom].value - acc[`${symptom}Exclude`] = cycleDay && cycleDay[symptom] && cycleDay[symptom].exclude - return acc - }, {}) - - return { - dateString, - y: symptoms.temperature ? normalizeToScale(symptoms.temperature) : null, - ...symptoms, - ...getFhmAndLtlInfo(dateString, symptoms.temperature) - } - }) - - return columns.map((col, i) => { - const info = getInfoForNeighborColumns(i, columns) - return Object.assign(col, info) - }) -} function getTodayAndPreviousDays(n) { const today = new Date() diff --git a/components/chart/day-column.js b/components/chart/day-column.js index 1b61a7a..b6bf2d5 100644 --- a/components/chart/day-column.js +++ b/components/chart/day-column.js @@ -105,25 +105,22 @@ export default class DayColumn extends Component { const cycleDayNumber = getCycleDayNumber(dateString) const shortDate = dateString.split('-').slice(1).join('-') const cycleDayLabel = ( - + {cycleDayNumber} ) const dateLabel = ( - + {shortDate} ) - columnElements.push( - - {cycleDayLabel} - {dateLabel} - - ) - return React.createElement( + const columnHeight = this.props.chartHeight * config.columnHeightPercentage + const xAxisHeight = this.props.chartHeight * config.xAxisHeightPercentage + + const column = React.createElement( TouchableOpacity, { - style: styles.column.rect, + style: [styles.column.rect, {height: columnHeight}], key: this.props.index.toString(), onPress: () => { this.passDateToDayView(dateString) @@ -132,5 +129,15 @@ export default class DayColumn extends Component { }, columnElements ) + + return ( + + {column} + + {cycleDayLabel} + {dateLabel} + + + ) } } \ No newline at end of file diff --git a/components/chart/nfp-lines.js b/components/chart/nfp-lines.js index d9f4507..ded95e8 100644 --- a/components/chart/nfp-lines.js +++ b/components/chart/nfp-lines.js @@ -1,7 +1,7 @@ import { getCycleStatusForDay } from '../../lib/sympto-adapter' import { normalizeToScale } from './y-axis' -export default function () { +export default function (chartHeight) { const cycle = { status: null } @@ -71,7 +71,7 @@ export default function () { dateIsInPeriOrPostPhase(dateString) && isInTempMeasuringPhase(temperature, dateString) ) { - ret.drawLtlAt = normalizeToScale(tempShift.ltl) + ret.drawLtlAt = normalizeToScale(tempShift.ltl, chartHeight) } } diff --git a/components/chart/styles.js b/components/chart/styles.js index 8ee5a30..d60e1a0 100644 --- a/components/chart/styles.js +++ b/components/chart/styles.js @@ -38,10 +38,10 @@ const styles = { }, rect: { width: config.columnWidth, - height: config.chartHeight, borderStyle: 'solid', borderColor: 'grey', - borderWidth: 0.5 + borderLeftWidth: 0.5, + borderRightWidth: 0.5, } }, bleedingIcon: { @@ -63,7 +63,6 @@ const styles = { '#993299' ], yAxis: { - height: config.chartHeight, width: config.columnWidth, borderRightWidth: 0.5, borderColor: 'lightgrey', diff --git a/components/chart/y-axis.js b/components/chart/y-axis.js index 5b78b36..e65449b 100644 --- a/components/chart/y-axis.js +++ b/components/chart/y-axis.js @@ -4,19 +4,18 @@ import config from '../../config' import styles from './styles' import { scaleObservable } from '../../local-storage' -export function makeYAxisLabels() { +export function makeYAxisLabels(chartHeight) { const units = config.temperatureScale.units const scaleMax = scaleObservable.value.max + const style = styles.yAxisLabel - return getTickPositions().map((y, i) => { - const style = styles.yAxisLabel + return getTickPositions(chartHeight).map((y, i) => { // this eyeballing is sadly necessary because RN does not // support percentage values for transforms, which we'd need // to reliably place the label vertically centered to the grid - style.top = y - 8 return ( {scaleMax - i * units} @@ -24,8 +23,8 @@ export function makeYAxisLabels() { }) } -export function makeHorizontalGrid() { - return getTickPositions().map(tick => { +export function makeHorizontalGrid(chartHeight) { + return getTickPositions(chartHeight).map(tick => { return ( { const value = Number(this.props.value) - console.log(value) if (isNaN(value)) return const scale = scaleObservable.value if (value < scale.min || value > scale.max) { diff --git a/config.js b/config.js index d44ba54..ffb8f60 100644 --- a/config.js +++ b/config.js @@ -1,6 +1,7 @@ const config = { - chartHeight: 350, columnWidth: 25, + columnHeightPercentage: 0.92, + xAxisHeightPercentage: 0.08, temperatureScale: { defaultLow: 35, defaultHigh: 38, @@ -10,9 +11,6 @@ const config = { } } -const margin = 3 -config.columnMiddle = config.columnWidth / 2, -config.dateRowY = config.chartHeight - 15 - margin -config.cycleDayNumberRowY = config.chartHeight - margin +config.columnMiddle = config.columnWidth / 2 export default config \ No newline at end of file diff --git a/styles/index.js b/styles/index.js index 43a5599..406de7a 100644 --- a/styles/index.js +++ b/styles/index.js @@ -92,16 +92,17 @@ export default StyleSheet.create({ }, header: { backgroundColor: primaryColor, - paddingVertical: 18, paddingHorizontal: 15, alignItems: 'center', - justifyContent: 'center' + justifyContent: 'center', + height: '10%' }, menu: { backgroundColor: primaryColor, alignItems: 'center', justifyContent: 'space-between', - flexDirection: 'row' + flexDirection: 'row', + height: '12%' }, menuItem: { alignItems: 'center', @@ -116,7 +117,8 @@ export default StyleSheet.create({ }, headerCycleDay: { flexDirection: 'row', - justifyContent: 'space-between' + justifyContent: 'space-between', + height: '15%' }, navigationArrow: { fontSize: 60, From c54581d6446a72633a0b9b95cbbeab1955da5242 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Fri, 24 Aug 2018 10:30:40 +0200 Subject: [PATCH 21/26] Introduce symptom row (WIP) --- components/chart/chart.js | 22 ++++++++++---- components/chart/day-column.js | 53 +++++++++++++++------------------- components/chart/y-axis.js | 33 ++++++++++++--------- config.js | 6 ++-- 4 files changed, 64 insertions(+), 50 deletions(-) diff --git a/components/chart/chart.js b/components/chart/chart.js index d8a9713..c56b77a 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -8,6 +8,7 @@ import DayColumn from './day-column' import { getCycleDay, cycleDaysSortedByDate, getAmountOfCycleDays } from '../../db' import styles from './styles' import { scaleObservable } from '../../local-storage' +import config from '../../config' export default class CycleChart extends Component { constructor(props) { @@ -70,9 +71,10 @@ export default class CycleChart extends Component { }, {}) const temp = symptoms.temperature + const columnHeight = this.state.chartHeight * config.columnHeightPercentage return { dateString, - y: temp ? normalizeToScale(temp, this.state.chartHeight) : null, + y: temp ? normalizeToScale(temp, columnHeight) : null, ...symptoms, ...getFhmAndLtlInfo(dateString, temp) } @@ -85,6 +87,12 @@ export default class CycleChart extends Component { } render() { + let columnHeight + let symptomRowHeight + if (this.state.chartHeight) { + columnHeight = this.state.chartHeight * config.columnHeightPercentage + symptomRowHeight = this.state.chartHeight * config.symptomRowHeightPercentage + } return ( Loading...} {this.state.chartHeight && - {makeYAxisLabels(this.state.chartHeight)} + {makeYAxisLabels(columnHeight)} } - {this.state.chartHeight && makeHorizontalGrid(this.state.chartHeight)} + {this.state.chartHeight && makeHorizontalGrid(columnHeight, symptomRowHeight)} {this.state.chartHeight && item.dateString} initialNumToRender={15} maxToRenderPerBatch={5} - > - + /> } ) diff --git a/components/chart/day-column.js b/components/chart/day-column.js index b6bf2d5..2f623a9 100644 --- a/components/chart/day-column.js +++ b/components/chart/day-column.js @@ -34,36 +34,11 @@ export default class DayColumn extends Component { rightY, rightTemperatureExclude, leftY, - leftTemperatureExclude + leftTemperatureExclude, + chartHeight } = this.props const columnElements = [] - if (typeof bleeding === 'number') { - columnElements.push( - - ) - } - - if (typeof mucus === 'number') { - const mucusIcon = ( - - ) - columnElements.push(mucusIcon) - } if(drawFhmLine) { const fhmLine = ( ) - const columnHeight = this.props.chartHeight * config.columnHeightPercentage - const xAxisHeight = this.props.chartHeight * config.xAxisHeightPercentage + const columnHeight = chartHeight * config.columnHeightPercentage + const xAxisHeight = chartHeight * config.xAxisHeightPercentage + const symptomHeight = chartHeight * config.symptomRowHeightPercentage const column = React.createElement( TouchableOpacity, @@ -132,7 +108,26 @@ export default class DayColumn extends Component { return ( + + {typeof mucus === 'number' && + + } + {typeof bleeding === 'number' && + + } + + {column} + {cycleDayLabel} {dateLabel} diff --git a/components/chart/y-axis.js b/components/chart/y-axis.js index e65449b..b215da0 100644 --- a/components/chart/y-axis.js +++ b/components/chart/y-axis.js @@ -4,15 +4,16 @@ import config from '../../config' import styles from './styles' import { scaleObservable } from '../../local-storage' -export function makeYAxisLabels(chartHeight) { +export function makeYAxisLabels(columnHeight) { const units = config.temperatureScale.units const scaleMax = scaleObservable.value.max const style = styles.yAxisLabel - return getTickPositions(chartHeight).map((y, i) => { + return getTickPositions(columnHeight).map((y, i) => { // this eyeballing is sadly necessary because RN does not // support percentage values for transforms, which we'd need // to reliably place the label vertically centered to the grid + if (scaleMax - i * units === 37) console.log(y) return ( { +export function makeHorizontalGrid(columnHeight, symptomRowHeight) { + return getTickPositions(columnHeight).map(tick => { return ( @@ -35,25 +36,31 @@ export function makeHorizontalGrid(chartHeight) { }) } -function getTickPositions(chartHeight) { +function getTickPositions(columnHeight) { const units = config.temperatureScale.units const scaleMin = scaleObservable.value.min const scaleMax = scaleObservable.value.max const numberOfTicks = (scaleMax - scaleMin) * (1 / units) + 1 - const columnHeight = chartHeight * config.columnHeightPercentage - const tickDistance = columnHeight / numberOfTicks + const tickDistance = 1 / (numberOfTicks - 1) const tickPositions = [] - const margin = tickDistance / 2 for (let i = 0; i < numberOfTicks; i++) { - tickPositions.push(tickDistance * i + margin) + const position = getAbsoluteValue(tickDistance * i, columnHeight) + tickPositions.push(position) } return tickPositions } -export function normalizeToScale(temp, chartHeight) { +export function normalizeToScale(temp, columnHeight) { const scale = scaleObservable.value const valueRelativeToScale = (scale.max - temp) / (scale.max - scale.min) - const scaleHeight = chartHeight * config.columnHeightPercentage - return scaleHeight * valueRelativeToScale + return getAbsoluteValue(valueRelativeToScale, columnHeight) +} + +function getAbsoluteValue(relative, columnHeight) { + // we add some height to have some breathing room + const verticalPadding = columnHeight * config.temperatureScale.verticalPadding + const scaleHeight = columnHeight - verticalPadding + return scaleHeight * relative + verticalPadding + } \ No newline at end of file diff --git a/config.js b/config.js index ffb8f60..772e828 100644 --- a/config.js +++ b/config.js @@ -1,13 +1,15 @@ const config = { columnWidth: 25, - columnHeightPercentage: 0.92, + columnHeightPercentage: 0.84, xAxisHeightPercentage: 0.08, + symptomRowHeightPercentage: 0.08, temperatureScale: { defaultLow: 35, defaultHigh: 38, min: 34, max: 40, - units: 0.1 + units: 0.1, + verticalPadding: 0.03 } } From f6607b98c75d40c3e6fc262f3e4ef78e982a8814 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Fri, 24 Aug 2018 19:20:40 +0200 Subject: [PATCH 22/26] Style symptom row --- components/chart/day-column.js | 2 +- components/chart/styles.js | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/components/chart/day-column.js b/components/chart/day-column.js index 2f623a9..c23da39 100644 --- a/components/chart/day-column.js +++ b/components/chart/day-column.js @@ -108,7 +108,7 @@ export default class DayColumn extends Component { return ( - + {typeof mucus === 'number' && Date: Sun, 26 Aug 2018 18:05:39 +0200 Subject: [PATCH 23/26] Use border style to draw fhm line --- components/chart/day-column.js | 32 ++++++++++++++++---------------- components/chart/styles.js | 1 - 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/components/chart/day-column.js b/components/chart/day-column.js index c23da39..268df06 100644 --- a/components/chart/day-column.js +++ b/components/chart/day-column.js @@ -38,19 +38,11 @@ export default class DayColumn extends Component { chartHeight } = this.props - const columnElements = [] + const columnHeight = chartHeight * config.columnHeightPercentage + const xAxisHeight = chartHeight * config.xAxisHeightPercentage + const symptomHeight = chartHeight * config.symptomRowHeightPercentage - if(drawFhmLine) { - const fhmLine = () - columnElements.push(fhmLine) - } + const columnElements = [] if(drawLtlAt) { const ltlLine = ( ) - const columnHeight = chartHeight * config.columnHeightPercentage - const xAxisHeight = chartHeight * config.xAxisHeightPercentage - const symptomHeight = chartHeight * config.symptomRowHeightPercentage + // we merge the colors here instead of from the stylesheet because of a RN + // bug that doesn't apply borderLeftColor otherwise + const customStyle = { + height: columnHeight, + borderLeftColor: 'grey', + borderRightColor: 'grey' + } + if (drawFhmLine) { + customStyle.borderLeftColor = styles.nfpLine.borderColor + customStyle.borderLeftWidth = 3 + } const column = React.createElement( TouchableOpacity, { - style: [styles.column.rect, {height: columnHeight}], + style: [styles.column.rect, customStyle], key: this.props.index.toString(), onPress: () => { this.passDateToDayView(dateString) diff --git a/components/chart/styles.js b/components/chart/styles.js index bfc3430..d7ab484 100644 --- a/components/chart/styles.js +++ b/components/chart/styles.js @@ -39,7 +39,6 @@ const styles = { rect: { width: config.columnWidth, borderStyle: 'solid', - borderColor: 'grey', borderLeftWidth: 0.5, borderRightWidth: 0.5, } From 2a07ce4ef2ce8d3a8eaf9586ff89bd6ee30bbc46 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Sun, 26 Aug 2018 18:28:59 +0200 Subject: [PATCH 24/26] Show loading message --- components/chart/chart.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/chart/chart.js b/components/chart/chart.js index c56b77a..0248979 100644 --- a/components/chart/chart.js +++ b/components/chart/chart.js @@ -98,8 +98,13 @@ export default class CycleChart extends Component { onLayout={this.onLayout} style={{ flexDirection: 'row', flex: 1 }} > - {!this.state.chartHeight && Loading...} - {this.state.chartHeight && + {!this.state.chartLoaded && + + Loading... + + } + + {this.state.chartHeight && this.state.chartLoaded && } - {this.state.chartHeight && makeHorizontalGrid(columnHeight, symptomRowHeight)} + {this.state.chartHeight && this.state.chartLoaded && makeHorizontalGrid(columnHeight, symptomRowHeight)} {this.state.chartHeight && item.dateString} initialNumToRender={15} maxToRenderPerBatch={5} + onLayout={() => this.setState({chartLoaded: true})} /> } From 8a6f943e5f7c93caf941cb0cc6b97f4d3b6ab2be Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Sun, 26 Aug 2018 19:34:52 +0200 Subject: [PATCH 25/26] Separate warning out of absolute range --- components/cycle-day/action-buttons.js | 48 -------------- components/cycle-day/labels/labels.js | 1 + .../symptoms/action-button-footer.js | 11 +++- components/cycle-day/symptoms/temperature.js | 64 +++++++++++++------ components/labels.js | 1 + 5 files changed, 55 insertions(+), 70 deletions(-) delete mode 100644 components/cycle-day/action-buttons.js diff --git a/components/cycle-day/action-buttons.js b/components/cycle-day/action-buttons.js deleted file mode 100644 index 9ddb036..0000000 --- a/components/cycle-day/action-buttons.js +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react' -import { - View, - Button, -} from 'react-native' -import { saveSymptom } from '../../db' - -const dayView = 'DayView' - -export default function (showView) { - return function ({ symptom, cycleDay, saveAction, saveDisabled}) { - const buttons = [ - { - title: 'Cancel', - action: () => showView(dayView) - }, - { - title: 'Delete', - action: () => { - saveSymptom(symptom, cycleDay) - showView(dayView) - } - }, { - title: 'Save', - action: async () => { - await saveAction() - showView(dayView) - }, - disabledCondition: saveDisabled - } - ] - - return buttons.map(({ title, action, disabledCondition }, i) => { - const style = { flex: 1, marginHorizontal: 10 } - if (i === 0) style.marginLeft = 0 - if (i === buttons.length - 1) style.marginRight = 0 - return ( - - - - ) - }) - } -} \ No newline at end of file diff --git a/components/cycle-day/labels/labels.js b/components/cycle-day/labels/labels.js index 910e6c9..6650e33 100644 --- a/components/cycle-day/labels/labels.js +++ b/components/cycle-day/labels/labels.js @@ -29,5 +29,6 @@ export const fertilityStatus = { export const temperature = { outOfRangeWarning: 'This temperature value is out of the current range for the temperature chart. You can change the range in the settings.', + outOfAbsoluteRangeWarning: 'This temperature value is too high or low to be shown on the temperature chart.', saveAnyway: 'Save anyway' } diff --git a/components/cycle-day/symptoms/action-button-footer.js b/components/cycle-day/symptoms/action-button-footer.js index a153496..dac39a6 100644 --- a/components/cycle-day/symptoms/action-button-footer.js +++ b/components/cycle-day/symptoms/action-button-footer.js @@ -8,7 +8,14 @@ import styles, {iconStyles} from '../../../styles' export default class ActionButtonFooter extends Component { render() { - const { symptom, cycleDay, saveAction, saveDisabled, navigate} = this.props + const { + symptom, + cycleDay, + saveAction, + saveDisabled, + navigate, + autoShowDayView = true} + = this.props const navigateToOverView = () => navigate('CycleDay', {cycleDay}) const buttons = [ { @@ -28,7 +35,7 @@ export default class ActionButtonFooter extends Component { title: 'Save', action: () => { saveAction() - navigateToOverView() + if (autoShowDayView) navigateToOverView() }, disabledCondition: saveDisabled, icon: 'content-save-outline' diff --git a/components/cycle-day/symptoms/temperature.js b/components/cycle-day/symptoms/temperature.js index fda5200..11ee7da 100644 --- a/components/cycle-day/symptoms/temperature.js +++ b/components/cycle-day/symptoms/temperature.js @@ -17,6 +17,7 @@ import { temperature as tempLabels } from '../labels/labels' import { scaleObservable } from '../../../local-storage' import { shared } from '../../labels' import ActionButtonFooter from './action-button-footer' +import config from '../../../config' const minutes = ChronoUnit.MINUTES @@ -49,6 +50,47 @@ export default class Temp extends Component { } } + saveTemperature = () => { + const dataToSave = { + value: Number(this.state.temperature), + exclude: this.state.exclude, + time: this.state.time + } + saveSymptom('temperature', this.cycleDay, dataToSave) + this.props.navigate('CycleDay', {cycleDay: this.cycleDay}) + } + + checkRangeAndSave = () => { + const value = Number(this.state.temperature) + + const absolute = { + min: config.temperatureScale.min, + max: config.temperatureScale.max + } + const scale = scaleObservable.value + let warningMsg + if (value < absolute.min || value > absolute.max) { + warningMsg = tempLabels.outOfAbsoluteRangeWarning + } else if (value < scale.min || value > scale.max) { + warningMsg = tempLabels.outOfRangeWarning + } + + if (warningMsg) { + Alert.alert( + shared.warning, + warningMsg, + [ + { text: shared.cancel }, + { text: shared.save, onPress: this.saveTemperature} + ] + ) + } else { + this.saveTemperature() + } + + } + + render() { return ( @@ -98,20 +140,14 @@ export default class Temp extends Component { { - const dataToSave = { - value: Number(this.state.temperature), - exclude: this.state.exclude, - time: this.state.time - } - saveSymptom('temperature', this.cycleDay, dataToSave) - }} + saveAction={() => this.checkRangeAndSave()} saveDisabled={ this.state.temperature === '' || isNaN(Number(this.state.temperature)) || isInvalidTime(this.state.time) } navigate={this.props.navigate} + autoShowDayView={false} /> ) @@ -119,18 +155,6 @@ export default class Temp extends Component { } class TempInput extends Component { - checkRange = () => { - const value = Number(this.props.value) - if (isNaN(value)) return - const scale = scaleObservable.value - if (value < scale.min || value > scale.max) { - Alert.alert( - shared.warning, - tempLabels.outOfRangeWarning, - ) - } - } - render() { const style = [styles.temperatureTextInput] if (this.props.isSuggestion) { diff --git a/components/labels.js b/components/labels.js index 28cd393..b249e37 100644 --- a/components/labels.js +++ b/components/labels.js @@ -1,5 +1,6 @@ export const shared = { cancel: 'Cancel', + save: 'Save', errorTitle: 'Error', successTitle: 'Success', warning: 'Warning' From 530c1096ed5025daaa04e8fc3d1b33fcc9b29cc7 Mon Sep 17 00:00:00 2001 From: Julia Friesel Date: Sun, 26 Aug 2018 19:56:26 +0200 Subject: [PATCH 26/26] Fix bottom scale margin --- components/chart/y-axis.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/chart/y-axis.js b/components/chart/y-axis.js index b215da0..27d1411 100644 --- a/components/chart/y-axis.js +++ b/components/chart/y-axis.js @@ -60,7 +60,9 @@ export function normalizeToScale(temp, columnHeight) { function getAbsoluteValue(relative, columnHeight) { // we add some height to have some breathing room const verticalPadding = columnHeight * config.temperatureScale.verticalPadding - const scaleHeight = columnHeight - verticalPadding + const scaleHeight = columnHeight - 2 * verticalPadding + console.log(scaleHeight) + console.log(columnHeight) return scaleHeight * relative + verticalPadding } \ No newline at end of file