diff --git a/public/locale/en.json b/public/locale/en.json index 79525b6771b..cb2bd83e8aa 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -48,6 +48,7 @@ "DOMESTIC_HEALTHCARE_SUPPORT__NO_SUPPORT": "No support", "DOMESTIC_HEALTHCARE_SUPPORT__PAID_CAREGIVER": "Paid caregiver", "ENCOUNTER_TAB__abdm": "ABDM Records", + "ENCOUNTER_TAB__care-plan": "Care Plan", "ENCOUNTER_TAB__feed": "Feed", "ENCOUNTER_TAB__files": "Files", "ENCOUNTER_TAB__medicines": "Medicines", @@ -282,18 +283,22 @@ "active_encounters": "Active Encounters", "active_files": "Active Files", "active_prescriptions": "Active Prescriptions", + "activities": "Activities", "add": "Add", + "add_activity": "Add Activity", "add_another_session": "Add another session", "add_as": "Add as", "add_attachments": "Add Attachments", "add_beds": "Add Bed(s)", "add_beds_to_configure_presets": "Add beds to this location to configure presets for them.", + "add_care_plan": "Add Care Plan", "add_consultation": "Add consultation", "add_consultation_update": "Add Consultation Update", "add_details_of_patient": "Add Details of Patient", "add_exception": "Add Exception", "add_facility": "Add Facility", "add_files": "Add Files", + "add_goal": "Add Goal", "add_insurance_details": "Add Insurance Details", "add_location": "Add Location", "add_location_description": "Create a Location such as Rooms/Beds", @@ -318,6 +323,7 @@ "add_skill": "Add Skill", "add_spoke": "Add Spoke Facility", "add_tags": "Add Tags", + "add_target": "Add Target", "add_user": "Add User", "additional_information": "Additional Information", "additional_instructions": "Additional Instructions", @@ -493,6 +499,10 @@ "care": "CARE", "care_backend": "Care Backend", "care_frontend": "Care Frontend", + "care_plan": "Care Plan", + "care_plan_goal": "Care Plan Goal", + "careplan_intent": "Care Plan Intent", + "careplan_status": "Care Plan Status", "category": "Category", "category_description": "Choose the category that best describes the resource needed.", "caution": "Caution", @@ -899,6 +909,7 @@ "encounter_suggestion__R": "Consultation", "encounter_suggestion_edit_disallowed": "Not allowed to switch to this option in edit consultation", "encounters": "Encounters", + "end_date": "End Date", "end_datetime": "End Date/Time", "end_dose": "End Dose", "end_time": "End Time", @@ -1044,6 +1055,7 @@ "getting_location": "Getting Location...", "go_back": "Go Back", "goal": "Our goal is to continuously improve the quality and accessibility of public healthcare services using digital tools.", + "goals": "Goals", "granted_on": "Granted On", "has_allergies": "Has Allergies", "has_child_locations": "Has child locations", @@ -1174,6 +1186,7 @@ "license": "License", "licenses_description": "Third-party software is used in Care, including the respective licenses and versions.", "licenses_title": "Third-Party Software and Licenses", + "lifecycle_status": "Lifecycle Status", "link_abha_number": "Link ABHA Number", "link_abha_profile": "Link ABHA Profile", "link_camera_and_bed": "Link bed to Camera", @@ -1532,6 +1545,7 @@ "patients": "Patients", "patients_per_slot": "Patients per Slot", "pending": "Pending", + "performed": "Performed", "permanant_address_is_required": "Permanant address is required", "permanent_address": "Permanent Address", "permission_denied": "You do not have permission to perform this action", @@ -2012,6 +2026,8 @@ "tag_slug": "Tag Slug", "taper_titrate_dosage": "Taper & Titrate Dosage", "target_dosage": "Target Dosage", + "targets": "Targets", + "task": "Task", "template_deleted": "Template has been deleted", "test_type": "Type of test done", "tested_on": "Tested on", diff --git a/src/Routers/routes/ConsultationRoutes.tsx b/src/Routers/routes/ConsultationRoutes.tsx index 41fee1a8479..2beb93bb1a9 100644 --- a/src/Routers/routes/ConsultationRoutes.tsx +++ b/src/Routers/routes/ConsultationRoutes.tsx @@ -3,6 +3,8 @@ import EncounterQuestionnaire from "@/components/Patient/EncounterQuestionnaire" import FileUploadPage from "@/components/Patient/FileUploadPage"; import { AppRoutes } from "@/Routers/AppRouter"; +import CarePlan from "@/pages/CarePlan/CarePlan"; +import CarePlanGoalPage from "@/pages/CarePlan/CarePlanGoalPage"; import { EncounterShow } from "@/pages/Encounters/EncounterShow"; import { PrintPrescription } from "@/pages/Encounters/PrintPrescription"; @@ -75,6 +77,26 @@ const consultationRoutes: AppRoutes = { type="encounter" /> ), + "/facility/:facilityId/encounter/:encounterId/care-plan/:careplanId": ({ + facilityId, + encounterId, + careplanId, + }) => ( + + ), + "/facility/:facilityId/encounter/:encounterId/care-plan/:careplanId/goal/:goalId": + ({ facilityId, encounterId, careplanId, goalId }) => ( + + ), }; export default consultationRoutes; diff --git a/src/components/Questionnaire/QuestionTypes/CarePlanQuestion.tsx b/src/components/Questionnaire/QuestionTypes/CarePlanQuestion.tsx new file mode 100644 index 00000000000..034fa61cef1 --- /dev/null +++ b/src/components/Questionnaire/QuestionTypes/CarePlanQuestion.tsx @@ -0,0 +1,1067 @@ +import { DotsVerticalIcon, MinusCircledIcon } from "@radix-ui/react-icons"; +import { useTranslation } from "react-i18next"; + +import { Button } from "@/components/ui/button"; +import { DateRangePicker } from "@/components/ui/date-range-picker"; +import { DateTimePicker } from "@/components/ui/date-time-picker"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Switch } from "@/components/ui/switch"; +import { Textarea } from "@/components/ui/textarea"; + +import { + ActivityRequest, + CARE_PLAN_INTENT, + CARE_PLAN_LIFECYCLE_STATUS, + CARE_PLAN_STATUS, + CARE_PLAN_TASK_INTENT, + CARE_PLAN_TASK_PRIORITY, + CARE_PLAN_TASK_STATUS, + CarePlanGoalRequest, + CarePlanRequest, + GoalTarget, + GoalUpdate, + TaskRequest, +} from "@/types/emr/careplan/careplan"; +import { + QuestionnaireResponse, + ResponseValue, +} from "@/types/questionnaire/form"; +import { Question } from "@/types/questionnaire/question"; + +interface CarePlanQuestionProps { + question: Question; + questionnaireResponse: QuestionnaireResponse; + updateQuestionnaireResponseCB: ( + values: ResponseValue[], + questionId: string, + note?: string, + ) => void; + disabled?: boolean; + encounterId?: string; + patientId: string; + facilityId: string; +} + +const sampleCodes = [ + { + code: "8480-6", + system: "http://loinc.org", + display: "Systolic", + }, + { + code: "8462-4", + system: "http://loinc.org", + display: "Diastolic", + }, + { + code: "8867-4", + system: "http://loinc.org", + display: "Pulse", + }, + { + code: "8310-5", + system: "http://loinc.org", + display: "Temperature", + }, + { + code: "9279-1", + system: "http://loinc.org", + display: "Respiratory Rate", + }, +]; + +const sampleTasks = [ + { + code: "1", + system: "http://example.com", + display: "Take medication", + }, + { + code: "2", + system: "http://example.com", + display: "Check blood pressure", + }, + { + code: "3", + system: "http://example.com", + display: "Check temperature", + }, + { + code: "4", + system: "http://example.com", + display: "Check pulse", + }, +]; + +export default function CarePlanQuestion({ + questionnaireResponse, + updateQuestionnaireResponseCB, + disabled, + patientId, + encounterId, + facilityId, +}: CarePlanQuestionProps) { + const { t } = useTranslation(); + const careplans = + (questionnaireResponse.values?.[0] + ?.value as unknown as CarePlanRequest[]) || []; + + const handleUpdate = (index: number, updates: Partial) => { + const newCarePlans = careplans.map((careplan, i) => + i === index ? { ...careplan, ...updates } : careplan, + ); + + updateQuestionnaireResponseCB( + [{ type: "care_plan", value: newCarePlans }], + questionnaireResponse.question_id, + ); + }; + + const handleGoalUpdate = ( + cpIndex: number, + index: number, + updates: Partial, + ) => { + const newCarePlans = careplans.map((careplan, i) => + i === cpIndex + ? { + ...careplan, + goals: careplan.goals?.map((goal, j) => + j === index ? { ...goal, ...updates } : goal, + ), + } + : careplan, + ); + + updateQuestionnaireResponseCB( + [{ type: "care_plan", value: newCarePlans }], + questionnaireResponse.question_id, + ); + }; + + const handleActivityUpdate = ( + cpIndex: number, + index: number, + updates: Partial, + ) => { + const newCarePlans = careplans.map((careplan, i) => + i === cpIndex + ? { + ...careplan, + activities: careplan.activities?.map((activity, j) => + j === index ? { ...activity, ...updates } : activity, + ), + } + : careplan, + ); + + updateQuestionnaireResponseCB( + [{ type: "care_plan", value: newCarePlans }], + questionnaireResponse.question_id, + ); + }; + + const handleGoalTargetUpdate = ( + cpIndex: number, + goalIndex: number, + index: number, + updates: Partial, + ) => { + const newCarePlans = careplans.map((careplan, i) => + i === cpIndex + ? { + ...careplan, + goals: careplan.goals?.map((goal, j) => + j === goalIndex + ? { + ...goal, + target: goal.target?.map((target, k) => + k === index ? { ...target, ...updates } : target, + ), + } + : goal, + ), + } + : careplan, + ); + + updateQuestionnaireResponseCB( + [{ type: "care_plan", value: newCarePlans }], + questionnaireResponse.question_id, + ); + }; + + const handleGoalUpdateUpdate = ( + cpIndex: number, + goalIndex: number, + index: number, + updates: Partial, + ) => { + const newCarePlans = careplans.map((careplan, i) => + i === cpIndex + ? { + ...careplan, + goals: careplan.goals?.map((goal, j) => + j === goalIndex + ? { + ...goal, + updates: goal.updates?.map((update, k) => + k === index ? { ...update, ...updates } : update, + ), + } + : goal, + ), + } + : careplan, + ); + + updateQuestionnaireResponseCB( + [{ type: "care_plan", value: newCarePlans }], + questionnaireResponse.question_id, + ); + }; + + const handleGoalUpdateValueUpdate = ( + cpIndex: number, + goalIndex: number, + updateIndex: number, + index: number, + updates: Partial, + ) => { + const newCarePlans = careplans.map((careplan, i) => + i === cpIndex + ? { + ...careplan, + goals: careplan.goals?.map((goal, j) => + j === goalIndex + ? { + ...goal, + updates: goal.updates?.map((update, k) => + k === updateIndex + ? { + ...update, + values: update.values.map((value, l) => + l === index ? { ...value, ...updates } : value, + ), + } + : update, + ), + } + : goal, + ), + } + : careplan, + ); + + updateQuestionnaireResponseCB( + [{ type: "care_plan", value: newCarePlans }], + questionnaireResponse.question_id, + ); + }; + + return ( +
+
+ {careplans.map((careplan, i) => ( +
+
+ + + + + + { + const newCarePlans = careplans.filter((_, j) => j !== i); + updateQuestionnaireResponseCB( + [{ type: "care_plan", value: newCarePlans }], + questionnaireResponse.question_id, + ); + }} + > + + {t("remove")} + + + +
+
+
+ + handleUpdate(i, { title: e.target.value })} + disabled={disabled} + /> +
+
+
+ + +
+
+ + +
+
+
+ +