@hedia/recommendation-screen 2.1.47 → 2.1.48-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.
Files changed (47) hide show
  1. package/dist/src/RecommendationScreen.d.ts +8 -0
  2. package/dist/src/RecommendationScreen.js +42 -39
  3. package/dist/src/assets/fonts/Poppins-Bold.ttf +0 -0
  4. package/dist/src/assets/fonts/Poppins-SemiBold.ttf +0 -0
  5. package/dist/src/assets/icons/Edit.d.ts +4 -0
  6. package/dist/src/assets/icons/Edit.js +7 -0
  7. package/dist/src/assets/icons/Edit.tsx +22 -0
  8. package/dist/src/assets/icons/X.d.ts +4 -0
  9. package/dist/src/assets/icons/X.js +6 -0
  10. package/dist/src/assets/icons/X.tsx +14 -0
  11. package/dist/src/components/ForecastInfoBar.d.ts +117 -0
  12. package/dist/src/components/ForecastInfoBar.js +150 -0
  13. package/dist/src/components/Header.d.ts +3 -5
  14. package/dist/src/components/Header.js +38 -59
  15. package/dist/src/components/InfoBars.d.ts +3 -2
  16. package/dist/src/components/InfoBars.js +10 -8
  17. package/dist/src/components/RecentInsulin.d.ts +1 -1
  18. package/dist/src/components/RecentInsulin.js +34 -54
  19. package/dist/src/components/RecommendationModal.d.ts +1 -2
  20. package/dist/src/components/RecommendationModal.js +15 -10
  21. package/dist/src/components/RecommendedCarbs.js +21 -25
  22. package/dist/src/components/RecommendedInsulin.js +50 -41
  23. package/dist/src/components/Remeasure.js +4 -3
  24. package/dist/src/components/{TransferToLogbook.d.ts → SaveButton.d.ts} +1 -1
  25. package/dist/src/components/SaveButton.js +71 -0
  26. package/dist/src/components/TwoOptionModal.d.ts +1 -0
  27. package/dist/src/components/TwoOptionModal.js +10 -9
  28. package/dist/src/components/mood/Emotion.js +3 -1
  29. package/dist/src/components/mood/MoodIcon.js +3 -3
  30. package/dist/src/locale/da/messages.js +1 -1
  31. package/dist/src/locale/da/messages.po +72 -64
  32. package/dist/src/locale/de/messages.js +1 -1
  33. package/dist/src/locale/de/messages.po +72 -64
  34. package/dist/src/locale/en/messages.js +1 -1
  35. package/dist/src/locale/en/messages.po +72 -64
  36. package/dist/src/locale/es/messages.js +1 -1
  37. package/dist/src/locale/es/messages.po +72 -64
  38. package/dist/src/locale/fr/messages.js +1 -1
  39. package/dist/src/locale/fr/messages.po +72 -64
  40. package/dist/src/locale/it/messages.js +1 -1
  41. package/dist/src/locale/it/messages.po +72 -64
  42. package/dist/src/types/enum.d.ts +6 -3
  43. package/dist/src/types/enum.js +3 -0
  44. package/dist/src/utils/Constants.d.ts +12 -6
  45. package/dist/src/utils/Constants.js +12 -6
  46. package/package.json +5 -3
  47. package/dist/src/components/TransferToLogbook.js +0 -92
@@ -29,6 +29,14 @@ export interface IRecommendationProps {
29
29
  latestLogbookFrom6Hours: Logbook.Types.ILogbookEntry | null;
30
30
  /** The properties of the entered activity that are not used for making the calculation itself, but will be used on the recommendation screen. */
31
31
  activityDisplayProps: IActivityDisplayProps | null;
32
+ /** The forecasted glucose value to display. */
33
+ forecastedGlucose: number | null;
34
+ /** Forecasted time value to display. */
35
+ forecastTime: string | null;
36
+ /** Latest CGM value to display. */
37
+ latestCGMReading: number | null;
38
+ /** Check if the forecasted glucose value is in very low range. */
39
+ isForecastedGlucoseVeryLow: boolean;
32
40
  /**
33
41
  * Callback function taking a single boolean argument and returning nothing.
34
42
  * To be called when the user decides on a presented carbohydrate recommendation.
@@ -1,7 +1,8 @@
1
1
  import React from "react";
2
- import { AppState, BackHandler, LogBox, StyleSheet, View } from "react-native";
2
+ import { AppState, BackHandler, Dimensions, LogBox, ScrollView, StatusBar, StyleSheet, View, } from "react-native";
3
3
  import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
4
- import { BACKGROUND_COLOUR_PURPLE, BORDER_COLOUR_GREY, BORDER_COLOUR_TEAL } from "./utils/Constants";
4
+ import { colors } from "./utils/Constants";
5
+ import ForecastInfoBar from "./components/ForecastInfoBar";
5
6
  import Header from "./components/Header";
6
7
  import InfoBars, { infoStyles } from "./components/InfoBars";
7
8
  import RecentInsulin from "./components/RecentInsulin";
@@ -12,7 +13,7 @@ import * as Calculator from "@hedia/recommendation-calculator";
12
13
  import { Milliseconds, } from "@hedia/types";
13
14
  import { I18nProvider } from "@lingui/react";
14
15
  import Emotion from "./components/mood/Emotion";
15
- import TransferToLogbook from "./components/TransferToLogbook";
16
+ import SaveButton from "./components/SaveButton";
16
17
  import { t } from "@lingui/macro";
17
18
  import Activity from "./components/activity/Activity";
18
19
  import LimitationMessage from "./components/LimitationMessage";
@@ -284,7 +285,7 @@ export default class RecommendationScreen extends React.Component {
284
285
  handleNoRecentInsulin = () => {
285
286
  this.setState({ isRecommendationDisplayed: true }, () => {
286
287
  setTimeout(() => {
287
- this.scrollView?.scrollToEnd(true);
288
+ this.scrollView?.scrollToEnd({ animated: true });
288
289
  }, 0);
289
290
  });
290
291
  };
@@ -453,56 +454,58 @@ export default class RecommendationScreen extends React.Component {
453
454
  if (this.hasError) {
454
455
  return <View style={containerStyles.container}/>;
455
456
  }
456
- const { activeInsulin, recommendationModal, carbRecommendation: carbRecommendationProp, enteredCarbs, enteredInsulin, insulinRecommendation, activityReduction, isRecommendationDisplayed, } = this.state;
457
- const { BloodGlucose: BGValueTestID, BloodKetone: BKValueTestID, ActiveInsulin: ActiveInsulinValueTestID, } = InfoBarTestIds.Value;
458
- const { ActiveInsulin: ActiveInsulinUnitTestID, BloodGlucose: BGUnitTestID, BloodKetone: BKUnitTestID, } = InfoBarTestIds.Unit;
457
+ const { activeInsulin, activityReduction, carbRecommendation: carbRecommendationProp, enteredCarbs, enteredInsulin, insulinRecommendation, isRecommendationDisplayed, recommendationModal, remeasureTime, selectedMood, showExitModal, showLimitationMessage, showTimeoutModal, } = this.state;
458
+ const { BloodGlucose: BGValueTestID, BloodKetone: BKValueTestID, ActiveInsulin: ActiveInsulinValueTestID, ForecastedGlucose: FGValueTestID, } = InfoBarTestIds.Value;
459
+ const { ActiveInsulin: ActiveInsulinUnitTestID, BloodGlucose: BGUnitTestID, BloodKetone: BKUnitTestID, ForecastedGlucose: FGUnitTestID, } = InfoBarTestIds.Unit;
459
460
  const carbRecommendation = carbRecommendationProp !== null ? Math.round(carbRecommendationProp) : null;
460
461
  const recommendedCarbs = enteredCarbs ?? carbRecommendation;
461
- const { calculatorParams, bloodGlucoseUnit, currentBKL, bloodKetoneUnit } = this.props;
462
- const { currentBGL, carbohydrates: providedCarbs } = calculatorParams;
462
+ const isModalOpen = showExitModal || showLimitationMessage || showTimeoutModal;
463
+ const { activityDisplayProps, bloodGlucoseUnit, bloodKetoneUnit, calculatorParams, currentBKL, injectionMethod, language, onRecentInsulinYes, forecastedGlucose, forecastTime, latestCGMReading, isForecastedGlucoseVeryLow, } = this.props;
464
+ const { activity, currentBGL, carbohydrates: providedCarbs } = calculatorParams;
463
465
  const displayedBGL = currentBGL ? Utils.displayedBGLValue(currentBGL, bloodGlucoseUnit) : null;
464
466
  const displayedBKL = currentBKL !== null && bloodKetoneUnit ? Utils.displayedBKLValue(currentBKL, bloodKetoneUnit) : null;
465
- return (<I18nProvider language={this.props.language} i18n={i18n}>
466
- <KeyboardAwareScrollView testID={RecommendationScreenTestIds.RecommendationScrollView} enableResetScrollToCoords={false} style={containerStyles.container} ref={(view) => {
467
+ return (<I18nProvider language={language} i18n={i18n}>
468
+ <KeyboardAwareScrollView scrollEnabled={!isModalOpen} style={containerStyles.container}>
469
+ <StatusBar backgroundColor={colors.darkBlue}/>
470
+ <ScrollView testID={RecommendationScreenTestIds.RecommendationScrollView} style={containerStyles.container} ref={(view) => {
467
471
  if (view !== null) {
468
472
  this.scrollView = view;
469
473
  }
470
474
  }}>
471
- <Header exitCallback={this.onExit}/>
472
- <InfoBars label={i18n._(t `Active Insulin`)} value={activeInsulin ? `${activeInsulin.toFixed(1)}` : null} unit={i18n._(t `units`)} showNullAsDash={false} testID={{ unitID: ActiveInsulinUnitTestID, valueID: ActiveInsulinValueTestID }}/>
473
- <InfoBars label={i18n._(t `Blood Glucose Level`)} value={displayedBGL} unit={this.props.bloodGlucoseUnit} showNullAsDash={true} testID={{ unitID: BGUnitTestID, valueID: BGValueTestID }}/>
474
- <InfoBars label={i18n._(t `Blood Ketone Level`)} value={displayedBKL} unit={this.props.bloodKetoneUnit} showNullAsDash={true} testID={{ unitID: BKUnitTestID, valueID: BKValueTestID }}/>
475
- <View style={containerStyles.calcContainer}>
476
- <View style={containerStyles.calcMargin}>
477
- <View style={[
478
- containerStyles.calcBorder,
479
- {
480
- borderColor: recommendedCarbs ? BORDER_COLOUR_TEAL : BORDER_COLOUR_GREY,
481
- },
482
- ]}>
483
- <RecommendedCarbs enteredCarbs={`${providedCarbs}`} changedRecommendedCarbs={this.updateCarbRecommendation} recommendedCarbs={`${recommendedCarbs}`} removeRecommendedCarbs={this.removeCarbRecommendation}/>
475
+ <Header exitCallback={this.onExit}/>
476
+ <InfoBars label={i18n._(t `Active Insulin`)} value={activeInsulin ? `${activeInsulin.toFixed(1)}` : null} unit={i18n._(t `units`)} showNullAsDash={false} testID={{ unitID: ActiveInsulinUnitTestID, valueID: ActiveInsulinValueTestID }}/>
477
+ {forecastedGlucose && !isForecastedGlucoseVeryLow ? (<ForecastInfoBar label={i18n._(t `Forecasted Glucose`)} value={forecastedGlucose} unit={bloodGlucoseUnit} forecastTime={forecastTime} latestCGMReading={latestCGMReading} testID={{ unitID: FGUnitTestID, valueID: FGValueTestID }}/>) : (<InfoBars label={i18n._(t `Blood Glucose Level`)} value={displayedBGL} unit={bloodGlucoseUnit} showNullAsDash={true} testID={{ unitID: BGUnitTestID, valueID: BGValueTestID }}/>)}
478
+ <InfoBars label={i18n._(t `Blood Ketone Level`)} value={displayedBKL} unit={bloodKetoneUnit} showNullAsDash={true} testID={{ unitID: BKUnitTestID, valueID: BKValueTestID }}/>
479
+ <View style={containerStyles.calcContainer}>
480
+ <View style={containerStyles.calcMargin}>
481
+ <View style={containerStyles.calcBorder}>
482
+ <RecommendedCarbs enteredCarbs={`${providedCarbs}`} changedRecommendedCarbs={this.updateCarbRecommendation} recommendedCarbs={`${recommendedCarbs}`} removeRecommendedCarbs={this.removeCarbRecommendation}/>
483
+ </View>
484
484
  </View>
485
485
  </View>
486
- </View>
487
- {this.props.calculatorParams.activity && this.props.activityDisplayProps ? (<Activity activity={this.props.calculatorParams.activity} activityType={this.props.activityDisplayProps.activityType} activityTitle={this.props.activityDisplayProps.activityTitle} activityReduction={this.state.activityReduction}/>) : null}
488
- <Remeasure onSliderChange={this.updateRemeasureTime} remeasureTime={this.state.remeasureTime}/>
489
- {!this.state.isRecommendationDisplayed ? (<RecentInsulin onRecentInsulinYes={this.props.onRecentInsulinYes} onRecentInsulinNo={this.handleNoRecentInsulin}/>) : (<RecommendedInsulin injectionMethod={this.props.injectionMethod} insulinRecommendation={insulinRecommendation} enteredInsulin={enteredInsulin} activityReduction={activityReduction} updateRecommendedInsulin={this.updateInsulinRecommendation}/>)}
490
- <Emotion moodSelected={this.handleMoodSelected} currentMood={this.state.selectedMood}/>
491
- <TransferToLogbook visible={isRecommendationDisplayed} transfer={this.handleTransfer}/>
492
- <RecommendationModal isVisible={recommendationModal} suggestedCarbohydrates={carbRecommendationProp} attentionMessage={this.getBGLevelAttentionMessage()} limitationMessage={this.getLimitationAttentionMessage()} onClickOkButton={this.hideAttentionModal} onAcceptCarbohydrates={this.acceptCarbRecommendation} onDeclineCarbohydrates={this.declineCarbRecommendation}/>
486
+ {activity && activityDisplayProps && (<Activity activity={activity} activityType={activityDisplayProps.activityType} activityTitle={activityDisplayProps.activityTitle} activityReduction={activityReduction}/>)}
487
+ <Remeasure onSliderChange={this.updateRemeasureTime} remeasureTime={remeasureTime}/>
488
+ {!isRecommendationDisplayed ? (<RecentInsulin onRecentInsulinYes={onRecentInsulinYes} onRecentInsulinNo={this.handleNoRecentInsulin}/>) : (<RecommendedInsulin injectionMethod={injectionMethod} insulinRecommendation={insulinRecommendation} enteredInsulin={enteredInsulin} activityReduction={activityReduction} updateRecommendedInsulin={this.updateInsulinRecommendation}/>)}
489
+ <Emotion moodSelected={this.handleMoodSelected} currentMood={selectedMood}/>
490
+ <SaveButton visible={isRecommendationDisplayed} transfer={this.handleTransfer}/>
491
+ <RecommendationModal isVisible={recommendationModal} suggestedCarbohydrates={carbRecommendationProp} attentionMessage={this.getBGLevelAttentionMessage()} limitationMessage={this.getLimitationAttentionMessage()} onClickOkButton={this.hideAttentionModal} onAcceptCarbohydrates={this.acceptCarbRecommendation} onDeclineCarbohydrates={this.declineCarbRecommendation}/>
492
+ </ScrollView>
493
+ {/* Modals */}
494
+ {showExitModal && (<TwoOptionModal title={i18n._(t `Save data before closing?`)} message={i18n._(t `Your saved data will be used for future calculations.`)} textFirstOption={i18n._(t `Save to logbook`)} textSecondOption={i18n._(t `Close calculation`)} isCancelable={true} rowAsButtonLayout={true} firstOption={this.handleTransfer} secondOption={this.closeCalculation} onClose={this.hideExitModal}/>)}
495
+ {showLimitationMessage && (<View style={modalStyle.container}>
496
+ <LimitationMessage limitationMessage={this.getLimitationAttentionMessage()} onPressNextButton={this.hideLimitationMessage}/>
497
+ </View>)}
498
+ {showTimeoutModal &&
499
+ (isRecommendationDisplayed ? (<TwoOptionModal title={Messages.TimeoutPrompTitle()} message={Messages.TimeoutRecommendationVisible(this.recommendationDate)} textFirstOption={i18n._(t `Yes, save to logbook`)} textSecondOption={i18n._(t `No, return to dashboard`)} rowAsButtonLayout={false} firstOption={this.handleTransfer} secondOption={this.closeCalculation}/>) : (<TwoOptionModal title={Messages.TimeoutPrompTitle()} message={Messages.TimeoutRecommendationNotVisible()} textFirstOption={i18n._(t `Start new calculation`)} textSecondOption={i18n._(t `Return to dashboard`)} rowAsButtonLayout={false} firstOption={this.restartCalculation} secondOption={this.closeCalculation}/>))}
493
500
  </KeyboardAwareScrollView>
494
- {this.state.showExitModal ? (<TwoOptionModal title={i18n._(t `Save data before closing?`)} message={i18n._(t `Your saved data will be used for future calculations.`)} textFirstOption={i18n._(t `Save to logbook`)} textSecondOption={i18n._(t `Close calculation`)} isCancelable={true} rowAsButtonLayout={true} firstOption={this.handleTransfer} secondOption={this.closeCalculation} onClose={this.hideExitModal}/>) : null}
495
- {this.state.showLimitationMessage ? (<View style={modalStyle.container}>
496
- <LimitationMessage limitationMessage={this.getLimitationAttentionMessage()} onPressNextButton={this.hideLimitationMessage}/>
497
- </View>) : null}
498
- {this.state.showTimeoutModal ? (this.state.isRecommendationDisplayed ? (<TwoOptionModal title={Messages.TimeoutPrompTitle()} message={Messages.TimeoutRecommendationVisible(this.recommendationDate)} textFirstOption={i18n._(t `Yes, save to logbook`)} textSecondOption={i18n._(t `No, return to dashboard`)} rowAsButtonLayout={false} firstOption={this.handleTransfer} secondOption={this.closeCalculation}/>) : (<TwoOptionModal title={Messages.TimeoutPrompTitle()} message={Messages.TimeoutRecommendationNotVisible()} textFirstOption={i18n._(t `Start new calculation`)} textSecondOption={i18n._(t `Return to dashboard`)} rowAsButtonLayout={false} firstOption={this.restartCalculation} secondOption={this.closeCalculation}/>)) : null}
499
501
  </I18nProvider>);
500
502
  }
501
503
  }
504
+ const { width } = Dimensions.get(`screen`);
502
505
  const containerStyles = StyleSheet.create({
503
506
  container: {
504
507
  flex: 1,
505
- backgroundColor: BACKGROUND_COLOUR_PURPLE,
508
+ backgroundColor: colors.darkBlue,
506
509
  },
507
510
  calcContainer: {
508
511
  flex: 1,
@@ -510,10 +513,10 @@ const containerStyles = StyleSheet.create({
510
513
  calcMargin: {
511
514
  flex: 1,
512
515
  marginBottom: 0,
513
- margin: `3%`,
516
+ marginHorizontal: width / 17,
517
+ marginVertical: `3%`,
514
518
  },
515
519
  calcBorder: {
516
520
  ...infoStyles.border,
517
- borderColor: BORDER_COLOUR_TEAL,
518
521
  },
519
522
  });
@@ -0,0 +1,4 @@
1
+ /// <reference types="react" />
2
+ import { SvgProps } from "react-native-svg";
3
+ declare const EditIcon: (props: SvgProps) => JSX.Element;
4
+ export default EditIcon;
@@ -0,0 +1,7 @@
1
+ import * as React from "react";
2
+ import { Path, Svg } from "react-native-svg";
3
+ const EditIcon = (props) => (<Svg width="17" height="17" viewBox="0 0 17 17" fill="none" {...props}>
4
+ <Path fillRule="evenodd" clip-rule="evenodd" d="M5.66373 11.2399L5.97672 9.34945L10.659 4.66714L12.2365 6.2446L7.55418 10.9269L5.66373 11.2399Z" fill="#fff"/>
5
+ <Path opacity="0.6" fillRule="evenodd" clip-rule="evenodd" d="M8.521 16.125C12.8357 16.125 16.3335 12.6272 16.3335 8.3125C16.3335 3.99778 12.8357 0.5 8.521 0.5C4.20627 0.5 0.708496 3.99778 0.708496 8.3125C0.708496 12.6272 4.20627 16.125 8.521 16.125Z" stroke="#fff" strokeWidth="2"/>
6
+ </Svg>);
7
+ export default EditIcon;
@@ -0,0 +1,22 @@
1
+ import * as React from "react";
2
+ import { Path, Svg, SvgProps } from "react-native-svg";
3
+
4
+ const EditIcon = (props: SvgProps) => (
5
+ <Svg width="17" height="17" viewBox="0 0 17 17" fill="none" {...props}>
6
+ <Path
7
+ fillRule="evenodd"
8
+ clip-rule="evenodd"
9
+ d="M5.66373 11.2399L5.97672 9.34945L10.659 4.66714L12.2365 6.2446L7.55418 10.9269L5.66373 11.2399Z"
10
+ fill="#fff"
11
+ />
12
+ <Path
13
+ opacity="0.6"
14
+ fillRule="evenodd"
15
+ clip-rule="evenodd"
16
+ d="M8.521 16.125C12.8357 16.125 16.3335 12.6272 16.3335 8.3125C16.3335 3.99778 12.8357 0.5 8.521 0.5C4.20627 0.5 0.708496 3.99778 0.708496 8.3125C0.708496 12.6272 4.20627 16.125 8.521 16.125Z"
17
+ stroke="#fff"
18
+ strokeWidth="2"
19
+ />
20
+ </Svg>
21
+ );
22
+ export default EditIcon;
@@ -0,0 +1,4 @@
1
+ /// <reference types="react" />
2
+ import { SvgProps } from "react-native-svg";
3
+ declare const XIcon: (props: SvgProps) => JSX.Element;
4
+ export default XIcon;
@@ -0,0 +1,6 @@
1
+ import * as React from "react";
2
+ import { Path, Svg } from "react-native-svg";
3
+ const XIcon = (props) => (<Svg width="20" height="20" viewBox="0 0 20 20" fill="none" {...props}>
4
+ <Path fill-rule="evenodd" clip-rule="evenodd" d="M4.29289 4.29289C4.68342 3.90237 5.31658 3.90237 5.70711 4.29289L10 8.58579L14.2929 4.29289C14.6834 3.90237 15.3166 3.90237 15.7071 4.29289C16.0976 4.68342 16.0976 5.31658 15.7071 5.70711L11.4142 10L15.7071 14.2929C16.0976 14.6834 16.0976 15.3166 15.7071 15.7071C15.3166 16.0976 14.6834 16.0976 14.2929 15.7071L10 11.4142L5.70711 15.7071C5.31658 16.0976 4.68342 16.0976 4.29289 15.7071C3.90237 15.3166 3.90237 14.6834 4.29289 14.2929L8.58579 10L4.29289 5.70711C3.90237 5.31658 3.90237 4.68342 4.29289 4.29289Z" fill={"#8388C8"}/>
5
+ </Svg>);
6
+ export default XIcon;
@@ -0,0 +1,14 @@
1
+ import * as React from "react";
2
+ import { Path, Svg, SvgProps } from "react-native-svg";
3
+
4
+ const XIcon = (props: SvgProps) => (
5
+ <Svg width="20" height="20" viewBox="0 0 20 20" fill="none" {...props}>
6
+ <Path
7
+ fill-rule="evenodd"
8
+ clip-rule="evenodd"
9
+ d="M4.29289 4.29289C4.68342 3.90237 5.31658 3.90237 5.70711 4.29289L10 8.58579L14.2929 4.29289C14.6834 3.90237 15.3166 3.90237 15.7071 4.29289C16.0976 4.68342 16.0976 5.31658 15.7071 5.70711L11.4142 10L15.7071 14.2929C16.0976 14.6834 16.0976 15.3166 15.7071 15.7071C15.3166 16.0976 14.6834 16.0976 14.2929 15.7071L10 11.4142L5.70711 15.7071C5.31658 16.0976 4.68342 16.0976 4.29289 15.7071C3.90237 15.3166 3.90237 14.6834 4.29289 14.2929L8.58579 10L4.29289 5.70711C3.90237 5.31658 3.90237 4.68342 4.29289 4.29289Z"
10
+ fill={"#8388C8"}
11
+ />
12
+ </Svg>
13
+ );
14
+ export default XIcon;
@@ -0,0 +1,117 @@
1
+ import { BloodGlucoseUnit } from "@hedia/types";
2
+ import React from "react";
3
+ import { Testing } from "../types/enum";
4
+ export interface IProps {
5
+ /** The display label that describes the value to the user. */
6
+ label: string;
7
+ /** The value to display. */
8
+ value: number;
9
+ /** Unit label to print after the value. */
10
+ unit: BloodGlucoseUnit;
11
+ /** Forecast time value to display. */
12
+ forecastTime: string | null;
13
+ /** Latest CGM value to display. */
14
+ latestCGMReading: number | null;
15
+ /** optional object that contains as properties a valueID and a unitID */
16
+ testID?: {
17
+ valueID: Testing.Id.InfoBarTestIds.Value;
18
+ unitID: Testing.Id.InfoBarTestIds.Unit;
19
+ };
20
+ }
21
+ /** A standard panel to display some data that the user entered. */
22
+ export default class ForecastInfoBar extends React.Component<IProps> {
23
+ /**
24
+ * Determine the unit string to be displayed in the infobar.
25
+ *
26
+ * @returns The string to display as the unit in the infobar
27
+ */
28
+ displayUnit: () => string;
29
+ /**
30
+ * @returns JSX element to display a card with the entered value.
31
+ */
32
+ render(): JSX.Element;
33
+ }
34
+ /** @internal */
35
+ export declare const infoStyles: {
36
+ container: {
37
+ flex: number;
38
+ marginVertical: number;
39
+ marginHorizontal: number;
40
+ marginBottom: number;
41
+ };
42
+ gradient: {
43
+ padding: number;
44
+ borderRadius: number;
45
+ };
46
+ border: {
47
+ borderRadius: number;
48
+ backgroundColor: string;
49
+ paddingTop: string;
50
+ paddingBottom: number;
51
+ paddingHorizontal: string;
52
+ };
53
+ row: {
54
+ flexDirection: "row";
55
+ };
56
+ labelContainer: {
57
+ flex: number;
58
+ justifyContent: "center";
59
+ };
60
+ label: {
61
+ color: string;
62
+ fontSize: number;
63
+ };
64
+ valueUnitContainer: {
65
+ flex: number;
66
+ justifyContent: "flex-end";
67
+ flexDirection: "row";
68
+ };
69
+ valueContainer: {
70
+ flex: number;
71
+ justifyContent: "flex-end";
72
+ };
73
+ value: {
74
+ color: string;
75
+ fontSize: number;
76
+ textAlign: "right";
77
+ };
78
+ unitContainer: {
79
+ flex: number;
80
+ justifyContent: "flex-end";
81
+ };
82
+ units: {
83
+ color: string;
84
+ fontSize: number;
85
+ textAlign: "left";
86
+ paddingLeft: string;
87
+ marginBottom: number;
88
+ };
89
+ forecastDot: {
90
+ height: number;
91
+ width: number;
92
+ borderRadius: number;
93
+ borderWidth: number;
94
+ borderColor: string;
95
+ };
96
+ forecastSubtitle: {
97
+ flexDirection: "row";
98
+ alignItems: "center";
99
+ paddingTop: number;
100
+ };
101
+ forecastText: {
102
+ color: string;
103
+ marginLeft: number;
104
+ };
105
+ forecastTime: {
106
+ color: string;
107
+ fontSize: number;
108
+ lineHeight: number;
109
+ marginLeft: number;
110
+ };
111
+ currentCGM: {
112
+ fontSize: number;
113
+ lineHeight: number;
114
+ color: string;
115
+ marginBottom: number;
116
+ };
117
+ };
@@ -0,0 +1,150 @@
1
+ import { t } from "@lingui/macro";
2
+ import React from "react";
3
+ import { Dimensions, StyleSheet, View } from "react-native";
4
+ import LinearGradient from "react-native-linear-gradient";
5
+ import { i18n } from "../locale/i18nUtils";
6
+ import { colors } from "../utils/Constants";
7
+ import { Utils } from "../utils/Utils";
8
+ import TextBold from "./text/TextBold";
9
+ import TextRegular from "./text/TextRegular";
10
+ /** A standard panel to display some data that the user entered. */
11
+ export default class ForecastInfoBar extends React.Component {
12
+ /**
13
+ * Determine the unit string to be displayed in the infobar.
14
+ *
15
+ * @returns The string to display as the unit in the infobar
16
+ */
17
+ displayUnit = () => {
18
+ const { unit } = this.props;
19
+ return Utils.formatUnit(unit);
20
+ };
21
+ /**
22
+ * @returns JSX element to display a card with the entered value.
23
+ */
24
+ render() {
25
+ const { testID, label, latestCGMReading } = this.props;
26
+ const { border, container, forecastDot, forecastSubtitle, forecastText, forecastTime, gradient, labelContainer, row, unitContainer, units, value, valueContainer, valueUnitContainer, } = infoStyles;
27
+ return (<View style={container}>
28
+ <LinearGradient style={gradient} colors={[`#8B38F5`, `#D593E5`]} useAngle={true} angle={170}>
29
+ <View style={border}>
30
+ <View style={row}>
31
+ <View style={labelContainer}>
32
+ <TextBold style={infoStyles.label}>{label}</TextBold>
33
+ </View>
34
+ <View style={valueUnitContainer}>
35
+ <View style={valueContainer}>
36
+ <TextBold style={value} testID={testID?.valueID}>
37
+ {this.props.value}
38
+ </TextBold>
39
+ </View>
40
+ <View style={unitContainer}>
41
+ <TextRegular style={units} testID={testID?.unitID}>
42
+ {this.displayUnit()}
43
+ </TextRegular>
44
+ </View>
45
+ </View>
46
+ </View>
47
+
48
+ <View style={row}>
49
+ <View style={forecastSubtitle}>
50
+ <LinearGradient colors={[`#8B38F5`, `#D593E5`]} useAngle={true} angle={135} style={forecastDot}/>
51
+ <TextRegular style={forecastText}>{i18n._(t `Forecast time:`)}</TextRegular>
52
+ <TextRegular style={forecastTime}>{this.props.forecastTime}</TextRegular>
53
+ </View>
54
+ </View>
55
+
56
+ <View style={row}>
57
+ <TextRegular style={infoStyles.currentCGM}>
58
+ {i18n._(t `Current glucose: ${latestCGMReading} ${this.displayUnit()}`)}
59
+ </TextRegular>
60
+ </View>
61
+ </View>
62
+ </LinearGradient>
63
+ </View>);
64
+ }
65
+ }
66
+ const { width } = Dimensions.get(`screen`);
67
+ /** @internal */
68
+ export const infoStyles = StyleSheet.create({
69
+ container: {
70
+ flex: 1,
71
+ marginVertical: width / 35,
72
+ marginHorizontal: width / 17,
73
+ marginBottom: 0,
74
+ },
75
+ gradient: {
76
+ padding: 2,
77
+ borderRadius: 5,
78
+ },
79
+ border: {
80
+ borderRadius: 5,
81
+ backgroundColor: colors.darkBlue,
82
+ paddingTop: `2%`,
83
+ paddingBottom: 0,
84
+ paddingHorizontal: `3%`,
85
+ },
86
+ row: {
87
+ flexDirection: `row`,
88
+ },
89
+ labelContainer: {
90
+ flex: 7,
91
+ justifyContent: `center`,
92
+ },
93
+ label: {
94
+ color: `white`,
95
+ fontSize: width / 22,
96
+ },
97
+ valueUnitContainer: {
98
+ flex: 6.5,
99
+ justifyContent: `flex-end`,
100
+ flexDirection: `row`,
101
+ },
102
+ valueContainer: {
103
+ flex: 5,
104
+ justifyContent: `flex-end`,
105
+ },
106
+ value: {
107
+ color: `white`,
108
+ fontSize: width / 15,
109
+ textAlign: `right`,
110
+ },
111
+ unitContainer: {
112
+ flex: 3,
113
+ justifyContent: `flex-end`,
114
+ },
115
+ units: {
116
+ color: `white`,
117
+ fontSize: width / 30,
118
+ textAlign: `left`,
119
+ paddingLeft: `15%`,
120
+ marginBottom: 4,
121
+ },
122
+ forecastDot: {
123
+ height: (width / 100) * 3,
124
+ width: (width / 100) * 3,
125
+ borderRadius: 6,
126
+ borderWidth: 1,
127
+ borderColor: colors.lightBlue,
128
+ },
129
+ forecastSubtitle: {
130
+ flexDirection: `row`,
131
+ alignItems: `center`,
132
+ paddingTop: 5,
133
+ },
134
+ forecastText: {
135
+ color: colors.lightBlue,
136
+ marginLeft: width / 40,
137
+ },
138
+ forecastTime: {
139
+ color: `white`,
140
+ fontSize: width / 32,
141
+ lineHeight: width / 28,
142
+ marginLeft: width / 100,
143
+ },
144
+ currentCGM: {
145
+ fontSize: 13,
146
+ lineHeight: 34,
147
+ color: colors.lightBlue,
148
+ marginBottom: 5,
149
+ },
150
+ });
@@ -1,10 +1,8 @@
1
- import React from "react";
1
+ /// <reference types="react" />
2
2
  export interface IProps {
3
3
  /** A callback that doesn’t take any arguments and doesn’t return a value to be called when the cancel-button is pressed. */
4
4
  exitCallback(): void;
5
5
  }
6
6
  /** Component to display a header text along with a cancel-button that triggers a callback function. */
7
- export default class Header extends React.Component<IProps> {
8
- /** JSX element to display the cancel button and header. When the cancel button in the header is tabbed, the exitCallback prop callback function should be called. */
9
- render(): JSX.Element;
10
- }
7
+ declare const Header: ({ exitCallback }: IProps) => JSX.Element;
8
+ export default Header;
@@ -1,75 +1,54 @@
1
1
  import { t } from "@lingui/macro";
2
2
  import React from "react";
3
3
  import { Dimensions, SafeAreaView, StyleSheet, TouchableOpacity, View } from "react-native";
4
+ import XIcon from "../assets/icons/X";
4
5
  import { i18n } from "../locale/i18nUtils";
5
6
  import { Testing } from "../types/enum";
6
- import { BACKGROUND_COLOUR_PURPLE, BORDER_COLOUR_GREY } from "../utils/Constants";
7
- import Icon from "./Icon";
8
7
  import TextBold from "./text/TextBold";
9
8
  /** Component to display a header text along with a cancel-button that triggers a callback function. */
10
- export default class Header extends React.Component {
11
- /** JSX element to display the cancel button and header. When the cancel button in the header is tabbed, the exitCallback prop callback function should be called. */
12
- render() {
13
- return (<React.Fragment>
14
- <SafeAreaView style={headerStyles.backgroundColour}/>
15
- <View style={headerStyles.headerContainer}>
16
- <View style={headerStyles.margin}>
17
- <View style={headerStyles.exitButtonContainer}>
18
- <View style={headerStyles.exitButton}>
19
- <TouchableOpacity testID={Testing.Id.HeaderTestIds.ExitCalculation} style={headerStyles.exitButton} onPress={this.props.exitCallback}>
20
- <Icon iconIdentifier={`Ionicons/ios-close-circle-outline`} style={headerStyles.iconStyle}/>
21
- </TouchableOpacity>
22
- <View style={headerStyles.headerFiller}/>
23
- </View>
24
- </View>
25
- <View style={headerStyles.headerTextContainer}>
26
- <TextBold style={headerStyles.headerText} testID={Testing.Id.HeaderTestIds.HeaderText}>
27
- {i18n._(t `INSULIN${`\n`}RECOMMENDATION`)}
28
- </TextBold>
29
- </View>
30
- <View style={headerStyles.headerFiller}/>
31
- </View>
32
- </View>
33
- </React.Fragment>);
34
- }
35
- }
9
+ const Header = ({ exitCallback }) => {
10
+ const { iconWrapper, container, emptyButton, text } = headerStyles;
11
+ return (<>
12
+ <SafeAreaView />
13
+ <View style={container}>
14
+ <TouchableOpacity testID={Testing.Id.HeaderTestIds.ExitCalculation} style={iconWrapper} onPress={exitCallback}>
15
+ <XIcon />
16
+ </TouchableOpacity>
17
+
18
+ <TextBold style={text} testID={Testing.Id.HeaderTestIds.HeaderText}>
19
+ {i18n._(t `Insulin recommendation`)}
20
+ </TextBold>
21
+
22
+ <View style={emptyButton}/>
23
+ </View>
24
+ </>);
25
+ };
26
+ const { width } = Dimensions.get(`screen`);
36
27
  const headerStyles = StyleSheet.create({
37
- backgroundColour: {
38
- backgroundColor: BACKGROUND_COLOUR_PURPLE,
39
- },
40
- margin: {
41
- margin: `1%`,
42
- marginBottom: `3%`,
43
- flexDirection: `row`,
44
- flex: 1,
45
- },
46
- headerContainer: {
28
+ container: {
47
29
  flexDirection: `row`,
48
30
  flex: 1,
49
- },
50
- exitButtonContainer: {
31
+ paddingHorizontal: width / 17,
32
+ paddingVertical: width / 43,
51
33
  alignItems: `center`,
52
- flex: 1,
53
- },
54
- exitButton: {
55
- flex: 1,
56
- },
57
- iconStyle: {
58
- fontSize: Dimensions.get(`screen`).width / 12,
59
- color: BORDER_COLOUR_GREY,
60
- },
61
- headerTextContainer: {
62
- flex: 6,
63
- justifyContent: `center`,
64
- alignItems: `center`,
65
- marginTop: `5%`,
66
- },
67
- headerText: {
68
- fontSize: Dimensions.get(`screen`).width / 18,
34
+ justifyContent: `space-between`,
35
+ },
36
+ iconWrapper: {
37
+ padding: width / 60,
38
+ borderWidth: 1,
39
+ borderColor: `#C8CCFA33`,
40
+ borderRadius: 10,
41
+ },
42
+ text: {
43
+ fontFamily: `Poppins-SemiBold`,
44
+ fontSize: width / 22,
45
+ lineHeight: width / 14,
69
46
  textAlign: `center`,
70
47
  color: `white`,
71
48
  },
72
- headerFiller: {
73
- flex: 1,
49
+ emptyButton: {
50
+ width: width / 11,
51
+ height: width / 11,
74
52
  },
75
53
  });
54
+ export default Header;
@@ -50,7 +50,8 @@ export declare const infoStyles: {
50
50
  };
51
51
  margin: {
52
52
  flex: number;
53
- margin: string;
53
+ marginVertical: number;
54
+ marginHorizontal: number;
54
55
  marginBottom: number;
55
56
  };
56
57
  border: {
@@ -90,12 +91,12 @@ export declare const infoStyles: {
90
91
  unitContainer: {
91
92
  flex: number;
92
93
  justifyContent: "flex-end";
93
- paddingBottom: string;
94
94
  };
95
95
  units: {
96
96
  color: string;
97
97
  fontSize: number;
98
98
  textAlign: "left";
99
99
  paddingLeft: string;
100
+ marginBottom: number;
100
101
  };
101
102
  };