diff --git a/app/components/datasources/DataConnectionsModal.js b/app/components/datasources/DataConnectionsModal.js index 4ca0616075..dd94882536 100644 --- a/app/components/datasources/DataConnectionsModal.js +++ b/app/components/datasources/DataConnectionsModal.js @@ -54,14 +54,14 @@ export const DataConnectionsModal = (props) => { dataSources, } : patient; - const [showPatientEmailModal, setShowPatientEmailModal] = useState(false); + const [showPatientEmailModal, setShowPatientEmailModal] = useState(false); const [processingEmailUpdate, setProcessingEmailUpdate] = useState(false); const [patientEmailFormContext, setPatientEmailFormContext] = useState(); const dispatch = useDispatch(); const fetchPatientDetails = useCallback(() => { - dispatch(actions.async.fetchPatientFromClinic(api, selectedClinicId, patient.id)); - }, [dispatch, patient.id, selectedClinicId]) + dispatch(actions.async.fetchPatientFromClinic(api, selectedClinicId, patient?.id)); + }, [dispatch, patient?.id, selectedClinicId]); // Pull the patient on load to ensure the most recent dexcom connection state is made available useEffect(() => { @@ -136,6 +136,8 @@ export const DataConnectionsModal = (props) => { ? t('Learn more.') : t('Learn more here.'); + if (!patient) return null; + return ( <> { const { t } = useTranslation(); const dispatch = useDispatch(); const selectedClinicId = useSelector((state) => state.blip.selectedClinicId); - const currentPatientInViewId = useSelector(state => state.blip.currentPatientInViewId); - const clinicPatient = useSelector(state => selectClinicPatient(state)); const clinic = useSelector(state => state.blip.clinics?.[selectedClinicId]); const isSmartOnFhir = useSelector(selectIsSmartOnFhirMode); + const patientId = clinicPatient?.id; const mrnSettings = useMemo(() => clinic?.mrnSettings ?? {}, [clinic?.mrnSettings]); const existingMRNs = useSelector(state => state.blip.clinicMRNsForPatientFormValidation)?.filter(mrn => mrn !== clinicPatient?.mrn) || []; @@ -74,7 +75,8 @@ const EditPatientDialog = ({ const onUpdateSuccess = () => { if (isOpen) onClose(); - dispatch(actions.worker.dataWorkerRemoveDataRequest(null, currentPatientInViewId)); + onEditSuccess(); + dispatch(actions.worker.dataWorkerRemoveDataRequest(null, patientId)); }; const updatingClinicPatient = useUpdatingClinicPatientWorkingState({ onUpdateSuccess }); @@ -89,7 +91,7 @@ const EditPatientDialog = ({ setPatientFormContext({ ...formikContext }); }; - if (!currentPatientInViewId || !selectedClinicId) return null; + if (!patientId || !selectedClinicId) return null; return ( setIsEditPatientModalOpen(false)} /> diff --git a/app/pages/clinicworkspace/DeviceIssues/DataConnectionsModalController.js b/app/pages/clinicworkspace/DeviceIssues/DataConnectionsModalController.js new file mode 100644 index 0000000000..7c54732ccf --- /dev/null +++ b/app/pages/clinicworkspace/DeviceIssues/DataConnectionsModalController.js @@ -0,0 +1,25 @@ +import React from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import DataConnectionsModal from '../../../components/datasources/DataConnectionsModal'; +import { closeModals } from './deviceIssuesSlice'; + +const DataConnectionsModalController = ({ patients }) => { + const dispatch = useDispatch(); + + const dataConnectionsModal = useSelector(state => state.blip.deviceIssues.dataConnectionsModal); + const { patientId, isOpen } = dataConnectionsModal; + + const patient = patients.find(patient => patient.id === patientId); + + const handleClose = () => dispatch(closeModals()); + + return ( + + ); +}; + +export default DataConnectionsModalController; diff --git a/app/pages/clinicworkspace/DeviceIssues/DeviceIssues.js b/app/pages/clinicworkspace/DeviceIssues/DeviceIssues.js index c4e6493f6c..75885931dc 100644 --- a/app/pages/clinicworkspace/DeviceIssues/DeviceIssues.js +++ b/app/pages/clinicworkspace/DeviceIssues/DeviceIssues.js @@ -7,6 +7,8 @@ import Table from '../../../components/elements/Table'; import { Box, Flex, Grid, Text } from 'theme-ui'; import FilterByCategory from './FilterByCategory'; +import EditPatientDialogController from './EditPatientDialogController'; +import DataConnectionsModalController from './DataConnectionsModalController'; import PaginationControls from '../components/PaginationControls'; import { setOffset, resetDeviceIssuesState } from './deviceIssuesSlice'; @@ -16,7 +18,7 @@ import PatientCount from '../components/PatientCount'; const LIMIT = 12; -const DeviceIssues = () => { +const DeviceIssues = ({ api, trackMetric }) => { const { t } = useTranslation(); const dispatch = useDispatch(); @@ -40,7 +42,7 @@ const DeviceIssues = () => { if (!data) return null; - const tableData = data?.data || []; + const patients = data?.data || []; const total = data?.meta?.count || 0; @@ -63,7 +65,7 @@ const DeviceIssues = () => { variant="condensed" label="deviceIssuesPatientsTable" columns={columns} - data={tableData} + data={patients} // sx={tableStyle} // onSort={handleSortChange} // order={sort?.substring(0, 1) === '+' ? 'asc' : 'desc'} @@ -86,6 +88,16 @@ const DeviceIssues = () => { + + + + ); }; diff --git a/app/pages/clinicworkspace/DeviceIssues/EditPatientDialogController.js b/app/pages/clinicworkspace/DeviceIssues/EditPatientDialogController.js new file mode 100644 index 0000000000..0b1dae2f32 --- /dev/null +++ b/app/pages/clinicworkspace/DeviceIssues/EditPatientDialogController.js @@ -0,0 +1,40 @@ +import React from 'react'; +import { useSelector, useDispatch } from 'react-redux'; +import { closeModals } from './deviceIssuesSlice'; +import { RTKQueryApi } from '../../../redux/api/baseApi'; +import EditPatientDialog from '../../../components/modals/EditPatientDialog'; +import { tagTypes } from './deviceIssuesApi'; + +const { DEVICE_ISSUES_PATIENTS } = tagTypes; + +const trackMetric = () => {}; + +const EditPatientDialogController = ({ api, patients }) => { + const dispatch = useDispatch(); + const editPatientDialog = useSelector(state => state.blip.deviceIssues.editPatientDialog); + + const clinicPatient = patients.find(patient => patient.id === editPatientDialog.patientId); + + const handleCloseModal = () => { + dispatch(closeModals()); + }; + + const handleEditSuccess = () => { + dispatch(RTKQueryApi.util.invalidateTags([DEVICE_ISSUES_PATIENTS])); + }; + + return ( + <> + + + ); +}; + +export default EditPatientDialogController; diff --git a/app/pages/clinicworkspace/DeviceIssues/MoreMenuCell.js b/app/pages/clinicworkspace/DeviceIssues/MoreMenuCell.js new file mode 100644 index 0000000000..a89a178c26 --- /dev/null +++ b/app/pages/clinicworkspace/DeviceIssues/MoreMenuCell.js @@ -0,0 +1,78 @@ +import React from 'react'; +import { useDispatch } from 'react-redux'; +import { useTranslation } from 'react-i18next'; + +import { + setEditPatientDialogIsOpen, + setEditPatientDialogPatientId, + setDataConnectionsModalIsOpen, + setDataConnectionsModalPatientId, +} from './deviceIssuesSlice'; + +import PopoverMenu from '../../../components/elements/PopoverMenu'; +import EditIcon from '@material-ui/icons/EditRounded'; +import DataInIcon from '../../../core/icons/DataInIcon.svg'; +import VisibilityOffIcon from '@material-ui/icons/VisibilityOff'; +import VisibilityIcon from '@material-ui/icons/Visibility'; + +const MoreMenuCell = ({ patient }) => { + const { t } = useTranslation(); + const dispatch = useDispatch(); + + const handleOpenEditPatientDialog = () => { + dispatch(setEditPatientDialogIsOpen(true)); + dispatch(setEditPatientDialogPatientId(patient.id)); + }; + + const handleOpenDataConnectionsModal = () => { + dispatch(setDataConnectionsModalIsOpen(true)); + dispatch(setDataConnectionsModalPatientId(patient.id)); + }; + + const handleHideIssue = () => { + // To implement + }; + + return ( + { + _popupState.close(); + handleOpenEditPatientDialog(); + }, + text: t('Edit Patient Details'), + }, { + iconSrc: DataInIcon, + iconLabel: t('Bring Data into Tidepool'), + iconPosition: 'left', + id: `edit-data-connections-${patient?.id}`, + variant: 'actionListItem', + onClick: (_popupState) => { + _popupState.close(); + handleOpenDataConnectionsModal(); + }, + text: t('Bring Data into Tidepool'), + }, { + icon: VisibilityOffIcon, + iconLabel: t('Hide Issue'), + iconPosition: 'left', + id: `hide-issue-${patient?.id}`, + variant: 'actionListItem', + onClick: (_popupState) => { + _popupState.close(); + handleHideIssue(); + }, + text: t('Hide Issue'), + }]} + sx={{ position: 'relative', left: '-2px' }} + /> + ); +}; + +export default MoreMenuCell; diff --git a/app/pages/clinicworkspace/DeviceIssues/deviceIssuesApi.js b/app/pages/clinicworkspace/DeviceIssues/deviceIssuesApi.js index a2a13e8fe9..ea8b8dd98f 100644 --- a/app/pages/clinicworkspace/DeviceIssues/deviceIssuesApi.js +++ b/app/pages/clinicworkspace/DeviceIssues/deviceIssuesApi.js @@ -25,6 +25,16 @@ const getDeviceIssuesParam = (category) => { } }; +export const tagTypes = { + DEVICE_ISSUES_PATIENTS: 'DEVICE_ISSUES_PATIENTS', +}; + +const { DEVICE_ISSUES_PATIENTS } = tagTypes; + +RTKQueryApi.enhanceEndpoints({ + addTagTypes: [DEVICE_ISSUES_PATIENTS], +}); + const deviceIssuesApi = RTKQueryApi.injectEndpoints({ endpoints: (builder) => ({ getDeviceIssuesPatients: builder.query({ @@ -42,6 +52,7 @@ const deviceIssuesApi = RTKQueryApi.injectEndpoints({ }, }; }, + providesTags: [DEVICE_ISSUES_PATIENTS], }), }), }); diff --git a/app/pages/clinicworkspace/DeviceIssues/deviceIssuesSlice.js b/app/pages/clinicworkspace/DeviceIssues/deviceIssuesSlice.js index cfc02cb48f..3b281ee705 100644 --- a/app/pages/clinicworkspace/DeviceIssues/deviceIssuesSlice.js +++ b/app/pages/clinicworkspace/DeviceIssues/deviceIssuesSlice.js @@ -5,6 +5,14 @@ import { CATEGORY } from './FilterByCategory'; const initialState = { category: CATEGORY.DEFAULT, offset: 0, + editPatientDialog: { + patientId: null, + isOpen: false, + }, + dataConnectionsModal: { + patientId: null, + isOpen: false, + }, }; const deviceIssuesSlice = createSlice({ @@ -17,9 +25,35 @@ const deviceIssuesSlice = createSlice({ setOffset: (state, action) => { state.offset = action.payload; }, + setEditPatientDialogPatientId: (state, action) => { + state.editPatientDialog.patientId = action.payload; + }, + setEditPatientDialogIsOpen: (state, action) => { + state.editPatientDialog.isOpen = action.payload; + }, + setDataConnectionsModalPatientId: (state, action) => { + state.dataConnectionsModal.patientId = action.payload; + }, + setDataConnectionsModalIsOpen: (state, action) => { + state.dataConnectionsModal.isOpen = action.payload; + }, + closeModals: (state) => { + state.editPatientDialog = initialState.editPatientDialog; + state.dataConnectionsModal = initialState.dataConnectionsModal; + }, resetDeviceIssuesState: () => initialState, }, }); -export const { setCategory, setOffset, resetDeviceIssuesState } = deviceIssuesSlice.actions; +export const { + setCategory, + setOffset, + setEditPatientDialogPatientId, + setEditPatientDialogIsOpen, + setDataConnectionsModalPatientId, + setDataConnectionsModalIsOpen, + closeModals, + resetDeviceIssuesState, +} = deviceIssuesSlice.actions; + export default deviceIssuesSlice.reducer; diff --git a/app/pages/clinicworkspace/DeviceIssues/useTableColumns.js b/app/pages/clinicworkspace/DeviceIssues/useTableColumns.js index b32ba53154..7dc12b979f 100644 --- a/app/pages/clinicworkspace/DeviceIssues/useTableColumns.js +++ b/app/pages/clinicworkspace/DeviceIssues/useTableColumns.js @@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next'; import PatientCell from './PatientCell'; import TagListCell from '../components/TagListCell'; +import MoreMenuCell from './MoreMenuCell'; const useTableColumns = () => { const { t } = useTranslation(); @@ -50,6 +51,7 @@ const useTableColumns = () => { title: t(''), field: 'more', align: 'left', + render: patient => , }, // More ].filter(column => !!column); }, [showTags]);