Client: Display records on dashboard

This commit is contained in:
Sam 2018-05-20 13:12:35 +02:00
parent c03d8f2736
commit e8d4ee2b6c
8 changed files with 121 additions and 15 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
} }

View 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>
)
}

View File

@ -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))

View File

@ -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,

View File

@ -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,
} }

View File

@ -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,
}
}