diff --git a/app/pages/clinicworkspace/TideDashboardV2/FilterByDataRecency.js b/app/pages/clinicworkspace/TideDashboardV2/FilterByDataRecency.js new file mode 100644 index 0000000000..7c66d54f23 --- /dev/null +++ b/app/pages/clinicworkspace/TideDashboardV2/FilterByDataRecency.js @@ -0,0 +1,156 @@ +import React, { useState} from 'react'; +import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; +import { bindPopover, bindTrigger, usePopupState } from 'material-ui-popup-state/hooks'; +import { setLastDataFilter } from './tideDashboardFiltersSlice'; +import { Box } from 'theme-ui'; +import Button from '../../../components/elements/Button'; +import Popover from '../../../components/elements/Popover'; +import RadioGroup from '../../../components/elements/RadioGroup'; + +import KeyboardArrowDownRoundedIcon from '@material-ui/icons/KeyboardArrowDownRounded'; + +import noop from 'lodash/noop'; +import reject from 'lodash/reject'; +import find from 'lodash/find'; + +import { lastDataFilterOptions } from '../../../core/clinicUtils'; +import { borders } from '../../../themes/baseTheme'; +import { DialogActions, DialogContent } from '../../../components/elements/Dialog'; +import { Body0 } from '../../../components/elements/FontStyles'; +import { setOffset } from './tideDashboardSlice'; + +const trackMetric = noop; +const prefixPopHealthMetric = noop; + +const customLastDataFilterOptions = lastDataFilterOptions.filter(opt => [1, 2, 7].includes(opt.value)); + +const DropdownContent = ({ + onClose = noop, +}) => { + const { t } = useTranslation(); + const dispatch = useDispatch(); + + const selectedClinicId = useSelector(state => state.blip.selectedClinicId); + const lastData = useSelector(state => state.blip.tideDashboardFilters.lastData); + const [pendingLastData, setPendingLastData] = useState(lastData); + + return ( + <> + + + {t('Data Recency')} + {t('Tidepool will only show patients who have data within the selected number of days.')} + + + setPendingLastData(parseInt(evt.target.value) || null)} + /> + + + + + + + + + ); +}; + +const FilterByDataRecency = () => { + const { t } = useTranslation(); + const lastDataPopupFilterState = usePopupState({ + variant: 'popover', + popupId: 'lastDataFilters', + }); + + const selectedClinicId = useSelector(state => state.blip.selectedClinicId); + const lastData = useSelector(state => state.blip.tideDashboardFilters.lastData); + + return ( + <> + { + if (!lastDataPopupFilterState.isOpen) { + trackMetric(prefixPopHealthMetric('Last data filter open'), { clinicId: selectedClinicId }); + } + }} + sx={{ flexShrink: 0 }} + > + + + + { + trackMetric(prefixPopHealthMetric('Last upload filter close'), { clinicId: selectedClinicId }); + }} + onClose={() => lastDataPopupFilterState.close()} + > + { lastDataPopupFilterState.isOpen && + lastDataPopupFilterState.close()} + /> + } + + + ); +}; + +export default FilterByDataRecency; diff --git a/app/pages/clinicworkspace/TideDashboardV2/FilterBySummaryPeriod.js b/app/pages/clinicworkspace/TideDashboardV2/FilterBySummaryPeriod.js new file mode 100644 index 0000000000..c759c720a4 --- /dev/null +++ b/app/pages/clinicworkspace/TideDashboardV2/FilterBySummaryPeriod.js @@ -0,0 +1,149 @@ +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; +import { bindPopover, bindTrigger, usePopupState } from 'material-ui-popup-state/hooks'; +import { setSummaryPeriodFilter } from './tideDashboardFiltersSlice'; +import { Box } from 'theme-ui'; +import Button from '../../../components/elements/Button'; +import Popover from '../../../components/elements/Popover'; +import RadioGroup from '../../../components/elements/RadioGroup'; + +import KeyboardArrowDownRoundedIcon from '@material-ui/icons/KeyboardArrowDownRounded'; + +import noop from 'lodash/noop'; +import find from 'lodash/find'; + +import { DialogActions, DialogContent } from '../../../components/elements/Dialog'; +import { Body0 } from '../../../components/elements/FontStyles'; +import { setOffset } from './tideDashboardSlice'; + +const trackMetric = noop; +const prefixPopHealthMetric = noop; + +const summaryPeriodOptions = [ + { value: '1d', label: '24 hours' }, + { value: '7d', label: '7 days' }, + { value: '14d', label: '14 days' }, + { value: '30d', label: '30 days' }, +]; + +const DropdownContent = ({ + onClose = noop, +}) => { + const { t } = useTranslation(); + const dispatch = useDispatch(); + + const selectedClinicId = useSelector(state => state.blip.selectedClinicId); + const summaryPeriod = useSelector(state => state.blip.tideDashboardFilters.summaryPeriod); + const [pendingSummaryPeriod, setPendingSummaryPeriod] = useState(summaryPeriod); + + return ( + <> + + + {t('Summary Period')} + {t('Tidepool will generate health summaries for the selected number of days.')} + + + setPendingSummaryPeriod(event.target.value)} + /> + + + + + + + + + ); +}; + +const FilterBySummaryPeriod = () => { + const { t } = useTranslation(); + const summaryPeriodPopupFilterState = usePopupState({ + variant: 'popover', + popupId: 'summaryPeriodFilters', + }); + + const selectedClinicId = useSelector(state => state.blip.selectedClinicId); + const summaryPeriod = useSelector(state => state.blip.tideDashboardFilters.summaryPeriod); + + return ( + <> + { + if (!summaryPeriodPopupFilterState.isOpen) { + trackMetric(prefixPopHealthMetric('Summary period filter open'), { clinicId: selectedClinicId }); + } + }} + sx={{ flexShrink: 0 }} + > + + + + { + trackMetric(prefixPopHealthMetric('Summary period filter close'), { clinicId: selectedClinicId }); + }} + onClose={() => summaryPeriodPopupFilterState.close()} + > + { summaryPeriodPopupFilterState.isOpen && + summaryPeriodPopupFilterState.close()} + /> + } + + + ); +}; + +export default FilterBySummaryPeriod; diff --git a/app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js b/app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js index ea6527c1c1..4a641a2c6f 100644 --- a/app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js +++ b/app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js @@ -4,10 +4,13 @@ import { useDispatch, useSelector } from 'react-redux'; import { useTranslation, Trans } from 'react-i18next'; import { colors as vizColors } from '@tidepool/viz'; import Table from '../../../components/elements/Table'; -import { Box, Flex, Grid, Text } from 'theme-ui'; +import { Flex, Text, Box, Grid } from 'theme-ui'; import FilterByCategory from './FilterByCategory'; import FilterByTags from './FilterByTags'; +import FilterByDataRecency from './FilterByDataRecency'; +import FilterBySummaryPeriod from './FilterBySummaryPeriod'; + import TableCategoryHeader from './TableCategoryHeader'; import PaginationControls from '../components/PaginationControls'; import ActiveFilterCount from '../components/ActiveFilterCount'; @@ -18,6 +21,7 @@ import { resetTideDashboardState, setOffset } from './tideDashboardSlice'; import { useGetTideDashboardPatientsQuery } from './tideDashboardApi'; import ResetFilters from '../components/ResetFilters'; import useActiveFiltersCount from './useActiveFiltersCount'; +import useDerivedDataRecencyEndpoints from './useDerivedDataRecencyEndpoints'; import usePruneInvalidFilters from './usePruneInvalidFilters'; import { resetTideDashboardFilters } from './tideDashboardFiltersSlice'; import EmptyContentNode from './EmptyContentNode'; @@ -26,6 +30,10 @@ import PatientCount from '../components/PatientCount'; const LIMIT = 12; +const Divider = () => ; + +const Gap = () => ; + const TideDashboard = () => { const { t } = useTranslation(); const dispatch = useDispatch(); @@ -37,8 +45,10 @@ const TideDashboard = () => { const offset = useSelector(state => state.blip.tideDashboard.offset); const { patientTags, clinicSites } = useSelector(state => state.blip.tideDashboardFilters); + const [lastDataFrom, lastDataTo] = useDerivedDataRecencyEndpoints(); + const { data } = useGetTideDashboardPatientsQuery( - { clinicId: selectedClinicId, offset, category, tags: patientTags, sites: clinicSites, limit: LIMIT }, + { clinicId: selectedClinicId, offset, category, lastDataTo, lastDataFrom, tags: patientTags, sites: clinicSites, limit: LIMIT }, { skip: !selectedClinicId } ); @@ -51,6 +61,8 @@ const TideDashboard = () => { const handleChangeOffset = (newOffset) => dispatch(setOffset(newOffset)); + const handleResetFilters = () => dispatch(resetTideDashboardFilters()); + if (!data) return null; const tableData = data?.data || []; @@ -63,10 +75,10 @@ const TideDashboard = () => { -