From b7d8b6b51434dbdf1f9b463dd6afc07954772e50 Mon Sep 17 00:00:00 2001 From: Gigin George Date: Wed, 8 Jan 2025 09:21:10 +0530 Subject: [PATCH 1/8] Use PatientContext from Router when required --- src/Routers/PatientRouter.tsx | 6 +++++- src/components/ui/sidebar/app-sidebar.tsx | 5 +---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Routers/PatientRouter.tsx b/src/Routers/PatientRouter.tsx index 99deda2f3a7..2079b213eaa 100644 --- a/src/Routers/PatientRouter.tsx +++ b/src/Routers/PatientRouter.tsx @@ -9,6 +9,8 @@ import ErrorPage from "@/components/ErrorPages/DefaultErrorPage"; import { patientTabs } from "@/components/Patient/PatientDetailsTab"; import { PatientHome } from "@/components/Patient/PatientHome"; +import { usePatientContext } from "@/hooks/usePatientUser"; + import PatientUserProvider from "@/Providers/PatientUserProvider"; import { PatientRegistration } from "@/pages/Appoinments/PatientRegistration"; import PatientSelect from "@/pages/Appoinments/PatientSelect"; @@ -68,6 +70,8 @@ export default function PatientRouter() { const appointmentPages = useRoutes(AppointmentRoutes); + const patientUserContext = usePatientContext(); + if (!pages) { if (appointmentPages) { return {appointmentPages}; @@ -78,7 +82,7 @@ export default function PatientRouter() { return ( - +
(null); - const patientUserContext = usePatientContext(); - const { t } = useTranslation(); const selectedOrganization = React.useMemo(() => { From adac786157297d22618c6edee38d95ab711b45e4 Mon Sep 17 00:00:00 2001 From: Gigin George Date: Wed, 8 Jan 2025 10:44:20 +0530 Subject: [PATCH 2/8] Cleanup Navbars --- src/Routers/PatientRouter.tsx | 8 +- src/components/ui/sidebar/app-sidebar.tsx | 137 +++------------------ src/components/ui/sidebar/facility-nav.tsx | 63 ++++++++++ src/components/ui/sidebar/nav-user.tsx | 15 +-- src/components/ui/sidebar/org-nav.tsx | 26 ++++ src/components/ui/sidebar/patient-nav.tsx | 59 +++++++++ 6 files changed, 171 insertions(+), 137 deletions(-) create mode 100644 src/components/ui/sidebar/facility-nav.tsx create mode 100644 src/components/ui/sidebar/org-nav.tsx create mode 100644 src/components/ui/sidebar/patient-nav.tsx diff --git a/src/Routers/PatientRouter.tsx b/src/Routers/PatientRouter.tsx index 2079b213eaa..bf16c8c3e30 100644 --- a/src/Routers/PatientRouter.tsx +++ b/src/Routers/PatientRouter.tsx @@ -2,15 +2,13 @@ import careConfig from "@careConfig"; import { useRoutes } from "raviger"; import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"; -import { AppSidebar } from "@/components/ui/sidebar/app-sidebar"; +import { AppSidebar, SidebarFor } from "@/components/ui/sidebar/app-sidebar"; import ErrorBoundary from "@/components/Common/ErrorBoundary"; import ErrorPage from "@/components/ErrorPages/DefaultErrorPage"; import { patientTabs } from "@/components/Patient/PatientDetailsTab"; import { PatientHome } from "@/components/Patient/PatientHome"; -import { usePatientContext } from "@/hooks/usePatientUser"; - import PatientUserProvider from "@/Providers/PatientUserProvider"; import { PatientRegistration } from "@/pages/Appoinments/PatientRegistration"; import PatientSelect from "@/pages/Appoinments/PatientSelect"; @@ -70,8 +68,6 @@ export default function PatientRouter() { const appointmentPages = useRoutes(AppointmentRoutes); - const patientUserContext = usePatientContext(); - if (!pages) { if (appointmentPages) { return {appointmentPages}; @@ -82,7 +78,7 @@ export default function PatientRouter() { return ( - +
{ user?: UserModel; facilitySidebar?: boolean; - patientUserContext?: PatientUserContextType; + sidebarFor?: SidebarFor; } -function generateFacilityLinks( - selectedFacility: UserFacilityModel | null, - t: TFunction, - // TODO: switch to UserBase once getcurrentuser serializer is updated - user?: UserModel, -) { - if (!selectedFacility) return []; - - const baseUrl = `/facility/${selectedFacility.id}`; - const links: NavigationLink[] = [ - { name: t("facility"), url: baseUrl, icon: "d-hospital" }, - { - name: t("appointments"), - url: `${baseUrl}/appointments`, - icon: "d-calendar", - }, - { - name: t("search_patients"), - url: `${baseUrl}/patients`, - icon: "d-patient", - }, - { name: t("encounters"), url: `${baseUrl}/encounters`, icon: "d-patient" }, - // { name: t("assets"), url: `${baseUrl}/assets`, icon: "d-folder" }, - { name: t("resource"), url: "/resource", icon: "d-book-open" }, - { name: t("users"), url: `${baseUrl}/users`, icon: "d-people" }, - { - name: t("organization"), - url: `${baseUrl}/organization`, - icon: "d-book-open", - }, - ]; - - if (user) { - links.push({ - name: t("schedules"), - url: `${baseUrl}/users/${user.username}/availability`, - icon: "d-calendar", - }); - } - - return links; -} - -function generateOrganizationLinks( - organizations: Organization[], -): NavigationLink[] { - return organizations.map((org) => ({ - name: org.name, - url: `/organization/${org.id}`, - })); -} - -function generatePatientLinks( - selectedUser: AppointmentPatient | null, - t: TFunction, -): NavigationLink[] { - if (!selectedUser) return []; - - const { geo_organization } = selectedUser; - let parentOrganization = geo_organization?.parent; - while (parentOrganization?.parent) { - if (parentOrganization.level_cache === 1) { - break; - } - parentOrganization = parentOrganization.parent; - } - - const queryParams = new URLSearchParams(); - - if (parentOrganization) { - queryParams.set("organization", String(parentOrganization?.id)); - } - - return [ - { name: t("appointments"), url: "/patient/home", icon: "d-patient" }, - { - name: t("nearby_facilities"), - url: `/nearby_facilities/?${queryParams.toString()}`, - icon: "d-patient", - }, - ]; +export enum SidebarFor { + FACILITY = "facility", + PATIENT = "patient", } export function AppSidebar({ user, - patientUserContext, - facilitySidebar = true, + sidebarFor = SidebarFor.FACILITY, ...props }: AppSidebarProps) { const exactMatch = usePathParams("/facility/:facilityId"); @@ -139,11 +48,12 @@ export function AppSidebar({ const orgSubpathMatch = usePathParams("/organization/:id/*"); const organizationId = orgMatch?.id || orgSubpathMatch?.id; + const facilitySidebar = sidebarFor === SidebarFor.FACILITY; + const patientSidebar = sidebarFor === SidebarFor.PATIENT; + const [selectedFacility, setSelectedFacility] = React.useState(null); - const { t } = useTranslation(); - const selectedOrganization = React.useMemo(() => { if (!user?.organizations || !organizationId) return undefined; return user.organizations.find((org) => org.id === organizationId); @@ -207,34 +117,17 @@ export function AppSidebar({ {facilitySidebar && !selectedOrganization && ( - + )} {selectedOrganization && ( - - )} - {patientUserContext && ( - <> - - - + )} + {patientSidebar && } {(facilitySidebar || selectedOrganization) && } - {patientUserContext && ( - - )} + {patientSidebar && } diff --git a/src/components/ui/sidebar/facility-nav.tsx b/src/components/ui/sidebar/facility-nav.tsx new file mode 100644 index 00000000000..75c6957919f --- /dev/null +++ b/src/components/ui/sidebar/facility-nav.tsx @@ -0,0 +1,63 @@ +import { TFunction } from "i18next"; +import { useTranslation } from "react-i18next"; + +import { NavMain } from "@/components/ui/sidebar/nav-main"; + +import { UserFacilityModel, UserModel } from "@/components/Users/models"; + +interface NavigationLink { + name: string; + url: string; + icon?: string; +} + +interface FacilityNavProps { + selectedFacility: UserFacilityModel | null; + user?: UserModel; +} + +function generateFacilityLinks( + selectedFacility: UserFacilityModel | null, + t: TFunction, + user?: UserModel, +) { + if (!selectedFacility) return []; + + const baseUrl = `/facility/${selectedFacility.id}`; + const links: NavigationLink[] = [ + { name: t("facility"), url: baseUrl, icon: "d-hospital" }, + { + name: t("appointments"), + url: `${baseUrl}/appointments`, + icon: "d-calendar", + }, + { + name: t("search_patients"), + url: `${baseUrl}/patients`, + icon: "d-patient", + }, + { name: t("encounters"), url: `${baseUrl}/encounters`, icon: "d-patient" }, + { name: t("resource"), url: "/resource", icon: "d-book-open" }, + { name: t("users"), url: `${baseUrl}/users`, icon: "d-people" }, + { + name: t("organization"), + url: `${baseUrl}/organization`, + icon: "d-book-open", + }, + ]; + + if (user) { + links.push({ + name: t("schedules"), + url: `${baseUrl}/users/${user.username}/availability`, + icon: "d-calendar", + }); + } + + return links; +} + +export function FacilityNav({ selectedFacility, user }: FacilityNavProps) { + const { t } = useTranslation(); + return ; +} diff --git a/src/components/ui/sidebar/nav-user.tsx b/src/components/ui/sidebar/nav-user.tsx index 56857862ad4..9a36b79a8ae 100644 --- a/src/components/ui/sidebar/nav-user.tsx +++ b/src/components/ui/sidebar/nav-user.tsx @@ -25,8 +25,7 @@ import { Avatar } from "@/components/Common/Avatar"; import useAuthUser, { useAuthContext } from "@/hooks/useAuthUser"; import { usePatientSignOut } from "@/hooks/usePatientSignOut"; - -import { AppointmentPatient } from "@/pages/Patient/Utils"; +import { usePatientContext } from "@/hooks/usePatientUser"; export function FacilityNavUser() { const { t } = useTranslation(); @@ -117,16 +116,14 @@ export function FacilityNavUser() { ); } -export function PatientNavUser({ - patient, - phoneNumber, -}: { - patient: AppointmentPatient | null; - phoneNumber: string; -}) { +export function PatientNavUser() { const { t } = useTranslation(); const { isMobile, open } = useSidebar(); const signOut = usePatientSignOut(); + const patientUserContext = usePatientContext(); + + const patient = patientUserContext?.selectedPatient; + const phoneNumber = patientUserContext?.tokenData.phoneNumber; return ( diff --git a/src/components/ui/sidebar/org-nav.tsx b/src/components/ui/sidebar/org-nav.tsx new file mode 100644 index 00000000000..cb4e3990554 --- /dev/null +++ b/src/components/ui/sidebar/org-nav.tsx @@ -0,0 +1,26 @@ +import { NavMain } from "@/components/ui/sidebar/nav-main"; + +import { Organization } from "@/types/organization/organization"; + +interface NavigationLink { + name: string; + url: string; + icon?: string; +} + +interface OrgNavProps { + organizations: Organization[]; +} + +function generateOrganizationLinks( + organizations: Organization[], +): NavigationLink[] { + return organizations.map((org) => ({ + name: org.name, + url: `/organization/${org.id}`, + })); +} + +export function OrgNav({ organizations }: OrgNavProps) { + return ; +} diff --git a/src/components/ui/sidebar/patient-nav.tsx b/src/components/ui/sidebar/patient-nav.tsx new file mode 100644 index 00000000000..b52cb5b4481 --- /dev/null +++ b/src/components/ui/sidebar/patient-nav.tsx @@ -0,0 +1,59 @@ +import { TFunction } from "i18next"; +import { useTranslation } from "react-i18next"; + +import { NavMain } from "@/components/ui/sidebar/nav-main"; +import { PatientSwitcher } from "@/components/ui/sidebar/patient-switcher"; + +import { usePatientContext } from "@/hooks/usePatientUser"; + +import { AppointmentPatient } from "@/pages/Patient/Utils"; + +interface NavigationLink { + name: string; + url: string; + icon?: string; +} + +function generatePatientLinks( + selectedUser: AppointmentPatient | null, + t: TFunction, +): NavigationLink[] { + if (!selectedUser) return []; + + const { geo_organization } = selectedUser; + let parentOrganization = geo_organization?.parent; + while (parentOrganization?.parent) { + if (parentOrganization.level_cache === 1) { + break; + } + parentOrganization = parentOrganization.parent; + } + + const queryParams = new URLSearchParams(); + + if (parentOrganization) { + queryParams.set("organization", String(parentOrganization?.id)); + } + + return [ + { name: t("appointments"), url: "/patient/home", icon: "d-patient" }, + { + name: t("nearby_facilities"), + url: `/nearby_facilities/?${queryParams.toString()}`, + icon: "d-patient", + }, + ]; +} + +export function PatientNav() { + const { t } = useTranslation(); + const patientUserContext = usePatientContext(); + const selectedPatient = patientUserContext?.selectedPatient; + + return ( + <> + + + + ); +} From a4814289333aa25fd2824f5e19dc305d99a60e99 Mon Sep 17 00:00:00 2001 From: Gigin George Date: Wed, 8 Jan 2025 12:24:55 +0530 Subject: [PATCH 3/8] AllergyList: Add i18n; map key --- src/components/Patient/allergy/list.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/Patient/allergy/list.tsx b/src/components/Patient/allergy/list.tsx index 284b7885a70..456f61c759e 100644 --- a/src/components/Patient/allergy/list.tsx +++ b/src/components/Patient/allergy/list.tsx @@ -1,4 +1,5 @@ import { useQuery } from "@tanstack/react-query"; +import { t } from "i18next"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; @@ -85,22 +86,22 @@ export function AllergyList({ patientId, encounterId }: AllergyListProps) { return ( - Allergies + {t("allergies")} - Allergen - Category - Status - Criticality - Created By + {t("allergen")} + {t("category")} + {t("status")} + {t("criticality")} + {t("created_by")} {allergies.results.map((allergy: AllergyIntolerance) => ( - + {allergy.code.display} From 1404a41a085a3cd90638819f66d3583a1a827189 Mon Sep 17 00:00:00 2001 From: Gigin George Date: Wed, 8 Jan 2025 12:38:11 +0530 Subject: [PATCH 4/8] Add Actions in Encounter --- public/locale/en.json | 5 ++ src/Routers/routes/ConsultationRoutes.tsx | 48 +++++------ src/components/Patient/PatientInfoCard.tsx | 95 ++++++++++++++++++++-- 3 files changed, 116 insertions(+), 32 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index 32cdc9c221c..5008b13f928 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -359,6 +359,7 @@ "all_changes_have_been_saved": "All changes have been saved", "all_details": "All Details", "all_patients": "All Patients", + "allergen": "Allergen", "allergies": "Allergies", "allow_transfer": "Allow Transfer", "allowed_formats_are": "Allowed formats are", @@ -650,6 +651,7 @@ "created_by": "Created By", "created_date": "Created Date", "created_on": "Created On", + "criticality": "Criticality", "csv_file_in_the_specified_format": "Select a CSV file in the specified format", "current_address": "Current Address", "current_password": "Current Password", @@ -829,6 +831,7 @@ "encounter_discharge_disposition__snf": "Skilled nursing facility", "encounter_duration_confirmation": "The duration of this encounter would be", "encounter_id": "Encounter ID", + "encounter_marked_as_complete": "Encounter Completed", "encounter_notes__all_discussions": "All Discussions", "encounter_notes__be_first_to_send": "Be the first to send a message", "encounter_notes__choose_template": "Choose a template or enter a custom title", @@ -899,6 +902,7 @@ "error_deleting_shifting": "Error while deleting Shifting record", "error_fetching_slots_data": "Error while fetching slots data", "error_sending_otp": "Error while sending OTP, Please try again later", + "error_updating_encounter": "Error to Updating Encounter", "error_verifying_otp": "Error while verifying OTP, Please request a new OTP", "error_while_deleting_record": "Error while deleting record", "escape": "Escape", @@ -1163,6 +1167,7 @@ "manufacturer": "Manufacturer", "map_acronym": "M.A.P.", "mark_all_as_read": "Mark all as Read", + "mark_as_complete": "Mark as Complete", "mark_as_fulfilled": "Mark as Fullfilled", "mark_as_noshow": "Mark as no-show", "mark_as_read": "Mark as Read", diff --git a/src/Routers/routes/ConsultationRoutes.tsx b/src/Routers/routes/ConsultationRoutes.tsx index a55b00b3513..96812b5ea40 100644 --- a/src/Routers/routes/ConsultationRoutes.tsx +++ b/src/Routers/routes/ConsultationRoutes.tsx @@ -42,26 +42,6 @@ const consultationRoutes: AppRoutes = { patientId={patientId} /> ), - "/facility/:facilityId/patient/:patientId/consultation/:id/consent-records": - ({ facilityId, patientId, id }) => ( - - ), - "/facility/:facilityId/patient/:patientId/encounterId/:id/files/": ({ - facilityId, - patientId, - id, - }) => ( - - ), "/facility/:facilityId/patient/:patientId/questionnaire": ({ facilityId, patientId, @@ -80,10 +60,6 @@ const consultationRoutes: AppRoutes = { patientId={patientId} /> ), - "/facility/:facilityId/patient/:patientId/encounter/:encounterId/questionnaire_response/:id": - ({ patientId, id }) => ( - - ), "/facility/:facilityId/patient/:patientId/encounter/:encounterId/questionnaire/:slug": ({ facilityId, encounterId, slug, patientId }) => ( ), + "/facility/:facilityId/patient/:patientId/encounter/:encounterId/questionnaire_response/:id": + ({ patientId, id }) => ( + + ), + "/facility/:facilityId/patient/:patientId/consultation/:id/consent-records": + ({ facilityId, patientId, id }) => ( + + ), + "/facility/:facilityId/patient/:patientId/encounterId/:id/files/": ({ + facilityId, + patientId, + id, + }) => ( + + ), }; export default consultationRoutes; diff --git a/src/components/Patient/PatientInfoCard.tsx b/src/components/Patient/PatientInfoCard.tsx index 8c0c8d29014..a943dca1882 100644 --- a/src/components/Patient/PatientInfoCard.tsx +++ b/src/components/Patient/PatientInfoCard.tsx @@ -1,3 +1,4 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; import { BedSingle, Building, @@ -9,8 +10,18 @@ import { } from "lucide-react"; import { Link } from "raviger"; import { useTranslation } from "react-i18next"; +import { toast } from "sonner"; import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; import { Popover, PopoverContent, @@ -19,13 +30,33 @@ import { import { Avatar } from "@/components/Common/Avatar"; +import routes from "@/Utils/request/api"; +import mutate from "@/Utils/request/mutate"; import { formatDateTime, formatPatientAge } from "@/Utils/utils"; import { Encounter, completedEncounterStatus } from "@/types/emr/encounter"; import { Patient } from "@/types/emr/newPatient"; -import { Button } from "../ui/button"; import ManageEncounterOrganizations from "./ManageEncounterOrganizations"; +const QUESTIONNAIRE_OPTIONS = [ + { + slug: "encounter", + title: "Update Encounter", + }, + { + slug: "community-nurse", + title: "Community Nurse Form", + }, + { + slug: "nursing_care_given", + title: "Nursing Care Given", + }, + { + slug: "recommend_discharge_v2", + title: "Recommend Discharge", + }, +] as const; + export interface PatientInfoCardProps { patient: Patient; encounter: Encounter; @@ -35,6 +66,36 @@ export interface PatientInfoCardProps { export default function PatientInfoCard(props: PatientInfoCardProps) { const { patient, encounter } = 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 ( <>
@@ -262,13 +323,31 @@ export default function PatientInfoCard(props: PatientInfoCardProps) { > {!completedEncounterStatus.includes(encounter.status) && (
- + + + + + + {QUESTIONNAIRE_OPTIONS.map((option) => ( + + + {t(option.title)} + + + ))} + + {t("actions")} + + {t("mark_as_complete")} + + +
)} From 450a6b90d49a222cfb37c75c32847db214b947a6 Mon Sep 17 00:00:00 2001 From: Gigin George Date: Wed, 8 Jan 2025 12:46:34 +0530 Subject: [PATCH 5/8] Remove Shortcut for Nursing Care --- src/components/Patient/PatientInfoCard.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/components/Patient/PatientInfoCard.tsx b/src/components/Patient/PatientInfoCard.tsx index a943dca1882..2c716095400 100644 --- a/src/components/Patient/PatientInfoCard.tsx +++ b/src/components/Patient/PatientInfoCard.tsx @@ -47,10 +47,6 @@ const QUESTIONNAIRE_OPTIONS = [ slug: "community-nurse", title: "Community Nurse Form", }, - { - slug: "nursing_care_given", - title: "Nursing Care Given", - }, { slug: "recommend_discharge_v2", title: "Recommend Discharge", From ca65cebeefeb9fa63264ff006a159ecb2ad8aa7e Mon Sep 17 00:00:00 2001 From: Gigin George Date: Wed, 8 Jan 2025 13:03:11 +0530 Subject: [PATCH 6/8] Update Crowdin configuration file --- crowdin.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crowdin.yml b/crowdin.yml index fdcb6bcd32d..237597dd875 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,6 +1,5 @@ files: - - source: /public/locale/{{lang}}.json + - source: '/public/locale/{{lang}}.json' translation: /public/locale/%two_letters_code%/%original_file_name% bundles: - 2 - From 008812337aa6648a399e60ed929d5257c8e2c090 Mon Sep 17 00:00:00 2001 From: Gigin George Date: Wed, 8 Jan 2025 14:27:16 +0530 Subject: [PATCH 7/8] Update Crowdin configuration file --- crowdin.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crowdin.yml b/crowdin.yml index 237597dd875..04cbe1a8d50 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,5 +1,5 @@ files: - - source: '/public/locale/{{lang}}.json' - translation: /public/locale/%two_letters_code%/%original_file_name% + - source: public/locale/en.json + translation: /public/locale/%two_letters_code%.json bundles: - 2 From 8bec8bc66d7620efe378cc3c00a76edab449ca36 Mon Sep 17 00:00:00 2001 From: Aditya Jindal Date: Wed, 8 Jan 2025 20:09:15 +0530 Subject: [PATCH 8/8] =?UTF-8?q?Fix:=20Replace=20InputWithError=20and=20Inp?= =?UTF-8?q?utErrors=20components=20with=20ShadCN=E2=80=99s=20components=20?= =?UTF-8?q?directly.=20(#9847)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/locale/en.json | 1 + .../Patient/PatientRegistration.tsx | 549 ++++++++++-------- src/components/ui/errors.tsx | 11 - src/components/ui/input-with-error.tsx | 24 - .../FacilityOrganizationSelector.tsx | 12 +- .../components/OrganizationSelector.tsx | 69 ++- 6 files changed, 358 insertions(+), 308 deletions(-) delete mode 100644 src/components/ui/errors.tsx delete mode 100644 src/components/ui/input-with-error.tsx diff --git a/public/locale/en.json b/public/locale/en.json index 5008b13f928..3fbcfc3de72 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -1632,6 +1632,7 @@ "select": "Select", "select_all": "Select All", "select_date": "Select date", + "select_department": "Select Department", "select_eligible_policy": "Select an Eligible Insurance Policy", "select_facility_for_discharged_patients_warning": "Facility needs to be selected to view discharged patients.", "select_for_administration": "Select for Administration", diff --git a/src/components/Patient/PatientRegistration.tsx b/src/components/Patient/PatientRegistration.tsx index 1dc236f5fb3..94289124403 100644 --- a/src/components/Patient/PatientRegistration.tsx +++ b/src/components/Patient/PatientRegistration.tsx @@ -8,7 +8,6 @@ import SectionNavigator from "@/CAREUI/misc/SectionNavigator"; import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; -import { InputErrors } from "@/components/ui/errors"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; @@ -49,7 +48,6 @@ import OrganizationSelector from "@/pages/Organization/components/OrganizationSe import { PatientModel, validatePatient } from "@/types/emr/patient"; import Autocomplete from "../ui/autocomplete"; -import InputWithError from "../ui/input-with-error"; interface PatientRegistrationPageProps { facilityId: string; @@ -316,71 +314,93 @@ export default function PatientRegistration(
{t("general_info_detail")}

- - - + + +
+ {errors["name"] && + errors["name"].map((error, i) => ( +
+ {error} +
+ ))} +

- - { - if (e.target.value.length > 13) return; - setForm((f) => ({ - ...f, - phone_number: e.target.value, - emergency_phone_number: samePhoneNumber - ? e.target.value - : f.emergency_phone_number, - })); + + { + if (e.target.value.length > 13) return; + setForm((f) => ({ + ...f, + phone_number: e.target.value, + emergency_phone_number: samePhoneNumber + ? e.target.value + : f.emergency_phone_number, + })); + }} + /> +
+ {errors["phone_number"] && + errors["phone_number"]?.map((error, i) => ( +
+ {error} +
+ ))} +
+ +
+ { + const newValue = !samePhoneNumber; + setSamePhoneNumber(newValue); + if (newValue) { + setForm((f) => ({ + ...f, + emergency_phone_number: f.phone_number, + })); + } }} + id="same-phone-number" /> - -
- - { - const newValue = !samePhoneNumber; - setSamePhoneNumber(newValue); - if (newValue) { - setForm((f) => ({ - ...f, - emergency_phone_number: f.phone_number, - })); - } - }} - id="same-phone-number" - /> - - +

- - { - if (e.target.value.length > 13) return; - setForm((f) => ({ - ...f, - emergency_phone_number: e.target.value, - })); - }} - disabled={samePhoneNumber} - /> - + + + { + if (e.target.value.length > 13) return; + setForm((f) => ({ + ...f, + emergency_phone_number: e.target.value, + })); + }} + disabled={samePhoneNumber} + /> +
+ {errors["emergency_phone_number"] && + errors["emergency_phone_number"]?.map((error, i) => ( +
+ {error} +
+ ))} +
{/*
*/}
- - - setForm((f) => ({ ...f, gender: value })) - } - className="flex items-center gap-4" - > - {GENDER_TYPES.map((g) => ( - - - - + + + + setForm((f) => ({ ...f, gender: value })) + } + className="flex items-center gap-4" + > + {GENDER_TYPES.map((g) => ( + + + + + ))} + +
+ {errors["gender"] && + errors["gender"]?.map((error, i) => ( +
+ {error} +
))} - - +
+
- - - + + + +
+ {errors["blood_group"] && + errors["blood_group"]?.map((error, i) => ( +
+ {error} +
+ ))} +
+
- - - setForm((f) => ({ - ...f, - date_of_birth: `${form.date_of_birth?.split("-")[0] || ""}-${form.date_of_birth?.split("-")[1] || ""}-${e.target.value}`, - })) - } - /> - + + + setForm((f) => ({ + ...f, + date_of_birth: `${form.date_of_birth?.split("-")[0] || ""}-${form.date_of_birth?.split("-")[1] || ""}-${e.target.value}`, + })) + } + />
- - - setForm((f) => ({ - ...f, - date_of_birth: `${form.date_of_birth?.split("-")[0] || ""}-${e.target.value}-${form.date_of_birth?.split("-")[2] || ""}`, - })) - } - /> - + + + setForm((f) => ({ + ...f, + date_of_birth: `${form.date_of_birth?.split("-")[0] || ""}-${e.target.value}-${form.date_of_birth?.split("-")[2] || ""}`, + })) + } + />
- - - setForm((f) => ({ - ...f, - date_of_birth: `${e.target.value}-${form.date_of_birth?.split("-")[1] || ""}-${form.date_of_birth?.split("-")[2] || ""}`, - })) - } - /> - + + + setForm((f) => ({ + ...f, + date_of_birth: `${e.target.value}-${form.date_of_birth?.split("-")[1] || ""}-${form.date_of_birth?.split("-")[2] || ""}`, + })) + } + />
{errors["date_of_birth"] && ( - +
+ {errors["date_of_birth"].map((error, i) => ( +
+ {error} +
+ ))} +
)} @@ -512,25 +564,32 @@ export default function PatientRegistration( {t("age_input_warning_bold")}
- - - setForm((f) => ({ - ...f, - age: e.target.value, - year_of_birth: e.target.value - ? new Date().getFullYear() - Number(e.target.value) - : undefined, - })) - } - type="number" - /> - + + + setForm((f) => ({ + ...f, + age: e.target.value, + year_of_birth: e.target.value + ? new Date().getFullYear() - Number(e.target.value) + : undefined, + })) + } + type="number" + /> +
+ {errors["year_of_birth"] && + errors["year_of_birth"]?.map((error, i) => ( +
+ {error} +
+ ))} +
+ {form.year_of_birth && (
{t("year_of_birth")} : {form.year_of_birth} @@ -540,68 +599,84 @@ export default function PatientRegistration(
- -