Client: Display records on dashboard
This commit is contained in:
parent
c03d8f2736
commit
e8d4ee2b6c
@ -25,13 +25,10 @@ def get_activities(auth_user_id):
|
|||||||
activities = Activity.query.filter_by(user_id=auth_user_id)\
|
activities = Activity.query.filter_by(user_id=auth_user_id)\
|
||||||
.order_by(Activity.activity_date.desc()).paginate(
|
.order_by(Activity.activity_date.desc()).paginate(
|
||||||
page, 5, False).items
|
page, 5, False).items
|
||||||
activities_list = []
|
|
||||||
for activity in activities:
|
|
||||||
activities_list.append(activity.serialize())
|
|
||||||
response_object = {
|
response_object = {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'data': {
|
'data': {
|
||||||
'activities': activities_list
|
'activities': [activity.serialize() for activity in activities]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
code = 200
|
code = 200
|
||||||
|
@ -13,13 +13,10 @@ sports_blueprint = Blueprint('sports', __name__)
|
|||||||
def get_sports(auth_user_id):
|
def get_sports(auth_user_id):
|
||||||
"""Get all sports"""
|
"""Get all sports"""
|
||||||
sports = Sport.query.order_by(Sport.id).all()
|
sports = Sport.query.order_by(Sport.id).all()
|
||||||
sports_list = []
|
|
||||||
for sport in sports:
|
|
||||||
sports_list.append(sport.serialize())
|
|
||||||
response_object = {
|
response_object = {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'data': {
|
'data': {
|
||||||
'sports': sports_list
|
'sports': [sport.serialize() for sport in sports]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return jsonify(response_object), 200
|
return jsonify(response_object), 200
|
||||||
|
@ -128,11 +128,21 @@ input, textarea {
|
|||||||
color: lightgrey;
|
color: lightgrey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.record-logo {
|
||||||
|
margin-right: 5px;
|
||||||
|
max-width: 25px;
|
||||||
|
max-height: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.record-table table, .record-table th, .record-table td{
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
.sport-img-medium {
|
.sport-img-medium {
|
||||||
max-width: 45px;
|
max-width: 45px;
|
||||||
max-height: 45px;
|
max-height: 45px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unlink {
|
.unlink {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
66
mpwo_client/src/components/Dashboard/Records.jsx
Normal file
66
mpwo_client/src/components/Dashboard/Records.jsx
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
|
import { formatRecord } from '../../utils'
|
||||||
|
|
||||||
|
export default function RecordsCard (props) {
|
||||||
|
const { records, sports } = props
|
||||||
|
const recordsBySport = records.reduce((sportList, record) => {
|
||||||
|
const sport = sports.find(s => s.id === record.sport_id)
|
||||||
|
if (sportList[sport.label] === void 0) {
|
||||||
|
sportList[sport.label] = {
|
||||||
|
img: sport.img,
|
||||||
|
records: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sportList[sport.label].records.push(formatRecord(record))
|
||||||
|
return sportList
|
||||||
|
}, {})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="card activity-card">
|
||||||
|
<div className="card-header">
|
||||||
|
Personal records
|
||||||
|
</div>
|
||||||
|
<div className="card-body">
|
||||||
|
{Object.keys(recordsBySport).map(sportLabel => (
|
||||||
|
<table
|
||||||
|
className="table table-borderless record-table"
|
||||||
|
key={sportLabel}
|
||||||
|
>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th colSpan="3">
|
||||||
|
<img
|
||||||
|
alt={`${sportLabel} logo`}
|
||||||
|
className="record-logo"
|
||||||
|
src={recordsBySport[sportLabel].img}
|
||||||
|
/>
|
||||||
|
{sportLabel}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{recordsBySport[sportLabel].records.map(rec => (
|
||||||
|
<tr key={rec.id}>
|
||||||
|
<td>
|
||||||
|
{rec.record_type}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{rec.value}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<Link to={`/activities/${rec.activity_id}`}>
|
||||||
|
{rec.activity_date}
|
||||||
|
</Link>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ import { Helmet } from 'react-helmet'
|
|||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
|
|
||||||
import ActivityCard from './ActivityCard'
|
import ActivityCard from './ActivityCard'
|
||||||
|
import Records from './Records'
|
||||||
import Statistics from './Statistics'
|
import Statistics from './Statistics'
|
||||||
import { getData } from '../../actions'
|
import { getData } from '../../actions'
|
||||||
import { getMoreActivities } from '../../actions/activities'
|
import { getMoreActivities } from '../../actions/activities'
|
||||||
@ -21,7 +22,7 @@ class DashBoard extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
activities, loadMoreActivities, message, sports
|
activities, loadMoreActivities, message, records, sports
|
||||||
} = this.props
|
} = this.props
|
||||||
const paginationEnd = activities.length > 0
|
const paginationEnd = activities.length > 0
|
||||||
? activities[activities.length - 1].previous_activity === null
|
? activities[activities.length - 1].previous_activity === null
|
||||||
@ -36,10 +37,14 @@ class DashBoard extends React.Component {
|
|||||||
{message ? (
|
{message ? (
|
||||||
<code>{message}</code>
|
<code>{message}</code>
|
||||||
) : (
|
) : (
|
||||||
activities.length > 0 ? (
|
(activities.length > 0 && sports.length > 0) ? (
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-md-6">
|
<div className="col-md-4">
|
||||||
|
<Records records={records} sports={sports} />
|
||||||
|
<Statistics />
|
||||||
|
</div>
|
||||||
|
<div className="col-md-8">
|
||||||
{activities.map(activity => (
|
{activities.map(activity => (
|
||||||
<ActivityCard
|
<ActivityCard
|
||||||
activity={activity}
|
activity={activity}
|
||||||
@ -59,9 +64,6 @@ class DashBoard extends React.Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-6">
|
|
||||||
<Statistics />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@ -76,11 +78,13 @@ export default connect(
|
|||||||
state => ({
|
state => ({
|
||||||
activities: state.activities.data,
|
activities: state.activities.data,
|
||||||
message: state.message,
|
message: state.message,
|
||||||
|
records: state.records.data,
|
||||||
sports: state.sports.data,
|
sports: state.sports.data,
|
||||||
}),
|
}),
|
||||||
dispatch => ({
|
dispatch => ({
|
||||||
loadActivities: () => {
|
loadActivities: () => {
|
||||||
dispatch(getData('activities', null, 1))
|
dispatch(getData('activities', null, 1))
|
||||||
|
dispatch(getData('records'))
|
||||||
},
|
},
|
||||||
loadMoreActivities: page => {
|
loadMoreActivities: page => {
|
||||||
dispatch(getMoreActivities(page))
|
dispatch(getMoreActivities(page))
|
||||||
|
@ -115,6 +115,9 @@ const messages = (state = initial.messages, action) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const records = (state = initial.records, action) =>
|
||||||
|
handleDataAndError(state, 'records', action)
|
||||||
|
|
||||||
const sports = (state = initial.sports, action) =>
|
const sports = (state = initial.sports, action) =>
|
||||||
handleDataAndError(state, 'sports', action)
|
handleDataAndError(state, 'sports', action)
|
||||||
|
|
||||||
@ -165,6 +168,7 @@ const reducers = combineReducers({
|
|||||||
gpx,
|
gpx,
|
||||||
message,
|
message,
|
||||||
messages,
|
messages,
|
||||||
|
records,
|
||||||
router: routerReducer,
|
router: routerReducer,
|
||||||
sports,
|
sports,
|
||||||
user,
|
user,
|
||||||
|
@ -43,6 +43,9 @@ export default {
|
|||||||
},
|
},
|
||||||
// check if storing gpx content is OK
|
// check if storing gpx content is OK
|
||||||
gpx: null,
|
gpx: null,
|
||||||
|
records: {
|
||||||
|
...emptyData,
|
||||||
|
},
|
||||||
sports: {
|
sports: {
|
||||||
...emptyData,
|
...emptyData,
|
||||||
}
|
}
|
||||||
|
@ -39,3 +39,28 @@ export const formatActivityDate = activityDateTime => {
|
|||||||
activity_time: null,
|
activity_time: null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const formatRecord = record => {
|
||||||
|
let value, recordType = null
|
||||||
|
switch (record.record_type) {
|
||||||
|
case 'AS':
|
||||||
|
case 'MS':
|
||||||
|
value = `${record.value} km/h`
|
||||||
|
recordType = record.record_type === 'AS' ? 'Avg speed' : 'Max speed'
|
||||||
|
break
|
||||||
|
case 'FD':
|
||||||
|
value = `${record.value} km`
|
||||||
|
recordType = 'Farest distance'
|
||||||
|
break
|
||||||
|
default: // 'LD'
|
||||||
|
value = record.value // eslint-disable-line prefer-destructuring
|
||||||
|
recordType = 'Longest duration'
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
activity_date: formatActivityDate(record.activity_date).activity_date,
|
||||||
|
activity_id: record.activity_id,
|
||||||
|
id: record.id,
|
||||||
|
record_type: recordType,
|
||||||
|
value: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user