Skip to content

Commit 3792d2a

Browse files
authored
[new_profile] Use API for candidate creation and swal for success (#7755)
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.
1 parent fe21f3a commit 3792d2a

File tree

4 files changed

+143
-330
lines changed

4 files changed

+143
-330
lines changed

modules/api/php/endpoints/candidates.class.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@ class Candidates extends Endpoint implements \LORIS\Middleware\ETagCalculator
210210
try {
211211
$candid = \Candidate::createNew(
212212
new \CenterID("$centerid"),
213-
$data['Candidate']['DoB'],
214-
$data['Candidate']['EDC'],
213+
$data['Candidate']['DoB'] ?? null,
214+
$data['Candidate']['EDC'] ?? null,
215215
$sex,
216216
$pscid,
217217
$project->getId()

modules/new_profile/jsx/NewProfileIndex.js

Lines changed: 138 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ class NewProfileIndex extends React.Component {
1919
this.state = {
2020
configData: {},
2121
formData: {},
22-
newData: {},
2322
isLoaded: false,
24-
isCreated: false,
2523
error: false,
2624
submitDisabled: false,
2725
};
@@ -83,46 +81,95 @@ class NewProfileIndex extends React.Component {
8381
e.preventDefault();
8482
const match = this.validateMatchDate();
8583
if (!match) {
86-
this.setState({
87-
isCreated: false,
88-
});
89-
} else {
90-
let formData = this.state.formData;
91-
let formObject = new FormData();
92-
for (let key in formData) {
93-
if (formData[key] !== '') {
94-
formObject.append(key, formData[key]);
95-
}
96-
}
97-
formObject.append('fire_away', 'New Candidate');
84+
return;
85+
}
86+
const formData = this.state.formData;
87+
const configData = this.state.configData;
88+
89+
let candidateObject = {
90+
'Candidate': {
91+
'Project': configData.project[formData.project],
92+
// 'PSCID' : conditionally included below
93+
// 'EDC' : conditionally included below
94+
'DoB': formData.dobDate,
95+
'Sex': formData.sex,
96+
'Site': configData.site[formData.site],
97+
},
98+
};
99+
100+
if (this.state.configData['edc'] === 'true') {
101+
candidateObject.Candidate.EDC = formData.edc;
102+
}
103+
if (this.state.configData['pscidSet'] === 'true') {
104+
candidateObject.Candidate.PSCID = formData.pscid;
105+
}
98106

99-
// disable button to prevent form resubmission.
100-
this.setState({submitDisabled: true});
107+
// disable button to prevent form resubmission.
108+
this.setState({submitDisabled: true});
101109

102-
fetch(this.props.submitURL, {
103-
method: 'POST',
104-
cache: 'no-cache',
105-
credentials: 'same-origin',
106-
body: formObject,
107-
})
108-
.then((resp) => {
109-
if (resp.ok && resp.status === 201) {
110-
resp.json().then((data) => {
111-
this.setState({newData: data});
112-
this.setState({isCreated: true});
110+
fetch(this.props.submitURL, {
111+
method: 'POST',
112+
cache: 'no-cache',
113+
credentials: 'same-origin',
114+
body: JSON.stringify(candidateObject),
115+
})
116+
.then((resp) => {
117+
if (resp.ok && resp.status === 201) {
118+
resp.json().then((data) => {
119+
swal.fire({
120+
type: 'success',
121+
title: 'New Candidate Created',
122+
html: 'DCCID: ' + data.CandID + ' '
123+
+ 'PSCID: ' + data.PSCID + ' ',
124+
confirmButtonText: 'Access Profile',
125+
// Repurpose "cancel" as "recruit another candidate".
126+
// Use the same colour for both buttons, since one
127+
// isn't more "right" than the other.
128+
showCancelButton: true,
129+
cancelButtonColor: '#3085d6',
130+
cancelButtonText: 'Recruit another candidate',
131+
}).then((result) => {
132+
if (result.value === true) {
133+
window.location.href = '/' + data.CandID;
134+
} else {
135+
this.setState({
136+
formData: {},
137+
submitDisabled: false,
138+
});
139+
}
113140
});
114-
} else {
115-
resp.json().then((message) => {
116-
// enable button for form resubmission.
117-
this.setState({submitDisabled: false});
118-
swal.fire('Error!', message.error, 'error');
141+
} )
142+
.catch((error) => {
143+
swal.fire({
144+
type: 'error',
145+
title: 'Error!',
146+
text: error,
119147
});
120-
}
121-
})
122-
.catch((error) => {
123-
console.error(error);
148+
console.error(error);
149+
});
150+
} else {
151+
resp.json().then((message) => {
152+
// enable button for form resubmission.
153+
this.setState({submitDisabled: false});
154+
swal.fire('Error!', message.error, 'error');
155+
}).catch((error) => {
156+
swal.fire({
157+
type: 'error',
158+
title: 'Error!',
159+
text: error,
160+
});
161+
console.error(error);
162+
});
163+
}
164+
})
165+
.catch((error) => {
166+
swal.fire({
167+
type: 'error',
168+
title: 'Error!',
169+
text: error,
124170
});
125-
}
171+
console.error(error);
172+
});
126173
}
127174

128175
/**
@@ -153,7 +200,6 @@ class NewProfileIndex extends React.Component {
153200
if (!this.state.isLoaded) {
154201
return <Loader/>;
155202
}
156-
let profile = null;
157203
let edc = null;
158204
let pscid = null;
159205
let site = null;
@@ -213,73 +259,59 @@ class NewProfileIndex extends React.Component {
213259
required = {true}
214260
/>;
215261
}
216-
if (!this.state.isCreated) {
217-
profile = (
218-
<FormElement
219-
name = "newProfileForm"
220-
onSubmit = {this.handleSubmit}
221-
>
222-
<DateElement
223-
name = "dobDate"
224-
label = "Date of Birth"
225-
minYear = {minYear}
226-
maxYear = {dobMaxYear}
227-
dateFormat = {dateFormat}
228-
onUserInput = {this.setFormData}
229-
value = {this.state.formData.dobDate}
230-
required = {requireBirthDate}
231-
/>
232-
<DateElement
233-
name = "dobDateConfirm"
234-
label = "Date of Birth Confirm"
235-
minYear = {minYear}
236-
maxYear = {dobMaxYear}
237-
dateFormat = {dateFormat}
238-
onUserInput = {this.setFormData}
239-
value = {this.state.formData.dobDateConfirm}
240-
required = {requireBirthDate}
241-
/>
242-
{edc}
243-
<SelectElement
244-
name = "sex"
245-
label = "Sex"
246-
options = {this.state.configData.sex}
247-
onUserInput = {this.setFormData}
248-
value = {this.state.formData.sex}
249-
required = {true}
250-
/>
251-
{site}
252-
{pscid}
253-
<SelectElement
254-
name = "project"
255-
label = "Project"
256-
options = {this.state.configData.project}
257-
onUserInput = {this.setFormData}
258-
value = {this.state.formData.project}
259-
required = {true}
260-
/>
261-
<ButtonElement
262-
name = "fire_away"
263-
label = "Create"
264-
id = "button"
265-
type = "submit"
266-
disabled={this.state.submitDisabled}
267-
/>
268-
</FormElement>
269-
);
270-
} else {
271-
profile = (
272-
<div>
273-
<p>{'New candidate created. '
274-
+ 'DCCID: ' + this.state.newData.candID + ' '
275-
+ 'PSCID: ' + this.state.newData.pscid + ' '}</p>
276-
<p><a href = {'/' + this.state.newData.candID}>
277-
Access this candidate
278-
</a></p>
279-
<p><a href = "/new_profile/" > Recruit another candidate </a></p>
280-
</div>
281-
);
282-
}
262+
const profile = (
263+
<FormElement
264+
name = "newProfileForm"
265+
onSubmit = {this.handleSubmit}
266+
>
267+
<DateElement
268+
name = "dobDate"
269+
label = "Date of Birth"
270+
minYear = {minYear}
271+
maxYear = {dobMaxYear}
272+
dateFormat = {dateFormat}
273+
onUserInput = {this.setFormData}
274+
value = {this.state.formData.dobDate}
275+
required = {requireBirthDate}
276+
/>
277+
<DateElement
278+
name = "dobDateConfirm"
279+
label = "Date of Birth Confirm"
280+
minYear = {minYear}
281+
maxYear = {dobMaxYear}
282+
dateFormat = {dateFormat}
283+
onUserInput = {this.setFormData}
284+
value = {this.state.formData.dobDateConfirm}
285+
required = {requireBirthDate}
286+
/>
287+
{edc}
288+
<SelectElement
289+
name = "sex"
290+
label = "Sex"
291+
options = {this.state.configData.sex}
292+
onUserInput = {this.setFormData}
293+
value = {this.state.formData.sex}
294+
required = {true}
295+
/>
296+
{site}
297+
{pscid}
298+
<SelectElement
299+
name = "project"
300+
label = "Project"
301+
options = {this.state.configData.project}
302+
onUserInput = {this.setFormData}
303+
value = {this.state.formData.project}
304+
required = {true}
305+
/>
306+
<ButtonElement
307+
name = "fire_away"
308+
label = "Create"
309+
id = "button"
310+
type = "submit"
311+
disabled={this.state.submitDisabled}
312+
/>
313+
</FormElement>
314+
);
283315
return (
284316
<FieldsetElement legend={'Create a New Profile'}>
285317
{profile}
@@ -291,7 +323,7 @@ window.addEventListener('load', () => {
291323
ReactDOM.render(
292324
<NewProfileIndex
293325
dataURL = {`${loris.BaseURL}/new_profile/?format=json`}
294-
submitURL = {`${loris.BaseURL}/new_profile/`}
326+
submitURL = {`${loris.BaseURL}/api/v0.0.3/candidates/`}
295327
hasPermission = {loris.userHasPermission}
296328
/>,
297329
document.getElementById('lorisworkspace')

0 commit comments

Comments
 (0)