-
-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1497 from tidepool-org/WEB-3346-summary-accuracy
[WEB-3346, WEB-3351] - CGM Summary Enhancements
- Loading branch information
Showing
14 changed files
with
398 additions
and
369 deletions.
There are no files selected for viewing
27 changes: 27 additions & 0 deletions
27
app/pages/dashboard/PatientDrawer/CGMStatistics/getReportDaysText.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import moment from 'moment'; | ||
import { MS_IN_MIN } from '../../../../core/constants'; | ||
import isNumber from 'lodash/isNumber'; | ||
import { utils as vizUtils } from '@tidepool/viz'; | ||
const { getOffset, formatDateRange } = vizUtils.datetime; | ||
|
||
const getDateRange = (startDate, endDate, dateParseFormat, _prefix, monthFormat, timezone) => { | ||
let start = startDate; | ||
let end = endDate; | ||
|
||
if (isNumber(startDate) && isNumber(endDate)) { | ||
start = startDate - getOffset(startDate, timezone) * MS_IN_MIN; | ||
end = endDate - getOffset(endDate, timezone) * MS_IN_MIN; | ||
} | ||
|
||
return formatDateRange(start, end, dateParseFormat, monthFormat); | ||
}; | ||
|
||
const getReportDaysText = (newestDatum, oldestDatum, bgDaysWorn, timezone) => { | ||
const reportDaysText = bgDaysWorn === 1 | ||
? moment.utc(newestDatum?.time - getOffset(newestDatum?.time, timezone) * MS_IN_MIN).format('MMMM D, YYYY') | ||
: getDateRange(oldestDatum?.time, newestDatum?.time, undefined, '', 'MMMM', timezone); | ||
|
||
return reportDaysText; | ||
}; | ||
|
||
export default getReportDaysText; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 16 additions & 85 deletions
101
app/pages/dashboard/PatientDrawer/MenuBar/CGMClipboardButton.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,119 +1,50 @@ | ||
import React, { useEffect, useState, useMemo } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import Button from '../../../../components/elements/Button'; | ||
import utils from '../../../../core/utils'; | ||
import { MGDL_UNITS } from '../../../../core/constants'; | ||
import { MS_IN_HOUR } from '../../../../core/constants'; | ||
import { Box } from 'theme-ui'; | ||
import { utils as vizUtils } from '@tidepool/viz'; | ||
const { TextUtil } = vizUtils.text; | ||
import { Box } from 'theme-ui' | ||
import moment from 'moment'; | ||
|
||
const formatDateRange = (startEndpoint, endEndpoint, timezoneName) => { | ||
const startDate = moment.utc(startEndpoint).tz(timezoneName); | ||
const endDate = moment.utc(endEndpoint).tz(timezoneName); | ||
const startYear = startDate.year(); | ||
const endYear = endDate.year(); | ||
|
||
if (startYear !== endYear) { | ||
return `${startDate.format('MMMM D, YYYY')} - ${endDate.format('MMMM D, YYYY')}`; | ||
} | ||
|
||
return `${startDate.format('MMMM D')} - ${endDate.format('MMMM D')}, ${endDate.format('YYYY')}`; | ||
} | ||
|
||
const getCGMClipboardText = (patient, agpCGM, t) => { | ||
if (!agpCGM || !patient) return ''; | ||
|
||
const { fullName, birthDate } = patient; | ||
|
||
const { | ||
timePrefs, | ||
bgPrefs: { bgUnits }, | ||
data: { | ||
current: { | ||
stats: { | ||
bgExtents: { newestDatum, oldestDatum }, | ||
averageGlucose: { averageGlucose }, | ||
timeInRange: { counts }, | ||
}, | ||
} | ||
} | ||
} = agpCGM; | ||
|
||
const timezoneName = vizUtils.datetime.getTimezoneFromTimePrefs(timePrefs); | ||
|
||
const currentDate = moment().format('MMMM Do, YYYY'); | ||
|
||
// TODO: Add test for no data scenario | ||
const dateRange = formatDateRange(oldestDatum?.time, newestDatum?.time, timezoneName); | ||
|
||
const targetRange = bgUnits === MGDL_UNITS ? '70-180' : '3.9-10.0'; | ||
const lowRange = bgUnits === MGDL_UNITS ? '54-70' : '3.0-3.9'; | ||
const veryLowRange = bgUnits === MGDL_UNITS ? '<54' : '<3.0'; | ||
|
||
const countsInTarget = utils.roundToPrecision((counts.target / counts.total) * 100, 0); | ||
const countsInLow = utils.roundToPrecision((counts.low * 100 ) / counts.total, 0); | ||
const countsInVeryLow = utils.roundToPrecision((counts.veryLow * 100 ) / counts.total, 0); | ||
|
||
const avgGlucose = utils.roundToPrecision(averageGlucose, bgUnits === MGDL_UNITS ? 0 : 1); | ||
|
||
const textUtil = new TextUtil(); | ||
let clipboardText = ''; | ||
|
||
clipboardText += textUtil.buildTextLine(fullName); | ||
clipboardText += textUtil.buildTextLine(t('Date of birth: {{birthDate}}', { birthDate })); | ||
clipboardText += textUtil.buildTextLine(t('Exported from Tidepool TIDE: {{currentDate}}', { currentDate })); | ||
clipboardText += textUtil.buildTextLine(''); | ||
clipboardText += textUtil.buildTextLine(t('Reporting Period: {{dateRange}}', { dateRange })); | ||
clipboardText += textUtil.buildTextLine(''); | ||
clipboardText += textUtil.buildTextLine(t('Avg. Daily Time In Range ({{bgUnits}})', { bgUnits })); | ||
clipboardText += textUtil.buildTextLine(t('{{targetRange}} {{countsInTarget}}%', { targetRange, countsInTarget })); | ||
clipboardText += textUtil.buildTextLine(t('{{lowRange}} {{countsInLow}}%', { lowRange, countsInLow })); | ||
clipboardText += textUtil.buildTextLine(t('{{veryLowRange}} {{countsInVeryLow}}%', { veryLowRange, countsInVeryLow })); | ||
clipboardText += textUtil.buildTextLine(''); | ||
clipboardText += textUtil.buildTextLine(t('Avg. Glucose (CGM): {{avgGlucose}} {{bgUnits}}', { avgGlucose, bgUnits })); | ||
|
||
return clipboardText; | ||
} | ||
const { agpCGMText } = vizUtils.text; | ||
|
||
const STATE = { | ||
DEFAULT: 'DEFAULT', | ||
CLICKED: 'CLICKED', | ||
} | ||
}; | ||
|
||
const CGMClipboardButton = ({ patient, agpCGM }) => { | ||
const CGMClipboardButton = ({ patient, data }) => { | ||
const { t } = useTranslation(); | ||
const [buttonState, setButtonState] = useState(STATE.DEFAULT); | ||
const clipboardText = useMemo(() => agpCGMText(patient, data), [patient, data]); | ||
|
||
useEffect(() => { | ||
let buttonTextEffect = setTimeout(() => { | ||
setButtonState(STATE.DEFAULT) | ||
setButtonState(STATE.DEFAULT); | ||
}, 1000); | ||
|
||
return () => { | ||
clearTimeout(buttonTextEffect); | ||
} | ||
}, [buttonState]) | ||
}; | ||
}, [buttonState]); | ||
|
||
const sensorUsage = agpCGM?.data?.current?.stats?.sensorUsage?.sensorUsage || 0; | ||
const { count, sampleFrequency } = data?.data?.current?.stats?.sensorUsage || {}; | ||
|
||
const isDisabled = !agpCGM || sensorUsage < 86400000; // minimum 24 hours | ||
const hoursOfCGMData = (count * sampleFrequency) / MS_IN_HOUR; | ||
|
||
const clipboardText = useMemo(() => getCGMClipboardText(patient, agpCGM, t), [patient, agpCGM, t]); | ||
const isDataInsufficient = !hoursOfCGMData || hoursOfCGMData < 24; | ||
|
||
const handleCopy = () => { | ||
navigator?.clipboard?.writeText(clipboardText); | ||
setButtonState(STATE.CLICKED); | ||
} | ||
}; | ||
|
||
return ( | ||
<Button disabled={isDisabled} onClick={handleCopy} variant="secondary"> | ||
<Button disabled={isDataInsufficient} onClick={handleCopy} variant="secondary"> | ||
{buttonState === STATE.CLICKED | ||
? <Box>{t('Copied ✓')}</Box> | ||
: <Box>{t('Copy as Text')}</Box> | ||
} | ||
</Button> | ||
) | ||
} | ||
); | ||
}; | ||
|
||
export default CGMClipboardButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.