├── .dockerignore ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmignore ├── .nvmrc ├── .prettierignore ├── .travis.yml ├── .yarnrc.yml ├── Dockerfile ├── LICENSE ├── README.md ├── SUMMARY.md ├── artifact.sh ├── babel.config.js ├── data ├── basal │ └── fixtures.js ├── bolus │ └── fixtures.js ├── deviceEvent │ └── fixtures.js ├── patient │ ├── data.js │ ├── profiles.js │ └── settings.js ├── print │ └── fixtures.js ├── pumpSettings │ ├── animas │ │ ├── flatrate.json │ │ ├── multirate.json │ │ └── multirate.raw.json │ ├── equil │ │ ├── flatrate.json │ │ ├── multirate.json │ │ └── multirate.raw.json │ ├── loop │ │ ├── flatrate.json │ │ ├── multirate.json │ │ └── multirate.raw.json │ ├── medtronic │ │ ├── automated.json │ │ ├── flatrate.json │ │ ├── multirate.json │ │ └── multirate.raw.json │ ├── omnipod │ │ ├── flatrate.json │ │ ├── multirate.json │ │ └── multirate.raw.json │ └── tandem │ │ ├── flatrate.json │ │ ├── multirate.json │ │ └── multirate.raw.json └── types.js ├── docs ├── Architecture.md ├── Background.md ├── CodeStyle.md ├── DirectoryStructure.md ├── FeatureOverview.md ├── StartHere.md ├── Storybook.md ├── deps │ ├── D3.md │ ├── GSAP.md │ ├── Moment.md │ ├── README.md │ ├── React.md │ ├── ReactMotion.md │ └── Webpack.md ├── misc │ ├── CommonProps.md │ ├── Docs.md │ ├── README.md │ └── TimeRenderingModes.md └── views │ ├── README.md │ ├── Trends.md │ └── images │ ├── bgm_trends.png │ ├── bgm_trends_date_line_hover.png │ ├── bgm_trends_range_hover.png │ ├── bgm_trends_smbg_hover.png │ ├── cgm_trends.png │ ├── cgm_trends_segment_hover.gif │ ├── cgm_trends_segment_hover_hold.png │ ├── cgm_trends_segment_hover_hold_cbg.png │ ├── tidelineContainer@2x.png │ ├── trends_code_locations.png │ └── trends_layout.sketch ├── karma.conf.js ├── loadtests.js ├── package.config.js ├── package.json ├── postcss.config.js ├── src ├── components │ ├── common │ │ ├── controls │ │ │ ├── ClipboardButton.css │ │ │ ├── ClipboardButton.js │ │ │ ├── InputGroup.css │ │ │ ├── InputGroup.js │ │ │ ├── LabeledCheckbox.css │ │ │ ├── LabeledCheckbox.js │ │ │ ├── TwoOptionToggle.css │ │ │ └── TwoOptionToggle.js │ │ ├── data │ │ │ ├── Basal.css │ │ │ ├── Basal.js │ │ │ ├── Bolus.css │ │ │ ├── Bolus.js │ │ │ └── Suspend.js │ │ ├── loader │ │ │ ├── Loader.css │ │ │ └── Loader.js │ │ ├── stat │ │ │ ├── BgBar.js │ │ │ ├── BgBarLabel.js │ │ │ ├── HoverBar.js │ │ │ ├── HoverBarLabel.js │ │ │ ├── Stat.css │ │ │ ├── Stat.js │ │ │ ├── StatLegend.css │ │ │ ├── StatLegend.js │ │ │ └── assets │ │ │ │ ├── chevron-right-24-px.png │ │ │ │ ├── expand-more-24-px.png │ │ │ │ └── info-outline-24-px.png │ │ └── tooltips │ │ │ ├── CgmSampleIntervalTooltip.css │ │ │ ├── CgmSampleIntervalTooltip.js │ │ │ ├── StatTooltip.css │ │ │ ├── StatTooltip.js │ │ │ ├── Tooltip.css │ │ │ └── Tooltip.js │ ├── daily │ │ ├── bolustooltip │ │ │ ├── BolusTooltip.css │ │ │ └── BolusTooltip.js │ │ ├── cbgtooltip │ │ │ ├── CBGTooltip.css │ │ │ └── CBGTooltip.js │ │ ├── foodtooltip │ │ │ ├── FoodTooltip.css │ │ │ └── FoodTooltip.js │ │ ├── pumpsettingsoverridetooltip │ │ │ ├── PumpSettingsOverrideTooltip.css │ │ │ └── PumpSettingsOverrideTooltip.js │ │ └── smbgtooltip │ │ │ ├── SMBGTooltip.css │ │ │ └── SMBGTooltip.js │ ├── settings │ │ ├── NonTandem.css │ │ ├── NonTandem.js │ │ ├── README.md │ │ ├── Tandem.css │ │ ├── Tandem.js │ │ ├── common │ │ │ ├── CollapsibleContainer.css │ │ │ ├── CollapsibleContainer.js │ │ │ ├── Header.css │ │ │ ├── Header.js │ │ │ ├── PumpSettingsContainer.js │ │ │ ├── SingleLineCollapsibleContainerLabel.css │ │ │ ├── SingleLineCollapsibleContainerLabel.js │ │ │ ├── Table.css │ │ │ ├── Table.js │ │ │ ├── TwoLineCollapsibleContainerLabel.css │ │ │ ├── TwoLineCollapsibleContainerLabel.js │ │ │ └── norgie.css │ │ └── settings.css │ └── trends │ │ ├── cbg │ │ ├── CBGDateTraceAnimated.css │ │ ├── CBGDateTraceAnimated.js │ │ ├── CBGDateTraceLabel.css │ │ ├── CBGDateTraceLabel.js │ │ ├── CBGDateTracesAnimationContainer.js │ │ ├── CBGMedianAnimated.css │ │ ├── CBGMedianAnimated.js │ │ ├── CBGSliceAnimated.css │ │ ├── CBGSliceAnimated.js │ │ ├── CBGSliceSegment.js │ │ ├── CBGSlicesContainer.js │ │ ├── FocusedCBGSliceSegment.css │ │ ├── FocusedCBGSliceSegment.js │ │ ├── RangeSelect.css │ │ └── RangeSelect.js │ │ ├── common │ │ ├── Background.css │ │ ├── Background.js │ │ ├── FocusedRangeLabels.css │ │ ├── FocusedRangeLabels.js │ │ ├── NoData.css │ │ ├── NoData.js │ │ ├── TargetRangeLines.css │ │ ├── TargetRangeLines.js │ │ ├── TrendsContainer.js │ │ ├── TrendsSVGContainer.js │ │ ├── XAxisLabels.css │ │ ├── XAxisLabels.js │ │ ├── XAxisTicks.css │ │ ├── XAxisTicks.js │ │ ├── YAxisLabelsAndTicks.css │ │ ├── YAxisLabelsAndTicks.js │ │ └── withDefaultYPosition.js │ │ └── smbg │ │ ├── FocusedSMBGPointLabel.css │ │ ├── FocusedSMBGPointLabel.js │ │ ├── SMBGDateLineAnimated.css │ │ ├── SMBGDateLineAnimated.js │ │ ├── SMBGDatePointsAnimated.css │ │ ├── SMBGDatePointsAnimated.js │ │ ├── SMBGMean.js │ │ ├── SMBGMeanAnimated.css │ │ ├── SMBGMeanAnimated.js │ │ ├── SMBGRange.js │ │ ├── SMBGRangeAnimated.css │ │ ├── SMBGRangeAnimated.js │ │ ├── SMBGRangeAvgContainer.js │ │ └── SMBGsByDateContainer.js ├── index.js ├── modules │ ├── data │ │ └── index.js │ ├── print │ │ ├── AGPPrintView.js │ │ ├── BasicsPrintView.js │ │ ├── BgLogPrintView.js │ │ ├── DailyPrintView.js │ │ ├── PrescriptionPrintView.js │ │ ├── PrintView.js │ │ ├── SettingsPrintView.js │ │ ├── index.js │ │ ├── pdfkitHelpers.js │ │ ├── registerStaticFiles.js │ │ └── utils │ │ │ ├── AGPConstants.js │ │ │ ├── AGPUtils.js │ │ │ └── constants.js │ └── render │ │ ├── basal.js │ │ └── bolus.js ├── propTypes │ └── index.js ├── styles │ ├── colors.css │ ├── diabetes.css │ ├── layout.css │ └── typography.css └── utils │ ├── .eslintrc │ ├── AggregationUtil.js │ ├── DataUtil.js │ ├── README.md │ ├── StatUtil.js │ ├── agp │ └── data.js │ ├── annotations.js │ ├── apidocs │ ├── README.md │ ├── basal.md │ ├── bloodglucose.md │ ├── bolus.md │ ├── datetime.md │ ├── format.md │ └── misc.md │ ├── basal.js │ ├── basics │ └── data.js │ ├── bgLog │ └── data.js │ ├── bloodglucose.js │ ├── bolus.js │ ├── constants.js │ ├── datetime.js │ ├── device.js │ ├── format.js │ ├── misc.js │ ├── print │ ├── data.js │ └── plotly.js │ ├── settings │ ├── data.js │ ├── nonTandemData.js │ ├── tandemData.js │ └── textData.js │ ├── stat.js │ ├── text │ └── TextUtil.js │ ├── trends │ └── data.js │ └── validation │ └── schema.js ├── static-assets └── images │ ├── capturAGP-logo.png │ ├── sitechange-cannula.png │ ├── sitechange-loop-tubing.png │ ├── sitechange-reservoir.png │ ├── sitechange-tubing.png │ ├── sitechange-twiist-cassette.png │ └── tidepool-logo-408x46.png ├── stories ├── components │ ├── common │ │ ├── controls │ │ │ ├── ClipboardButton.js │ │ │ ├── InputGroup.js │ │ │ └── TwoOptionToggle.js │ │ ├── loader │ │ │ └── Loader.js │ │ ├── stats │ │ │ └── Stat.js │ │ └── tooltips │ │ │ ├── CgmSampleIntervalTooltip.js │ │ │ ├── StatTooltip.js │ │ │ └── Tooltip.js │ ├── daily │ │ ├── BolusTooltip.js │ │ ├── CBGTooltip.js │ │ ├── FoodTooltip.js │ │ ├── PumpSettingsOverrideTooltip.js │ │ └── SMBGTooltip.js │ ├── settings │ │ └── DeviceSettings.js │ └── trends │ │ └── common │ │ └── Background.js ├── data │ └── DataUtil.js ├── fonts.css ├── index.js └── print │ ├── AGPViewPrintPDF.js │ ├── BasicsViewPrintPDF.js │ ├── BgLogViewPrintPDF.js │ ├── CombinedViewPrintPDF.js │ ├── DailyViewPrintPDF.js │ ├── PrescriptionPrintPDF.js │ └── SettingsViewPrintPDF.js ├── storiesDatatypes ├── components │ ├── common │ │ └── data │ │ │ ├── Basal.js │ │ │ ├── Bolus.js │ │ │ └── Suspend.js │ └── index.js └── helpers │ └── SixHrScaleSVGDecorator.js ├── storybook ├── main.js ├── preview.js └── webpack.config.js ├── storybookDatatypes ├── main.js └── webpack.config.js ├── test ├── .eslintrc ├── components │ ├── common │ │ ├── controls │ │ │ ├── ClipboardButton.test.js │ │ │ ├── InputGroup.test.js │ │ │ ├── LabeledCheckbox.test.js │ │ │ └── TwoOptionToggle.test.js │ │ ├── data │ │ │ ├── Basal.test.js │ │ │ ├── Bolus.test.js │ │ │ └── Suspend.test.js │ │ ├── loader │ │ │ └── Loader.test.js │ │ ├── stat │ │ │ ├── BgBar.test.js │ │ │ ├── BgBarLabel.test.js │ │ │ ├── HoverBar.test.js │ │ │ ├── HoverBarLabel.test.js │ │ │ ├── Stat.test.js │ │ │ └── StatLegend.test.js │ │ └── tooltip │ │ │ ├── StatTooltip.test.js │ │ │ └── Tooltip.test.js │ ├── daily │ │ ├── BolusTooltip.test.js │ │ ├── CBGTooltip.test.js │ │ ├── FoodTooltip.test.js │ │ ├── PumpSettingsOverrideTooltip.test.js │ │ └── SMBGTooltip.test.js │ ├── settings │ │ ├── NonTandem.test.js │ │ ├── Tandem.test.js │ │ └── common │ │ │ ├── CollapsibleContainer.test.js │ │ │ ├── Header.test.js │ │ │ ├── PumpSettingsContainer.test.js │ │ │ ├── SingleLineCollapsibleContainerLabel.test.js │ │ │ ├── Table.test.js │ │ │ └── TwoLineCollapsibleContainerLabel.test.js │ └── trends │ │ ├── cbg │ │ ├── CBGDateTraceAnimated.test.js │ │ ├── CBGDateTraceLabel.test.js │ │ ├── CBGDateTracesAnimationContainer.test.js │ │ ├── CBGMedianAnimated.test.js │ │ ├── CBGSliceAnimated.test.js │ │ ├── CBGSliceSegment.test.js │ │ ├── CBGSlicesContainer.test.js │ │ ├── FocusedCBGSliceSegment.test.js │ │ └── RangeSelect.test.js │ │ ├── common │ │ ├── Background.test.js │ │ ├── FocusedRangeLabels.test.js │ │ ├── NoData.test.js │ │ ├── TargetRangeLines.test.js │ │ ├── TrendsContainer.test.js │ │ ├── TrendsSVGContainer.test.js │ │ ├── XAxisLabels.test.js │ │ ├── XAxisTicks.test.js │ │ ├── YAxisLabelsAndTicks.test.js │ │ └── withDefaultYPosition.test.js │ │ └── smbg │ │ ├── FocusedSMBGPointLabel.test.js │ │ ├── SMBGDateLineAnimated.test.js │ │ ├── SMBGDatePointsAnimated.test.js │ │ ├── SMBGMean.test.js │ │ ├── SMBGMeanAnimated.test.js │ │ ├── SMBGRange.test.js │ │ ├── SMBGRangeAnimated.test.js │ │ ├── SMBGRangeAvgContainer.test.js │ │ └── SMBGsByDateContainer.test.js ├── helpers │ ├── DummyComponent.js │ ├── SVGContainer.js │ ├── bgBounds.js │ ├── bgConversion.js │ ├── cssmodules.js │ ├── pdfDoc.js │ └── scales.js ├── modules │ ├── print │ │ ├── AGPPrintView.test.js │ │ ├── BasicsPrintView.test.js │ │ ├── BgLogPrintView.test.js │ │ ├── DailyPrintView.test.js │ │ ├── PrescriptionPrintView.test.js │ │ ├── PrintView.test.js │ │ ├── SettingsPrintView.test.js │ │ ├── index.test.js │ │ └── utils │ │ │ ├── AGPConstants.test.js │ │ │ ├── AGPUtils.test.js │ │ │ └── constants.test.js │ └── render │ │ ├── basal.test.js │ │ └── bolus.test.js ├── propTypes │ └── index.test.js ├── styles │ └── colors.test.js └── utils │ ├── AggregationUtil.test.js │ ├── DataUtil.test.js │ ├── StatUtil.test.js │ ├── agp │ └── data.test.js │ ├── annotations.test.js │ ├── basal.test.js │ ├── basics │ └── data.test.js │ ├── bgLog │ └── data.test.js │ ├── bloodglucose.test.js │ ├── bolus.test.js │ ├── constants.test.js │ ├── datetime.test.js │ ├── device.test.js │ ├── format.test.js │ ├── misc.test.js │ ├── print │ ├── data.test.js │ └── plotly.test.js │ ├── settings │ ├── data.test.js │ └── nonTandemData.test.js │ ├── stat.test.js │ ├── text │ └── TextUtil.test.js │ ├── trends │ └── data.test.js │ └── validation │ └── schema.test.js ├── webpack.config.js └── yarn.lock /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .gitignore 3 | node_modules 4 | npm-debug.log 5 | dist 6 | local 7 | coverage 8 | web 9 | *.log 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | coverage/ 3 | dist/ 4 | local/ 5 | node_modules/ 6 | web/ 7 | *.log 8 | package-lock.json 9 | 10 | # yarn (ref https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored) 11 | .pnp.* 12 | .yarn/* 13 | !.yarn/patches 14 | !.yarn/plugins 15 | !.yarn/releases 16 | !.yarn/sdks 17 | !.yarn/versions 18 | 19 | .codegpt -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | **/*.sketch 2 | coverage/ 3 | data/ 4 | local/ 5 | src/ 6 | stories/ 7 | storiesDatatypes/ 8 | storybook/ 9 | storybookDatatypes/ 10 | test/ 11 | .babelrc 12 | .editorconfig 13 | .eslintrc 14 | .gitignore 15 | .travis.yml 16 | karma.conf.js 17 | loadtests.js 18 | package.config.js 19 | webpack.config.js 20 | yarn.lock 21 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.8.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | ** 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: linux 2 | dist: jammy 3 | 4 | services: 5 | - docker 6 | 7 | script: 8 | - docker build -t viz-test --target test . 9 | - ./artifact.sh 10 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:experimental 2 | 3 | ### Stage: Base image 4 | FROM node:20.8.0-alpine as base 5 | WORKDIR /app 6 | RUN corepack enable \ 7 | && yarn set version 3.6.4 \ 8 | && mkdir -p dist node_modules .yarn/cache && chown -R node:node . 9 | 10 | 11 | ### Stage: Test 12 | FROM base as test 13 | ENV \ 14 | CHROME_BIN=/usr/bin/chromium-browser \ 15 | NODE_ENV=test 16 | USER root 17 | RUN apk add --no-cache chromium && rm -rf /var/cache/apk/* /tmp/* 18 | USER node 19 | RUN --mount=type=bind,source=package.json,target=package.json \ 20 | --mount=type=bind,source=yarn.lock,target=yarn.lock \ 21 | --mount=type=bind,source=.yarnrc.yml,target=.yarnrc.yml \ 22 | --mount=type=cache,target=.yarn/cache,uid=1000,gid=1000 \ 23 | yarn install --immutable 24 | COPY . . 25 | RUN npm run test 26 | 27 | 28 | ### Stage 1 - Base image for development image to install and configure Chromium for unit tests 29 | FROM base as developbase 30 | RUN \ 31 | echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories \ 32 | && echo "http://dl-cdn.alpinelinux.org/alpine/edge/main" >> /etc/apk/repositories \ 33 | && echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories \ 34 | && apk --no-cache update \ 35 | && apk --no-cache upgrade \ 36 | && apk add --no-cache git fontconfig bash udev ttf-opensans chromium \ 37 | && rm -rf /var/cache/apk/* /tmp/* 38 | ENV \ 39 | CHROME_BIN=/usr/bin/chromium-browser \ 40 | NODE_ENV=development 41 | 42 | 43 | ### Stage 2 - Create cached `node_modules` 44 | # Only rebuild layer if `package.json` has changed 45 | FROM base as dependencies 46 | RUN apk --no-cache update \ 47 | && apk --no-cache upgrade \ 48 | && apk add --no-cache git 49 | COPY package.json . 50 | COPY yarn.lock . 51 | COPY .yarnrc.yml . 52 | RUN yarn plugin import workspace-tools && yarn workspaces focus --production 53 | 54 | 55 | ### Stage 3 - Development root with Chromium installed for unit tests 56 | FROM developbase as develop 57 | WORKDIR /app 58 | USER node 59 | # Copy all `node_modules` from dependancies layer 60 | COPY --chown=node:node --from=dependencies /app/node_modules ./node_modules 61 | # Copy source files 62 | COPY --chown=node:node . . 63 | EXPOSE 8082 8083 64 | VOLUME ["/app", "/app/node_modules", "/app/dist"] 65 | CMD ["npm", "start"] 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Tidepool Project 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | 2. Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or other 12 | materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | + [@tidepool/viz developer guide](docs/StartHere.md) 4 | + [background](docs/Background.md) 5 | + [overview of features](docs/FeatureOverview.md) 6 | + [planned architecture](docs/Architecture.md) 7 | + [app & directory structure](docs/DirectoryStructure.md) 8 | + [code style](docs/CodeStyle.md) 9 | + [per-view documentation](docs/views/README.md) 10 | + [Device Settings view](src/components/settings/README.md) 11 | + [Trends view](docs/views/Trends.md) 12 | + [use of React Storybook](docs/Storybook.md) 13 | + [usage of dependencies](docs/deps/README.md) 14 | + [D3](docs/deps/D3.md) 15 | + [GSAP](docs/deps/GSAP.md) 16 | + [Moment](docs/deps/Moment.md) 17 | + [React](docs/deps/React.md) 18 | + [React Motion](docs/deps/ReactMotion.md) 19 | + [Redux](docs/deps/Redux.md) 20 | + [webpack](docs/deps/Webpack.md) 21 | + [utilities](src/utils/README.md) 22 | + [API docs for utilities](src/utils/apidocs/README.md) 23 | + [basal](src/utils/apidocs/basal.md) 24 | + [blood glucose](src/utils/apidocs/bloodglucose.md) 25 | + [bolus](src/utils/apidocs/bolus.md) 26 | + [datetime](src/utils/apidocs/datetime.md) 27 | + [format](src/utils/apidocs/format.md) 28 | + [misc](src/utils/apidocs/misc.md) 29 | + [misc](docs/misc/README.md) 30 | + [Common props](docs/misc/CommonProps.md) 31 | + [Docs setup & publishing](docs/misc/Docs.md) 32 | + [Time-rendering modes](docs/misc/TimeRenderingModes.md) 33 | -------------------------------------------------------------------------------- /artifact.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | 3 | wget -q -O artifact_docker.sh 'https://raw.githubusercontent.com/tidepool-org/tools/master/artifact/artifact.sh' 4 | chmod +x artifact_docker.sh 5 | 6 | ./artifact_docker.sh docker 7 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function babelConfig(api) { 2 | const presets = [ 3 | '@babel/preset-env', 4 | '@babel/preset-react', 5 | 'babel-preset-react-app', 6 | ]; 7 | 8 | const plugins = [ 9 | 'react-hot-loader/babel', 10 | '@babel/plugin-transform-modules-commonjs', 11 | ]; 12 | 13 | const env = api.env(); 14 | 15 | if (env === 'test') { 16 | plugins.unshift( 17 | ['babel-plugin-istanbul', { 18 | useInlineSourceMaps: false, 19 | }] 20 | ); 21 | } 22 | 23 | api.cache(true); 24 | 25 | return { 26 | presets, 27 | plugins, 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /data/patient/data.js: -------------------------------------------------------------------------------- 1 | import { MGDL_UNITS, MMOLL_UNITS } from '../../src/utils/constants'; 2 | 3 | export const data = { 4 | [MGDL_UNITS]: { 5 | basics: {}, 6 | daily: {}, 7 | settings: {}, 8 | }, 9 | [MMOLL_UNITS]: { 10 | basics: {}, 11 | daily: {}, 12 | settings: {}, 13 | }, 14 | }; 15 | 16 | export default data; 17 | -------------------------------------------------------------------------------- /data/patient/profiles.js: -------------------------------------------------------------------------------- 1 | export const standard = { 2 | profile: { 3 | fullName: 'Mary Smith', 4 | patient: { 5 | mrn: 'mrn123', 6 | diagnosisDate: '1990-01-31', 7 | birthday: '1983-01-31', 8 | }, 9 | }, 10 | }; 11 | 12 | export const fakeChildAcct = { 13 | profile: { 14 | fullName: 'Mary Smith', 15 | patient: { 16 | isOtherPerson: true, 17 | fullName: 'My Kid', 18 | diagnosisDate: '1990-01-31', 19 | birthday: '1983-01-31', 20 | }, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /data/patient/settings.js: -------------------------------------------------------------------------------- 1 | export const tubingPrimeSelected = { 2 | settings: { 3 | siteChangeSource: 'tubingPrime', 4 | }, 5 | }; 6 | 7 | export const cannulaPrimeSelected = { 8 | settings: { 9 | siteChangeSource: 'cannulaPrime', 10 | }, 11 | }; 12 | 13 | export const reservoirChangeSelected = { 14 | settings: { 15 | siteChangeSource: 'reservoirChange', 16 | }, 17 | }; 18 | 19 | export const siteChangeSourceUndefined = { 20 | settings: { 21 | siteChangeSource: undefined, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /data/pumpSettings/animas/flatrate.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "pumpSettings", 3 | "activeSchedule": "normal", 4 | "basalSchedules": [ 5 | { 6 | "name": "normal", 7 | "value": [ 8 | { 9 | "start": 0, 10 | "rate": 0.85 11 | } 12 | ] 13 | }, 14 | { 15 | "name": "stress", 16 | "value" : [ 17 | { 18 | "start": 0, 19 | "rate": 1.725 20 | } 21 | ] 22 | }, 23 | { 24 | "name": "Weekday", 25 | "value" : [ 26 | { 27 | "start": 0, 28 | "rate": 0.325 29 | } 30 | ] 31 | } 32 | ], 33 | "units": { 34 | "carbs": "grams", 35 | "bg": "mmol/L" 36 | }, 37 | "bgTarget": [ 38 | { 39 | "start": 0, 40 | "target": 4.9956731919409805, 41 | "range": 1.3876869977613833 42 | } 43 | ], 44 | "carbRatio": [ 45 | { 46 | "amount": 9, 47 | "start": 0 48 | } 49 | ], 50 | "insulinSensitivity": [ 51 | { 52 | "amount": 2.9418964352541326, 53 | "start": 0 54 | } 55 | ], 56 | "clockDriftOffset": 0, 57 | "conversionOffset": 0, 58 | "deviceId": "DevId0987654321", 59 | "deviceTime": "2016-08-22T13:31:55", 60 | "guid": "5886768b-012e-453d-8e3e-2c5280995c47", 61 | "id": "8372053933d14de3974c8d183c2a433d", 62 | "time": "2016-08-22T01:31:55.605Z", 63 | "timezoneOffset": 720, 64 | "source": "Animas", 65 | "deviceSerialNumber": "123-45-678", 66 | "uploadId": "SampleUploadId" 67 | } 68 | -------------------------------------------------------------------------------- /data/pumpSettings/animas/multirate.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "pumpSettings", 3 | "activeSchedule": "Stress", 4 | "basalSchedules": [ 5 | { 6 | "name": "At home", 7 | "value": [ 8 | { 9 | "start": 0, 10 | "rate": 0.85 11 | }, 12 | { 13 | "start": 41400000, 14 | "rate": 1.625 15 | } 16 | ] 17 | }, 18 | { 19 | "name": "Stress", 20 | "value" : [ 21 | { 22 | "start": 0, 23 | "rate": 1.725 24 | }, 25 | { 26 | "start": 9000000, 27 | "rate": 0.425 28 | } 29 | ] 30 | }, 31 | { 32 | "name": "Weekday", 33 | "value" : [ 34 | { 35 | "start": 0, 36 | "rate": 0.325 37 | } 38 | ] 39 | } 40 | ], 41 | "units": { 42 | "carbs": "grams", 43 | "bg": "mmol/L" 44 | }, 45 | "bgTarget": [ 46 | { 47 | "start": 0, 48 | "target": 4.9956731919409805, 49 | "range": 1.3876869977613833 50 | } 51 | ], 52 | "carbRatio": [ 53 | { 54 | "amount": 9, 55 | "start": 0 56 | } 57 | ], 58 | "insulinSensitivity": [ 59 | { 60 | "amount": 2.9418964352541326, 61 | "start": 0 62 | } 63 | ], 64 | "clockDriftOffset": 0, 65 | "conversionOffset": 0, 66 | "deviceId": "DevId0987654321", 67 | "deviceTime": "2016-08-22T13:31:55", 68 | "guid": "5886768b-012e-453d-8e3e-2c5280995c47", 69 | "id": "8372053933d14de3974c8d183c2a433d", 70 | "time": "2016-08-22T01:31:55.605Z", 71 | "timezoneOffset": 720, 72 | "source": "Animas", 73 | "deviceSerialNumber": "123-45-678", 74 | "uploadId": "SampleUploadId" 75 | } 76 | -------------------------------------------------------------------------------- /data/pumpSettings/animas/multirate.raw.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "pumpSettings", 3 | "activeSchedule": "Stress", 4 | "basalSchedules": { 5 | "At home": [ 6 | { 7 | "start": 0, 8 | "rate": 0.85 9 | }, 10 | { 11 | "start": 41400000, 12 | "rate": 1.625 13 | } 14 | ], 15 | "Stress": [ 16 | { 17 | "start": 0, 18 | "rate": 1.725 19 | }, 20 | { 21 | "start": 9000000, 22 | "rate": 0.425 23 | } 24 | ], 25 | "Weekday": [ 26 | { 27 | "start": 0, 28 | "rate": 0.325 29 | } 30 | ] 31 | }, 32 | "units": { 33 | "carbs": "grams", 34 | "bg": "mmol/L" 35 | }, 36 | "bgTarget": [ 37 | { 38 | "start": 0, 39 | "target": 4.9956731919409805, 40 | "range": 1.3876869977613833 41 | } 42 | ], 43 | "carbRatio": [ 44 | { 45 | "amount": 9, 46 | "start": 0 47 | } 48 | ], 49 | "insulinSensitivity": [ 50 | { 51 | "amount": 2.9418964352541326, 52 | "start": 0 53 | } 54 | ], 55 | "clockDriftOffset": 0, 56 | "conversionOffset": 0, 57 | "deviceId": "DevId0987654321", 58 | "deviceTime": "2016-08-22T13:31:55", 59 | "guid": "5886768b-012e-453d-8e3e-2c5280995c47", 60 | "id": "8372053933d14de3974c8d183c2a433d", 61 | "time": "2016-08-22T01:31:55.605Z", 62 | "timezoneOffset": 720, 63 | "source": "Animas", 64 | "deviceSerialNumber": "123-45-678", 65 | "uploadId": "SampleUploadId" 66 | } 67 | -------------------------------------------------------------------------------- /data/pumpSettings/equil/flatrate.json: -------------------------------------------------------------------------------- 1 | { 2 | "activeSchedule": "Program 2", 3 | "basalSchedules": [ 4 | { 5 | "name": "Program 2", 6 | "value": [ 7 | { 8 | "rate": 0.15000000000000002, 9 | "start": 0 10 | } 11 | ] 12 | } 13 | ], 14 | "bgTarget": [ 15 | { 16 | "high": 180.00006514650002, 17 | "low": 69.9999352568, 18 | "start": 0 19 | }, 20 | { 21 | "high": 208.9999405254, 22 | "low": 69.9999352568, 23 | "start": 16200000 24 | }, 25 | { 26 | "high": 250.0000004033, 27 | "low": 69.9999352568, 28 | "start": 37800000 29 | } 30 | ], 31 | "carbRatio": [ 32 | { 33 | "amount": 1, 34 | "start": 0 35 | }, 36 | { 37 | "amount": 16, 38 | "start": 86400000 39 | } 40 | ], 41 | "conversionOffset": 0, 42 | "deviceId": "equil-C0210B", 43 | "deviceTime": 1626859633000, 44 | "id": "72c0997583244df09d3f763e1f043a74", 45 | "insulinSensitivity": [ 46 | { 47 | "amount": 1.0000454009, 48 | "start": 0 49 | }, 50 | { 51 | "amount": 22.999963285299998, 52 | "start": 86400000 53 | } 54 | ], 55 | "manufacturers": [ 56 | "Microtech" 57 | ], 58 | "serialNumber": "C0210B", 59 | "time": 1626856029000, 60 | "timezoneOffset": 0, 61 | "type": "pumpSettings", 62 | "units": { 63 | "bg": "mg/dL", 64 | "carb": "grams" 65 | }, 66 | "uploadId": "b74d248548461cad70124d3749cf2e05", 67 | "_time": "2021-07-21T08:27:09.000Z", 68 | "_deviceTime": "2021-07-21T10:27:13", 69 | "normalTime": 1626856029000, 70 | "displayOffset": 60, 71 | "deviceSerialNumber": "C0210B", 72 | "source": "Microtech" 73 | } 74 | -------------------------------------------------------------------------------- /data/pumpSettings/medtronic/automated.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "pumpSettings", 3 | "activeSchedule": "Auto Mode", 4 | "lastManualBasalSchedule": "Standard", 5 | "basal": { 6 | "rateMaximum": { 7 | "units": "Units/hour", 8 | "value": 2 9 | }, 10 | "temporary": { 11 | "type": "percent" 12 | } 13 | }, 14 | "basalSchedules": [ 15 | { 16 | "name": "Auto Mode", 17 | "value": [] 18 | }, 19 | { 20 | "name": "Standard", 21 | "value": [ 22 | { 23 | "start": 0, 24 | "rate": 0.75 25 | } 26 | ] 27 | }, 28 | { 29 | "name": "Pattern A", 30 | "value": [] 31 | }, 32 | { 33 | "name": "Pattern B", 34 | "value": [] 35 | } 36 | ], 37 | "units": { 38 | "carbs": "grams", 39 | "bg": "mmol/L" 40 | }, 41 | "bgTarget": [ 42 | { 43 | "start": 0, 44 | "low": 3.8855235937318735, 45 | "high": 7.771047187463747 46 | }, 47 | { 48 | "start": 41400000, 49 | "low": 4.440598392836427, 50 | "high": 6.66089758925464 51 | }, 52 | { 53 | "start": 64800000, 54 | "low": 4.16306099328415, 55 | "high": 8.3261219865683 56 | } 57 | ], 58 | "bolus": { 59 | "amountMaximum": { 60 | "units": "Units", 61 | "value": 9.5 62 | }, 63 | "calculator": { 64 | "enabled": true, 65 | "insulin": { 66 | "duration": 4, 67 | "units": "hours" 68 | } 69 | }, 70 | "extended": { 71 | "enabled": true 72 | } 73 | }, 74 | "carbRatio": [ 75 | { 76 | "amount": 24, 77 | "start": 0 78 | }, 79 | { 80 | "amount": 22, 81 | "start": 9000000 82 | }, 83 | { 84 | "amount": 17, 85 | "start": 21600000 86 | }, 87 | { 88 | "amount": 6, 89 | "start": 63000000 90 | } 91 | ], 92 | "insulinSensitivity": [ 93 | { 94 | "amount": 1.7762393571345707, 95 | "start": 0 96 | } 97 | ], 98 | "clockDriftOffset": 0, 99 | "conversionOffset": 0, 100 | "deviceId": "DevId0987654321", 101 | "deviceTime": "2016-07-15T11:31:43", 102 | "guid": "654fb6d4-85ba-4dcc-870d-4f99f2414363", 103 | "id": "e6ddc63d00b542d4818ae6c81e4b17d2", 104 | "time": "2016-07-14T23:31:43.009Z", 105 | "timezoneOffset": 720, 106 | "source": "Medtronic", 107 | "deviceSerialNumber": "123-45-678", 108 | "uploadId": "SampleUploadId" 109 | } 110 | -------------------------------------------------------------------------------- /data/pumpSettings/medtronic/flatrate.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "pumpSettings", 3 | "activeSchedule": "standard", 4 | "basal": { 5 | "rateMaximum": { 6 | "units": "Units/hour", 7 | "value": 2 8 | }, 9 | "temporary": { 10 | "type": "percent" 11 | } 12 | }, 13 | "basalSchedules": [ 14 | { 15 | "name": "standard", 16 | "value": [ 17 | { 18 | "start": 0, 19 | "rate": 0.75 20 | } 21 | ] 22 | }, 23 | { 24 | "name": "pattern a", 25 | "value": [] 26 | }, 27 | { 28 | "name": "pattern b", 29 | "value": [] 30 | } 31 | ], 32 | "units": { 33 | "carbs": "grams", 34 | "bg": "mmol/L" 35 | }, 36 | "bgTarget": [ 37 | { 38 | "start": 0, 39 | "low": 3.8855235937318735, 40 | "high": 7.771047187463747 41 | }, 42 | { 43 | "start": 41400000, 44 | "low": 4.440598392836427, 45 | "high": 6.66089758925464 46 | }, 47 | { 48 | "start": 64800000, 49 | "low": 4.16306099328415, 50 | "high": 8.3261219865683 51 | } 52 | ], 53 | "bolus": { 54 | "amountMaximum": { 55 | "units": "Units", 56 | "value": 9.5 57 | }, 58 | "calculator": { 59 | "enabled": true, 60 | "insulin": { 61 | "duration": 4, 62 | "units": "hours" 63 | } 64 | }, 65 | "extended": { 66 | "enabled": true 67 | } 68 | }, 69 | "carbRatio": [ 70 | { 71 | "amount": 24, 72 | "start": 0 73 | }, 74 | { 75 | "amount": 22, 76 | "start": 9000000 77 | }, 78 | { 79 | "amount": 17, 80 | "start": 21600000 81 | }, 82 | { 83 | "amount": 6, 84 | "start": 63000000 85 | } 86 | ], 87 | "insulinSensitivity": [ 88 | { 89 | "amount": 1.7762393571345707, 90 | "start": 0 91 | } 92 | ], 93 | "clockDriftOffset": 0, 94 | "conversionOffset": 0, 95 | "deviceId": "DevId0987654321", 96 | "deviceTime": "2016-07-15T11:31:43", 97 | "guid": "654fb6d4-85ba-4dcc-870d-4f99f2414363", 98 | "id": "e6ddc63d00b542d4818ae6c81e4b17d2", 99 | "time": "2016-07-14T23:31:43.009Z", 100 | "timezoneOffset": 720, 101 | "source": "Medtronic", 102 | "deviceSerialNumber": "123-45-678", 103 | "uploadId": "SampleUploadId" 104 | } 105 | -------------------------------------------------------------------------------- /data/pumpSettings/medtronic/multirate.raw.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "pumpSettings", 3 | "activeSchedule": "standard", 4 | "basalSchedules": { 5 | "standard": [ 6 | { 7 | "rate": 0.75, 8 | "start": 0 9 | }, 10 | { 11 | "rate": 0.85, 12 | "start": 9000000 13 | }, 14 | { 15 | "rate": 0.9, 16 | "start": 21600000 17 | }, 18 | { 19 | "rate": 0.85, 20 | "start": 63000000 21 | } 22 | ], 23 | "pattern a": [ 24 | { 25 | "rate": 0, 26 | "start": 0 27 | } 28 | ], 29 | "pattern b": [] 30 | }, 31 | "units": { 32 | "carbs": "grams", 33 | "bg": "mmol/L" 34 | }, 35 | "bgTarget": [ 36 | { 37 | "start": 0, 38 | "low": 3.8855235937318735, 39 | "high": 7.771047187463747 40 | }, 41 | { 42 | "start": 41400000, 43 | "low": 4.440598392836427, 44 | "high": 6.66089758925464 45 | }, 46 | { 47 | "start": 64800000, 48 | "low": 4.16306099328415, 49 | "high": 8.3261219865683 50 | } 51 | ], 52 | "carbRatio": [ 53 | { 54 | "amount": 24, 55 | "start": 0 56 | }, 57 | { 58 | "amount": 22, 59 | "start": 9000000 60 | }, 61 | { 62 | "amount": 17, 63 | "start": 21600000 64 | }, 65 | { 66 | "amount": 6, 67 | "start": 63000000 68 | } 69 | ], 70 | "insulinSensitivity": [ 71 | { 72 | "amount": 1.7762393571345707, 73 | "start": 0 74 | } 75 | ], 76 | "clockDriftOffset": 0, 77 | "conversionOffset": 0, 78 | "deviceId": "DevId0987654321", 79 | "deviceTime": "2016-07-15T11:31:43", 80 | "guid": "654fb6d4-85ba-4dcc-870d-4f99f2414363", 81 | "id": "e6ddc63d00b542d4818ae6c81e4b17d2", 82 | "time": "2016-07-14T23:31:43.009Z", 83 | "timezoneOffset": 720, 84 | "source": "Medtronic", 85 | "deviceSerialNumber": "123-45-678", 86 | "uploadId": "SampleUploadId" 87 | } 88 | -------------------------------------------------------------------------------- /data/pumpSettings/omnipod/flatrate.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "pumpSettings", 3 | "activeSchedule": "normal", 4 | "basal": { 5 | "rateMaximum": { 6 | "units": "Units/hour", 7 | "value": 2 8 | }, 9 | "temporary": { 10 | "type": "percent" 11 | } 12 | }, 13 | "basalSchedules": [ 14 | { 15 | "name": "normal", 16 | "value": [ 17 | { 18 | "rate": 0.325, 19 | "start": 0 20 | } 21 | ] 22 | } 23 | ], 24 | "units": { 25 | "carbs": "grams", 26 | "bg": "mmol/L" 27 | }, 28 | "bgTarget": [ 29 | { 30 | "start": 0, 31 | "target": 6.1058227901500866, 32 | "high": 6.938434988806917 33 | } 34 | ], 35 | "bolus": { 36 | "amountMaximum": { 37 | "units": "Units", 38 | "value": 9.5 39 | }, 40 | "calculator": { 41 | "enabled": true, 42 | "insulin": { 43 | "duration": 260, 44 | "units": "minutes" 45 | } 46 | }, 47 | "extended": { 48 | "enabled": true 49 | } 50 | }, 51 | "carbRatio": [ 52 | { 53 | "amount": 20, 54 | "start": 0 55 | } 56 | ], 57 | "insulinSensitivity": [ 58 | { 59 | "amount": 3.774508633910963, 60 | "start": 0 61 | } 62 | ], 63 | "clockDriftOffset": 0, 64 | "conversionOffset": 0, 65 | "deviceId": "DevId0987654321", 66 | "deviceTime": "2016-08-22T13:29:54", 67 | "guid": "929bcfc1-b9fe-4b6d-9bf7-499d6b09c949", 68 | "id": "897a76c611234fb6a540af93325b6e31", 69 | "time": "2016-08-22T01:29:54.952Z", 70 | "timezoneOffset": 720, 71 | "source": "Insulet", 72 | "deviceSerialNumber": "123-45-678", 73 | "uploadId": "SampleUploadId" 74 | } 75 | -------------------------------------------------------------------------------- /data/pumpSettings/omnipod/multirate.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "pumpSettings", 3 | "activeSchedule": "Normal", 4 | "basal": { 5 | "rateMaximum": { 6 | "units": "Units/hour", 7 | "value": 2 8 | }, 9 | "temporary": { 10 | "type": "percent" 11 | } 12 | }, 13 | "basalSchedules": [ 14 | { 15 | "name": "Normal", 16 | "value": [ 17 | { 18 | "start": 0, 19 | "rate": 0.325 20 | }, 21 | { 22 | "start": 9000000, 23 | "rate": 0.45 24 | }, 25 | { 26 | "start": 23400000, 27 | "rate": 0.95 28 | }, 29 | { 30 | "start": 46800000, 31 | "rate": 1.375 32 | } 33 | ] 34 | }, 35 | { 36 | "name": "Other", 37 | "value": [ 38 | { 39 | "start": 0, 40 | "rate": 0.325 41 | }, 42 | { 43 | "start": 9000000, 44 | "rate": 0.45 45 | }, 46 | { 47 | "start": 23400000, 48 | "rate": 0.95 49 | }, 50 | { 51 | "start": 46800000, 52 | "rate": 1.375 53 | } 54 | ] 55 | } 56 | ], 57 | "bolus": { 58 | "amountMaximum": { 59 | "units": "Units", 60 | "value": 9.5 61 | }, 62 | "calculator": { 63 | "enabled": true, 64 | "insulin": { 65 | "duration": 245, 66 | "units": "minutes" 67 | } 68 | }, 69 | "extended": { 70 | "enabled": true 71 | } 72 | }, 73 | "units": { 74 | "carbs": "grams", 75 | "bg": "mmol/L" 76 | }, 77 | "bgTarget": [ 78 | { 79 | "start": 0, 80 | "target": 6.1058227901500866, 81 | "high": 6.938434988806917 82 | } 83 | ], 84 | "carbRatio": [ 85 | { 86 | "amount": 20, 87 | "start": 0 88 | } 89 | ], 90 | "insulinSensitivity": [ 91 | { 92 | "amount": 3.774508633910963, 93 | "start": 0 94 | } 95 | ], 96 | "clockDriftOffset": 0, 97 | "conversionOffset": 0, 98 | "deviceId": "DevId0987654321", 99 | "deviceTime": "2016-08-22T13:29:54", 100 | "guid": "929bcfc1-b9fe-4b6d-9bf7-499d6b09c949", 101 | "id": "897a76c611234fb6a540af93325b6e31", 102 | "time": "2016-08-22T01:29:54.952Z", 103 | "timezoneOffset": 720, 104 | "source": "Insulet", 105 | "deviceSerialNumber": "123-45-678", 106 | "uploadId": "SampleUploadId" 107 | } 108 | -------------------------------------------------------------------------------- /data/pumpSettings/omnipod/multirate.raw.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "pumpSettings", 3 | "activeSchedule": "Normal", 4 | "basalSchedules": { 5 | "Normal": [ 6 | { 7 | "start": 0, 8 | "rate": 0.325 9 | }, 10 | { 11 | "start": 9000000, 12 | "rate": 0.45 13 | }, 14 | { 15 | "start": 23400000, 16 | "rate": 0.95 17 | }, 18 | { 19 | "start": 46800000, 20 | "rate": 1.375 21 | } 22 | ], 23 | "Other": [ 24 | { 25 | "start": 0, 26 | "rate": 0.325 27 | }, 28 | { 29 | "start": 9000000, 30 | "rate": 0.45 31 | }, 32 | { 33 | "start": 23400000, 34 | "rate": 0.95 35 | }, 36 | { 37 | "start": 46800000, 38 | "rate": 1.375 39 | } 40 | ] 41 | }, 42 | "units": { 43 | "carbs": "grams", 44 | "bg": "mmol/L" 45 | }, 46 | "bgTarget": [ 47 | { 48 | "start": 0, 49 | "target": 6.1058227901500866, 50 | "high": 6.938434988806917 51 | } 52 | ], 53 | "carbRatio": [ 54 | { 55 | "amount": 20, 56 | "start": 0 57 | } 58 | ], 59 | "insulinSensitivity": [ 60 | { 61 | "amount": 3.774508633910963, 62 | "start": 0 63 | } 64 | ], 65 | "clockDriftOffset": 0, 66 | "conversionOffset": 0, 67 | "deviceId": "DevId0987654321", 68 | "deviceTime": "2016-08-22T13:29:54", 69 | "guid": "929bcfc1-b9fe-4b6d-9bf7-499d6b09c949", 70 | "id": "897a76c611234fb6a540af93325b6e31", 71 | "time": "2016-08-22T01:29:54.952Z", 72 | "timezoneOffset": 720, 73 | "source": "Insulet", 74 | "deviceSerialNumber": "123-45-678", 75 | "uploadId": "SampleUploadId" 76 | } 77 | -------------------------------------------------------------------------------- /data/pumpSettings/tandem/flatrate.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "pumpSettings", 3 | "activeSchedule": "sick", 4 | "basalSchedules": [ 5 | { 6 | "name": "Normal", 7 | "value": [ 8 | { 9 | "rate": 0.45, 10 | "start": 0 11 | } 12 | ] 13 | }, 14 | { 15 | "name": "sick", 16 | "value": [ 17 | { 18 | "rate": 0.675, 19 | "start": 0 20 | } 21 | ] 22 | } 23 | ], 24 | "bolus": { 25 | "Normal": { 26 | "amountMaximum": { 27 | "units": "Units", 28 | "value": 12 29 | }, 30 | "calculator": { 31 | "enabled": true, 32 | "insulin": { 33 | "duration": 300, 34 | "units": "minutes" 35 | } 36 | } 37 | }, 38 | "sick": { 39 | "amountMaximum": { 40 | "units": "Units", 41 | "value": 10 42 | }, 43 | "calculator": { 44 | "enabled": true, 45 | "insulin": { 46 | "duration": 245, 47 | "units": "minutes" 48 | } 49 | } 50 | } 51 | }, 52 | "units": { 53 | "carbs": "grams", 54 | "bg": "mmol/L" 55 | }, 56 | "bgTargets": { 57 | "Normal": [ 58 | { 59 | "start": 0, 60 | "target": 4.9956731919409805 61 | } 62 | ], 63 | "sick": [ 64 | { 65 | "start": 0, 66 | "target": 5.273210591493257 67 | } 68 | ] 69 | }, 70 | "carbRatios": { 71 | "Normal": [ 72 | { 73 | "amount": 9, 74 | "start": 0 75 | } 76 | ], 77 | "sick": [ 78 | { 79 | "amount": 7, 80 | "start": 0 81 | } 82 | ] 83 | }, 84 | "insulinSensitivities": { 85 | "Normal": [ 86 | { 87 | "amount": 4.496105872746882, 88 | "start": 0 89 | } 90 | ], 91 | "sick": [ 92 | { 93 | "amount": 2.608851555791401, 94 | "start": 0 95 | } 96 | ] 97 | }, 98 | "clockDriftOffset": 0, 99 | "conversionOffset": 0, 100 | "deviceId": "DevId0987654321", 101 | "deviceTime": "2016-07-12T23:56:43", 102 | "guid": "73fab33a-cd94-4dca-811d-795d519b795e", 103 | "id": "5bd5bfa1f1364f53b848a9e00ef23c65", 104 | "time": "2016-07-13T06:56:43.251Z", 105 | "timezoneOffset": -420, 106 | "uploadId": "SampleUploadId", 107 | "source": "Tandem", 108 | "deviceSerialNumber": "0987654321" 109 | } 110 | -------------------------------------------------------------------------------- /docs/CodeStyle.md: -------------------------------------------------------------------------------- 1 | ## Code style 2 | 3 | In this repository—our newest front-end repository at Tidepool—our JavaScript style is *much* stricter than in our other repositories, largely because we started the work and continue to develop with a [very strict ESLint configuration, borrowed from AirBnb](https://www.npmjs.com/package/eslint-config-airbnb 'npm: eslint-config-airbnb'). 4 | 5 | It is not worth duplicating a description of the vast number of constraints that this configuration imposes. Our advice is to configure your editor to provide instant linting feedback as you code[^a], and you will learn the constraints quite quickly 😜 6 | 7 | To summarize in general the constraints that the AirBnb ESLint configuration imposes: 8 | - ES2015/ES6 given preference over ES5 (so `const` and `let` over `var`, etc.) 9 | - lots of general code quality/bug prevention constraints like no unused variables, no mutating arguments to functions, etc. 10 | - React components that don't need a (substantive) constructor, any of the lifecycle methods, or component-internal state should be [pure functional components](https://facebook.github.io/react/docs/components-and-props.html#functional-and-class-components 'React docs: Functional and Class Components') instead of classes 11 | - all React components should type-check the props used via [PropTypes](https://facebook.github.io/react/docs/typechecking-with-proptypes.html 'React docs: Typechecking with PropTypes') 12 | 13 | We have also added an additional plug-in for enforcing a preference for [lodash](https://lodash.com/docs/4.16.6 'Lodash utility library') utility methods over their native implementations (e.g., lodash `_.map` instead of JavaScript `Array.map`). 14 | 15 | Also see the documentation on [directory structure](./DirectoryStructure.md) for our conventions around file naming, placement, and in particular our semantic division between "containers" and "components." 16 | 17 | * * * * * 18 | 19 | [^a]: And you don't even have to Google! Here's where to get started for [Sublime Text](http://www.sublimelinter.com/en/latest/ 'SublimeLinter 3') and [Atom](https://atom.io/packages/linter 'Linter'). 20 | -------------------------------------------------------------------------------- /docs/StartHere.md: -------------------------------------------------------------------------------- 1 | # @tidepool/viz developer guide 2 | 3 | This repository, which is published to [npm](https://www.npmjs.com/ 'node package manager') as [@tidepool/viz](https://www.npmjs.com/package/@tidepool/viz 'npm: @tidepool/viz') is a library providing data visualization components and state management tools for use in [blip](https://github.com/tidepool-org/blip 'GitHub: blip'), Tidepool's main web application for people with type 1 diabetes and their care teams to view and contextualize (via notes) the PwD's diabetes device data. 4 | 5 | You can view (some of) the components in this library via two Storybooks published as static sites: 6 | 7 | 1. [components rendering data types in the Tidepool data model](http://developer.tidepool.io/viz/diabetes-data-stories/ 'Storybook for Tidepool diabetes data model renderers') 8 | 1. [all other components](http://developer.tidepool.io/viz/stories/ 'Storybook for all non-diabetes data @tidepool/viz components') 9 | 10 | As you're getting ready to develop code in this repository, we recommend starting with the following documents: 11 | 12 | - [project background](./Background.md) 13 | - [overview of features](./FeatureOverview.md) 14 | - [planned architecture](./Architecture.md) 15 | - [app & directory structure](./DirectoryStructure.md) 16 | - [code style](./CodeStyle.md) 17 | - [dependencies](./deps/README.md) 18 | - [use of React Storybook](./Storybook.md) 19 | 20 | The root-level [README](../README.md) contains the nuts & bolts of installing, configuring, and commands to accomplish various tasks. 21 | 22 | The [per-view documentation](./views/README.md) is the place to look for details on the implementation of each major data "view" implemented in this repository for inclusion in blip. 23 | 24 | Finally, there are some miscellaneous docs on *miscellaneous* topics: 25 | 26 | - [Common props](./misc/CommonProps.md) documents and provides a quick reference to a few very common props you will see used and passed around many viz components. 27 | - [Working on docs](./misc/Docs.md) contains guidance on getting set up to add to this documentation. 28 | - [Time rendering modes](./misc/TimeRenderingModes.md) documents the difference between the "timezone-aware" (default) and "timezone-naïve" rendering modes. 29 | -------------------------------------------------------------------------------- /docs/deps/Moment.md: -------------------------------------------------------------------------------- 1 | ## @tidepool/viz's usage of Moment.js 2 | 3 | We use [moment](http://momentjs.com/ 'Moment.js') and [moment-timezone](http://momentjs.com/timezone/ 'Moment Timezone') to handle datetime computations with arbitrary timezone support. (JavaScript's built-in [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date 'MDN: JavaScript Date')) only handles UTC or browser-local time natively and *does not* support datetimes in an arbitrary timezone (i.e., that may be different from the current browser timezone). 4 | 5 | Moment's APIs are rather complex and the differences between nearly identical methods can be subtle (but important!). This document is to record the biggest "gotchas" we've run into with moment, or, in other words, to record what we've derived as our moment best practices over our years of hard lessons using the library. 6 | 7 | More to come! 8 | -------------------------------------------------------------------------------- /docs/deps/README.md: -------------------------------------------------------------------------------- 1 | ## Dependencies 2 | 3 | We use [webpack](https://webpack.github.io/ 'webpack module bundler') to bundle the JavaScript, CSS, and JSON assets in this repository into a single JavaScript bundle from which blip can import the pieces (components, functions, etc.) needed. 4 | 5 | Some of the other dependencies we leverage in this repository are, like webpack, commonly used by many others building apps today with React, and some are a bit more unusual: 6 | 7 | - [D3](https://d3js.org/ 'D3: Data-Driven Documents') ([read more](./D3.md)) 8 | - [GSAP](https://greensock.com/ 'GreenSock') ([read more](./GSAP.md)) 9 | - [Moment](http://momentjs.com/ 'Moment.js') ([read more](./Moment.md)) 10 | - [React](https://facebook.github.io/react/ 'React') ([read more](./React.md)) 11 | - [react-motion](https://github.com/chenglou/react-motion 'GitHub: react-motion') (see [D3 usage](./D3.md) as well as [React Motion](./ReactMotion.md)) 12 | - [webpack](https://webpack.github.io/ 'webpack module bundler') ([read more](./Webpack.md)) 13 | 14 | Follow the "read more" link where available in this list of tools to learn more about the specifics of our usage of the tool in this repository. 15 | -------------------------------------------------------------------------------- /docs/deps/React.md: -------------------------------------------------------------------------------- 1 | ## @tidepool/viz's usage of React 2 | 3 | Aside from [our general views on React best practices at Tidepool](http://developer.tidepool.io/docs/front-end/react/index.html 'Tidepool developer portal: React @ Tidepool'), to develop code in this repository you should: 4 | 5 | - understand our division between [components, "container" components, and views](../DirectoryStructure.md#react-component-directories) 6 | - understand [how we use D3 and React together]('./D3.md') 7 | -------------------------------------------------------------------------------- /docs/deps/Webpack.md: -------------------------------------------------------------------------------- 1 | ## @tidepool/viz's usage of webpack 2 | 3 | Our use of [webpack](https://webpack.github.io/ 'webpack module bundler') in this repository is a bit different from our use of it in blip or the Tidepool uploader, where we're using it to build applications. Here we're using webpack to bundle our JavaScript, CSS, and JSON[^a] into a bundle that can be published to the [node package manager](http://npmjs.com/ 'npm') and then included as a dependency in other projects like blip. 4 | 5 | While [the development webpack configuration](https://github.com/tidepool-org/viz/blob/master/webpack.config.js 'GitHub: viz webpack.config.js') is pretty similar to the configurations we used in blip and the uploader, [the production packaging configuration](https://github.com/tidepool-org/viz/blob/master/package.config.js 'GitHub: viz package.config.js') is different in that it specifies a `libraryTarget` and defines many of the dependencies as `externals` so that they don't get bundled twice (in both the viz JavaScript bundle and the blip bundle). 6 | 7 | [^a]: The timezone database that comes with [moment-timezone](http://momentjs.com/timezone/ 'Moment Timezone') is JSON. 8 | -------------------------------------------------------------------------------- /docs/misc/Docs.md: -------------------------------------------------------------------------------- 1 | ## Working on viz docs 2 | 3 | This repository's docs are set up like all of Tidepool's front-end and docs repos. For details on this setup, see the [general guidance for docs setup & workflow](http://developer.tidepool.io/docs/docs/workflow.html 'Tidepool docs setup & workflow'). 4 | 5 | ### Setup 6 | 7 | To summarize briefly, the steps you will need to have done in order to use the `npm` scripts configured for docs work in the repository are: 8 | 9 | - clone a second copy of this repository as a subdirectory `web/`; you can do this from your `viz/` directory with `git clone git@github.com:tidepool-org/viz.git web` 10 | - switch to the `gh-pages` branch in the embedded clone and delete the `master` branch 11 | 12 | ```bash 13 | $ cd web/ 14 | $ git checkout gh-pages 15 | $ git branch -d master 16 | ``` 17 | 18 | ### Regenerating 19 | 20 | We generate Markdown documentation for the utilities in `src/utils/` from the [JSDoc comments](http://usejsdoc.org/ 'JSDoc') included with all exports and/or functions. The [README](../../src/utils/README.md) in `src/utils/` documents how to regenerate these Markdown files; this regeneration should be performed whenever you've added or updated a utility functon and/or the JSDoc for that utility. 21 | 22 | ### Publishing 23 | 24 | To publish revised docs and/or Storybooks, run the following from the root of the `viz/` directory: 25 | 26 | For updating just docs (including the `adidocs/` in `src/utils/`) by building the static [GitBook](https://www.gitbook.com/ 'GitBook') site that we publish to GitHub Pages: 27 | 28 | ```bash 29 | $ npm run build-docs 30 | ``` 31 | 32 | Then `cd web/` and review the unstaged changes. Stage & commit the changes you want to make. Finally, "publish" to GitHub pages by pushing to the upstream `gh-pages` branch. 33 | 34 | For updating the Storybooks (again from the root of `viz/`: 35 | 36 | ```bash 37 | $ npm run build-storybooks 38 | ``` 39 | 40 | Again navigate into the embedded `web/` directory to review, stage, commit, and push the changes upstream. 41 | -------------------------------------------------------------------------------- /docs/misc/README.md: -------------------------------------------------------------------------------- 1 | ## Miscellaneous documents 2 | 3 | + [common props](./CommonProps.md) 4 | + [this repo's documentation](./Docs.md) 5 | + [time rendering modes](./TimeRenderingModes.md) 6 | -------------------------------------------------------------------------------- /docs/views/README.md: -------------------------------------------------------------------------------- 1 | ## per-view documentation 2 | 3 | Following Tidepool's general [documentation guidelines](http://developer.tidepool.io/docs/docs/guidelines.html 'Tidepool Developer Portal: Docs Guideslines'), included here is documentation regarding the implementation of each major data "view" implemented in this repository for inclusion in Tidepool's web application blip. 4 | 5 | - [Device Settings view](../../src/components/settings/README.md) 6 | - [Trends view](./Trends.md) 7 | -------------------------------------------------------------------------------- /docs/views/images/bgm_trends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/bgm_trends.png -------------------------------------------------------------------------------- /docs/views/images/bgm_trends_date_line_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/bgm_trends_date_line_hover.png -------------------------------------------------------------------------------- /docs/views/images/bgm_trends_range_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/bgm_trends_range_hover.png -------------------------------------------------------------------------------- /docs/views/images/bgm_trends_smbg_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/bgm_trends_smbg_hover.png -------------------------------------------------------------------------------- /docs/views/images/cgm_trends.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/cgm_trends.png -------------------------------------------------------------------------------- /docs/views/images/cgm_trends_segment_hover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/cgm_trends_segment_hover.gif -------------------------------------------------------------------------------- /docs/views/images/cgm_trends_segment_hover_hold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/cgm_trends_segment_hover_hold.png -------------------------------------------------------------------------------- /docs/views/images/cgm_trends_segment_hover_hold_cbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/cgm_trends_segment_hover_hold_cbg.png -------------------------------------------------------------------------------- /docs/views/images/tidelineContainer@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/tidelineContainer@2x.png -------------------------------------------------------------------------------- /docs/views/images/trends_code_locations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/trends_code_locations.png -------------------------------------------------------------------------------- /docs/views/images/trends_layout.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/docs/views/images/trends_layout.sketch -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpackConf = require('./webpack.config.js'); 3 | const optional = require('optional'); 4 | const mochaConf = optional('./local/mocha.opts.json') || {}; 5 | 6 | webpackConf.externals = { 7 | cheerio: 'window', 8 | 'react/addons': true, 9 | 'react/lib/ExecutionEnvironment': true, 10 | 'react/lib/ReactContext': true, 11 | }; 12 | 13 | webpackConf.devtool = process.env.DEV_TOOL || false; 14 | webpackConf.mode = 'development'; 15 | 16 | webpackConf.output = { 17 | path: path.join(__dirname, '/dist/'), 18 | }; 19 | 20 | delete webpackConf.entry; 21 | 22 | module.exports = function karmaConfig(config) { 23 | config.set({ 24 | autoWatch: true, 25 | browserNoActivityTimeout: 60000, 26 | browsers: ['CustomChromeHeadless'], 27 | captureTimeout: 60000, 28 | client: { 29 | mocha: mochaConf, 30 | }, 31 | colors: true, 32 | concurrency: Infinity, 33 | coverageReporter: { 34 | dir: 'coverage/', 35 | reporters: [ 36 | { type: 'html' }, 37 | { type: 'text' }, 38 | ], 39 | }, 40 | customLaunchers: { 41 | CustomChromeHeadless: { 42 | base: 'ChromeHeadless', 43 | flags: [ 44 | '--headless', 45 | '--enable-automation', 46 | '--no-sandbox', 47 | '--remote-debugging-port=9222', 48 | ], 49 | }, 50 | }, 51 | files: [ 52 | 'loadtests.js', 53 | ], 54 | frameworks: ['webpack', 'mocha', 'chai', 'sinon', 'intl-shim'], 55 | logLevel: config.LOG_INFO, 56 | plugins: [ 57 | 'karma-webpack', 58 | 'karma-sourcemap-loader', 59 | 'karma-mocha', 60 | 'karma-mocha-reporter', 61 | 'karma-chai', 62 | 'karma-sinon', 63 | 'karma-intl-shim', 64 | 'karma-chrome-launcher', 65 | 'karma-coverage', 66 | ], 67 | preprocessors: { 68 | 'loadtests.js': ['webpack', 'sourcemap'], 69 | }, 70 | reporters: ['mocha', 'coverage'], 71 | singleRun: true, 72 | webpack: webpackConf, 73 | webpackMiddleware: { 74 | noInfo: true, 75 | stats: 'errors-only', 76 | }, 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /loadtests.js: -------------------------------------------------------------------------------- 1 | require('@babel/polyfill'); 2 | require('intl/locale-data/jsonp/en.js'); 3 | require('intl-pluralrules'); 4 | 5 | const _ = require('lodash'); 6 | const enzyme = require('enzyme'); 7 | const Adapter = require('enzyme-adapter-react-16'); 8 | const i18next = require('i18next'); 9 | 10 | // Should be initialized in calling module 11 | if (_.get(i18next, 'options.returnEmptyString') === undefined) { 12 | // Return key if no translation is present 13 | i18next.init({ returnEmptyString: false, nsSeparator: '|' }); 14 | } 15 | 16 | enzyme.configure({ 17 | adapter: new Adapter(), 18 | disableLifecycleMethods: true, 19 | }); 20 | 21 | const context = require.context('./test', true, /\.test\.js$/); // Load .js files in /test 22 | context.keys().forEach(context); // eslint-disable-line lodash/prefer-lodash-method 23 | -------------------------------------------------------------------------------- /package.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const _ = require('lodash'); 3 | 4 | const baseConfig = require('./webpack.config'); 5 | const packageConfig = _.cloneDeep(baseConfig); 6 | 7 | // eslint-disable-next-line no-underscore-dangle 8 | const __DEV__ = process.env.NODE_ENV === 'development'; 9 | 10 | packageConfig.output.libraryTarget = 'commonjs'; 11 | 12 | packageConfig.externals = { 13 | bluebird: 'bluebird', 14 | bows: 'bows', 15 | 'browserify-zlib': 'browserify-zlib', 16 | buffer: 'buffer', 17 | classnames: 'classnames', 18 | crossfilter2: 'crossfilter2', 19 | 'd3-array': 'd3-array', 20 | 'd3-format': 'd3-format', 21 | 'd3-scale': 'd3-scale', 22 | 'd3-shape': 'd3-shape', 23 | 'd3-time': 'd3-time', 24 | 'd3-time-format': 'd3-time-format', 25 | emotion: 'emotion', 26 | events: 'events', 27 | 'fastest-validator': 'fastest-validator', 28 | gsap: 'gsap', 29 | i18next: 'i18next', 30 | intl: 'intl', 31 | 'intl-pluralrules': 'intl-pluralrules', 32 | lodash: 'lodash', 33 | memorystream: 'memorystream', 34 | moment: 'moment', 35 | 'moment-timezone': 'moment-timezone', 36 | 'parse-svg-path': 'parse-svg-path', 37 | process: 'process', 38 | 'prop-types': 'prop-types', 39 | react: 'react', 40 | 'react-clipboard.js': 'react-clipboard.js', 41 | 'react-collapse': 'react-collapse', 42 | 'react-dimensions': 'react-dimensions', 43 | 'react-dom': 'react-dom', 44 | 'react-markdown': 'react-markdown', 45 | 'react-motion': 'react-motion', 46 | 'react-redux': 'react-redux', 47 | 'react-select': 'react-select', 48 | 'react-sizeme': 'react-sizeme', 49 | 'react-transition-group-plus': 'react-transition-group-plus', 50 | 'readable-stream': 'readable-stream', 51 | reductio: 'reductio', 52 | redux: 'redux', 53 | 'serialize-svg-path': 'serialize-svg-path', 54 | sundial: 'sundial', 55 | 'svg-to-pdfkit': 'svg-to-pdfkit', 56 | 'text-table': 'text-table', 57 | 'translate-svg-path': 'translate-svg-path', 58 | util: 'util', 59 | victory: 'victory', 60 | 'voilab-pdf-table': 'voilab-pdf-table', 61 | }; 62 | 63 | packageConfig.plugins = [ 64 | new webpack.DefinePlugin({ 65 | __DEV__, 66 | }), 67 | ]; 68 | 69 | packageConfig.mode = 'production'; 70 | 71 | module.exports = packageConfig; 72 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | const calc = require('postcss-calc'); 2 | const cssVariables = require('postcss-custom-properties'); 3 | 4 | module.exports = { 5 | plugins: [calc, cssVariables], 6 | }; 7 | -------------------------------------------------------------------------------- /src/components/common/controls/ClipboardButton.css: -------------------------------------------------------------------------------- 1 | .copyButton { 2 | composes: defaultSize from '../../../styles/typography.css'; 3 | padding: 5px 10px; 4 | border-radius: 4px; 5 | cursor: pointer; 6 | color: var(--text-medium-contrast); 7 | background-color: var(--white); 8 | border: solid 1px var(--stat--border); 9 | outline: none; 10 | position: relative; 11 | text-align: left; 12 | line-height: 1; 13 | } 14 | 15 | .copyButton:hover { 16 | background-image: none; 17 | color: var(--white); 18 | background-color: var(--brand-purple); 19 | border-color: var(--brand-purple); 20 | } 21 | 22 | .copyButton:active { 23 | background-image: none; 24 | color: var(--white); 25 | background-color: var(--brand-purple); 26 | border-color: var(--brand-purple); 27 | opacity: 0.62; 28 | } 29 | 30 | .buttonText, .successText { 31 | margin: 0; 32 | padding: 0; 33 | display: block; 34 | } 35 | 36 | .copyButton.buttonTextHidden .buttonText { 37 | visibility: hidden; 38 | height: 0; 39 | } 40 | 41 | .copyButton.successTextHidden .successText { 42 | visibility: hidden; 43 | height: 0; 44 | } 45 | 46 | @media print { 47 | .copyButton { 48 | display: none; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/components/common/controls/InputGroup.css: -------------------------------------------------------------------------------- 1 | :global(.inputGroup-suffix__indicator-separator) { 2 | display: none !important; 3 | } 4 | 5 | :global(.inputGroup-suffix__input) { 6 | color: transparent; 7 | } 8 | 9 | :global(.inputGroup-suffix__control) { 10 | height: 24px; 11 | min-height: 24px !important; 12 | border: none !important; 13 | background-color: transparent !important; 14 | border-radius: 0 !important; 15 | box-shadow: none !important; 16 | } 17 | 18 | :global(.inputGroup-suffix__control--is-focused) { 19 | border: none !important; 20 | box-shadow: none !important; 21 | outline: 0 !important; 22 | } 23 | 24 | :global(.inputGroup-suffix__dropdown-indicator) { 25 | padding: 0 !important; 26 | } 27 | 28 | :global(.inputGroup-suffix__dropdown-indicator svg) { 29 | height: 14px; 30 | } 31 | 32 | :global(.inputGroup-suffix__value-container) { 33 | padding: 0 4px !important; 34 | line-height: 1; 35 | } 36 | 37 | .wrapper { 38 | display: flex; 39 | justify-content: space-between; 40 | align-items: center; 41 | } 42 | 43 | .label { 44 | composes: largeSize from '../../../styles/typography.css'; 45 | } 46 | 47 | .inputs { 48 | display: flex; 49 | align-items: center; 50 | composes: smallSize from '../../../styles/typography.css'; 51 | } 52 | 53 | .inputs > input:first-child { 54 | border-top-left-radius: 4px; 55 | border-bottom-left-radius: 4px; 56 | border: 1px solid var(--stat--border); 57 | border-right: none; 58 | padding: 0 5px; 59 | height: 24px; 60 | } 61 | 62 | .inputs > input:first-child:focus { 63 | outline: 0; 64 | } 65 | 66 | .input-number { 67 | min-width: 50px; 68 | -moz-appearance: textfield; 69 | } 70 | 71 | .input-number::-webkit-outer-spin-button, 72 | .input-number::-webkit-inner-spin-button { 73 | -webkit-appearance: none; 74 | margin: 0; 75 | } 76 | 77 | .suffix { 78 | min-width: 45px; 79 | border: 1px solid var(--input--border); 80 | border-top-right-radius: 4px; 81 | border-bottom-right-radius: 4px; 82 | height: 24px; 83 | } 84 | 85 | .suffixText { 86 | composes: suffix; 87 | display: flex; 88 | align-items: center; 89 | padding-left: 5px; 90 | min-width: 40px; 91 | color: var(--input--disabled); 92 | } 93 | -------------------------------------------------------------------------------- /src/components/common/controls/LabeledCheckbox.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .label { 19 | composes: mediumContrastText largeSize from '../../../styles/typography.css'; 20 | padding-right: 12px; 21 | } 22 | -------------------------------------------------------------------------------- /src/components/common/controls/LabeledCheckbox.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import PropTypes from 'prop-types'; 19 | import React from 'react'; 20 | 21 | import styles from './LabeledCheckbox.css'; 22 | 23 | const LabeledCheckbox = (props) => { 24 | const { name, checked, onFn, offFn, label } = props; 25 | const handleChange = function handleChange() { 26 | if (checked) { 27 | offFn(); 28 | } else { 29 | onFn(); 30 | } 31 | }; 32 | 33 | return ( 34 | 41 | ); 42 | }; 43 | 44 | LabeledCheckbox.propTypes = { 45 | checked: PropTypes.bool.isRequired, 46 | onFn: PropTypes.func.isRequired, 47 | offFn: PropTypes.func.isRequired, 48 | label: PropTypes.node.isRequired, 49 | name: PropTypes.string.isRequired, 50 | }; 51 | 52 | export default LabeledCheckbox; 53 | -------------------------------------------------------------------------------- /src/components/common/controls/TwoOptionToggle.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .container { 19 | display: flex; 20 | align-items: center; 21 | } 22 | 23 | .label { 24 | composes: mediumContrastText smallSize from '../../../styles/typography.css'; 25 | padding: 4px; 26 | } 27 | 28 | .active { 29 | font-weight: bold; 30 | } 31 | 32 | .toggle { 33 | display: inline-block; 34 | position: relative; 35 | 36 | background-color: transparent; 37 | border: 0; 38 | cursor: pointer; 39 | padding: 0; 40 | user-select: none; 41 | } 42 | 43 | .disabled { 44 | composes: toggle; 45 | cursor: not-allowed; 46 | opacity: 0.5; 47 | transition: opacity 0.25s; 48 | } 49 | 50 | .track { 51 | width: 50px; 52 | height: 24px; 53 | 54 | background-color: var(--chrome); 55 | border-radius: 30px; 56 | padding: 0; 57 | transition: all 0.2s ease; 58 | } 59 | 60 | .thumb { 61 | position: absolute; 62 | top: 1px; 63 | 64 | width: 22px; 65 | height: 22px; 66 | 67 | background-color: white; 68 | border: 1px solid var(--chrome); 69 | border-radius: 50%; 70 | box-sizing: border-box; 71 | transition: all 0.25s ease; 72 | } 73 | 74 | .leftThumb { 75 | composes: thumb; 76 | left: 1px; 77 | } 78 | 79 | .rightThumb { 80 | composes: thumb; 81 | left: 27px; 82 | } 83 | -------------------------------------------------------------------------------- /src/components/common/data/Basal.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | :root { 18 | --stroke-width: 1.5; 19 | } 20 | 21 | .noFill { 22 | fill: none; 23 | } 24 | 25 | .noStroke { 26 | stroke: none; 27 | stroke-width: 0; 28 | } 29 | 30 | .border--delivered--manual { 31 | composes: noFill; 32 | composes: basalScheduledPath from '../../../styles/diabetes.css'; 33 | stroke-width: var(--stroke-width); 34 | } 35 | 36 | .border--delivered--automated { 37 | composes: noFill; 38 | composes: basalAutomatedPath from '../../../styles/diabetes.css'; 39 | stroke-width: var(--stroke-width); 40 | } 41 | 42 | .border--undelivered { 43 | composes: noFill; 44 | composes: basalUndeliveredPath from '../../../styles/diabetes.css'; 45 | } 46 | 47 | .border--undelivered--automated { 48 | composes: noFill; 49 | composes: basalUndeliveredPath from '../../../styles/diabetes.css'; 50 | stroke-width: 2; 51 | } 52 | 53 | .fill--scheduled { 54 | composes: noStroke; 55 | composes: basalScheduledFill from '../../../styles/diabetes.css'; 56 | } 57 | 58 | .fill--automated { 59 | composes: noStroke; 60 | composes: basalAutomatedFill from '../../../styles/diabetes.css'; 61 | } 62 | 63 | .fill--temp { 64 | composes: basalTempFill from '../../../styles/diabetes.css'; 65 | } 66 | 67 | .marker { 68 | stroke-width: 2.5; 69 | } 70 | 71 | .marker--manual { 72 | composes: marker; 73 | fill: var(--basal); 74 | stroke: var(--basal); 75 | } 76 | 77 | .marker--automated { 78 | composes: marker; 79 | fill: var(--basal-automated); 80 | stroke: var(--basal-automated); 81 | } 82 | 83 | .markerText { 84 | fill: var(--white); 85 | stroke-width: 0; 86 | font-size: 10px; 87 | text-anchor: middle; 88 | dominant-baseline: central; 89 | } 90 | 91 | .marker--automated .markerText { 92 | fill: var(--gray-dark); 93 | } 94 | 95 | :export { 96 | strokeWidth: 1.5; 97 | } 98 | -------------------------------------------------------------------------------- /src/components/common/data/Bolus.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .noStroke { 19 | stroke: none; 20 | stroke-width: 0; 21 | } 22 | 23 | .carbCircle { 24 | composes: noStroke; 25 | composes: carbs from '../../../styles/diabetes.css'; 26 | } 27 | 28 | .carbText { 29 | composes: mediumContrastText smallSize svgMiddleAnchored svgVerticalCentered from '../../../styles/typography.css'; 30 | } 31 | 32 | .delivered { 33 | composes: noStroke; 34 | composes: bolusDelivered from '../../../styles/diabetes.css'; 35 | } 36 | 37 | .extendedExpectationPath { 38 | composes: bolusUndelivered from '../../../styles/diabetes.css'; 39 | } 40 | 41 | .extendedInterrupted { 42 | composes: bolusInterrupted from '../../../styles/diabetes.css'; 43 | } 44 | 45 | .extendedPath { 46 | composes: noStroke; 47 | composes: bolusDelivered from '../../../styles/diabetes.css'; 48 | } 49 | 50 | .extendedTriangle { 51 | composes: noStroke; 52 | composes: bolusDelivered from '../../../styles/diabetes.css'; 53 | } 54 | 55 | .extendedTriangleInterrupted { 56 | composes: noStroke; 57 | composes: bolusUndelivered from '../../../styles/diabetes.css'; 58 | } 59 | 60 | .interrupted { 61 | composes: bolusInterrupted from '../../../styles/diabetes.css'; 62 | } 63 | 64 | .programmed { 65 | composes: bolusProgrammed from '../../../styles/diabetes.css'; 66 | } 67 | 68 | .triangle { 69 | composes: noStroke; 70 | composes: bolusRideTriangle from '../../../styles/diabetes.css'; 71 | } 72 | 73 | .undelivered { 74 | composes: noStroke; 75 | composes: bolusUndelivered from '../../../styles/diabetes.css'; 76 | } 77 | 78 | .underride { 79 | composes: noStroke; 80 | composes: bolusUnderride from '../../../styles/diabetes.css'; 81 | } 82 | -------------------------------------------------------------------------------- /src/components/common/loader/Loader.css: -------------------------------------------------------------------------------- 1 | .loader { 2 | display: flex; 3 | pointer-events: none; 4 | } 5 | 6 | .loaderDots { 7 | opacity: 1; 8 | transition: opacity .25s ease; 9 | display: flex; 10 | position: absolute; 11 | z-index: 10; 12 | top: 50%; 13 | left: 50%; 14 | transform: translate(-50%, -50%); 15 | justify-content: center; 16 | align-items: center; 17 | width: 100%; 18 | height: 100%; 19 | } 20 | 21 | .loaderText { 22 | color: var(--text-high-contrast); 23 | font-size: 14px; 24 | display: flex; 25 | width: 100%; 26 | justify-content: center; 27 | position: absolute; 28 | top: calc(50% + 29px); 29 | left: 50%; 30 | transform: translate(-50%, -50%); 31 | } 32 | 33 | .loaderDots.overlay { 34 | background: radial-gradient(rgba(255,255,255,0.9), rgba(255,255,255,0.7)); 35 | } 36 | 37 | .loaderDots.hidden { 38 | opacity: 0.01; 39 | } 40 | 41 | .loaderDot { 42 | margin: 5px; 43 | width: 16px; 44 | height: 16px; 45 | border-radius: 50%; 46 | background: var(--brand-purple-dark); 47 | transform: scale(0.5); 48 | } 49 | 50 | .loaderDot.animating { 51 | animation: scale-dot 1.2s ease-out infinite; 52 | } 53 | 54 | .loaderDot:nth-of-type(2) { 55 | animation-delay: 0.2s; 56 | } 57 | 58 | .loaderDot:nth-of-type(3) { 59 | animation-delay: 0.3s; 60 | } 61 | 62 | .loaderDot:nth-of-type(4) { 63 | animation-delay: 0.4s; 64 | } 65 | 66 | .loaderDot:nth-of-type(5) { 67 | animation-delay: 0.5s; 68 | } 69 | 70 | @keyframes scale-dot { 71 | 0% { 72 | transform: scale(0.5); 73 | } 74 | 25% { 75 | transform: scale(1); 76 | } 77 | 75% { 78 | transform: scale(0.5); 79 | } 80 | 100% { 81 | transform: scale(0.5); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/components/common/loader/Loader.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import PropTypes from 'prop-types'; 19 | import React from 'react'; 20 | import cx from 'classnames'; 21 | 22 | import styles from './Loader.css'; 23 | 24 | const Loader = (props) => { 25 | const { show, overlay, text } = props; 26 | 27 | const loaderOuterClasses = cx({ 28 | loader: true, 29 | [styles.loader]: true, 30 | }); 31 | 32 | const loaderInnerClasses = cx({ 33 | [styles.loaderDots]: true, 34 | [styles.hidden]: !show, 35 | [styles.overlay]: overlay, 36 | }); 37 | 38 | const loaderDotClasses = cx({ 39 | [styles.loaderDot]: true, 40 | [styles.animating]: show, 41 | }); 42 | 43 | return ( 44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | 52 |
{text}
53 |
54 |
55 | ); 56 | }; 57 | 58 | Loader.defaultProps = { 59 | overlay: false, 60 | show: true, 61 | text: 'Loading...', 62 | }; 63 | 64 | Loader.propTypes = { 65 | overlay: PropTypes.bool.isRequired, 66 | show: PropTypes.bool.isRequired, 67 | text: PropTypes.string, 68 | }; 69 | 70 | export default Loader; 71 | -------------------------------------------------------------------------------- /src/components/common/stat/BgBarLabel.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import _ from 'lodash'; 4 | import { VictoryLabel } from 'victory'; 5 | 6 | export const BgBarLabel = props => { 7 | const { 8 | barWidth, 9 | domain, 10 | scale = { 11 | x: _.noop, 12 | y: _.noop, 13 | }, 14 | } = props; 15 | 16 | const labelStyle = _.assign({}, props.style, { 17 | pointerEvents: 'none', 18 | }); 19 | 20 | return ( 21 | 22 | 32 | 33 | ); 34 | }; 35 | 36 | BgBarLabel.propTypes = { 37 | domain: PropTypes.object.isRequired, 38 | scale: PropTypes.object, 39 | text: PropTypes.func, 40 | y: PropTypes.number, 41 | }; 42 | 43 | BgBarLabel.displayName = 'BgBarLabel'; 44 | 45 | export default BgBarLabel; 46 | -------------------------------------------------------------------------------- /src/components/common/stat/HoverBar.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { Bar, Rect } from 'victory'; 4 | import _ from 'lodash'; 5 | 6 | import colors from '../../../styles/colors.css'; 7 | 8 | export const HoverBar = props => { 9 | const { 10 | barSpacing, 11 | barWidth, 12 | chartLabelWidth, 13 | cornerRadius, 14 | domain, 15 | index, 16 | scale = { 17 | x: _.noop, 18 | y: _.noop, 19 | }, 20 | width, 21 | x 22 | } = props; 23 | 24 | const barGridWidth = barWidth / 6; 25 | const barGridRadius = _.get(cornerRadius, 'top', 2); 26 | const widthCorrection = (width - chartLabelWidth) / width; 27 | 28 | return ( 29 | 30 | 31 | 45 | 46 | 47 | 60 | 61 | 62 | 67 | 68 | 69 | ); 70 | }; 71 | 72 | HoverBar.propTypes = { 73 | chartLabelWidth: PropTypes.number, 74 | domain: PropTypes.object.isRequired, 75 | scale: PropTypes.object, 76 | y: PropTypes.number, 77 | }; 78 | 79 | HoverBar.displayName = 'HoverBar'; 80 | 81 | export default HoverBar; 82 | -------------------------------------------------------------------------------- /src/components/common/stat/StatLegend.css: -------------------------------------------------------------------------------- 1 | .StatLegend { 2 | composes: smallSize from '../../../styles/typography.css'; 3 | position: relative; 4 | list-style: none; 5 | display: flex; 6 | margin: 0; 7 | padding: 0; 8 | } 9 | 10 | .StatLegendItem { 11 | display: flex; 12 | flex-wrap: nowrap; 13 | align-items: center; 14 | margin: 0 1em 0 0; 15 | border-bottom: 2px solid; 16 | } 17 | 18 | .StatLegendTitle { 19 | letter-spacing: -.01em; 20 | white-space: nowrap; 21 | line-height: 16px; 22 | } 23 | -------------------------------------------------------------------------------- /src/components/common/stat/StatLegend.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React, { PureComponent } from 'react'; 3 | import _ from 'lodash'; 4 | 5 | import colors from '../../../styles/colors.css'; 6 | import styles from './StatLegend.css'; 7 | 8 | class StatLegend extends PureComponent { 9 | static propTypes = { 10 | items: PropTypes.arrayOf(PropTypes.shape({ 11 | id: PropTypes.string, 12 | legendTitle: PropTypes.string, 13 | })).isRequired, 14 | }; 15 | 16 | static displayName = 'StatLegend'; 17 | 18 | renderLegendItems = (items) => ( 19 | _.map(items, (item) => ( 20 |
  • 25 | 26 | {item.legendTitle} 27 | 28 |
  • 29 | )) 30 | ); 31 | 32 | render() { 33 | return ( 34 |
      35 | {this.renderLegendItems(this.props.items)} 36 |
    37 | ); 38 | } 39 | } 40 | 41 | export default StatLegend; 42 | -------------------------------------------------------------------------------- /src/components/common/stat/assets/chevron-right-24-px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/src/components/common/stat/assets/chevron-right-24-px.png -------------------------------------------------------------------------------- /src/components/common/stat/assets/expand-more-24-px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/src/components/common/stat/assets/expand-more-24-px.png -------------------------------------------------------------------------------- /src/components/common/stat/assets/info-outline-24-px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/src/components/common/stat/assets/info-outline-24-px.png -------------------------------------------------------------------------------- /src/components/common/tooltips/CgmSampleIntervalTooltip.css: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 260px; 3 | } 4 | 5 | .row { 6 | composes: smallSize from '../../../styles/typography.css'; 7 | line-height: 16px; 8 | color: var(--stat--default); 9 | margin-bottom: 8px; 10 | font-weight: medium; 11 | } 12 | 13 | .title { 14 | composes: row; 15 | font-weight: bold; 16 | } 17 | 18 | .subtitle { 19 | composes: row; 20 | } 21 | 22 | .annotations { 23 | padding-left: 24px; 24 | margin: 0 0 6px; 25 | } 26 | 27 | .annotation { 28 | composes: row; 29 | margin-bottom: 2px; 30 | } 31 | -------------------------------------------------------------------------------- /src/components/common/tooltips/StatTooltip.css: -------------------------------------------------------------------------------- 1 | .row { 2 | composes: smallSize from '../../../styles/typography.css'; 3 | line-height: 16px; 4 | max-width: 180px; 5 | min-width: 160px; 6 | font-weight: medium; 7 | } 8 | 9 | .message { 10 | composes: row; 11 | color: var(--stat--default); 12 | } 13 | 14 | .message p { 15 | margin: 0; 16 | } 17 | 18 | .message a { 19 | pointer-events: all; 20 | } 21 | 22 | .divider { 23 | height: 2px; 24 | margin: 10px -12px; 25 | background-color: var(--stat--default); 26 | } 27 | 28 | .hiddenDivider { 29 | height: 10px; 30 | background-color: transparent; 31 | } 32 | -------------------------------------------------------------------------------- /src/components/common/tooltips/Tooltip.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .tooltip { 19 | display: block; 20 | composes: defaultSize from '../../../styles/typography.css'; 21 | background-color: #FFFFFF; 22 | border: solid; 23 | pointer-events: none; 24 | position: absolute; 25 | border-radius: 4px; 26 | z-index: 1000; 27 | } 28 | 29 | .content { 30 | display: flex; 31 | align-items: center; 32 | justify-content: space-between; 33 | width: 100%; 34 | padding: 10px 12px; 35 | box-sizing: border-box; 36 | } 37 | 38 | .content span { 39 | width: 100%; 40 | } 41 | 42 | .title { 43 | composes: mediumContrastText from '../../../styles/typography.css'; 44 | composes: content; 45 | background-color: var(--tooltip-title-bg); 46 | } 47 | 48 | .tail { 49 | width: 0px; 50 | height: 0px; 51 | border-style: solid; 52 | border-color: transparent; 53 | position: absolute; 54 | } 55 | 56 | :export { 57 | tooltipTitleBg: var(--tooltip-title-bg); 58 | } 59 | -------------------------------------------------------------------------------- /src/components/daily/cbgtooltip/CBGTooltip.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | @import '../../../styles/colors.css'; 18 | 19 | .container { 20 | opacity: 1; 21 | display: flex; 22 | flex-direction: column; 23 | min-width: 80px; 24 | margin: 2px 0; 25 | max-width: 180px; 26 | } 27 | 28 | .row { 29 | composes: smallSize from '../../../styles/typography.css'; 30 | display: flex; 31 | flex-direction: row; 32 | justify-content: space-between; 33 | line-height: 20px; 34 | } 35 | 36 | .label { 37 | flex-grow: 1; 38 | } 39 | 40 | .value { 41 | margin-left: 20px; 42 | } 43 | 44 | .units { 45 | min-width: 0.7em; 46 | margin-left: 10px; 47 | } 48 | 49 | .title { 50 | composes: smallSize from '../../../styles/typography.css'; 51 | text-align: right; 52 | } 53 | 54 | .bg { 55 | composes: row; 56 | font-weight: bold; 57 | } 58 | 59 | .subType { 60 | composes: row; 61 | color: var(--gray-dark); 62 | } 63 | 64 | .annotation { 65 | composes: subType; 66 | } 67 | 68 | .divider { 69 | height: 3px; 70 | margin: 5px -10px; 71 | } 72 | -------------------------------------------------------------------------------- /src/components/daily/foodtooltip/FoodTooltip.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | @import '../../../styles/colors.css'; 18 | 19 | .container { 20 | opacity: 1; 21 | display: flex; 22 | flex-direction: column; 23 | min-width: 80px; 24 | margin: 2px 0; 25 | max-width: 180px; 26 | } 27 | 28 | .row { 29 | composes: smallSize from '../../../styles/typography.css'; 30 | display: flex; 31 | flex-direction: row; 32 | justify-content: space-between; 33 | line-height: 20px; 34 | } 35 | 36 | .label { 37 | flex-grow: 1; 38 | } 39 | 40 | .value { 41 | margin-left: 20px; 42 | } 43 | 44 | .units { 45 | min-width: 0.7em; 46 | margin-left: 10px; 47 | } 48 | 49 | .title { 50 | composes: smallSize from '../../../styles/typography.css'; 51 | text-align: right; 52 | } 53 | 54 | .carb { 55 | composes: row; 56 | font-weight: bold; 57 | } 58 | 59 | .divider { 60 | background-color: var(--bolus); 61 | height: 3px; 62 | margin: 5px -10px; 63 | } 64 | -------------------------------------------------------------------------------- /src/components/daily/pumpsettingsoverridetooltip/PumpSettingsOverrideTooltip.css: -------------------------------------------------------------------------------- 1 | @import '../../../styles/colors.css'; 2 | 3 | .container { 4 | opacity: 1; 5 | display: flex; 6 | flex-direction: column; 7 | min-width: 80px; 8 | margin: 2px 0; 9 | max-width: 250px; 10 | } 11 | 12 | .row { 13 | composes: smallSize from '../../../styles/typography.css'; 14 | display: flex; 15 | flex-direction: row; 16 | justify-content: space-between; 17 | line-height: 20px; 18 | } 19 | 20 | .label { 21 | flex-grow: 1; 22 | } 23 | 24 | .boldLabel { 25 | composes: label; 26 | font-weight: bold; 27 | } 28 | 29 | .value { 30 | margin-left: 20px; 31 | } 32 | 33 | .title { 34 | composes: smallSize from '../../../styles/typography.css'; 35 | text-align: center; 36 | } 37 | 38 | .target { 39 | composes: row; 40 | } 41 | 42 | .overrideType { 43 | composes: row; 44 | font-weight: normal; 45 | } 46 | 47 | .overrideType div:last-child { 48 | font-weight: bold; 49 | } 50 | -------------------------------------------------------------------------------- /src/components/daily/smbgtooltip/SMBGTooltip.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | @import '../../../styles/colors.css'; 18 | 19 | .container { 20 | opacity: 1; 21 | display: flex; 22 | flex-direction: column; 23 | min-width: 80px; 24 | margin: 2px 0; 25 | max-width: 180px; 26 | } 27 | 28 | .row { 29 | composes: smallSize from '../../../styles/typography.css'; 30 | display: flex; 31 | flex-direction: row; 32 | justify-content: space-between; 33 | line-height: 20px; 34 | } 35 | 36 | .label { 37 | flex-grow: 1; 38 | } 39 | 40 | .value { 41 | margin-left: 20px; 42 | } 43 | 44 | .units { 45 | min-width: 0.7em; 46 | margin-left: 10px; 47 | } 48 | 49 | .title { 50 | composes: smallSize from '../../../styles/typography.css'; 51 | text-align: right; 52 | } 53 | 54 | .bg { 55 | composes: row; 56 | font-weight: bold; 57 | } 58 | 59 | .subType { 60 | composes: row; 61 | color: var(--gray-dark); 62 | } 63 | 64 | .confirmBg { 65 | composes: subType; 66 | } 67 | 68 | .source { 69 | composes: subType; 70 | } 71 | 72 | .annotation { 73 | composes: subType; 74 | } 75 | 76 | .divider { 77 | height: 3px; 78 | margin: 5px -10px; 79 | } 80 | -------------------------------------------------------------------------------- /src/components/settings/README.md: -------------------------------------------------------------------------------- 1 | ## Device settings (i.e., insulin pump settings) utilities 2 | 3 | This directory contains the components required to visualize and also copy device settings 4 | 5 | ### Copy text 6 | 7 | *Aim:* 8 | To enable the easy copy and pasting of the settings while also allowing the user to modify the table that has been copied. To do this we need to remove all styles and have a very simple text representation of the table while still keeping its basic format. 9 | 10 | *In the component:* 11 | We are using `ClipboardButton` and then have built a text representation of the settings that essentially uses a command-line tool `text-table`. This is then embedded in a `
    ..
    ` tag as we want to ensure no styles are copied. All of the work is done in `utils/settings/textData.js` to build the table. 12 | -------------------------------------------------------------------------------- /src/components/settings/common/CollapsibleContainer.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .secondaryLabel { 19 | composes: secondaryText from '../settings.css'; 20 | } 21 | 22 | :global(.containerCollapse) { 23 | transition: height 250ms; 24 | } 25 | -------------------------------------------------------------------------------- /src/components/settings/common/CollapsibleContainer.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | import { Collapse } from 'react-collapse'; 5 | 6 | import SingleLineCollapsibleContainerLabel from './SingleLineCollapsibleContainerLabel'; 7 | import TwoLineCollapsibleContainerLabel from './TwoLineCollapsibleContainerLabel'; 8 | 9 | import styles from './CollapsibleContainer.css'; 10 | 11 | const CollapsibleContainer = (props) => { 12 | const { label, labelClass, opened, toggleExpansion } = props; 13 | let renderedLabel = ( 14 | 20 | ); 21 | const { twoLineLabel, label: { secondary } } = props; 22 | if (twoLineLabel && !_.isEmpty(secondary)) { 23 | renderedLabel = ( 24 | 30 | ); 31 | } 32 | 33 | return ( 34 |
    35 | {renderedLabel} 36 | 41 |
    {props.children}
    42 |
    43 |
    44 | ); 45 | }; 46 | 47 | CollapsibleContainer.defaultProps = { 48 | twoLineLabel: true, 49 | }; 50 | 51 | CollapsibleContainer.propTypes = { 52 | children: PropTypes.element.isRequired, 53 | label: PropTypes.shape({ 54 | main: PropTypes.string.isRequired, 55 | secondary: PropTypes.string.isRequired, 56 | units: PropTypes.string.isRequired, 57 | }).isRequired, 58 | labelClass: PropTypes.string.isRequired, 59 | opened: PropTypes.bool.isRequired, 60 | toggleExpansion: PropTypes.func.isRequired, 61 | twoLineLabel: PropTypes.bool, 62 | }; 63 | 64 | export default CollapsibleContainer; 65 | -------------------------------------------------------------------------------- /src/components/settings/common/Header.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .header { 19 | position: relative; 20 | display: table; 21 | padding-left: 0px; 22 | margin-bottom: 5px; 23 | } 24 | .headerOuter:nth-last-of-type(1) .headerInner{ 25 | transition-property: width; 26 | transition-duration: .25s; 27 | overflow: hidden; 28 | } 29 | .headerClosed .headerOuter:nth-last-of-type(1) .headerInner { 30 | width: 0px; 31 | } 32 | .headerExpanded .headerOuter:nth-last-of-type(1) .headerInner { 33 | width: 100%; 34 | } 35 | .headerOuter { 36 | composes: header; 37 | display: inline-block; 38 | font-weight: 300; 39 | overflow: hidden; 40 | } 41 | .headerInner { 42 | composes: header; 43 | display: block; 44 | margin: 5px 5px 5px 0; 45 | white-space: nowrap; 46 | } 47 | .headerOuter:nth-last-of-type(2) { 48 | padding-right: 10px; 49 | } 50 | .headerClosed .headerOuter:nth-last-of-type(2)::after { 51 | content: '›'; 52 | font-size: 15px; 53 | font-weight: bold; 54 | position: absolute; 55 | right: 5px; 56 | top: 45%; 57 | transform: translateY(-50%); 58 | } 59 | .headerExpanded .headerOuter:nth-last-of-type(2)::after { 60 | content: '›'; 61 | font-size: 15px; 62 | font-weight: bold; 63 | position: absolute; 64 | right: 5px; 65 | top: 55%; 66 | transform: rotate(180deg) translateY(50%); 67 | } 68 | 69 | @media print { 70 | 71 | .headerOuter { 72 | composes: lightText largeSize from '../../../styles/typography.css'; 73 | color: var(--text-black); 74 | } 75 | 76 | .headerOuter:first-of-type { 77 | color: var(--text-black); 78 | font-weight: normal; 79 | font-size: 16px; 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/components/settings/common/Header.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import PropTypes from 'prop-types'; 19 | import React, { PureComponent } from 'react'; 20 | 21 | import styles from './Header.css'; 22 | 23 | import i18next from 'i18next'; 24 | const t = i18next.t.bind(i18next); 25 | 26 | class Header extends PureComponent { 27 | render() { 28 | return ( 29 |
    30 |
      31 |
    • 32 | 33 | {t('Active at Upload on')} {this.props.deviceMeta.uploaded} 34 | 35 |
    • 36 |
    37 |
    38 | ); 39 | } 40 | } 41 | 42 | Header.propTypes = { 43 | deviceMeta: PropTypes.object.isRequired, 44 | }; 45 | 46 | export default Header; 47 | -------------------------------------------------------------------------------- /src/components/settings/common/SingleLineCollapsibleContainerLabel.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .collapsibleLabel { 19 | composes: settingsHeader from '../settings.css'; 20 | } 21 | 22 | .labelContainer { 23 | composes: defaultSize mediumContrastText from '../../../styles/typography.css'; 24 | composes: norgie from './norgie.css'; 25 | cursor: pointer; 26 | display: flex; 27 | align-items: baseline; 28 | } 29 | 30 | .labelContainer:hover { 31 | color: var(--text-hover); 32 | } 33 | 34 | .mainText { 35 | composes: boldText from '../../../styles/typography.css'; 36 | } 37 | 38 | .secondaryText { 39 | composes: secondaryText from '../settings.css'; 40 | } 41 | 42 | @media print { 43 | 44 | .labelContainer { 45 | align-items: flex-end; 46 | } 47 | 48 | .mainText { 49 | composes: mainHeaderText from '../settings.css'; 50 | } 51 | 52 | .secondaryText { 53 | composes: secondaryText from '../settings.css'; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/components/settings/common/SingleLineCollapsibleContainerLabel.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import cx from 'classnames'; 3 | import PropTypes from 'prop-types'; 4 | import React from 'react'; 5 | 6 | import norgie from './norgie.css'; 7 | import styles from './SingleLineCollapsibleContainerLabel.css'; 8 | 9 | const SingleLineCollapsibleContainerLabel = (props) => { 10 | const { className, isOpened, label: { main, secondary, units }, onClick } = props; 11 | const containerClasses = cx({ 12 | label: true, // for testing 13 | [styles.collapsibleLabel]: !Boolean(className), 14 | [styles.labelContainer]: true, 15 | [className]: Boolean(className), 16 | [norgie.opened]: isOpened, 17 | }); 18 | return ( 19 |
    20 |
    21 | {main} 22 | {_.isEmpty(secondary) ? 23 | null : ({secondary})} 24 | {_.isEmpty(units) ? 25 | null : ({units})} 26 |
    27 |
    28 | ); 29 | }; 30 | 31 | SingleLineCollapsibleContainerLabel.propTypes = { 32 | className: PropTypes.string, 33 | isOpened: PropTypes.bool.isRequired, 34 | label: PropTypes.shape({ 35 | main: PropTypes.string.isRequired, 36 | secondary: PropTypes.string.isRequired, 37 | units: PropTypes.string, 38 | }).isRequired, 39 | onClick: PropTypes.func.isRequired, 40 | }; 41 | 42 | export default SingleLineCollapsibleContainerLabel; 43 | -------------------------------------------------------------------------------- /src/components/settings/common/Table.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .secondaryLabelAlone { 19 | composes: secondaryLeftPadding from '../settings.css'; 20 | font-weight: normal; 21 | } 22 | 23 | .secondaryLabelWithMain { 24 | composes: lightText from '../../../styles/typography.css'; 25 | composes: secondaryLeftPadding from '../settings.css'; 26 | } 27 | 28 | .tooltipIcon { 29 | position: relative; 30 | margin-right: .75em; 31 | float: right; 32 | } 33 | 34 | .tooltipIcon > img { 35 | width: 14px; 36 | } 37 | 38 | .rowTooltipIcon { 39 | composes: tooltipIcon; 40 | margin-right: 0; 41 | margin-left: .75em; 42 | float: none; 43 | } 44 | 45 | .rowTooltipIcon > img { 46 | width: 14px; 47 | } 48 | 49 | .TableTooltipWrapper { 50 | z-index: 1; 51 | position: relative; 52 | } 53 | 54 | @media print { 55 | 56 | .secondaryLabelWithMain { 57 | composes: lightText largeSize from '../../../styles/typography.css'; 58 | color: var(--text-black); 59 | composes: secondaryLeftPadding from '../settings.css'; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/components/settings/common/TwoLineCollapsibleContainerLabel.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .collapsibleLabel { 19 | composes: settingsHeaderDecoration settingsHeaderLayout settingsHeaderText from '../settings.css'; 20 | } 21 | 22 | .labelContainer { 23 | composes: defaultSize mediumContrastText from '../../../styles/typography.css'; 24 | cursor: pointer; 25 | box-sizing: border-box; 26 | display: flex; 27 | flex-direction: column; 28 | justify-content: space-between; 29 | height: 66px; 30 | min-width: 240px; 31 | padding-top: 10px; 32 | padding-bottom: 10px; 33 | } 34 | 35 | .labelContainer:hover { 36 | color: var(--text-hover); 37 | } 38 | 39 | .norgieLabelContainer { 40 | composes: norgie from './norgie.css'; 41 | display: flex; 42 | justify-content: space-between; 43 | align-items: baseline; 44 | } 45 | 46 | .mainText { 47 | composes: boldText from '../../../styles/typography.css'; 48 | } 49 | 50 | .secondaryText { 51 | composes: secondaryText from '../settings.css'; 52 | } 53 | 54 | .secondaryLabel { 55 | composes: lightText from '../../../styles/typography.css'; 56 | } 57 | 58 | @media print { 59 | 60 | .labelContainer { 61 | composes: defaultSize mediumContrastText from '../../../styles/typography.css'; 62 | cursor: pointer; 63 | box-sizing: border-box; 64 | display: flex; 65 | flex-direction: row-reverse; 66 | text-overflow: ellipsis; 67 | max-width: 280px; 68 | min-width: 200px; 69 | padding-top: 10px; 70 | padding-bottom: 10px; 71 | height: auto; 72 | } 73 | 74 | .mainText{ 75 | composes: mainHeaderText from '../settings.css'; 76 | } 77 | 78 | .secondaryText, 79 | .secondaryLabel { 80 | composes: secondaryText from '../settings.css'; 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /src/components/settings/common/TwoLineCollapsibleContainerLabel.js: -------------------------------------------------------------------------------- 1 | import cx from 'classnames'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | import norgie from './norgie.css'; 6 | import styles from './TwoLineCollapsibleContainerLabel.css'; 7 | 8 | const TwoLineCollapsibleContainerLabel = (props) => { 9 | const { className, isOpened, label: { main, secondary, units }, onClick } = props; 10 | const containerClasses = cx({ 11 | label: true, // for testing 12 | [styles.collapsibleLabel]: !Boolean(className), 13 | [styles.labelContainer]: true, 14 | [className]: Boolean(className), 15 | }); 16 | const norgieContainerClasses = cx({ 17 | [styles.norgieLabelContainer]: true, 18 | [norgie.opened]: isOpened, 19 | }); 20 | return ( 21 |
    22 |
    {secondary}
    23 |
    24 |
    25 | {main} 26 | {units} 27 |
    28 |
    29 |
    30 | ); 31 | }; 32 | 33 | TwoLineCollapsibleContainerLabel.propTypes = { 34 | className: PropTypes.string, 35 | isOpened: PropTypes.bool.isRequired, 36 | label: PropTypes.shape({ 37 | main: PropTypes.string.isRequired, 38 | secondary: PropTypes.string.isRequired, 39 | units: PropTypes.string.isRequired, 40 | }), 41 | onClick: PropTypes.func.isRequired, 42 | }; 43 | 44 | export default TwoLineCollapsibleContainerLabel; 45 | -------------------------------------------------------------------------------- /src/components/settings/common/norgie.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .norgie { 19 | 20 | } 21 | 22 | .norgie::after { 23 | content: '›'; 24 | font-size: 15px; 25 | font-weight: bold; 26 | padding-left: 8px; 27 | margin-right: 16px; 28 | transform: rotate(0deg); 29 | 30 | transition-duration: 0.25s; 31 | transition-property: rotate, transform; 32 | } 33 | 34 | .opened::after { 35 | transform: rotate(90deg) translate(-20%, -15%); 36 | } 37 | 38 | @media print { 39 | .norgie::after { 40 | content: ''; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/components/trends/cbg/CBGDateTraceAnimated.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .border { 19 | stroke: white; 20 | stroke-width: 0.5px; 21 | } 22 | 23 | .veryLow { 24 | composes: border; 25 | composes: bgVeryLow from '../../../styles/diabetes.css'; 26 | } 27 | 28 | .low { 29 | composes: border; 30 | composes: bgLow from '../../../styles/diabetes.css'; 31 | } 32 | 33 | .target { 34 | composes: border; 35 | composes: bgTarget from '../../../styles/diabetes.css'; 36 | } 37 | 38 | .high { 39 | composes: border; 40 | composes: bgHigh from '../../../styles/diabetes.css'; 41 | } 42 | 43 | .veryHigh { 44 | composes: border; 45 | composes: bgVeryHigh from '../../../styles/diabetes.css'; 46 | } 47 | -------------------------------------------------------------------------------- /src/components/trends/cbg/CBGDateTraceLabel.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .container { 19 | composes: absolute smallHorizontalPadding from '../../../styles/layout.css'; 20 | top: 0px; 21 | z-index: 1; 22 | } 23 | 24 | .dateLabel { 25 | composes: highContrastText noWrap defaultSize from '../../../styles/typography.css'; 26 | } 27 | -------------------------------------------------------------------------------- /src/components/trends/cbg/CBGDateTraceLabel.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import PropTypes from 'prop-types'; 19 | import React from 'react'; 20 | 21 | import Tooltip from '../../common/tooltips/Tooltip'; 22 | 23 | import { utcFormat } from 'd3-time-format'; 24 | 25 | import styles from './CBGDateTraceLabel.css'; 26 | 27 | const CBGDateTraceLabel = (props) => { 28 | if (!props.focusedDateTrace) { 29 | return null; 30 | } 31 | const { focusedDateTrace: { data: { localDate: date }, position } } = props; 32 | const formattedDate = utcFormat('%A, %B %-d')(Date.parse(date)); 33 | return ( 34 |
    35 | {formattedDate}} 37 | borderWidth={0} 38 | position={{ left: position.left, top: 2.25 * position.yPositions.topMargin }} 39 | side={'bottom'} 40 | tail={false} 41 | /> 42 |
    43 | ); 44 | }; 45 | 46 | CBGDateTraceLabel.propTypes = { 47 | focusedDateTrace: PropTypes.shape({ 48 | data: PropTypes.shape({ 49 | localDate: PropTypes.string.isRequired, 50 | }), 51 | position: PropTypes.shape({ 52 | left: PropTypes.number.isRequired, 53 | yPositions: PropTypes.shape({ 54 | top: PropTypes.number.isRequired, 55 | topMargin: PropTypes.number.isRequired, 56 | }), 57 | }), 58 | }), 59 | }; 60 | 61 | export default CBGDateTraceLabel; 62 | -------------------------------------------------------------------------------- /src/components/trends/cbg/CBGDateTracesAnimationContainer.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | import TransitionGroupPlus from 'react-transition-group-plus'; 5 | 6 | import CBGDateTraceAnimated from './CBGDateTraceAnimated'; 7 | 8 | const CBGDateTracesAnimationContainer = (props) => { 9 | const { bgBounds, bgUnits, data, dates, topMargin, xScale, yScale } = props; 10 | return ( 11 | 12 | {_.map(dates, (localDate) => ( 13 | 26 | ))} 27 | 28 | ); 29 | }; 30 | 31 | CBGDateTracesAnimationContainer.propTypes = { 32 | bgBounds: PropTypes.shape({ 33 | veryHighThreshold: PropTypes.number.isRequired, 34 | targetUpperBound: PropTypes.number.isRequired, 35 | targetLowerBound: PropTypes.number.isRequired, 36 | veryLowThreshold: PropTypes.number.isRequired, 37 | }).isRequired, 38 | data: PropTypes.object, 39 | dates: PropTypes.arrayOf(PropTypes.string), 40 | focusCbgDateTrace: PropTypes.func.isRequired, 41 | unfocusCbgDateTrace: PropTypes.func.isRequired, 42 | onSelectDate: PropTypes.func.isRequired, 43 | topMargin: PropTypes.number.isRequired, 44 | xScale: PropTypes.func.isRequired, 45 | yScale: PropTypes.func.isRequired, 46 | }; 47 | 48 | export default CBGDateTracesAnimationContainer; 49 | -------------------------------------------------------------------------------- /src/components/trends/cbg/FocusedCBGSliceSegment.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | :export { 19 | stroke: 2; 20 | } 21 | 22 | .segment { 23 | stroke: black; 24 | stroke-width: 2; 25 | pointer-events: none; 26 | fill: transparent; 27 | } -------------------------------------------------------------------------------- /src/components/trends/cbg/RangeSelect.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .container { 19 | display: flex; 20 | flex-direction: row; 21 | composes: mediumContrastText defaultSize from '../../../styles/typography.css'; 22 | padding-top: 15px; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/trends/common/Background.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .background { 19 | stroke: var(--bkgrnd-lines); 20 | stroke-width: 1px; 21 | fill: var(--bkgrnd); 22 | } 23 | 24 | .threeHrLine { 25 | stroke: var(--bkgrnd-lines); 26 | stroke-width: 1px; 27 | } -------------------------------------------------------------------------------- /src/components/trends/common/Background.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { range } from 'd3-array'; 3 | import PropTypes from 'prop-types'; 4 | import React from 'react'; 5 | 6 | import * as datetime from '../../../utils/datetime'; 7 | 8 | import styles from './Background.css'; 9 | 10 | const Background = (props) => { 11 | const { data, margins, svgDimensions, xScale } = props; 12 | 13 | const width = svgDimensions.width - margins.left - margins.right; 14 | const height = svgDimensions.height - margins.top - margins.bottom; 15 | 16 | const lines = props.linesAtThreeHrs ? _.map(data, (val, i) => ( 17 | 25 | )) : null; 26 | 27 | return ( 28 | 29 | 36 | {lines} 37 | 38 | ); 39 | }; 40 | 41 | Background.defaultProps = { 42 | data: _.map(range(1, 8), (i) => (i * datetime.THREE_HRS)), 43 | linesAtThreeHrs: false, 44 | }; 45 | 46 | Background.propTypes = { 47 | data: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired, 48 | linesAtThreeHrs: PropTypes.bool.isRequired, 49 | margins: PropTypes.shape({ 50 | top: PropTypes.number.isRequired, 51 | right: PropTypes.number.isRequired, 52 | bottom: PropTypes.number.isRequired, 53 | left: PropTypes.number.isRequired, 54 | }).isRequired, 55 | svgDimensions: PropTypes.shape({ 56 | width: PropTypes.number.isRequired, 57 | height: PropTypes.number.isRequired, 58 | }).isRequired, 59 | xScale: PropTypes.func.isRequired, 60 | }; 61 | 62 | export default Background; 63 | -------------------------------------------------------------------------------- /src/components/trends/common/FocusedRangeLabels.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .container { 19 | composes: absolute smallHorizontalPadding from '../../../styles/layout.css'; 20 | top: 0px; 21 | z-index: 1; 22 | } 23 | 24 | .number { 25 | composes: boldText highContrastText noWrap largeSize from '../../../styles/typography.css'; 26 | } 27 | 28 | .explainerText { 29 | composes: highContrastText noWrap from '../../../styles/typography.css'; 30 | display: block; 31 | } 32 | 33 | .timeLabel { 34 | composes: highContrastText noWrap defaultSize from '../../../styles/typography.css'; 35 | } 36 | -------------------------------------------------------------------------------- /src/components/trends/common/NoData.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .noDataMsg { 19 | composes: mediumContrastText svgMiddleAnchored from '../../../styles/typography.css'; 20 | } -------------------------------------------------------------------------------- /src/components/trends/common/TargetRangeLines.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .targetRangeLine { 19 | pointer-events: none; 20 | 21 | stroke: white; 22 | stroke-dasharray: 9,9; 23 | stroke-width: 2px; 24 | } -------------------------------------------------------------------------------- /src/components/trends/common/TargetRangeLines.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import PropTypes from 'prop-types'; 19 | import React from 'react'; 20 | 21 | import styles from './TargetRangeLines.css'; 22 | 23 | const TargetRangeLines = (props) => { 24 | const { bgBounds, smbgOpts, xScale, yScale } = props; 25 | const x1 = xScale.range()[0] - smbgOpts.maxR; 26 | const x2 = xScale.range()[1] + smbgOpts.maxR; 27 | return ( 28 | 29 | 37 | 45 | 46 | ); 47 | }; 48 | 49 | TargetRangeLines.propTypes = { 50 | bgBounds: PropTypes.shape({ 51 | veryHighThreshold: PropTypes.number.isRequired, 52 | targetUpperBound: PropTypes.number.isRequired, 53 | targetLowerBound: PropTypes.number.isRequired, 54 | veryLowThreshold: PropTypes.number.isRequired, 55 | }), 56 | smbgOpts: PropTypes.shape({ 57 | maxR: PropTypes.number.isRequired, 58 | r: PropTypes.number.isRequired, 59 | }).isRequired, 60 | xScale: PropTypes.func.isRequired, 61 | yScale: PropTypes.func.isRequired, 62 | }; 63 | 64 | TargetRangeLines.displayName = 'TargetRangeLines'; 65 | 66 | export default TargetRangeLines; 67 | -------------------------------------------------------------------------------- /src/components/trends/common/XAxisLabels.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .text { 19 | composes: axisSize mediumContrastText svgStartAnchored from '../../../styles/typography.css'; 20 | } 21 | 22 | .focusedRange { 23 | composes: axisSize boldText mediumContrastText svgStartAnchored from '../../../styles/typography.css'; 24 | } -------------------------------------------------------------------------------- /src/components/trends/common/XAxisLabels.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { range } from 'd3-array'; 3 | import PropTypes from 'prop-types'; 4 | import React from 'react'; 5 | 6 | import { formatClocktimeFromMsPer24, THREE_HRS } from '../../../utils/datetime'; 7 | 8 | import styles from './XAxisLabels.css'; 9 | 10 | const XAxisLabels = (props) => { 11 | const { data, margins, xOffset, xScale, yOffset } = props; 12 | const yPos = margins.top - yOffset; 13 | 14 | return ( 15 | 16 | {_.map(data, (msInDay) => { 17 | const displayTime = formatClocktimeFromMsPer24(msInDay, 'h a'); 18 | return ( 19 | 25 | {displayTime} 26 | 27 | ); 28 | })} 29 | 30 | ); 31 | }; 32 | 33 | XAxisLabels.defaultProps = { 34 | data: _.map(range(0, 8), (i) => (i * THREE_HRS)), 35 | xOffset: 5, 36 | yOffset: 5, 37 | }; 38 | 39 | XAxisLabels.propTypes = { 40 | data: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired, 41 | margins: PropTypes.shape({ 42 | top: PropTypes.number.isRequired, 43 | right: PropTypes.number.isRequired, 44 | bottom: PropTypes.number.isRequired, 45 | left: PropTypes.number.isRequired, 46 | }).isRequired, 47 | xOffset: PropTypes.number.isRequired, 48 | xScale: PropTypes.func.isRequired, 49 | yOffset: PropTypes.number.isRequired, 50 | }; 51 | 52 | export default XAxisLabels; 53 | -------------------------------------------------------------------------------- /src/components/trends/common/XAxisTicks.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .tick { 19 | stroke: var(--axis-tick); 20 | } -------------------------------------------------------------------------------- /src/components/trends/common/XAxisTicks.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import { range } from 'd3-array'; 3 | import PropTypes from 'prop-types'; 4 | import React from 'react'; 5 | 6 | import * as datetime from '../../../utils/datetime'; 7 | 8 | import styles from './XAxisTicks.css'; 9 | 10 | const XAxisTicks = (props) => { 11 | const { data, margins, tickLength, xScale } = props; 12 | return ( 13 | 14 | {_.map(data, (msInDay) => ( 15 | 23 | ))} 24 | 25 | ); 26 | }; 27 | 28 | XAxisTicks.defaultProps = { 29 | data: _.map(range(0, 9), (i) => (i * datetime.THREE_HRS)), 30 | tickLength: 15, 31 | }; 32 | 33 | XAxisTicks.propTypes = { 34 | data: PropTypes.arrayOf(PropTypes.number.isRequired).isRequired, 35 | margins: PropTypes.shape({ 36 | top: PropTypes.number.isRequired, 37 | right: PropTypes.number.isRequired, 38 | bottom: PropTypes.number.isRequired, 39 | left: PropTypes.number.isRequired, 40 | }).isRequired, 41 | tickLength: PropTypes.number.isRequired, 42 | xScale: PropTypes.func.isRequired, 43 | }; 44 | 45 | export default XAxisTicks; 46 | -------------------------------------------------------------------------------- /src/components/trends/common/YAxisLabelsAndTicks.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .text { 19 | composes: axisSize mediumContrastText svgRightAnchored svgVerticalCentered from '../../../styles/typography.css'; 20 | } 21 | 22 | .tick { 23 | stroke: var(--axis-tick); 24 | } -------------------------------------------------------------------------------- /src/components/trends/common/YAxisLabelsAndTicks.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import PropTypes from 'prop-types'; 3 | import React from 'react'; 4 | 5 | import { MGDL_UNITS, MMOLL_UNITS } from '../../../utils/constants'; 6 | import { formatBgValue } from '../../../utils/format'; 7 | 8 | import styles from './YAxisLabelsAndTicks.css'; 9 | 10 | const YAxisLabels = (props) => { 11 | const { bgPrefs, margins, textToTickGap, tickWidth, yScale } = props; 12 | const { bgBounds } = bgPrefs; 13 | 14 | return ( 15 | 16 | {_.map(['targetLowerBound', 'targetUpperBound', 'veryHighThreshold', 'veryLowThreshold'], 17 | (boundKey) => ( 18 | 19 | 24 | {formatBgValue(bgBounds[boundKey], bgPrefs)} 25 | 26 | 33 | 34 | ) 35 | )} 36 | 37 | ); 38 | }; 39 | 40 | YAxisLabels.defaultProps = { 41 | textToTickGap: 2, 42 | tickWidth: 8, 43 | }; 44 | 45 | YAxisLabels.propTypes = { 46 | bgPrefs: PropTypes.shape({ 47 | bgBounds: PropTypes.shape({ 48 | veryHighThreshold: PropTypes.number.isRequired, 49 | targetUpperBound: PropTypes.number.isRequired, 50 | targetLowerBound: PropTypes.number.isRequired, 51 | veryLowThreshold: PropTypes.number.isRequired, 52 | }), 53 | bgUnits: PropTypes.oneOf([MGDL_UNITS, MMOLL_UNITS]).isRequired, 54 | }), 55 | margins: PropTypes.shape({ 56 | top: PropTypes.number.isRequired, 57 | right: PropTypes.number.isRequired, 58 | bottom: PropTypes.number.isRequired, 59 | left: PropTypes.number.isRequired, 60 | }).isRequired, 61 | textToTickGap: PropTypes.number.isRequired, 62 | tickWidth: PropTypes.number.isRequired, 63 | yScale: PropTypes.func.isRequired, 64 | }; 65 | 66 | export default YAxisLabels; 67 | -------------------------------------------------------------------------------- /src/components/trends/common/withDefaultYPosition.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import PropTypes from 'prop-types'; 19 | import React from 'react'; 20 | 21 | const withDefaultYPosition = (WrappedComponent) => { 22 | const WithDefault = (props) => { 23 | const { bgBounds: { targetLowerBound, targetUpperBound }, yScale } = props; 24 | 25 | // default Y position is the center of the target range 26 | // i.e., 100 mg/dL if target range is 80-120 mg/dL 27 | const defaultY = yScale(targetUpperBound - (targetUpperBound - targetLowerBound) / 2); 28 | 29 | return ( 30 | 31 | ); 32 | }; 33 | 34 | WithDefault.propTypes = { 35 | bgBounds: PropTypes.shape({ 36 | targetLowerBound: PropTypes.number.isRequired, 37 | targetUpperBound: PropTypes.number.isRequired, 38 | }).isRequired, 39 | yScale: PropTypes.func.isRequired, 40 | }; 41 | 42 | return WithDefault; 43 | }; 44 | 45 | export default withDefaultYPosition; 46 | -------------------------------------------------------------------------------- /src/components/trends/smbg/FocusedSMBGPointLabel.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .container { 19 | composes: absolute smallHorizontalPadding from '../../../styles/layout.css'; 20 | top: 0px; 21 | z-index: 1; 22 | } 23 | 24 | .number { 25 | composes: boldText highContrastText noWrap largeSize from '../../../styles/typography.css'; 26 | } 27 | 28 | .explainerText { 29 | composes: smallSize noWrap from '../../../styles/typography.css'; 30 | display: block; 31 | } 32 | 33 | .detailNumber { 34 | composes: explainerText number; 35 | text-align: center; 36 | } 37 | 38 | .dateTime { 39 | composes: explainerText; 40 | } 41 | 42 | .subType { 43 | composes: explainerText; 44 | font-style: italic; 45 | } 46 | 47 | .tipWrapper { 48 | text-align: right; 49 | } 50 | -------------------------------------------------------------------------------- /src/components/trends/smbg/SMBGDateLineAnimated.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .smbgPath { 19 | fill: none; 20 | stroke: var(--trends--dark); 21 | stroke-dasharray: 4, 4; 22 | } 23 | 24 | .highlightPath { 25 | stroke-width: 2px; 26 | stroke-dasharray: 4, 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/components/trends/smbg/SMBGDatePointsAnimated.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .veryLow { 19 | composes: bgVeryLow from '../../../styles/diabetes.css'; 20 | } 21 | 22 | .low { 23 | composes: bgLow from '../../../styles/diabetes.css'; 24 | } 25 | 26 | .target { 27 | composes: bgTarget from '../../../styles/diabetes.css'; 28 | } 29 | 30 | .high { 31 | composes: bgHigh from '../../../styles/diabetes.css'; 32 | } 33 | 34 | .veryHigh { 35 | composes: bgVeryHigh from '../../../styles/diabetes.css'; 36 | } 37 | -------------------------------------------------------------------------------- /src/components/trends/smbg/SMBGRangeAnimated.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | @keyframes fadein { 19 | from { 20 | fill-opacity: 0.3; 21 | } 22 | to { 23 | fill-opacity: 0.4; 24 | } 25 | } 26 | 27 | @keyframes fadeout { 28 | from { 29 | fill-opacity: 0.4; 30 | } 31 | to { 32 | fill-opacity: 0.3; 33 | } 34 | } 35 | 36 | .smbgRange { 37 | fill: var(--trends--light); 38 | stroke: none; 39 | } 40 | 41 | .fadeIn { 42 | animation: fadein 0.25s forwards ease-in-out; 43 | } 44 | 45 | .fadeOut { 46 | animation: fadeout 0.25s forwards ease-in-out; 47 | } 48 | -------------------------------------------------------------------------------- /src/modules/data/index.js: -------------------------------------------------------------------------------- 1 | import DataUtil from '../../utils/DataUtil'; 2 | 3 | export { 4 | DataUtil, 5 | }; 6 | -------------------------------------------------------------------------------- /src/modules/print/pdfkitHelpers.js: -------------------------------------------------------------------------------- 1 | /* global self */ 2 | 3 | export const waitForData = async doc => new Promise((resolve, reject) => { 4 | const buffers = []; 5 | doc.on('data', buffers.push.bind(buffers)); 6 | doc.on('end', async () => { 7 | const pdfBuffer = Buffer.concat(buffers); 8 | const pdfBase64 = pdfBuffer.toString('base64'); 9 | resolve(pdfBase64); 10 | }); 11 | doc.on('error', reject); 12 | }); 13 | 14 | export const base64ToArrayBuffer = base64Str => { 15 | const binaryString = self.atob(base64Str); 16 | const binaryLen = binaryString.length; 17 | const bytes = new Uint8Array(binaryLen); 18 | 19 | for (let i = 0; i < binaryLen; i++) { 20 | const ascii = binaryString.charCodeAt(i); 21 | bytes[i] = ascii; 22 | } 23 | 24 | return bytes; 25 | }; 26 | -------------------------------------------------------------------------------- /src/modules/print/registerStaticFiles.js: -------------------------------------------------------------------------------- 1 | // ref https://github.com/foliojs/pdfkit/blob/65670353f9a3f4ceea2ac0f37cd92f476bfd11ae/examples/webpack/src/registerStaticFiles.js 2 | 3 | // the fs here is not node fs but the provided virtual one 4 | import fs from 'fs'; 5 | import forEach from 'lodash/forEach'; 6 | // the content file is returned as is (webpack is configured to load *.afm files as asset/source) 7 | 8 | function registerBinaryFiles(ctx) { 9 | forEach(ctx.keys(), key => { 10 | // extracts "./" from beginning of the key 11 | fs.writeFileSync(key.substring(2), ctx(key)); 12 | }); 13 | } 14 | 15 | function registerAFMFonts(ctx) { 16 | forEach(ctx.keys(), key => { 17 | const match = key.match(/([^/]*\.afm$)/); 18 | if (match) { 19 | // afm files must be stored on data path 20 | fs.writeFileSync(`data/${match[0]}`, ctx(key)); 21 | } 22 | }); 23 | } 24 | 25 | // register all files found in assets folder (relative to src) 26 | registerBinaryFiles(require.context('/static-assets', true)); 27 | 28 | // register AFM fonts distributed with pdfkit 29 | // is good practice to register only required fonts to avoid the bundle size increase too much 30 | registerAFMFonts(require.context('pdfkit/js/data', false, /Helvetica.*\.afm$/)); 31 | -------------------------------------------------------------------------------- /src/modules/print/utils/constants.js: -------------------------------------------------------------------------------- 1 | // DPI here is the coordinate system, not the resolution; sub-dot precision renders crisply! 2 | export const DPI = 72; 3 | export const MARGIN = DPI / 2; 4 | export const HEIGHT = 11 * DPI - (2 * MARGIN); 5 | export const WIDTH = 8.5 * DPI - (2 * MARGIN); 6 | export const MARGINS = { 7 | left: MARGIN, 8 | top: MARGIN, 9 | right: MARGIN, 10 | bottom: MARGIN, 11 | }; 12 | export const DEFAULT_FONT_SIZE = 10; 13 | export const LARGE_FONT_SIZE = 12; 14 | export const FOOTER_FONT_SIZE = 8; 15 | export const HEADER_FONT_SIZE = 14; 16 | export const SMALL_FONT_SIZE = 8; 17 | export const EXTRA_SMALL_FONT_SIZE = 6; 18 | -------------------------------------------------------------------------------- /src/propTypes/index.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { MGDL_UNITS, MMOLL_UNITS } from '../utils/constants'; 3 | 4 | export const bgPrefsPropType = PropTypes.shape({ 5 | bgBounds: PropTypes.shape({ 6 | veryHighThreshold: PropTypes.number.isRequired, 7 | targetUpperBound: PropTypes.number.isRequired, 8 | targetLowerBound: PropTypes.number.isRequired, 9 | veryLowThreshold: PropTypes.number.isRequired, 10 | }), 11 | bgUnits: PropTypes.oneOf([MGDL_UNITS, MMOLL_UNITS]), 12 | }); 13 | -------------------------------------------------------------------------------- /src/styles/layout.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .absolute { 19 | pointer-events: none; 20 | position: absolute; 21 | } 22 | 23 | .smallHorizontalPadding { 24 | padding: 0px 6px; 25 | } -------------------------------------------------------------------------------- /src/styles/typography.css: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | .whiteText { 19 | color: white; 20 | fill: white; 21 | } 22 | 23 | .boldText { 24 | font-weight: bold; 25 | } 26 | 27 | .lightText { 28 | font-weight: 300; 29 | } 30 | 31 | .smallSize { 32 | font-size: 12px; 33 | } 34 | 35 | .axisSize { 36 | font-size: 14px; 37 | } 38 | 39 | .defaultSize { 40 | font-size: 14px; 41 | } 42 | 43 | .largeSize { 44 | font-size: 16px; 45 | } 46 | 47 | .extraLargeSize { 48 | font-size: 24px; 49 | } 50 | 51 | .mediumContrastText { 52 | color: var(--text-medium-contrast); 53 | fill: var(--text-medium-contrast); 54 | } 55 | 56 | .highContrastText { 57 | color: var(--text-high-contrast); 58 | fill: var(--text-high-contrast); 59 | } 60 | 61 | .noWrap { 62 | white-space: nowrap; 63 | } 64 | 65 | .svgMiddleAnchored { 66 | text-anchor: middle; 67 | } 68 | 69 | .svgRightAnchored { 70 | text-anchor: end; 71 | } 72 | 73 | .svgStartAnchored { 74 | text-anchor: start; 75 | } 76 | 77 | .svgVerticalCentered { 78 | dominant-baseline: central; 79 | } 80 | -------------------------------------------------------------------------------- /src/utils/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "moment-utc" 4 | ], 5 | "rules": { 6 | "moment-utc/no-moment-without-utc": 2, 7 | "require-jsdoc": "error" 8 | } 9 | } -------------------------------------------------------------------------------- /src/utils/apidocs/README.md: -------------------------------------------------------------------------------- 1 | ## @tidepool/viz utilities API documentation 2 | 3 | This documentation is generated using [jsdoc2md](https://github.com/jsdoc2md/jsdoc-to-markdown 'jsdoc2md'). 4 | 5 | Contents: 6 | - [blood glucose utilities](./bloodglucose.md 'bloodglucose utilities') 7 | - [bolus utilities](./bolus.md 'bolus utilities') 8 | - [datetime utilities](./datetime.md 'datetime utilities') 9 | - [formatting utilities](./format.md 'format utilities') 10 | - [miscellaneous utilities](./misc.md 'misc utilities') 11 | -------------------------------------------------------------------------------- /src/utils/apidocs/basal.md: -------------------------------------------------------------------------------- 1 | 2 | > @tidepool/viz@0.8.1 apidocs /Users/jebeck/Tidepool/viz 3 | > jsdoc2md "src/utils/basal.js" 4 | 5 | ## Functions 6 | 7 |
    8 |
    getBasalSequences(basals)Array
    9 |

    getBasalSequences

    10 |
    11 |
    12 | 13 | 14 | 15 | ## getBasalSequences(basals) ⇒ Array 16 | getBasalSequences 17 | 18 | **Kind**: global function 19 | **Returns**: Array - Array of Arrays where each component Array is a sequence of basals 20 | of the same subType to be rendered as a unit 21 | 22 | | Param | Type | Description | 23 | | --- | --- | --- | 24 | | basals | Array | Array of preprocessed Tidepool basal objects | 25 | -------------------------------------------------------------------------------- /src/utils/apidocs/bloodglucose.md: -------------------------------------------------------------------------------- 1 | 2 | > @tidepool/viz@0.8.1 apidocs /Users/jebeck/Tidepool/viz 3 | > jsdoc2md "src/utils/bloodglucose.js" 4 | 5 | ## Functions 6 | 7 |
    8 |
    classifyBgValue(bgBounds, bgValue, classificationType)String
    9 |

    classifyBgValue

    10 |
    11 |
    convertToMmolL(bgVal)Number
    12 |

    convertToMmolL

    13 |
    14 |
    reshapeBgClassesToBgBounds(bgPrefs)Object
    15 |

    reshapeBgClassesToBgBounds

    16 |
    17 |
    18 | 19 | 20 | 21 | ## classifyBgValue(bgBounds, bgValue, classificationType) ⇒ String 22 | classifyBgValue 23 | 24 | **Kind**: global function 25 | **Returns**: String - bgClassification - low, target, high 26 | 27 | | Param | Type | Description | 28 | | --- | --- | --- | 29 | | bgBounds | Object | object describing boundaries for blood glucose categories | 30 | | bgValue | Number | integer or float blood glucose value in either mg/dL or mmol/L | 31 | | classificationType | String | 'threeWay' or 'fiveWay' | 32 | 33 | 34 | 35 | ## convertToMmolL(bgVal) ⇒ Number 36 | convertToMmolL 37 | 38 | **Kind**: global function 39 | **Returns**: Number - convertedBgVal - blood glucose value in mmol/L, unrounded 40 | 41 | | Param | Type | Description | 42 | | --- | --- | --- | 43 | | bgVal | Number | blood glucose value in mg/dL | 44 | 45 | 46 | 47 | ## reshapeBgClassesToBgBounds(bgPrefs) ⇒ Object 48 | reshapeBgClassesToBgBounds 49 | 50 | **Kind**: global function 51 | **Returns**: Object - bgBounds - @tidepool/viz-style bgBounds 52 | 53 | | Param | Type | Description | 54 | | --- | --- | --- | 55 | | bgPrefs | Object | bgPrefs object from blip containing tideline-style bgClasses | 56 | 57 | -------------------------------------------------------------------------------- /src/utils/apidocs/misc.md: -------------------------------------------------------------------------------- 1 | 2 | > @tidepool/viz@0.8.1 apidocs /Users/jebeck/Tidepool/viz 3 | > jsdoc2md "src/utils/misc.js" 4 | 5 | 6 | 7 | ## getPatientFullName(patient) ⇒ String 8 | getPatientFullName 9 | 10 | **Kind**: global function 11 | **Returns**: String - PwD's full name (first & last) 12 | 13 | | Param | Type | Description | 14 | | --- | --- | --- | 15 | | patient | Object | Tidepool patient object containing profile | 16 | 17 | -------------------------------------------------------------------------------- /src/utils/bgLog/data.js: -------------------------------------------------------------------------------- 1 | import _ from 'lodash'; 2 | import i18next from 'i18next'; 3 | 4 | import TextUtil from '../text/TextUtil'; 5 | import { statsText } from '../stat'; 6 | import { reshapeBgClassesToBgBounds } from '../bloodglucose'; 7 | import { formatBgValue } from '../format'; 8 | import { formatLocalizedFromUTC } from '../datetime'; 9 | 10 | const t = i18next.t.bind(i18next); 11 | 12 | // Exporting utils for easy stubbing in tests 13 | export const utils = { 14 | reshapeBgClassesToBgBounds, 15 | statsText, 16 | TextUtil, 17 | }; 18 | 19 | /** 20 | * trendsText 21 | * @param {Object} patient - the patient object that contains the profile 22 | * @param {Object} data - DataUtil data object 23 | * @param {Array} stats - Processed stats array 24 | * @param {Object} chartPrefs - trends chartPrefs object from blip 25 | * 26 | * @return {String} Trends data as a formatted string 27 | */ 28 | export function bgLogText(patient, data, stats) { 29 | const { 30 | bgPrefs, 31 | data: { 32 | current: { 33 | endpoints = {}, 34 | }, 35 | }, 36 | metaData, 37 | timePrefs, 38 | } = data; 39 | 40 | _.defaults(bgPrefs, { 41 | bgBounds: utils.reshapeBgClassesToBgBounds(bgPrefs), 42 | }); 43 | 44 | const textUtil = new utils.TextUtil(patient, endpoints.range, timePrefs); 45 | let bgLogString = textUtil.buildDocumentHeader('BG Log'); 46 | bgLogString += textUtil.buildDocumentDates(); 47 | bgLogString += utils.statsText(stats, textUtil, bgPrefs); 48 | bgLogString += textUtil.buildTextLine(); 49 | 50 | const smbgData = _.filter( 51 | data?.data?.combined || [], 52 | d => d.type === 'smbg' && d.normalTime >= endpoints.range[0] && d.normalTime < endpoints.range[1] 53 | ); 54 | 55 | bgLogString += _.map(smbgData.reverse(), d => ([ 56 | formatLocalizedFromUTC(d.normalTime, timePrefs, 'ddd, MMM D, YYYY h:mm A'), 57 | formatBgValue(d.value, bgPrefs), 58 | `(${_.capitalize(d.subType || 'meter')})`, 59 | ].join('\t'))).join('\n'); 60 | 61 | 62 | const devices = _.filter(metaData?.devices, ({ id }) => metaData?.matchedDevices?.[id]); 63 | 64 | if (devices.length) { 65 | const textLines = [ 66 | `\n\n${t('Devices Uploaded')}`, 67 | ..._.map(devices, ({ id, label }) => label || id), 68 | ]; 69 | 70 | _.each(textLines, line => { 71 | bgLogString += textUtil.buildTextLine(line); 72 | }); 73 | } 74 | 75 | return bgLogString; 76 | } 77 | -------------------------------------------------------------------------------- /src/utils/misc.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import _ from 'lodash'; 19 | 20 | /** 21 | * getPatientFullName 22 | * @param {Object} patient - Tidepool patient object containing profile 23 | * 24 | * @return {String} PwD's full name (first & last) 25 | */ 26 | export function getPatientFullName(patient) { 27 | const profile = _.get(patient, ['profile'], {}); 28 | const patientInfo = profile.patient || {}; 29 | 30 | if (patientInfo.isOtherPerson) { 31 | return patientInfo.fullName; 32 | } 33 | return profile.fullName; 34 | } 35 | -------------------------------------------------------------------------------- /static-assets/images/capturAGP-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/static-assets/images/capturAGP-logo.png -------------------------------------------------------------------------------- /static-assets/images/sitechange-cannula.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/static-assets/images/sitechange-cannula.png -------------------------------------------------------------------------------- /static-assets/images/sitechange-loop-tubing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/static-assets/images/sitechange-loop-tubing.png -------------------------------------------------------------------------------- /static-assets/images/sitechange-reservoir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/static-assets/images/sitechange-reservoir.png -------------------------------------------------------------------------------- /static-assets/images/sitechange-tubing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/static-assets/images/sitechange-tubing.png -------------------------------------------------------------------------------- /static-assets/images/sitechange-twiist-cassette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/static-assets/images/sitechange-twiist-cassette.png -------------------------------------------------------------------------------- /static-assets/images/tidepool-logo-408x46.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tidepool-org/viz/22af47c9516f0cd145df5bbb6be128fdd5105f63/static-assets/images/tidepool-logo-408x46.png -------------------------------------------------------------------------------- /stories/components/common/controls/InputGroup.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import _ from 'lodash'; 3 | import { storiesOf } from '@storybook/react'; 4 | 5 | import InputGroup from '../../../../src/components/common/controls/InputGroup'; 6 | 7 | const stories = storiesOf('InputGroup', module); 8 | 9 | const suffixOptions = [ 10 | { 11 | label: 'kg', 12 | value: 'kg', 13 | }, 14 | { 15 | label: 'lb', 16 | value: 'lb', 17 | }, 18 | ]; 19 | 20 | const suffix = { 21 | id: 'units', 22 | options: suffixOptions, 23 | value: suffixOptions[0], 24 | }; 25 | 26 | const Wrapper = ({ children }) => ( 27 |
    35 | {children} 36 |
    37 | ); 38 | 39 | class InteractiveContainer extends React.PureComponent { 40 | constructor(props) { 41 | super(props); 42 | this.state = { 43 | value: props.value, 44 | suffix: props.suffix, 45 | }; 46 | } 47 | 48 | handleInputChange = event => { 49 | event.persist(); 50 | this.setState(() => ({ 51 | value: event.target.value, 52 | })); 53 | }; 54 | 55 | handleSuffixChange = value => { 56 | this.setState((state) => ({ 57 | suffix: _.assign({}, state.suffix, { 58 | value, 59 | }), 60 | })); 61 | }; 62 | 63 | render = () => ( 64 | 71 | ); 72 | } 73 | 74 | stories.add('Number, Suffix options', () => ( 75 | 76 | 83 | 84 | )); 85 | 86 | stories.add('Number, Suffix string', () => ( 87 | 88 | 95 | 96 | )); 97 | -------------------------------------------------------------------------------- /stories/components/common/controls/TwoOptionToggle.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | 4 | import { storiesOf } from '@storybook/react'; 5 | 6 | import TwoOptionToggle from '../../../../src/components/common/controls/TwoOptionToggle'; 7 | 8 | // eslint-disable-next-line no-console 9 | const toggleFn = () => { console.log('Clicked toggle!'); }; 10 | 11 | class InteractiveContainer extends React.Component { 12 | static propTypes = { 13 | disabled: PropTypes.bool, 14 | }; 15 | 16 | constructor(props) { 17 | super(props); 18 | this.state = { 19 | leftOption: true, 20 | rightOption: false, 21 | }; 22 | this.toggle = this.toggle.bind(this); 23 | } 24 | 25 | toggle() { 26 | this.setState({ 27 | leftOption: !this.state.leftOption, 28 | rightOption: !this.state.rightOption, 29 | }); 30 | } 31 | 32 | render() { 33 | return ( 34 |
    35 | 41 |
    42 | ); 43 | } 44 | } 45 | 46 | storiesOf('TwoOptionToggle', module) 47 | .add('left selected', () => ( 48 | 53 | )) 54 | .add('right selected', () => ( 55 | 60 | )) 61 | .add('disabled', () => ( 62 | 68 | )) 69 | .add('interactive', () => ( 70 | 71 | )); 72 | -------------------------------------------------------------------------------- /stories/components/common/loader/Loader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { storiesOf } from '@storybook/react'; 4 | 5 | import Loader from '../../../../src/components/common/loader/Loader'; 6 | 7 | const props = {}; 8 | 9 | const BackgroundDecorator = (story) => ( 10 |
    11 | {story()} 12 |
    13 | ); 14 | 15 | storiesOf('Loader', module) 16 | .addDecorator(BackgroundDecorator) 17 | .add('defaults', () => ( 18 |
    19 | 20 |
    21 | )) 22 | .add('with overlay', () => ( 23 |
    24 | 25 |
    26 | )) 27 | .add('with custom text', () => ( 28 |
    29 | 30 |
    31 | )) 32 | .add('with no text', () => ( 33 |
    34 | 35 |
    36 | )); 37 | -------------------------------------------------------------------------------- /stories/components/common/tooltips/CgmSampleIntervalTooltip.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { storiesOf } from '@storybook/react'; 4 | 5 | import CgmSampleIntervalTooltip from '../../../../src/components/common/tooltips/CgmSampleIntervalTooltip'; 6 | 7 | const props = { 8 | position: { top: 205, left: 105 }, 9 | }; 10 | 11 | const BackgroundDecorator = story => ( 12 |
    {story()}
    13 | ); 14 | 15 | const refDiv = ( 16 |
    28 | ); 29 | 30 | const stories = storiesOf('CgmSampleIntervalTooltip', module); 31 | stories.addDecorator(BackgroundDecorator); 32 | 33 | stories.add('default tootlip', () => ( 34 |
    35 | {refDiv} 36 | 37 |
    38 | )); 39 | -------------------------------------------------------------------------------- /stories/components/common/tooltips/StatTooltip.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { storiesOf } from '@storybook/react'; 4 | 5 | import StatTooltip from '../../../../src/components/common/tooltips/StatTooltip'; 6 | 7 | const props = { 8 | position: { top: 105, left: 105 }, 9 | }; 10 | 11 | const BackgroundDecorator = story => ( 12 |
    {story()}
    13 | ); 14 | 15 | const refDiv = ( 16 |
    28 | ); 29 | 30 | const stories = storiesOf('StatTooltip', module); 31 | stories.addDecorator(BackgroundDecorator); 32 | 33 | stories.add('short annotation', () => ( 34 |
    35 | {refDiv} 36 | 37 |
    38 | )); 39 | 40 | stories.add('long annotation', () => ( 41 |
    42 | {refDiv} 43 | 44 |
    45 | )); 46 | 47 | stories.add('markdown annotation', () => ( 48 |
    49 | {refDiv} 50 | 51 |
    52 | )); 53 | 54 | stories.add('multiple annotations', () => ( 55 |
    56 | {refDiv} 57 | 64 |
    65 | )); 66 | -------------------------------------------------------------------------------- /stories/components/daily/FoodTooltip.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import moment from 'moment'; 3 | 4 | import { storiesOf } from '@storybook/react'; 5 | 6 | import FoodTooltip from '../../../src/components/daily/foodtooltip/FoodTooltip'; 7 | 8 | const props = { 9 | position: { top: 200, left: 200 }, 10 | timePrefs: { timezoneAware: false }, 11 | }; 12 | 13 | const BackgroundDecorator = story => ( 14 |
    {story()}
    15 | ); 16 | 17 | const refDiv = ( 18 |
    30 | ); 31 | 32 | const standard = { 33 | nutrition: { 34 | carbohydrate: { 35 | net: 3, 36 | units: 'grams', 37 | }, 38 | }, 39 | }; 40 | 41 | const loop = { 42 | ...standard, 43 | origin: { name: 'com.X48HMZH853.loopkit.Loop' }, 44 | name: '🌮', 45 | nutrition: { 46 | ...standard.nutrition, 47 | estimatedAbsorptionDuration: 10800, 48 | }, 49 | }; 50 | 51 | const loopTimeOfEntry = { 52 | ...loop, 53 | payload: { 54 | userCreatedDate: moment().toISOString(), 55 | }, 56 | normalTime: moment().subtract(15, 'minutes').toISOString(), 57 | }; 58 | 59 | const loopEdited = { 60 | ...loop, 61 | payload: { 62 | userUpdatedDate: moment().toISOString(), 63 | }, 64 | normalTime: moment().subtract(30, 'minutes').toISOString(), 65 | }; 66 | 67 | storiesOf('FoodTooltip', module) 68 | .addDecorator(BackgroundDecorator) 69 | .add('standard', () => ( 70 |
    71 | {refDiv} 72 | 73 |
    74 | )) 75 | .add('Loop', () => ( 76 |
    77 | {refDiv} 78 | 79 |
    80 | )) 81 | .add('Loop time of entry', () => ( 82 |
    83 | {refDiv} 84 | 85 |
    86 | )) 87 | .add('Loop edited', () => ( 88 |
    89 | {refDiv} 90 | 91 |
    92 | )); 93 | -------------------------------------------------------------------------------- /stories/components/daily/PumpSettingsOverrideTooltip.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import moment from 'moment'; 3 | 4 | import { storiesOf } from '@storybook/react'; 5 | 6 | import PumpSettingsOverrideTooltip from '../../../src/components/daily/pumpsettingsoverridetooltip/PumpSettingsOverrideTooltip'; 7 | import { MGDL_UNITS, MS_IN_HOUR } from '../../../src/utils/constants'; 8 | 9 | const now = moment().valueOf(); 10 | 11 | const sleep = { 12 | duration: MS_IN_HOUR * 8, 13 | overrideType: 'sleep', 14 | source: 'tandem', 15 | subType: 'pumpSettingsOverride', 16 | normalTime: moment(now).subtract(1, 'h').valueOf(), 17 | normalEnd: now, 18 | type: 'deviceEvent', 19 | }; 20 | 21 | const physicalActivity = { 22 | duration: MS_IN_HOUR * 1, 23 | overrideType: 'physicalActivity', 24 | source: 'tandem', 25 | subType: 'pumpSettingsOverride', 26 | normalTime: moment(now).subtract(1, 'h').valueOf(), 27 | normalEnd: now, 28 | type: 'deviceEvent', 29 | }; 30 | 31 | const preprandial = { 32 | duration: MS_IN_HOUR * 1, 33 | overrideType: 'preprandial', 34 | source: 'diy loop', 35 | subType: 'pumpSettingsOverride', 36 | normalTime: moment(now).subtract(1, 'h').valueOf(), 37 | normalEnd: now, 38 | type: 'deviceEvent', 39 | bgTarget: { 40 | low: 110.554, 41 | high: 120.004, 42 | }, 43 | }; 44 | 45 | const props = { 46 | position: { top: 200, left: 200 }, 47 | timePrefs: { timezoneAware: false }, 48 | bgPrefs: { bgUnits: MGDL_UNITS }, 49 | }; 50 | 51 | const BackgroundDecorator = story => ( 52 |
    {story()}
    53 | ); 54 | 55 | const refDiv = ( 56 |
    68 | ); 69 | 70 | storiesOf('PumpSettingsOverrideTooltip', module) 71 | .addDecorator(BackgroundDecorator) 72 | .add('Sleep', () => ( 73 |
    74 | {refDiv} 75 | 76 |
    77 | )) 78 | .add('Exercise', () => ( 79 |
    80 | {refDiv} 81 | 82 |
    83 | )) 84 | .add('Premeal', () => ( 85 |
    86 | {refDiv} 87 | 88 |
    89 | )); 90 | -------------------------------------------------------------------------------- /stories/components/trends/common/Background.js: -------------------------------------------------------------------------------- 1 | import { scaleLinear } from 'd3-scale'; 2 | import React from 'react'; 3 | 4 | import { storiesOf } from '@storybook/react'; 5 | 6 | // eslint-disable-next-line max-len 7 | import Background from '../../../../src/components/trends/common/Background'; 8 | 9 | const w = 800; 10 | const h = 450; 11 | const props = { 12 | margins: { 13 | left: 0, 14 | right: 0, 15 | top: 0, 16 | bottom: 0, 17 | }, 18 | svgDimensions: { 19 | width: w, 20 | height: h, 21 | }, 22 | xScale: scaleLinear().domain([0, 864e5]).range([0, w]), 23 | }; 24 | 25 | storiesOf('Background', module) 26 | .add('without lines', () => ( 27 | 28 | 29 | 30 | )) 31 | .add('with lines at three-hour intervals', () => ( 32 | 33 | 34 | 35 | )); 36 | -------------------------------------------------------------------------------- /stories/fonts.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,300italic,400italic,600italic,700italic); 2 | 3 | :root { 4 | font-family: "Basis", "Helvetica Neue", Helvetica, Arial, sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /stories/index.js: -------------------------------------------------------------------------------- 1 | require('../src/styles/colors.css'); 2 | require('./fonts.css'); 3 | -------------------------------------------------------------------------------- /stories/print/PrescriptionPrintPDF.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | import { storiesOf } from '@storybook/react'; 20 | import PDFDocument from 'pdfkit'; 21 | 22 | import { createPrintView } from '../../src/modules/print/index'; 23 | import { MARGIN } from '../../src/modules/print/utils/constants'; 24 | import PrintView from '../../src/modules/print/PrintView'; 25 | import { base64ToArrayBuffer, waitForData } from '../../src/modules/print/pdfkitHelpers'; 26 | 27 | import * as profiles from '../../data/patient/profiles'; 28 | import { MGDL_UNITS } from '../../src/utils/constants'; 29 | import { prescriptionData } from '../../data/print/fixtures'; 30 | 31 | /* global window */ 32 | /* eslint-disable max-len */ 33 | 34 | const stories = storiesOf('Prescription View PDF', module); 35 | 36 | function openPDF({ patient }) { 37 | const doc = new PDFDocument({ autoFirstPage: false, bufferPages: true, margin: MARGIN }); 38 | 39 | const opts = { 40 | patient, 41 | }; 42 | 43 | const data = { 44 | ...prescriptionData, 45 | bgPrefs: { bgUnits: MGDL_UNITS }, 46 | }; 47 | 48 | createPrintView('prescription', data, opts, doc).render(); 49 | PrintView.renderPageNumbers(doc); 50 | 51 | waitForData(doc) 52 | .then(dataUrl => { 53 | const byte = base64ToArrayBuffer(dataUrl); 54 | const blob = new Blob([byte], { type: 'application/pdf' }); 55 | window.open(URL.createObjectURL(blob), '_blank'); 56 | }) 57 | .catch(error => { 58 | console.log(error); 59 | }); 60 | 61 | doc.end(); 62 | } 63 | 64 | stories.add('standard account', () => ( 65 | 68 | )); 69 | -------------------------------------------------------------------------------- /storiesDatatypes/components/common/data/Suspend.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | import { scaleLinear } from 'd3-scale'; 20 | import { storiesOf } from '@storybook/react'; 21 | 22 | import Suspend from '../../../../src/components/common/data/Suspend'; 23 | 24 | import SixHrScaleSVGDecorator, { HEIGHT, xScale } from '../../../helpers/SixHrScaleSVGDecorator'; 25 | 26 | const yScale = scaleLinear().domain([0, 15]).range([HEIGHT, 0]); 27 | 28 | import * as suspends from '../../../../data/deviceEvent/fixtures'; 29 | 30 | const stories = storiesOf('Suspend', module); 31 | stories.addDecorator(SixHrScaleSVGDecorator); 32 | 33 | stories.add('single automated suspend', () => ( 34 | 35 | ), { notes: 'A single automated suspend' }); 36 | stories.add('multiple automated suspends', () => ( 37 | 38 | ), { notes: 'A set of automated suspends' }); 39 | -------------------------------------------------------------------------------- /storiesDatatypes/components/index.js: -------------------------------------------------------------------------------- 1 | require('../../src/styles/colors.css'); 2 | require('../../stories/fonts.css'); 3 | -------------------------------------------------------------------------------- /storiesDatatypes/helpers/SixHrScaleSVGDecorator.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import { scaleLinear } from 'd3-scale'; 19 | import React from 'react'; 20 | 21 | export const WIDTH = 345; 22 | export const HEIGHT = 145; 23 | 24 | const longestTick = 40; 25 | 26 | const SixHrScaleSVGDecorator = (story) => ( 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 9 pm 36 | 37 | 38 | 39 | 12 am 40 | 41 | 42 | Monday, March 6 43 | 44 | 45 | 46 | 3 am 47 | 48 | 49 | {story()} 50 | 51 | ); 52 | 53 | export const xScale = scaleLinear().domain([0, 216e5]).range([115, WIDTH]); 54 | 55 | export default SixHrScaleSVGDecorator; 56 | -------------------------------------------------------------------------------- /storybook/main.js: -------------------------------------------------------------------------------- 1 | import custom from './webpack.config.js'; 2 | 3 | const config = { 4 | framework: '@storybook/react-webpack5', 5 | stories: ['../stories/**/*.@(js|jsx|mjs|ts|tsx)'], 6 | 7 | addons: [ 8 | '@storybook/addon-essentials', 9 | '@storybook/addon-knobs', 10 | ], 11 | 12 | features: { 13 | storyStoreV7: false, 14 | }, 15 | 16 | webpackFinal: async (config) => { 17 | delete config.resolve.fallback.fs; 18 | 19 | const finalConfig = { 20 | ...config, 21 | module: { ...config.module, rules: [ 22 | ...config.module.rules.filter(rule => { 23 | return rule.test 24 | ? rule.test.toString().indexOf('css') === -1 && rule.test.toString().indexOf('svg') === -1 25 | : true; 26 | }), 27 | ...custom.module.rules, 28 | ] }, 29 | resolve: { ...config.resolve, 30 | alias: { 31 | ...config.resolve.alias, 32 | ...custom.resolve.alias, 33 | }, 34 | fallback: { 35 | ...config.resolve.fallback, 36 | ...custom.resolve.fallback, 37 | }, 38 | }, 39 | plugins: [...config.plugins, ...custom.plugins], 40 | devtool: 'inline-source-map', 41 | }; 42 | 43 | return finalConfig; 44 | }, 45 | }; 46 | 47 | export default config; 48 | -------------------------------------------------------------------------------- /storybook/preview.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import DataUtil from '../src/utils/DataUtil'; 4 | 5 | let data; 6 | try { 7 | // eslint-disable-next-line global-require, import/no-unresolved 8 | data = require('../local/rawData.json'); 9 | let dataSource = 'the Tidepool API'; 10 | 11 | if (data?.data?.current?.data) { 12 | data = _.flatten(_.values(data.data.current.data)); 13 | dataSource = 'a Tidepool Web console export'; 14 | } else if (data?.[0].dataset) { 15 | data = _.flatten(_.map(data, v => v.data)); 16 | dataSource = 'a Tidepool Account Tool export'; 17 | } 18 | 19 | console.log(`Loading dataset provided by ${dataSource}`); 20 | } catch (e) { 21 | data = { data: [] }; 22 | } 23 | 24 | const patientId = 'abc123'; 25 | const dataUtil = new DataUtil(); 26 | dataUtil.addData(data, patientId); 27 | 28 | const props = { 29 | dataUtil, 30 | patientId, 31 | }; 32 | 33 | const preview = { 34 | decorators: [ 35 | (Story) => ( 36 |
    {Story(props)}
    37 | ), 38 | ], 39 | }; 40 | 41 | export default preview; 42 | -------------------------------------------------------------------------------- /storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../webpack.config.js'); 2 | 3 | module.exports = config; 4 | -------------------------------------------------------------------------------- /storybookDatatypes/main.js: -------------------------------------------------------------------------------- 1 | import custom from './webpack.config.js'; 2 | 3 | const config = { 4 | framework: '@storybook/react-webpack5', 5 | stories: ['../storiesDatatypes/components/**/*.@(js|jsx|mjs|ts|tsx)'], 6 | 7 | addons: [ 8 | '@storybook/addon-essentials', 9 | ], 10 | 11 | features: { 12 | storyStoreV7: false, 13 | }, 14 | 15 | webpackFinal: async (config) => { 16 | delete config.resolve.fallback.fs; 17 | 18 | const finalConfig = { 19 | ...config, 20 | module: { ...config.module, rules: [ 21 | ...config.module.rules.filter(rule => { 22 | return rule.test 23 | ? rule.test.toString().indexOf('css') === -1 && rule.test.toString().indexOf('svg') === -1 24 | : true; 25 | }), 26 | ...custom.module.rules, 27 | ] }, 28 | resolve: { ...config.resolve, 29 | alias: { 30 | ...config.resolve.alias, 31 | ...custom.resolve.alias, 32 | }, 33 | fallback: { 34 | ...config.resolve.fallback, 35 | ...custom.resolve.fallback, 36 | }, 37 | }, 38 | plugins: [...config.plugins, ...custom.plugins], 39 | }; 40 | 41 | return finalConfig; 42 | }, 43 | }; 44 | 45 | export default config; 46 | -------------------------------------------------------------------------------- /storybookDatatypes/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../webpack.config.js'); 2 | 3 | module.exports = config; 4 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true, 4 | "node": true 5 | }, 6 | "globals": { 7 | "assert": false, 8 | "expect": false, 9 | "sinon": false 10 | }, 11 | "rules": { 12 | "comma-dangle": ["error", "only-multiline"], 13 | "no-multiple-empty-lines": 0, 14 | "no-mixed-operators": 0, 15 | "no-redeclare": 0, 16 | "function-call-argument-newline": 0, 17 | "max-len": 0, 18 | "max-classes-per-file": 0, 19 | "no-unused-vars": 0, 20 | "no-import-assign": 0, 21 | "function-paren-newline": 0, 22 | "import/first": 0, 23 | "import/no-useless-path-segments": 0, 24 | "indent": 0, 25 | "lodash/prefer-lodash-method": ["error", { 26 | "ignoreMethods": ["find", "split", "trim", "replace"] 27 | }], 28 | "no-prototype-builtins": 0, 29 | "no-unused-expressions": 0, 30 | "no-useless-escape": 0, 31 | "object-property-newline": 0, 32 | "operator-assignment": 0, 33 | "react/jsx-curly-brace-presence": 0, 34 | "react/jsx-props-no-spreading": 0, 35 | "react/function-component-definition": 0, 36 | "space-unary-ops": 0 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/components/common/stat/BgBarLabel.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import _ from 'lodash'; 3 | import { mount } from 'enzyme'; 4 | 5 | import BgBarLabel from '../../../../src/components/common/stat/BgBarLabel'; 6 | 7 | describe('BgBarLabel', () => { 8 | let wrapper; 9 | 10 | const defaultProps = { 11 | barWidth: 4, 12 | domain: { 13 | x: [0, 1], 14 | y: [0, 1], 15 | }, 16 | scale: { 17 | x: val => val, 18 | y: val => val, 19 | }, 20 | style: {}, 21 | text: () => 'text!', 22 | width: 80, 23 | }; 24 | 25 | const props = overrides => _.assign({}, defaultProps, overrides); 26 | 27 | beforeEach(() => { 28 | wrapper = mount(); 29 | }); 30 | 31 | it('should render the text prop', () => { 32 | expect(wrapper.find('VictoryLabel')).to.have.length(1); 33 | expect(wrapper.find('VictoryLabel').text()).to.equal('text!'); 34 | }); 35 | 36 | it('should render the text element with the styles provided in the style prop', () => { 37 | wrapper.setProps(props({ style: { fill: 'mauve', fontSize: '40px' } })); 38 | expect(wrapper.find('VictoryLabel').props().style.fill).to.equal('mauve'); 39 | expect(wrapper.find('VictoryLabel').props().style.fontSize).to.equal('40px'); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/components/common/stat/HoverBarLabel.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import _ from 'lodash'; 4 | 5 | import HoverBarLabel from '../../../../src/components/common/stat/HoverBarLabel'; 6 | 7 | describe('HoverBarLabel', () => { 8 | let wrapper; 9 | 10 | const defaultProps = { 11 | barWidth: 30, 12 | isDisabled: () => false, 13 | domain: { 14 | x: [0, 1], 15 | y: [0, 1], 16 | }, 17 | style: {}, 18 | scale: { 19 | x: val => val, 20 | y: val => val, 21 | }, 22 | text: () => ['text!', 'suffix!'], 23 | tooltipText: () => 'tooltip!', 24 | }; 25 | 26 | const props = overrides => _.assign({}, defaultProps, overrides); 27 | 28 | beforeEach(() => { 29 | wrapper = mount(); 30 | }); 31 | 32 | it('should render the a text prop for the value and suffix text', () => { 33 | expect(wrapper.find('VictoryLabel')).to.have.length(2); 34 | expect(wrapper.find('VictoryLabel').at(0).text()).to.equal('text!'); 35 | expect(wrapper.find('VictoryLabel').at(1).text()).to.equal('suffix!'); 36 | }); 37 | 38 | it('should render the text element with the styles provided in the style prop', () => { 39 | wrapper.setProps(props({ style: { fill: 'mauve', fontSize: '40px' } })); 40 | expect(wrapper.find('VictoryLabel').at(0).props().style.fill).to.equal('mauve'); 41 | expect(wrapper.find('VictoryLabel').at(0).props().style.fontSize).to.equal('40px'); 42 | }); 43 | 44 | it('should render the tooltip text', () => { 45 | expect(wrapper.find('VictoryTooltip')).to.have.length(1); 46 | expect(wrapper.find('VictoryTooltip').props().text()).to.equal('tooltip!'); 47 | }); 48 | 49 | it('should render the text element with the styles provided in the style prop', () => { 50 | wrapper.setProps(props({ style: { fill: 'mauve', fontSize: '40px' } })); 51 | expect(wrapper.find('VictoryTooltip').props().style.fill).to.equal('mauve'); 52 | }); 53 | 54 | it('should enforce the tooltip fontsize to the minimum of half the bar width or 12', () => { 55 | wrapper.setProps(props({ barWidth: 30 })); 56 | expect(wrapper.find('VictoryTooltip').props().style.fontSize).to.equal(12); 57 | 58 | wrapper.setProps(props({ barWidth: 20 })); 59 | expect(wrapper.find('VictoryTooltip').props().style.fontSize).to.equal(10); 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /test/components/common/stat/StatLegend.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { shallow } from 'enzyme'; 3 | 4 | import { formatClassesAsSelector } from '../../../helpers/cssmodules'; 5 | import StatLegend from '../../../../src/components/common/stat/StatLegend'; 6 | import styles from '../../../../src/components/common/stat/StatLegend.css'; 7 | import colors from '../../../../src/styles/colors.css'; 8 | 9 | describe('StatLegend', () => { 10 | let wrapper; 11 | 12 | const defaultProps = { 13 | items: [ 14 | { 15 | id: 'basal', 16 | legendTitle: 'Basal', 17 | }, 18 | { 19 | id: 'bolus', 20 | legendTitle: 'Bolus', 21 | }, 22 | ], 23 | }; 24 | 25 | beforeEach(() => { 26 | wrapper = shallow(); 27 | }); 28 | 29 | it('should render legend item titles', () => { 30 | const items = wrapper.find(formatClassesAsSelector(styles.StatLegendItem)); 31 | expect(items).to.have.length(2); 32 | expect(items.at(0).text()).to.equal('Basal'); 33 | expect(items.at(1).text()).to.equal('Bolus'); 34 | }); 35 | 36 | it('should render legend item borders in proper color based on id', () => { 37 | const items = wrapper.find(formatClassesAsSelector(styles.StatLegendItem)); 38 | expect(items.at(0).props().style.borderBottomColor).to.equal(colors.basal); 39 | expect(items.at(1).props().style.borderBottomColor).to.equal(colors.bolus); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/components/common/tooltip/StatTooltip.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { mount } from 'enzyme'; 3 | import _ from 'lodash'; 4 | 5 | import { formatClassesAsSelector } from '../../../helpers/cssmodules'; 6 | import StatTooltip from '../../../../src/components/common/tooltips/StatTooltip'; 7 | import styles from '../../../../src/components/common/tooltips/StatTooltip.css'; 8 | 9 | describe('StatTooltip', () => { 10 | let wrapper; 11 | 12 | const defaultProps = { 13 | position: { 14 | top: 0, 15 | left: 0, 16 | }, 17 | annotations: [ 18 | 'message 1', 19 | 'message 2', 20 | ], 21 | }; 22 | 23 | beforeEach(() => { 24 | wrapper = mount(); 25 | }); 26 | 27 | it('should render a tooltip', () => { 28 | expect(wrapper.find('Tooltip')).to.have.length(1); 29 | }); 30 | 31 | it('should render text messages', () => { 32 | const messages = wrapper.find(formatClassesAsSelector(styles.message)).hostNodes(); 33 | expect(messages).to.have.length(2); 34 | expect(messages.at(0).text()).to.equal('message 1'); 35 | expect(messages.at(1).text()).to.equal('message 2'); 36 | }); 37 | 38 | it('should render markdown messages', () => { 39 | wrapper.setProps(_.assign({}, defaultProps, { 40 | annotations: [ 41 | 'Some _italic_ text', 42 | 'Some **bold** text', 43 | 'a [link](http://www.example.com)', 44 | ], 45 | })); 46 | const messages = wrapper.find(formatClassesAsSelector(styles.message)).hostNodes(); 47 | expect(messages.at(0).html()).to.include('italic'); 48 | expect(messages.at(1).html()).to.include('bold'); 49 | expect(messages.at(2).html()).to.include('link'); 50 | }); 51 | 52 | it('should render a divider between messages', () => { 53 | const dividers = () => wrapper.find(formatClassesAsSelector(styles.divider)); 54 | expect(dividers()).to.have.length(1); 55 | wrapper.setProps(_.assign({}, defaultProps, { 56 | annotations: [ 57 | 'message 1', 58 | 'message 2', 59 | 'message 3', 60 | 'message 4', 61 | ], 62 | })); 63 | expect(dividers()).to.have.length(3); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /test/components/settings/common/Header.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | import { shallow } from 'enzyme'; 20 | 21 | import Header from '../../../../src/components/settings/common/Header'; 22 | 23 | describe('Header', () => { 24 | it('should render the device upload date', () => { 25 | const wrapper = shallow( 26 |
    31 | ); 32 | expect(wrapper.find('span').text()).to.equal('Active at Upload on Jul 12th 2016'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /test/components/settings/common/SingleLineCollapsibleContainerLabel.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | import { shallow } from 'enzyme'; 20 | 21 | import SingleLineCollapsibleContainerLabel 22 | from '../../../../src/components/settings/common/SingleLineCollapsibleContainerLabel'; 23 | 24 | describe('SingleLineCollapsibleContainerLabel', () => { 25 | it('should render a label with a click handler', () => { 26 | const clicker = sinon.stub(); 27 | expect(clicker.callCount).to.equal(0); 28 | const wrapper = shallow( 29 | 34 | ); 35 | wrapper.simulate('click'); 36 | expect(clicker.callCount).to.equal(1); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/components/settings/common/TwoLineCollapsibleContainerLabel.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | import { shallow } from 'enzyme'; 20 | 21 | import TwoLineCollapsibleContainerLabel 22 | from '../../../../src/components/settings/common/TwoLineCollapsibleContainerLabel'; 23 | 24 | describe('TwoLineCollapsibleContainerLabel', () => { 25 | it('should render a label with a click handler', () => { 26 | const clicker = sinon.stub(); 27 | expect(clicker.callCount).to.equal(0); 28 | const wrapper = shallow( 29 | 34 | ); 35 | wrapper.simulate('click'); 36 | expect(clicker.callCount).to.equal(1); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /test/components/trends/cbg/CBGDateTraceLabel.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | import { mount } from 'enzyme'; 20 | 21 | import { formatClassesAsSelector } from '../../../helpers/cssmodules'; 22 | 23 | import CBGDateTraceLabel from '../../../../src/components/trends/cbg/CBGDateTraceLabel'; 24 | import styles from '../../../../src/components/trends/cbg/CBGDateTraceLabel.css'; 25 | 26 | describe('CBGDateTraceLabel', () => { 27 | const props = { 28 | focusedDateTrace: { 29 | data: { 30 | localDate: '2017-01-01', 31 | }, 32 | position: { 33 | left: 10, 34 | yPositions: { 35 | top: 100, 36 | topMargin: 50, 37 | }, 38 | }, 39 | }, 40 | }; 41 | 42 | describe('with no date trace currently focused', () => { 43 | it('should render nothing', () => { 44 | const wrapper = mount(); 45 | expect(wrapper.html()).to.be.null; 46 | }); 47 | }); 48 | 49 | describe('with a date trace focused', () => { 50 | it('should render a date label', () => { 51 | const wrapper = mount(); 52 | const label = wrapper.find(formatClassesAsSelector(styles.dateLabel)); 53 | expect(label).to.have.length(1); 54 | expect(label.text()).to.equal('Sunday, January 1'); 55 | }); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /test/components/trends/cbg/CBGDateTracesAnimationContainer.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import _ from 'lodash'; 19 | import React from 'react'; 20 | import TransitionGroupPlus from 'react-transition-group-plus'; 21 | import { shallow } from 'enzyme'; 22 | 23 | import bgBounds from '../../../helpers/bgBounds'; 24 | import CBGDateTraceAnimated from '../../../../src/components/trends/cbg/CBGDateTraceAnimated'; 25 | 26 | import CBGDateTracesAnimationContainer 27 | from '../../../../src/components/trends/cbg/CBGDateTracesAnimationContainer'; 28 | 29 | describe('CBGDateTracesAnimationContainer', () => { 30 | const props = { 31 | bgBounds, 32 | data: { 33 | '2016-12-25': [], 34 | '2017-01-01': [], 35 | }, 36 | dates: ['2016-12-25', '2017-01-01'], 37 | xScale: sinon.stub(), 38 | yScale: sinon.stub(), 39 | }; 40 | 41 | it('should render a TransitionGroupPlus even if there are no dates or data', () => { 42 | const noDataProps = _.assign({}, props, { data: {}, dates: [] }); 43 | const wrapper = shallow(); 44 | expect(wrapper.find(TransitionGroupPlus)).to.have.length(1); 45 | expect(wrapper.find(CBGDateTraceAnimated)).to.have.length(0); 46 | }); 47 | 48 | it('should render a TransitionGroupPlus and a CBGDateTraceAnimated for each date', () => { 49 | const wrapper = shallow(); 50 | expect(wrapper.find(TransitionGroupPlus)).to.have.length(1); 51 | expect(wrapper.find(CBGDateTraceAnimated)).to.have.length(2); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /test/components/trends/cbg/FocusedCBGSliceSegment.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | import { shallow } from 'enzyme'; 20 | 21 | import FocusedCBGSliceSegment from '../../../../src/components/trends/cbg/FocusedCBGSliceSegment'; 22 | 23 | describe('FocusedCBGSliceSegment', () => { 24 | const focusedSlice = { 25 | position: { 26 | left: 10, 27 | yPositions: { 28 | upperQuantile: 90, 29 | thirdQuartile: 75, 30 | }, 31 | }, 32 | }; 33 | const focusedSliceKeys = ['thirdQuartile', 'upperQuantile']; 34 | 35 | it('renders nothing if there\'s no `focusedSlice` in props', () => { 36 | const wrapper = shallow(); 37 | expect(wrapper.html()).to.be.null; 38 | }); 39 | 40 | it('renders nothing if there\'s no `focusedSliceKeys` in props', () => { 41 | const wrapper = shallow(); 42 | expect(wrapper.html()).to.be.null; 43 | }); 44 | 45 | it('renders a single rect when `focusedSlice` and `focusedSliceKeys`', () => { 46 | const props = { focusedSlice, focusedSliceKeys }; 47 | const wrapper = shallow(); 48 | expect(wrapper.find('rect').length).to.equal(1); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /test/components/trends/cbg/RangeSelect.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | 20 | import { mount } from 'enzyme'; 21 | import LabeledCheckbox from '../../../../src/components/common/controls/LabeledCheckbox'; 22 | import RangeSelect from '../../../../src/components/trends/cbg/RangeSelect'; 23 | 24 | describe('RangeSelect', () => { 25 | const props = { 26 | currentPatientInViewId: 'a1b2c3', 27 | displayFlags: { 28 | cbg100Enabled: false, 29 | cbg80Enabled: true, 30 | cbg50Enabled: true, 31 | cbgMedianEnabled: true, 32 | }, 33 | updateCbgRange: sinon.spy(), 34 | }; 35 | 36 | const wrapper = mount( 37 | 38 | ); 39 | 40 | it('should render four LabeledCheckboxes', () => { 41 | expect(wrapper.find(LabeledCheckbox).length).to.equal(4); 42 | expect(wrapper.find('input[type="checkbox"]').length).to.equal(4); 43 | }); 44 | 45 | it('clicking on the first checkbox should turn on 100%', () => { 46 | wrapper.find('input[type="checkbox"]').at(0).simulate('change'); 47 | expect(props.updateCbgRange.callCount).to.equal(1); 48 | expect(props.updateCbgRange.calledWith('cbg100Enabled', true)).to.be.true; 49 | }); 50 | 51 | it('clicking on the second checkbox should turn off 80%', () => { 52 | wrapper.find('input[type="checkbox"]').at(1).simulate('change'); 53 | expect(props.updateCbgRange.callCount).to.equal(2); 54 | expect(props.updateCbgRange.calledWith('cbg80Enabled', false)).to.be.true; 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /test/components/trends/common/XAxisLabels.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | 20 | import { mount } from 'enzyme'; 21 | 22 | import * as scales from '../../../helpers/scales'; 23 | const { 24 | trendsHeight, 25 | trendsWidth, 26 | trendsXScale: xScale, 27 | } = scales.trends; 28 | import SVGContainer from '../../../helpers/SVGContainer'; 29 | 30 | import { TWENTY_FOUR_HRS } from '../../../../src/utils/datetime'; 31 | 32 | import XAxisLabels from '../../../../src/components/trends/common/XAxisLabels'; 33 | 34 | describe('XAxisLabels', () => { 35 | let wrapper; 36 | const props = { 37 | margins: { 38 | top: 0, 39 | right: 0, 40 | bottom: 0, 41 | left: 0, 42 | }, 43 | xOffset: 0, 44 | xScale, 45 | }; 46 | 47 | before(() => { 48 | wrapper = mount( 49 | 50 | 51 | 52 | ); 53 | }); 54 | 55 | it('should render eight text labels at three hour intervals', () => { 56 | const labels = wrapper.find('text'); 57 | expect(labels).to.have.length(8); 58 | // Enzyme forEach cannot be replaced by _.forEach 59 | // eslint-disable-next-line lodash/prefer-lodash-method 60 | labels.forEach((label, i) => { 61 | expect(label.prop('x')).to.equal(xScale(i * (TWENTY_FOUR_HRS / 8))); 62 | }); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /test/components/trends/common/XAxisTicks.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | 20 | import { mount } from 'enzyme'; 21 | 22 | import * as scales from '../../../helpers/scales'; 23 | const { 24 | trendsHeight, 25 | trendsWidth, 26 | trendsXScale: xScale, 27 | } = scales.trends; 28 | import SVGContainer from '../../../helpers/SVGContainer'; 29 | 30 | import { TWENTY_FOUR_HRS } from '../../../../src/utils/datetime'; 31 | 32 | import XAxisTicks from '../../../../src/components/trends/common/XAxisTicks'; 33 | 34 | describe('XAxisTicks', () => { 35 | let wrapper; 36 | const props = { 37 | margins: { 38 | top: 0, 39 | right: 0, 40 | bottom: 0, 41 | left: 0, 42 | }, 43 | xOffset: 0, 44 | xScale, 45 | }; 46 | 47 | before(() => { 48 | wrapper = mount( 49 | 50 | 51 | 52 | ); 53 | }); 54 | 55 | it('should render nine tick lines at three hour intervals', () => { 56 | const ticks = wrapper.find('line'); 57 | expect(ticks).to.have.length(9); 58 | // Enzyme forEach cannot be replaced by _.forEach 59 | // eslint-disable-next-line lodash/prefer-lodash-method 60 | ticks.forEach((tick, i) => { 61 | expect(tick.prop('x1')).to.equal(xScale(i * (TWENTY_FOUR_HRS / 8))); 62 | expect(tick.prop('x2')).to.equal(xScale(i * (TWENTY_FOUR_HRS / 8))); 63 | }); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /test/components/trends/common/withDefaultYPosition.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | import { shallow } from 'enzyme'; 20 | 21 | import bgBounds from '../../../helpers/bgBounds'; 22 | import DummyComponent from '../../../helpers/DummyComponent'; 23 | import * as scales from '../../../helpers/scales'; 24 | const { 25 | trendsYScale: yScale, 26 | } = scales.trends; 27 | 28 | import withDefaultYPosition from '../../../../src/components/trends/common/withDefaultYPosition'; 29 | 30 | describe('withDefaultYPosition', () => { 31 | const props = { 32 | bgBounds, 33 | yScale, 34 | foo: 'bar', 35 | }; 36 | const ToRender = withDefaultYPosition(DummyComponent); 37 | let wrapper; 38 | before(() => { 39 | wrapper = shallow(); 40 | }); 41 | 42 | it('should render the DummyComponent with an additional defaultY prop', () => { 43 | const dummy = wrapper.find(DummyComponent); 44 | expect(dummy.length).to.equal(1); 45 | const { targetLowerBound, targetUpperBound } = bgBounds; 46 | expect(dummy.prop('defaultY')) 47 | .to.equal(yScale(targetUpperBound - (targetUpperBound - targetLowerBound) / 2)); 48 | }); 49 | 50 | it('should also pass through all other props', () => { 51 | const dummy = wrapper.find(DummyComponent); 52 | expect(dummy.prop('bgBounds')).to.deep.equal(bgBounds); 53 | expect(dummy.prop('yScale')).to.equal(yScale); 54 | expect(dummy.prop('foo')).to.equal('bar'); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /test/helpers/DummyComponent.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import React from 'react'; 19 | 20 | const DummyComponent = () => (
    ); 21 | 22 | export default DummyComponent; 23 | -------------------------------------------------------------------------------- /test/helpers/SVGContainer.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import PropTypes from 'prop-types'; 19 | import React from 'react'; 20 | 21 | const SVGContainer = (props) => { 22 | const { children, dimensions: { width, height } } = props; 23 | 24 | return ( 25 |
    26 | 27 | {children} 28 | 29 |
    30 | ); 31 | }; 32 | 33 | SVGContainer.propTypes = { 34 | children: PropTypes.object.isRequired, 35 | dimensions: PropTypes.shape({ 36 | width: PropTypes.number.isRequired, 37 | height: PropTypes.number.isRequired, 38 | }).isRequired, 39 | }; 40 | 41 | export default SVGContainer; 42 | -------------------------------------------------------------------------------- /test/helpers/bgBounds.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | export default { 19 | veryHighThreshold: 300, 20 | targetUpperBound: 180, 21 | targetLowerBound: 70, 22 | veryLowThreshold: 55, 23 | }; 24 | -------------------------------------------------------------------------------- /test/helpers/bgConversion.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import { MGDL_PER_MMOLL } from '../../src/utils/constants'; 19 | 20 | export const toMmolL = (val) => (val / MGDL_PER_MMOLL); 21 | -------------------------------------------------------------------------------- /test/helpers/cssmodules.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | export function formatClassesAsSelector(classesStr) { 19 | return `.${classesStr}`.replace(/\s/g, '.'); 20 | } 21 | -------------------------------------------------------------------------------- /test/helpers/scales.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2016, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import { scaleLinear } from 'd3-scale'; 19 | 20 | const trendsWidth = 864; 21 | const trendsHeight = 360; 22 | 23 | const trendsXScale = scaleLinear() 24 | .domain([0, 864e5]) 25 | .range([0, trendsWidth]); 26 | 27 | const trendsYScale = scaleLinear() 28 | .domain([40, 400]) 29 | .range([trendsHeight, 0]) 30 | .clamp(true); 31 | 32 | const trends = { trendsWidth, trendsHeight, trendsXScale, trendsYScale }; 33 | 34 | const detailWidth = 864; 35 | const detailHeight = 100; 36 | 37 | const detailXScale = scaleLinear() 38 | .domain([0, 864e5]) 39 | .range([0, detailWidth]); 40 | 41 | const detailBasalScale = scaleLinear() 42 | .domain([0, 5]) 43 | .range([detailHeight, 0]); 44 | 45 | const detailBolusScale = scaleLinear() 46 | .domain([0, 15]) 47 | .range([detailHeight, 0]); 48 | 49 | const detail = { detailWidth, detailHeight, detailXScale, detailBasalScale, detailBolusScale }; 50 | 51 | export { detail, trends }; 52 | -------------------------------------------------------------------------------- /test/propTypes/index.test.js: -------------------------------------------------------------------------------- 1 | import * as propTypes from '../../src/propTypes'; 2 | 3 | describe('common propTypes', () => { 4 | it('should export `bgPrefsPropType` definition', () => { 5 | expect(propTypes.bgPrefsPropType).to.be.a('function'); 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /test/styles/colors.test.js: -------------------------------------------------------------------------------- 1 | import colors from '../../src/styles/colors.css'; 2 | import _ from 'lodash'; 3 | 4 | describe('colors', () => { 5 | it('should export all required colors', () => { 6 | expect(_.toLower(colors.bolus)).to.equal('#7cd0f0'); 7 | expect(_.toLower(colors.bolusAutomated)).to.equal('#00b2c3'); 8 | expect(_.toLower(colors.basal)).to.equal('#19a0d7'); 9 | expect(_.toLower(colors.basalAutomated)).to.equal('#00b2c3'); 10 | expect(_.toLower(colors.sleep)).to.equal('#4457d9'); 11 | expect(_.toLower(colors.physicalActivity)).to.equal('#758cff'); 12 | expect(_.toLower(colors.preprandial)).to.equal('#4457d9'); 13 | expect(_.toLower(colors.statDark)).to.equal('#27385b'); 14 | expect(_.toLower(colors.statDefault)).to.equal('#727375'); 15 | expect(_.toLower(colors.statDisabled)).to.equal('#e7e9ee'); 16 | expect(_.toLower(colors.veryLow)).to.equal('#fb5951'); 17 | expect(_.toLower(colors.low)).to.equal('#ff8b7c'); 18 | expect(_.toLower(colors.target)).to.equal('#76d3a6'); 19 | expect(_.toLower(colors.high)).to.equal('#bb9ae7'); 20 | expect(_.toLower(colors.veryHigh)).to.equal('#8c65d6'); 21 | expect(_.toLower(colors.insulin)).to.equal('#0096d1'); 22 | expect(_.toLower(colors.white)).to.equal('#ffffff'); 23 | expect(_.toLower(colors.axis)).to.equal('#e7e9ee'); 24 | expect(_.toLower(colors.muted)).to.equal('#c1c9d6'); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/utils/misc.test.js: -------------------------------------------------------------------------------- 1 | /* 2 | * == BSD2 LICENSE == 3 | * Copyright (c) 2017, Tidepool Project 4 | * 5 | * This program is free software; you can redistribute it and/or modify it under 6 | * the terms of the associated License, which is identical to the BSD 2-Clause 7 | * License as published by the Open Source Initiative at opensource.org. 8 | * 9 | * This program is distributed in the hope that it will be useful, but WITHOUT 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | * FOR A PARTICULAR PURPOSE. See the License for more details. 12 | * 13 | * You should have received a copy of the License along with this program; if 14 | * not, you can obtain one from Tidepool Project at tidepool.org. 15 | * == BSD2 LICENSE == 16 | */ 17 | 18 | import * as patients from '../../data/patient/profiles'; 19 | import * as misc from '../../src/utils/misc'; 20 | 21 | describe('misc utility functions', () => { 22 | describe('getPatientFullName', () => { 23 | const { 24 | standard, 25 | fakeChildAcct, 26 | } = patients; 27 | 28 | it('should be a function', () => { 29 | assert.isFunction(misc.getPatientFullName); 30 | }); 31 | 32 | it('returns patient name', () => { 33 | expect(misc.getPatientFullName(standard)).to.equal(standard.profile.fullName); 34 | }); 35 | 36 | it('returns child name when isOtherPerson', () => { 37 | expect(misc.getPatientFullName(fakeChildAcct)) 38 | .to.equal(fakeChildAcct.profile.patient.fullName); 39 | }); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/utils/print/plotly.test.js: -------------------------------------------------------------------------------- 1 | import * as plotlyUtils from '../../../src/utils/print/plotly'; 2 | import { createAGPData } from '../../../data/print/fixtures'; 3 | import { BGM_DATA_KEY, CGM_DATA_KEY } from '../../../src/utils/constants'; 4 | 5 | describe('generateAGPFigureDefinitions', () => { 6 | it('generate agp svg image figures for each section for cbg data', async () => { 7 | const images = await plotlyUtils.generateAGPFigureDefinitions(createAGPData(CGM_DATA_KEY)); 8 | expect(images.percentInRanges).to.be.an('object'); 9 | expect(images.percentInRanges).to.have.property('data'); 10 | expect(images.percentInRanges).to.have.property('layout'); 11 | expect(images.ambulatoryGlucoseProfile).to.be.an('object'); 12 | expect(images.ambulatoryGlucoseProfile).to.have.property('data'); 13 | expect(images.ambulatoryGlucoseProfile).to.have.property('layout'); 14 | expect(images.dailyGlucoseProfiles).to.be.an('array').and.have.lengthOf(2); 15 | expect(images.dailyGlucoseProfiles[0]).to.be.an('object'); 16 | expect(images.dailyGlucoseProfiles[0]).to.have.property('data'); 17 | expect(images.dailyGlucoseProfiles[0]).to.have.property('layout'); 18 | expect(images.dailyGlucoseProfiles[1]).to.be.an('object'); 19 | expect(images.dailyGlucoseProfiles[1]).to.have.property('data'); 20 | expect(images.dailyGlucoseProfiles[1]).to.have.property('layout'); 21 | }); 22 | 23 | it('generate agp svg image figures for each section for smbg data', async () => { 24 | const images = await plotlyUtils.generateAGPFigureDefinitions(createAGPData(BGM_DATA_KEY)); 25 | expect(images.percentInRanges).to.be.an('object'); 26 | expect(images.percentInRanges).to.have.property('data'); 27 | expect(images.percentInRanges).to.have.property('layout'); 28 | expect(images.ambulatoryGlucoseProfile).to.be.an('object'); 29 | expect(images.ambulatoryGlucoseProfile).to.have.property('data'); 30 | expect(images.ambulatoryGlucoseProfile).to.have.property('layout'); 31 | expect(images.dailyGlucoseProfiles).to.be.an('array').and.have.lengthOf(2); 32 | expect(images.dailyGlucoseProfiles[0]).to.be.an('object'); 33 | expect(images.dailyGlucoseProfiles[0]).to.have.property('data'); 34 | expect(images.dailyGlucoseProfiles[0]).to.have.property('layout'); 35 | expect(images.dailyGlucoseProfiles[1]).to.be.an('object'); 36 | expect(images.dailyGlucoseProfiles[1]).to.have.property('data'); 37 | expect(images.dailyGlucoseProfiles[1]).to.have.property('layout'); 38 | }); 39 | }); 40 | --------------------------------------------------------------------------------