Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions scope_shared/scope/schemas/documents/assessment-log.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
}
42 changes: 21 additions & 21 deletions server_flask/app_config/assessments/medication.json
Original file line number Diff line number Diff line change
@@ -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": []
}
2 changes: 2 additions & 0 deletions web_patient/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -42,6 +43,7 @@ export const App: FunctionComponent = () => {
path={`/${Routes.progress}/*`}
element={
<RouterSwitch>
<Route path={`/${Routes.medicationProgress}`} element={<MedicationTrackingHome assessmentType="medication" />} />
<Route path={`/${Routes.moodProgress}`} element={<MoodTrackingHome />} />
<Route path={`/${Routes.activityProgress}`} element={<ActivityTrackingHome />} />
<Route
Expand Down
6 changes: 4 additions & 2 deletions web_patient/src/components/Forms/GetFormDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@ import React, { FunctionComponent } from 'react';
import { ActivityLoggingForm } from 'src/components/Forms/ActivityLoggingForm';
import AddEditActivityForm from 'src/components/Forms/AddEditActivityForm';
import { AssessmentForm } from 'src/components/Forms/AssessmentForm';
import MedicationLoggingForm from 'src/components/Forms/MedicationLoggingForm';
import MoodLoggingForm from 'src/components/Forms/MoodLoggingForm';
import SafetyPlanForm from 'src/components/Forms/SafetyPlanForm';
import { getRouteParameter, Parameters, ParameterValues } from 'src/services/routes';

const formComponents: { [paramName: string]: FunctionComponent<IFormProps> } = {
[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,
};

Expand Down
200 changes: 200 additions & 0 deletions web_patient/src/components/Forms/MedicationLoggingForm.tsx
Original file line number Diff line number Diff line change
@@ -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<IQuestionFormProps> = (props) => {
const { instruction, question, questionId, value, options, onValueChange } = props;
return (
<FormSection
prompt={instruction}
subPrompt={question}
content={
<FormControl component="fieldset">
<RadioGroup
aria-label={questionId}
name={questionId}
value={value == undefined ? '' : value}
onChange={(_, val) => onValueChange(Number(val))}>
{options.map((resp, ridx) => {
return (
<FormControlLabel
key={`${questionId}-${ridx}`}
value={ridx}
control={<Radio />}
label={`${resp.text}`}
/>
);
})}
</RadioGroup>
</FormControl>
}
/>
);
};

export const MedicationLoggingForm: FunctionComponent<IMedicationLoggingFormProps> = 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<boolean>) => {
dataState.medicationQuestion = event.target.value == "true" ? true : false as boolean;
});

const handleMedicationNote = action((event: React.ChangeEvent<HTMLInputElement>) => {
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: (
<QuestionForm
{...assessmentContent}
question={adherenceQuestion.question}
questionId={adherenceQuestion.id}
value={dataState.adherence}
onValueChange={handleAdherence}
/>
),
canGoNext: dataState.adherence != undefined,
};

const medicationQuestionPage = {
content: (
<Stack spacing={4}>
<FormSection
prompt={getString('Form_medication_logging_medication_question_prompt')}
content={
<FormControl>
<RadioGroup
aria-labelledby="medication-prompt-label"
value={dataState.medicationQuestion}
name="medication-prompt-group"
onChange={handleMedicationQuestion}
>
<FormControlLabel value={true} control={<Radio />} label="Yes" />
<FormControlLabel value={false} control={<Radio />} label="No" />
</RadioGroup>
</FormControl>
}
/>
{dataState.medicationQuestion && (
<FormSection
prompt={getString(
'Form_medication_logging_medication_note_prompt'
)}
help={getString('Form_medication_logging_medication_note_subprompt')}
content={
<TextField
fullWidth
value={dataState.medicationNote}
onChange={handleMedicationNote}
variant="outlined"
multiline
rows={5}
helperText={getString('Form_medication_logging_medication_note_subprompt_helper_text')}
/>
}
/>
)}
</Stack>
),
canGoNext: !dataState.medicationQuestion || (dataState.medicationNote != ''),
};


return [adherenceQuestionPage, medicationQuestionPage];
};

return (
<FormDialog
title={`${assessmentContent.name} ${getString('Form_assessment_checkin_title')}`}
isOpen={true}
canClose={true}
loading={patientStore.loadAssessmentLogsState.pending}
pages={getAssessmentPages()}
onSubmit={handleSubmit}
submitToast={getString('Form_assessment_submit_success')}
/>
);
});

export default MedicationLoggingForm;
18 changes: 14 additions & 4 deletions web_patient/src/components/Home/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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) => ({
Expand Down Expand Up @@ -75,6 +76,7 @@ export const HomePage: FunctionComponent = observer(() => {
navigate(`${Routes.resources}/${Routes.valuesInventory}`);
});


return (
<MainPage title={getGreeting(new Date())}>
{!!rootStore.inspirationalQuote ? (
Expand Down Expand Up @@ -122,10 +124,18 @@ export const HomePage: FunctionComponent = observer(() => {
<ListItem
button
component={Link}
to={getFormPath(ParameterValues.form.assessmentLog, {
[Parameters.taskId]: assessment.scheduledAssessmentId,
[Parameters.assessmentId]: assessment.assessmentId,
})}>
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,
})
}
>
<ListItemAvatar>
<Avatar
variant="square"
Expand Down
Loading