Skip to content
This repository has been archived by the owner on May 28, 2018. It is now read-only.

Commit

Permalink
Drop application from applicant list
Browse files Browse the repository at this point in the history
  • Loading branch information
nbrohee committed Sep 6, 2017
1 parent 2820ff7 commit 48916d3
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
7 changes: 7 additions & 0 deletions client/src/actions/applicationActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ export function sendApplication() {
}
}

export function dropApplication(applicationId, reason) {
return (dispatch, getState) => {
const {user} = getState()
return applicationApi.dropApplication(applicationId, reason, user.token)
}
}

export function getPepiteApplication() {
return (dispatch, getState) => {
const {user} = getState()
Expand Down
14 changes: 14 additions & 0 deletions client/src/api/applicationApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ class applicationApi {
})
}

static dropApplication(id, reason, userToken) {
return axios.put(`/application/${id}/drop`, { dropReason: reason },
{
'headers': {
'Authorization': `Bearer ${userToken}`
}
})
.then((res) => {
const applicationResponse = res.data
return (Object.assign({}, applicationResponse, { id: applicationResponse._id }))
})
.catch((err) => { throw new Error(err) })
}

static getAllPepiteApplications(pepiteId, userToken) {
return axios.get(`/pepite/${pepiteId}/application`,
{
Expand Down
8 changes: 7 additions & 1 deletion client/src/components/pepite/Applicant/ApplicantPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as applicationActions from '../../../actions/applicationActions'
import * as pepiteListActions from '../../../actions/pepiteListActions'
import PepiteApplicantTable from './PepiteApplicantTable'
import PepiteAcceptedApplicantTable from './PepiteAcceptedApplicantTable'
import PepiteRefusedTable from './PepiteRefusedTable'
import Const from '../../common/Table/Const'

export class ApplicantPage extends React.Component {
Expand All @@ -17,7 +18,8 @@ export class ApplicantPage extends React.Component {
this.state = {
applications: [],
accepted: [],
refused: []
refused: [],
dropped: []
}
this.getPepiteApplicationXls = this.getPepiteApplicationXls.bind(this)
this.sortApplication = this.sortApplication.bind(this)
Expand All @@ -30,6 +32,7 @@ export class ApplicantPage extends React.Component {
applications: [...applications.filter((a) => a.status == 'sent')],
accepted: [...applications.filter((a) => a.status == 'accepted')],
refused: [...applications.filter((a) => a.status == 'refused')],
dropped: [...applications.filter((a) => a.status == 'dropped')]
})
})
.catch((err) => {
Expand Down Expand Up @@ -78,6 +81,9 @@ export class ApplicantPage extends React.Component {
<Tab eventKey={3} title={<div>Réfusées <span className="badge">{this.state.refused.length}</span></div>}>
<PepiteApplicantTable applicants={this.state.refused} sort={this.sortApplication('refused')} />
</Tab>
<Tab eventKey={4} title={<div>Abandonnées <span className="badge">{this.state.dropped.length}</span></div>}>
<PepiteRefusedTable applicants={this.state.refused} sort={this.sortApplication('dropped')} />
</Tab>
</Tabs>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React, { PropTypes } from 'react'
import { FormGroup, ControlLabel, Button } from 'react-bootstrap'
import ValidatedFormControl from '../../../common/ValidatedFormControl'
import ValidatedComponent from '../../../common/ValidatedComponent'
import Textarea from 'react-textarea-autosize'

const DropApplicationForm = ({reason, error, onChange, dropApplication}) => {
return (
<form>
<FormGroup className="required">
<ControlLabel>Raison de l'abandon</ControlLabel>
<ValidatedComponent error={error}>
<Textarea className="form-control" name="reason" rows={5} placeholder="raison" onChange={onChange} value={reason} />
</ValidatedComponent>
</FormGroup>
<Button bsStyle="danger" onClick={dropApplication}>Confirmer l'abandon</Button>
</form>
)
}

DropApplicationForm.propTypes = {
reason: PropTypes.object,
onChange: PropTypes.func.isRequired,
error: PropTypes.object,
dropApplication: PropTypes.func.isRequired
}

export default DropApplicationForm
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React, { PropTypes } from 'react'
import toastr from 'toastr'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'

import DropApplicationForm from './DropApplicationForm'
import * as applicationActions from '../../../../actions/applicationActions'

class DropApplicationPage extends React.Component {
constructor(props, context) {
super(props, context)
this.state = {
reason: '',
errors: ''
}
this.updateReason = this.updateReason.bind(this)
this.dropApplication = this.dropApplication.bind(this)
}

componentDidMount() {
if (this.props.applicationId) {
this.props.actions.loadApplication(this.props.applicationId).catch((err) => {
toastr.error(err)
})
}
}

updateReason(event) {
const reason = event.target.value
this.setState({
reason
})
}

dropApplication(event) {
event.preventDefault()
const reason = this.state.reason
if (reason || reason.length || reason.trim()) {
this.props.actions.dropApplication(this.props.applicationId, reason).then(() => {
toastr.success(`Candidature de ${this.props.applicantFullname} abandonnée`)
this.context.router.push('/pepite/applicant')
})
.catch((err) => {
toastr.error(err)
})
} else {
this.setState({
error: 'obligatoire'
})
}
}

render() {
return (
<div className="container back-content">
<div className="page-header">
<h1>Abandonner la candidature de {this.props.applicantFullname}</h1>
</div>
<DropApplicationForm
committeeAnswer={this.state.committeeAnswer}
onChange={this.updateReason}
errors={this.state.errors}
dropApplication={this.dropApplication} />
</div>
)
}
}

function mapStateToProps(state, ownProps) {
return {
applicationId: ownProps.params.id,
applicantFullname: `${state.contact.firstname} ${state.contact.name}`
}
}

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(applicationActions, dispatch),
}
}

DropApplicationPage.propTypes = {
actions: PropTypes.object.isRequired,
applicantFullname: PropTypes.string.isRequired,
applicationId: PropTypes.string
}

DropApplicationPage.contextTypes = {
router: React.PropTypes.object.isRequired
}

export default connect(mapStateToProps, mapDispatchToProps)(DropApplicationPage)
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const PepiteApplicantRow = ({ application }) => {
<td><GraduationLabel application={application} /></td>
<td><a className="btn btn-info btn-xs" target="_blank" href={`/application/${application._id}/print`}><Glyphicon glyph="print" /></a></td>
<td><Link to={`/pepite/committeeAnswer/${application._id}`} className="btn btn-info btn-xs"><Glyphicon glyph="edit" /></Link></td>
<td><Link to={`/pepite/dropApplication/${application._id}`} className="btn btn-danger btn-xs"><Glyphicon glyph="remove" /></Link></td>
<td><OtherApplicationLabel applicantId={application._id} /></td>
</tr>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export class PepiteApplicantTable extends React.Component {
<th>Statut</th>
<th>Version imprimable</th>
<th>Comité d'engagement</th>
<th>Abandon</th>
<th>Autres candidatures</th>
</tr>
</thead>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*global API_URI*/
import React, { PropTypes } from 'react'
import { Glyphicon } from 'react-bootstrap'
import GraduationLabel from './GraduationLabel'
import { Link } from 'react-router'

const PepiteRefusedApplicantRow = ({ application }) => {
return (
<tr>
<td>{application.contact.schoolYear}</td>
<td>{application.contact.name}</td>
<td>{application.contact.firstname}</td>
<td>{application.contact.email}</td>
<td>{application.career.diploma.establishment}</td>
<td><GraduationLabel application={application} /></td>
<td><a className="btn btn-info btn-xs" target="_blank" href={`/application/${application._id}/print`}><Glyphicon glyph="print" /></a></td>
</tr>
)
}

PepiteRefusedApplicantRow.propTypes = {
application: PropTypes.object.isRequired
}

export default PepiteRefusedApplicantRow
32 changes: 32 additions & 0 deletions client/src/components/pepite/Applicant/PepiteRefusedTable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React, { PropTypes } from 'react'
import { Glyphicon } from 'react-bootstrap'
import PepiteRefusedApplicantRow from './PepiteRefusedApplicantRow'
import TableHeader from '../../common/Table/TableHeader'

const PepiteRefusedTable = ({ applicants, sort }) => {
return (
<table className="table table-hover">
<thead>
<tr>
<TableHeader onSort={sort} field="contact.schoolYear">Promotion</TableHeader>
<TableHeader onSort={sort} field="contact.name">Nom</TableHeader>
<TableHeader onSort={sort} field="contact.firstname">Prénom</TableHeader>
<TableHeader onSort={sort} field="contact.email">Email</TableHeader>
<TableHeader onSort={sort} field="career.diploma.establishment">Établissement</TableHeader>
<th>Statut</th>
<th>Version imprimable</th>
</tr>
</thead>
<tbody>
{applicants.map((application, i) => { return (<PepiteRefusedApplicantRow key={i} application={application} />) })}
</tbody>
</table>
)
}

PepiteRefusedTable.propTypes = {
applicants: PropTypes.array.isRequired,
sort: PropTypes.func.isRequired
}

export default PepiteRefusedTable
5 changes: 5 additions & 0 deletions client/src/components/pepite/Applicant/StatusLabel.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ function statusToLabel(status) {
style: 'primary',
text: 'sauvegardé'
}
case 'dropped':
return {
style: 'warning',
text: 'abandon'
}
default:
return {
style: 'warning',
Expand Down
2 changes: 2 additions & 0 deletions client/src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import PrintPage from './components/application/PrintPage'
import LoginPage from './components/login/LoginPage'
import PepiteHomePage from './components/pepite/PepiteHomePage'
import CommitteeAnswerPage from './components/pepite/Applicant/CommitteeAnswer/CommitteeAnswerPage'
import DropApplicationPage from './components/pepite/Applicant/DropApplication/DropApplicationPage'
import ApplicantPage from './components/pepite/Applicant/ApplicantPage'
import CommitteePage from './components/pepite/Committee/CommitteePage'
import StudentPage from './components/pepite/Student/StudentPage'
Expand All @@ -30,6 +31,7 @@ export default (
<Route path="pepite/committee" component={CommitteePage} />
<Route path="pepite/student" component={StudentPage} />
<Route path="pepite/committeeAnswer/:id" component={CommitteeAnswerPage} />
<Route path="pepite/dropApplication/:id" component={DropApplicationPage} />
<Route path="admin" component={AdminPage} />
</Route>
<Route path="*" component={NotFound} />
Expand Down

0 comments on commit 48916d3

Please sign in to comment.