Skip to content

Commit

Permalink
[candidate_parameters] Add 'Date of Birth' tab (#4915)
Browse files Browse the repository at this point in the history
Add a tab to the candidate parameter's page to allow users with appropriate permissions to modify the candidate's date of birth.
  • Loading branch information
jesscall authored Feb 4, 2020
1 parent 694d8dc commit d4dafd1
Show file tree
Hide file tree
Showing 8 changed files with 242 additions and 2 deletions.
3 changes: 2 additions & 1 deletion SQL/0000-00-01-Permission.sql
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ INSERT INTO `permissions` VALUES
(53,'instrument_manager_write', 'Instrument Manager: Install new instruments via file upload', 2),
(54,'publication_view', 'Publication - Access to module', 2),
(55,'publication_propose', 'Publication - Propose a project', 2),
(56,'publication_approve', 'Publication - Approve or reject proposed publication projects', 2);
(56,'publication_approve', 'Publication - Approve or reject proposed publication projects', 2),
(57, 'candidate_dob_edit', 'Edit dates of birth', 2);


INSERT INTO `user_perm_rel` (userID, permID)
Expand Down
5 changes: 5 additions & 0 deletions SQL/New_patches/2019_07_02_Add_Edit_DoB_Permissions.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
INSERT INTO permissions (code, description, categoryID) VALUES
("candidate_dob_edit","Edit dates of birth",2);

INSERT INTO user_perm_rel VALUES
(1, (SELECT permID FROM permissions WHERE code='candidate_dob_edit'));
3 changes: 2 additions & 1 deletion jsx/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -1424,7 +1424,7 @@ class StaticElement extends Component {
{this.props.label}
</label>
<div className="col-sm-9">
<p className="form-control-static">{this.props.text}</p>
<p className={this.props.class}>{this.props.text}</p>
</div>
</div>
);
Expand All @@ -1442,6 +1442,7 @@ StaticElement.propTypes = {
StaticElement.defaultProps = {
label: '',
text: null,
class: 'form-control-static',
};

/**
Expand Down
33 changes: 33 additions & 0 deletions modules/candidate_parameters/ajax/formHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
editConsentStatusFields($db, $user);
break;

case 'candidateDOB':
editCandidateDOB($db, $user);
break;

default:
header("HTTP/1.1 404 Not Found");
exit;
Expand Down Expand Up @@ -525,3 +529,32 @@ function editConsentStatusFields($db, $user)
}
}
}

/**
* Handles the updating of candidate's date of birth.
*
* @param Database $db database object
* @param User $user user object
*
* @throws DatabaseException
*
* @return void
*/
function editCandidateDOB(\Database $db, \User $user): void
{
$candID = new CandID($_POST['candID']);
$dob = $_POST['dob'];
$strippedDate = null;
if (!empty($dob)) {
$config = \NDB_Config::singleton();
$dobFormat = $config->getSetting('dobFormat');
if ($dobFormat === 'YM') {
$strippedDate = date("Y-m", strtotime($dob))."-01";
}
$db->update(
'candidate',
array('DoB' => $strippedDate ?? $dob),
array('CandID' => $candID->__toString())
);
}
}
27 changes: 27 additions & 0 deletions modules/candidate_parameters/ajax/getData.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
case 'consentStatus':
echo json_encode(getConsentStatusFields());
exit;
case 'candidateDOB':
echo json_encode(getDOBFields());
exit;
default:
header("HTTP/1.1 404 Not Found");
exit;
Expand Down Expand Up @@ -492,3 +495,27 @@ function getConsentStatusHistory($pscid)
}
return $formattedHistory;
}

/**
* Handles the fetching of candidate's date of birth.
*
* @return array
*/
function getDOBFields(): array
{
$candID = new CandID($_GET['candID']);
$db = \Database::singleton();
// Get PSCID
$candidateData = $db->pselectRow(
'SELECT PSCID,DoB FROM candidate where CandID =:candid',
array('candid' => $candID->__toString())
);
$pscid = $candidateData['PSCID'] ?? null;
$dob = $candidateData['DoB'] ?? null;
$result = [
'pscid' => $pscid,
'candID' => $candID->__toString(),
'dob' => $dob,
];
return $result;
}
170 changes: 170 additions & 0 deletions modules/candidate_parameters/jsx/CandidateDOB.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Loader from 'Loader';

class CandidateDOB extends Component {
constructor(props) {
super(props);

this.state = {
data: {},
formData: {
dob: null,
},
error: false,
isLoaded: false,
};

this.fetchData = this.fetchData.bind(this);
this.setFormData = this.setFormData.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}

componentDidMount() {
this.fetchData()
.then(() => this.setState({isLoaded: true}));
}

fetchData() {
return fetch(this.props.dataURL, {credentials: 'same-origin'})
.then((resp) => resp.json())
.then((data) => this.setState({data: data, formData: data}))
.catch((error) => {
this.setState({error: true});
console.error(error);
});
}

setFormData(formElement, value) {
let formData = this.state.formData;
formData[formElement] = value;
this.setState({
formData: formData,
});
}

render() {
if (this.state.error) {
return <h3>An error occured while loading the page.</h3>;
}

if (!this.state.isLoaded) {
return <Loader/>;
}

let disabled = true;
let updateButton = null;
if (loris.userHasPermission('candidate_dob_edit')) {
disabled = false;
updateButton = <ButtonElement label='Update' />;
}
return (
<div className='row'>
<FormElement
name='candidateDOB'
onSubmit={this.handleSubmit}
ref='form'
class='col-md-6'
>
<StaticElement
label='PSCID'
text={this.state.data.pscid}
/>
<StaticElement
label='DCCID'
text={this.state.data.candID}
/>
<StaticElement
label='Disclaimer:'
text='Any changes to the date of birth requires an administrator to run the fix_candidate_age script.'
class='form-control-static text-danger bg-danger col-sm-10'
/>
<DateElement
label='Date Of Birth:'
name='dob'
value={this.state.formData.dob}
onUserInput={this.setFormData}
disabled={disabled}
required={true}
/>
{updateButton}
</FormElement>
</div>
);
}

/**
* Handles form submission
*
* @param {event} e - Form submission event
*/
handleSubmit(e) {
e.preventDefault();

let today = new Date();
let dd = String(today.getDate()).padStart(2, '0');
let mm = String(today.getMonth() + 1).padStart(2, '0'); // January is 0!
let yyyy = today.getFullYear();
today = yyyy + '-' + mm + '-' + dd;

let dob = this.state.formData.dob ?
this.state.formData.dob : null;
if (dob > today) {
swal({
title: 'Error!',
text: 'Date of birth cannot be later than today!',
type: 'error',
confrimButtonText: 'OK',
});
return;
}
// Set form data and upload the media file
let formData = this.state.formData;
let formObject = new FormData();
for (let key in formData) {
if (formData.hasOwnProperty(key)) {
if (formData[key] !== '') {
formObject.append(key, formData[key]);
}
}
}

formObject.append('tab', this.props.tabName);

fetch(this.props.action, {
method: 'POST',
cache: 'no-cache',
credentials: 'same-origin',
body: formObject,
})
.then((resp) => {
if (resp.ok && resp.status === 200) {
swal({
title: 'Success!',
text: 'Date of birth updated!',
type: 'success',
confrimButtonText: 'OK',
});
if (result.value) {
this.fetchData();
}
} else {
swal({
title: 'Error!',
text: 'Something went wrong.',
type: 'error',
confrimButtonText: 'OK',
});
}
})
.catch((error) => {
console.error(error);
});
}
}
CandidateDOB.propTypes = {
dataURL: PropTypes.string,
tabName: PropTypes.string,
action: PropTypes.string,
};
export default CandidateDOB;
2 changes: 2 additions & 0 deletions modules/candidate_parameters/jsx/CandidateParameters.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ProbandInfo from './ProbandInfo';
import FamilyInfo from './FamilyInfo';
import ParticipantStatus from './ParticipantStatus';
import ConsentStatus from './ConsentStatus';
import CandidateDOB from './CandidateDOB';
import {Tabs, TabPane} from 'Tabs';

class CandidateParameters extends Component {
Expand Down Expand Up @@ -35,6 +36,7 @@ class CandidateParameters extends Component {
let tabList = [
{id: 'candidateInfo', label: 'Candidate Information', component: CandidateInfo},
{id: 'participantStatus', label: 'Participant Status', component: ParticipantStatus},
{id: 'candidateDOB', label: 'Date of Birth', component: CandidateDOB},
];

if (loris.config('useProband') === 'true') {
Expand Down
1 change: 1 addition & 0 deletions raisinbread/RB_files/RB_permissions.sql
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,6 @@ INSERT INTO `permissions` (`permID`, `code`, `description`, `categoryID`) VALUES
INSERT INTO `permissions` (`permID`, `code`, `description`, `categoryID`) VALUES (54,'publication_propose','Publication - Propose a project',2);
INSERT INTO `permissions` (`permID`, `code`, `description`, `categoryID`) VALUES (55,'publication_approve','Publication - Approve or reject proposed publication projects',2);
INSERT INTO `permissions` (`permID`, `code`, `description`, `categoryID`) VALUES (56,'data_release_view','Data Release: View releases',2);
INSERT INTO `permissions` (`permID`, `code`, `description`, `categoryID`) VALUES (57,'candidate_dob_edit','Edit dates of birth',2);
UNLOCK TABLES;
SET FOREIGN_KEY_CHECKS=1;

0 comments on commit d4dafd1

Please sign in to comment.