Skip to content

Commit

Permalink
Merge pull request #1596 from tidepool-org/UPLOAD-1132-mrn-validation
Browse files Browse the repository at this point in the history
[UPLOAD-1132] mrn validation
  • Loading branch information
krystophv authored Jan 23, 2024
2 parents 4ee9bfb + 61e871e commit 7412409
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 33 deletions.
115 changes: 101 additions & 14 deletions app/components/ClinicUserEdit.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,36 @@ function validateForm(values, props){
if(mrnRequired && !values.mrn){
errors.mrn = i18n.t('Patient\'s MRN is required');
}
// mrn needs to be uppercase alphanumeric between 6 and 25 characters
if(values.mrn && !/^[A-Z0-9]{6,25}$/.test(values.mrn)){
errors.mrn = (
<div>
{i18n.t('Patient’s MRN is invalid. MRN must meet the following criteria:')}
<ul>
<li>{i18n.t('All upper case letters or numbers')}</li>
<li>{i18n.t('Minimum length: 6 characters')}</li>
<li>{i18n.t('Maximum length: 25 characters')}</li>
<li>{i18n.t('No spaces')}</li>
</ul>
</div>
);
}
// mrn needs to be unique
if (values.mrn && props.selectedClinicId) {
var { targetId } = props;
var patients = _.get(
props.clinics,
[props.selectedClinicId, 'patients'],
{}
);
var filteredPatients = _.reject(patients, { id: targetId });
var mrnExists = _.find(filteredPatients, { mrn: values.mrn });
if (mrnExists) {
errors.mrn = i18n.t(
'This MRN is already in use. Please enter a valid MRN.'
);
}
}
return errors;
}

Expand Down Expand Up @@ -119,6 +149,57 @@ class ClinicUserEdit extends React.Component {
clinics: PropTypes.object.isRequired,
};

static defaultProps = {
searchDebounceMs: 1000,
};

constructor(props) {
super(props);
const { targetId, memberships, selectedClinicId, clinics } = props;
this.state = {
searchText: '',
updateTrigger: false,
isCustodialAccount: this.isCustodialAccount(memberships, targetId, selectedClinicId, clinics)
};
};

isCustodialAccount = (memberships, targetId, selectedClinicId, clinics) => {
return (
_.has(_.get(memberships, [targetId, 'permissions']), 'custodian') ||
(selectedClinicId &&
_.has(
_.get(clinics, [
selectedClinicId,
'patients',
targetId,
'permissions',
]),
'custodian'
))
);
};

componentDidUpdate(prevProps) {
const { targetId, memberships, selectedClinicId, clinics } = this.props;
if (
this.props.working.fetchingPatientsForClinic.inProgress === false &&
prevProps.working.fetchingPatientsForClinic.inProgress === true
) {
this.props.change('_forceValidation', Date.now());
}

if (this.props.targetId !== prevProps.targetId) {
this.setState({
isCustodialAccount: this.isCustodialAccount(
memberships,
targetId,
selectedClinicId,
clinics
)
});
}
};

handleCancel = () => {
if(this.props.working.creatingClinicCustodialAccount.notification) {
this.props.acknowledgeNotification();
Expand Down Expand Up @@ -174,6 +255,22 @@ class ClinicUserEdit extends React.Component {
}
};

handleSearchChange = () => _.debounce((e) => {
let searchText = e.target.value;
const {fetchPatientsForClinic, selectedClinicId, targetId} = this.props;
if(searchText !== this.state.searchText){
if(_.isEmpty(searchText)){
if(!targetId){
this.setState({searchText});
fetchPatientsForClinic(selectedClinicId);
}
} else {
this.setState({searchText});
fetchPatientsForClinic(selectedClinicId, {search: searchText});
}
}
}, this.props.searchDebounceMs);

renderCreateError = () => {
if (
this.props.createCustodialAccountErrorDismissed ||
Expand Down Expand Up @@ -286,23 +383,12 @@ class ClinicUserEdit extends React.Component {
};

render() {
const { handleSubmit, targetId, memberships, clinics, selectedClinicId } = this.props;
const isCustodialAccount =
_.has(_.get(memberships, [targetId, 'permissions']), 'custodian') ||
(selectedClinicId &&
_.has(
_.get(clinics, [
selectedClinicId,
'patients',
targetId,
'permissions',
]),
'custodian'
));
const { handleSubmit, targetId, clinics, selectedClinicId } = this.props;

const titleText = targetId
? i18n.t('Edit patient account')
: i18n.t('Create a new patient account');
const editable = targetId ? isCustodialAccount : true;
const editable = targetId ? this.state.isCustodialAccount : true;
const mrnRequired = _.get(
clinics,
[selectedClinicId, 'mrnSettings', 'required'],
Expand Down Expand Up @@ -346,6 +432,7 @@ class ClinicUserEdit extends React.Component {
name="mrn"
component={renderInput}
props={{ disabled: !editable }}
onChange={this.handleSearchChange()}
/>
</div>
<div className={styles.inputWrap}>
Expand Down
50 changes: 33 additions & 17 deletions app/containers/ClinicUserEditPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,46 @@ export class ClinicUserEditPage extends Component {
};

render() {
const { allUsers, uploadTargetUser, memberships } = this.props;
const {
allUsers,
uploadTargetUser,
memberships,
loggedInUser,
createCustodialAccountErrorMessage,
createCustodialAccountErrorDismissed,
updateProfileErrorMessage,
updateProfileErrorDismissed,
selectedClinicId,
clinics,
working,
async,
sync
} = this.props;

return (
<div>
<ClinicUserEdit
targetId={uploadTargetUser}
allUsers={allUsers}
memberships={memberships}
loggedInUser={this.props.loggedInUser}
createUser={this.props.async.createCustodialAccount}
createClinicUser={this.props.async.createClinicCustodialAccount}
updateUser={this.props.async.clickEditUserNext}
updateClinicPatient={this.props.async.clickClinicEditUserNext}
loggedInUser={loggedInUser}
createUser={async.createCustodialAccount}
createClinicUser={async.createClinicCustodialAccount}
updateUser={async.clickEditUserNext}
updateClinicPatient={async.clickClinicEditUserNext}
cancelEdit={_.partial(this.handleClickChangePerson, {metric: {eventName: metrics.CLINIC_ADD_CANCEL}})}
createCustodialAccountErrorMessage={this.props.createCustodialAccountErrorMessage}
createCustodialAccountErrorDismissed={this.props.createCustodialAccountErrorDismissed}
updateProfileErrorMessage={this.props.updateProfileErrorMessage}
updateProfileErrorDismissed={this.props.updateProfileErrorDismissed}
dismissCreateCustodialAccountError={this.props.sync.dismissCreateCustodialAccountError}
dismissUpdateProfileError={this.props.sync.dismissUpdateProfileError}
onSubmitFail={this.props.sync.clinicInvalidDate}
selectedClinicId={this.props.selectedClinicId}
clinics={this.props.clinics}
working={this.props.working}
acknowledgeNotification={this.props.sync.acknowledgeNotification} />
createCustodialAccountErrorMessage={createCustodialAccountErrorMessage}
createCustodialAccountErrorDismissed={createCustodialAccountErrorDismissed}
updateProfileErrorMessage={updateProfileErrorMessage}
updateProfileErrorDismissed={updateProfileErrorDismissed}
dismissCreateCustodialAccountError={sync.dismissCreateCustodialAccountError}
dismissUpdateProfileError={sync.dismissUpdateProfileError}
onSubmitFail={sync.clinicInvalidDate}
selectedClinicId={selectedClinicId}
clinics={clinics}
working={working}
acknowledgeNotification={sync.acknowledgeNotification}
fetchPatientsForClinic={async.fetchPatientsForClinic} />
</div>
);
}
Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "tidepool-uploader",
"productName": "tidepool-uploader",
"version": "2.55.1-tandem-compatibility.updates.1",
"version": "2.55.1-mrn-validation.2",
"description": "Tidepool Project Universal Uploader",
"main": "./main.prod.js",
"author": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tidepool-uploader",
"version": "2.55.1-tandem-compatibility.updates.1",
"version": "2.55.1-mrn-validation.2",
"description": "Tidepool Project Universal Uploader",
"private": true,
"main": "main.prod.js",
Expand Down
5 changes: 5 additions & 0 deletions styles/components/ClinicUserEdit.module.less
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@
.validationError {
color: @red-error;
margin-top: 10px;

ul {
padding-left: 20px;
margin-top: 0px;
}
}

.iconClose {
Expand Down

0 comments on commit 7412409

Please sign in to comment.