Client: upload a zip archive containing gpx files

This commit is contained in:
Sam 2018-05-29 20:08:34 +02:00
parent 373d20f0b7
commit bddb86d765
7 changed files with 87 additions and 24 deletions

View File

@ -2,7 +2,7 @@ import mpwoGenericApi from '../mwpoApi'
import mpwoApi from '../mwpoApi/activities'
import { history } from '../index'
import { formatChartData } from '../utils'
import { setError } from './index'
import { setError, setLoading } from './index'
export const pushActivities = activities => ({
type: 'PUSH_ACTIVITIES',
@ -23,10 +23,17 @@ export const addActivity = form => dispatch => mpwoApi
.addActivity(form)
.then(ret => {
if (ret.status === 'created') {
history.push(`/activities/${ret.data.activities[0].id}`)
if (ret.data.activities.length === 0) {
dispatch(setError('activities: no correct file'))
} else if (ret.data.activities.length === 1) {
history.push(`/activities/${ret.data.activities[0].id}`)
} else { // ret.data.activities.length > 1
history.push('/')
}
} else {
dispatch(setError(`activities: ${ret.message}`))
}
dispatch(setLoading())
})
.catch(error => dispatch(setError(`activities: ${error}`)))
@ -97,6 +104,7 @@ export const editActivity = form => dispatch => mpwoGenericApi
} else {
dispatch(setError(`activities: ${ret.message}`))
}
dispatch(setLoading())
})
.catch(error => dispatch(setError(`activities: ${error}`)))

View File

@ -13,6 +13,10 @@ export const setError = message => ({
message,
})
export const setLoading = () => ({
type: 'SET_LOADING',
})
export const getData = (target, id = null, data = null) => dispatch => {
if (id !== null && isNaN(id)) {
return dispatch(setError(target, `${target}: Incorrect id`))

View File

@ -1,10 +1,11 @@
import React from 'react'
import { Helmet } from 'react-helmet'
import { connect } from 'react-redux'
import FormWithGpx from './ActivityForms/FormWithGpx'
import FormWithoutGpx from './ActivityForms/FormWithoutGpx'
export default class ActivityAddEdit extends React.Component {
class ActivityAddEdit extends React.Component {
constructor(props, context) {
super(props, context)
this.state = {
@ -21,7 +22,7 @@ export default class ActivityAddEdit extends React.Component {
}
render() {
const { activity, message, sports } = this.props
const { activity, loading, message, sports } = this.props
const { withGpx } = this.state
return (
<div>
@ -59,6 +60,7 @@ export default class ActivityAddEdit extends React.Component {
<input
type="radio"
name="withGpx"
disabled={loading}
checked={withGpx}
onChange={event => this.handleRadioChange(event)}
/>
@ -70,6 +72,7 @@ export default class ActivityAddEdit extends React.Component {
<input
type="radio"
name="withoutGpx"
disabled={loading}
checked={!withGpx}
onChange={event => this.handleRadioChange(event)}
/>
@ -96,3 +99,8 @@ export default class ActivityAddEdit extends React.Component {
}
}
export default connect(
state => ({
loading: state.loading
}),
)(ActivityAddEdit)

View File

@ -1,12 +1,15 @@
import React from 'react'
import { connect } from 'react-redux'
import { setLoading } from '../../../actions/index'
import { addActivity, editActivity } from '../../../actions/activities'
import { history } from '../../../index'
function FormWithGpx (props) {
const { activity, onAddActivity, onEditActivity, sports } = props
const {
activity, loading, onAddActivity, onEditActivity, sports
} = props
const sportId = activity ? activity.sport_id : ''
return (
<form
@ -20,6 +23,7 @@ function FormWithGpx (props) {
<select
className="form-control input-lg"
defaultValue={sportId}
disabled={loading}
name="sport"
required
>
@ -39,6 +43,7 @@ function FormWithGpx (props) {
<input
name="title"
defaultValue={activity ? activity.title : ''}
disabled={loading}
className="form-control input-lg"
/>
</label>
@ -46,10 +51,12 @@ function FormWithGpx (props) {
) : (
<div className="form-group">
<label>
GPX file:
<strong>gpx</strong> file or <strong>zip</strong>{' '}
file containing <strong>gpx</strong> (no folder inside):
<input
accept=".gpx"
accept=".gpx, .zip"
className="form-control input-lg"
disabled={loading}
name="gpxFile"
required
type="file"
@ -57,30 +64,39 @@ function FormWithGpx (props) {
</label>
</div>
)}
<input
type="submit"
className="btn btn-primary btn-lg btn-block"
onClick={
event => activity
? onEditActivity(event, activity)
: onAddActivity(event)
}
value="Submit"
/>
<input
type="submit"
className="btn btn-secondary btn-lg btn-block"
onClick={() => history.go(-1)}
value="Cancel"
/>
{loading ? (
<div className="loader" />
) : (
<div>
<input
type="submit"
className="btn btn-primary btn-lg btn-block"
onClick={
event => activity
? onEditActivity(event, activity)
: onAddActivity(event)
}
value="Submit"
/>
<input
type="submit"
className="btn btn-secondary btn-lg btn-block"
onClick={() => history.go(-1)}
value="Cancel"
/>
</div>
)}
</form>
)
}
export default connect(
() => ({ }),
state => ({
loading: state.loading
}),
dispatch => ({
onAddActivity: e => {
dispatch(setLoading())
const form = new FormData()
form.append('file', e.target.form.gpxFile.files[0])
form.append(
@ -89,6 +105,7 @@ export default connect(
dispatch(addActivity(form))
},
onEditActivity: (e, activity) => {
dispatch(setLoading())
dispatch(editActivity({
id: activity.id,
sport_id: +e.target.form.sport.value,

View File

@ -173,3 +173,18 @@ input, textarea {
.unlink {
color: black;
}
.loader {
animation: spin 2s linear infinite;
border: 16px solid #f3f3f3;
border-top: 16px solid #3498db;
border-radius: 50%;
height: 120px;
margin-left: 41%;
width: 120px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}

View File

@ -93,6 +93,15 @@ const gpx = (state = initial.gpx, action) => {
}
}
const loading = (state = initial.loading, action) => {
switch (action.type) {
case 'SET_LOADING':
return !state
default:
return state
}
}
const message = (state = initial.message, action) => {
switch (action.type) {
case 'AUTH_ERROR':
@ -176,6 +185,7 @@ const reducers = combineReducers({
formData,
formProfile,
gpx,
loading,
message,
messages,
records,

View File

@ -44,6 +44,7 @@ export default {
chartData: [],
// check if storing gpx content is OK
gpx: null,
loading: false,
records: {
...emptyData,
},