@hedia/recommendation-screen 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.idea/workspace.xml +36 -31
  2. package/package.json +1 -1
  3. package/src/RecommendationScreen.d.ts +3 -0
  4. package/src/RecommendationScreen.jsx +50 -41
  5. package/src/RecommendationScreen.tsx +80 -56
  6. package/src/components/InvisibleNumberInput.d.ts +1 -0
  7. package/src/components/InvisibleNumberInput.jsx +8 -8
  8. package/src/components/InvisibleNumberInput.tsx +10 -7
  9. package/src/components/RecommendedCarbs.d.ts +0 -2
  10. package/src/components/RecommendedCarbs.jsx +8 -3
  11. package/src/components/RecommendedCarbs.tsx +10 -5
  12. package/src/components/RecommendedInsulin.d.ts +3 -3
  13. package/src/components/RecommendedInsulin.jsx +21 -8
  14. package/src/components/RecommendedInsulin.tsx +27 -13
  15. package/src/components/activity/ActivityIcon.jsx +1 -1
  16. package/src/components/activity/ActivityIcon.tsx +1 -1
  17. package/src/types/enum.d.ts +9 -10
  18. package/src/types/enum.js +9 -10
  19. package/src/types/enum.ts +0 -1
  20. package/src/types/types.ts +1 -0
  21. package/src/utils/AttentionMessages.d.ts +1 -1
  22. package/src/utils/AttentionMessages.jsx +1 -1
  23. package/src/utils/AttentionMessages.tsx +1 -1
  24. package/src/utils/Constants.d.ts +3 -0
  25. package/src/utils/Constants.js +4 -1
  26. package/src/utils/Constants.ts +5 -0
  27. package/src/utils/RecommendationError.d.ts +0 -1
  28. package/src/utils/RecommendationError.jsx +1 -3
  29. package/src/utils/RecommendationError.tsx +0 -7
  30. package/src/utils/RecommendationUtils.d.ts +2 -3
  31. package/src/utils/RecommendationUtils.js +3 -4
  32. package/src/utils/RecommendationUtils.ts +2 -4
  33. package/src/utils/Utils.d.ts +1 -0
  34. package/src/utils/Utils.js +4 -0
  35. package/src/utils/Utils.ts +4 -0
  36. package/src/utils/Validations.js +15 -11
  37. package/src/utils/Validations.ts +16 -11
@@ -50,6 +50,7 @@
50
50
  <property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
51
51
  <property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
52
52
  <property name="TERMINAL_CUSTOM_COMMANDS_GOT_IT" value="true" />
53
+ <property name="ToolWindowGit.ShowToolbar" value="false" />
53
54
  <property name="WebServerToolWindowFactoryState" value="false" />
54
55
  <property name="dart.analysis.tool.window.visible" value="false" />
55
56
  <property name="last_opened_file_path" value="$PROJECT_DIR$/android/app/src/main/res/values" />
@@ -169,7 +170,11 @@
169
170
  <workItem from="1599031274561" duration="12226000" />
170
171
  <workItem from="1599119614705" duration="6081000" />
171
172
  <workItem from="1599205746476" duration="8368000" />
172
- <workItem from="1599465060245" duration="4106000" />
173
+ <workItem from="1599465060245" duration="4905000" />
174
+ <workItem from="1599554723490" duration="10979000" />
175
+ <workItem from="1599637277136" duration="8223000" />
176
+ <workItem from="1599729519931" duration="17229000" />
177
+ <workItem from="1599810708519" duration="2071000" />
173
178
  </task>
174
179
  <servers />
175
180
  </component>
@@ -229,48 +234,48 @@
229
234
  <state x="0" y="123" width="1792" height="897" key="DiffContextDialog/1792.-195.3440.1417/0.23.1792.1097@0.23.1792.1097" timestamp="1597747801467" />
230
235
  <state x="0" y="123" width="1792" height="897" key="DiffContextDialog/1792.-410.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1597836504040" />
231
236
  <state x="1792" y="-314" width="1920" height="865" key="DiffContextDialog/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1598603549140" />
232
- <state width="1276" height="270" key="GridCell.Tab.0.bottom" timestamp="1599230158300">
233
- <screen x="0" y="23" width="1792" height="1097" />
237
+ <state width="1878" height="183" key="GridCell.Tab.0.bottom" timestamp="1599814597572">
238
+ <screen x="1792" y="-410" width="1920" height="1057" />
234
239
  </state>
235
240
  <state width="1750" height="261" key="GridCell.Tab.0.bottom/-1920.-66.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1596194051670" />
236
- <state width="1878" height="249" key="GridCell.Tab.0.bottom/0.23.1792.1097@0.23.1792.1097" timestamp="1596482378171" />
241
+ <state width="1678" height="263" key="GridCell.Tab.0.bottom/0.23.1792.1097@0.23.1792.1097" timestamp="1599753977842" />
237
242
  <state width="1750" height="383" key="GridCell.Tab.0.bottom/1792.-195.3440.1417/0.23.1792.1097@0.23.1792.1097" timestamp="1597945008184" />
238
- <state width="1678" height="367" key="GridCell.Tab.0.bottom/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599152764316" />
243
+ <state width="1678" height="263" key="GridCell.Tab.0.bottom/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599741473452" />
239
244
  <state width="1276" height="270" key="GridCell.Tab.0.bottom/1792.-410.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1599230158300" />
240
- <state width="1878" height="259" key="GridCell.Tab.0.bottom/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599060151002" />
241
- <state width="1276" height="270" key="GridCell.Tab.0.center" timestamp="1599230158300">
242
- <screen x="0" y="23" width="1792" height="1097" />
245
+ <state width="1878" height="183" key="GridCell.Tab.0.bottom/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599814597572" />
246
+ <state width="1878" height="183" key="GridCell.Tab.0.center" timestamp="1599814597571">
247
+ <screen x="1792" y="-410" width="1920" height="1057" />
243
248
  </state>
244
249
  <state width="1750" height="261" key="GridCell.Tab.0.center/-1920.-66.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1596194051669" />
245
- <state width="1878" height="249" key="GridCell.Tab.0.center/0.23.1792.1097@0.23.1792.1097" timestamp="1596482378170" />
250
+ <state width="1678" height="263" key="GridCell.Tab.0.center/0.23.1792.1097@0.23.1792.1097" timestamp="1599753977841" />
246
251
  <state width="1750" height="383" key="GridCell.Tab.0.center/1792.-195.3440.1417/0.23.1792.1097@0.23.1792.1097" timestamp="1597945008183" />
247
- <state width="1678" height="367" key="GridCell.Tab.0.center/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599152764316" />
252
+ <state width="1678" height="263" key="GridCell.Tab.0.center/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599741473451" />
248
253
  <state width="1276" height="270" key="GridCell.Tab.0.center/1792.-410.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1599230158300" />
249
- <state width="1878" height="259" key="GridCell.Tab.0.center/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599060151001" />
250
- <state width="1276" height="270" key="GridCell.Tab.0.left" timestamp="1599230158299">
251
- <screen x="0" y="23" width="1792" height="1097" />
254
+ <state width="1878" height="183" key="GridCell.Tab.0.center/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599814597571" />
255
+ <state width="1878" height="183" key="GridCell.Tab.0.left" timestamp="1599814597571">
256
+ <screen x="1792" y="-410" width="1920" height="1057" />
252
257
  </state>
253
258
  <state width="1750" height="261" key="GridCell.Tab.0.left/-1920.-66.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1596194051668" />
254
- <state width="1878" height="249" key="GridCell.Tab.0.left/0.23.1792.1097@0.23.1792.1097" timestamp="1596482378170" />
259
+ <state width="1678" height="263" key="GridCell.Tab.0.left/0.23.1792.1097@0.23.1792.1097" timestamp="1599753977841" />
255
260
  <state width="1750" height="383" key="GridCell.Tab.0.left/1792.-195.3440.1417/0.23.1792.1097@0.23.1792.1097" timestamp="1597945008182" />
256
- <state width="1678" height="367" key="GridCell.Tab.0.left/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599152764315" />
261
+ <state width="1678" height="263" key="GridCell.Tab.0.left/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599741473451" />
257
262
  <state width="1276" height="270" key="GridCell.Tab.0.left/1792.-410.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1599230158299" />
258
- <state width="1878" height="259" key="GridCell.Tab.0.left/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599060150995" />
259
- <state width="1276" height="270" key="GridCell.Tab.0.right" timestamp="1599230158300">
260
- <screen x="0" y="23" width="1792" height="1097" />
263
+ <state width="1878" height="183" key="GridCell.Tab.0.left/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599814597571" />
264
+ <state width="1878" height="183" key="GridCell.Tab.0.right" timestamp="1599814597572">
265
+ <screen x="1792" y="-410" width="1920" height="1057" />
261
266
  </state>
262
267
  <state width="1750" height="261" key="GridCell.Tab.0.right/-1920.-66.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1596194051669" />
263
- <state width="1878" height="249" key="GridCell.Tab.0.right/0.23.1792.1097@0.23.1792.1097" timestamp="1596482378171" />
268
+ <state width="1678" height="263" key="GridCell.Tab.0.right/0.23.1792.1097@0.23.1792.1097" timestamp="1599753977842" />
264
269
  <state width="1750" height="383" key="GridCell.Tab.0.right/1792.-195.3440.1417/0.23.1792.1097@0.23.1792.1097" timestamp="1597945008183" />
265
- <state width="1678" height="367" key="GridCell.Tab.0.right/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599152764316" />
270
+ <state width="1678" height="263" key="GridCell.Tab.0.right/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599741473452" />
266
271
  <state width="1276" height="270" key="GridCell.Tab.0.right/1792.-410.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1599230158300" />
267
- <state width="1878" height="259" key="GridCell.Tab.0.right/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599060151002" />
268
- <state x="2773" y="167" key="IDE.errors.dialog" timestamp="1598973647546">
269
- <screen x="1792" y="-195" width="3440" height="1417" />
272
+ <state width="1878" height="183" key="GridCell.Tab.0.right/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599814597572" />
273
+ <state x="2340" y="-140" key="IDE.errors.dialog" timestamp="1599637300780">
274
+ <screen x="1792" y="-410" width="1920" height="1057" />
270
275
  </state>
271
276
  <state x="511" y="303" key="IDE.errors.dialog/1792.-195.3440.1417/0.23.1792.1097@0.23.1792.1097" timestamp="1597308623997" />
272
277
  <state x="2773" y="167" key="IDE.errors.dialog/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1598973647546" />
273
- <state x="2340" y="-140" key="IDE.errors.dialog/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1596547237176" />
278
+ <state x="2340" y="-140" key="IDE.errors.dialog/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599637300780" />
274
279
  <state x="0" y="23" width="1792" height="1097" key="MergeDialog" timestamp="1597409959598">
275
280
  <screen x="0" y="23" width="1792" height="1097" />
276
281
  </state>
@@ -294,27 +299,27 @@
294
299
  <screen x="0" y="23" width="1792" height="1097" />
295
300
  </state>
296
301
  <state x="428" y="230" key="com.intellij.openapi.vcs.changes.SpecificFilesViewDialog/-1920.-66.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1596103115204" />
297
- <state x="558" y="310" width="1234" height="580" key="find.popup" timestamp="1599469543819">
298
- <screen x="0" y="23" width="1792" height="1097" />
302
+ <state x="2390" y="-133" width="1322" height="582" key="find.popup" timestamp="1599811241735">
303
+ <screen x="1792" y="-410" width="1920" height="1057" />
299
304
  </state>
300
305
  <state x="559" y="310" width="1233" height="522" key="find.popup/-1920.-66.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1596116959250" />
301
306
  <state x="559" y="310" width="1233" height="522" key="find.popup/0.23.1792.1097@0.23.1792.1097" timestamp="1596191045450" />
302
307
  <state x="558" y="310" width="1234" height="580" key="find.popup/1792.-195.3440.1417/0.23.1792.1097@0.23.1792.1097" timestamp="1597748403272" />
303
- <state x="2863" y="176" width="2369" height="738" key="find.popup/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599137555658" />
308
+ <state x="2491" y="140" width="2369" height="738" key="find.popup/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599749408344" />
304
309
  <state x="558" y="310" width="1234" height="580" key="find.popup/1792.-410.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1599469543819" />
305
- <state x="2390" y="-133" width="1322" height="582" key="find.popup/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599038215964" />
310
+ <state x="2390" y="-133" width="1322" height="582" key="find.popup/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599811241735" />
306
311
  <state x="2477" y="-143" key="refactoring.ChangeSignatureDialog" timestamp="1599040674381">
307
312
  <screen x="1792" y="-410" width="1920" height="1057" />
308
313
  </state>
309
314
  <state x="2477" y="-143" key="refactoring.ChangeSignatureDialog/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599040674381" />
310
- <state x="2178" y="-174" width="718" height="652" key="search.everywhere.popup" timestamp="1599489043631">
315
+ <state x="2178" y="-174" width="718" height="652" key="search.everywhere.popup" timestamp="1599814957048">
311
316
  <screen x="1792" y="-410" width="1920" height="1057" />
312
317
  </state>
313
318
  <state x="360" y="268" width="670" height="676" key="search.everywhere.popup/-1920.-66.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1596101738778" />
314
319
  <state x="360" y="268" width="670" height="676" key="search.everywhere.popup/0.23.1792.1097@0.23.1792.1097" timestamp="1596191050648" />
315
320
  <state x="360" y="268" width="671" height="677" key="search.everywhere.popup/1792.-195.3440.1417/0.23.1792.1097@0.23.1792.1097" timestamp="1597748285464" />
316
- <state x="2484" y="121" width="1287" height="875" key="search.everywhere.popup/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599137557476" />
321
+ <state x="2484" y="121" width="1287" height="875" key="search.everywhere.popup/1792.-195.3440.1417/0.23.1792.1097@1792.-195.3440.1417" timestamp="1599744384312" />
317
322
  <state x="360" y="268" width="671" height="677" key="search.everywhere.popup/1792.-410.1920.1057/0.23.1792.1097@0.23.1792.1097" timestamp="1599216348282" />
318
- <state x="2178" y="-174" width="718" height="652" key="search.everywhere.popup/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599489043631" />
323
+ <state x="2178" y="-174" width="718" height="652" key="search.everywhere.popup/1792.-410.1920.1057/0.23.1792.1097@1792.-410.1920.1057" timestamp="1599814957048" />
319
324
  </component>
320
325
  </project>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hedia/recommendation-screen",
3
- "version": "1.2.1",
3
+ "version": "1.3.1",
4
4
  "description": "Hedia Recommendation Screen for Bolus and Carbohydrates",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -42,8 +42,11 @@ interface IState {
42
42
  export default class RecommendationScreen extends React.Component<IRecommendationProps, IState> {
43
43
  private readonly timer;
44
44
  private readonly suggestedCarbs;
45
+ private readonly hasError;
45
46
  private scrollView;
46
47
  constructor(props: IRecommendationProps);
48
+ componentWillUnmount(): void;
49
+ recalculateInsulin: (calculatorParams: Calculator.IRecommendationParams) => void;
47
50
  onExit: () => void;
48
51
  updateRemeasureTime: (remeasureTime: number) => void;
49
52
  handleNoRecentInsulin: () => void;
@@ -51,13 +51,20 @@ react_native_1.YellowBox.ignoreWarnings([`Setting a timer`]);
51
51
  class RecommendationScreen extends react_1.default.Component {
52
52
  constructor(props) {
53
53
  super(props);
54
+ this.hasError = false;
55
+ this.recalculateInsulin = (calculatorParams) => {
56
+ const { bolus } = Calculator.calculateRecommendation(RecommendationUtils_1.assignTargetBGL(calculatorParams));
57
+ this.setState({
58
+ insulinRecommendation: Utils_1.Utils.roundValue(bolus, this.props.injectionMethod),
59
+ enteredInsulin: undefined,
60
+ });
61
+ };
54
62
  this.onExit = () => {
55
63
  if (this.state.isRecommendationDisplayed) {
56
64
  this.setState({ exitModal: true }, () => this.props.showBolusBar(!this.state.exitModal));
57
65
  }
58
66
  else {
59
67
  this.props.exitCallback();
60
- clearTimeout(this.timer);
61
68
  }
62
69
  };
63
70
  this.updateRemeasureTime = (remeasureTime) => {
@@ -71,10 +78,11 @@ class RecommendationScreen extends react_1.default.Component {
71
78
  });
72
79
  };
73
80
  this.updateCarbRecommendation = (enteredCarbs) => {
74
- this.setState({ enteredCarbs });
81
+ const providedCarbs = this.props.calculatorParams.carbohydrates;
82
+ this.setState({ enteredCarbs }, () => this.recalculateInsulin({ ...this.props.calculatorParams, carbohydrates: providedCarbs + enteredCarbs }));
75
83
  };
76
84
  this.removeCarbRecommendation = () => {
77
- this.setState({ enteredCarbs: null, carbRecommendation: null });
85
+ this.setState({ enteredCarbs: null, carbRecommendation: null }, () => this.recalculateInsulin({ ...this.props.calculatorParams }));
78
86
  };
79
87
  this.declineCarbRecommendation = () => {
80
88
  this.hideAttentionModal();
@@ -93,7 +101,6 @@ class RecommendationScreen extends react_1.default.Component {
93
101
  };
94
102
  this.closeCalculation = () => {
95
103
  this.hideExitModal();
96
- clearTimeout(this.timer);
97
104
  this.props.closeCalculationCallback();
98
105
  };
99
106
  this.handleMoodSelected = (selectedMood) => {
@@ -106,14 +113,9 @@ class RecommendationScreen extends react_1.default.Component {
106
113
  if (this.state.exitModal) {
107
114
  this.hideExitModal();
108
115
  }
109
- this.props.transferToLogbook({
110
- suggested: this.suggestedCarbs,
111
- entered: this.state.enteredCarbs,
112
- }, {
113
- suggested: this.state.insulinRecommendation,
114
- entered: this.state.enteredInsulin,
115
- }, this.state.remeasureTime);
116
- clearTimeout(this.timer);
116
+ const carbs = { suggested: this.suggestedCarbs, entered: this.state.enteredCarbs };
117
+ const insulin = { suggested: this.state.insulinRecommendation, entered: this.state.enteredInsulin };
118
+ this.props.transferToLogbook(carbs, insulin, this.state.remeasureTime);
117
119
  };
118
120
  this.getBGLevelAttentionMessage = () => {
119
121
  const { calculatorParams, latestLogbookFrom6Hours } = this.props;
@@ -132,42 +134,49 @@ class RecommendationScreen extends react_1.default.Component {
132
134
  return RecommendationUtils_1.getLimitationMessage(wasLimited, activityReduction);
133
135
  };
134
136
  try {
135
- Validations_1.validateParams(props);
137
+ Validations_1.validateParams(this.props);
138
+ i18nUtils_1.changeLanguage(props.language);
139
+ const { recentBoluses } = this.props?.calculatorParams;
140
+ const { bolus, carbRecommendation, activityReduction, wasLimited, activeInsulin, } = Calculator.calculateRecommendation(RecommendationUtils_1.assignTargetBGL(this.props.calculatorParams));
141
+ this.suggestedCarbs = carbRecommendation;
142
+ this.state = {
143
+ remeasureTime: this.getBGLevelRemeasurementReminder(),
144
+ isRecommendationDisplayed: recentBoluses?.length !== 0,
145
+ insulinRecommendation: Utils_1.Utils.roundValue(bolus, props.injectionMethod),
146
+ wasLimited,
147
+ activityReduction,
148
+ bolus,
149
+ carbRecommendation,
150
+ activeInsulin,
151
+ selectedMood: null,
152
+ recommendationModal: wasLimited || !!Math.round(carbRecommendation) || !!this.getBGLevelAttentionMessage(),
153
+ exitModal: false,
154
+ };
155
+ this.timer = setTimeout(() => {
156
+ props.onError(RecommendationError_1.TimeoutLimitError());
157
+ }, enum_1.Milliseconds.Minute * 15);
136
158
  }
137
159
  catch (error) {
138
- props.onError(error);
160
+ this.hasError = true;
161
+ this.props.onError(error);
139
162
  }
140
- i18nUtils_1.changeLanguage(props.language);
141
- const { recentBoluses } = props?.calculatorParams;
142
- const { bolus, carbRecommendation, activityReduction, wasLimited } = Calculator.calculateRecommendation(RecommendationUtils_1.getParams(this.props));
143
- this.suggestedCarbs = carbRecommendation;
144
- const activeInsulin = Calculator.calculateActiveInsulin(recentBoluses ?? []);
145
- this.state = {
146
- remeasureTime: this.getBGLevelRemeasurementReminder(),
147
- isRecommendationDisplayed: recentBoluses?.length !== 0,
148
- insulinRecommendation: Utils_1.Utils.roundValue(bolus, props.injectionMethod),
149
- wasLimited,
150
- activityReduction,
151
- bolus,
152
- carbRecommendation,
153
- activeInsulin,
154
- selectedMood: null,
155
- recommendationModal: wasLimited || !!Math.round(carbRecommendation) || !!this.getBGLevelAttentionMessage(),
156
- exitModal: false,
157
- };
158
- this.timer = setTimeout(() => {
159
- props.onError(RecommendationError_1.TimeoutLimitError());
160
- }, enum_1.Milliseconds.Minute * 15);
163
+ }
164
+ componentWillUnmount() {
165
+ clearTimeout(this.timer);
161
166
  }
162
167
  render() {
163
- const { activeInsulin, recommendationModal, carbRecommendation, enteredCarbs } = this.state;
164
- const { calculatorParams } = this.props;
168
+ if (this.hasError) {
169
+ return <react_native_1.View style={containerStyles.container}/>;
170
+ }
171
+ const { activeInsulin, recommendationModal, carbRecommendation, enteredCarbs, enteredInsulin, insulinRecommendation, activityReduction, isRecommendationDisplayed, } = this.state;
172
+ const { calculatorParams, units } = this.props;
165
173
  const { currentBGL, carbohydrates } = calculatorParams;
174
+ const displayedBGL = units === enum_1.BGUnit.MMOL_L ? currentBGL : Utils_1.Utils.convertToMGDL(currentBGL);
166
175
  return (<react_2.I18nProvider language={this.props.language} i18n={i18nUtils_1.i18n}>
167
176
  <react_native_1.ScrollView style={containerStyles.container} ref={(view) => (this.scrollView = view)}>
168
177
  <Header_1.default exitCallback={this.onExit}/>
169
178
  <InfoBars_1.default style={{ flex: 5 }} label={i18nUtils_1.i18n._(macro_1.t `Active Insulin`)} value={activeInsulin ? `${activeInsulin.toFixed(1)}` : null} units={i18nUtils_1.i18n._(macro_1.t `units`)} showZeroAsDash={false}/>
170
- <InfoBars_1.default label={i18nUtils_1.i18n._(macro_1.t `Blood Glucose Level`)} value={currentBGL ? `${currentBGL}` : null} units={this.props.units} showZeroAsDash={true}/>
179
+ <InfoBars_1.default label={i18nUtils_1.i18n._(macro_1.t `Blood Glucose Level`)} value={currentBGL ? `${displayedBGL}` : null} units={this.props.units} showZeroAsDash={true}/>
171
180
  <react_native_1.View style={containerStyles.calcContainer}>
172
181
  <react_native_1.View style={containerStyles.calcMargin}>
173
182
  <react_native_1.View style={[
@@ -176,15 +185,15 @@ class RecommendationScreen extends react_1.default.Component {
176
185
  borderColor: carbRecommendation ? Constants_1.BORDER_COLOUR_TEAL : Constants_1.BORDER_COLOUR_GREY,
177
186
  },
178
187
  ]}>
179
- <RecommendedCarbs_1.default enteredCarbs={`${carbohydrates}`} changedRecommendedCarbs={this.updateCarbRecommendation} recommendedCarbs={`${enteredCarbs ?? Math.round(carbRecommendation)}`} removeRecommendedCarbs={this.removeCarbRecommendation} onError={this.props.onError}/>
188
+ <RecommendedCarbs_1.default enteredCarbs={`${carbohydrates}`} changedRecommendedCarbs={this.updateCarbRecommendation} recommendedCarbs={`${enteredCarbs ?? Math.round(carbRecommendation)}`} removeRecommendedCarbs={this.removeCarbRecommendation}/>
180
189
  <Remeasure_1.default onSliderChange={this.updateRemeasureTime} remeasureTime={this.state.remeasureTime}/>
181
190
  </react_native_1.View>
182
191
  </react_native_1.View>
183
192
  </react_native_1.View>
184
193
  {this.props.calculatorParams.activity && this.props.activityType !== null ? (<Activity_1.default activity={this.props.calculatorParams.activity} activityType={this.props.activityType} activityReduction={this.state.activityReduction}/>) : null}
185
- {!this.state.isRecommendationDisplayed ? (<RecentInsulin_1.default onRecentInsulinYes={this.props.onRecentInsulinYes} onRecentInsulinNo={this.handleNoRecentInsulin}/>) : (<RecommendedInsulin_1.default injectionMethod={this.props.injectionMethod} insulinRecommendation={this.state.enteredInsulin ?? this.state.insulinRecommendation} activityReduction={this.state.activityReduction} updateRecommendedInsulin={this.updateInsulinRecommendation} onError={this.props.onError}/>)}
194
+ {!this.state.isRecommendationDisplayed ? (<RecentInsulin_1.default onRecentInsulinYes={this.props.onRecentInsulinYes} onRecentInsulinNo={this.handleNoRecentInsulin}/>) : (<RecommendedInsulin_1.default injectionMethod={this.props.injectionMethod} insulinRecommendation={insulinRecommendation} enteredInsulin={enteredInsulin} activityReduction={activityReduction} updateRecommendedInsulin={this.updateInsulinRecommendation}/>)}
186
195
  <Emotion_1.default moodSelected={this.handleMoodSelected} currentMood={this.state.selectedMood}/>
187
- <TransferToLogbook_1.default visible={this.state.isRecommendationDisplayed} transfer={this.handleTransfer}/>
196
+ <TransferToLogbook_1.default visible={isRecommendationDisplayed} transfer={this.handleTransfer}/>
188
197
  <RecommendationModal_1.default isVisible={recommendationModal} suggestedCarbohydrates={carbRecommendation} attentionMessage={this.getBGLevelAttentionMessage()} limitationMessage={this.getLimitationAttentionMessage()} onClickOkButton={this.hideAttentionModal} onAcceptCarbohydrates={this.acceptCarbRecommendation} onDeclineCarbohydrates={this.declineCarbRecommendation}/>
189
198
  </react_native_1.ScrollView>
190
199
  {this.state.exitModal ? (<ExitModal_1.default onSave={this.handleTransfer} onCloseCalculation={this.closeCalculation} onClose={this.hideExitModal}/>) : null}
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { ScrollView, StyleSheet, View, YellowBox } from "react-native";
3
+
3
4
  import { ActivityEnum, BGUnit, InjectionMethod, Languages, Milliseconds, MoodEnum } from "./types/enum";
4
5
  import { BACKGROUND_COLOUR_PURPLE, BORDER_COLOUR_GREY, BORDER_COLOUR_TEAL } from "./utils/Constants";
5
6
 
@@ -24,10 +25,10 @@ import { changeLanguage, i18n } from "./locale/i18nUtils";
24
25
  import { IActivity, logbookEntry } from "./types/types";
25
26
  import { AttentionMessage } from "./utils/AttentionMessages";
26
27
  import {
28
+ assignTargetBGL,
27
29
  getAttentionMessage,
28
30
  getBGLevel,
29
31
  getLimitationMessage,
30
- getParams,
31
32
  getReminder,
32
33
  } from "./utils/RecommendationUtils";
33
34
  import { Utils } from "./utils/Utils";
@@ -81,52 +82,68 @@ interface IState {
81
82
  export default class RecommendationScreen extends React.Component<IRecommendationProps, IState> {
82
83
  private readonly timer: ReturnType<typeof setTimeout>;
83
84
  private readonly suggestedCarbs: number;
85
+ private readonly hasError: boolean = false;
84
86
  private scrollView: ScrollView;
85
87
 
86
88
  constructor(props: IRecommendationProps) {
87
89
  super(props);
88
90
  try {
89
- validateParams(props);
91
+ validateParams(this.props);
92
+
93
+ changeLanguage(props.language);
94
+
95
+ const { recentBoluses } = this.props?.calculatorParams;
96
+ const {
97
+ bolus,
98
+ carbRecommendation,
99
+ activityReduction,
100
+ wasLimited,
101
+ activeInsulin,
102
+ } = Calculator.calculateRecommendation(assignTargetBGL(this.props.calculatorParams));
103
+
104
+ this.suggestedCarbs = carbRecommendation;
105
+
106
+ this.state = {
107
+ remeasureTime: this.getBGLevelRemeasurementReminder(),
108
+ isRecommendationDisplayed: recentBoluses?.length !== 0,
109
+ insulinRecommendation: Utils.roundValue(bolus, props.injectionMethod),
110
+ wasLimited,
111
+ activityReduction,
112
+ bolus,
113
+ carbRecommendation,
114
+ activeInsulin,
115
+ selectedMood: null,
116
+ recommendationModal:
117
+ wasLimited || !!Math.round(carbRecommendation) || !!this.getBGLevelAttentionMessage(),
118
+ exitModal: false,
119
+ };
120
+
121
+ this.timer = setTimeout((): void => {
122
+ props.onError(TimeoutLimitError());
123
+ }, Milliseconds.Minute * 15);
90
124
  } catch (error) {
91
- props.onError(error);
125
+ this.hasError = true;
126
+ this.props.onError(error);
92
127
  }
128
+ }
93
129
 
94
- changeLanguage(props.language);
95
-
96
- const { recentBoluses } = props?.calculatorParams;
97
- const { bolus, carbRecommendation, activityReduction, wasLimited } = Calculator.calculateRecommendation(
98
- getParams(this.props),
99
- );
100
-
101
- this.suggestedCarbs = carbRecommendation;
102
-
103
- const activeInsulin = Calculator.calculateActiveInsulin(recentBoluses ?? []);
104
-
105
- this.state = {
106
- remeasureTime: this.getBGLevelRemeasurementReminder(),
107
- isRecommendationDisplayed: recentBoluses?.length !== 0,
108
- insulinRecommendation: Utils.roundValue(bolus, props.injectionMethod),
109
- wasLimited,
110
- activityReduction,
111
- bolus,
112
- carbRecommendation,
113
- activeInsulin,
114
- selectedMood: null,
115
- recommendationModal: wasLimited || !!Math.round(carbRecommendation) || !!this.getBGLevelAttentionMessage(),
116
- exitModal: false,
117
- };
118
-
119
- this.timer = setTimeout((): void => {
120
- props.onError(TimeoutLimitError());
121
- }, Milliseconds.Minute * 15);
130
+ public componentWillUnmount(): void {
131
+ clearTimeout(this.timer);
122
132
  }
123
133
 
134
+ public recalculateInsulin = (calculatorParams: Calculator.IRecommendationParams): void => {
135
+ const { bolus } = Calculator.calculateRecommendation(assignTargetBGL(calculatorParams));
136
+ this.setState({
137
+ insulinRecommendation: Utils.roundValue(bolus, this.props.injectionMethod),
138
+ enteredInsulin: undefined,
139
+ });
140
+ };
141
+
124
142
  public onExit = (): void => {
125
143
  if (this.state.isRecommendationDisplayed) {
126
144
  this.setState({ exitModal: true }, (): void => this.props.showBolusBar(!this.state.exitModal));
127
145
  } else {
128
146
  this.props.exitCallback();
129
- clearTimeout(this.timer);
130
147
  }
131
148
  };
132
149
 
@@ -143,11 +160,16 @@ export default class RecommendationScreen extends React.Component<IRecommendatio
143
160
  };
144
161
 
145
162
  public updateCarbRecommendation = (enteredCarbs: number): void => {
146
- this.setState({ enteredCarbs });
163
+ const providedCarbs = this.props.calculatorParams.carbohydrates;
164
+ this.setState({ enteredCarbs }, (): void =>
165
+ this.recalculateInsulin({ ...this.props.calculatorParams, carbohydrates: providedCarbs + enteredCarbs }),
166
+ );
147
167
  };
148
168
 
149
169
  public removeCarbRecommendation = (): void => {
150
- this.setState({ enteredCarbs: null, carbRecommendation: null });
170
+ this.setState({ enteredCarbs: null, carbRecommendation: null }, (): void =>
171
+ this.recalculateInsulin({ ...this.props.calculatorParams }),
172
+ );
151
173
  };
152
174
 
153
175
  public declineCarbRecommendation = (): void => {
@@ -168,7 +190,6 @@ export default class RecommendationScreen extends React.Component<IRecommendatio
168
190
  };
169
191
  public closeCalculation = (): void => {
170
192
  this.hideExitModal();
171
- clearTimeout(this.timer);
172
193
  this.props.closeCalculationCallback();
173
194
  };
174
195
 
@@ -184,19 +205,9 @@ export default class RecommendationScreen extends React.Component<IRecommendatio
184
205
  if (this.state.exitModal) {
185
206
  this.hideExitModal();
186
207
  }
187
- this.props.transferToLogbook(
188
- {
189
- suggested: this.suggestedCarbs,
190
- entered: this.state.enteredCarbs,
191
- },
192
- {
193
- suggested: this.state.insulinRecommendation,
194
- entered: this.state.enteredInsulin,
195
- },
196
- this.state.remeasureTime,
197
- );
198
-
199
- clearTimeout(this.timer);
208
+ const carbs: IResult = { suggested: this.suggestedCarbs, entered: this.state.enteredCarbs };
209
+ const insulin: IResult = { suggested: this.state.insulinRecommendation, entered: this.state.enteredInsulin };
210
+ this.props.transferToLogbook(carbs, insulin, this.state.remeasureTime);
200
211
  };
201
212
 
202
213
  public getBGLevelAttentionMessage = (): AttentionMessage => {
@@ -218,9 +229,23 @@ export default class RecommendationScreen extends React.Component<IRecommendatio
218
229
  };
219
230
 
220
231
  public render(): JSX.Element {
221
- const { activeInsulin, recommendationModal, carbRecommendation, enteredCarbs } = this.state;
222
- const { calculatorParams } = this.props;
232
+ if (this.hasError) {
233
+ return <View style={containerStyles.container} />;
234
+ }
235
+
236
+ const {
237
+ activeInsulin,
238
+ recommendationModal,
239
+ carbRecommendation,
240
+ enteredCarbs,
241
+ enteredInsulin,
242
+ insulinRecommendation,
243
+ activityReduction,
244
+ isRecommendationDisplayed,
245
+ } = this.state;
246
+ const { calculatorParams, units } = this.props;
223
247
  const { currentBGL, carbohydrates } = calculatorParams;
248
+ const displayedBGL = units === BGUnit.MMOL_L ? currentBGL : Utils.convertToMGDL(currentBGL);
224
249
 
225
250
  return (
226
251
  <I18nProvider language={this.props.language} i18n={i18n}>
@@ -235,7 +260,7 @@ export default class RecommendationScreen extends React.Component<IRecommendatio
235
260
  />
236
261
  <InfoBars
237
262
  label={i18n._(t`Blood Glucose Level`)}
238
- value={currentBGL ? `${currentBGL}` : null}
263
+ value={currentBGL ? `${displayedBGL}` : null}
239
264
  units={this.props.units}
240
265
  showZeroAsDash={true}
241
266
  />
@@ -254,7 +279,6 @@ export default class RecommendationScreen extends React.Component<IRecommendatio
254
279
  changedRecommendedCarbs={this.updateCarbRecommendation}
255
280
  recommendedCarbs={`${enteredCarbs ?? Math.round(carbRecommendation)}`}
256
281
  removeRecommendedCarbs={this.removeCarbRecommendation}
257
- onError={this.props.onError}
258
282
  />
259
283
  <Remeasure
260
284
  onSliderChange={this.updateRemeasureTime}
@@ -278,14 +302,14 @@ export default class RecommendationScreen extends React.Component<IRecommendatio
278
302
  ) : (
279
303
  <RecommendedInsulin
280
304
  injectionMethod={this.props.injectionMethod}
281
- insulinRecommendation={this.state.enteredInsulin ?? this.state.insulinRecommendation}
282
- activityReduction={this.state.activityReduction}
305
+ insulinRecommendation={insulinRecommendation}
306
+ enteredInsulin={enteredInsulin}
307
+ activityReduction={activityReduction}
283
308
  updateRecommendedInsulin={this.updateInsulinRecommendation}
284
- onError={this.props.onError}
285
309
  />
286
310
  )}
287
311
  <Emotion moodSelected={this.handleMoodSelected} currentMood={this.state.selectedMood} />
288
- <TransferToLogbook visible={this.state.isRecommendationDisplayed} transfer={this.handleTransfer} />
312
+ <TransferToLogbook visible={isRecommendationDisplayed} transfer={this.handleTransfer} />
289
313
  <RecommendationModal
290
314
  isVisible={recommendationModal}
291
315
  suggestedCarbohydrates={carbRecommendation}
@@ -5,6 +5,7 @@ interface IProps {
5
5
  decimalPlaces: number;
6
6
  cleanPartialInput: boolean;
7
7
  negativeAllowed: boolean;
8
+ maxLength?: number;
8
9
  visible(toggle: () => void): void;
9
10
  onEnd?(value: number): void;
10
11
  partialInput?(value: string): void;
@@ -16,10 +16,7 @@ class InvisibleNumberInput extends react_1.default.Component {
16
16
  const round = (value) => {
17
17
  const temp = Number(value) * Math.pow(10, this.props.decimalPlaces);
18
18
  const rounded = Math.round(temp) / Math.pow(10, this.props.decimalPlaces);
19
- if (this.props.negativeAllowed) {
20
- return rounded.toFixed(this.props.decimalPlaces);
21
- }
22
- return Math.abs(rounded).toFixed(this.props.decimalPlaces);
19
+ return rounded.toFixed(this.props.decimalPlaces);
23
20
  };
24
21
  if (!isNaN(Number(replaced))) {
25
22
  return round(replaced);
@@ -28,11 +25,14 @@ class InvisibleNumberInput extends react_1.default.Component {
28
25
  };
29
26
  this.handleOnChangeText = (text) => {
30
27
  const cleaned = this.props.cleanPartialInput ? this.cleanInput(text) : text.replace(/\,/g, `.`);
31
- const replacedSeperator = cleaned.replace(/\.+/g, `.`);
28
+ let replacedSeparator = cleaned.replace(/\.+/g, `.`).replace(/(\d*\.\d*).*/, `$1`);
29
+ if (!this.props.negativeAllowed) {
30
+ replacedSeparator = replacedSeparator.replace(/[^0-9.]/g, ``);
31
+ }
32
32
  this.setState({
33
- value: `${replacedSeperator}`,
33
+ value: `${replacedSeparator}`,
34
34
  });
35
- this.props.partialInput?.(`${replacedSeperator}`);
35
+ this.props.partialInput?.(`${replacedSeparator}`);
36
36
  };
37
37
  this.onEndEdit = () => {
38
38
  const cleaned = this.cleanInput(this.state.value);
@@ -51,7 +51,7 @@ class InvisibleNumberInput extends react_1.default.Component {
51
51
  });
52
52
  }
53
53
  render() {
54
- return (<react_native_1.TextInput accessibilityLabel="InvisibleNumberInput" value={`${this.state.value}`} ref={(textInput) => (this.textInput = textInput)} style={inputStyles.textInput} keyboardType="numeric" onChangeText={this.handleOnChangeText} onEndEditing={this.onEndEdit}/>);
54
+ return (<react_native_1.TextInput accessibilityLabel="InvisibleNumberInput" value={`${this.state.value}`} ref={(textInput) => (this.textInput = textInput)} style={inputStyles.textInput} keyboardType="numeric" onChangeText={this.handleOnChangeText} onEndEditing={this.onEndEdit} maxLength={this.props.maxLength} selectTextOnFocus/>);
55
55
  }
56
56
  }
57
57
  exports.default = InvisibleNumberInput;
@@ -6,6 +6,7 @@ interface IProps {
6
6
  decimalPlaces: number;
7
7
  cleanPartialInput: boolean;
8
8
  negativeAllowed: boolean;
9
+ maxLength?: number;
9
10
  visible(toggle: () => void): void;
10
11
  onEnd?(value: number): void;
11
12
  partialInput?(value: string): void;
@@ -39,10 +40,7 @@ export default class InvisibleNumberInput extends React.Component<IProps, IState
39
40
  const round = (value: string): string => {
40
41
  const temp = Number(value) * Math.pow(10, this.props.decimalPlaces);
41
42
  const rounded = Math.round(temp) / Math.pow(10, this.props.decimalPlaces);
42
- if (this.props.negativeAllowed) {
43
- return rounded.toFixed(this.props.decimalPlaces);
44
- }
45
- return Math.abs(rounded).toFixed(this.props.decimalPlaces);
43
+ return rounded.toFixed(this.props.decimalPlaces);
46
44
  };
47
45
  if (!isNaN(Number(replaced))) {
48
46
  return round(replaced);
@@ -52,11 +50,14 @@ export default class InvisibleNumberInput extends React.Component<IProps, IState
52
50
 
53
51
  public handleOnChangeText = (text: string): void => {
54
52
  const cleaned = this.props.cleanPartialInput ? this.cleanInput(text) : text.replace(/\,/g, `.`);
55
- const replacedSeperator = cleaned.replace(/\.+/g, `.`);
53
+ let replacedSeparator = cleaned.replace(/\.+/g, `.`).replace(/(\d*\.\d*).*/, `$1`);
54
+ if (!this.props.negativeAllowed) {
55
+ replacedSeparator = replacedSeparator.replace(/[^0-9.]/g, ``);
56
+ }
56
57
  this.setState({
57
- value: `${replacedSeperator}`,
58
+ value: `${replacedSeparator}`,
58
59
  });
59
- this.props.partialInput?.(`${replacedSeperator}`);
60
+ this.props.partialInput?.(`${replacedSeparator}`);
60
61
  };
61
62
 
62
63
  public onEndEdit = (): void => {
@@ -74,6 +75,8 @@ export default class InvisibleNumberInput extends React.Component<IProps, IState
74
75
  keyboardType="numeric"
75
76
  onChangeText={this.handleOnChangeText}
76
77
  onEndEditing={this.onEndEdit}
78
+ maxLength={this.props.maxLength}
79
+ selectTextOnFocus
77
80
  />
78
81
  );
79
82
  }