Merge branch 'master' into v0.3.0

Conflicts:
	docs/objects.inv
	docs/searchindex.js
	fittrackee_api/poetry.lock
	fittrackee_api/pyproject.toml
	fittrackee_client/src/actions/index.js
	fittrackee_client/src/components/App.jsx
	fittrackee_client/src/utils/index.js
This commit is contained in:
Sam
2020-02-07 11:12:32 +01:00
55 changed files with 827 additions and 1091 deletions

View File

@ -52,7 +52,10 @@ export const addActivity = form => dispatch =>
}
dispatch(setLoading(false))
})
.catch(error => dispatch(setError(`activities|${error}`)))
.catch(error => {
dispatch(setLoading(false))
dispatch(setError(`activities|${error}`))
})
export const addActivityWithoutGpx = form => dispatch =>
FitTrackeeGenericApi.addData('activities/no_gpx', form)
@ -154,7 +157,10 @@ export const editActivity = form => dispatch =>
}
dispatch(setLoading(false))
})
.catch(error => dispatch(setError(`activities|${error}`)))
.catch(error => {
dispatch(setLoading(false))
dispatch(setError(`activities|${error}`))
})
export const getMoreActivities = params => dispatch =>
FitTrackeeGenericApi.getData('activities', params)

View File

@ -28,14 +28,15 @@ export const updateSportsData = data => ({
type: 'UPDATE_SPORT_DATA',
data,
})
export const getOrUpdateData = (
action,
target,
data,
canDispatch = true
) => dispatch => {
dispatch(setLoading(true))
if (data && data.id && isNaN(data.id)) {
dispatch(setLoading(false))
return dispatch(setError(`${target}|Incorrect id`))
}
dispatch(setError(''))
@ -50,8 +51,12 @@ export const getOrUpdateData = (
} else {
dispatch(setError(`${target}|${ret.message || ret.status}`))
}
dispatch(setLoading(false))
})
.catch(error => {
dispatch(setLoading(false))
dispatch(setError(`${target}|${error}`))
})
.catch(error => dispatch(setError(`${target}|${error}`)))
}
export const addData = (target, data) => dispatch =>

View File

@ -7,7 +7,7 @@ import { getDateWithTZ } from '../../utils'
export default class ActivitiesList extends React.PureComponent {
render() {
const { activities, sports, t, user } = this.props
const { activities, loading, sports, t, user } = this.props
return (
<div className="card activity-card">
<div className="card-body">
@ -24,7 +24,8 @@ export default class ActivitiesList extends React.PureComponent {
</tr>
</thead>
<tbody>
{sports &&
{!loading &&
sports &&
activities.map((activity, idx) => (
// eslint-disable-next-line react/no-array-index-key
<tr key={idx}>
@ -61,6 +62,7 @@ export default class ActivitiesList extends React.PureComponent {
))}
</tbody>
</table>
{loading && <div className="loader" />}
</div>
</div>
)

View File

@ -38,6 +38,7 @@ class Activities extends React.Component {
render() {
const {
activities,
loading,
loadActivities,
loadMoreActivities,
message,
@ -71,6 +72,7 @@ class Activities extends React.Component {
<div className="col-md-9 activities-result">
<ActivitiesList
activities={activities}
loading={loading}
sports={sports}
t={t}
user={user}
@ -101,6 +103,7 @@ export default withTranslation()(
connect(
state => ({
activities: state.activities.data,
loading: state.loading,
message: state.message,
sports: state.sports.data,
user: state.user,

View File

@ -364,12 +364,12 @@ label {
.loader {
animation: spin 2s linear infinite;
border: 16px solid #f3f3f3;
border-top: 16px solid #3498db;
border: 8px solid #f3f3f3;
border-top: 8px solid #3498db;
border-radius: 50%;
height: 120px;
height: 60px;
margin-left: 41%;
width: 120px;
width: 60px;
}
@keyframes spin {

View File

@ -1,6 +1,6 @@
import React from 'react'
import { connect } from 'react-redux'
import { Redirect, Route, Switch } from 'react-router-dom'
import { Route, Switch } from 'react-router-dom'
import './App.css'
import Admin from './Admin'
@ -16,7 +16,6 @@ import ProfileEdit from './User/ProfileEdit'
import Statistics from './Statistics'
import UserForm from './User/UserForm'
import { getAppData } from '../actions/application'
import { isLoggedIn } from '../utils'
class App extends React.Component {
constructor(props) {
@ -32,59 +31,24 @@ class App extends React.Component {
<div className="App">
<NavBar />
<Switch>
<Route
exact
path="/"
render={() =>
isLoggedIn() ? <Dashboard /> : <Redirect to="/login" />
}
/>
<Route exact path="/" component={Dashboard} />
<Route
exact
path="/register"
render={() =>
isLoggedIn() ? (
<Redirect to="/" />
) : (
<UserForm formType={'register'} />
)
}
render={() => <UserForm formType={'register'} />}
/>
<Route
exact
path="/login"
render={() =>
isLoggedIn() ? (
<Redirect to="/" />
) : (
<UserForm formType={'login'} />
)
}
render={() => <UserForm formType={'login'} />}
/>
<Route exact path="/logout" component={Logout} />
<Route
exact
path="/profile/edit"
render={() =>
isLoggedIn() ? <ProfileEdit /> : <UserForm formType={'login'} />
}
/>
<Route
exact
path="/profile"
render={() =>
isLoggedIn() ? <Profile /> : <UserForm formType={'login'} />
}
/>
<Route exact path="/profile/edit" component={ProfileEdit} />
<Route exact path="/profile" component={Profile} />
<Route exact path="/activities/history" component={Activities} />
<Route exact path="/activities/statistics" component={Statistics} />
<Route path="/activities" component={Activity} />
<Route
path="/admin"
render={() =>
isLoggedIn() ? <Admin /> : <UserForm formType={'login'} />
}
/>
<Route path="/admin" component={Admin} />
<Route component={NotFound} />
</Switch>
<Footer />

View File

@ -13,8 +13,9 @@ import Root from './components/Root'
import registerServiceWorker from './registerServiceWorker'
import createRootReducer from './reducers'
import { loadProfile } from './actions/user'
import { historyEnhancer } from './utils/history'
export const history = createBrowserHistory()
export const history = historyEnhancer(createBrowserHistory())
history.listen(() => {
window.scrollTo(0, 0)

View File

@ -18,6 +18,8 @@ const handleDataAndError = (state, type, action) => {
const activities = (state = initial.activities, action) => {
switch (action.type) {
case 'LOGOUT':
return initial.activities
case 'PUSH_ACTIVITIES':
return {
...state,
@ -50,13 +52,17 @@ const application = (state = initial.application, action) => {
}
const calendarActivities = (state = initial.calendarActivities, action) => {
if (action.type === 'UPDATE_CALENDAR') {
return {
...state,
data: action.activities,
}
switch (action.type) {
case 'LOGOUT':
return initial.calendarActivities
case 'UPDATE_CALENDAR':
return {
...state,
data: action.activities,
}
default:
return handleDataAndError(state, 'calendarActivities', action)
}
return handleDataAndError(state, 'calendarActivities', action)
}
const chartData = (state = initial.chartData, action) => {
@ -118,8 +124,12 @@ const messages = (state = initial.messages, action) => {
}
}
const records = (state = initial.records, action) =>
handleDataAndError(state, 'records', action)
const records = (state = initial.records, action) => {
if (action.type === 'LOGOUT') {
return initial.records
}
return handleDataAndError(state, 'records', action)
}
const sports = (state = initial.sports, action) => {
if (action.type === 'UPDATE_SPORT_DATA') {
@ -150,8 +160,12 @@ const user = (state = initial.user, action) => {
}
}
const statistics = (state = initial.statistics, action) =>
handleDataAndError(state, 'statistics', action)
const statistics = (state = initial.statistics, action) => {
if (action.type === 'LOGOUT') {
return initial.statistics
}
return handleDataAndError(state, 'statistics', action)
}
export default history =>
combineReducers({

View File

@ -0,0 +1,35 @@
const updatePath = (toPath, newPath) => {
if (typeof toPath === 'string' || toPath instanceof String) {
toPath = newPath
} else {
toPath.pathname = newPath
}
return toPath
}
const pathInterceptor = toPath => {
if (
!window.localStorage.authToken &&
!['/login', '/register'].includes(toPath.pathname)
) {
toPath = updatePath(toPath, '/login')
}
if (
window.localStorage.authToken &&
['/login', '/register'].includes(toPath.pathname)
) {
toPath = updatePath(toPath, '/')
}
return toPath
}
export const historyEnhancer = originalHistory => {
originalHistory.location = pathInterceptor(originalHistory.location)
return {
...originalHistory,
push: (path, ...args) =>
originalHistory.push(pathInterceptor(path), ...args),
replace: (path, ...args) =>
originalHistory.replace(pathInterceptor(path), ...args),
}
}

View File

@ -15,7 +15,7 @@ export const getFileSizeInMB = fileSize => {
return (!fileSize && 0) || +value.toFixed(2)
}
export const version = '0.2.4-beta' // version stored in 'utils' for now
export const version = '0.2.5-beta' // version stored in 'utils' for now
export const apiUrl = `${process.env.REACT_APP_API_URL}/api/`
/* prettier-ignore */
export const thunderforestApiKey = `${