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)\
|
||||
.order_by(Activity.activity_date.desc()).paginate(
|
||||
page, 5, False).items
|
||||
activities_list = []
|
||||
for activity in activities:
|
||||
activities_list.append(activity.serialize())
|
||||
response_object = {
|
||||
'status': 'success',
|
||||
'data': {
|
||||
'activities': activities_list
|
||||
'activities': [activity.serialize() for activity in activities]
|
||||
}
|
||||
}
|
||||
code = 200
|
||||
|
@ -13,13 +13,10 @@ sports_blueprint = Blueprint('sports', __name__)
|
||||
def get_sports(auth_user_id):
|
||||
"""Get all sports"""
|
||||
sports = Sport.query.order_by(Sport.id).all()
|
||||
sports_list = []
|
||||
for sport in sports:
|
||||
sports_list.append(sport.serialize())
|
||||
response_object = {
|
||||
'status': 'success',
|
||||
'data': {
|
||||
'sports': sports_list
|
||||
'sports': [sport.serialize() for sport in sports]
|
||||
}
|
||||
}
|
||||
return jsonify(response_object), 200
|
||||
|
@ -128,11 +128,21 @@ input, textarea {
|
||||
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 {
|
||||
max-width: 45px;
|
||||
max-height: 45px;
|
||||
}
|
||||
|
||||
.unlink {
|
||||
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 ActivityCard from './ActivityCard'
|
||||
import Records from './Records'
|
||||
import Statistics from './Statistics'
|
||||
import { getData } from '../../actions'
|
||||
import { getMoreActivities } from '../../actions/activities'
|
||||
@ -21,7 +22,7 @@ class DashBoard extends React.Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
activities, loadMoreActivities, message, sports
|
||||
activities, loadMoreActivities, message, records, sports
|
||||
} = this.props
|
||||
const paginationEnd = activities.length > 0
|
||||
? activities[activities.length - 1].previous_activity === null
|
||||
@ -36,10 +37,14 @@ class DashBoard extends React.Component {
|
||||
{message ? (
|
||||
<code>{message}</code>
|
||||
) : (
|
||||
activities.length > 0 ? (
|
||||
(activities.length > 0 && sports.length > 0) ? (
|
||||
<div className="container">
|
||||
<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 => (
|
||||
<ActivityCard
|
||||
activity={activity}
|
||||
@ -59,9 +64,6 @@ class DashBoard extends React.Component {
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
<Statistics />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
@ -76,11 +78,13 @@ export default connect(
|
||||
state => ({
|
||||
activities: state.activities.data,
|
||||
message: state.message,
|
||||
records: state.records.data,
|
||||
sports: state.sports.data,
|
||||
}),
|
||||
dispatch => ({
|
||||
loadActivities: () => {
|
||||
dispatch(getData('activities', null, 1))
|
||||
dispatch(getData('records'))
|
||||
},
|
||||
loadMoreActivities: 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) =>
|
||||
handleDataAndError(state, 'sports', action)
|
||||
|
||||
@ -165,6 +168,7 @@ const reducers = combineReducers({
|
||||
gpx,
|
||||
message,
|
||||
messages,
|
||||
records,
|
||||
router: routerReducer,
|
||||
sports,
|
||||
user,
|
||||
|
@ -43,6 +43,9 @@ export default {
|
||||
},
|
||||
// check if storing gpx content is OK
|
||||
gpx: null,
|
||||
records: {
|
||||
...emptyData,
|
||||
},
|
||||
sports: {
|
||||
...emptyData,
|
||||
}
|
||||
|
@ -39,3 +39,28 @@ export const formatActivityDate = activityDateTime => {
|
||||
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