Redesign chart
This commit is contained in:
committed by
Sofiya Tepikin
parent
550b1e6314
commit
ef16cfd041
@@ -1,32 +1,38 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { View } from 'react-native'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
|
||||
import AppText from '../common/app-text'
|
||||
import DripHomeIcon from '../../assets/drip-home-icons'
|
||||
|
||||
import styles from './styles'
|
||||
import { cycleDayColor } from '../../styles'
|
||||
|
||||
import { Typography } from '../../styles/redesign'
|
||||
import { CHART_YAXIS_WIDTH } from '../../config'
|
||||
import { shared as labels } from '../../i18n/en/labels'
|
||||
|
||||
const ChartLegend = ({ xAxisHeight }) => {
|
||||
const ChartLegend = ({ height }) => {
|
||||
return (
|
||||
<View style={[styles.yAxis, styles.chartLegend, {height: xAxisHeight}]}>
|
||||
<DripHomeIcon
|
||||
name="circle"
|
||||
size={styles.yAxis.width - 7}
|
||||
color={cycleDayColor}
|
||||
/>
|
||||
<AppText style={styles.yAxisLabels.dateLabel}>
|
||||
{labels.date.toLowerCase()}
|
||||
</AppText>
|
||||
<View style={[styles.container, { height }]}>
|
||||
<AppText style={styles.textBold}>#</AppText>
|
||||
<AppText style={styles.text}>{labels.date}</AppText>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
ChartLegend.propTypes = {
|
||||
xAxisHeight: PropTypes.number.isRequired
|
||||
height: PropTypes.number.isRequired
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
width: CHART_YAXIS_WIDTH
|
||||
},
|
||||
text: {
|
||||
...Typography.label
|
||||
},
|
||||
textBold: {
|
||||
...Typography.labelBold
|
||||
}
|
||||
})
|
||||
|
||||
export default ChartLegend
|
||||
|
||||
@@ -3,20 +3,16 @@ import PropTypes from 'prop-types'
|
||||
|
||||
import { Shape } from 'react-native/Libraries/ART/ReactNativeART'
|
||||
|
||||
import styles from './styles'
|
||||
import { Colors } from '../../styles/redesign'
|
||||
import { CHART_STROKE_WIDTH, CHART_GRID_LINE_HORIZONTAL_WIDTH } from '../../config'
|
||||
|
||||
const ChartLine = ({ path, isNfpLine = false }) => {
|
||||
const strokeStyle =
|
||||
isNfpLine ? styles.nfpLine.stroke : styles.column.stroke.color
|
||||
const strokeWidth =
|
||||
isNfpLine ? styles.nfpLine.strokeWidth : styles.column.stroke.width
|
||||
const ChartLine = ({ path, isNfpLine }) => {
|
||||
const color = isNfpLine ? Colors.orange : Colors.grey
|
||||
const width = isNfpLine
|
||||
? CHART_STROKE_WIDTH : CHART_GRID_LINE_HORIZONTAL_WIDTH
|
||||
|
||||
return (
|
||||
<Shape
|
||||
stroke={strokeStyle}
|
||||
strokeWidth={strokeWidth}
|
||||
d={path}
|
||||
/>
|
||||
<Shape d={path} stroke={color} strokeWidth={width} />
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,4 +21,8 @@ ChartLine.propTypes = {
|
||||
isNfpLine: PropTypes.bool,
|
||||
}
|
||||
|
||||
ChartLine.defaultProps = {
|
||||
isNfpLine: false
|
||||
}
|
||||
|
||||
export default ChartLine
|
||||
|
||||
+112
-60
@@ -1,26 +1,33 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { View, FlatList, ActivityIndicator } from 'react-native'
|
||||
import { ActivityIndicator, FlatList, StyleSheet, View } from 'react-native'
|
||||
|
||||
import NoData from './no-data'
|
||||
import AppLoadingView from '../common/app-loading'
|
||||
import YAxis from './y-axis'
|
||||
import nfpLines from './nfp-lines'
|
||||
import AppPage from '../common/app-page'
|
||||
import AppText from '../common/app-text'
|
||||
|
||||
import DayColumn from './day-column'
|
||||
import HorizontalGrid from './horizontal-grid'
|
||||
import AppText from '../common/app-text'
|
||||
import NoData from './no-data'
|
||||
import Tutorial from './tutorial'
|
||||
import YAxis from './y-axis'
|
||||
|
||||
import { connect } from 'react-redux'
|
||||
import { navigate } from '../../slices/navigation'
|
||||
|
||||
import { getCycleDaysSortedByDate } from '../../db'
|
||||
import nothingChanged from '../../db/db-unchanged'
|
||||
import { scaleObservable } from '../../local-storage'
|
||||
import { makeColumnInfo } from '../helpers/chart'
|
||||
import { getChartFlag, scaleObservable, setChartFlag } from '../../local-storage'
|
||||
import { makeColumnInfo, nfpLines } from '../helpers/chart'
|
||||
|
||||
import config from '../../config'
|
||||
import {
|
||||
CHART_COLUMN_WIDTH,
|
||||
SYMPTOMS,
|
||||
CHART_SYMPTOM_HEIGHT_RATIO,
|
||||
CHART_XAXIS_HEIGHT_RATIO
|
||||
} from '../../config'
|
||||
import { shared } from '../../i18n/en/labels'
|
||||
import styles from './styles'
|
||||
import { Colors, Spacing } from '../../styles/redesign'
|
||||
|
||||
class CycleChart extends Component {
|
||||
static propTypes = {
|
||||
@@ -36,11 +43,35 @@ class CycleChart extends Component {
|
||||
this.getFhmAndLtlInfo = nfpLines()
|
||||
this.shouldShowTemperatureColumn = false
|
||||
|
||||
this.checkShouldShowHint()
|
||||
this.prepareSymptomData()
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.cycleDaysSortedByDate.removeListener(this.handleDbChange)
|
||||
this.removeObvListener()
|
||||
}
|
||||
|
||||
checkShouldShowHint = async () => {
|
||||
const flag = await getChartFlag()
|
||||
const shouldShowHint = flag === 'true' ? true : false
|
||||
this.setState({ shouldShowHint })
|
||||
}
|
||||
|
||||
setShouldShowHint = async () => {
|
||||
await setChartFlag()
|
||||
this.setState({ shouldShowHint: false })
|
||||
}
|
||||
|
||||
onLayout = ({ nativeEvent }) => {
|
||||
if (this.state.chartHeight) return false
|
||||
|
||||
this.reCalculateChartInfo(nativeEvent)
|
||||
this.updateListeners(this.reCalculateChartInfo)
|
||||
}
|
||||
|
||||
prepareSymptomData = () => {
|
||||
this.symptomRowSymptoms = config.symptoms.filter((symptomName) => {
|
||||
this.symptomRowSymptoms = SYMPTOMS.filter((symptomName) => {
|
||||
return this.cycleDaysSortedByDate.some(cycleDay => {
|
||||
return cycleDay[symptomName]
|
||||
})
|
||||
@@ -71,33 +102,21 @@ class CycleChart extends Component {
|
||||
|
||||
reCalculateChartInfo = (nativeEvent) => {
|
||||
const { height, width } = nativeEvent.layout
|
||||
const xAxisCoefficient = this.shouldShowTemperatureColumn ?
|
||||
config.xAxisHeightPercentage : config.xAxisHeightPercentageLarge
|
||||
const symptomCoefficient = this.shouldShowTemperatureColumn ?
|
||||
config.symptomHeightPercentage : config.symptomHeightPercentageLarge
|
||||
|
||||
this.xAxisHeight = height * xAxisCoefficient
|
||||
this.xAxisHeight = height * CHART_XAXIS_HEIGHT_RATIO
|
||||
const remainingHeight = height - this.xAxisHeight
|
||||
this.symptomHeight = remainingHeight * symptomCoefficient
|
||||
this.symptomHeight = remainingHeight * CHART_SYMPTOM_HEIGHT_RATIO
|
||||
this.symptomRowHeight = this.symptomRowSymptoms.length *
|
||||
this.symptomHeight
|
||||
this.columnHeight = remainingHeight - this.symptomRowHeight
|
||||
const chartHeight = this.shouldShowTemperatureColumn ?
|
||||
height : (this.symptomRowHeight + this.xAxisHeight)
|
||||
|
||||
const numberOfColumnsToRender = Math.round(width / config.columnWidth)
|
||||
const numberOfColumnsToRender = Math.round(width / CHART_COLUMN_WIDTH)
|
||||
const columns = makeColumnInfo()
|
||||
|
||||
this.setState({ columns, chartHeight, numberOfColumnsToRender })
|
||||
}
|
||||
|
||||
onLayout = ({ nativeEvent }) => {
|
||||
if (this.state.chartHeight) return
|
||||
|
||||
this.reCalculateChartInfo(nativeEvent)
|
||||
this.updateListeners(this.reCalculateChartInfo)
|
||||
}
|
||||
|
||||
updateListeners(dataUpdateHandler) {
|
||||
// remove existing listeners
|
||||
if(this.handleDbChange) {
|
||||
@@ -114,38 +133,47 @@ class CycleChart extends Component {
|
||||
this.removeObvListener = scaleObservable(dataUpdateHandler, false)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.cycleDaysSortedByDate.removeListener(this.handleDbChange)
|
||||
this.removeObvListener()
|
||||
}
|
||||
|
||||
render() {
|
||||
const { chartHeight, chartLoaded, numberOfColumnsToRender } = this.state
|
||||
const shouldShowChart = this.chartSymptoms.length > 0 ? true : false
|
||||
const {
|
||||
chartHeight,
|
||||
chartLoaded,
|
||||
shouldShowHint,
|
||||
numberOfColumnsToRender
|
||||
} = this.state
|
||||
const hasDataToDisplay = this.chartSymptoms.length > 0
|
||||
|
||||
return (
|
||||
<View onLayout={this.onLayout} style={styles.container}>
|
||||
{!shouldShowChart && <NoData navigate={this.props.navigate}/>}
|
||||
{shouldShowChart && !chartHeight && !chartLoaded && <AppLoadingView />}
|
||||
<AppPage
|
||||
contentContainerStyle={styles.pageContainer}
|
||||
onLayout={this.onLayout}
|
||||
scrollViewStyle={styles.page}
|
||||
>
|
||||
{!hasDataToDisplay && <NoData />}
|
||||
{hasDataToDisplay && !chartHeight && !chartLoaded && <AppLoadingView />}
|
||||
<View style={styles.chartContainer}>
|
||||
{shouldShowChart && (
|
||||
{shouldShowHint && chartLoaded &&
|
||||
<Tutorial onClose={this.setShouldShowHint} />
|
||||
}
|
||||
{hasDataToDisplay && chartLoaded &&
|
||||
!this.shouldShowTemperatureColumn &&
|
||||
<View style={styles.centerItem}>
|
||||
<AppText style={styles.warning}>
|
||||
{shared.noTemperatureWarning}
|
||||
</AppText>
|
||||
</View>
|
||||
}
|
||||
{hasDataToDisplay && (
|
||||
<View style={styles.chartArea}>
|
||||
|
||||
{chartHeight && chartLoaded && (
|
||||
<React.Fragment>
|
||||
<YAxis
|
||||
height={this.columnHeight}
|
||||
symptomsToDisplay={this.symptomRowSymptoms}
|
||||
symptomsSectionHeight={this.symptomRowHeight}
|
||||
shouldShowTemperatureColumn=
|
||||
{this.shouldShowTemperatureColumn}
|
||||
xAxisHeight={this.xAxisHeight}
|
||||
/>
|
||||
{this.shouldShowTemperatureColumn && (<HorizontalGrid
|
||||
height={this.columnHeight}
|
||||
startPosition={this.symptomRowHeight}
|
||||
/>)}
|
||||
</React.Fragment>
|
||||
<YAxis
|
||||
height={this.columnHeight}
|
||||
symptomsToDisplay={this.symptomRowSymptoms}
|
||||
symptomsSectionHeight={this.symptomRowHeight}
|
||||
shouldShowTemperatureColumn=
|
||||
{this.shouldShowTemperatureColumn}
|
||||
xAxisHeight={this.xAxisHeight}
|
||||
/>
|
||||
)}
|
||||
|
||||
{chartHeight &&
|
||||
@@ -162,27 +190,28 @@ class CycleChart extends Component {
|
||||
onEndReached={() => this.setState({end: true})}
|
||||
ListFooterComponent={<LoadingMoreView end={this.state.end}/>}
|
||||
updateCellsBatchingPeriod={800}
|
||||
contentContainerStyle={{height: chartHeight}}
|
||||
contentContainerStyle={{ height: chartHeight }}
|
||||
/>
|
||||
}
|
||||
{chartHeight && chartLoaded && (
|
||||
<React.Fragment>
|
||||
{this.shouldShowTemperatureColumn &&
|
||||
<HorizontalGrid height={this.columnHeight} />
|
||||
}
|
||||
</React.Fragment>
|
||||
)}
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
{shouldShowChart && chartLoaded && !this.shouldShowTemperatureColumn
|
||||
&& (
|
||||
<View style={styles.centerItem}>
|
||||
<AppText style={{textAlign: 'center'}}>{shared.noTemperatureWarning}</AppText>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</AppPage>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function LoadingMoreView({ end }) {
|
||||
return (
|
||||
<View style={styles.loadingMore}>
|
||||
{!end && <ActivityIndicator size={'large'} color={'white'}/>}
|
||||
<View style={styles.loadingContainer}>
|
||||
{!end && <ActivityIndicator size={'large'} color={Colors.orange}/>}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -191,6 +220,29 @@ LoadingMoreView.propTypes = {
|
||||
end: PropTypes.bool
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
chartArea: {
|
||||
flexDirection: 'row'
|
||||
},
|
||||
chartContainer: {
|
||||
flexDirection: 'column'
|
||||
},
|
||||
loadingContainer: {
|
||||
height: '100%',
|
||||
backgroundColor: Colors.tourquiseLight,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
page: {
|
||||
marginVertical: Spacing.small
|
||||
},
|
||||
pageContainer: {
|
||||
paddingHorizontal: Spacing.base
|
||||
},
|
||||
warning: {
|
||||
padding: Spacing.large
|
||||
}
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return({
|
||||
navigate: (page) => dispatch(navigate(page)),
|
||||
|
||||
@@ -1,32 +1,33 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Text, View } from 'react-native'
|
||||
|
||||
import moment from 'moment'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import { LocalDate } from 'js-joda'
|
||||
import moment from 'moment'
|
||||
|
||||
import AppText from '../common/app-text'
|
||||
|
||||
import styles from './styles'
|
||||
import cycleModule from '../../lib/cycle'
|
||||
import { dateEnding } from '../helpers/home'
|
||||
import { Containers, Typography } from '../../styles/redesign'
|
||||
|
||||
const CycleDayLabel = ({ height, date }) => {
|
||||
const { label } = styles.column
|
||||
const dayDate = LocalDate.parse(date)
|
||||
const cycleDayNumber = cycleModule().getCycleDayNumber(date)
|
||||
|
||||
const isFirstDayOfMonth = dayDate.dayOfMonth() === 1
|
||||
const dateFormatting = isFirstDayOfMonth ? 'MMM' : 'Do'
|
||||
const dateFormatting = isFirstDayOfMonth ? 'MMM' : 'D'
|
||||
const shortDate = moment(date, "YYYY-MM-DD").format(dateFormatting)
|
||||
const boldDateLabel = isFirstDayOfMonth ? {fontWeight: 'bold'} : {}
|
||||
const ending = isFirstDayOfMonth ?
|
||||
'' : dateEnding[this.cycleDayNumber] || dateEnding['default']
|
||||
const cycleDayLabel = cycleDayNumber ? cycleDayNumber : ' '
|
||||
|
||||
return (
|
||||
<View style={[styles.chartLegend, { height }]}>
|
||||
<Text style={label.number}>
|
||||
{cycleDayNumber ? cycleDayNumber : ' '}
|
||||
</Text>
|
||||
<Text style={[label.date, boldDateLabel]}>
|
||||
{shortDate}
|
||||
</Text>
|
||||
<View style={[styles.container, { height }]}>
|
||||
<AppText style={styles.textBold}>{cycleDayLabel}</AppText>
|
||||
<View style={{flexDirection: 'row', justifyContent: 'space-around', alignItems: 'center'}}>
|
||||
<AppText style={styles.text}>{shortDate}</AppText>
|
||||
<AppText style={styles.textLight}>{ending}</AppText>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -36,4 +37,24 @@ CycleDayLabel.propTypes = {
|
||||
date: PropTypes.string,
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
alignItems: 'flex-start',
|
||||
justifyContent: 'flex-end',
|
||||
left: 4,
|
||||
},
|
||||
containerRow: {
|
||||
...Containers.rowContainer
|
||||
},
|
||||
text: {
|
||||
...Typography.label
|
||||
},
|
||||
textBold: {
|
||||
...Typography.labelBold
|
||||
},
|
||||
textLight: {
|
||||
...Typography.labelLight
|
||||
}
|
||||
})
|
||||
|
||||
export default CycleDayLabel
|
||||
|
||||
@@ -92,6 +92,18 @@ class DayColumn extends Component {
|
||||
activeOpacity={1}
|
||||
>
|
||||
|
||||
{shouldShowTemperatureColumn && <TemperatureColumn
|
||||
horizontalLinePosition={this.fhmAndLtl.drawLtlAt}
|
||||
isVerticalLine={this.fhmAndLtl.drawFhmLine}
|
||||
data={this.data && this.data.temperature}
|
||||
columnHeight={columnHeight}
|
||||
/>}
|
||||
|
||||
<CycleDayLabel
|
||||
height={xAxisHeight}
|
||||
date={dateString}
|
||||
/>
|
||||
|
||||
{ symptomRowSymptoms.map(symptom => {
|
||||
const hasSymptomData = this.data.hasOwnProperty(symptom)
|
||||
return (
|
||||
@@ -107,18 +119,6 @@ class DayColumn extends Component {
|
||||
}
|
||||
)}
|
||||
|
||||
{shouldShowTemperatureColumn && <TemperatureColumn
|
||||
horizontalLinePosition={this.fhmAndLtl.drawLtlAt}
|
||||
isVerticalLine={this.fhmAndLtl.drawFhmLine}
|
||||
data={this.data && this.data.temperature}
|
||||
columnHeight={columnHeight}
|
||||
/>}
|
||||
|
||||
<CycleDayLabel
|
||||
height={xAxisHeight}
|
||||
date={dateString}
|
||||
/>
|
||||
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,8 +2,14 @@ import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Path, Shape } from 'react-native/Libraries/ART/ReactNativeART'
|
||||
|
||||
import styles from './styles'
|
||||
import config from '../../config'
|
||||
import { Colors } from '../../styles/redesign'
|
||||
|
||||
import {
|
||||
CHART_COLUMN_WIDTH,
|
||||
CHART_COLUMN_MIDDLE,
|
||||
CHART_DOT_RADIUS,
|
||||
CHART_STROKE_WIDTH
|
||||
} from '../../config'
|
||||
|
||||
export default class DotAndLine extends Component {
|
||||
static propTypes = {
|
||||
@@ -20,48 +26,56 @@ export default class DotAndLine extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
const y = this.props.y
|
||||
const exclude = this.props.exclude
|
||||
let lineToRight
|
||||
let lineToLeft
|
||||
const {
|
||||
exclude,
|
||||
leftTemperatureExclude,
|
||||
leftY,
|
||||
rightTemperatureExclude,
|
||||
rightY,
|
||||
y
|
||||
} = this.props
|
||||
let excludeLeftLine, excludeRightLine, lineLeft, lineRight
|
||||
|
||||
if (this.props.leftY) {
|
||||
const middleY = ((this.props.leftY - y) / 2) + y
|
||||
const excludedLine = this.props.leftTemperatureExclude || exclude
|
||||
lineToLeft = makeLine(y, middleY, 0, excludedLine)
|
||||
if (leftY) {
|
||||
const middleY = ((leftY - y) / 2) + y
|
||||
excludeLeftLine = leftTemperatureExclude || exclude
|
||||
lineLeft = new Path()
|
||||
.moveTo(CHART_COLUMN_MIDDLE - CHART_DOT_RADIUS, y)
|
||||
.lineTo(0, middleY)
|
||||
}
|
||||
if (this.props.rightY) {
|
||||
const middleY = ((y - this.props.rightY) / 2) + this.props.rightY
|
||||
const excludedLine = this.props.rightTemperatureExclude || exclude
|
||||
lineToRight = makeLine(y, middleY, config.columnWidth, excludedLine)
|
||||
if (rightY) {
|
||||
const middleY = ((y - rightY) / 2) + rightY
|
||||
excludeRightLine = rightTemperatureExclude || exclude
|
||||
lineRight = new Path()
|
||||
.moveTo(CHART_COLUMN_MIDDLE + CHART_DOT_RADIUS, y)
|
||||
.lineTo(CHART_COLUMN_WIDTH, middleY)
|
||||
}
|
||||
|
||||
const dotStyle = exclude ? styles.curveDotsExcluded : styles.curveDots
|
||||
const radius = dotStyle.r
|
||||
const dot = (
|
||||
<Shape
|
||||
d={new Path()
|
||||
.moveTo(config.columnMiddle, y - radius)
|
||||
.arc(0, radius * 2, radius)
|
||||
.arc(0, radius * -2, radius)
|
||||
}
|
||||
fill={dotStyle.fill}
|
||||
key='dot'
|
||||
/>
|
||||
const dot = new Path().moveTo(CHART_COLUMN_MIDDLE , y - CHART_DOT_RADIUS)
|
||||
.arc(0, CHART_DOT_RADIUS * 2, CHART_DOT_RADIUS)
|
||||
.arc(0, CHART_DOT_RADIUS * -2, CHART_DOT_RADIUS)
|
||||
const dotColor = exclude ? Colors.tourquise : Colors.tourquiseDark
|
||||
const lineColorLeft = excludeLeftLine ?
|
||||
Colors.tourquise : Colors.tourquiseDark
|
||||
const lineColorRight = excludeRightLine ?
|
||||
Colors.tourquise : Colors.tourquiseDark
|
||||
|
||||
return(
|
||||
<React.Fragment>
|
||||
<Shape
|
||||
d={lineLeft}
|
||||
stroke={lineColorLeft}
|
||||
strokeWidth={CHART_STROKE_WIDTH}
|
||||
key={y}
|
||||
/>
|
||||
<Shape
|
||||
d={lineRight}
|
||||
stroke={lineColorRight}
|
||||
strokeWidth={CHART_STROKE_WIDTH}
|
||||
key={y + CHART_DOT_RADIUS}
|
||||
/>
|
||||
<Shape d={dot} stroke={dotColor} strokeWidth={CHART_STROKE_WIDTH} key='dot' />
|
||||
</React.Fragment>
|
||||
)
|
||||
return [lineToLeft, lineToRight, dot]
|
||||
}
|
||||
}
|
||||
|
||||
function makeLine(currY, middleY, x, excludeLine) {
|
||||
const lineStyle = excludeLine ? styles.curveExcluded : styles.curve
|
||||
|
||||
return <Shape
|
||||
stroke={lineStyle.stroke}
|
||||
d={new Path()
|
||||
.moveTo(config.columnMiddle, currY)
|
||||
.lineTo(x, middleY)
|
||||
}
|
||||
key={x.toString()}
|
||||
/>
|
||||
}
|
||||
@@ -1,26 +1,33 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { View } from 'react-native'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
|
||||
import { getTickPositions } from '../helpers/chart'
|
||||
|
||||
import styles from './styles'
|
||||
import { Colors } from '../../styles/redesign'
|
||||
import { CHART_GRID_LINE_HORIZONTAL_WIDTH, CHART_YAXIS_WIDTH } from '../../config'
|
||||
|
||||
const HorizontalGrid = ({ height, startPosition }) => {
|
||||
const HorizontalGrid = ({ height }) => {
|
||||
return getTickPositions(height).map(tick => {
|
||||
return (
|
||||
<View
|
||||
top={startPosition + tick}
|
||||
{...styles.horizontalGrid}
|
||||
key={tick}
|
||||
/>
|
||||
<View key={tick} top={tick} {...styles.line}/>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
HorizontalGrid.propTypes = {
|
||||
height: PropTypes.number,
|
||||
startPosition: PropTypes.number,
|
||||
height: PropTypes.number
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
line: {
|
||||
borderStyle: 'solid',
|
||||
borderBottomColor: Colors.grey,
|
||||
borderBottomWidth: CHART_GRID_LINE_HORIZONTAL_WIDTH,
|
||||
left: CHART_YAXIS_WIDTH,
|
||||
position:'absolute',
|
||||
right: 0
|
||||
}
|
||||
})
|
||||
|
||||
export default HorizontalGrid
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
import { getCycleStatusForDay } from '../../lib/sympto-adapter'
|
||||
import { normalizeToScale } from '../helpers/chart'
|
||||
|
||||
export default function () {
|
||||
const cycle = {
|
||||
status: null
|
||||
}
|
||||
|
||||
function updateCurrentCycle(dateString) {
|
||||
// for the NFP lines, we don't care about potentially extending the
|
||||
// preOvu phase, so we don't include all earlier cycles, as that is
|
||||
// an expensive db operation at the moment
|
||||
cycle.status = getCycleStatusForDay(
|
||||
dateString, { excludeEarlierCycles: true }
|
||||
)
|
||||
if(!cycle.status) {
|
||||
cycle.noMoreCycles = true
|
||||
return
|
||||
}
|
||||
if (cycle.status.phases.preOvulatory) {
|
||||
cycle.startDate = cycle.status.phases.preOvulatory.start.date
|
||||
} else {
|
||||
cycle.startDate = cycle.status.phases.periOvulatory.start.date
|
||||
}
|
||||
}
|
||||
|
||||
function dateIsInPeriOrPostPhase(dateString) {
|
||||
return (
|
||||
dateString >= cycle.status.phases.periOvulatory.start.date
|
||||
)
|
||||
}
|
||||
|
||||
function precededByAnotherTempValue(dateString) {
|
||||
return (
|
||||
// we are only interested in days that have a preceding
|
||||
// temp
|
||||
Object.keys(cycle.status.phases).some(phaseName => {
|
||||
return cycle.status.phases[phaseName].cycleDays.some(day => {
|
||||
return day.temperature && day.date < dateString
|
||||
})
|
||||
})
|
||||
// and also a following temp, so we don't draw the line
|
||||
// longer than necessary
|
||||
&&
|
||||
cycle.status.phases.postOvulatory.cycleDays.some(day => {
|
||||
return day.temperature && day.date > dateString
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
function isInTempMeasuringPhase(temperature, dateString) {
|
||||
return (
|
||||
temperature || precededByAnotherTempValue(dateString)
|
||||
)
|
||||
}
|
||||
|
||||
return function(dateString, temperature, columnHeight) {
|
||||
const ret = {
|
||||
drawLtlAt: null,
|
||||
drawFhmLine: false
|
||||
}
|
||||
if (!cycle.status && !cycle.noMoreCycles) updateCurrentCycle(dateString)
|
||||
if (cycle.noMoreCycles) return ret
|
||||
|
||||
if (dateString < cycle.startDate) updateCurrentCycle(dateString)
|
||||
if (cycle.noMoreCycles) return ret
|
||||
|
||||
const tempShift = cycle.status.temperatureShift
|
||||
|
||||
if (tempShift) {
|
||||
if (tempShift.firstHighMeasurementDay.date === dateString) {
|
||||
ret.drawFhmLine = true
|
||||
}
|
||||
|
||||
if (
|
||||
dateIsInPeriOrPostPhase(dateString) &&
|
||||
isInTempMeasuringPhase(temperature, dateString)
|
||||
) {
|
||||
ret.drawLtlAt = normalizeToScale(tempShift.ltl, columnHeight)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
}
|
||||
+28
-15
@@ -1,31 +1,44 @@
|
||||
import React from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import PropTypes from 'prop-types'
|
||||
import { View } from 'react-native'
|
||||
|
||||
import AppText from '../common/app-text'
|
||||
import SettingsButton from '../settings/shared/settings-button'
|
||||
import Button from '../common/button'
|
||||
|
||||
import { connect } from 'react-redux'
|
||||
import { navigate } from '../../slices/navigation'
|
||||
|
||||
import { Containers } from '../../styles/redesign'
|
||||
import { shared } from '../../i18n/en/labels'
|
||||
import styles from './styles'
|
||||
|
||||
const NoData = ({ navigate }) => {
|
||||
return (
|
||||
<View flex={1}>
|
||||
<View style={styles.centerItem}>
|
||||
<AppText>{shared.noDataWarning}</AppText>
|
||||
<SettingsButton
|
||||
onPress={() => {navigate('CycleDay')}}
|
||||
style={{marginHorizontal: 40}}
|
||||
>
|
||||
{shared.noDataButtonText}
|
||||
</SettingsButton>
|
||||
</View>
|
||||
<View style={styles.container}>
|
||||
<AppText>{shared.noDataWarning}</AppText>
|
||||
<Button isCTA onPress={() => {navigate('CycleDay')}}>
|
||||
{shared.noDataButtonText}
|
||||
</Button>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
NoData.propTypes = {
|
||||
navigate: PropTypes.func,
|
||||
navigate: PropTypes.func.isRequired,
|
||||
}
|
||||
|
||||
export default NoData
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
...Containers.centerItems
|
||||
}
|
||||
})
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return({
|
||||
navigate: (page) => dispatch(navigate(page)),
|
||||
})
|
||||
}
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
mapDispatchToProps,
|
||||
)(NoData)
|
||||
@@ -1,174 +0,0 @@
|
||||
import config from '../../config'
|
||||
import { shadesOfRed, cycleDayColor } from '../../styles/index'
|
||||
|
||||
const colorTemperature = '#765285'
|
||||
const colorTemperatureLight = '#a67fb5'
|
||||
export const dotRadius = 5
|
||||
const lineWidth = 1.5
|
||||
const colorLtl = '#feb47b'
|
||||
const gridColor = '#d3d3d3'
|
||||
const gridLineWidthVertical = 0.6
|
||||
const gridLineWidthHorizontal = 0.3
|
||||
const numberLabelFontSize = 13
|
||||
|
||||
const redColor = '#c3000d'
|
||||
const violetColor = '#6a7b98'
|
||||
const shadesOfViolet = ['#e3e7ed', '#c8cfdc', '#acb8cb', '#91a0ba', '#7689a9', violetColor] // light to dark
|
||||
const yellowColor = '#dbb40c'
|
||||
const shadesOfYellow = ['#f0e19d', '#e9d26d', '#e2c33c', yellowColor] // light to dark
|
||||
const magentaColor = '#6f2565'
|
||||
const shadesOfMagenta = ['#a87ca2', '#8b5083', magentaColor] // light to dark
|
||||
const pinkColor = '#9e346c'
|
||||
const shadesOfPink = ['#c485a6', '#b15c89', pinkColor] // light to dark
|
||||
const lightGreenColor = '#bccd67'
|
||||
const orangeColor = '#bc6642'
|
||||
const mintColor = '#6ca299'
|
||||
|
||||
const styles = {
|
||||
container: { flex: 1 },
|
||||
chartContainer: { flexDirection: 'column' },
|
||||
chartArea: { flexDirection: 'row' },
|
||||
centerItem: {
|
||||
flex:1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginHorizontal: 25,
|
||||
},
|
||||
curve: {
|
||||
stroke: colorTemperature,
|
||||
strokeWidth: lineWidth,
|
||||
},
|
||||
curveExcluded: {
|
||||
stroke: colorTemperatureLight,
|
||||
strokeWidth: lineWidth
|
||||
},
|
||||
curveDots: {
|
||||
fill: colorTemperature,
|
||||
r: dotRadius
|
||||
},
|
||||
curveDotsExcluded: {
|
||||
fill: colorTemperatureLight,
|
||||
r: dotRadius
|
||||
},
|
||||
column: {
|
||||
label: {
|
||||
date: {
|
||||
color: 'grey',
|
||||
fontSize: 9,
|
||||
fontWeight: '100',
|
||||
textAlign: 'center',
|
||||
paddingTop: 2.5
|
||||
},
|
||||
number: {
|
||||
color: cycleDayColor,
|
||||
fontSize: numberLabelFontSize,
|
||||
textAlign: 'center',
|
||||
}
|
||||
},
|
||||
stroke: {
|
||||
color: gridColor,
|
||||
width: gridLineWidthVertical,
|
||||
}
|
||||
},
|
||||
symptomDot: {
|
||||
width: 12,
|
||||
height: 12,
|
||||
borderRadius: 50,
|
||||
},
|
||||
iconColors: {
|
||||
'bleeding': {
|
||||
color: redColor,
|
||||
shades: shadesOfRed,
|
||||
},
|
||||
'mucus': {
|
||||
color: violetColor,
|
||||
shades: shadesOfViolet,
|
||||
},
|
||||
'cervix': {
|
||||
color: yellowColor,
|
||||
shades: shadesOfYellow,
|
||||
},
|
||||
'sex': {
|
||||
color: magentaColor,
|
||||
shades: shadesOfMagenta,
|
||||
},
|
||||
'desire': {
|
||||
color: pinkColor,
|
||||
shades: shadesOfPink,
|
||||
},
|
||||
'pain': {
|
||||
color: lightGreenColor,
|
||||
shades: [lightGreenColor],
|
||||
},
|
||||
'mood': {
|
||||
color: orangeColor,
|
||||
shades: [orangeColor],
|
||||
},
|
||||
'note': {
|
||||
color: mintColor,
|
||||
shades: [mintColor],
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
width: 27,
|
||||
borderRightWidth: 1,
|
||||
borderColor: 'lightgrey',
|
||||
borderStyle: 'solid'
|
||||
},
|
||||
yAxisLabels: {
|
||||
tempScale: {
|
||||
position: 'absolute',
|
||||
right: 2,
|
||||
color: 'grey',
|
||||
fontSize: 9,
|
||||
textAlign: 'left'
|
||||
},
|
||||
cycleDayLabel: {
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: Math.ceil(numberLabelFontSize / 2)
|
||||
},
|
||||
dateLabel: {
|
||||
textAlign: 'center',
|
||||
justifyContent: 'center',
|
||||
color: 'grey',
|
||||
fontSize: 9,
|
||||
fontWeight: '100',
|
||||
}
|
||||
},
|
||||
symptomIcon: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
chartLegend: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
boldTick: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: 11,
|
||||
},
|
||||
horizontalGrid: {
|
||||
position:'absolute',
|
||||
borderStyle: 'solid',
|
||||
borderBottomColor: gridColor,
|
||||
borderBottomWidth: gridLineWidthHorizontal,
|
||||
width: '100%',
|
||||
left: config.columnWidth
|
||||
},
|
||||
nfpLine: {
|
||||
stroke: colorLtl,
|
||||
strokeWidth: lineWidth,
|
||||
},
|
||||
symptomRow: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
loadingMore: {
|
||||
height: '100%',
|
||||
backgroundColor: 'lightgrey',
|
||||
justifyContent: 'center'
|
||||
}
|
||||
}
|
||||
|
||||
export default styles
|
||||
@@ -1,9 +1,13 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { View } from 'react-native'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
|
||||
import styles from './styles'
|
||||
import config from '../../config'
|
||||
import { Colors, Containers } from '../../styles/redesign'
|
||||
import {
|
||||
CHART_COLUMN_WIDTH,
|
||||
CHART_DOT_RADIUS,
|
||||
CHART_GRID_LINE_HORIZONTAL_WIDTH
|
||||
} from '../../config'
|
||||
|
||||
const SymptomCell = ({
|
||||
height,
|
||||
@@ -13,29 +17,23 @@ const SymptomCell = ({
|
||||
}) => {
|
||||
|
||||
const shouldDrawDot = symptomValue !== false
|
||||
const styleParent = [styles.symptomRow, { height, width: config.columnWidth }]
|
||||
let styleChild
|
||||
const styleCell = [styles.cell, { height, width: CHART_COLUMN_WIDTH }]
|
||||
let styleDot
|
||||
|
||||
if (shouldDrawDot) {
|
||||
const styleSymptom = styles.iconColors[symptom]
|
||||
const styleSymptom = Colors.iconColors[symptom]
|
||||
const symptomColor = styleSymptom.shades[symptomValue]
|
||||
|
||||
const isMucusOrCervix = (symptom === 'mucus') || (symptom === 'cervix')
|
||||
|
||||
const backgroundColor = (isMucusOrCervix && !isSymptomDataComplete) ?
|
||||
'white' : symptomColor
|
||||
const borderWidth = (isMucusOrCervix && !isSymptomDataComplete) ? 2 : 0
|
||||
const borderColor = symptomColor
|
||||
styleChild = [styles.symptomDot, {
|
||||
backgroundColor,
|
||||
borderColor,
|
||||
borderWidth
|
||||
}]
|
||||
styleDot = [styles.dot, { backgroundColor, borderColor, borderWidth }]
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styleParent} key={symptom}>
|
||||
{shouldDrawDot && <View style={styleChild} />}
|
||||
<View style={styleCell} key={symptom}>
|
||||
{shouldDrawDot && <View style={styleDot} />}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -50,4 +48,17 @@ SymptomCell.propTypes = {
|
||||
isSymptomDataComplete: PropTypes.bool,
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
cell: {
|
||||
backgroundColor: 'white',
|
||||
borderColor: Colors.greyLight,
|
||||
borderWidth: CHART_GRID_LINE_HORIZONTAL_WIDTH,
|
||||
...Containers.centerItems
|
||||
},
|
||||
dot: {
|
||||
width: CHART_DOT_RADIUS * 2,
|
||||
height: CHART_DOT_RADIUS * 2,
|
||||
borderRadius: 50
|
||||
}
|
||||
})
|
||||
export default SymptomCell
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { View } from 'react-native'
|
||||
import { StyleSheet , View } from 'react-native'
|
||||
|
||||
import DripIcon from '../../assets/drip-icons'
|
||||
|
||||
import styles from './styles'
|
||||
import { Colors, Containers } from '../../styles/redesign'
|
||||
import { CHART_YAXIS_WIDTH, CHART_ICON_SIZE } from '../../config'
|
||||
|
||||
const SymptomIcon = ({ symptom, height }) => {
|
||||
return (
|
||||
<View style={styles.symptomIcon} width={styles.yAxis.width} height={height}>
|
||||
<View style={styles.container} width={CHART_YAXIS_WIDTH} height={height}>
|
||||
<DripIcon
|
||||
size={16}
|
||||
size={CHART_ICON_SIZE}
|
||||
name={`drip-icon-${symptom}`}
|
||||
color={styles.iconColors[symptom].color}
|
||||
color={Colors.iconColors[symptom].color}
|
||||
/>
|
||||
</View>
|
||||
)
|
||||
@@ -23,4 +24,10 @@ SymptomIcon.propTypes = {
|
||||
symptom: PropTypes.string,
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
...Containers.centerItems
|
||||
}
|
||||
})
|
||||
|
||||
export default SymptomIcon
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { StyleSheet } from 'react-native'
|
||||
|
||||
import { Surface , Path } from 'react-native/Libraries/ART/ReactNativeART'
|
||||
|
||||
import ChartLine from './chart-line'
|
||||
import DotAndLine from './dot-and-line'
|
||||
|
||||
import styles from './styles'
|
||||
import config from '../../config'
|
||||
import { CHART_COLUMN_WIDTH, CHART_STROKE_WIDTH } from '../../config'
|
||||
|
||||
const TemperatureColumn = ({
|
||||
horizontalLinePosition,
|
||||
@@ -15,20 +15,21 @@ const TemperatureColumn = ({
|
||||
data,
|
||||
columnHeight
|
||||
}) => {
|
||||
|
||||
const x = styles.nfpLine.strokeWidth / 2
|
||||
const x = CHART_STROKE_WIDTH / 2
|
||||
|
||||
return (
|
||||
<Surface width={config.columnWidth} height={columnHeight}>
|
||||
<Surface
|
||||
width={CHART_COLUMN_WIDTH}
|
||||
height={columnHeight}
|
||||
style={styles.container}
|
||||
>
|
||||
|
||||
<ChartLine
|
||||
path={new Path().lineTo(0, columnHeight)}
|
||||
/>
|
||||
<ChartLine path={new Path().lineTo(0, columnHeight)}/>
|
||||
|
||||
{horizontalLinePosition && <ChartLine
|
||||
path={new Path()
|
||||
.moveTo(0, horizontalLinePosition)
|
||||
.lineTo(config.columnWidth, horizontalLinePosition)
|
||||
.lineTo(CHART_COLUMN_WIDTH, horizontalLinePosition)
|
||||
}
|
||||
isNfpLine={true}
|
||||
key='ltl'
|
||||
@@ -61,4 +62,10 @@ TemperatureColumn.propTypes = {
|
||||
columnHeight: PropTypes.number,
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: 'white'
|
||||
}
|
||||
})
|
||||
|
||||
export default TemperatureColumn
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { View } from 'react-native'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
|
||||
import Tick from './tick'
|
||||
|
||||
import { getTickList } from '../helpers/chart'
|
||||
|
||||
import styles from './styles'
|
||||
|
||||
const TickList = ({ height }) => {
|
||||
|
||||
return (
|
||||
<View style={[styles.yAxis, { height }]}>{
|
||||
getTickList(height)
|
||||
.map(({ label, position, isBold, shouldShowLabel}) => {
|
||||
return (
|
||||
<Tick
|
||||
key={label}
|
||||
yPosition={position}
|
||||
isBold={isBold}
|
||||
shouldShowLabel={shouldShowLabel}
|
||||
label={label}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}</View>
|
||||
<View style={[styles.container, height]}>
|
||||
{
|
||||
getTickList(height)
|
||||
.map(({ isBold, label, position, shouldShowLabel, tickHeight}) => {
|
||||
return (
|
||||
<Tick
|
||||
height={tickHeight}
|
||||
isBold={isBold}
|
||||
key={label}
|
||||
label={label}
|
||||
shouldShowLabel={shouldShowLabel}
|
||||
yPosition={position}
|
||||
/>
|
||||
)
|
||||
})
|
||||
}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -31,4 +33,10 @@ TickList.propTypes = {
|
||||
height: PropTypes.number,
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1
|
||||
}
|
||||
})
|
||||
|
||||
export default TickList
|
||||
|
||||
+36
-12
@@ -1,29 +1,53 @@
|
||||
import React from 'react'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import AppText from '../common/app-text'
|
||||
|
||||
import styles from './styles'
|
||||
import { Sizes } from '../../styles/redesign'
|
||||
|
||||
const Tick = ({ yPosition, isBold, shouldShowLabel, label }) => {
|
||||
// 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
|
||||
const topPosition = yPosition - 8
|
||||
const style = [
|
||||
styles.yAxisLabels.tempScale,
|
||||
{top: topPosition},
|
||||
isBold && styles.boldTick
|
||||
]
|
||||
const Tick = ({ yPosition, height, isBold, shouldShowLabel, label }) => {
|
||||
const top = yPosition - height / 2
|
||||
const containerStyle = [ styles.container, { flexBasis: height, height, top }]
|
||||
const textStyle = isBold ? styles.textBold : styles.textNormal
|
||||
|
||||
return <AppText style={style}>{shouldShowLabel && label}</AppText>
|
||||
return(
|
||||
<View style={containerStyle}>
|
||||
<AppText style={textStyle}>{shouldShowLabel && label}</AppText>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
Tick.propTypes = {
|
||||
yPosition: PropTypes.number,
|
||||
height: PropTypes.number.isRequired,
|
||||
isBold: PropTypes.bool,
|
||||
shouldShowLabel: PropTypes.bool,
|
||||
label: PropTypes.string,
|
||||
}
|
||||
|
||||
|
||||
const text = {
|
||||
right: 4,
|
||||
lineHeight: Sizes.base,
|
||||
textAlign: 'right',
|
||||
textAlignVertical: 'center'
|
||||
}
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
position: 'absolute',
|
||||
right: 0,
|
||||
width: 40
|
||||
},
|
||||
textBold: {
|
||||
fontSize: Sizes.base,
|
||||
fontWeight: 'bold',
|
||||
...text
|
||||
},
|
||||
textNormal: {
|
||||
fontSize: Sizes.small,
|
||||
...text
|
||||
}
|
||||
})
|
||||
|
||||
export default Tick
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { Image, StyleSheet, TouchableOpacity, View } from 'react-native'
|
||||
|
||||
import AppIcon from '../common/app-icon'
|
||||
import AppText from '../common/app-text'
|
||||
|
||||
import { Colors, Containers, Sizes, Spacing } from '../../styles/redesign'
|
||||
import { chart } from '../../i18n/en/labels'
|
||||
|
||||
const image = require('../../assets/swipe.png')
|
||||
|
||||
const Tutorial = ({ onClose }) => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Image resizeMode='contain' source={image} style={styles.image} />
|
||||
<View style={styles.textContainer}>
|
||||
<AppText>{chart.tutorial}</AppText>
|
||||
</View>
|
||||
<TouchableOpacity onPress={onClose} style={styles.iconContainer}>
|
||||
<AppIcon name='cross' color={Colors.orange} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
Tutorial.propTypes = {
|
||||
onClose: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
...Containers.rowContainer,
|
||||
padding: Spacing.large
|
||||
},
|
||||
iconContainer: {
|
||||
alignSelf: 'flex-start',
|
||||
marginBottom: Sizes.base
|
||||
},
|
||||
image: {
|
||||
height: 40
|
||||
},
|
||||
textContainer: {
|
||||
width: '70%'
|
||||
}
|
||||
})
|
||||
|
||||
export default Tutorial
|
||||
@@ -1,12 +1,12 @@
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { View } from 'react-native'
|
||||
import { StyleSheet, View } from 'react-native'
|
||||
|
||||
import SymptomIcon from './symptom-icon'
|
||||
import TickList from './tick-list'
|
||||
import ChartLegend from './chart-legend'
|
||||
|
||||
import styles from './styles'
|
||||
import { CHART_YAXIS_WIDTH } from '../../config'
|
||||
|
||||
const YAxis = ({
|
||||
height,
|
||||
@@ -19,6 +19,8 @@ const YAxis = ({
|
||||
|
||||
return (
|
||||
<View>
|
||||
{shouldShowTemperatureColumn && <TickList height={height} />}
|
||||
<ChartLegend height={xAxisHeight} />
|
||||
<View style={[styles.yAxis, {height: symptomsSectionHeight}]}>
|
||||
{symptomsToDisplay.map(symptom => (
|
||||
<SymptomIcon
|
||||
@@ -29,8 +31,6 @@ const YAxis = ({
|
||||
)
|
||||
)}
|
||||
</View>
|
||||
{shouldShowTemperatureColumn && <TickList height={height} />}
|
||||
<ChartLegend xAxisHeight={xAxisHeight} />
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -43,4 +43,10 @@ YAxis.propTypes = {
|
||||
xAxisHeight: PropTypes.number.isRequired
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
yAxis: {
|
||||
width: CHART_YAXIS_WIDTH
|
||||
}
|
||||
})
|
||||
|
||||
export default YAxis
|
||||
|
||||
Reference in New Issue
Block a user