diff --git a/.example.env b/.example.env index 79e826ad65f..25056224337 100644 --- a/.example.env +++ b/.example.env @@ -64,4 +64,7 @@ REACT_ALLOWED_LOCALES="en,hi,ta,ml,mr,kn" REACT_DEFAULT_COUNTRY= # Maps fallback URL template (default:"https://www.openstreetmap.org/?mlat={lat}&mlon={long}&zoom=15") -REACT_MAPS_FALLBACK_URL_TEMPLATE= \ No newline at end of file +REACT_MAPS_FALLBACK_URL_TEMPLATE= + +# OTP resend timeout in seconds (eg. 90 seconds) (default : 120 seconds) +REACT_APP_RESEND_OTP_TIMEOUT= \ No newline at end of file diff --git a/care.config.ts b/care.config.ts index 9f646dbab0a..71cbec3e970 100644 --- a/care.config.ts +++ b/care.config.ts @@ -136,6 +136,10 @@ const careConfig = { env.REACT_OBSERVATION_PLOTS_CONFIG_URL || "/config/plots.json", defaultCountry: (env.REACT_DEFAULT_COUNTRY || "IN") as CountryCode, + + resendOtpTimeout: env.REACT_APP_RESEND_OTP_TIMEOUT + ? parseInt(env.REACT_APP_RESEND_OTP_TIMEOUT, 10) + : 30, } as const; export default careConfig; diff --git a/public/locale/en.json b/public/locale/en.json index 7c297c0722c..bf3d28f8eb4 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -232,6 +232,7 @@ "SYSTEM__govt_org_type__corporation": "Corporation", "SYSTEM__govt_org_type__default": "State", "SYSTEM__govt_org_type__district": "District", + "SYSTEM__govt_org_type__district_panchayat": "District Panchayat", "SYSTEM__govt_org_type__grama_panchayat": "Grama Panchayat", "SYSTEM__govt_org_type__local_body": "Local Body", "SYSTEM__govt_org_type__municipality": "Municipality", @@ -285,11 +286,13 @@ "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", "add_beds": "Add Bed(s)", "add_beds_to_configure_presets": "Add beds to this location to configure presets for them.", + "add_condition": "Add Condition", "add_consultation": "Add consultation", "add_consultation_update": "Add Consultation Update", "add_contact_point": "Add Contact Point", @@ -312,6 +315,7 @@ "add_notes_about_diagnosis": "Add notes about the diagnosis...", "add_notes_about_symptom": "Add notes about the symptom...", "add_notes_about_the_allergy": "Add notes about the allergy", + "add_option": "Add Option", "add_organizations": "Add Organizations", "add_patient_updates": "Add Patient Updates", "add_policy": "Add Insurance Policy", @@ -319,12 +323,14 @@ "add_prescription_to_consultation_note": "Add a new prescription to this consultation.", "add_preset": "Add preset", "add_prn_prescription": "Add PRN Prescription", + "add_question": "Add Question", "add_questionnaire": "Add Questionnaire", "add_remarks": "Add remarks", "add_schedule_exceptions": "Add Schedule Exceptions", "add_schedule_exceptions_description": "Configure absences or add availability beyond the regular schedule.", "add_skill": "Add Skill", "add_spoke": "Add Spoke Facility", + "add_sub_question": "Add Sub-Question", "add_tags": "Add Tags", "add_user": "Add User", "added_on": "Added on", @@ -551,6 +557,7 @@ "choose_date_time": "Choose Date and Time", "choose_district": "Choose District", "choose_file": "Upload From Device", + "choose_layout_style": "Choose the layout style that best fits your sub-questions from the available options.", "choose_localbody": "Choose Local Body", "choose_location": "Choose Location", "choose_other_search_type": "Choose other search types", @@ -604,10 +611,16 @@ "click_manage_sub_locations": "Click See Details to manage sub-locations.", "click_manage_sub_locations_mobile": "Click to edit and to manage sub-locations.", "click_on": "Click on", + "clone_questionnaire": "Clone Questionnaire", "close": "Close", "close_scanner": "Close Scanner", "collapse_all": "Collapse All", "collapse_sidebar": "Collapse Sidebar", + "collect": "Collect", + "collect_body_site": "Collect Body Site", + "collect_method": "Collect Method", + "collect_performer": "Collect Performer", + "collect_time": "Collect Time", "combine_files_pdf": "Combine Files To PDF", "comment_added_successfully": "Comment added successfully", "comment_min_length": "Comment Should Contain At Least 1 Character", @@ -875,6 +888,7 @@ "edit_device_description": "Edit the details of the device", "edit_facility": "Edit Facility", "edit_facility_details": "Edit Facility Details", + "edit_form": "Edit Form", "edit_history": "Edit History", "edit_location": "Edit Location", "edit_location_description": "Edit the Location to make any changes", @@ -1506,7 +1520,9 @@ "more_details": "More details", "more_info": "More Info", "morning_slots": "Morning Slots", + "move_down": "Move Down", "move_to_onvif_preset": "Move to an ONVIF Preset", + "move_up": "Move Up", "moving_camera": "Moving Camera", "my_doctors": "My Doctors", "my_organizations": "My Organizations", @@ -1603,6 +1619,7 @@ "no_reason_provided": "No reason provided", "no_records_found": "No Records Found", "no_remarks": "No remarks", + "no_requested_questionnaires_found": "The requested questionnaire could not be found.", "no_resource_requests_found": "No requests found", "no_resources_found": "No resources found", "no_results": "No results", @@ -1680,10 +1697,12 @@ "ordering": "Ordering", "organization": "Organization", "organization_access_help": "Organizations help you manage facilities, users, and resources efficiently. Contact your administrator to get access.", + "organization_added_successfully": "Organization added successfully", "organization_created_successfully": "Organization created successfully", "organization_for_care_support": "Organization for Care Support", "organization_forbidden": "You don't have access to any organizations yet.", "organization_not_found": "No Organizations Found", + "organization_removed_successfully": "Organization removed successfully", "organization_required": "Organization is required", "organizations": "Organizations", "organizations_fetch_error": "Error while fetching organizations", @@ -1867,6 +1886,8 @@ "preset_name_placeholder": "Specify an identifiable name for the new preset", "preset_updated": "Preset updated", "prev_sessions": "Prev Sessions", + "preview": "Preview", + "preview_form": "Preview form", "previous": "Previous", "primary_ph_no": "Primary Ph No.", "primary_phone_no": "Primary ph. no.", @@ -1896,12 +1917,18 @@ "quantity_approved": "Quantity Approved", "quantity_requested": "Quantity Requested", "quantity_required": "Quantity Required", + "question": "Question", + "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_one": "Questionnaire", "questionnaire_other": "Questionnaires", "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", "quick_access": "Quick Access", "quick_actions": "Quick Actions", "quick_actions_description": "Schedule an appointment or create a new encounter", @@ -1960,6 +1987,7 @@ "remove_user_warn": "Are you sure you want to remove {{firstName}} {{lastName}} from this organization? This action cannot be undone.", "rename": "Rename", "rename_file": "Rename File", + "repeatable": "Repeatable", "replace_home_facility": "Replace Home Facility", "replace_home_facility_confirm": "Are you sure you want to replace", "replace_home_facility_confirm_as": "as home facility for user", @@ -1993,6 +2021,7 @@ "rescheduled": "Rescheduled", "rescheduling": "Rescheduling...", "resend_otp": "Resend OTP", + "resend_otp_timer": "Resend OTP in {{time}} seconds", "reserved": "Reserved", "reset": "Reset", "reset_password": "Reset Password", @@ -2287,7 +2316,9 @@ "stream_stop_due_to_inativity": "The live feed will stop streaming due to inactivity", "stream_stopped_due_to_inativity": "The live feed has stopped streaming due to inactivity", "stream_uuid": "Stream UUID", + "structured_type": "Structured Type", "sub_category": "Sub Category", + "sub_questions": "sub-questions", "subject": "Subject", "subject_type": "Subject Type", "submit": "Submit", diff --git a/src/Routers/AppRouter.tsx b/src/Routers/AppRouter.tsx index 2290d192f95..0aafce99685 100644 --- a/src/Routers/AppRouter.tsx +++ b/src/Routers/AppRouter.tsx @@ -86,7 +86,7 @@ export default function AppRouter() { const appPages = useRoutes(routes); const adminPages = useRoutes(AdminRouter); - const sidebarFor = appPages ? SidebarFor.FACILITY : SidebarFor.ADMIN; + const sidebarFor = adminPages ? SidebarFor.ADMIN : SidebarFor.FACILITY; const pages = appPages || adminPages || ; @@ -105,7 +105,7 @@ export default function AppRouter() { )}
diff --git a/src/Routers/routes/ConsultationRoutes.tsx b/src/Routers/routes/ConsultationRoutes.tsx index 080b90a0a54..570667419e0 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,35 +39,37 @@ const consultationRoutes: AppRoutes = { encounterId={encounterId} questionnaireSlug={slug} patientId={patientId} + subjectType="encounter" /> ), + "/facility/:facilityId/patient/:patientId/encounter/:encounterId/questionnaire_response/:id": ({ patientId, id }) => ( ), - "/facility/:facilityId/patient/:patientId/encounter/:encounterId/:tab": ({ - facilityId, - patientId, - encounterId, - tab, - }) => ( - - ), - "/facility/:facilityId/patient/:patientId/encounter/:encounterId/:tab/:subPage": - ({ facilityId, encounterId, patientId, tab, subPage }) => ( + ...["facility", "organization"].reduce((acc: AppRoutes, identifier) => { + acc[`/${identifier}/:id/patient/:patientId/encounter/:encounterId/:tab`] = + ({ id, encounterId, tab, patientId }) => ( + + ); + acc[ + `/${identifier}/:id/patient/:patientId/encounter/:encounterId/:tab/:subPage` + ] = ({ id, encounterId, patientId, tab, subPage }) => ( - ), + ); + return acc; + }, {}), "/facility/:facilityId/patient/:patientId/consultation": ({ facilityId, patientId, @@ -87,6 +90,9 @@ const consultationRoutes: AppRoutes = { subjectType="patient" /> ), + "/patient/:patientId/questionnaire": ({ patientId }) => ( + + ), }; export default consultationRoutes; diff --git a/src/Routers/routes/PatientRoutes.tsx b/src/Routers/routes/PatientRoutes.tsx index 26b2ff4aa38..090061a225a 100644 --- a/src/Routers/routes/PatientRoutes.tsx +++ b/src/Routers/routes/PatientRoutes.tsx @@ -1,7 +1,4 @@ -import { - facilityPatientTabs, - patientTabs, -} from "@/components/Patient/PatientDetailsTab"; +import { patientTabs } from "@/components/Patient/PatientDetailsTab"; import { PatientHome } from "@/components/Patient/PatientHome"; import PatientIndex from "@/components/Patient/PatientIndex"; import PatientRegistration from "@/components/Patient/PatientRegistration"; @@ -34,7 +31,7 @@ const PatientRoutes: AppRoutes = { "/facility/:facilityId/patient/:id": ({ facilityId, id }) => ( ), - ...facilityPatientTabs.reduce((acc: AppRoutes, tab) => { + ...patientTabs.reduce((acc: AppRoutes, tab) => { acc["/facility/:facilityId/patient/:id/" + tab.route] = ({ facilityId, id, diff --git a/src/components/Auth/Login.tsx b/src/components/Auth/Login.tsx index 87eb7c10004..e8b3d128639 100644 --- a/src/components/Auth/Login.tsx +++ b/src/components/Auth/Login.tsx @@ -69,8 +69,14 @@ interface LoginProps { const Login = (props: LoginProps) => { const { signIn, patientLogin, isAuthenticating } = useAuthContext(); - const { reCaptchaSiteKey, urls, stateLogo, customLogo, customLogoAlt } = - careConfig; + const { + reCaptchaSiteKey, + urls, + stateLogo, + customLogo, + customLogoAlt, + resendOtpTimeout, + } = careConfig; const customDescriptionHtml = __CUSTOM_DESCRIPTION_HTML__; const initForm: any = { username: "", @@ -93,6 +99,21 @@ const Login = (props: LoginProps) => { const [otp, setOtp] = useState(""); const [otpError, setOtpError] = useState(""); const [otpValidationError, setOtpValidationError] = useState(""); + const [resendOtpCountdown, setResendOtpCountdown] = + useState(resendOtpTimeout); + + // Timer Function for resend OTP + useEffect(() => { + if (resendOtpCountdown <= 0) { + return; + } + + const timer = setInterval(() => { + setResendOtpCountdown((prevTime) => prevTime - 1); + }, 1000); + + return () => clearInterval(timer); + }, []); // Remember the last login mode useEffect(() => { @@ -272,6 +293,7 @@ const Login = (props: LoginProps) => { if (!isOtpSent) { sendOtp({ phone_number: phone }); + setResendOtpCountdown(resendOtpTimeout); } else { verifyOtp({ phone_number: phone, otp }); } @@ -673,6 +695,28 @@ const Login = (props: LoginProps) => { t("send_otp") )} + {isOtpSent && + (resendOtpCountdown <= 0 ? ( +
+ +
+ ) : ( +

+ {t("resend_otp_timer", { + time: resendOtpCountdown, + })} +

+ ))} diff --git a/src/components/Common/FilePreviewDialog.tsx b/src/components/Common/FilePreviewDialog.tsx index 7aaabf84dd5..ea03c164153 100644 --- a/src/components/Common/FilePreviewDialog.tsx +++ b/src/components/Common/FilePreviewDialog.tsx @@ -1,6 +1,3 @@ -import { TooltipContent, TooltipTrigger } from "@radix-ui/react-tooltip"; -import { TooltipProvider } from "@radix-ui/react-tooltip"; -import { Tooltip } from "@radix-ui/react-tooltip"; import { Dispatch, ReactNode, @@ -24,6 +21,7 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; +import { TooltipComponent } from "@/components/ui/tooltip"; import CircularProgress from "@/components/Common/CircularProgress"; import { FileUploadModel } from "@/components/Patient/models"; @@ -191,20 +189,11 @@ const FilePreviewDialog = (props: FilePreviewProps) => { <>
- - - -

- {fileNameTooltip} -

-
- -

- {fileName} -

-
-
-
+ +

+ {fileNameTooltip} +

+
{uploadedFiles && uploadedFiles[index] && uploadedFiles[index].created_date && ( diff --git a/src/components/Encounter/EncounterActions.tsx b/src/components/Encounter/EncounterActions.tsx new file mode 100644 index 00000000000..5919290ddfc --- /dev/null +++ b/src/components/Encounter/EncounterActions.tsx @@ -0,0 +1,202 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { Link } from "raviger"; +import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; + +import { cn } from "@/lib/utils"; + +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog"; +import { Button, buttonVariants } from "@/components/ui/button"; +import { DropdownMenuItem } from "@/components/ui/dropdown-menu"; + +import { PLUGIN_Component } from "@/PluginEngine"; +import routes from "@/Utils/request/api"; +import mutate from "@/Utils/request/mutate"; +import { Encounter, completedEncounterStatus } from "@/types/emr/encounter"; + +interface EncounterActionsProps { + encounter: Encounter; + variant?: "default" | "outline" | "ghost"; + size?: "default" | "sm" | "lg" | "icon"; + disableButtons?: boolean; + className?: string; + layout?: "dropdown" | "standalone"; +} + +export default function EncounterActions({ + encounter, + variant = "outline", + size = "default", + disableButtons = false, + className, + layout = "standalone", +}: EncounterActionsProps) { + const { t } = useTranslation(); + const queryClient = useQueryClient(); + + const { mutate: updateEncounter } = useMutation({ + mutationFn: mutate(routes.encounter.update, { + pathParams: { id: encounter.id }, + }), + onSuccess: () => { + toast.success(t("encounter_marked_as_complete")); + queryClient.invalidateQueries({ queryKey: ["encounter", encounter.id] }); + }, + onError: () => { + toast.error(t("error_updating_encounter")); + }, + }); + + const handleMarkAsComplete = () => { + updateEncounter({ + ...encounter, + status: "completed", + organizations: encounter.organizations.map((org) => org.id), + patient: encounter.patient.id, + encounter_class: encounter.encounter_class, + period: encounter.period, + hospitalization: encounter.hospitalization, + priority: encounter.priority, + external_identifier: encounter.external_identifier, + facility: encounter.facility.id, + }); + }; + + if (completedEncounterStatus.includes(encounter.status) || disableButtons) { + return null; + } + + const ActionItems = () => { + if (layout === "dropdown") { + return ( + <> + + + {t("treatment_summary")} + + + + + {t("discharge_summary")} + + + + + e.preventDefault()}> + {t("mark_as_complete")} + + + + + {t("mark_as_complete")} + + {t("mark_encounter_as_complete_confirmation")} + + + + + + + {t("cancel")} + + {t("mark_as_complete")} + + + + + + ); + } + + return ( +
+ + + + + + + + + {t("mark_as_complete")} + + {t("mark_encounter_as_complete_confirmation")} + + + + + + + {t("cancel")} + + {t("mark_as_complete")} + + + + + +
+ ); + }; + + return ActionItems(); +} diff --git a/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx b/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx index c6fc5667222..bba948cfd72 100644 --- a/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx +++ b/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx @@ -25,6 +25,7 @@ import { QuestionnaireResponse } from "@/types/questionnaire/questionnaireRespon interface Props { encounter?: Encounter; patientId: string; + facilityId?: string; isPrintPreview?: boolean; onlyUnstructured?: boolean; } @@ -312,6 +313,7 @@ export default function QuestionnaireResponsesList({ }), encounter: encounter?.id, only_unstructured: onlyUnstructured, + subject_type: encounter ? "encounter" : "patient", }, maxPages: isPrintPreview ? undefined : 1, pageSize: isPrintPreview ? 100 : RESULTS_PER_PAGE_LIMIT, diff --git a/src/components/Facility/ConsultationDetails/QuickAccess.tsx b/src/components/Facility/ConsultationDetails/QuickAccess.tsx index 649bfe6ef8b..6c23a0b90ed 100644 --- a/src/components/Facility/ConsultationDetails/QuickAccess.tsx +++ b/src/components/Facility/ConsultationDetails/QuickAccess.tsx @@ -6,6 +6,7 @@ import CareIcon from "@/CAREUI/icons/CareIcon"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; +import EncounterActions from "@/components/Encounter/EncounterActions"; import LinkDepartmentsSheet from "@/components/Patient/LinkDepartmentsSheet"; import useQuestionnaireOptions from "@/hooks/useQuestionnaireOptions"; @@ -44,6 +45,15 @@ export default function QuickAccess({ encounter }: QuickAccessProps) { )} + {/* Encounter Actions */} +
+

+ {t("actions")} +

+ + +
+ {/* Departments and Teams */}
diff --git a/src/components/Facility/EncounterCard.tsx b/src/components/Facility/EncounterCard.tsx index a9fc72dff59..f20a58d7bee 100644 --- a/src/components/Facility/EncounterCard.tsx +++ b/src/components/Facility/EncounterCard.tsx @@ -16,10 +16,11 @@ import { Encounter, completedEncounterStatus } from "@/types/emr/encounter"; interface EncounterCardProps { encounter: Encounter; + facilityId?: string; } export const EncounterCard = (props: EncounterCardProps) => { - const { encounter } = props; + const { encounter, facilityId } = props; const Icon = encounterIcons[encounter.encounter_class]; @@ -118,7 +119,11 @@ export const EncounterCard = (props: EncounterCardProps) => {
} />
-
+
- -
+ +
- - {t("address")} - - + {t("address")} + {facilityData.address}
-
- +
+ {t("mobile_number")} - +
-
- +
+ {t("location_details")} - + {facilityData.latitude && facilityData.longitude && ( {
- + -
+
{facilityData.geo_organization && renderGeoOrganizations( facilityData.geo_organization, ).map((item, index) => (
- + {item.label} - + {item.value}
@@ -358,7 +372,7 @@ export const FacilityHome = ({ facilityId }: Props) => { FACILITY_FEATURE_TYPES.some((f) => f.id === feature), ) && ( - + {t("features")} @@ -379,7 +393,10 @@ export const FacilityHome = ({ facilityId }: Props) => { {facilityData?.description && ( - + )} diff --git a/src/components/Files/ArchivedFileDialog.tsx b/src/components/Files/ArchivedFileDialog.tsx index ac3eec81e3e..a6b9e29caa4 100644 --- a/src/components/Files/ArchivedFileDialog.tsx +++ b/src/components/Files/ArchivedFileDialog.tsx @@ -7,12 +7,7 @@ import { DialogHeader, DialogTitle, } from "@/components/ui/dialog"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; +import { TooltipComponent } from "@/components/ui/tooltip"; import { FileUploadModel } from "@/components/Patient/models"; @@ -42,16 +37,11 @@ export default function ArchivedFileDialog({ {t("archived_file")}:{" "} - - - - {fileName} - - -

{fileName}

-
-
-
+ + + {fileName} + +
diff --git a/src/components/Files/FilesTab.tsx b/src/components/Files/FilesTab.tsx index 3c1abcbfb45..96702737e08 100644 --- a/src/components/Files/FilesTab.tsx +++ b/src/components/Files/FilesTab.tsx @@ -28,12 +28,7 @@ import { TableRow, } from "@/components/ui/table"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; +import { TooltipComponent } from "@/components/ui/tooltip"; import Loading from "@/components/Common/Loading"; import ArchivedFileDialog from "@/components/Files/ArchivedFileDialog"; @@ -548,18 +543,11 @@ export const FilesTab = (props: FilesTabProps) => { {file.name && file.name.length > 20 ? ( - - - - - {fileName} - - - - {fileName} - - - + + + {fileName} + + ) : ( {fileName} diff --git a/src/components/Medicine/MedicationRequestTable/index.tsx b/src/components/Medicine/MedicationRequestTable/index.tsx index 400a1c5724a..40ea54e20b4 100644 --- a/src/components/Medicine/MedicationRequestTable/index.tsx +++ b/src/components/Medicine/MedicationRequestTable/index.tsx @@ -52,7 +52,6 @@ export const EmptyState = ({ interface Props { readonly?: boolean; - facilityId: string; patientId: string; encounterId: string; } @@ -60,7 +59,6 @@ interface Props { export default function MedicationRequestTable({ patientId, encounterId, - facilityId, }: Props) { const [searchQuery, setSearchQuery] = useState(""); const [showStopped, setShowStopped] = useState(false); @@ -162,9 +160,7 @@ export default function MedicationRequestTable({ className="text-gray-950 hover:text-gray-700 h-9" data-cy="edit-prescription" > - + {t("edit")} @@ -175,9 +171,7 @@ export default function MedicationRequestTable({ size="sm" className="text-gray-950 hover:text-gray-700 h-9" > - + {t("print")} diff --git a/src/components/Patient/EncounterQuestionnaire.tsx b/src/components/Patient/EncounterQuestionnaire.tsx index 0a7eefe1804..5488e40c112 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,13 +34,13 @@ export default function EncounterQuestionnaire({ queryKey: ["encounter", encounterId], queryFn: query(routes.encounter.get, { pathParams: { id: encounterId ?? "" }, - queryParams: { facility: facilityId }, + queryParams: { facility: facilityId! }, }), enabled: !!encounterId, }); return ( -
+
{encounter && (
{ - if (encounterId) { + if (encounterId && facilityId) { navigate( `/facility/${facilityId}/patient/${patientId}/encounter/${encounterId}/updates`, ); + } else if (facilityId) { + navigate( + `/facility/${facilityId}/patient/${patientId}/updates`, + ); } else { navigate(`/patient/${patientId}/updates`); } diff --git a/src/components/Patient/LinkDepartmentsSheet.tsx b/src/components/Patient/LinkDepartmentsSheet.tsx index d3f98027b06..e51f49c7658 100644 --- a/src/components/Patient/LinkDepartmentsSheet.tsx +++ b/src/components/Patient/LinkDepartmentsSheet.tsx @@ -84,25 +84,28 @@ function getInvalidateQueries( return ["location", entityId, "organizations"]; } -export default function LinkDepartmentsSheet({ +function DeleteOrganizationButton({ + organizationId, entityType, entityId, - currentOrganizations, facilityId, - trigger, - onUpdate, -}: Props) { - const [open, setOpen] = useState(false); - const [selectedOrg, setSelectedOrg] = useState(""); + onSuccess, +}: { + organizationId: string; + entityType: "encounter" | "location"; + entityId: string; + facilityId: string; + onSuccess?: () => void; +}) { const queryClient = useQueryClient(); - const { mutate: addOrganization, isPending: isAdding } = useMutation({ + const { mutate: removeOrganization, isPending } = useMutation({ mutationFn: (organizationId: string) => { const { route, pathParams } = getMutationParams( entityType, entityId, facilityId, - true, + false, ); return mutate(route, { pathParams, @@ -110,12 +113,15 @@ export default function LinkDepartmentsSheet({ })({ organization: organizationId }); }, onSuccess: () => { - const invalidateQueries = getInvalidateQueries(entityType, entityId); - queryClient.invalidateQueries({ queryKey: invalidateQueries }); - toast.success("Organization added successfully"); - setSelectedOrg(""); - setOpen(false); - onUpdate?.(); + const { queryKey } = getMutationParams( + entityType, + entityId, + facilityId, + false, + ); + queryClient.invalidateQueries({ queryKey }); + toast.success(t("organization_removed_successfully")); + onSuccess?.(); }, onError: (error) => { const errorData = error.cause as { errors: { msg: string }[] }; @@ -125,13 +131,41 @@ export default function LinkDepartmentsSheet({ }, }); - const { mutate: removeOrganization, isPending: isRemoving } = useMutation({ + return ( + + ); +} + +export default function LinkDepartmentsSheet({ + entityType, + entityId, + currentOrganizations, + facilityId, + trigger, + onUpdate, +}: Props) { + const [open, setOpen] = useState(false); + const [selectedOrg, setSelectedOrg] = useState(""); + const queryClient = useQueryClient(); + + const { mutate: addOrganization, isPending: isAdding } = useMutation({ mutationFn: (organizationId: string) => { const { route, pathParams } = getMutationParams( entityType, entityId, facilityId, - false, + true, ); return mutate(route, { pathParams, @@ -139,14 +173,11 @@ export default function LinkDepartmentsSheet({ })({ organization: organizationId }); }, onSuccess: () => { - const { queryKey } = getMutationParams( - entityType, - entityId, - facilityId, - false, - ); - queryClient.invalidateQueries({ queryKey }); - toast.success("Organization removed successfully"); + const invalidateQueries = getInvalidateQueries(entityType, entityId); + queryClient.invalidateQueries({ queryKey: invalidateQueries }); + toast.success(t("organization_added_successfully")); + setSelectedOrg(""); + setOpen(false); onUpdate?.(); }, onError: (error) => { @@ -215,18 +246,13 @@ export default function LinkDepartmentsSheet({ )}
- +
))} {currentOrganizations.length === 0 && ( diff --git a/src/components/Patient/PatientDetailsTab/Appointments.tsx b/src/components/Patient/PatientDetailsTab/Appointments.tsx index 62d4e138be9..53b445e434d 100644 --- a/src/components/Patient/PatientDetailsTab/Appointments.tsx +++ b/src/components/Patient/PatientDetailsTab/Appointments.tsx @@ -26,13 +26,20 @@ export const Appointments = (props: PatientProps) => { const { patientData, facilityId, patientId } = props; const { t } = useTranslation(); - const { data } = useQuery({ + const { data, isLoading } = useQuery({ queryKey: ["patient-appointments", patientId], - queryFn: query(scheduleApis.appointments.list, { - pathParams: { facility_id: facilityId ?? "" }, - queryParams: { patient: patientId, limit: 100 }, - }), - enabled: !!facilityId, + queryFn: query( + facilityId + ? scheduleApis.appointments.list + : scheduleApis.appointments.getAppointments, + { + pathParams: { + facility_id: facilityId ?? "", + patient_id: patientId, + }, + queryParams: { patient: patientId, limit: 100 }, + }, + ), }); const appointments = data?.results; @@ -64,15 +71,17 @@ export const Appointments = (props: PatientProps) => {

{t("appointments")}

- + {facilityId && ( + + )}
@@ -87,13 +96,13 @@ export const Appointments = (props: PatientProps) => { - {!appointments ? ( + {isLoading ? ( {t("loading")} - ) : appointments.length ? ( + ) : appointments && appointments.length ? ( appointments.map((appointment) => ( diff --git a/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx b/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx index 9fc0119582b..1789b100422 100644 --- a/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx +++ b/src/components/Patient/PatientDetailsTab/EncounterHistory.tsx @@ -104,7 +104,11 @@ const EncounterHistory = (props: PatientProps) => {
    {encounterData?.results?.map((encounter) => (
  • - +
  • ))}
    diff --git a/src/components/Patient/PatientDetailsTab/HealthProfileSummary.tsx b/src/components/Patient/PatientDetailsTab/HealthProfileSummary.tsx index 26573a62045..3ee20bb53e1 100644 --- a/src/components/Patient/PatientDetailsTab/HealthProfileSummary.tsx +++ b/src/components/Patient/PatientDetailsTab/HealthProfileSummary.tsx @@ -26,15 +26,15 @@ export const HealthProfileSummary = (props: PatientProps) => {
    - +
    - +
    - +
diff --git a/src/components/Patient/PatientDetailsTab/index.tsx b/src/components/Patient/PatientDetailsTab/index.tsx index 975b54158cb..05a45162d0d 100644 --- a/src/components/Patient/PatientDetailsTab/index.tsx +++ b/src/components/Patient/PatientDetailsTab/index.tsx @@ -1,8 +1,6 @@ -import QuestionnaireResponsesList from "@/components/Facility/ConsultationDetails/QuestionnaireResponsesList"; 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"; @@ -10,6 +8,7 @@ import { Appointments } from "./Appointments"; import { PatientFilesTab } from "./PatientFiles"; import { PatientUsers } from "./PatientUsers"; import { ResourceRequests } from "./ResourceRequests"; +import { Updates } from "./patientUpdates"; export interface PatientProps { facilityId?: string; @@ -18,37 +17,6 @@ export interface PatientProps { } export const patientTabs = [ - { - route: "demography", - component: Demography, - }, - { - route: "encounters", - component: EncounterHistory, - }, - { - route: "health-profile", - component: HealthProfileSummary, - }, - { - route: "updates", - component: Updates, - }, - { - route: "resource_requests", - component: ResourceRequests, - }, - { - route: "users", - component: PatientUsers, - }, - { - route: "files", - component: PatientFilesTab, - }, -]; - -export const facilityPatientTabs = [ { route: "demography", component: Demography, @@ -67,7 +35,7 @@ export const facilityPatientTabs = [ }, { route: "updates", - component: QuestionnaireResponsesList, + component: Updates, }, { route: "resource_requests", diff --git a/src/components/Patient/PatientDetailsTab/patientUpdates.tsx b/src/components/Patient/PatientDetailsTab/patientUpdates.tsx index 5ca27e7d507..6e387b8e26a 100644 --- a/src/components/Patient/PatientDetailsTab/patientUpdates.tsx +++ b/src/components/Patient/PatientDetailsTab/patientUpdates.tsx @@ -1,126 +1,36 @@ -import { useQuery } from "@tanstack/react-query"; -import { useQueryParams } from "raviger"; +import { Link } from "raviger"; import { useTranslation } from "react-i18next"; -import { cn } from "@/lib/utils"; - import CareIcon from "@/CAREUI/icons/CareIcon"; -import { Card } from "@/components/ui/card"; - -import PaginationComponent from "@/components/Common/Pagination"; -import { CardListSkeleton } from "@/components/Common/SkeletonLoading"; +import { Button } from "@/components/ui/button"; -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 QuestionnaireResponsesList from "@/components/Facility/ConsultationDetails/QuestionnaireResponsesList"; import { PatientProps } from "."; export const Updates = (props: PatientProps) => { - const { patientId } = props; + const { patientId, facilityId } = 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)); -} diff --git a/src/components/Patient/PatientHome.tsx b/src/components/Patient/PatientHome.tsx index 839cc637e2f..637d6ad82fb 100644 --- a/src/components/Patient/PatientHome.tsx +++ b/src/components/Patient/PatientHome.tsx @@ -5,20 +5,12 @@ import { useTranslation } from "react-i18next"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; +import { TooltipComponent } from "@/components/ui/tooltip"; import { Avatar } from "@/components/Common/Avatar"; import Loading from "@/components/Common/Loading"; import Page from "@/components/Common/Page"; -import { - facilityPatientTabs, - patientTabs, -} from "@/components/Patient/PatientDetailsTab"; +import { patientTabs as tabs } from "@/components/Patient/PatientDetailsTab"; import { PLUGIN_Component } from "@/PluginEngine"; import routes from "@/Utils/request/api"; @@ -29,7 +21,7 @@ import { Patient } from "@/types/emr/newPatient"; export const PatientHome = (props: { facilityId?: string; id: string; - page: (typeof patientTabs | typeof facilityPatientTabs)[0]["route"]; + page: (typeof tabs)[0]["route"]; }) => { const { facilityId, id, page } = props; @@ -49,8 +41,6 @@ export const PatientHome = (props: { return ; } - const tabs = facilityId ? facilityPatientTabs : patientTabs; - const Tab = tabs.find((t) => t.route === page)?.component; if (!patientData) { @@ -74,7 +64,7 @@ export const PatientHome = (props: { } > -
+
@@ -198,18 +188,11 @@ export const PatientHome = (props: {
{patientData.modified_date ? ( - - - - - {relativeTime(patientData.modified_date)} - - - - {formatDateTime(patientData.modified_date)} - - - + + {relativeTime(patientData.modified_date)} + ) : ( "--:--" )} @@ -226,18 +209,11 @@ export const PatientHome = (props: {
{patientData.created_date ? ( - - - - - {relativeTime(patientData.created_date)} - - - - {formatDateTime(patientData.created_date)} - - - + + {relativeTime(patientData.created_date)} + ) : ( "--:--" )} diff --git a/src/components/Patient/PatientInfoCard.tsx b/src/components/Patient/PatientInfoCard.tsx index 71c0f1b51a8..81d44f6a34f 100644 --- a/src/components/Patient/PatientInfoCard.tsx +++ b/src/components/Patient/PatientInfoCard.tsx @@ -1,4 +1,3 @@ -import { useMutation, useQueryClient } from "@tanstack/react-query"; import { BedSingle, Building, @@ -10,29 +9,16 @@ import { } from "lucide-react"; import { Link } from "raviger"; import { useTranslation } from "react-i18next"; -import { toast } from "sonner"; import { cn } from "@/lib/utils"; import CareIcon from "@/CAREUI/icons/CareIcon"; -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger, -} from "@/components/ui/alert-dialog"; import { Badge } from "@/components/ui/badge"; -import { Button, buttonVariants } from "@/components/ui/button"; +import { Button } from "@/components/ui/button"; import { DropdownMenu, DropdownMenuContent, - DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; @@ -43,14 +29,13 @@ import { } from "@/components/ui/popover"; import { Avatar } from "@/components/Common/Avatar"; +import EncounterActions from "@/components/Encounter/EncounterActions"; import { LocationSheet } from "@/components/Location/LocationSheet"; import { LocationTree } from "@/components/Location/LocationTree"; import LinkDepartmentsSheet from "@/components/Patient/LinkDepartmentsSheet"; import { PLUGIN_Component } from "@/PluginEngine"; import dayjs from "@/Utils/dayjs"; -import routes from "@/Utils/request/api"; -import mutate from "@/Utils/request/mutate"; import { formatDateTime, formatPatientAge } from "@/Utils/utils"; import { Encounter, @@ -70,35 +55,6 @@ export interface PatientInfoCardProps { export default function PatientInfoCard(props: PatientInfoCardProps) { const { patient, encounter, disableButtons = false } = props; const { t } = useTranslation(); - const queryClient = useQueryClient(); - - const { mutate: updateEncounter } = useMutation({ - mutationFn: mutate(routes.encounter.update, { - pathParams: { id: encounter.id }, - }), - onSuccess: () => { - toast.success(t("encounter_marked_as_complete")); - queryClient.invalidateQueries({ queryKey: ["encounter", encounter.id] }); - }, - onError: () => { - toast.error(t("error_updating_encounter")); - }, - }); - - const handleMarkAsComplete = () => { - updateEncounter({ - ...encounter, - status: "completed", - organizations: encounter.organizations.map((org) => org.id), - patient: encounter.patient.id, - encounter_class: encounter.encounter_class, - period: encounter.period, - hospitalization: encounter.hospitalization, - priority: encounter.priority, - external_identifier: encounter.external_identifier, - facility: encounter.facility.id, - }); - }; return ( <> @@ -475,71 +431,22 @@ export default function PatientInfoCard(props: PatientInfoCardProps) { className="flex w-full flex-col gap-3 lg:w-auto 2xl:flex-row" data-cy="update-encounter-button" > - - - - - - - {t("actions")} - - - {t("treatment_summary")} - - - - - {t("discharge_summary")} - - - - e.preventDefault()}> - {t("mark_as_complete")} - - - - - - - - - {t("mark_as_complete")} - - - {t("mark_encounter_as_complete_confirmation")} - - - + + + + + + {t("actions")} + - - - {t("cancel")} - - - {t("mark_as_complete")} - - - - + +
)}
diff --git a/src/components/Patient/allergy/list.tsx b/src/components/Patient/allergy/list.tsx index e65a630de03..17d59af7712 100644 --- a/src/components/Patient/allergy/list.tsx +++ b/src/components/Patient/allergy/list.tsx @@ -50,6 +50,7 @@ interface AllergyListProps { patientId: string; encounterId?: string; className?: string; + readOnly?: boolean; encounterStatus?: Encounter["status"]; } @@ -68,10 +69,10 @@ export const CATEGORY_ICONS: Record = { }; export function AllergyList({ - facilityId, patientId, encounterId, - className, + className = "", + readOnly = false, encounterStatus, }: AllergyListProps) { const [showEnteredInError, setShowEnteredInError] = useState(false); @@ -90,11 +91,7 @@ export function AllergyList({ if (isLoading) { return ( - + @@ -113,11 +110,7 @@ export function AllergyList({ if (!filteredAllergies?.length) { return ( - +

{t("no_allergies_recorded")}

@@ -211,12 +204,7 @@ export function AllergyList({ } return ( - + @@ -282,25 +270,21 @@ export function AllergyList({ } const AllergyListLayout = ({ - facilityId, - patientId, - encounterId, children, className, + readOnly = false, }: { - facilityId?: string; - patientId: string; - encounterId?: string; children: ReactNode; className?: string; + readOnly?: boolean; }) => { return ( {t("allergies")} - {facilityId && encounterId && ( + {!readOnly && ( diff --git a/src/components/Patient/diagnosis/list.tsx b/src/components/Patient/diagnosis/list.tsx index d1efbc8ee53..57294d700cd 100644 --- a/src/components/Patient/diagnosis/list.tsx +++ b/src/components/Patient/diagnosis/list.tsx @@ -21,13 +21,14 @@ interface DiagnosisListProps { encounterId?: string; facilityId?: string; className?: string; + readOnly?: boolean; } export function DiagnosisList({ patientId, encounterId, - facilityId, - className, + className = "", + readOnly = false, }: DiagnosisListProps) { const [showEnteredInError, setShowEnteredInError] = useState(false); @@ -41,12 +42,7 @@ export function DiagnosisList({ if (isLoading) { return ( - + @@ -66,12 +62,7 @@ export function DiagnosisList({ if (!filteredDiagnoses?.length) { return ( - +

{t("no_diagnoses_recorded")}

@@ -80,12 +71,7 @@ export function DiagnosisList({ } return ( - + <> { return ( @@ -141,9 +123,9 @@ const DiagnosisListLayout = ({ className={cn("px-4 pt-4 pb-2 flex justify-between flex-row")} > {t("diagnoses")} - {facilityId && encounterId && ( + {!readOnly && ( diff --git a/src/components/Patient/symptoms/list.tsx b/src/components/Patient/symptoms/list.tsx index c22033bbee9..9e2b974a13e 100644 --- a/src/components/Patient/symptoms/list.tsx +++ b/src/components/Patient/symptoms/list.tsx @@ -19,15 +19,15 @@ import { SymptomTable } from "./SymptomTable"; interface SymptomsListProps { patientId: string; encounterId?: string; - facilityId?: string; className?: string; + readOnly?: boolean; } export function SymptomsList({ patientId, encounterId, - facilityId, className, + readOnly = false, }: SymptomsListProps) { const [showEnteredInError, setShowEnteredInError] = useState(false); @@ -42,9 +42,9 @@ export function SymptomsList({ if (isLoading) { return ( @@ -65,9 +65,9 @@ export function SymptomsList({ if (!filteredSymptoms?.length) { return (

{t("no_symptoms_recorded")}

@@ -78,10 +78,10 @@ export function SymptomsList({ return ( { return ( {t("symptoms")} - {facilityId && encounterId && ( + {!readOnly && ( 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/DateTimeQuestion.tsx b/src/components/Questionnaire/QuestionTypes/DateTimeQuestion.tsx index 4432477b82b..df327ed4d43 100644 --- a/src/components/Questionnaire/QuestionTypes/DateTimeQuestion.tsx +++ b/src/components/Questionnaire/QuestionTypes/DateTimeQuestion.tsx @@ -92,7 +92,7 @@ export function DateTimeQuestion({ }; return ( -
+
)} - - - - - - - {medication.status === "entered_in_error" - ? t("medication_already_marked_as_error") - : t("remove_medication")} - - - + + +
diff --git a/src/components/Questionnaire/QuestionTypes/MedicationStatementQuestion.tsx b/src/components/Questionnaire/QuestionTypes/MedicationStatementQuestion.tsx index b48013beee5..44ba2fe232f 100644 --- a/src/components/Questionnaire/QuestionTypes/MedicationStatementQuestion.tsx +++ b/src/components/Questionnaire/QuestionTypes/MedicationStatementQuestion.tsx @@ -34,12 +34,7 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; +import { TooltipComponent } from "@/components/ui/tooltip"; import { NotesInput } from "@/components/Questionnaire/QuestionTypes/NotesInput"; import ValueSetSelect from "@/components/Questionnaire/ValueSetSelect"; @@ -295,32 +290,29 @@ export function MedicationStatementQuestion({ )} - - - - - - - {medication.status === "entered_in_error" - ? t("medication_already_marked_as_error") - : t("remove_medication")} - - - + + + diff --git a/src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx b/src/components/Questionnaire/QuestionTypes/QuestionGroup.tsx index 0020234a9aa..2bb3907074a 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")} - Clone Questionnaire + {t("clone_questionnaire")} } /> @@ -749,7 +749,7 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) { Not Found - The requested questionnaire could not be found. + {t("no_requested_questionnaires_found")} ); @@ -812,18 +812,17 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {

{id ? t("edit") + " " + questionnaire.title - : "Create Questionnaire"} + : t("create_questionnaire")}

{questionnaire.description}

@@ -835,14 +834,13 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) { - Edit form + {t("edit_form")} - Preview form + {t("form_preview")} -
@@ -948,11 +946,11 @@ export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) {
- Basic Information + {t("basic_info")}
- +
- +
- +