diff --git a/scope_shared/scope/schemas/documents/assessment-log.json b/scope_shared/scope/schemas/documents/assessment-log.json index ad6d653b..04d45a47 100644 --- a/scope_shared/scope/schemas/documents/assessment-log.json +++ b/scope_shared/scope/schemas/documents/assessment-log.json @@ -40,13 +40,21 @@ "type": "string" }, "pointValues": { - "type": "object", - "$comment": "TODO" + "type": "object" }, "totalScore": { "type": "number" + }, + "adherence": { + "type": "number" + }, + "medicationQuestion": { + "type": "boolean" + }, + "medicationNote": { + "type": "string" } }, "additionalProperties": false, - "required": ["_type", "recordedDateTime", "scheduledAssessmentId", "assessmentId", "pointValues"] + "required": ["_type", "recordedDateTime", "scheduledAssessmentId", "assessmentId"] } diff --git a/server_flask/app_config/assessments/medication.json b/server_flask/app_config/assessments/medication.json index e88f09bf..63a0a129 100644 --- a/server_flask/app_config/assessments/medication.json +++ b/server_flask/app_config/assessments/medication.json @@ -1,23 +1,23 @@ { - "id": "medication", - "name": "Medication Check-In", - "instruction": "The following questions pertain to any medications you are taking for stress, mood, anxiety, sleep, or other psychological symptoms.", - "questions": [ - { - "question": "In the past 7 days, did you take all your prescribed medications as scheduled?", - "id": "adherence" - } - ], - "options": [ - { - "text": "Yes, I took my medications as scheduled", - "value": 1 - }, - { - "text": "No, I did not take all my medications as scheduled", - "value": 0 - } - ], - "interpretationName": "Medication tracking", - "interpretationTable": [] + "id": "medication", + "name": "Medication", + "instruction": "The following questions pertain to any medications you are taking for stress, mood, anxiety, sleep, or other psychological symptoms.", + "questions": [ + { + "question": "In the past 7 days, did you take all your prescribed medications as scheduled?", + "id": "adherence" + } + ], + "options": [ + { + "text": "Yes, I took my medications as scheduled", + "value": 1 + }, + { + "text": "No, I did not take all my medications as scheduled", + "value": 0 + } + ], + "interpretationName": "Medication tracking", + "interpretationTable": [] } diff --git a/web_patient/src/App.tsx b/web_patient/src/App.tsx index c76b7d43..313f4fc2 100644 --- a/web_patient/src/App.tsx +++ b/web_patient/src/App.tsx @@ -6,6 +6,7 @@ import Chrome from 'src/components/Chrome/Chrome'; import HomePage from 'src/components/Home/HomePage'; import ActivityTrackingHome from 'src/components/Progress/ActivityTrackingHome'; import AssessmentHome from 'src/components/Progress/AssessmentHome'; +import MedicationTrackingHome from 'src/components/Progress/MedicationTrackingHome'; import MoodTrackingHome from 'src/components/Progress/MoodTrackingHome'; import ProgressPage from 'src/components/Progress/ProgressPage'; import AboutUsPage from 'src/components/Resources/AboutUsPage'; @@ -42,6 +43,7 @@ export const App: FunctionComponent = () => { path={`/${Routes.progress}/*`} element={ + } /> } /> } /> } = { - [ParameterValues.form.moodLog]: MoodLoggingForm, - [ParameterValues.form.assessmentLog]: AssessmentForm, [ParameterValues.form.activityLog]: ActivityLoggingForm, [ParameterValues.form.addActivity]: AddEditActivityForm, [ParameterValues.form.addActivitySchedule]: AddEditActivityForm, + [ParameterValues.form.assessmentLog]: AssessmentForm, [ParameterValues.form.editActivity]: AddEditActivityForm, [ParameterValues.form.editActivitySchedule]: AddEditActivityForm, + [ParameterValues.form.medicationLog]: MedicationLoggingForm, + [ParameterValues.form.moodLog]: MoodLoggingForm, [ParameterValues.form.safetyPlan]: SafetyPlanForm, }; diff --git a/web_patient/src/components/Forms/MedicationLoggingForm.tsx b/web_patient/src/components/Forms/MedicationLoggingForm.tsx new file mode 100644 index 00000000..2c7e7614 --- /dev/null +++ b/web_patient/src/components/Forms/MedicationLoggingForm.tsx @@ -0,0 +1,200 @@ +import { + FormControl, + FormControlLabel, + Radio, + RadioGroup, + SelectChangeEvent, + Stack, + TextField, +} from '@mui/material'; +import { action } from 'mobx'; +import { observer, useLocalObservable } from 'mobx-react'; +import React, { FunctionComponent } from 'react'; +import { IAssessmentLog } from 'shared/types'; +import FormDialog from 'src/components/Forms/FormDialog'; +import FormSection from 'src/components/Forms/FormSection'; +import { IFormProps } from 'src/components/Forms/GetFormDialog'; +import { getRouteParameter, Parameters } from 'src/services/routes'; +import { getString } from 'src/services/strings'; +import { useStores } from 'src/stores/stores'; + +export interface IMedicationLoggingFormProps extends IFormProps { } + +interface IQuestionFormProps { + instruction: string; + question: string; + questionId: string; + value: number | undefined; + options: { text: string; value: number }[]; + onValueChange: (newValue: number) => void; +} + + +const QuestionForm: FunctionComponent = (props) => { + const { instruction, question, questionId, value, options, onValueChange } = props; + return ( + + onValueChange(Number(val))}> + {options.map((resp, ridx) => { + return ( + } + label={`${resp.text}`} + /> + ); + })} + + + } + /> + ); +}; + +export const MedicationLoggingForm: FunctionComponent = observer(() => { + const assessmentId = getRouteParameter(Parameters.assessmentId); + const scheduleId = getRouteParameter(Parameters.taskId); + + if (!assessmentId || !scheduleId) { + console.error(`Scheduled id or assessment id not found in query paramters: ${assessmentId} ${scheduleId}`); + return null; + } + + const rootStore = useStores(); + const { patientStore } = rootStore; + const scheduledAssessment = patientStore.getScheduledAssessmentById(scheduleId); + + if (!scheduledAssessment) { + console.error(`Scheduled assessment not found by schedule id: ${scheduleId}`); + return null; + } + + const assessmentContent = rootStore.getAssessmentContent(scheduledAssessment?.assessmentId); + + if (!assessmentContent) { + return null; + } + + + const dataState = useLocalObservable<{ adherence: number | undefined, medicationQuestion: boolean, medicationNote: string | undefined }>(() => ({ + adherence: undefined, + medicationQuestion: false, + medicationNote: '', + })); + + const handleAdherence = action((value: number) => { + dataState.adherence = value as number; + }); + + const handleMedicationQuestion = action((event: SelectChangeEvent) => { + dataState.medicationQuestion = event.target.value == "true" ? true : false as boolean; + }); + + const handleMedicationNote = action((event: React.ChangeEvent) => { + dataState.medicationNote = event.target.value; + }); + + const handleSubmit = action(async () => { + const { scheduledAssessmentId, assessmentId } = scheduledAssessment; + try { + const log = { + scheduledAssessmentId, + assessmentId, + patientSubmitted: true, + recordedDateTime: new Date(), + adherence: dataState.adherence, + medicationQuestion: dataState.medicationQuestion, + medicationNote: dataState.medicationQuestion ? dataState.medicationNote : undefined, + } as IAssessmentLog; + await patientStore.saveAssessmentLog(log); + return !patientStore.loadAssessmentLogsState.error; + } catch { + return false; + } + }); + + const getAssessmentPages = () => { + let adherenceQuestion = assessmentContent.questions[0]; + const adherenceQuestionPage = { + content: ( + + ), + canGoNext: dataState.adherence != undefined, + }; + + const medicationQuestionPage = { + content: ( + + + + } label="Yes" /> + } label="No" /> + + + } + /> + {dataState.medicationQuestion && ( + + } + /> + )} + + ), + canGoNext: !dataState.medicationQuestion || (dataState.medicationNote != ''), + }; + + + return [adherenceQuestionPage, medicationQuestionPage]; + }; + + return ( + + ); +}); + +export default MedicationLoggingForm; diff --git a/web_patient/src/components/Home/HomePage.tsx b/web_patient/src/components/Home/HomePage.tsx index ad3720c6..476b8e8f 100644 --- a/web_patient/src/components/Home/HomePage.tsx +++ b/web_patient/src/components/Home/HomePage.tsx @@ -25,6 +25,7 @@ import { getString } from 'src/services/strings'; import { useStores } from 'src/stores/stores'; import { getGreeting } from 'src/utils/schedule'; import styled from 'styled-components'; +import _ from 'lodash'; const CompactList = withTheme( styled(List)((props) => ({ @@ -75,6 +76,7 @@ export const HomePage: FunctionComponent = observer(() => { navigate(`${Routes.resources}/${Routes.valuesInventory}`); }); + return ( {!!rootStore.inspirationalQuote ? ( @@ -122,10 +124,18 @@ export const HomePage: FunctionComponent = observer(() => { + to={ + _.isEqual(assessment.assessmentId, "medication") + ? getFormPath(ParameterValues.form.medicationLog, { + [Parameters.taskId]: assessment.scheduledAssessmentId, + [Parameters.assessmentId]: assessment.assessmentId, + }) + : getFormPath(ParameterValues.form.assessmentLog, { + [Parameters.taskId]: assessment.scheduledAssessmentId, + [Parameters.assessmentId]: assessment.assessmentId, + }) + } + > = observer((props) => { + const { assessmentType } = props; + const navigate = useNavigate(); + const rootStore = useStores(); + const { patientStore } = rootStore; + + const viewState = useLocalObservable<{ selectedLog?: IAssessmentLog; isOpen: boolean }>(() => ({ + selectedLog: undefined, + isOpen: false, + })); + + const handleGoBack = action(() => { + navigate(-1); + }); + + const handleLogClick = action((log: IAssessmentLog) => { + viewState.selectedLog = log; + viewState.isOpen = true; + }); + + const handleClose = action(() => { + viewState.selectedLog = undefined; + viewState.isOpen = false; + }); + + const title = 'Progress_medication_tracking_title'; + const assessmentContent = rootStore.getAssessmentContent(assessmentType); + + const logs = patientStore.assessmentLogs.filter((a) => a.assessmentId.toLowerCase() == assessmentType); + + return ( + + patientStore.loadAssessmentLogs()}> + {logs.length > 0 ? ( + + + + + {getString('Assessment_progress_column_date')} + {getString('Medication_progress_adherence')} + {getString('Medication_progress_note')} + + + + {logs.map((log, idx) => ( + handleLogClick(log)}> + + {`${format(log.recordedDateTime, 'MM/dd')}`} + + {log.adherence == 1 ? 'Yes' : 'No'} + {log.medicationNote} + + ))} + +
+ {viewState.selectedLog && ( + + + + + {getString('Assessment_progress_column_date')} + + {`${ + viewState.selectedLog?.recordedDateTime && + format( + viewState.selectedLog.recordedDateTime, + 'MM/dd/yyyy h:mm aaa', + ) + }`} + + + + {getString('Medication_progress_adherence')} + + + {viewState.selectedLog?.adherence == 1 ? 'Yes' : 'No'} + + + + + {getString('Medication_progress_note')} + + {viewState.selectedLog?.medicationNote} + + + + } + onClose={handleClose} + /> + )} +
+ ) : ( + {getString('Assessment_progress_no_data')} + )} +
+
+ ); +}); + +export default MedicationTrackingHome; diff --git a/web_patient/src/components/Progress/ProgressPage.tsx b/web_patient/src/components/Progress/ProgressPage.tsx index 8cb587be..e7bbddc4 100644 --- a/web_patient/src/components/Progress/ProgressPage.tsx +++ b/web_patient/src/components/Progress/ProgressPage.tsx @@ -40,6 +40,12 @@ export const ProgressPage: FunctionComponent = () => { imageSrc={getImage('Progress_mood_button_image')} />
+ + +
diff --git a/web_patient/src/services/images.ts b/web_patient/src/services/images.ts index fde31a9a..a248b2dd 100644 --- a/web_patient/src/services/images.ts +++ b/web_patient/src/services/images.ts @@ -8,6 +8,7 @@ import AboutUsImageSrc from 'src/assets/about_us_icon.png'; import CrisisResourcesImageSrc from 'src/assets/crisis_resources_icon.png'; import PhqAssessmentImageSrc from 'src/assets/assessment_phq9_depression.png'; import GadAssessmentImageSrc from 'src/assets/assessment_gad7_anxiety.png'; +import MedicationAssessmentImageSrc from 'src/assets/medication_pill.png'; import LogoutImageSrc from 'src/assets/log_out_icon.png'; const _images = { @@ -23,6 +24,7 @@ const _images = { Progress_activity_button_image: ActivityProgressImageSrc, Progress_assessment_phq_button_image: PhqAssessmentImageSrc, Progress_assessment_gad_button_image: GadAssessmentImageSrc, + Progress_assessment_medication_button_image: MedicationAssessmentImageSrc, Progress_mood_button_image: MoodLoggingImageSrc, }; diff --git a/web_patient/src/services/routes.ts b/web_patient/src/services/routes.ts index cf5143cf..824e8e32 100644 --- a/web_patient/src/services/routes.ts +++ b/web_patient/src/services/routes.ts @@ -13,6 +13,7 @@ export const Routes = { gadProgress: 'gad', activityProgress: 'activities', moodProgress: 'mood', + medicationProgress: 'medication', }; export const Parameters = { @@ -27,19 +28,20 @@ export const Parameters = { export const ParameterValues = { form: { - moodLog: 'log-mood', - assessmentLog: 'log-assessment', activityLog: 'log-activity', addActivity: 'add-activity', addActivitySchedule: 'add-activity-schedule', + assessmentLog: 'log-assessment', editActivity: 'edit-activity', editActivitySchedule: 'edit-activity-schedule', + medicationLog: 'log-medication', + moodLog: 'log-mood', safetyPlan: 'safety-plan', }, addSchedule: { true: 'true', false: 'false', - } + }, }; export const getRouteParameter = (paramName: string) => { diff --git a/web_patient/src/services/strings.ts b/web_patient/src/services/strings.ts index f9673cce..f8f55350 100644 --- a/web_patient/src/services/strings.ts +++ b/web_patient/src/services/strings.ts @@ -51,6 +51,11 @@ const _strings = { Form_mood_submit_success_2_after_link: '.', + Form_medication_logging_medication_question_prompt: 'Do you have questions for your psychosocial care team about any of the medications you are taking?', + Form_medication_logging_medication_note_prompt: 'What question about your medications would you like to ask your phsychosocial team?', + Form_medication_logging_medication_note_subprompt: '(If this is an emergency, please contact your medical team, call 911, or go to the nearest emergency room)', + Form_medication_logging_medication_note_subprompt_helper_text: 'This is a place you can remind yourself of any side effects or other medication questions you would like to discuss with your psychosocial team.', + Form_assessment_checkin_title: 'Check-In', Form_assessment_score_column_name: 'Score', Form_assessment_comment_prompt: 'Do you have any other notes?', @@ -162,6 +167,7 @@ const _strings = { Progress_gad_assessment_title: 'Anxiety Check-In', Progress_activity_tracking_title: 'Activity Tracking', Progress_mood_tracking_title: 'Mood Tracking', + Progress_medication_tracking_title: 'Medication Check-in', Activity_tracking_column_date: 'Date', Activity_tracking_column_name: 'Activity Name', @@ -192,8 +198,12 @@ const _strings = { Assessment_progress_column_comment: 'Note', Assessment_progress_no_data: 'There are no submitted data for this assessment.', + Medication_progress_adherence: 'Took all meds for last 7 days', + Medication_progress_note: 'Question or Comment for Care Team', + Progress_phq_assessment_detail_title: 'Depression Assessment', Progress_gad_assessment_detail_title: 'Anxiety Assessment', + Progress_medication_assessment_detail_title: 'Medication Assessment', Careplan_no_tasks: 'There are no planned activities for this day.', Careplan_view_calendar: 'Calendar View', diff --git a/web_registry/src/components/PatientDetail/MedicationProgress.tsx b/web_registry/src/components/PatientDetail/MedicationProgress.tsx index ee7be59a..b9374604 100644 --- a/web_registry/src/components/PatientDetail/MedicationProgress.tsx +++ b/web_registry/src/components/PatientDetail/MedicationProgress.tsx @@ -43,14 +43,15 @@ export const MedicationProgress: FunctionComponent = o state.openConfigure = false; }); - // const handleConfigure = action(() => { - // state.openConfigure = true; - // state.frequency = assessment.frequency || 'Every 2 weeks'; - // state.dayOfWeek = assessment.dayOfWeek || 'Monday'; - // }); + const handleConfigure = action(() => { + state.openConfigure = true; + state.frequency = assessment.frequency || 'Every 2 weeks'; + state.dayOfWeek = assessment.dayOfWeek || 'Monday'; + }); const onSaveConfigure = action(() => { const { frequency, dayOfWeek } = state; + assessment.assignedDateTime = new Date(); var newAssessment = { ...assessment, frequency, dayOfWeek }; currentPatient.updateAssessment(newAssessment); state.openConfigure = false; @@ -66,15 +67,16 @@ export const MedicationProgress: FunctionComponent = o const sortedLogs = assessmentLogs?.slice().sort((a, b) => compareDesc(a.recordedDateTime, b.recordedDateTime)); + const tableData = sortedLogs?.map((a) => { return { date: format(a.recordedDateTime, 'MM/dd/yy'), adherence: - a.pointValues['Adherence'] == 1 + a.adherence == 1 ? getString('patient_progress_medication_adherence_yes') : getString('patient_progress_medication_adherence_no'), id: a.assessmentLogId, - comment: a.comment, + medicationNote: a.medicationQuestion ? a.medicationNote : undefined, }; }); @@ -96,7 +98,7 @@ export const MedicationProgress: FunctionComponent = o headerAlign: 'center', }, { - field: 'comment', + field: 'medicationNote', headerName: getString('patient_progress_medication_header_comment'), width: 300, flex: 1, @@ -108,9 +110,9 @@ export const MedicationProgress: FunctionComponent = o const recurrence = assessment.assigned && assessment.assignedDateTime ? `${assessment.frequency} on ${assessment.dayOfWeek}s, assigned on ${format( - assessment.assignedDateTime, - 'MM/dd/yyyy', - )}` + assessment.assignedDateTime, + 'MM/dd/yyyy', + )}` : 'Not assigned'; return ( @@ -126,21 +128,19 @@ export const MedicationProgress: FunctionComponent = o text: assessment.assigned ? getString('patient_progress_assessment_assigned_button') : getString('patient_progress_assessment_assign_button'), - // Temporarily disable assignment - // onClick: assessment.assigned - // ? undefined - // : () => currentPatient?.assignAssessment(assessment.assessmentId), + onClick: assessment.assigned + ? undefined + : () => currentPatient?.assignAssessment(assessment.assessmentId), } as IActionButton, ].concat( assessment.assigned ? [ - { - icon: , - text: getString('patient_progress_assessment_action_configure'), - // Temporarily disable assignment - // onClick: handleConfigure, - } as IActionButton, - ] + { + icon: , + text: getString('patient_progress_assessment_action_configure'), + onClick: handleConfigure, + } as IActionButton, + ] : [], )}> diff --git a/web_shared/types.ts b/web_shared/types.ts index 71d07430..3cfde83a 100644 --- a/web_shared/types.ts +++ b/web_shared/types.ts @@ -184,6 +184,11 @@ export interface IAssessmentLog extends ILog { submittedByProviderId?: string; pointValues: AssessmentData; totalScore?: number; + + // For mediation tracking + adherence?: number; + medicationQuestion?: boolean; + medicationNote?: string; } export interface IMoodLog extends ILog {