@hedia/recommendation-screen 2.1.42 → 2.1.43-alpha.0
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.
- package/dist/src/RecommendationScreen.js +337 -312
- package/dist/src/components/Header.js +4 -4
- package/dist/src/components/Icon.js +2 -0
- package/dist/src/components/InfoBars.d.ts +0 -2
- package/dist/src/components/InfoBars.js +39 -42
- package/dist/src/components/InvisibleNumberInput.js +70 -71
- package/dist/src/components/LimitationMessage.js +13 -14
- package/dist/src/components/RecentInsulin.js +19 -19
- package/dist/src/components/RecommendationModal.d.ts +0 -1
- package/dist/src/components/RecommendationModal.js +73 -65
- package/dist/src/components/RecommendedCarbs.js +101 -97
- package/dist/src/components/RecommendedInsulin.js +98 -95
- package/dist/src/components/Remeasure.js +34 -32
- package/dist/src/components/TransferToLogbook.js +23 -25
- package/dist/src/components/TwoOptionModal.d.ts +0 -10
- package/dist/src/components/TwoOptionModal.js +10 -18
- package/dist/src/components/activity/Activity.js +14 -12
- package/dist/src/components/activity/ActivityIcon.js +11 -11
- package/dist/src/components/activity/ActivityIntensity.js +16 -19
- package/dist/src/components/mood/Emotion.js +29 -32
- package/dist/src/components/mood/MoodIcon.js +23 -26
- package/dist/src/components/text/TextBold.d.ts +8 -0
- package/dist/src/components/text/TextBold.js +12 -0
- package/dist/src/components/text/TextRegular.d.ts +8 -0
- package/dist/src/components/text/TextRegular.js +12 -0
- package/dist/src/utils/AttentionMessages.js +36 -36
- package/dist/src/utils/RecommendationError.js +1 -0
- package/dist/src/utils/Utils.js +15 -15
- package/package.json +5 -5
|
@@ -35,6 +35,36 @@ LogBox.ignoreLogs([`Setting a timer`]);
|
|
|
35
35
|
* @noInheritDoc
|
|
36
36
|
*/
|
|
37
37
|
export default class RecommendationScreen extends React.Component {
|
|
38
|
+
/** Reference to the timer that prompts the user to make a new calculation after 15 minutes. */
|
|
39
|
+
timer;
|
|
40
|
+
/**
|
|
41
|
+
* The carbohydrate recommendation for the user.
|
|
42
|
+
* This value is saved in a member variable because we want to store it unmodified if the logbook entry
|
|
43
|
+
* gets saved regardless of what other changes were made on the recommendation screen.
|
|
44
|
+
*/
|
|
45
|
+
suggestedCarbs;
|
|
46
|
+
/**
|
|
47
|
+
* A guard against displaying wrong or dangerous information to the user.
|
|
48
|
+
* If an error has occurred, this variable will be set to true and an empty placeholder will be rendered instead of the normal recommendation screen.
|
|
49
|
+
*/
|
|
50
|
+
hasError = false;
|
|
51
|
+
/** The timestamp when the current recommendation was made. For determining if the recommendation is too old and should be hidden from the user. */
|
|
52
|
+
recommendationDate;
|
|
53
|
+
/**
|
|
54
|
+
* A reference to the screens scrollview allowing us to programmatically scroll the screen in the handleNoRecentInsulin() method.
|
|
55
|
+
* The member is initiated without a value but will be set as soon as the component is being rendered.
|
|
56
|
+
*/
|
|
57
|
+
scrollView;
|
|
58
|
+
/**
|
|
59
|
+
* A reference to the eventSubscription that'll be returned by AppState.addEventListener().
|
|
60
|
+
* It'll allow us to later remove the subscription.
|
|
61
|
+
*/
|
|
62
|
+
appStateSubscription;
|
|
63
|
+
/**
|
|
64
|
+
* A reference to the eventSubscription that'll be returned by BackHandler.addEventListener().
|
|
65
|
+
* It'll allow us to later remove the subscription.
|
|
66
|
+
*/
|
|
67
|
+
backHandlerSubscription;
|
|
38
68
|
/**
|
|
39
69
|
* Steps:
|
|
40
70
|
* 1. Call the super() method with the props.
|
|
@@ -61,309 +91,6 @@ export default class RecommendationScreen extends React.Component {
|
|
|
61
91
|
*/
|
|
62
92
|
constructor(props) {
|
|
63
93
|
super(props);
|
|
64
|
-
/**
|
|
65
|
-
* A guard against displaying wrong or dangerous information to the user.
|
|
66
|
-
* If an error has occurred, this variable will be set to true and an empty placeholder will be rendered instead of the normal recommendation screen.
|
|
67
|
-
*/
|
|
68
|
-
this.hasError = false;
|
|
69
|
-
/**
|
|
70
|
-
* Steps:
|
|
71
|
-
* 1. Evaluate a boolean called isOlderThan15Minutes to indicate whether the recommendationDate member variable represents a time more than 15 minutes ago.
|
|
72
|
-
* 2. If nextAppState is ‘active’ and isOlderThan15Minutes is true then call the showTimeoutModal() method.
|
|
73
|
-
* @param nextAppState The new state of the app.
|
|
74
|
-
*/
|
|
75
|
-
this.handleAppStateChange = (nextAppState) => {
|
|
76
|
-
const time = this.recommendationDate.getTime();
|
|
77
|
-
const isOlderThan15Minutes = global.Date.now() - time > Milliseconds.Minute * 15;
|
|
78
|
-
if (nextAppState === `active` && isOlderThan15Minutes) {
|
|
79
|
-
this.showTimeoutModal();
|
|
80
|
-
}
|
|
81
|
-
};
|
|
82
|
-
/**
|
|
83
|
-
* Steps:
|
|
84
|
-
* 1. Set the showTimeoutModal state variable to be true. Use a callback function to call the showBolusBar prop callback function with false as argument when the state has been updated.
|
|
85
|
-
* */
|
|
86
|
-
this.showTimeoutModal = () => {
|
|
87
|
-
this.setState({ showTimeoutModal: true }, () => this.props.showBolusBar(!this.state.showTimeoutModal));
|
|
88
|
-
};
|
|
89
|
-
/**
|
|
90
|
-
* Make a new insulin calculation and set the result to be displayed to the user.
|
|
91
|
-
*
|
|
92
|
-
* Steps:
|
|
93
|
-
* 1. Use calculatorParams as an argument for calling calculateRecommendation(). Unpack bolus, wasLimited, and activityReduction from the result.
|
|
94
|
-
* 2. Set the following state variables:
|
|
95
|
-
* - Set insulinRecommendation to the bolus rounded using the roundValue() function.
|
|
96
|
-
* - Set enteredInsulin to be undefined.
|
|
97
|
-
* - Set wasLimited to be the value returned from the insulin calculator.
|
|
98
|
-
* - Set activityReduction to be the value returned from the insulin calculator.
|
|
99
|
-
* - Set showLimitationMessage to be the wasLimited value returned from the insulin calculator.
|
|
100
|
-
* @param calculatorParams The input values for the bolus calculator itself.
|
|
101
|
-
*/
|
|
102
|
-
this.recalculateInsulin = (calculatorParams) => {
|
|
103
|
-
const { bolus, wasLimited, activityReduction } = Calculator.calculateRecommendation(calculatorParams);
|
|
104
|
-
this.setState({
|
|
105
|
-
insulinRecommendation: Utils.roundValue(bolus, this.props.injectionMethod),
|
|
106
|
-
enteredInsulin: null,
|
|
107
|
-
wasLimited,
|
|
108
|
-
activityReduction,
|
|
109
|
-
showLimitationMessage: wasLimited,
|
|
110
|
-
});
|
|
111
|
-
};
|
|
112
|
-
/**
|
|
113
|
-
* Handle presses on the exit button in the header bar.
|
|
114
|
-
*
|
|
115
|
-
* Steps:
|
|
116
|
-
* 1. If the insulin recommendation is being displayed (the isRecommendationDisplayed state variable is true):
|
|
117
|
-
* - Set the showExitModal state variable to true. When the state has been updated, call the showBolusBar prop callback function with the inverse value of the showExitModal state variable as argument.
|
|
118
|
-
* 2. Else:
|
|
119
|
-
* - Call the exitCallback prop callback function.
|
|
120
|
-
*/
|
|
121
|
-
this.onExit = () => {
|
|
122
|
-
if (this.state.isRecommendationDisplayed) {
|
|
123
|
-
this.setState({ showExitModal: true }, () => this.props.showBolusBar(!this.state.showExitModal));
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
this.props.exitCallback();
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
/**
|
|
130
|
-
* Callback to be executed by the back handler listener.
|
|
131
|
-
*
|
|
132
|
-
* Steps:
|
|
133
|
-
* 1. Call the onExist method
|
|
134
|
-
* 2. Return true so that the default behaviour is overwritten.
|
|
135
|
-
*/
|
|
136
|
-
this.onBackHandlerPress = () => {
|
|
137
|
-
this.onExit();
|
|
138
|
-
return true;
|
|
139
|
-
};
|
|
140
|
-
/**
|
|
141
|
-
* Hide the modal that shows attention messages.
|
|
142
|
-
*
|
|
143
|
-
* Steps:
|
|
144
|
-
* 1. Set the recommendationModal state variable to false.
|
|
145
|
-
*/
|
|
146
|
-
this.hideAttentionModal = () => {
|
|
147
|
-
this.setState({ recommendationModal: false });
|
|
148
|
-
};
|
|
149
|
-
/**
|
|
150
|
-
* Hide the modal that shows attention messages.
|
|
151
|
-
*
|
|
152
|
-
* Steps:
|
|
153
|
-
* 1. Set the showLimitationMessage state variable to false.
|
|
154
|
-
*/
|
|
155
|
-
this.hideLimitationMessage = () => {
|
|
156
|
-
this.setState({ showLimitationMessage: false });
|
|
157
|
-
};
|
|
158
|
-
/**
|
|
159
|
-
* Hide the exit modal. To be used when the user closes the modal directly or in some way exits the recommendation screen.
|
|
160
|
-
*
|
|
161
|
-
* Steps:
|
|
162
|
-
* 1. Set the showExitModal state variable to false.
|
|
163
|
-
* When the state has been updated, call the showBolusBar prop callback function with the inverse value of the showExitModal state variable as argument.
|
|
164
|
-
*/
|
|
165
|
-
this.hideExitModal = () => {
|
|
166
|
-
this.setState({ showExitModal: false }, () => this.props.showBolusBar(!this.state.showExitModal));
|
|
167
|
-
};
|
|
168
|
-
/**
|
|
169
|
-
* Hide the modal that warns the user that their recommendation is old.
|
|
170
|
-
*
|
|
171
|
-
* Steps:
|
|
172
|
-
* 1. Set the showTimeoutModal state variable to false.
|
|
173
|
-
* When the state has been updated, call the showBolusBar prop callback function with the inverse value of the showTimeoutModal state variable as argument.
|
|
174
|
-
*/
|
|
175
|
-
this.hideTimeoutModal = () => {
|
|
176
|
-
this.setState({ showTimeoutModal: false }, () => this.props.showBolusBar(!this.state.showTimeoutModal));
|
|
177
|
-
};
|
|
178
|
-
/**
|
|
179
|
-
* Used as a callback function for the Remeasure component to update the state when the remeasure time slider’s value changes.
|
|
180
|
-
*
|
|
181
|
-
* Steps:
|
|
182
|
-
* 1. Set the remeasureTime state variable to the value of the remeasureTime argument.
|
|
183
|
-
* @param remeasureTime The number of hours for which to wait before reminding the user to measure their BGL again. 0 indicates that the user should not be reminded.
|
|
184
|
-
*/
|
|
185
|
-
this.updateRemeasureTime = (remeasureTime) => {
|
|
186
|
-
this.setState({ remeasureTime });
|
|
187
|
-
};
|
|
188
|
-
/**
|
|
189
|
-
* Handle what happens if the user taps “No” to the question about injecting insulin within the last 4 hours.
|
|
190
|
-
* The card that prompts the user to answer if they have injected insulin within the last 4 hours shall be hidden and
|
|
191
|
-
* the screen shall automatically be scrolled to the bottom so the user can see the now visible “Transfer to logbook” button.
|
|
192
|
-
*
|
|
193
|
-
* Steps:
|
|
194
|
-
* 1. Set the isRecommendationDisplayed state variable to be true.
|
|
195
|
-
* 2. As a callback to the setState() method, define a new anonymous function that calls setTimeout() with a duration of 0 milliseconds.
|
|
196
|
-
* When the time expires, call the scrollToEnd() method of the scrollView member, with the animated argument set to true.
|
|
197
|
-
* This ensures that the scroll event happens after all other events that get queued to happen at the same time,
|
|
198
|
-
* so all relevant elements are visible on the screen and the scroll happens reliably.
|
|
199
|
-
*/
|
|
200
|
-
this.handleNoRecentInsulin = () => {
|
|
201
|
-
this.setState({ isRecommendationDisplayed: true }, () => {
|
|
202
|
-
setTimeout(() => {
|
|
203
|
-
this.scrollView?.scrollToEnd({ animated: true });
|
|
204
|
-
}, 0);
|
|
205
|
-
});
|
|
206
|
-
};
|
|
207
|
-
/**
|
|
208
|
-
* Handle what happens when the user changes the content of the additional carbohydrates input field.
|
|
209
|
-
*
|
|
210
|
-
* Steps:
|
|
211
|
-
* 1. Set the enteredCarbs state variable to the value of the enteredCarbs argument.
|
|
212
|
-
* 2. As a callback to the setState() method, define a new anonymous function that calls the recalculateInsulin() function using
|
|
213
|
-
* a copy of the calculatorParams prop where the carbohydrates property has been overwritten to be
|
|
214
|
-
* the sum of the carbohydrates property of the calculatorParams prop and the enteredCarbs argument.
|
|
215
|
-
* @param enteredCarbs The amount of carbohydrates in grams that has been entered in the additional carbohydrates input field.
|
|
216
|
-
*/
|
|
217
|
-
this.updateCarbRecommendation = (enteredCarbs) => {
|
|
218
|
-
const providedCarbs = this.props.calculatorParams.carbohydrates;
|
|
219
|
-
this.setState({ enteredCarbs }, () => {
|
|
220
|
-
this.recalculateInsulin({ ...this.props.calculatorParams, carbohydrates: providedCarbs + enteredCarbs });
|
|
221
|
-
});
|
|
222
|
-
};
|
|
223
|
-
/**
|
|
224
|
-
* Handle what happens when the cross button by the additional carbohydrates button is tapped.
|
|
225
|
-
*
|
|
226
|
-
* Steps:
|
|
227
|
-
* 1. Set both the enteredCarbs and the carbRecommendation state variables to null.
|
|
228
|
-
* 2. As a callback to the setState() method, define a new anonymous function that calls the recalculateInsulin() function using a copy of the calculatorParams prop.
|
|
229
|
-
*/
|
|
230
|
-
this.removeCarbRecommendation = () => {
|
|
231
|
-
this.setState({ enteredCarbs: null, carbRecommendation: null }, () => this.recalculateInsulin({ ...this.props.calculatorParams }));
|
|
232
|
-
};
|
|
233
|
-
/**
|
|
234
|
-
* Handle what happens when the user is recommended to eat additional carbohydrates but taps the decline button.
|
|
235
|
-
*
|
|
236
|
-
* Steps:
|
|
237
|
-
* 1. Call the hideAttentionModal() method.
|
|
238
|
-
* 2. Call the removeCarbRecommendation() method.
|
|
239
|
-
* 3. Call the carbRecommendationAnswer() prop callback function with false as argument.
|
|
240
|
-
*/
|
|
241
|
-
this.declineCarbRecommendation = () => {
|
|
242
|
-
this.hideAttentionModal();
|
|
243
|
-
this.removeCarbRecommendation();
|
|
244
|
-
this.props.carbRecommendationAnswer(false);
|
|
245
|
-
};
|
|
246
|
-
/**
|
|
247
|
-
* Handle what happens when the user is recommended to eat additional carbohydrates and they tap the accept button.
|
|
248
|
-
*
|
|
249
|
-
* Steps:
|
|
250
|
-
* 1. Call the hideAttentionModal() method.
|
|
251
|
-
* 2. Call the carbRecommendationAnswer() prop callback function with true as argument.
|
|
252
|
-
*/
|
|
253
|
-
this.acceptCarbRecommendation = () => {
|
|
254
|
-
this.hideAttentionModal();
|
|
255
|
-
this.props.carbRecommendationAnswer(true);
|
|
256
|
-
};
|
|
257
|
-
/**
|
|
258
|
-
* Handles what happens when the user hits the “close calculation”-button on the exit modal.
|
|
259
|
-
*
|
|
260
|
-
* Steps:
|
|
261
|
-
* 1. If the showExitModal state variable is true then call the hideExitModal() method. Otherwise, call the hideTimeoutModal() method
|
|
262
|
-
* 2. Call the closeCalculationCallback prop callback function.
|
|
263
|
-
*/
|
|
264
|
-
this.closeCalculation = () => {
|
|
265
|
-
this.state.showExitModal ? this.hideExitModal() : this.hideTimeoutModal();
|
|
266
|
-
this.props.closeCalculationCallback();
|
|
267
|
-
};
|
|
268
|
-
/**
|
|
269
|
-
* Close the current recommendation and start a new bolus calculation.
|
|
270
|
-
*
|
|
271
|
-
* Steps:
|
|
272
|
-
* 1. Call the hideTimeoutModal() method.
|
|
273
|
-
* 2. Call the restartCalculation prop callback function.
|
|
274
|
-
*/
|
|
275
|
-
this.restartCalculation = () => {
|
|
276
|
-
this.hideTimeoutModal();
|
|
277
|
-
this.props.restartCalculation();
|
|
278
|
-
};
|
|
279
|
-
/**
|
|
280
|
-
* Used as a callback function for the Emotion component to update the state when a mood icon is tapped.
|
|
281
|
-
*
|
|
282
|
-
* Steps:
|
|
283
|
-
* 1. Set the selectedMood state variable to the value of the selectedMood argument.
|
|
284
|
-
* @param selectedMood he mood that should be selected going forward or null if no mood should be selected.
|
|
285
|
-
*/
|
|
286
|
-
this.handleMoodSelected = (selectedMood) => {
|
|
287
|
-
this.setState({ selectedMood });
|
|
288
|
-
};
|
|
289
|
-
/**
|
|
290
|
-
* Handle what happens when the user changes the content of the insulin input field.
|
|
291
|
-
*
|
|
292
|
-
* Steps:
|
|
293
|
-
* 1. Set the enteredInsulin state variable to the value of the enteredInsulin argument.
|
|
294
|
-
* @param enteredInsulin The amount of insulin (in units) that has been entered in the insulin input field.
|
|
295
|
-
*/
|
|
296
|
-
this.updateInsulinRecommendation = (enteredInsulin) => {
|
|
297
|
-
this.setState({ enteredInsulin });
|
|
298
|
-
};
|
|
299
|
-
/**
|
|
300
|
-
* Handle what happens when the “Transfer to Logbook” button is pressed.
|
|
301
|
-
* Namely, the entered data should be saved in a logbook entry and the recommendation screen should be closed.
|
|
302
|
-
*
|
|
303
|
-
* Steps:
|
|
304
|
-
* 1. Unpack the enteredCarbs, enteredInsulin, insulinRecommendation, remeasureTime, and showExitModal state variables
|
|
305
|
-
* 2. Create an IResult object called carbs consisting of suggestedCarbs and enteredCarbs.
|
|
306
|
-
* 3. Create an IResult object called Insulin consisting of insulinRecommendation and enteredInsulin.
|
|
307
|
-
* 4. If showExitModal is true then call the hideExitModal() method. otherwise call the hideTimeoutModal() method.
|
|
308
|
-
* 5. Call the transferToLogbook prop callback function with the following arguments:
|
|
309
|
-
* - Set the carbs argument to the carbs IResult object.
|
|
310
|
-
* - Set the insulin argument to the insulin IResult object.
|
|
311
|
-
* - Set the reminder argument to the remeasureTime state variable.
|
|
312
|
-
* - Set the recommendationDate argument to the recommendationDate member variable.
|
|
313
|
-
*/
|
|
314
|
-
this.handleTransfer = () => {
|
|
315
|
-
const { enteredCarbs, enteredInsulin, insulinRecommendation, remeasureTime, showExitModal, selectedMood } = this.state;
|
|
316
|
-
const carbs = { suggested: this.suggestedCarbs, entered: enteredCarbs };
|
|
317
|
-
const insulin = { suggested: insulinRecommendation, entered: enteredInsulin };
|
|
318
|
-
showExitModal ? this.hideExitModal() : this.hideTimeoutModal();
|
|
319
|
-
this.props.transferToLogbook(carbs, insulin, remeasureTime, this.recommendationDate, selectedMood);
|
|
320
|
-
};
|
|
321
|
-
/**
|
|
322
|
-
* Get the attention message that should be displayed for the user to draw their attention to noteworthy circumstances regarding their current blood glucose level.
|
|
323
|
-
*
|
|
324
|
-
* Steps:
|
|
325
|
-
* 1. Unpack calculatorParams and latestLogbookFrom6Hours from the props.
|
|
326
|
-
* 2. Unpack currentBGL and activity from calculatorparams.
|
|
327
|
-
* 3. Get bgLevel, the categorisation of the blood glucose level, by calling the getBGLevel() function with the currentBGL and latestLogbookFrom6Hours as arguments.
|
|
328
|
-
* 4. Return the attention message that is returned when calling getAttentionMessage() using bgLevel and activity as arguments.
|
|
329
|
-
* @returns A string describing what the user needs to be aware of regarding their current blood glucose level.
|
|
330
|
-
* If there is nothing noteworthy, null will be returned instead.
|
|
331
|
-
*/
|
|
332
|
-
this.getBGLevelAttentionMessage = () => {
|
|
333
|
-
const { calculatorParams, latestLogbookFrom6Hours } = this.props;
|
|
334
|
-
const { currentBGL, activity } = calculatorParams;
|
|
335
|
-
const bgLevel = getBGLevel(currentBGL, latestLogbookFrom6Hours);
|
|
336
|
-
return getAttentionMessage(bgLevel, activity);
|
|
337
|
-
};
|
|
338
|
-
/**
|
|
339
|
-
* Get the initial value for the remeasurement reminder time slider depending on the user’s entered information.
|
|
340
|
-
*
|
|
341
|
-
* Steps:
|
|
342
|
-
* 1. Unpack calculatorParams, userReminder, and latestLogbookFrom6Hours from the props.
|
|
343
|
-
* 2. Unpack currentBGL, activity, and carbohydrates from calculatorParams.
|
|
344
|
-
* 3. Get bgLevel, the categorisation of the blood glucose level, by calling the getBGLevel() function with the currentBGL and latestLogbookFrom6Hours as arguments.
|
|
345
|
-
* 4. Return the attention message that is returned when calling getReminder() using bgLevel, carbohydrates, userReminder, and activity as arguments.
|
|
346
|
-
* @returns The time interval in hours that should be used as the initial value for the remeasurement reminder time slider.
|
|
347
|
-
*/
|
|
348
|
-
this.getBGLevelRemeasurementReminder = () => {
|
|
349
|
-
const { calculatorParams, userReminder, latestLogbookFrom6Hours } = this.props;
|
|
350
|
-
const { currentBGL, activity, carbohydrates } = calculatorParams;
|
|
351
|
-
const bgLevel = getBGLevel(currentBGL, latestLogbookFrom6Hours);
|
|
352
|
-
return getReminder(bgLevel, carbohydrates, userReminder, activity);
|
|
353
|
-
};
|
|
354
|
-
/**
|
|
355
|
-
* Get the attention message that should be displayed to the user to let them know that the insulin recommendation that
|
|
356
|
-
* is being displayed to them was limited by the maximum insulin threshold.
|
|
357
|
-
*
|
|
358
|
-
* Steps:
|
|
359
|
-
* 1. Unpack the wasLimited and activityReduction state variables.
|
|
360
|
-
* 2. Return the result from calling getLimitationMessage() with wasLimited and activityReduction as arguments.
|
|
361
|
-
* @returns A message to inform the user how the insulin recommendation was limited. If there is no limitation attention message, null will be returned instead.
|
|
362
|
-
*/
|
|
363
|
-
this.getLimitationAttentionMessage = () => {
|
|
364
|
-
const { wasLimited, activityReduction } = this.state;
|
|
365
|
-
return getLimitationMessage(wasLimited, activityReduction);
|
|
366
|
-
};
|
|
367
94
|
try {
|
|
368
95
|
validateParams(props);
|
|
369
96
|
this.recommendationDate = new Date(global.Date.now());
|
|
@@ -423,6 +150,304 @@ export default class RecommendationScreen extends React.Component {
|
|
|
423
150
|
this.appStateSubscription?.remove();
|
|
424
151
|
this.backHandlerSubscription?.remove();
|
|
425
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Steps:
|
|
155
|
+
* 1. Evaluate a boolean called isOlderThan15Minutes to indicate whether the recommendationDate member variable represents a time more than 15 minutes ago.
|
|
156
|
+
* 2. If nextAppState is ‘active’ and isOlderThan15Minutes is true then call the showTimeoutModal() method.
|
|
157
|
+
* @param nextAppState The new state of the app.
|
|
158
|
+
*/
|
|
159
|
+
handleAppStateChange = (nextAppState) => {
|
|
160
|
+
const time = this.recommendationDate.getTime();
|
|
161
|
+
const isOlderThan15Minutes = global.Date.now() - time > Milliseconds.Minute * 15;
|
|
162
|
+
if (nextAppState === `active` && isOlderThan15Minutes) {
|
|
163
|
+
this.showTimeoutModal();
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
/**
|
|
167
|
+
* Steps:
|
|
168
|
+
* 1. Set the showTimeoutModal state variable to be true. Use a callback function to call the showBolusBar prop callback function with false as argument when the state has been updated.
|
|
169
|
+
* */
|
|
170
|
+
showTimeoutModal = () => {
|
|
171
|
+
this.setState({ showTimeoutModal: true }, () => this.props.showBolusBar(!this.state.showTimeoutModal));
|
|
172
|
+
};
|
|
173
|
+
/**
|
|
174
|
+
* Make a new insulin calculation and set the result to be displayed to the user.
|
|
175
|
+
*
|
|
176
|
+
* Steps:
|
|
177
|
+
* 1. Use calculatorParams as an argument for calling calculateRecommendation(). Unpack bolus, wasLimited, and activityReduction from the result.
|
|
178
|
+
* 2. Set the following state variables:
|
|
179
|
+
* - Set insulinRecommendation to the bolus rounded using the roundValue() function.
|
|
180
|
+
* - Set enteredInsulin to be undefined.
|
|
181
|
+
* - Set wasLimited to be the value returned from the insulin calculator.
|
|
182
|
+
* - Set activityReduction to be the value returned from the insulin calculator.
|
|
183
|
+
* - Set showLimitationMessage to be the wasLimited value returned from the insulin calculator.
|
|
184
|
+
* @param calculatorParams The input values for the bolus calculator itself.
|
|
185
|
+
*/
|
|
186
|
+
recalculateInsulin = (calculatorParams) => {
|
|
187
|
+
const { bolus, wasLimited, activityReduction } = Calculator.calculateRecommendation(calculatorParams);
|
|
188
|
+
this.setState({
|
|
189
|
+
insulinRecommendation: Utils.roundValue(bolus, this.props.injectionMethod),
|
|
190
|
+
enteredInsulin: null,
|
|
191
|
+
wasLimited,
|
|
192
|
+
activityReduction,
|
|
193
|
+
showLimitationMessage: wasLimited,
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Handle presses on the exit button in the header bar.
|
|
198
|
+
*
|
|
199
|
+
* Steps:
|
|
200
|
+
* 1. If the insulin recommendation is being displayed (the isRecommendationDisplayed state variable is true):
|
|
201
|
+
* - Set the showExitModal state variable to true. When the state has been updated, call the showBolusBar prop callback function with the inverse value of the showExitModal state variable as argument.
|
|
202
|
+
* 2. Else:
|
|
203
|
+
* - Call the exitCallback prop callback function.
|
|
204
|
+
*/
|
|
205
|
+
onExit = () => {
|
|
206
|
+
if (this.state.isRecommendationDisplayed) {
|
|
207
|
+
this.setState({ showExitModal: true }, () => this.props.showBolusBar(!this.state.showExitModal));
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
this.props.exitCallback();
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* Callback to be executed by the back handler listener.
|
|
215
|
+
*
|
|
216
|
+
* Steps:
|
|
217
|
+
* 1. Call the onExist method
|
|
218
|
+
* 2. Return true so that the default behaviour is overwritten.
|
|
219
|
+
*/
|
|
220
|
+
onBackHandlerPress = () => {
|
|
221
|
+
this.onExit();
|
|
222
|
+
return true;
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Hide the modal that shows attention messages.
|
|
226
|
+
*
|
|
227
|
+
* Steps:
|
|
228
|
+
* 1. Set the recommendationModal state variable to false.
|
|
229
|
+
*/
|
|
230
|
+
hideAttentionModal = () => {
|
|
231
|
+
this.setState({ recommendationModal: false });
|
|
232
|
+
};
|
|
233
|
+
/**
|
|
234
|
+
* Hide the modal that shows attention messages.
|
|
235
|
+
*
|
|
236
|
+
* Steps:
|
|
237
|
+
* 1. Set the showLimitationMessage state variable to false.
|
|
238
|
+
*/
|
|
239
|
+
hideLimitationMessage = () => {
|
|
240
|
+
this.setState({ showLimitationMessage: false });
|
|
241
|
+
};
|
|
242
|
+
/**
|
|
243
|
+
* Hide the exit modal. To be used when the user closes the modal directly or in some way exits the recommendation screen.
|
|
244
|
+
*
|
|
245
|
+
* Steps:
|
|
246
|
+
* 1. Set the showExitModal state variable to false.
|
|
247
|
+
* When the state has been updated, call the showBolusBar prop callback function with the inverse value of the showExitModal state variable as argument.
|
|
248
|
+
*/
|
|
249
|
+
hideExitModal = () => {
|
|
250
|
+
this.setState({ showExitModal: false }, () => this.props.showBolusBar(!this.state.showExitModal));
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Hide the modal that warns the user that their recommendation is old.
|
|
254
|
+
*
|
|
255
|
+
* Steps:
|
|
256
|
+
* 1. Set the showTimeoutModal state variable to false.
|
|
257
|
+
* When the state has been updated, call the showBolusBar prop callback function with the inverse value of the showTimeoutModal state variable as argument.
|
|
258
|
+
*/
|
|
259
|
+
hideTimeoutModal = () => {
|
|
260
|
+
this.setState({ showTimeoutModal: false }, () => this.props.showBolusBar(!this.state.showTimeoutModal));
|
|
261
|
+
};
|
|
262
|
+
/**
|
|
263
|
+
* Used as a callback function for the Remeasure component to update the state when the remeasure time slider’s value changes.
|
|
264
|
+
*
|
|
265
|
+
* Steps:
|
|
266
|
+
* 1. Set the remeasureTime state variable to the value of the remeasureTime argument.
|
|
267
|
+
* @param remeasureTime The number of hours for which to wait before reminding the user to measure their BGL again. 0 indicates that the user should not be reminded.
|
|
268
|
+
*/
|
|
269
|
+
updateRemeasureTime = (remeasureTime) => {
|
|
270
|
+
this.setState({ remeasureTime });
|
|
271
|
+
};
|
|
272
|
+
/**
|
|
273
|
+
* Handle what happens if the user taps “No” to the question about injecting insulin within the last 4 hours.
|
|
274
|
+
* The card that prompts the user to answer if they have injected insulin within the last 4 hours shall be hidden and
|
|
275
|
+
* the screen shall automatically be scrolled to the bottom so the user can see the now visible “Transfer to logbook” button.
|
|
276
|
+
*
|
|
277
|
+
* Steps:
|
|
278
|
+
* 1. Set the isRecommendationDisplayed state variable to be true.
|
|
279
|
+
* 2. As a callback to the setState() method, define a new anonymous function that calls setTimeout() with a duration of 0 milliseconds.
|
|
280
|
+
* When the time expires, call the scrollToEnd() method of the scrollView member, with the animated argument set to true.
|
|
281
|
+
* This ensures that the scroll event happens after all other events that get queued to happen at the same time,
|
|
282
|
+
* so all relevant elements are visible on the screen and the scroll happens reliably.
|
|
283
|
+
*/
|
|
284
|
+
handleNoRecentInsulin = () => {
|
|
285
|
+
this.setState({ isRecommendationDisplayed: true }, () => {
|
|
286
|
+
setTimeout(() => {
|
|
287
|
+
this.scrollView?.scrollToEnd({ animated: true });
|
|
288
|
+
}, 0);
|
|
289
|
+
});
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* Handle what happens when the user changes the content of the additional carbohydrates input field.
|
|
293
|
+
*
|
|
294
|
+
* Steps:
|
|
295
|
+
* 1. Set the enteredCarbs state variable to the value of the enteredCarbs argument.
|
|
296
|
+
* 2. As a callback to the setState() method, define a new anonymous function that calls the recalculateInsulin() function using
|
|
297
|
+
* a copy of the calculatorParams prop where the carbohydrates property has been overwritten to be
|
|
298
|
+
* the sum of the carbohydrates property of the calculatorParams prop and the enteredCarbs argument.
|
|
299
|
+
* @param enteredCarbs The amount of carbohydrates in grams that has been entered in the additional carbohydrates input field.
|
|
300
|
+
*/
|
|
301
|
+
updateCarbRecommendation = (enteredCarbs) => {
|
|
302
|
+
const providedCarbs = this.props.calculatorParams.carbohydrates;
|
|
303
|
+
this.setState({ enteredCarbs }, () => {
|
|
304
|
+
this.recalculateInsulin({ ...this.props.calculatorParams, carbohydrates: providedCarbs + enteredCarbs });
|
|
305
|
+
});
|
|
306
|
+
};
|
|
307
|
+
/**
|
|
308
|
+
* Handle what happens when the cross button by the additional carbohydrates button is tapped.
|
|
309
|
+
*
|
|
310
|
+
* Steps:
|
|
311
|
+
* 1. Set both the enteredCarbs and the carbRecommendation state variables to null.
|
|
312
|
+
* 2. As a callback to the setState() method, define a new anonymous function that calls the recalculateInsulin() function using a copy of the calculatorParams prop.
|
|
313
|
+
*/
|
|
314
|
+
removeCarbRecommendation = () => {
|
|
315
|
+
this.setState({ enteredCarbs: null, carbRecommendation: null }, () => this.recalculateInsulin({ ...this.props.calculatorParams }));
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* Handle what happens when the user is recommended to eat additional carbohydrates but taps the decline button.
|
|
319
|
+
*
|
|
320
|
+
* Steps:
|
|
321
|
+
* 1. Call the hideAttentionModal() method.
|
|
322
|
+
* 2. Call the removeCarbRecommendation() method.
|
|
323
|
+
* 3. Call the carbRecommendationAnswer() prop callback function with false as argument.
|
|
324
|
+
*/
|
|
325
|
+
declineCarbRecommendation = () => {
|
|
326
|
+
this.hideAttentionModal();
|
|
327
|
+
this.removeCarbRecommendation();
|
|
328
|
+
this.props.carbRecommendationAnswer(false);
|
|
329
|
+
};
|
|
330
|
+
/**
|
|
331
|
+
* Handle what happens when the user is recommended to eat additional carbohydrates and they tap the accept button.
|
|
332
|
+
*
|
|
333
|
+
* Steps:
|
|
334
|
+
* 1. Call the hideAttentionModal() method.
|
|
335
|
+
* 2. Call the carbRecommendationAnswer() prop callback function with true as argument.
|
|
336
|
+
*/
|
|
337
|
+
acceptCarbRecommendation = () => {
|
|
338
|
+
this.hideAttentionModal();
|
|
339
|
+
this.props.carbRecommendationAnswer(true);
|
|
340
|
+
};
|
|
341
|
+
/**
|
|
342
|
+
* Handles what happens when the user hits the “close calculation”-button on the exit modal.
|
|
343
|
+
*
|
|
344
|
+
* Steps:
|
|
345
|
+
* 1. If the showExitModal state variable is true then call the hideExitModal() method. Otherwise, call the hideTimeoutModal() method
|
|
346
|
+
* 2. Call the closeCalculationCallback prop callback function.
|
|
347
|
+
*/
|
|
348
|
+
closeCalculation = () => {
|
|
349
|
+
this.state.showExitModal ? this.hideExitModal() : this.hideTimeoutModal();
|
|
350
|
+
this.props.closeCalculationCallback();
|
|
351
|
+
};
|
|
352
|
+
/**
|
|
353
|
+
* Close the current recommendation and start a new bolus calculation.
|
|
354
|
+
*
|
|
355
|
+
* Steps:
|
|
356
|
+
* 1. Call the hideTimeoutModal() method.
|
|
357
|
+
* 2. Call the restartCalculation prop callback function.
|
|
358
|
+
*/
|
|
359
|
+
restartCalculation = () => {
|
|
360
|
+
this.hideTimeoutModal();
|
|
361
|
+
this.props.restartCalculation();
|
|
362
|
+
};
|
|
363
|
+
/**
|
|
364
|
+
* Used as a callback function for the Emotion component to update the state when a mood icon is tapped.
|
|
365
|
+
*
|
|
366
|
+
* Steps:
|
|
367
|
+
* 1. Set the selectedMood state variable to the value of the selectedMood argument.
|
|
368
|
+
* @param selectedMood he mood that should be selected going forward or null if no mood should be selected.
|
|
369
|
+
*/
|
|
370
|
+
handleMoodSelected = (selectedMood) => {
|
|
371
|
+
this.setState({ selectedMood });
|
|
372
|
+
};
|
|
373
|
+
/**
|
|
374
|
+
* Handle what happens when the user changes the content of the insulin input field.
|
|
375
|
+
*
|
|
376
|
+
* Steps:
|
|
377
|
+
* 1. Set the enteredInsulin state variable to the value of the enteredInsulin argument.
|
|
378
|
+
* @param enteredInsulin The amount of insulin (in units) that has been entered in the insulin input field.
|
|
379
|
+
*/
|
|
380
|
+
updateInsulinRecommendation = (enteredInsulin) => {
|
|
381
|
+
this.setState({ enteredInsulin });
|
|
382
|
+
};
|
|
383
|
+
/**
|
|
384
|
+
* Handle what happens when the “Transfer to Logbook” button is pressed.
|
|
385
|
+
* Namely, the entered data should be saved in a logbook entry and the recommendation screen should be closed.
|
|
386
|
+
*
|
|
387
|
+
* Steps:
|
|
388
|
+
* 1. Unpack the enteredCarbs, enteredInsulin, insulinRecommendation, remeasureTime, and showExitModal state variables
|
|
389
|
+
* 2. Create an IResult object called carbs consisting of suggestedCarbs and enteredCarbs.
|
|
390
|
+
* 3. Create an IResult object called Insulin consisting of insulinRecommendation and enteredInsulin.
|
|
391
|
+
* 4. If showExitModal is true then call the hideExitModal() method. otherwise call the hideTimeoutModal() method.
|
|
392
|
+
* 5. Call the transferToLogbook prop callback function with the following arguments:
|
|
393
|
+
* - Set the carbs argument to the carbs IResult object.
|
|
394
|
+
* - Set the insulin argument to the insulin IResult object.
|
|
395
|
+
* - Set the reminder argument to the remeasureTime state variable.
|
|
396
|
+
* - Set the recommendationDate argument to the recommendationDate member variable.
|
|
397
|
+
*/
|
|
398
|
+
handleTransfer = () => {
|
|
399
|
+
const { enteredCarbs, enteredInsulin, insulinRecommendation, remeasureTime, showExitModal, selectedMood } = this.state;
|
|
400
|
+
const carbs = { suggested: this.suggestedCarbs, entered: enteredCarbs };
|
|
401
|
+
const insulin = { suggested: insulinRecommendation, entered: enteredInsulin };
|
|
402
|
+
showExitModal ? this.hideExitModal() : this.hideTimeoutModal();
|
|
403
|
+
this.props.transferToLogbook(carbs, insulin, remeasureTime, this.recommendationDate, selectedMood);
|
|
404
|
+
};
|
|
405
|
+
/**
|
|
406
|
+
* Get the attention message that should be displayed for the user to draw their attention to noteworthy circumstances regarding their current blood glucose level.
|
|
407
|
+
*
|
|
408
|
+
* Steps:
|
|
409
|
+
* 1. Unpack calculatorParams and latestLogbookFrom6Hours from the props.
|
|
410
|
+
* 2. Unpack currentBGL and activity from calculatorparams.
|
|
411
|
+
* 3. Get bgLevel, the categorisation of the blood glucose level, by calling the getBGLevel() function with the currentBGL and latestLogbookFrom6Hours as arguments.
|
|
412
|
+
* 4. Return the attention message that is returned when calling getAttentionMessage() using bgLevel and activity as arguments.
|
|
413
|
+
* @returns A string describing what the user needs to be aware of regarding their current blood glucose level.
|
|
414
|
+
* If there is nothing noteworthy, null will be returned instead.
|
|
415
|
+
*/
|
|
416
|
+
getBGLevelAttentionMessage = () => {
|
|
417
|
+
const { calculatorParams, latestLogbookFrom6Hours } = this.props;
|
|
418
|
+
const { currentBGL, activity } = calculatorParams;
|
|
419
|
+
const bgLevel = getBGLevel(currentBGL, latestLogbookFrom6Hours);
|
|
420
|
+
return getAttentionMessage(bgLevel, activity);
|
|
421
|
+
};
|
|
422
|
+
/**
|
|
423
|
+
* Get the initial value for the remeasurement reminder time slider depending on the user’s entered information.
|
|
424
|
+
*
|
|
425
|
+
* Steps:
|
|
426
|
+
* 1. Unpack calculatorParams, userReminder, and latestLogbookFrom6Hours from the props.
|
|
427
|
+
* 2. Unpack currentBGL, activity, and carbohydrates from calculatorParams.
|
|
428
|
+
* 3. Get bgLevel, the categorisation of the blood glucose level, by calling the getBGLevel() function with the currentBGL and latestLogbookFrom6Hours as arguments.
|
|
429
|
+
* 4. Return the attention message that is returned when calling getReminder() using bgLevel, carbohydrates, userReminder, and activity as arguments.
|
|
430
|
+
* @returns The time interval in hours that should be used as the initial value for the remeasurement reminder time slider.
|
|
431
|
+
*/
|
|
432
|
+
getBGLevelRemeasurementReminder = () => {
|
|
433
|
+
const { calculatorParams, userReminder, latestLogbookFrom6Hours } = this.props;
|
|
434
|
+
const { currentBGL, activity, carbohydrates } = calculatorParams;
|
|
435
|
+
const bgLevel = getBGLevel(currentBGL, latestLogbookFrom6Hours);
|
|
436
|
+
return getReminder(bgLevel, carbohydrates, userReminder, activity);
|
|
437
|
+
};
|
|
438
|
+
/**
|
|
439
|
+
* Get the attention message that should be displayed to the user to let them know that the insulin recommendation that
|
|
440
|
+
* is being displayed to them was limited by the maximum insulin threshold.
|
|
441
|
+
*
|
|
442
|
+
* Steps:
|
|
443
|
+
* 1. Unpack the wasLimited and activityReduction state variables.
|
|
444
|
+
* 2. Return the result from calling getLimitationMessage() with wasLimited and activityReduction as arguments.
|
|
445
|
+
* @returns A message to inform the user how the insulin recommendation was limited. If there is no limitation attention message, null will be returned instead.
|
|
446
|
+
*/
|
|
447
|
+
getLimitationAttentionMessage = () => {
|
|
448
|
+
const { wasLimited, activityReduction } = this.state;
|
|
449
|
+
return getLimitationMessage(wasLimited, activityReduction);
|
|
450
|
+
};
|
|
426
451
|
/** Render a JSX element for displaying the insulin recommendation screen. */
|
|
427
452
|
render() {
|
|
428
453
|
if (this.hasError) {
|
|
@@ -440,10 +465,10 @@ export default class RecommendationScreen extends React.Component {
|
|
|
440
465
|
return (<I18nProvider language={this.props.language} i18n={i18n}>
|
|
441
466
|
<KeyboardAwareScrollView>
|
|
442
467
|
<ScrollView testID={RecommendationScreenTestIds.RecommendationScrollView} style={containerStyles.container} ref={(view) => {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
468
|
+
if (view !== null) {
|
|
469
|
+
this.scrollView = view;
|
|
470
|
+
}
|
|
471
|
+
}}>
|
|
447
472
|
<Header exitCallback={this.onExit}/>
|
|
448
473
|
<InfoBars label={i18n._(t `Active Insulin`)} value={activeInsulin ? `${activeInsulin.toFixed(1)}` : null} unit={i18n._(t `units`)} showNullAsDash={false} testID={{ unitID: ActiveInsulinUnitTestID, valueID: ActiveInsulinValueTestID }}/>
|
|
449
474
|
<InfoBars label={i18n._(t `Blood Glucose Level`)} value={displayedBGL} unit={this.props.bloodGlucoseUnit} showNullAsDash={true} testID={{ unitID: BGUnitTestID, valueID: BGValueTestID }}/>
|
|
@@ -451,11 +476,11 @@ export default class RecommendationScreen extends React.Component {
|
|
|
451
476
|
<View style={containerStyles.calcContainer}>
|
|
452
477
|
<View style={containerStyles.calcMargin}>
|
|
453
478
|
<View style={[
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
479
|
+
containerStyles.calcBorder,
|
|
480
|
+
{
|
|
481
|
+
borderColor: recommendedCarbs ? BORDER_COLOUR_TEAL : BORDER_COLOUR_GREY,
|
|
482
|
+
},
|
|
483
|
+
]}>
|
|
459
484
|
<RecommendedCarbs enteredCarbs={`${providedCarbs}`} changedRecommendedCarbs={this.updateCarbRecommendation} recommendedCarbs={`${recommendedCarbs}`} removeRecommendedCarbs={this.removeCarbRecommendation}/>
|
|
460
485
|
</View>
|
|
461
486
|
</View>
|