stats components refactor

This commit is contained in:
Sam 2019-01-03 11:16:46 +01:00
parent 0e6b9030f8
commit af5b0e1889
6 changed files with 170 additions and 239 deletions

View File

@ -128,10 +128,6 @@ label {
font-style: italic;
}
.chart-month {
font-size: 0.8em;
}
.chart-radio {
display: flex;
font-size: 0.9em;
@ -145,6 +141,10 @@ label {
margin-right: 10px;
}
.chart-stats {
font-size: 0.8em;
}
.chart-title {
font-size: 1.1em;
margin-bottom: 10px;

View File

@ -1,140 +1,31 @@
import { endOfMonth, format, startOfMonth } from 'date-fns'
import { endOfMonth, startOfMonth } from 'date-fns'
import React from 'react'
import { connect } from 'react-redux'
import {
Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis
} from 'recharts'
import { getStats } from '../../actions/stats'
import { activityColors, formatDuration, formatStats } from '../../utils'
import CustomTooltip from '../Others/CustomTooltip'
import Stats from '../Others/Stats'
class Statistics extends React.Component {
export default class Statistics extends React.Component {
constructor(props, context) {
super(props, context)
const date = new Date()
this.state = {
start: startOfMonth(date),
end: endOfMonth(date),
displayedData: 'distance'
duration: 'week',
type: 'by_time',
}
}
componentDidMount() {
this.props.loadMonthActivities(
this.props.user.id,
this.state.start,
this.state.end,
)
}
handleRadioChange (changeEvent) {
this.setState({
displayedData: changeEvent.target.name
})
}
render() {
const { sports, statistics } = this.props
const { displayedData, end, start } = this.state
const stats = formatStats(statistics, sports, start, end)
return (
<div className="card activity-card">
<div className="card-header">
This month
</div>
<div className="card-body">
{Object.keys(statistics).length === 0 ? (
'No workouts'
) : (
<div className="chart-month">
<div className="row chart-radio">
<label className="radioLabel col">
<input
type="radio"
name="distance"
checked={displayedData === 'distance'}
onChange={e => this.handleRadioChange(e)}
/>
distance
</label>
<label className="radioLabel col">
<input
type="radio"
name="duration"
checked={displayedData === 'duration'}
onChange={e => this.handleRadioChange(e)}
/>
duration
</label>
<label className="radioLabel col">
<input
type="radio"
name="activities"
checked={displayedData === 'activities'}
onChange={e => this.handleRadioChange(e)}
/>
activities
</label>
</div>
<ResponsiveContainer height={300}>
<BarChart
data={stats[displayedData]}
margin={{ top: 15, bottom: 0 }}
>
<XAxis
dataKey="date"
interval={0} // to force to display all ticks
/>
<YAxis
tickFormatter={value => displayedData === 'distance'
? `${value} km`
: displayedData === 'duration'
? formatDuration(value)
: value
}
/>
<Tooltip content={
<CustomTooltip
displayedData={displayedData}
/>
}
/>
{sports.map((s, i) => (
<Bar
key={s.id}
dataKey={s.label}
stackId="a"
fill={activityColors[i]}
unit={displayedData === 'distance' ? ' km' : ''}
/>
))}
</BarChart>
</ResponsiveContainer>
</div>
)}
<Stats statsParams={this.state} />
</div>
</div>
)
}
}
export default connect(
state => ({
sports: state.sports.data,
statistics: state.statistics.data,
user: state.user,
}),
dispatch => ({
loadMonthActivities: (userId, start, end) => {
const dateFormat = 'YYYY-MM-DD'
const params = {
from: format(start, dateFormat),
to: format(end, dateFormat),
time: 'week'
}
dispatch(getStats(userId, 'by_time', params))
},
})
)(Statistics)

View File

@ -0,0 +1,97 @@
import React from 'react'
import {
Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis
} from 'recharts'
import { activityColors, formatDuration } from '../../../utils'
import CustomTooltip from '../CustomTooltip'
export default class StatsCharts extends React.PureComponent {
constructor(props, context) {
super(props, context)
this.state = {
displayedData: 'distance'
}
}
handleRadioChange (changeEvent) {
this.setState({
displayedData: changeEvent.target.name
})
}
render() {
const { displayedData } = this.state
const { sports, stats } = this.props
if (Object.keys(stats).length === 0) {
return 'No workouts'
}
return (
<div className="chart-stats">
<div className="row chart-radio">
<label className="radioLabel col">
<input
type="radio"
name="distance"
checked={displayedData === 'distance'}
onChange={e => this.handleRadioChange(e)}
/>
distance
</label>
<label className="radioLabel col">
<input
type="radio"
name="duration"
checked={displayedData === 'duration'}
onChange={e => this.handleRadioChange(e)}
/>
duration
</label>
<label className="radioLabel col">
<input
type="radio"
name="activities"
checked={displayedData === 'activities'}
onChange={e => this.handleRadioChange(e)}
/>
activities
</label>
</div>
<ResponsiveContainer height={300}>
<BarChart
data={stats[displayedData]}
margin={{ top: 15, bottom: 0 }}
>
<XAxis
dataKey="date"
interval={0} // to force to display all ticks
/>
<YAxis
tickFormatter={value => displayedData === 'distance'
? `${value} km`
: displayedData === 'duration'
? formatDuration(value)
: value
}
/>
<Tooltip content={
<CustomTooltip
displayedData={displayedData}
/>
}
/>
{sports.map((s, i) => (
<Bar
key={s.id}
dataKey={s.label}
stackId="a"
fill={activityColors[i]}
unit={displayedData === 'distance' ? ' km' : ''}
/>
))}
</BarChart>
</ResponsiveContainer>
</div>
)
}
}

View File

@ -0,0 +1,50 @@
import { format } from 'date-fns'
import React from 'react'
import { connect } from 'react-redux'
import { getStats } from '../../../actions/stats'
import { formatStats } from '../../../utils'
import StatsChart from './StatsChart'
class Statistics extends React.PureComponent {
componentDidMount() {
this.props.loadMonthActivities(
this.props.user.id,
this.props.statsParams,
)
}
render() {
const { sports, statistics, statsParams } = this.props
const stats = formatStats(statistics, sports, statsParams)
return (
<>
{Object.keys(statistics).length === 0 ? (
'No workouts'
) : (
<StatsChart sports={sports} stats={stats} />
)}
</>
)
}
}
export default connect(
state => ({
sports: state.sports.data,
statistics: state.statistics.data,
user: state.user,
}),
dispatch => ({
loadMonthActivities: (userId, data) => {
const dateFormat = 'YYYY-MM-DD'
const params = {
from: format(data.start, dateFormat),
to: format(data.end, dateFormat),
time: data.duration
}
dispatch(getStats(userId, data.type, params))
},
})
)(Statistics)

View File

@ -1,44 +1,22 @@
import { endOfMonth, format, startOfMonth, subMonths } from 'date-fns'
import { endOfMonth, startOfMonth, subMonths } from 'date-fns'
import React from 'react'
import { connect } from 'react-redux'
import {
Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis
} from 'recharts'
import { getStats } from '../../actions/stats'
import { activityColors, formatDuration, formatStats } from '../../utils'
import CustomTooltip from '../Others/CustomTooltip'
import Stats from '../Others/Stats'
class Statistics extends React.Component {
export default class Statistics extends React.Component {
constructor(props, context) {
super(props, context)
const date = new Date()
this.state = {
start: startOfMonth(subMonths(date, 12)),
end: endOfMonth(date),
displayedData: 'distance'
duration: 'month',
type: 'by_time',
}
}
componentDidMount() {
this.props.loadMonthActivities(
this.props.user.id,
this.state.start,
this.state.end,
)
}
handleRadioChange (changeEvent) {
this.setState({
displayedData: changeEvent.target.name
})
}
render() {
const { sports, statistics } = this.props
const { displayedData, end, start } = this.state
const stats = formatStats(statistics, sports, start, end, 'month')
return (
<div className="container dashboard">
<div className="card activity-card">
@ -46,97 +24,10 @@ class Statistics extends React.Component {
Statistics
</div>
<div className="card-body">
{Object.keys(statistics).length === 0 ? (
'No workouts'
) : (
<div className="chart-month">
<div className="row chart-radio">
<label className="radioLabel col">
<input
type="radio"
name="distance"
checked={displayedData === 'distance'}
onChange={e => this.handleRadioChange(e)}
/>
distance
</label>
<label className="radioLabel col">
<input
type="radio"
name="duration"
checked={displayedData === 'duration'}
onChange={e => this.handleRadioChange(e)}
/>
duration
</label>
<label className="radioLabel col">
<input
type="radio"
name="activities"
checked={displayedData === 'activities'}
onChange={e => this.handleRadioChange(e)}
/>
activities
</label>
</div>
<ResponsiveContainer height={300}>
<BarChart
data={stats[displayedData]}
margin={{ top: 15, bottom: 0 }}
>
<XAxis
dataKey="date"
interval={0} // to force to display all ticks
/>
<YAxis
tickFormatter={value => displayedData === 'distance'
? `${value} km`
: displayedData === 'duration'
? formatDuration(value)
: value
}
/>
<Tooltip content={
<CustomTooltip
displayedData={displayedData}
/>
}
/>
{sports.map((s, i) => (
<Bar
key={s.id}
dataKey={s.label}
stackId="a"
fill={activityColors[i]}
unit={displayedData === 'distance' ? ' km' : ''}
/>
))}
</BarChart>
</ResponsiveContainer>
</div>
)}
<Stats statsParams={this.state} />
</div>
</div>
</div>
)
}
}
export default connect(
state => ({
sports: state.sports.data,
statistics: state.statistics.data,
user: state.user,
}),
dispatch => ({
loadMonthActivities: (userId, start, end) => {
const dateFormat = 'YYYY-MM-DD'
const params = {
from: format(start, dateFormat),
to: format(end, dateFormat),
time: 'month'
}
dispatch(getStats(userId, 'by_time', params))
},
})
)(Statistics)

View File

@ -172,17 +172,19 @@ const dateIncrement = (duration, day) => {
}
export const formatStats = (
stats, sports, startDate, endDate, duration = 'week'
stats, sports, params
) => {
const nbActivitiesStats = []
const distanceStats = []
const durationStats = []
for (let day = startOfWeek(startDate);
day <= endDate;
day = dateIncrement(duration, day)
for (let day = startOfWeek(params.start);
day <= params.end;
day = dateIncrement(params.duration, day)
) {
const [xAxisFormat] = xAxisFormats.filter(x => x.duration === duration)
const [xAxisFormat] = xAxisFormats.filter(
x => x.duration === params.duration
)
const date = format(day, xAxisFormat.dateFormat)
const xAxis = format(day, xAxisFormat.xAxis)
const dataNbActivities = { date: xAxis }