diff --git a/app/pages/clinicworkspace/TideDashboardV2/PatientLastReviewed.js b/app/pages/clinicworkspace/TideDashboardV2/PatientLastReviewed.js
new file mode 100644
index 0000000000..4e50aa2a80
--- /dev/null
+++ b/app/pages/clinicworkspace/TideDashboardV2/PatientLastReviewed.js
@@ -0,0 +1,115 @@
+import React from 'react';
+import { useSelector } from 'react-redux';
+import { useTranslation } from 'react-i18next';
+import { Text, Box, FlexProps } from 'theme-ui';
+import moment from 'moment-timezone';
+import CheckRoundedIcon from '@material-ui/icons/CheckRounded';
+import { utils as vizUtils } from '@tidepool/viz';
+import upperFirst from 'lodash/upperFirst';
+
+import HoverButton from '../../../components/elements/HoverButton';
+import Icon from '../../../components/elements/Icon';
+import { useToasts } from '../../../providers/ToastProvider';
+import { useSetClinicPatientLastReviewedMutation, useRevertClinicPatientLastReviewedMutation } from './tideDashboardApi';
+import useTideDashboardPatients from './useTideDashboardPatients';
+
+const {
+ formatTimeAgo,
+ getTimezoneFromTimePrefs,
+} = vizUtils.datetime;
+
+const trackMetric = () => {}; // TODO: FIX
+
+const PatientLastReviewed = ({ patient }) => {
+ const { t } = useTranslation();
+ // const { set: setToast } = useToasts();
+ const selectedClinicId = useSelector((state) => state.blip.selectedClinicId);
+ const loggedInUserId = useSelector((state) => state.blip.loggedInUserId);
+ const timePrefs = useSelector((state) => state.blip.timePrefs);
+ const patientId = patient?.id;
+
+ const { isFetching } = useTideDashboardPatients();
+
+ const [setClinicPatientLastReviewed, { isLoading: isSetting }] = useSetClinicPatientLastReviewedMutation();
+ const [revertClinicPatientLastReviewed, { isLoading: isReverting }] = useRevertClinicPatientLastReviewedMutation();
+
+ const handleReview = () => {
+ // trackMetric('Clinic - Mark patient reviewed', { clinicId: selectedClinicId, source: metricSource });
+ setClinicPatientLastReviewed({ clinicId: selectedClinicId, patientId });
+ // onReview && onReview();
+ };
+
+ const handleUndo = () => {
+ // trackMetric('Clinic - Undo mark patient reviewed', { clinicId: selectedClinicId, source: metricSource });
+ revertClinicPatientLastReviewed({ clinicId: selectedClinicId, patientId });
+ };
+
+ const recentlyReviewedThresholdDate = moment().startOf('isoWeek').toISOString();
+
+ let clickHandler = handleReview;
+ let buttonText = t('Mark Reviewed');
+
+ let formattedLastReviewed = { daysText: '-' };
+ let lastReviewIsToday = false;
+ let reviewIsRecent = false;
+ let canReview = true;
+ let color = 'feedback.warning';
+
+ if (patient?.reviews?.[0]?.time) {
+ formattedLastReviewed = formatTimeAgo(patient.reviews[0].time, timePrefs);
+ lastReviewIsToday = moment.utc(patient.reviews[0].time).tz(getTimezoneFromTimePrefs(timePrefs)).isSame(moment(), 'day');
+
+ if (lastReviewIsToday) {
+ canReview = false;
+ clickHandler = null;
+ }
+
+ if (moment.utc(patient.reviews[0].time).isSameOrAfter(moment(recentlyReviewedThresholdDate))) {
+ reviewIsRecent = true;
+ }
+
+ if (lastReviewIsToday && patient.reviews[0].clinicianId === loggedInUserId) {
+ clickHandler = handleUndo;
+ buttonText = t('Undo');
+ };
+
+ if (reviewIsRecent) {
+ color = 'feedback.success';
+ }
+ }
+
+
+ return (
+
+
+
+
+ {reviewIsRecent && }
+ {upperFirst(formattedLastReviewed.daysText)}
+
+
+
+
+ );
+};
+
+export default PatientLastReviewed;
diff --git a/app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js b/app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js
index 24c60c7d23..84de737f1a 100644
--- a/app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js
+++ b/app/pages/clinicworkspace/TideDashboardV2/TideDashboardV2.js
@@ -16,7 +16,7 @@ import PaginationControls from '../components/PaginationControls';
import ActiveFilterCount from '../components/ActiveFilterCount';
import { resetTideDashboardState, setOffset } from './tideDashboardSlice';
-import { useGetTideDashboardPatientsQuery } from './tideDashboardApi';
+import useTideDashboardPatients, { LIMIT } from './useTideDashboardPatients';
import ResetFilters from '../components/ResetFilters';
import useActiveFiltersCount from './useActiveFiltersCount';
import useDerivedDataRecencyEndpoints from './useDerivedDataRecencyEndpoints';
@@ -27,8 +27,6 @@ import EmptyContentNode from './EmptyContentNode';
import FilterBySites from './FilterBySites';
import PatientCount from '../components/PatientCount';
-const LIMIT = 12;
-
const Divider = () => ;
const Gap = () => ;
@@ -42,14 +40,8 @@ const TideDashboard = () => {
const selectedClinicId = useSelector(state => state.blip.selectedClinicId);
const category = useSelector(state => state.blip.tideDashboard.category);
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, lastDataTo, lastDataFrom, tags: patientTags, sites: clinicSites, limit: LIMIT },
- { skip: !selectedClinicId }
- );
+ const { data } = useTideDashboardPatients();
// Sync category to data fetching resolution; prevents visual glitch due to
// category updating view before the API call resolves and updates it again
diff --git a/app/pages/clinicworkspace/TideDashboardV2/tideDashboardApi.js b/app/pages/clinicworkspace/TideDashboardV2/tideDashboardApi.js
index fbe93d81dc..13a254fa00 100644
--- a/app/pages/clinicworkspace/TideDashboardV2/tideDashboardApi.js
+++ b/app/pages/clinicworkspace/TideDashboardV2/tideDashboardApi.js
@@ -36,6 +36,11 @@ export const buildGetTideDashboardPatientsParams = (offset, limit, category, las
};
};
+const TAGS = {
+ TIDE_DASHBOARD_PATIENTS: 'TideDashboardPatients',
+};
+
+const { TIDE_DASHBOARD_PATIENTS } = TAGS;
const tideDashboardApi = RTKQueryApi.injectEndpoints({
endpoints: (builder) => ({
@@ -52,8 +57,27 @@ const tideDashboardApi = RTKQueryApi.injectEndpoints({
...response,
category: arg.category,
}),
+ providesTags: [TIDE_DASHBOARD_PATIENTS],
+ }),
+ setClinicPatientLastReviewed: builder.mutation({
+ query: ({ clinicId, patientId }) => ({
+ url: `/clinics/${clinicId}/patients/${patientId}/reviews`,
+ method: 'PUT',
+ }),
+ invalidatesTags: [TIDE_DASHBOARD_PATIENTS],
+ }),
+ revertClinicPatientLastReviewed: builder.mutation({
+ query: ({ clinicId, patientId }) => ({
+ url: `/clinics/${clinicId}/patients/${patientId}/reviews`,
+ method: 'DELETE',
+ }),
+ invalidatesTags: [TIDE_DASHBOARD_PATIENTS],
}),
}),
});
-export const { useGetTideDashboardPatientsQuery } = tideDashboardApi;
+export const {
+ useGetTideDashboardPatientsQuery,
+ useSetClinicPatientLastReviewedMutation,
+ useRevertClinicPatientLastReviewedMutation,
+} = tideDashboardApi;
diff --git a/app/pages/clinicworkspace/TideDashboardV2/useTableColumns.js b/app/pages/clinicworkspace/TideDashboardV2/useTableColumns.js
index ceaf67bb6e..35855488eb 100644
--- a/app/pages/clinicworkspace/TideDashboardV2/useTableColumns.js
+++ b/app/pages/clinicworkspace/TideDashboardV2/useTableColumns.js
@@ -25,6 +25,7 @@ import {
} from './Cells';
import TagListCell from '../components/TagListCell';
+import PatientLastReviewed from './PatientLastReviewed';
const getColumnTypes = (t, category, thresholds) => ({
patientDetails: {
@@ -111,6 +112,7 @@ const getColumnTypes = (t, category, thresholds) => ({
title: t('Last Reviewed'),
field: 'lastReviewed',
align: 'center',
+ render: patient => ,
},
moreMenu: {
title: t(''),
diff --git a/app/pages/clinicworkspace/TideDashboardV2/useTideDashboardPatients.js b/app/pages/clinicworkspace/TideDashboardV2/useTideDashboardPatients.js
new file mode 100644
index 0000000000..cf8e438cc3
--- /dev/null
+++ b/app/pages/clinicworkspace/TideDashboardV2/useTideDashboardPatients.js
@@ -0,0 +1,21 @@
+import { useSelector } from 'react-redux';
+import { useGetTideDashboardPatientsQuery } from './tideDashboardApi';
+import useDerivedDataRecencyEndpoints from './useDerivedDataRecencyEndpoints';
+
+const LIMIT = 12;
+
+const useTideDashboardPatients = () => {
+ const selectedClinicId = useSelector(state => state.blip.selectedClinicId);
+ const category = useSelector(state => state.blip.tideDashboard.category);
+ const offset = useSelector(state => state.blip.tideDashboard.offset);
+ const patientTags = useSelector(state => state.blip.tideDashboardFilters.patientTags);
+ const [lastDataFrom, lastDataTo] = useDerivedDataRecencyEndpoints();
+
+ return useGetTideDashboardPatientsQuery(
+ { clinicId: selectedClinicId, offset, category, lastDataTo, lastDataFrom, tags: patientTags, limit: LIMIT },
+ { skip: !selectedClinicId }
+ );
+};
+
+export { LIMIT };
+export default useTideDashboardPatients;
diff --git a/app/pages/clinicworkspace/components/TagListCell.js b/app/pages/clinicworkspace/components/TagListCell.js
index 38d2654858..b500a5cb60 100644
--- a/app/pages/clinicworkspace/components/TagListCell.js
+++ b/app/pages/clinicworkspace/components/TagListCell.js
@@ -10,7 +10,7 @@ const TagListCell = ({ patient }) => {
const patientTags = clinic?.patientTags || [];
const tagIds = patient?.tags || [];
- const tags = tagIds.map(tag => patientTags.find(ptTag => ptTag.id === tag)); // TODO: index
+ const tags = tagIds.map(tag => patientTags.find(ptTag => ptTag.id === tag)).filter(Boolean); // TODO: index
return ;
};
diff --git a/app/pages/dashboard/PatientDrawer/MenuBar/MenuBar.js b/app/pages/dashboard/PatientDrawer/MenuBar/MenuBar.js
index 8cc65c6bf8..7a47a771db 100644
--- a/app/pages/dashboard/PatientDrawer/MenuBar/MenuBar.js
+++ b/app/pages/dashboard/PatientDrawer/MenuBar/MenuBar.js
@@ -35,7 +35,6 @@ const tabs = {
const MenuBar = ({ patientId, onClose, onSelectTab, selectedTab, trackMetric }) => {
const dispatch = useDispatch();
const { t } = useTranslation();
- const { showTideDashboardLastReviewed } = useFlags();
const selectedClinicId = useSelector(state => state.blip.selectedClinicId);
const patient = useSelector(state => state.blip.clinics[state.blip.selectedClinicId]?.patients?.[patientId]);
@@ -87,26 +86,24 @@ const MenuBar = ({ patientId, onClose, onSelectTab, selectedTab, trackMetric })
- {showTideDashboardLastReviewed && (
-
-
- {t('Last Reviewed')}
-
-
-
-
- )}
+
+
+ {t('Last Reviewed')}
+
+
+
+
diff --git a/app/redux/api/baseApi.js b/app/redux/api/baseApi.js
index b8b223a09a..2d730c17d2 100644
--- a/app/redux/api/baseApi.js
+++ b/app/redux/api/baseApi.js
@@ -42,6 +42,7 @@ export const RTKQueryApi = createApi({
baseQuery,
{ maxRetries: RETRY_COUNT },
),
+ tagTypes: ['TideDashboardPatients'],
refetchOnMountOrArgChange: true,
endpoints: () => ({}),
});