Chore/make function components 5

This commit is contained in:
Sofiya Tepikin
2022-09-12 11:04:20 +00:00
parent c8d2f5d9ee
commit 92236dfc8a
5 changed files with 163 additions and 202 deletions
+83 -199
View File
@@ -1,32 +1,20 @@
import React, { Component } from 'react' import React, { useEffect, useState } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { import { Dimensions, PixelRatio, StyleSheet, View } from 'react-native'
ActivityIndicator,
Dimensions,
FlatList,
PixelRatio,
StyleSheet,
View,
} from 'react-native'
import AppLoadingView from '../common/app-loading'
import AppPage from '../common/app-page' import AppPage from '../common/app-page'
import AppText from '../common/app-text'
import DayColumn from './day-column' import DayColumn from './day-column'
import HorizontalGrid from './horizontal-grid' import HorizontalGrid from './horizontal-grid'
import MainGrid from './main-grid'
import NoData from './no-data' import NoData from './no-data'
import NoTemperature from './no-temperature'
import Tutorial from './tutorial' import Tutorial from './tutorial'
import YAxis from './y-axis' import YAxis from './y-axis'
import { getCycleDaysSortedByDate } from '../../db' import { getCycleDaysSortedByDate } from '../../db'
import nothingChanged from '../../db/db-unchanged' import { getChartFlag, setChartFlag } from '../../local-storage'
import { import { makeColumnInfo } from '../helpers/chart'
getChartFlag,
scaleObservable,
setChartFlag,
} from '../../local-storage'
import { makeColumnInfo, nfpLines } from '../helpers/chart'
import { import {
CHART_COLUMN_WIDTH, CHART_COLUMN_WIDTH,
@@ -35,204 +23,108 @@ import {
CHART_XAXIS_HEIGHT_RATIO, CHART_XAXIS_HEIGHT_RATIO,
SYMPTOMS, SYMPTOMS,
} from '../../config' } from '../../config'
import { shared } from '../../i18n/en/labels' import { Spacing } from '../../styles'
import { Colors, Spacing } from '../../styles'
class CycleChart extends Component { const getSymptomsFromCycleDays = (cycleDays) =>
static propTypes = { SYMPTOMS.filter((symptom) => cycleDays.some((cycleDay) => cycleDay[symptom]))
navigate: PropTypes.func,
end: PropTypes.bool,
setDate: PropTypes.func,
}
constructor(props) { const CycleChart = ({ navigate, setDate }) => {
super(props) const [shouldShowHint, setShouldShowHint] = useState(true)
this.state = {} useEffect(async () => {
this.cycleDaysSortedByDate = getCycleDaysSortedByDate()
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 flag = await getChartFlag()
const shouldShowHint = flag === 'true' ? true : false setShouldShowHint(flag === 'true')
this.setState({ shouldShowHint }) }, [])
const hideHint = () => {
setShouldShowHint(false)
setChartFlag()
} }
setShouldShowHint = async () => { const cycleDaysSortedByDate = getCycleDaysSortedByDate()
await setChartFlag()
this.setState({ shouldShowHint: false })
}
onLayout = () => { const chartSymptoms = getSymptomsFromCycleDays(cycleDaysSortedByDate)
if (this.state.chartHeight) return false const symptomRowSymptoms = chartSymptoms.filter(
(symptom) => symptom !== 'temperature'
)
this.reCalculateChartInfo() const shouldShowTemperatureColumn = chartSymptoms.indexOf('temperature') > -1
this.updateListeners(this.reCalculateChartInfo)
}
prepareSymptomData = () => { const { width, height } = Dimensions.get('window')
this.symptomRowSymptoms = SYMPTOMS.filter((symptomName) => { const numberOfColumnsToRender = Math.round(width / CHART_COLUMN_WIDTH)
return this.cycleDaysSortedByDate.some((cycleDay) => {
return symptomName !== 'temperature' && cycleDay[symptomName]
})
})
this.chartSymptoms = [...this.symptomRowSymptoms]
if (this.cycleDaysSortedByDate.some((day) => day.temperature)) {
this.chartSymptoms.push('temperature')
this.shouldShowTemperatureColumn = true
}
}
renderColumn = ({ item, index }) => { const xAxisHeight = height * 0.7 * CHART_XAXIS_HEIGHT_RATIO
const remainingHeight = height * 0.7 - xAxisHeight
const symptomHeight = PixelRatio.roundToNearestPixel(
remainingHeight * CHART_SYMPTOM_HEIGHT_RATIO
)
const symptomRowHeight =
PixelRatio.roundToNearestPixel(symptomRowSymptoms.length * symptomHeight) +
CHART_GRID_LINE_HORIZONTAL_WIDTH
const columnHeight = remainingHeight - symptomRowHeight
const chartHeight = shouldShowTemperatureColumn
? height * 0.7
: symptomRowHeight + xAxisHeight
const columns = makeColumnInfo()
const renderColumn = ({ item }) => {
return ( return (
<DayColumn <DayColumn
setDate={this.props.setDate} setDate={setDate}
dateString={item} dateString={item}
index={index} navigate={navigate}
navigate={this.props.navigate} symptomHeight={symptomHeight}
symptomHeight={this.symptomHeight} columnHeight={columnHeight}
columnHeight={this.columnHeight} symptomRowSymptoms={symptomRowSymptoms}
symptomRowSymptoms={this.symptomRowSymptoms} chartSymptoms={chartSymptoms}
chartSymptoms={this.chartSymptoms} shouldShowTemperatureColumn={shouldShowTemperatureColumn}
shouldShowTemperatureColumn={this.shouldShowTemperatureColumn} xAxisHeight={xAxisHeight}
getFhmAndLtlInfo={this.getFhmAndLtlInfo}
xAxisHeight={this.xAxisHeight}
/> />
) )
} }
reCalculateChartInfo = () => { const hasDataToDisplay = chartSymptoms.length > 0
const { width, height } = Dimensions.get('window')
this.xAxisHeight = height * 0.7 * CHART_XAXIS_HEIGHT_RATIO if (!hasDataToDisplay) {
const remainingHeight = height * 0.7 - this.xAxisHeight return <NoData navigate={navigate} />
this.symptomHeight = PixelRatio.roundToNearestPixel(
remainingHeight * CHART_SYMPTOM_HEIGHT_RATIO
)
this.symptomRowHeight =
PixelRatio.roundToNearestPixel(
this.symptomRowSymptoms.length * this.symptomHeight
) + CHART_GRID_LINE_HORIZONTAL_WIDTH
this.columnHeight = remainingHeight - this.symptomRowHeight
const chartHeight = this.shouldShowTemperatureColumn
? height * 0.7
: this.symptomRowHeight + this.xAxisHeight
const numberOfColumnsToRender = Math.round(width / CHART_COLUMN_WIDTH)
const columns = makeColumnInfo()
this.setState({ columns, chartHeight, numberOfColumnsToRender })
} }
updateListeners(dataUpdateHandler) { return (
// remove existing listeners <AppPage
if (this.handleDbChange) { contentContainerStyle={styles.pageContainer}
this.cycleDaysSortedByDate.removeListener(this.handleDbChange) scrollViewStyle={styles.page}
} >
if (this.removeObvListener) this.removeObvListener() <View style={styles.chartContainer}>
{shouldShowHint && <Tutorial onClose={hideHint} />}
this.handleDbChange = (_, changes) => { {!shouldShowTemperatureColumn && <NoTemperature />}
if (nothingChanged(changes)) return <View style={styles.chartArea}>
dataUpdateHandler() <YAxis
} height={columnHeight}
symptomsToDisplay={symptomRowSymptoms}
this.cycleDaysSortedByDate.addListener(this.handleDbChange) symptomsSectionHeight={symptomRowHeight}
this.removeObvListener = scaleObservable(dataUpdateHandler, false) shouldShowTemperatureColumn={shouldShowTemperatureColumn}
} xAxisHeight={xAxisHeight}
/>
render() { <MainGrid
const { data={columns}
chartHeight, renderItem={renderColumn}
chartLoaded, initialNumToRender={numberOfColumnsToRender}
shouldShowHint, contentContainerStyle={{ height: chartHeight }}
numberOfColumnsToRender, />
} = this.state {shouldShowTemperatureColumn && (
const hasDataToDisplay = this.chartSymptoms.length > 0 <HorizontalGrid height={columnHeight} />
return (
<AppPage
contentContainerStyle={styles.pageContainer}
onLayout={this.onLayout}
scrollViewStyle={styles.page}
>
{!hasDataToDisplay && <NoData navigate={this.props.navigate} />}
{hasDataToDisplay && !chartHeight && !chartLoaded && <AppLoadingView />}
<View style={styles.chartContainer}>
{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 && (
<YAxis
height={this.columnHeight}
symptomsToDisplay={this.symptomRowSymptoms}
symptomsSectionHeight={this.symptomRowHeight}
shouldShowTemperatureColumn={this.shouldShowTemperatureColumn}
xAxisHeight={this.xAxisHeight}
/>
)}
{chartHeight && (
<FlatList
horizontal={true}
inverted={true}
showsHorizontalScrollIndicator={false}
data={this.state.columns}
renderItem={this.renderColumn}
keyExtractor={(item) => item}
initialNumToRender={numberOfColumnsToRender}
windowSize={30}
onLayout={() => this.setState({ chartLoaded: true })}
onEndReached={() => this.setState({ end: true })}
ListFooterComponent={<LoadingMoreView end={this.state.end} />}
updateCellsBatchingPeriod={800}
contentContainerStyle={{ height: chartHeight }}
/>
)}
{chartHeight && chartLoaded && (
<React.Fragment>
{this.shouldShowTemperatureColumn && (
<HorizontalGrid height={this.columnHeight} />
)}
</React.Fragment>
)}
</View>
)} )}
</View> </View>
</AppPage> </View>
) </AppPage>
}
}
function LoadingMoreView({ end }) {
return (
<View style={styles.loadingContainer}>
{!end && <ActivityIndicator size={'large'} color={Colors.orange} />}
</View>
) )
} }
LoadingMoreView.propTypes = { CycleChart.propTypes = {
end: PropTypes.bool, navigate: PropTypes.func,
setDate: PropTypes.func,
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@@ -242,20 +134,12 @@ const styles = StyleSheet.create({
chartContainer: { chartContainer: {
flexDirection: 'column', flexDirection: 'column',
}, },
loadingContainer: {
height: '100%',
backgroundColor: Colors.turquoiseLight,
justifyContent: 'center',
},
page: { page: {
marginVertical: Spacing.small, marginVertical: Spacing.small,
}, },
pageContainer: { pageContainer: {
paddingHorizontal: Spacing.base, paddingHorizontal: Spacing.base,
}, },
warning: {
padding: Spacing.large,
},
}) })
export default CycleChart export default CycleChart
+2 -3
View File
@@ -12,13 +12,13 @@ import {
symptomColorMethods, symptomColorMethods,
getTemperatureProps, getTemperatureProps,
isSymptomDataComplete, isSymptomDataComplete,
nfpLines,
} from '../helpers/chart' } from '../helpers/chart'
const DayColumn = ({ const DayColumn = ({
dateString, dateString,
chartSymptoms, chartSymptoms,
columnHeight, columnHeight,
getFhmAndLtlInfo,
setDate, setDate,
navigate, navigate,
shouldShowTemperatureColumn, shouldShowTemperatureColumn,
@@ -54,7 +54,7 @@ const DayColumn = ({
}, data) }, data)
} }
const fhmAndLtl = getFhmAndLtlInfo( const fhmAndLtl = nfpLines()(
dateString, dateString,
data.temperature ? data.temperature.value : null, data.temperature ? data.temperature.value : null,
columnHeight columnHeight
@@ -104,7 +104,6 @@ DayColumn.propTypes = {
dateString: PropTypes.string.isRequired, dateString: PropTypes.string.isRequired,
chartSymptoms: PropTypes.array, chartSymptoms: PropTypes.array,
columnHeight: PropTypes.number.isRequired, columnHeight: PropTypes.number.isRequired,
getFhmAndLtlInfo: PropTypes.func.isRequired,
navigate: PropTypes.func.isRequired, navigate: PropTypes.func.isRequired,
setDate: PropTypes.func.isRequired, setDate: PropTypes.func.isRequired,
shouldShowTemperatureColumn: PropTypes.bool, shouldShowTemperatureColumn: PropTypes.bool,
+27
View File
@@ -0,0 +1,27 @@
import React from 'react'
import PropTypes from 'prop-types'
import { ActivityIndicator, StyleSheet, View } from 'react-native'
import { Colors } from '../../styles'
function LoadingMoreView({ end }) {
return (
<View style={styles.loadingContainer}>
{!end && <ActivityIndicator size={'large'} color={Colors.orange} />}
</View>
)
}
LoadingMoreView.propTypes = {
end: PropTypes.bool,
}
const styles = StyleSheet.create({
loadingContainer: {
height: '100%',
backgroundColor: Colors.turquoiseLight,
justifyContent: 'center',
},
})
export default LoadingMoreView
+32
View File
@@ -0,0 +1,32 @@
import React, { useState } from 'react'
import PropTypes from 'prop-types'
import { FlatList } from 'react-native'
import LoadingMoreView from './loading-more'
const MainGrid = (props) => {
const [endReached, setEndReached] = useState(false)
return (
<FlatList
horizontal={true}
inverted={true}
showsHorizontalScrollIndicator={false}
keyExtractor={(item) => item}
windowSize={30}
onEndReached={() => setEndReached(true)}
ListFooterComponent={<LoadingMoreView end={endReached} />}
updateCellsBatchingPeriod={800}
{...props}
/>
)
}
MainGrid.propTypes = {
height: PropTypes.number,
data: PropTypes.array,
renderItem: PropTypes.func,
initialNumToRender: PropTypes.number,
contentContainerStyle: PropTypes.object,
}
export default MainGrid
+19
View File
@@ -0,0 +1,19 @@
import React from 'react'
import { StyleSheet } from 'react-native'
import AppText from '../common/app-text'
import { shared } from '../../i18n/en/labels'
import { Spacing } from '../../styles'
function NoTemperature() {
return <AppText style={styles.warning}>{shared.noTemperatureWarning}</AppText>
}
const styles = StyleSheet.create({
warning: {
padding: Spacing.large,
},
})
export default NoTemperature