Api & Client: add an activity
This commit is contained in:
		@@ -95,6 +95,7 @@ def post_activity(auth_user_id):
 | 
			
		||||
        new_activity.ascent = gpx_data['uphill']
 | 
			
		||||
        new_activity.max_speed = gpx_data['max_speed']
 | 
			
		||||
        new_activity.ave_speed = gpx_data['average_speed']
 | 
			
		||||
        db.session.add(new_activity)
 | 
			
		||||
        db.session.commit()
 | 
			
		||||
 | 
			
		||||
        response_object = {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								mpwo_client/src/actions/activities.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								mpwo_client/src/actions/activities.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
import mpwoApi from '../mwpoApi/activities'
 | 
			
		||||
import { history } from '../index'
 | 
			
		||||
import { setError } from './index'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export function addActivity(form) {
 | 
			
		||||
  return function(dispatch) {
 | 
			
		||||
    return mpwoApi
 | 
			
		||||
    .addActivity(form)
 | 
			
		||||
    .then(ret => {
 | 
			
		||||
      if (ret.status === 'created') {
 | 
			
		||||
        history.push('/')
 | 
			
		||||
      } else {
 | 
			
		||||
        dispatch(setError(`activities: ${ret.message}`))
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
    .catch(error => dispatch(setError(`activities: ${error}`)))
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										114
									
								
								mpwo_client/src/components/Activities/AddActivity.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								mpwo_client/src/components/Activities/AddActivity.jsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,114 @@
 | 
			
		||||
import React from 'react'
 | 
			
		||||
import { Helmet } from 'react-helmet'
 | 
			
		||||
import { connect } from 'react-redux'
 | 
			
		||||
 | 
			
		||||
import { addActivity } from '../../actions/activities'
 | 
			
		||||
import { getData } from '../../actions/index'
 | 
			
		||||
import { history } from '../../index'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AddActivity extends React.Component {
 | 
			
		||||
  componentDidMount() {
 | 
			
		||||
      this.props.loadSports()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  render() {
 | 
			
		||||
    const { message, onAddSport, sports } = this.props
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
      <div>
 | 
			
		||||
        <Helmet>
 | 
			
		||||
          <title>mpwo - Add an activity</title>
 | 
			
		||||
        </Helmet>
 | 
			
		||||
        <br /><br />
 | 
			
		||||
        {message && (
 | 
			
		||||
          <code>{message}</code>
 | 
			
		||||
        )}
 | 
			
		||||
 | 
			
		||||
        <div className="container">
 | 
			
		||||
          <div className="row">
 | 
			
		||||
            <div className="col-md-2" />
 | 
			
		||||
            <div className="col-md-8">
 | 
			
		||||
              <div className="card add-activity">
 | 
			
		||||
                <h2 className="card-header text-center">
 | 
			
		||||
                  Add a sport
 | 
			
		||||
                </h2>
 | 
			
		||||
                <div className="card-body">
 | 
			
		||||
                  <form
 | 
			
		||||
                    encType="multipart/form-data"
 | 
			
		||||
                    method="post"
 | 
			
		||||
                    onSubmit={event => event.preventDefault()}
 | 
			
		||||
                  >
 | 
			
		||||
                    <div className="form-group">
 | 
			
		||||
                      <label>
 | 
			
		||||
                        Sport:
 | 
			
		||||
                        <select
 | 
			
		||||
                          className="form-control input-lg"
 | 
			
		||||
                          name="sport"
 | 
			
		||||
                          required
 | 
			
		||||
                        >
 | 
			
		||||
                          <option value="" />
 | 
			
		||||
                          {sports.map(sport => (
 | 
			
		||||
                            <option key={sport.id} value={sport.id}>
 | 
			
		||||
                              {sport.label}
 | 
			
		||||
                            </option>
 | 
			
		||||
                          ))}
 | 
			
		||||
                        </select>
 | 
			
		||||
                      </label>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div className="form-group">
 | 
			
		||||
                      <label>
 | 
			
		||||
                        GPX file:
 | 
			
		||||
                        <input
 | 
			
		||||
                          accept=".gpx"
 | 
			
		||||
                          className="form-control input-lg"
 | 
			
		||||
                          name="gpxFile"
 | 
			
		||||
                          required
 | 
			
		||||
                          type="file"
 | 
			
		||||
                        />
 | 
			
		||||
                      </label>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <input
 | 
			
		||||
                      type="submit"
 | 
			
		||||
                      className="btn btn-primary btn-lg btn-block"
 | 
			
		||||
                      onClick={event => onAddSport(event)}
 | 
			
		||||
                      value="Submit"
 | 
			
		||||
                    />
 | 
			
		||||
                    <input
 | 
			
		||||
                      type="submit"
 | 
			
		||||
                      className="btn btn-secondary btn-lg btn-block"
 | 
			
		||||
                      onClick={() => history.go(-1)}
 | 
			
		||||
                      value="Cancel"
 | 
			
		||||
                    />
 | 
			
		||||
                  </form>
 | 
			
		||||
                </div>
 | 
			
		||||
              </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div className="col-md-2" />
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default connect(
 | 
			
		||||
  state => ({
 | 
			
		||||
    message: state.message,
 | 
			
		||||
    sports: state.sports.data,
 | 
			
		||||
    user: state.user,
 | 
			
		||||
  }),
 | 
			
		||||
  dispatch => ({
 | 
			
		||||
    loadSports: () => {
 | 
			
		||||
      dispatch(getData('sports'))
 | 
			
		||||
    },
 | 
			
		||||
    onAddSport: event => {
 | 
			
		||||
      const form = new FormData()
 | 
			
		||||
      form.append('file', event.target.form.gpxFile.files[0])
 | 
			
		||||
      form.append(
 | 
			
		||||
        'data', `{"sport_id": ${event.target.form.sport.value}}`
 | 
			
		||||
      )
 | 
			
		||||
      dispatch(addActivity(form))
 | 
			
		||||
    },
 | 
			
		||||
  })
 | 
			
		||||
)(AddActivity)
 | 
			
		||||
@@ -56,3 +56,7 @@ input, textarea {
 | 
			
		||||
  margin: 1em;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.add-activity {
 | 
			
		||||
  margin-top: 50px;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@ import { Redirect, Route, Switch } from 'react-router-dom'
 | 
			
		||||
 | 
			
		||||
import './App.css'
 | 
			
		||||
import Admin from './Admin'
 | 
			
		||||
import AddWorkout from './Activities/AddActivity'
 | 
			
		||||
import Dashboard from './Dashboard'
 | 
			
		||||
import Logout from './User/Logout'
 | 
			
		||||
import NavBar from './NavBar'
 | 
			
		||||
@@ -83,6 +84,7 @@ export default class App extends React.Component {
 | 
			
		||||
              )
 | 
			
		||||
            )}
 | 
			
		||||
          />
 | 
			
		||||
          <Route exact path="/activities/add" component={AddWorkout} />
 | 
			
		||||
          <Route path="/admin" component={Admin} />
 | 
			
		||||
          <Route component={NotFound} />
 | 
			
		||||
        </Switch>
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,18 @@ function NavBar (props) {
 | 
			
		||||
                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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								mpwo_client/src/mwpoApi/activities.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								mpwo_client/src/mwpoApi/activities.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
import { apiUrl } from '../utils'
 | 
			
		||||
 | 
			
		||||
export default class MpwoApi {
 | 
			
		||||
 | 
			
		||||
  static addActivity(formData) {
 | 
			
		||||
    const request = new Request(`${apiUrl}activities`, {
 | 
			
		||||
      method: 'POST',
 | 
			
		||||
      headers: new Headers({
 | 
			
		||||
        Authorization: `Bearer ${window.localStorage.getItem('authToken')}`,
 | 
			
		||||
      }),
 | 
			
		||||
      body: formData,
 | 
			
		||||
    })
 | 
			
		||||
    return fetch(request)
 | 
			
		||||
      .then(response => response.json())
 | 
			
		||||
      .catch(error => error)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user