import React, { Component } from 'react' import PropTypes from 'prop-types' import { View, FlatList, ActivityIndicator } 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 DayColumn from './day-column' import HorizontalGrid from './horizontal-grid' import AppText from '../common/app-text' 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 config from '../../config' import { shared } from '../../i18n/en/labels' import styles from './styles' class CycleChart extends Component { static propTypes = { navigate: PropTypes.func, end: PropTypes.bool } constructor(props) { super(props) this.state = {} this.cycleDaysSortedByDate = getCycleDaysSortedByDate() this.getFhmAndLtlInfo = nfpLines() this.shouldShowTemperatureColumn = false this.prepareSymptomData() } prepareSymptomData = () => { this.symptomRowSymptoms = config.symptoms.filter((symptomName) => { return this.cycleDaysSortedByDate.some(cycleDay => { return cycleDay[symptomName] }) }) this.chartSymptoms = [...this.symptomRowSymptoms] if (this.cycleDaysSortedByDate.some(day => day.temperature)) { this.chartSymptoms.push('temperature') this.shouldShowTemperatureColumn = true } } renderColumn = ({ item, index }) => { return ( ) } 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 const remainingHeight = height - this.xAxisHeight this.symptomHeight = remainingHeight * symptomCoefficient 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 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) { this.cycleDaysSortedByDate.removeListener(this.handleDbChange) } if (this.removeObvListener) this.removeObvListener() this.handleDbChange = (_, changes) => { if (nothingChanged(changes)) return dataUpdateHandler() } this.cycleDaysSortedByDate.addListener(this.handleDbChange) 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 return ( {!shouldShowChart && } {shouldShowChart && !chartHeight && !chartLoaded && } {shouldShowChart && ( {chartHeight && chartLoaded && ( {this.shouldShowTemperatureColumn && ()} )} {chartHeight && item} initialNumToRender={numberOfColumnsToRender} windowSize={30} onLayout={() => this.setState({chartLoaded: true})} onEndReached={() => this.setState({end: true})} ListFooterComponent={} updateCellsBatchingPeriod={800} contentContainerStyle={{height: chartHeight}} /> } )} {shouldShowChart && chartLoaded && !this.shouldShowTemperatureColumn && ( {shared.noTemperatureWarning} )} ) } } function LoadingMoreView({ end }) { return ( {!end && } ) } LoadingMoreView.propTypes = { end: PropTypes.bool } const mapDispatchToProps = (dispatch) => { return({ navigate: (page) => dispatch(navigate(page)), }) } export default connect( null, mapDispatchToProps, )(CycleChart)