API & Client: fix and update (pagination, style)
This commit is contained in:
parent
ca80a8b6d5
commit
f744eb0769
@ -160,6 +160,20 @@ class Activity(db.Model):
|
|||||||
self.duration = duration
|
self.duration = duration
|
||||||
|
|
||||||
def serialize(self):
|
def serialize(self):
|
||||||
|
previous_activity = Activity.query.filter(
|
||||||
|
Activity.id != self.id,
|
||||||
|
Activity.user_id == self.user_id,
|
||||||
|
Activity.activity_date <= self.activity_date
|
||||||
|
).order_by(
|
||||||
|
Activity.activity_date.desc()
|
||||||
|
).first()
|
||||||
|
next_activity = Activity.query.filter(
|
||||||
|
Activity.id != self.id,
|
||||||
|
Activity.user_id == self.user_id,
|
||||||
|
Activity.activity_date >= self.activity_date
|
||||||
|
).order_by(
|
||||||
|
Activity.activity_date.asc()
|
||||||
|
).first()
|
||||||
return {
|
return {
|
||||||
"id": self.id,
|
"id": self.id,
|
||||||
"user_id": self.user_id,
|
"user_id": self.user_id,
|
||||||
@ -180,6 +194,8 @@ class Activity(db.Model):
|
|||||||
"ave_speed": float(self.ave_speed) if self.ave_speed else None,
|
"ave_speed": float(self.ave_speed) if self.ave_speed else None,
|
||||||
"with_gpx": self.gpx is not None,
|
"with_gpx": self.gpx is not None,
|
||||||
"bounds": [float(bound) for bound in self.bounds] if self.bounds else [], # noqa
|
"bounds": [float(bound) for bound in self.bounds] if self.bounds else [], # noqa
|
||||||
|
"previous_activity": previous_activity.id if previous_activity else None, # noqa
|
||||||
|
"next_activity": next_activity.id if next_activity else None,
|
||||||
"segments": [segment.serialize() for segment in self.segments],
|
"segments": [segment.serialize() for segment in self.segments],
|
||||||
"records": [record.serialize() for record in self.records]
|
"records": [record.serialize() for record in self.records]
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,6 @@ import mpwoApi from '../mwpoApi/activities'
|
|||||||
import { history } from '../index'
|
import { history } from '../index'
|
||||||
import { setError } from './index'
|
import { setError } from './index'
|
||||||
|
|
||||||
export const endPagination = status => ({
|
|
||||||
type: 'END_PAGINATION',
|
|
||||||
status,
|
|
||||||
})
|
|
||||||
|
|
||||||
export const pushActivities = activities => ({
|
export const pushActivities = activities => ({
|
||||||
type: 'PUSH_ACTIVITIES',
|
type: 'PUSH_ACTIVITIES',
|
||||||
activities,
|
activities,
|
||||||
@ -90,9 +85,6 @@ export const getMoreActivities = page => dispatch => mpwoGenericApi
|
|||||||
if (ret.data.activities.length > 0) {
|
if (ret.data.activities.length > 0) {
|
||||||
dispatch(pushActivities(ret.data.activities))
|
dispatch(pushActivities(ret.data.activities))
|
||||||
}
|
}
|
||||||
if (ret.data.activities.length < 5) {
|
|
||||||
dispatch(endPagination(true))
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
dispatch(setError(`activities: ${ret.message}`))
|
dispatch(setError(`activities: ${ret.message}`))
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ class ActivityDisplay extends React.Component {
|
|||||||
}}
|
}}
|
||||||
close={() => this.setState({ displayModal: false })}
|
close={() => this.setState({ displayModal: false })}
|
||||||
/>}
|
/>}
|
||||||
{activity && sport && (
|
{activity && sport && activities.length === 1 && (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col">
|
<div className="col">
|
||||||
<div className="card">
|
<div className="card">
|
||||||
@ -194,11 +194,11 @@ export default connect(
|
|||||||
user: state.user,
|
user: state.user,
|
||||||
}),
|
}),
|
||||||
dispatch => ({
|
dispatch => ({
|
||||||
onDeleteActivity: activityId => {
|
|
||||||
dispatch(deleteActivity(activityId))
|
|
||||||
},
|
|
||||||
loadActivity: activityId => {
|
loadActivity: activityId => {
|
||||||
dispatch(getData('activities', activityId))
|
dispatch(getData('activities', activityId))
|
||||||
},
|
},
|
||||||
|
onDeleteActivity: activityId => {
|
||||||
|
dispatch(deleteActivity(activityId))
|
||||||
|
},
|
||||||
})
|
})
|
||||||
)(ActivityDisplay)
|
)(ActivityDisplay)
|
||||||
|
@ -8,6 +8,10 @@ class AdminSports extends React.Component {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.loadSport(this.props.match.params.sportId)
|
this.props.loadSport(this.props.match.params.sportId)
|
||||||
}
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
// reload all Sports
|
||||||
|
this.props.loadSport(null)
|
||||||
|
}
|
||||||
render() {
|
render() {
|
||||||
const { sports } = this.props
|
const { sports } = this.props
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
.App {
|
.App {
|
||||||
|
background-color: #eaeaea;
|
||||||
|
min-height: 100vh;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,7 +101,7 @@ input, textarea {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
margin: 20% auto;
|
margin: 20% auto;
|
||||||
z-index: 100;
|
z-index: 1250;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-modal-backdrop {
|
.custom-modal-backdrop {
|
||||||
@ -110,7 +112,7 @@ input, textarea {
|
|||||||
right: 0;
|
right: 0;
|
||||||
background-color: rgba(0,0,0,0.3);
|
background-color: rgba(0,0,0,0.3);
|
||||||
padding: 50px;
|
padding: 50px;
|
||||||
z-index: 90;
|
z-index: 1240;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-fa {
|
.custom-fa {
|
||||||
|
@ -5,7 +5,7 @@ import { connect } from 'react-redux'
|
|||||||
import ActivityCard from './ActivityCard'
|
import ActivityCard from './ActivityCard'
|
||||||
import Statistics from './Statistics'
|
import Statistics from './Statistics'
|
||||||
import { getData } from '../../actions'
|
import { getData } from '../../actions'
|
||||||
import { endPagination, getMoreActivities } from '../../actions/activities'
|
import { getMoreActivities } from '../../actions/activities'
|
||||||
|
|
||||||
class DashBoard extends React.Component {
|
class DashBoard extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
@ -19,14 +19,13 @@ class DashBoard extends React.Component {
|
|||||||
this.props.loadActivities()
|
this.props.loadActivities()
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.props.resetPaginationStatus(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
activities, loadMoreActivities, message, paginationEnd, sports
|
activities, loadMoreActivities, message, sports
|
||||||
} = this.props
|
} = this.props
|
||||||
|
const paginationEnd = activities.length > 0
|
||||||
|
? activities[activities.length - 1].previous_activity === null
|
||||||
|
: true
|
||||||
const { page } = this.state
|
const { page } = this.state
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -76,14 +75,10 @@ class DashBoard extends React.Component {
|
|||||||
export default connect(
|
export default connect(
|
||||||
state => ({
|
state => ({
|
||||||
activities: state.activities.data,
|
activities: state.activities.data,
|
||||||
paginationEnd: state.activities.pagination_end,
|
|
||||||
message: state.message,
|
message: state.message,
|
||||||
sports: state.sports.data,
|
sports: state.sports.data,
|
||||||
}),
|
}),
|
||||||
dispatch => ({
|
dispatch => ({
|
||||||
resetPaginationStatus: () => {
|
|
||||||
dispatch(endPagination(false))
|
|
||||||
},
|
|
||||||
loadActivities: () => {
|
loadActivities: () => {
|
||||||
dispatch(getData('activities', null, 1))
|
dispatch(getData('activities', null, 1))
|
||||||
},
|
},
|
||||||
|
@ -5,12 +5,13 @@ import { Link } from 'react-router-dom'
|
|||||||
import { apiUrl } from '../../utils'
|
import { apiUrl } from '../../utils'
|
||||||
|
|
||||||
|
|
||||||
function NavBar (props) {
|
function NavBar(props) {
|
||||||
return (
|
return (
|
||||||
<header>
|
<header>
|
||||||
<nav className="navbar navbar-expand-lg navbar-light bg-light">
|
<nav className="navbar navbar-expand-lg navbar-light bg-light">
|
||||||
<span className="navbar-brand">mpwo</span>
|
<div className="container">
|
||||||
<button
|
<span className="navbar-brand">mpwo</span>
|
||||||
|
<button
|
||||||
className="navbar-toggler"
|
className="navbar-toggler"
|
||||||
type="button"
|
type="button"
|
||||||
data-toggle="collapse"
|
data-toggle="collapse"
|
||||||
@ -18,109 +19,111 @@ function NavBar (props) {
|
|||||||
aria-controls="navbarSupportedContent"
|
aria-controls="navbarSupportedContent"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-label="Toggle navigation"
|
aria-label="Toggle navigation"
|
||||||
>
|
>
|
||||||
<span className="navbar-toggler-icon" />
|
<span className="navbar-toggler-icon" />
|
||||||
</button>
|
</button>
|
||||||
<div className="collapse navbar-collapse" id="navbarSupportedContent">
|
<div className="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
<ul className="navbar-nav mr-auto">
|
<ul className="navbar-nav mr-auto">
|
||||||
<li className="nav-item">
|
|
||||||
<Link
|
|
||||||
className="nav-link"
|
|
||||||
to={{
|
|
||||||
pathname: '/',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Dashboard
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
{props.user.isAuthenticated && (
|
|
||||||
<li className="nav-item">
|
|
||||||
<Link
|
|
||||||
className="nav-link"
|
|
||||||
to={{
|
|
||||||
pathname: '/activities/add',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Add a workout
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
)}
|
|
||||||
{props.user.isAdmin && (
|
|
||||||
<li className="nav-item">
|
|
||||||
<Link
|
|
||||||
className="nav-link"
|
|
||||||
to={{
|
|
||||||
pathname: '/admin',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Admin
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
<ul className="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
|
||||||
{!props.user.isAuthenticated && (
|
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<Link
|
<Link
|
||||||
className="nav-link"
|
className="nav-link"
|
||||||
to={{
|
to={{
|
||||||
pathname: '/register',
|
pathname: '/',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Register
|
Dashboard
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
)}
|
{props.user.isAuthenticated && (
|
||||||
{!props.user.isAuthenticated && (
|
<li className="nav-item">
|
||||||
<li className="nav-item">
|
<Link
|
||||||
<Link
|
className="nav-link"
|
||||||
className="nav-link"
|
to={{
|
||||||
to={{
|
pathname: '/activities/add',
|
||||||
pathname: '/login',
|
}}
|
||||||
}}
|
>
|
||||||
>
|
Add a workout
|
||||||
Login
|
</Link>
|
||||||
</Link>
|
</li>
|
||||||
</li>
|
)}
|
||||||
)}
|
{props.user.isAdmin && (
|
||||||
{props.user.picture === true && (
|
<li className="nav-item">
|
||||||
<img
|
<Link
|
||||||
alt="Avatar"
|
className="nav-link"
|
||||||
src={`${apiUrl}users/${props.user.id}/picture` +
|
to={{
|
||||||
|
pathname: '/admin',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Admin
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
<ul className="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||||||
|
{!props.user.isAuthenticated && (
|
||||||
|
<li className="nav-item">
|
||||||
|
<Link
|
||||||
|
className="nav-link"
|
||||||
|
to={{
|
||||||
|
pathname: '/register',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Register
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
{!props.user.isAuthenticated && (
|
||||||
|
<li className="nav-item">
|
||||||
|
<Link
|
||||||
|
className="nav-link"
|
||||||
|
to={{
|
||||||
|
pathname: '/login',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Login
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
{props.user.picture === true && (
|
||||||
|
<img
|
||||||
|
alt="Avatar"
|
||||||
|
src={`${apiUrl}users/${props.user.id}/picture` +
|
||||||
`?${Date.now()}`}
|
`?${Date.now()}`}
|
||||||
className="img-fluid App-nav-profile-img"
|
className="img-fluid App-nav-profile-img"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{props.user.isAuthenticated && (
|
{props.user.isAuthenticated && (
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<Link
|
<Link
|
||||||
className="nav-link"
|
className="nav-link"
|
||||||
to={{
|
to={{
|
||||||
pathname: '/profile',
|
pathname: '/profile',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.user.username}
|
{props.user.username}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
{props.user.isAuthenticated && (
|
{props.user.isAuthenticated && (
|
||||||
<li className="nav-item">
|
<li className="nav-item">
|
||||||
<Link
|
<Link
|
||||||
className="nav-link"
|
className="nav-link"
|
||||||
to={{
|
to={{
|
||||||
pathname: '/logout',
|
pathname: '/logout',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Logout
|
Logout
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
state => ({
|
state => ({
|
||||||
user: state.user,
|
user: state.user,
|
||||||
|
@ -21,11 +21,6 @@ const handleDataAndError = (state, type, action) => {
|
|||||||
|
|
||||||
const activities = (state = initial.activities, action) => {
|
const activities = (state = initial.activities, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'END_PAGINATION':
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
pagination_end: action.status
|
|
||||||
}
|
|
||||||
case 'PUSH_ACTIVITIES':
|
case 'PUSH_ACTIVITIES':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
@ -40,7 +40,6 @@ export default {
|
|||||||
},
|
},
|
||||||
activities: {
|
activities: {
|
||||||
...emptyData,
|
...emptyData,
|
||||||
pagination_end: false
|
|
||||||
},
|
},
|
||||||
// check if storing gpx content is OK
|
// check if storing gpx content is OK
|
||||||
gpx: null,
|
gpx: null,
|
||||||
|
Loading…
Reference in New Issue
Block a user