Skip to content

Commit

Permalink
[new_profile] Use API for candidate creation and swal for success (#7755
Browse files Browse the repository at this point in the history
)

This updates the candidate creation on the new profile page to
se the LORIS API instead of duplicating the logic in PHP. The form
already collects the exact data that a POST request to the API
requires, but submits it to a different endpoint in a form encoding
instead of a json encoding.

At the same time, the logic for the response is simplified by using
a swal instead of a (very empty looking) new page. swals are already
used for errors in the module, just not success. This change simplifies
both the code and the UX.
  • Loading branch information
driusan authored Oct 27, 2022
1 parent fe21f3a commit 3792d2a
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 330 deletions.
4 changes: 2 additions & 2 deletions modules/api/php/endpoints/candidates.class.inc
Original file line number Diff line number Diff line change
Expand Up @@ -210,8 +210,8 @@ class Candidates extends Endpoint implements \LORIS\Middleware\ETagCalculator
try {
$candid = \Candidate::createNew(
new \CenterID("$centerid"),
$data['Candidate']['DoB'],
$data['Candidate']['EDC'],
$data['Candidate']['DoB'] ?? null,
$data['Candidate']['EDC'] ?? null,
$sex,
$pscid,
$project->getId()
Expand Down
244 changes: 138 additions & 106 deletions modules/new_profile/jsx/NewProfileIndex.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ class NewProfileIndex extends React.Component {
this.state = {
configData: {},
formData: {},
newData: {},
isLoaded: false,
isCreated: false,
error: false,
submitDisabled: false,
};
Expand Down Expand Up @@ -83,46 +81,95 @@ class NewProfileIndex extends React.Component {
e.preventDefault();
const match = this.validateMatchDate();
if (!match) {
this.setState({
isCreated: false,
});
} else {
let formData = this.state.formData;
let formObject = new FormData();
for (let key in formData) {
if (formData[key] !== '') {
formObject.append(key, formData[key]);
}
}
formObject.append('fire_away', 'New Candidate');
return;
}
const formData = this.state.formData;
const configData = this.state.configData;

let candidateObject = {
'Candidate': {
'Project': configData.project[formData.project],
// 'PSCID' : conditionally included below
// 'EDC' : conditionally included below
'DoB': formData.dobDate,
'Sex': formData.sex,
'Site': configData.site[formData.site],
},
};

if (this.state.configData['edc'] === 'true') {
candidateObject.Candidate.EDC = formData.edc;
}
if (this.state.configData['pscidSet'] === 'true') {
candidateObject.Candidate.PSCID = formData.pscid;
}

// disable button to prevent form resubmission.
this.setState({submitDisabled: true});
// disable button to prevent form resubmission.
this.setState({submitDisabled: true});

fetch(this.props.submitURL, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
body: formObject,
})
.then((resp) => {
if (resp.ok && resp.status === 201) {
resp.json().then((data) => {
this.setState({newData: data});
this.setState({isCreated: true});
fetch(this.props.submitURL, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
body: JSON.stringify(candidateObject),
})
.then((resp) => {
if (resp.ok && resp.status === 201) {
resp.json().then((data) => {
swal.fire({
type: 'success',
title: 'New Candidate Created',
html: 'DCCID: ' + data.CandID + ' '
+ 'PSCID: ' + data.PSCID + ' ',
confirmButtonText: 'Access Profile',
// Repurpose "cancel" as "recruit another candidate".
// Use the same colour for both buttons, since one
// isn't more "right" than the other.
showCancelButton: true,
cancelButtonColor: '#3085d6',
cancelButtonText: 'Recruit another candidate',
}).then((result) => {
if (result.value === true) {
window.location.href = '/' + data.CandID;
} else {
this.setState({
formData: {},
submitDisabled: false,
});
}
});
} else {
resp.json().then((message) => {
// enable button for form resubmission.
this.setState({submitDisabled: false});
swal.fire('Error!', message.error, 'error');
} )
.catch((error) => {
swal.fire({
type: 'error',
title: 'Error!',
text: error,
});
}
})
.catch((error) => {
console.error(error);
console.error(error);
});
} else {
resp.json().then((message) => {
// enable button for form resubmission.
this.setState({submitDisabled: false});
swal.fire('Error!', message.error, 'error');
}).catch((error) => {
swal.fire({
type: 'error',
title: 'Error!',
text: error,
});
console.error(error);
});
}
})
.catch((error) => {
swal.fire({
type: 'error',
title: 'Error!',
text: error,
});
}
console.error(error);
});
}

/**
Expand Down Expand Up @@ -153,7 +200,6 @@ class NewProfileIndex extends React.Component {
if (!this.state.isLoaded) {
return <Loader/>;
}
let profile = null;
let edc = null;
let pscid = null;
let site = null;
Expand Down Expand Up @@ -213,73 +259,59 @@ class NewProfileIndex extends React.Component {
required = {true}
/>;
}
if (!this.state.isCreated) {
profile = (
<FormElement
name = "newProfileForm"
onSubmit = {this.handleSubmit}
>
<DateElement
name = "dobDate"
label = "Date of Birth"
minYear = {minYear}
maxYear = {dobMaxYear}
dateFormat = {dateFormat}
onUserInput = {this.setFormData}
value = {this.state.formData.dobDate}
required = {requireBirthDate}
/>
<DateElement
name = "dobDateConfirm"
label = "Date of Birth Confirm"
minYear = {minYear}
maxYear = {dobMaxYear}
dateFormat = {dateFormat}
onUserInput = {this.setFormData}
value = {this.state.formData.dobDateConfirm}
required = {requireBirthDate}
/>
{edc}
<SelectElement
name = "sex"
label = "Sex"
options = {this.state.configData.sex}
onUserInput = {this.setFormData}
value = {this.state.formData.sex}
required = {true}
/>
{site}
{pscid}
<SelectElement
name = "project"
label = "Project"
options = {this.state.configData.project}
onUserInput = {this.setFormData}
value = {this.state.formData.project}
required = {true}
/>
<ButtonElement
name = "fire_away"
label = "Create"
id = "button"
type = "submit"
disabled={this.state.submitDisabled}
/>
</FormElement>
);
} else {
profile = (
<div>
<p>{'New candidate created. '
+ 'DCCID: ' + this.state.newData.candID + ' '
+ 'PSCID: ' + this.state.newData.pscid + ' '}</p>
<p><a href = {'/' + this.state.newData.candID}>
Access this candidate
</a></p>
<p><a href = "/new_profile/" > Recruit another candidate </a></p>
</div>
);
}
const profile = (
<FormElement
name = "newProfileForm"
onSubmit = {this.handleSubmit}
>
<DateElement
name = "dobDate"
label = "Date of Birth"
minYear = {minYear}
maxYear = {dobMaxYear}
dateFormat = {dateFormat}
onUserInput = {this.setFormData}
value = {this.state.formData.dobDate}
required = {requireBirthDate}
/>
<DateElement
name = "dobDateConfirm"
label = "Date of Birth Confirm"
minYear = {minYear}
maxYear = {dobMaxYear}
dateFormat = {dateFormat}
onUserInput = {this.setFormData}
value = {this.state.formData.dobDateConfirm}
required = {requireBirthDate}
/>
{edc}
<SelectElement
name = "sex"
label = "Sex"
options = {this.state.configData.sex}
onUserInput = {this.setFormData}
value = {this.state.formData.sex}
required = {true}
/>
{site}
{pscid}
<SelectElement
name = "project"
label = "Project"
options = {this.state.configData.project}
onUserInput = {this.setFormData}
value = {this.state.formData.project}
required = {true}
/>
<ButtonElement
name = "fire_away"
label = "Create"
id = "button"
type = "submit"
disabled={this.state.submitDisabled}
/>
</FormElement>
);
return (
<FieldsetElement legend={'Create a New Profile'}>
{profile}
Expand All @@ -291,7 +323,7 @@ window.addEventListener('load', () => {
ReactDOM.render(
<NewProfileIndex
dataURL = {`${loris.BaseURL}/new_profile/?format=json`}
submitURL = {`${loris.BaseURL}/new_profile/`}
submitURL = {`${loris.BaseURL}/api/v0.0.3/candidates/`}
hasPermission = {loris.userHasPermission}
/>,
document.getElementById('lorisworkspace')
Expand Down
Loading

0 comments on commit 3792d2a

Please sign in to comment.