init statistics page (wip) - #13
This commit is contained in:
parent
3e22feba73
commit
c28d56f975
@ -11,6 +11,7 @@ import NavBar from './NavBar'
|
||||
import NotFound from './Others/NotFound'
|
||||
import Profile from './User/Profile'
|
||||
import ProfileEdit from './User/ProfileEdit'
|
||||
import Statistics from './Statistics'
|
||||
import UserForm from './User/UserForm'
|
||||
import { isLoggedIn } from '../utils'
|
||||
|
||||
@ -89,6 +90,10 @@ export default class App extends React.Component {
|
||||
exact path="/activities/history"
|
||||
component={Activities}
|
||||
/>
|
||||
<Route
|
||||
exact path="/activities/statistics"
|
||||
component={Statistics}
|
||||
/>
|
||||
<Route path="/activities" component={Activity} />
|
||||
{/* <Route path="/admin" component={Admin} /> */}
|
||||
<Route component={NotFound} />
|
||||
|
@ -46,6 +46,18 @@ function NavBar(props) {
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{props.user.isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
className="nav-link"
|
||||
to={{
|
||||
pathname: '/activities/statistics',
|
||||
}}
|
||||
>
|
||||
Statistics
|
||||
</Link>
|
||||
</li>
|
||||
)}
|
||||
{props.user.isAuthenticated && (
|
||||
<li className="nav-item">
|
||||
<Link
|
||||
|
142
fittrackee_client/src/components/Statistics/index.jsx
Normal file
142
fittrackee_client/src/components/Statistics/index.jsx
Normal file
@ -0,0 +1,142 @@
|
||||
import { endOfMonth, format, 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'
|
||||
|
||||
|
||||
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'
|
||||
}
|
||||
}
|
||||
|
||||
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">
|
||||
<div className="card-header">
|
||||
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'
|
||||
? format(formatDuration(value), 'HH:mm')
|
||||
: 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>
|
||||
)}
|
||||
</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)
|
@ -1,5 +1,7 @@
|
||||
import togeojson from '@mapbox/togeojson'
|
||||
import { addDays, format, parse, startOfWeek, subHours } from 'date-fns'
|
||||
import {
|
||||
addDays, addMonths, addYears, format, parse, startOfWeek, subHours
|
||||
} from 'date-fns'
|
||||
import { DateTime } from 'luxon'
|
||||
|
||||
export const apiUrl = `${process.env.REACT_APP_API_URL}/api/`
|
||||
@ -137,17 +139,37 @@ export const formatChartData = chartData => {
|
||||
return chartData
|
||||
}
|
||||
|
||||
export const formatStats = (stats, sports, startDate, endDate) => {
|
||||
const xAxisFormats = [
|
||||
{ duration: 'week', dateFormat: 'YYYY-MM-DD', xAxis: 'DD/MM' },
|
||||
{ duration: 'month', dateFormat: 'YYYY-MM', xAxis: 'MM/YYYY' },
|
||||
{ duration: 'year', dateFormat: 'YYYY', xAxis: 'YYYY' },
|
||||
]
|
||||
|
||||
const dateIncrement = (duration, day) => {
|
||||
switch (duration) {
|
||||
case 'week':
|
||||
return addDays(day, 7)
|
||||
case 'month':
|
||||
return addMonths(day, 1)
|
||||
case 'year':
|
||||
return addYears(day, 1)
|
||||
}
|
||||
}
|
||||
|
||||
export const formatStats = (
|
||||
stats, sports, startDate, endDate, duration = 'week'
|
||||
) => {
|
||||
const nbActivitiesStats = []
|
||||
const distanceStats = []
|
||||
const durationStats = []
|
||||
|
||||
for (let day = startOfWeek(startDate);
|
||||
day <= endDate;
|
||||
day = addDays(day, 7)
|
||||
day = dateIncrement(duration, day)
|
||||
) {
|
||||
const date = format(day, 'YYYY-MM-DD')
|
||||
const xAxis = format(day, 'DD/MM')
|
||||
const [xAxisFormat] = xAxisFormats.filter(x => x.duration === duration)
|
||||
const date = format(day, xAxisFormat.dateFormat)
|
||||
const xAxis = format(day, xAxisFormat.xAxis)
|
||||
const dataNbActivities = { date: xAxis }
|
||||
const dataDistance = { date: xAxis }
|
||||
const dataDuration = { date: xAxis }
|
||||
|
Loading…
Reference in New Issue
Block a user