From d5d20513c20363512672173425683e1b8678c9f8 Mon Sep 17 00:00:00 2001 From: Jacob John Jeevan Date: Tue, 4 Mar 2025 00:46:13 +0530 Subject: [PATCH 1/4] add patient questionnaire - org --- public/locale/en.json | 6 ++++ src/Routers/routes/ConsultationRoutes.tsx | 3 ++ .../Patient/EncounterQuestionnaire.tsx | 6 ++-- .../PatientDetailsTab/patientUpdates.tsx | 9 +++++- .../Questionnaire/QuestionRenderer.tsx | 2 +- .../QuestionTypes/QuestionGroup.tsx | 2 +- .../QuestionTypes/QuestionInput.tsx | 31 +++++++------------ .../Questionnaire/QuestionnaireForm.tsx | 2 +- 8 files changed, 34 insertions(+), 27 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index 9d6df393904..7f91f01a7b6 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -285,6 +285,7 @@ "active_location_cannot_be_in_future": "Active location cannot be in the future", "active_prescriptions": "Active Prescriptions", "add": "Add", + "add_another": "Add Another", "add_another_session": "Add another session", "add_as": "Add as", "add_attachments": "Add Attachments", @@ -1885,10 +1886,15 @@ "quantity_requested": "Quantity Requested", "quantity_required": "Quantity Required", "questionnaire": "Questionnaire", + "questionnaire_diagnosis_no_encounter": "Diagnosis cannot be recorded without an active encounter", "questionnaire_error_loading": "Error loading questionnaire", + "questionnaire_medication_request_no_encounter": "Medication requests cannot be recorded without an active encounter", + "questionnaire_medication_statement_no_encounter": "Medication statements cannot be recorded without an active encounter", + "questionnaire_no_encounter": "Create an encounter first in order to update it", "questionnaire_not_exist": "The questionnaire you tried to access does not exist.", "questionnaire_submission_failed": "Failed to submit questionnaire", "questionnaire_submitted_successfully": "Questionnaire submitted successfully", + "questionnaire_symptom_no_encounter": "Symptoms cannot be recorded without an active encounter", "questionnaires": "Questionnaires", "quick_access": "Quick Access", "quick_actions": "Quick Actions", diff --git a/src/Routers/routes/ConsultationRoutes.tsx b/src/Routers/routes/ConsultationRoutes.tsx index 080b90a0a54..3e86b59bb49 100644 --- a/src/Routers/routes/ConsultationRoutes.tsx +++ b/src/Routers/routes/ConsultationRoutes.tsx @@ -87,6 +87,9 @@ const consultationRoutes: AppRoutes = { subjectType="patient" /> ), + "/patient/:patientId/questionnaire": ({ patientId }) => ( + + ), }; export default consultationRoutes; diff --git a/src/components/Patient/EncounterQuestionnaire.tsx b/src/components/Patient/EncounterQuestionnaire.tsx index 10799afe296..cebcacc094e 100644 --- a/src/components/Patient/EncounterQuestionnaire.tsx +++ b/src/components/Patient/EncounterQuestionnaire.tsx @@ -15,7 +15,7 @@ import query from "@/Utils/request/query"; import { formatDateTime } from "@/Utils/utils"; interface Props { - facilityId: string; + facilityId?: string; patientId: string; encounterId?: string; questionnaireSlug?: string; @@ -34,7 +34,7 @@ export default function EncounterQuestionnaire({ queryKey: ["encounter", encounterId], queryFn: query(routes.encounter.get, { pathParams: { id: encounterId ?? "" }, - queryParams: { facility: facilityId }, + queryParams: { facility: facilityId! }, }), enabled: !!encounterId, }); @@ -72,7 +72,7 @@ export default function EncounterQuestionnaire({ encounterId={encounterId} questionnaireSlug={questionnaireSlug} onSubmit={() => { - if (encounterId) { + if (encounterId && facilityId) { navigate( `/facility/${facilityId}/patient/${patientId}/encounter/${encounterId}/updates`, ); diff --git a/src/components/Patient/PatientDetailsTab/patientUpdates.tsx b/src/components/Patient/PatientDetailsTab/patientUpdates.tsx index 5ca27e7d507..888c8dda3f3 100644 --- a/src/components/Patient/PatientDetailsTab/patientUpdates.tsx +++ b/src/components/Patient/PatientDetailsTab/patientUpdates.tsx @@ -1,11 +1,12 @@ import { useQuery } from "@tanstack/react-query"; -import { useQueryParams } from "raviger"; +import { Link, useQueryParams } from "raviger"; import { useTranslation } from "react-i18next"; import { cn } from "@/lib/utils"; import CareIcon from "@/CAREUI/icons/CareIcon"; +import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; import PaginationComponent from "@/components/Common/Pagination"; @@ -41,6 +42,12 @@ export const Updates = (props: PatientProps) => {

{t("updates")}

+
diff --git a/src/components/Questionnaire/QuestionRenderer.tsx b/src/components/Questionnaire/QuestionRenderer.tsx index 4b149dfd4b6..b2fd7b0d341 100644 --- a/src/components/Questionnaire/QuestionRenderer.tsx +++ b/src/components/Questionnaire/QuestionRenderer.tsx @@ -29,7 +29,7 @@ interface QuestionRendererProps { disabled?: boolean; activeGroupId?: string; encounterId?: string; - facilityId: string; + facilityId?: string; patientId: string; } diff --git a/src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx b/src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx index 37c95e324c6..3c4e4815f46 100644 --- a/src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx +++ b/src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx @@ -26,7 +26,7 @@ interface QuestionGroupProps { clearError: (questionId: string) => void; disabled?: boolean; activeGroupId?: string; - facilityId: string; + facilityId?: string; patientId: string; } diff --git a/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx b/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx index f23073636d9..90a99efc115 100644 --- a/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx +++ b/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx @@ -1,3 +1,5 @@ +import { useTranslation } from "react-i18next"; + import { cn } from "@/lib/utils"; import CareIcon from "@/CAREUI/icons/CareIcon"; @@ -39,7 +41,7 @@ interface QuestionInputProps { errors: QuestionValidationError[]; clearError: () => void; disabled?: boolean; - facilityId: string; + facilityId?: string; patientId: string; } @@ -54,6 +56,7 @@ export function QuestionInput({ facilityId, patientId, }: QuestionInputProps) { + const { t } = useTranslation(); const questionnaireResponse = questionnaireResponses.find( (v) => v.question_id === question.id, ); @@ -124,10 +127,7 @@ export function QuestionInput({ ); } return ( - - Medication requests cannot be recorded without an active - encounter - + {t("questionnaire_medication_request_no_encounter")} ); case "medication_statement": if (encounterId) { @@ -140,8 +140,7 @@ export function QuestionInput({ } return ( - Medication statement cannot be recorded without an active - encounter + {t("questionnaire_medication_statement_no_encounter")} ); case "allergy_intolerance": @@ -156,24 +155,18 @@ export function QuestionInput({ /> ); } - return ( - Symptoms cannot be recorded without an encounter - ); + return {t("questionnaire_symptom_no_encounter")}; case "diagnosis": if (encounterId) { return ( ); } - return ( - - Diagnosis cannot be recorded without an active encounter - - ); + return {t("questionnaire_diagnosis_no_encounter")}; case "appointment": return ; case "encounter": - if (encounterId) { + if (encounterId && facilityId) { return ( ); } - return ( - Create an encounter first in order to update it - ); + return {t("questionnaire_no_encounter")}; } return null; @@ -270,7 +261,7 @@ export function QuestionInput({ disabled={disabled} > - Add Another + {t("add_another")} void; onCancel?: () => void; - facilityId: string; + facilityId?: string; } export function QuestionnaireForm({ From 2d56a6caafadf66e2537eb958355c392eac3205c Mon Sep 17 00:00:00 2001 From: Jacob John Jeevan Date: Wed, 5 Mar 2025 12:33:22 +0530 Subject: [PATCH 2/4] fixes for patient questionnaire --- src/Routers/routes/ConsultationRoutes.tsx | 2 ++ src/components/Questionnaire/QuestionnaireForm.tsx | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Routers/routes/ConsultationRoutes.tsx b/src/Routers/routes/ConsultationRoutes.tsx index 3e86b59bb49..9c77376a072 100644 --- a/src/Routers/routes/ConsultationRoutes.tsx +++ b/src/Routers/routes/ConsultationRoutes.tsx @@ -29,6 +29,7 @@ const consultationRoutes: AppRoutes = { facilityId={facilityId} encounterId={encounterId} patientId={patientId} + subjectType="encounter" /> ), "/facility/:facilityId/patient/:patientId/encounter/:encounterId/questionnaire/:slug": @@ -38,6 +39,7 @@ const consultationRoutes: AppRoutes = { encounterId={encounterId} questionnaireSlug={slug} patientId={patientId} + subjectType="encounter" /> ), "/facility/:facilityId/patient/:patientId/encounter/:encounterId/questionnaire_response/:id": diff --git a/src/components/Questionnaire/QuestionnaireForm.tsx b/src/components/Questionnaire/QuestionnaireForm.tsx index da1180f8eee..4ed1926462e 100644 --- a/src/components/Questionnaire/QuestionnaireForm.tsx +++ b/src/components/Questionnaire/QuestionnaireForm.tsx @@ -294,7 +294,7 @@ export function QuestionnaireForm({ method: "POST", reference_id: form.questionnaire.id, body: { - resource_id: encounterId, + resource_id: encounterId ? encounterId : patientId, encounter: encounterId, patient: patientId, results: nonStructuredResponses From 587d8231fea54907bc605a48738cb5a3d951d481 Mon Sep 17 00:00:00 2001 From: Jacob John Jeevan Date: Thu, 6 Mar 2025 12:51:53 +0530 Subject: [PATCH 3/4] switched to using questionnaireresponselist for updates --- .../QuestionnaireResponsesList.tsx | 27 +++- .../Patient/PatientDetailsTab/index.tsx | 3 +- .../PatientDetailsTab/patientUpdates.tsx | 133 ------------------ 3 files changed, 25 insertions(+), 138 deletions(-) delete mode 100644 src/components/Patient/PatientDetailsTab/patientUpdates.tsx diff --git a/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx b/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx index c6fc5667222..4f9c245594a 100644 --- a/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx +++ b/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx @@ -1,11 +1,14 @@ import { useQuery } from "@tanstack/react-query"; import { t } from "i18next"; -import { useQueryParams } from "raviger"; +import { Link, useQueryParams } from "raviger"; import { Trans, useTranslation } from "react-i18next"; import { cn } from "@/lib/utils"; +import CareIcon from "@/CAREUI/icons/CareIcon"; + import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; @@ -25,6 +28,7 @@ import { QuestionnaireResponse } from "@/types/questionnaire/questionnaireRespon interface Props { encounter?: Encounter; patientId: string; + facilityId?: string; isPrintPreview?: boolean; onlyUnstructured?: boolean; } @@ -293,8 +297,8 @@ function ResponseCard({ } export default function QuestionnaireResponsesList({ - encounter, patientId, + facilityId, isPrintPreview = false, onlyUnstructured, }: Props) { @@ -310,8 +314,8 @@ export default function QuestionnaireResponsesList({ limit: RESULTS_PER_PAGE_LIMIT, offset: ((qParams.page ?? 1) - 1) * RESULTS_PER_PAGE_LIMIT, }), - encounter: encounter?.id, only_unstructured: onlyUnstructured, + subject_type: "patient", }, maxPages: isPrintPreview ? undefined : 1, pageSize: isPrintPreview ? 100 : RESULTS_PER_PAGE_LIMIT, @@ -321,6 +325,23 @@ export default function QuestionnaireResponsesList({ return (
+
+
+ {t("updates")} +
+ +
{isLoading ? (
diff --git a/src/components/Patient/PatientDetailsTab/index.tsx b/src/components/Patient/PatientDetailsTab/index.tsx index 975b54158cb..7fdf223a052 100644 --- a/src/components/Patient/PatientDetailsTab/index.tsx +++ b/src/components/Patient/PatientDetailsTab/index.tsx @@ -2,7 +2,6 @@ import QuestionnaireResponsesList from "@/components/Facility/ConsultationDetail import EncounterHistory from "@/components/Patient/PatientDetailsTab//EncounterHistory"; import { HealthProfileSummary } from "@/components/Patient/PatientDetailsTab//HealthProfileSummary"; import { Demography } from "@/components/Patient/PatientDetailsTab/Demography"; -import { Updates } from "@/components/Patient/PatientDetailsTab/patientUpdates"; import { Patient } from "@/types/emr/newPatient"; @@ -32,7 +31,7 @@ export const patientTabs = [ }, { route: "updates", - component: Updates, + component: QuestionnaireResponsesList, }, { route: "resource_requests", diff --git a/src/components/Patient/PatientDetailsTab/patientUpdates.tsx b/src/components/Patient/PatientDetailsTab/patientUpdates.tsx deleted file mode 100644 index 888c8dda3f3..00000000000 --- a/src/components/Patient/PatientDetailsTab/patientUpdates.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import { useQuery } from "@tanstack/react-query"; -import { Link, useQueryParams } from "raviger"; -import { useTranslation } from "react-i18next"; - -import { cn } from "@/lib/utils"; - -import CareIcon from "@/CAREUI/icons/CareIcon"; - -import { Button } from "@/components/ui/button"; -import { Card } from "@/components/ui/card"; - -import PaginationComponent from "@/components/Common/Pagination"; -import { CardListSkeleton } from "@/components/Common/SkeletonLoading"; - -import { RESULTS_PER_PAGE_LIMIT } from "@/common/constants"; - -import routes from "@/Utils/request/api"; -import query from "@/Utils/request/query"; -import { formatDateTime, properCase } from "@/Utils/utils"; -import { QuestionnaireResponse } from "@/types/questionnaire/questionnaireResponse"; - -import { PatientProps } from "."; - -export const Updates = (props: PatientProps) => { - const { patientId } = props; - const { t } = useTranslation(); - - const [qParams, setQueryParams] = useQueryParams<{ page?: number }>(); - - const { data: patientUpdatesData, isLoading } = useQuery({ - queryKey: ["patientUpdates", patientId, qParams], - queryFn: query(routes.getQuestionnaireResponses, { - queryParams: { - limit: RESULTS_PER_PAGE_LIMIT, - offset: ((qParams.page ?? 1) - 1) * RESULTS_PER_PAGE_LIMIT, - }, - pathParams: { patientId }, - }), - }); - - return ( -
-
-

{t("updates")}

- -
-
-
- {isLoading ? ( -
- -
- ) : ( -
- {patientUpdatesData?.results?.length === 0 ? ( - -
- {t("no_update_available")} -
-
- ) : ( -
    - {patientUpdatesData?.results?.map((update) => ( -
  • - -
    - -
    -

    - {update.questionnaire?.title || - structuredResponsesPreview( - update.structured_responses, - )} -

    -
    - - {formatDateTime(update.created_date)} -
    -
    - by {update.created_by?.first_name || ""}{" "} - {update.created_by?.last_name || ""} - {update.created_by?.user_type && - ` (${update.created_by?.user_type})`} -
    -
    -
    -
    -
  • - ))} -
    -
    - RESULTS_PER_PAGE_LIMIT - ? "visible" - : "invisible", - )} - > - setQueryParams({ page })} - /> -
    -
    -
- )} -
- )} -
-
-
- ); -}; - -function structuredResponsesPreview( - structured_responses?: QuestionnaireResponse["structured_responses"], -) { - return Object.keys(structured_responses || {}).map((key) => properCase(key)); -} From 5a3186682869d230d8811fb2cc80b17ad9812e50 Mon Sep 17 00:00:00 2001 From: Jacob John Jeevan Date: Thu, 6 Mar 2025 16:54:08 +0530 Subject: [PATCH 4/4] onSubmit navigation for patient --- src/components/Patient/EncounterQuestionnaire.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/components/Patient/EncounterQuestionnaire.tsx b/src/components/Patient/EncounterQuestionnaire.tsx index 4e5cef5dca4..e35e5daa5d5 100644 --- a/src/components/Patient/EncounterQuestionnaire.tsx +++ b/src/components/Patient/EncounterQuestionnaire.tsx @@ -76,6 +76,10 @@ export default function EncounterQuestionnaire({ navigate( `/facility/${facilityId}/patient/${patientId}/encounter/${encounterId}/updates`, ); + } else if (facilityId) { + navigate( + `/facility/${facilityId}/patient/${patientId}/updates`, + ); } else { navigate(`/patient/${patientId}/updates`); }