Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit dbf3aa5

Browse files
authored
Add functionality for i18n within application (#7)
1 parent 58146e0 commit dbf3aa5

File tree

83 files changed

+10900
-442
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+10900
-442
lines changed

.eslintrc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
"FHIR": true,
88
"document": true,
99
"Canadarm": true,
10-
"canadarmConfig": true
10+
"canadarmConfig": true,
11+
"navigator": true
1112
},
1213
"rules": {
1314
"class-methods-use-this": ["error", {"exceptMethods": ["handleSubmit", "handleKeyPress", "shouldComponentUpdate", "render"]}],
1415
"no-console": 0,
15-
"jsx-a11y/no-static-element-interactions": 0
16+
"jsx-a11y/no-static-element-interactions": 0,
17+
"react/prefer-stateless-function": [0, { "ignorePureComponents": true }]
1618
}
1719
}

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# CHANGELOG
22

3+
* 1.4.0
4+
- Add i18n functionality to allow for specific language/locale
5+
- Replaced fhir-client library with the latest version
6+
- Allow for unknown gender option to be pulled in via FHIR
37
* 1.3.0
48
- Update UI for the risk factors view to be print-friendly
59
* 1.2.0

app/__mocks__/fileMock.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = 'test-file-stub';

app/__mocks__/load_fhir_data.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,16 @@ ASCVDRisk.computeLifetimeRisk = jest.fn(() => 35);
2121
ASCVDRisk.computeLowestLifetime = jest.fn(() => 5);
2222
ASCVDRisk.computePotentialRisk = jest.fn(() => 20);
2323
ASCVDRisk.canCalculateScore = jest.fn(() => true);
24-
ASCVDRisk.missingFields = jest.fn();
24+
ASCVDRisk.missingFields = jest.fn(() => []);
2525
ASCVDRisk.isValidAge = jest.fn(() => true);
2626
ASCVDRisk.isValidTotalCholesterol = jest.fn(() => false);
2727
ASCVDRisk.isValidSysBP = jest.fn(() => true);
2828
ASCVDRisk.isValidHDL = jest.fn(() => true);
2929
ASCVDRisk.computeBirthDateFromAge = jest.fn();
3030

31+
// Test function to change gender in Jest component tests.
32+
ASCVDRisk.changeGender = (gender) => {
33+
ASCVDRisk.patientInfo.gender = gender;
34+
};
35+
3136
module.exports = ASCVDRisk;

app/load_fhir_data.js

Lines changed: 10 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -673,50 +673,33 @@ window.ASCVDRisk = window.ASCVDRisk || {};
673673
const missingFields = () => {
674674
const needInput = [];
675675
if (!ASCVDRisk.isValidTotalCholesterol(ASCVDRisk.patientInfo.totalCholesterol)) {
676-
needInput.push('Total cholesterol');
676+
needInput.push('formTotalCholesterol');
677677
}
678678
if (ASCVDRisk.patientInfo.relatedFactors.diabetic === undefined) {
679-
needInput.push('Diabetes status');
679+
needInput.push('formDiabetic');
680680
}
681681
if (!ASCVDRisk.isValidAge(ASCVDRisk.patientInfo.age)) {
682-
needInput.push('Age');
682+
needInput.push('formAge');
683683
}
684684
if (!ASCVDRisk.isValidHDL(ASCVDRisk.patientInfo.hdl)) {
685-
needInput.push('HDL - cholesterol');
685+
needInput.push('formHdl');
686686
}
687687
if (ASCVDRisk.patientInfo.relatedFactors.smoker === undefined) {
688-
needInput.push('Current smoking status');
688+
needInput.push('formSmoker');
689689
}
690690
if (ASCVDRisk.patientInfo.relatedFactors.race === undefined) {
691-
needInput.push('Race');
691+
needInput.push('formRace');
692692
}
693693
if (!ASCVDRisk.isValidSysBP(ASCVDRisk.patientInfo.systolicBloodPressure)) {
694-
needInput.push('Systolic blood pressure');
694+
needInput.push('formSysBP');
695695
}
696696
if (ASCVDRisk.patientInfo.relatedFactors.hypertensive === undefined) {
697-
needInput.push('Hypertension status');
697+
needInput.push('formHypertensive');
698698
}
699699
if (ASCVDRisk.patientInfo.gender === undefined) {
700-
needInput.push('Gender');
700+
needInput.push('formSex');
701701
}
702-
if (needInput.length === 9) {
703-
return 'All fields required to compute ASCVD risk';
704-
} else if (needInput.length > 2) {
705-
let retStatement = '';
706-
for (let i = 0; i < needInput.length; i += 1) {
707-
if (i === needInput.length - 1) {
708-
retStatement += `and ${needInput[i]} are all required to compute ASCVD risk`;
709-
} else {
710-
retStatement += `${needInput[i]}, `;
711-
}
712-
}
713-
return retStatement;
714-
} else if (needInput.length === 2) {
715-
return `${needInput[0]} and ${needInput[1]} are both required to compute ASCVD risk`;
716-
} else if (needInput.length === 1) {
717-
return `${needInput[0]} is required to compute ASCVD risk`;
718-
} else if (needInput.length === 0) { return ''; }
719-
return '';
702+
return needInput;
720703
};
721704
ASCVDRisk.missingFields = missingFields;
722705
ASCVDRisk.patientInfo = PatientInfo;

build/css/styles.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/images/Settings.svg

Lines changed: 1 addition & 0 deletions
Loading

build/js/bundle.js

Lines changed: 15 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/App/app.jsx

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React from 'react';
2+
import { intlShape } from 'react-intl';
23
import ASCVDRisk from '../../app/load_fhir_data';
34
import PatientBanner from '../../components/PatientBanner/banner';
45
import Header from '../../components/Header/header';
@@ -17,6 +18,7 @@ class App extends React.Component {
1718
this.updateRiskScores = this.updateRiskScores.bind(this);
1819
this.updateChangedProperty = this.updateChangedProperty.bind(this);
1920
this.setView = this.setView.bind(this);
21+
this.getBirthDateDisplay = this.getBirthDateDisplay.bind(this);
2022
this.addOption = this.addOption.bind(this);
2123
this.removeOption = this.removeOption.bind(this);
2224
this.state = {
@@ -65,6 +67,8 @@ class App extends React.Component {
6567
updateChangedProperty={this.updateChangedProperty}
6668
options={this.state.options}
6769
removeOption={this.removeOption}
70+
intl={this.props.intl}
71+
currentLocale={this.props.currentLocale}
6872
/>
6973
);
7074
} else if (this.state.view === 'Risk Factors') {
@@ -77,13 +81,34 @@ class App extends React.Component {
7781
lifetimeBest={ASCVDRisk.computeLowestLifetime()}
7882
options={this.state.options}
7983
removeOption={this.removeOption}
84+
intl={this.props.intl}
85+
currentLocale={this.props.currentLocale}
8086
/>
8187
);
8288
}
8389
return (
84-
<Recommendations />
90+
<Recommendations intl={this.props.intl} />
8591
);
8692
}
93+
/**
94+
* Displays a user-friendly date of birth
95+
* @returns {string} - Internationalized string representing a possible date of birth
96+
*/
97+
getBirthDateDisplay() {
98+
const propIntl = this.props.intl;
99+
const messages = propIntl.messages;
100+
let birthDateDisplay = '';
101+
const date = ASCVDRisk.patientInfo.dateOfBirth;
102+
if (Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date.getTime())) {
103+
birthDateDisplay = propIntl.formatMessage(messages.bannerDate, {
104+
date: (`0${date.getDate()}`).slice(-2),
105+
month: (`0${date.getMonth() + 1}`).slice(-2),
106+
year: date.getFullYear(),
107+
});
108+
}
109+
return birthDateDisplay;
110+
}
111+
87112

88113
/**
89114
* Adds a risk factor option to options property
@@ -137,16 +162,40 @@ class App extends React.Component {
137162
}
138163

139164
render() {
165+
const propIntl = this.props.intl;
166+
const messages = propIntl.messages;
167+
let gender;
168+
if (ASCVDRisk.patientInfo.gender &&
169+
ASCVDRisk.patientInfo.gender.toLowerCase() === 'female') {
170+
gender = propIntl.formatMessage(messages.bannerFemale);
171+
} else if (ASCVDRisk.patientInfo.gender &&
172+
ASCVDRisk.patientInfo.gender.toLowerCase() === 'male') {
173+
gender = propIntl.formatMessage(messages.bannerMale);
174+
} else {
175+
gender = propIntl.formatMessage(messages.bannerUnknownGender);
176+
}
140177
return (
141178
<div>
142179
<PatientBanner
143180
hideBanner={ASCVDRisk.hideDemoBanner}
144181
name={`${ASCVDRisk.patientInfo.firstName} ${ASCVDRisk.patientInfo.lastName}`}
145-
age={ASCVDRisk.patientInfo.age}
146-
gender={ASCVDRisk.patientInfo.gender}
147-
dob={ASCVDRisk.patientInfo.dateOfBirth}
182+
age={propIntl.formatMessage(messages.bannerYears,
183+
{ age: propIntl.formatNumber(ASCVDRisk.patientInfo.age) })}
184+
gender={gender}
185+
dobPrompt={propIntl.formatMessage(messages.bannerDOB)}
186+
dob={this.getBirthDateDisplay()}
187+
/>
188+
<Header
189+
header={propIntl.formatMessage(messages.appHeader)}
190+
languagePrompt={propIntl.formatMessage(messages.language)}
191+
locales={[
192+
{ name: propIntl.formatMessage(messages.enUS), val: 'en' },
193+
{ name: propIntl.formatMessage(messages.enUK), val: 'en-GB' },
194+
{ name: propIntl.formatMessage(messages.es), val: 'es' },
195+
]}
196+
updateLocale={this.props.updateLocale}
197+
currentLocale={this.props.currentLocale}
148198
/>
149-
<Header header={'ASCVD Risk Calculator'} />
150199
<Navbar
151200
updateView={this.updateView}
152201
tab_one={'Results'}
@@ -155,11 +204,18 @@ class App extends React.Component {
155204
tabIndex={this.state.tabIndex}
156205
hideNav={this.state.hideNav}
157206
changedProperty={this.state.changedProperty}
207+
intl={propIntl}
208+
currentLocale={this.props.currentLocale}
158209
/>
159210
{ this.setView() }
160211
</div>
161212
);
162213
}
163214
}
215+
App.propTypes = {
216+
intl: intlShape,
217+
currentLocale: React.PropTypes.string,
218+
updateLocale: React.PropTypes.func.isRequired,
219+
};
164220

165221
export default App;

components/App/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { injectIntl } from 'react-intl';
2+
import App from './app';
3+
export default injectIntl(App);

0 commit comments

Comments
 (0)