From 6bea49af43e0cc75f23d4bd1a14bb5a9119a9c9c Mon Sep 17 00:00:00 2001 From: Tanuj Nainwal <125687187+Tanuj1718@users.noreply.github.com> Date: Thu, 28 Nov 2024 10:44:57 +0530 Subject: [PATCH 01/26] updated crowdin.yml file (#9211) Co-authored-by: Tanuj Nainwal --- crowdin.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crowdin.yml b/crowdin.yml index 0ab1a042711..fdcb6bcd32d 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,5 +1,6 @@ files: - - source: /src/Locale/en/*.json - translation: /src/Locale/%two_letters_code%/%original_file_name% + - source: /public/locale/{{lang}}.json + translation: /public/locale/%two_letters_code%/%original_file_name% bundles: - 2 + From fa5fa25bad596c4863d38864d0e1ecb105995cf0 Mon Sep 17 00:00:00 2001 From: Shaurya Gupta Date: Thu, 28 Nov 2024 15:13:54 +0530 Subject: [PATCH 02/26] Fix: Breadcrumbs redirection to patient edit consultation form (#8985) --- src/components/Facility/ConsultationDetails/index.tsx | 4 ++++ src/components/Patient/PatientConsentRecords.tsx | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/Facility/ConsultationDetails/index.tsx b/src/components/Facility/ConsultationDetails/index.tsx index 4834ba40198..191d0156d03 100644 --- a/src/components/Facility/ConsultationDetails/index.tsx +++ b/src/components/Facility/ConsultationDetails/index.tsx @@ -213,6 +213,10 @@ export const ConsultationDetails = (props: any) => { crumbsReplacements={{ [facilityId]: { name: patientData?.facility_object?.name }, [patientId]: { name: patientData?.name }, + consultation: { + name: "Consultation", + uri: `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/update`, + }, [consultationId]: { name: consultationData.suggestion === "A" diff --git a/src/components/Patient/PatientConsentRecords.tsx b/src/components/Patient/PatientConsentRecords.tsx index 162dcb2ff77..cbeb56b894f 100644 --- a/src/components/Patient/PatientConsentRecords.tsx +++ b/src/components/Patient/PatientConsentRecords.tsx @@ -112,6 +112,10 @@ export default function PatientConsentRecords(props: { crumbsReplacements={{ [facilityId]: { name: patient?.facility_object?.name }, [patientId]: { name: patient?.name }, + consultation: { + name: "Consultation", + uri: `/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/update`, + }, [consultationId]: { name: patient?.last_consultation?.suggestion === "A" @@ -121,7 +125,7 @@ export default function PatientConsentRecords(props: { : patient?.last_consultation?.suggestion_text, }, }} - backUrl={`/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/`} + backUrl={`/facility/${facilityId}/patient/${patientId}/consultation/${consultationId}/update`} > {fileUpload.Dialogues} {fileManager.Dialogues} From fc2ac3b0f66775c05e36a012823125228271fdfd Mon Sep 17 00:00:00 2001 From: JavidSumra <112365664+JavidSumra@users.noreply.github.com> Date: Thu, 28 Nov 2024 16:11:16 +0530 Subject: [PATCH 03/26] Fixes PR thank you msg. from potentially tagging the PR author twice (#9228) --- .github/workflows/thank-you.yml | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/.github/workflows/thank-you.yml b/.github/workflows/thank-you.yml index 192f71d1a64..b91642dd24f 100644 --- a/.github/workflows/thank-you.yml +++ b/.github/workflows/thank-you.yml @@ -18,26 +18,20 @@ jobs: uses: actions/github-script@v6.3.3 with: script: | - const thankyouNote = 'Your efforts have helped advance digital healthcare and TeleICU systems. :rocket: Thank you for taking the time out to make CARE better. We hope you continue to innovate and contribute; your impact is immense! :raised_hands:' + const thankyouNote = 'Your efforts have helped advance digital healthcare and TeleICU systems. :rocket: Thank you for taking the time out to make CARE better. We hope you continue to innovate and contribute; your impact is immense! :raised_hands:'; const options = { issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - } + }; - const result = await github.rest.issues.get({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - }) - - const { assignees, user } = result.data + const { data : { assignees, user } } = await github.rest.issues.get(options); - const assignees_tagged = assignees.map((user) => '@' + user.login).join(' ') - const owner_tagged = '@' + user.login + const taggedUsers = [...new Set( + assignees.map(u => "@"+u.login).concat("@"+user.login) + )].join(" ") - if (assignees.length == 0) { - await github.rest.issues.createComment({ ...options, body: `${owner_tagged} ${thankyouNote}` }) - } else { - await github.rest.issues.createComment({ ...options, body: `${assignees_tagged} ${owner_tagged} ${thankyouNote}` }) - } + await github.rest.issues.createComment({ + ...options, + body: `${taggedUsers} ${thankyouNote}` + }); From c4071204a02f029542ffe19e9de9986e02e6dfb8 Mon Sep 17 00:00:00 2001 From: Sarvesh <142646866+sarvesh-official@users.noreply.github.com> Date: Fri, 29 Nov 2024 10:35:14 +0530 Subject: [PATCH 04/26] Implemented Next and Previous button for files preview (#9196) --- src/components/Common/FilePreviewDialog.tsx | 113 ++++++++++++++++++-- src/components/Files/FileUpload.tsx | 12 ++- src/components/Patient/FileUploadPage.tsx | 2 - src/hooks/useFileManager.tsx | 9 +- 4 files changed, 123 insertions(+), 13 deletions(-) diff --git a/src/components/Common/FilePreviewDialog.tsx b/src/components/Common/FilePreviewDialog.tsx index 4b7a07bd0cd..fa8a333515d 100644 --- a/src/components/Common/FilePreviewDialog.tsx +++ b/src/components/Common/FilePreviewDialog.tsx @@ -4,6 +4,7 @@ import { SetStateAction, Suspense, lazy, + useEffect, useState, } from "react"; import { useTranslation } from "react-i18next"; @@ -15,6 +16,8 @@ import CircularProgress from "@/components/Common/CircularProgress"; import DialogModal from "@/components/Common/Dialog"; import { StateInterface } from "@/components/Files/FileUpload"; +import { FileUploadModel } from "../Patient/models"; + const PDFViewer = lazy(() => import("@/components/Common/PDFViewer")); export const zoom_values = [ @@ -40,6 +43,9 @@ type FilePreviewProps = { className?: string; titleAction?: ReactNode; fixedWidth?: boolean; + uploadedFiles?: FileUploadModel[]; + loadFile?: (file: FileUploadModel, associating_id: string) => void; + currentIndex: number; }; const previewExtensions = [ @@ -56,12 +62,28 @@ const previewExtensions = [ ]; const FilePreviewDialog = (props: FilePreviewProps) => { - const { show, onClose, file_state, setFileState, downloadURL, fileUrl } = - props; + const { + show, + onClose, + file_state, + setFileState, + downloadURL, + fileUrl, + uploadedFiles, + loadFile, + currentIndex, + } = props; const { t } = useTranslation(); const [page, setPage] = useState(1); const [numPages, setNumPages] = useState(1); + const [index, setIndex] = useState(currentIndex); + + useEffect(() => { + if (uploadedFiles && show) { + setIndex(currentIndex); + } + }, [uploadedFiles, show, currentIndex]); const handleZoomIn = () => { const checkFull = file_state.zoom === zoom_values.length; @@ -79,9 +101,27 @@ const FilePreviewDialog = (props: FilePreviewProps) => { }); }; + const handleNext = (newIndex: number) => { + if ( + !uploadedFiles?.length || + !loadFile || + newIndex < 0 || + newIndex >= uploadedFiles.length + ) + return; + + const nextFile = uploadedFiles[newIndex]; + if (!nextFile?.id) return; + + const associating_id = nextFile.associating_id || ""; + loadFile(nextFile, associating_id); + setIndex(newIndex); + }; + const handleClose = () => { setPage(1); setNumPages(1); + setIndex(-1); onClose?.(); }; @@ -102,6 +142,21 @@ const FilePreviewDialog = (props: FilePreviewProps) => { : `rotate-${normalizedRotation}`; } + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (!show) return; + if (e.key === "ArrowLeft" && index > 0) { + handleNext(index - 1); + } + if (e.key === "ArrowRight" && index < (uploadedFiles?.length || 0) - 1) { + handleNext(index + 1); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [show, index, uploadedFiles]); + return ( { onClose={() => { handleClose(); }} - title={t("file_preview")} + title={{t("file_preview")}} show={show} > {fileUrl ? ( <> -
-

- {file_state.name}.{file_state.extension} -

-
+
+
+

+ {file_state.name}.{file_state.extension} +

+ {uploadedFiles && + uploadedFiles[index] && + uploadedFiles[index].created_date && ( +

+ Created on{" "} + {new Date( + uploadedFiles[index].created_date!, + ).toLocaleString("en-US", { + dateStyle: "long", + timeStyle: "short", + })} +

+ )} +
+
{downloadURL && downloadURL.length > 0 && ( {
+ {uploadedFiles && uploadedFiles.length > 1 && ( + handleNext(index - 1)} + disabled={index <= 0} + aria-label="Previous file" + onKeyDown={(e) => + e.key === "ArrowLeft" && handleNext(index - 1) + } + > + + + )}
{file_state.isImage ? ( {
)}
+ + {uploadedFiles && uploadedFiles.length > 1 && ( + handleNext(index + 1)} + disabled={index >= uploadedFiles.length - 1} + aria-label="Next file" + onKeyDown={(e) => + e.key === "ArrowRight" && handleNext(index + 1) + } + > + + + )}
diff --git a/src/components/Files/FileUpload.tsx b/src/components/Files/FileUpload.tsx index d98df131863..50ab3ffdb01 100644 --- a/src/components/Files/FileUpload.tsx +++ b/src/components/Files/FileUpload.tsx @@ -69,6 +69,8 @@ export interface StateInterface { isZoomInDisabled: boolean; isZoomOutDisabled: boolean; rotation: number; + id?: string; + associating_id?: string; } export const FileUpload = (props: FileUploadProps) => { @@ -208,8 +210,15 @@ export const FileUpload = (props: FileUploadProps) => { type, onArchive: refetchAll, onEdit: refetchAll, + uploadedFiles: + fileQuery?.data?.results + .slice() + .reverse() + .map((file) => ({ + ...file, + associating_id: associatedId, + })) || [], }); - const dischargeSummaryFileManager = useFileManager({ type: "DISCHARGE_SUMMARY", onArchive: refetchAll, @@ -244,7 +253,6 @@ export const FileUpload = (props: FileUploadProps) => { id: "record-audio", }, ]; - return (
{fileUpload.Dialogues} diff --git a/src/components/Patient/FileUploadPage.tsx b/src/components/Patient/FileUploadPage.tsx index 518644f54d7..d38b149ebeb 100644 --- a/src/components/Patient/FileUploadPage.tsx +++ b/src/components/Patient/FileUploadPage.tsx @@ -11,12 +11,10 @@ export default function FileUploadPage(props: { type: "CONSULTATION" | "PATIENT"; }) { const { facilityId, patientId, consultationId, type } = props; - const { data: patient } = useQuery(routes.getPatient, { pathParams: { id: patientId }, prefetch: !!patientId, }); - return ( void; onEdit?: () => void; + uploadedFiles?: FileUploadModel[]; } export interface FileManagerResult { viewFile: (file: FileUploadModel, associating_id: string) => void; @@ -48,7 +49,7 @@ export interface FileManagerResult { export default function useFileManager( options: FileManagerOptions, ): FileManagerResult { - const { type: fileType, onArchive, onEdit } = options; + const { type: fileType, onArchive, onEdit, uploadedFiles } = options; const [file_state, setFileState] = useState({ open: false, @@ -72,6 +73,7 @@ export default function useFileManager( const [editDialogueOpen, setEditDialogueOpen] = useState(null); const [editError, setEditError] = useState(""); + const [currentIndex, setCurrentIndex] = useState(-1); const getExtension = (url: string) => { const div1 = url.split("?")[0].split("."); @@ -80,6 +82,8 @@ export default function useFileManager( }; const viewFile = async (file: FileUploadModel, associating_id: string) => { + const index = uploadedFiles?.findIndex((f) => f.id === file.id) ?? -1; + setCurrentIndex(index); setFileUrl(""); setFileState({ ...file_state, open: true }); const { data } = await request(routes.retrieveUpload, { @@ -225,9 +229,12 @@ export default function useFileManager( file_state={file_state} setFileState={setFileState} downloadURL={downloadURL} + uploadedFiles={uploadedFiles} onClose={handleFilePreviewClose} fixedWidth={false} className="h-[80vh] w-full md:h-screen" + loadFile={viewFile} + currentIndex={currentIndex} /> Date: Fri, 29 Nov 2024 11:58:38 +0530 Subject: [PATCH 05/26] Fix: Date of Birth to Year of Birth on Patient Details Page when DOB is Missing (#9242) --- public/locale/en.json | 3 ++- .../Patient/PatientDetailsTab/Demography.tsx | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index 56f84a1883a..cd921bef06a 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -562,7 +562,7 @@ "date_and_time": "Date and Time", "date_declared_positive": "Date of declaring positive", "date_of_admission": "Date of Admission", - "date_of_birth": "Date of birth", + "date_of_birth": "Date of Birth", "date_of_positive_covid_19_swab": "Date of Positive Covid 19 Swab", "date_of_result": "Covid confirmation date", "date_of_return": "Date of Return", @@ -1433,6 +1433,7 @@ "why_the_asset_is_not_working": "Why the asset is not working?", "width": "Width ({{unit}})", "working_status": "Working Status", + "year_of_birth": "Year of Birth", "years": "years", "years_of_experience": "Years of Experience", "years_of_experience_of_the_doctor": "Years of Experience of the Doctor", diff --git a/src/components/Patient/PatientDetailsTab/Demography.tsx b/src/components/Patient/PatientDetailsTab/Demography.tsx index 7ac854b8ee6..2a412f03f9a 100644 --- a/src/components/Patient/PatientDetailsTab/Demography.tsx +++ b/src/components/Patient/PatientDetailsTab/Demography.tsx @@ -188,12 +188,19 @@ export const Demography = (props: PatientProps) => { ), }, { - label: t("date_of_birth"), - value: ( + label: t( + patientData.date_of_birth ? "date_of_birth" : "year_of_birth", + ), + value: patientData.date_of_birth ? ( <> {dayjs(patientData.date_of_birth).format("DD MMM YYYY")} ( {formatPatientAge(patientData, true)}) + ) : ( + <> + {patientData.year_of_birth} ({formatPatientAge(patientData, true)} + ) + ), }, { From 2a89332514050c5f519ec650d6d5baf84c786f69 Mon Sep 17 00:00:00 2001 From: Bodhish Thomas Date: Fri, 29 Nov 2024 15:31:18 +0530 Subject: [PATCH 06/26] Update cursorrules --- .cursorrules | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/.cursorrules b/.cursorrules index 2eed3afe459..94ebea1bd57 100644 --- a/.cursorrules +++ b/.cursorrules @@ -1,23 +1,35 @@ -Care is a React Typescript Project, built with Vite and styled with TailwindCSS. +You are an expert in TypeScript, React, Shadcn UI, Tailwind. -Care uses a Plugin Architecture. Apps are installed in /apps. +Key Principles -Care uses a custom useQuery hook to fetch data from the API. APIs are defined in the api.tsx file +- Write concise, technical TypeScript code with accurate examples. +- Use functional and declarative programming patterns; avoid classes. +- Prefer iteration and modularization over code duplication. +- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError). -Here's an example of how to use the useQuery hook to fetch data from the API: +Naming Conventions -``` -useQuery from "@/common/hooks/useQuery"; -const { data, loading, error } = useQuery(routes.getFacilityUsers, { - facility_id: "1", -}); +- Use lowercase with dashes for directories (e.g., components/auth-wizard). +- Favor named exports for components. -request from "@/common/utils/request"; -const { res } = await request(routes.partialUpdateAsset, { - pathParams: { external_id: assetId }, - body: data, -}); -``` +TypeScript Usage +- Use TypeScript for all code; prefer interfaces over types. +- Avoid enums; use maps instead. +- Use functional components with TypeScript interfaces. +Syntax and Formatting +- Use the "function" keyword for pure functions. +- Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements. +- Use declarative JSX. + +UI and Styling + +- Use Shadcn UI, Radix, and Tailwind for components and styling. +- Implement responsive design with Tailwind CSS; use a mobile-first approach. + +General Guidelines + +- Care uses a custom useQuery hook to fetch data from the API. (Docs @ /Utils/request/useQuery) +- APIs are defined in the api.tsx file. From c58de1777e8945a41b26690be3f73e055d19d143 Mon Sep 17 00:00:00 2001 From: Swanand Shekhar Bhuskute <103440604+SwanandBhuskute@users.noreply.github.com> Date: Fri, 29 Nov 2024 18:27:32 +0530 Subject: [PATCH 07/26] fixing back button for camera asset (#9246) --- src/components/CameraFeed/ConfigureCamera.tsx | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/components/CameraFeed/ConfigureCamera.tsx b/src/components/CameraFeed/ConfigureCamera.tsx index f969ed2b0ca..eec453053d6 100644 --- a/src/components/CameraFeed/ConfigureCamera.tsx +++ b/src/components/CameraFeed/ConfigureCamera.tsx @@ -89,16 +89,15 @@ export default function ConfigureCamera(props: Props) { const firstBedId = linkedAssetBeds?.[0]?.bed_object.id ?? unlinkedBeds?.[0]?.id; - useEffect(() => { - if (!query.bed && firstBedId) { - setQuery({ bed: firstBedId }); - } - }, [query.bed, firstBedId]); + + const selectedBedId = query.bed || firstBedId; const selectedAssetBed = linkedAssetBeds?.find( - (a) => a.bed_object.id === query.bed, + (a) => a.bed_object.id === selectedBedId, + ); + const selectedUnlinkedBed = unlinkedBeds?.find( + (bed) => bed.id === selectedBedId, ); - const selectedUnlinkedBed = unlinkedBeds?.find((bed) => bed.id === query.bed); const cameraPresetsQuery = useQuery(FeedRoutes.listAssetBedPresets, { pathParams: { assetbed_id: selectedAssetBed?.id ?? "" }, From 59cc025ee2026213392a9337a2bcc89baec7e783 Mon Sep 17 00:00:00 2001 From: Anvesh Nalimela <151531961+AnveshNalimela@users.noreply.github.com> Date: Sat, 30 Nov 2024 05:57:40 +0530 Subject: [PATCH 08/26] Rewriting UsersCreation.cy.ts according to POM approach (#8930) Co-authored-by: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> --- .../e2e/facility_spec/FacilityLocation.cy.ts | 5 +- cypress/e2e/users_spec/UsersCreation.cy.ts | 215 +++++++++--------- cypress/e2e/users_spec/UsersManage.cy.ts | 7 +- cypress/e2e/users_spec/UsersProfile.cy.ts | 15 +- cypress/pageobject/Users/UserCreation.ts | 79 +++---- cypress/pageobject/Users/UserProfilePage.ts | 42 ++-- cypress/pageobject/utils/constants.ts | 11 +- 7 files changed, 179 insertions(+), 195 deletions(-) diff --git a/cypress/e2e/facility_spec/FacilityLocation.cy.ts b/cypress/e2e/facility_spec/FacilityLocation.cy.ts index 9ac85e9ba4c..19c43d4dcf4 100644 --- a/cypress/e2e/facility_spec/FacilityLocation.cy.ts +++ b/cypress/e2e/facility_spec/FacilityLocation.cy.ts @@ -36,6 +36,7 @@ describe("Location Management Section", () => { const bedType = "ICU"; const bedStatus = "Vacant"; const bedModifiedName = "test modified bed"; + const duplicateBedName = "ICCU"; const bedModifiedDescrption = "test modified description"; const bedModifiedType = "Isolation"; const numberOfBeds = 10; @@ -96,12 +97,12 @@ describe("Location Management Section", () => { facilityHome.verifyAndCloseNotifyModal(); // edit the created bed facilityLocation.clickEditBedButton(); - facilityLocation.enterBedName(bedModifiedName); + facilityLocation.enterBedName(duplicateBedName); facilityLocation.enterBedDescription(bedModifiedDescrption); facilityLocation.selectBedType(bedModifiedType); assetPage.clickassetupdatebutton(); // verify the modification - facilityLocation.verifyBedNameBadge(bedModifiedName); + facilityLocation.verifyBedNameBadge(duplicateBedName); facilityLocation.verifyBedBadge(bedModifiedType); facilityLocation.verifyBedBadge(bedStatus); facilityLocation.closeNotification(); diff --git a/cypress/e2e/users_spec/UsersCreation.cy.ts b/cypress/e2e/users_spec/UsersCreation.cy.ts index f495a136d97..96b953a3e17 100644 --- a/cypress/e2e/users_spec/UsersCreation.cy.ts +++ b/cypress/e2e/users_spec/UsersCreation.cy.ts @@ -1,3 +1,6 @@ +import ManageUserPage from "pageobject/Users/ManageUserPage"; +import UserProfilePage from "pageobject/Users/UserProfilePage"; + import { AssetSearchPage } from "../../pageobject/Asset/AssetSearch"; import FacilityPage from "../../pageobject/Facility/FacilityCreation"; import LoginPage from "../../pageobject/Login/LoginPage"; @@ -11,13 +14,15 @@ import { describe("User Creation", () => { const userPage = new UserPage(); const loginPage = new LoginPage(); + const userProfilePage = new UserProfilePage(); + const manageUserPage = new ManageUserPage(); const userCreationPage = new UserCreationPage(); const facilityPage = new FacilityPage(); const assetSearchPage = new AssetSearchPage(); - const phone_number = generatePhoneNumber(); - const emergency_phone_number = generateEmergencyPhoneNumber(); + const phoneNumber = generatePhoneNumber(); + const emergencyPhoneNumber = generateEmergencyPhoneNumber(); const fillFacilityName = "Dummy Facility 40"; - const makeid = (length: number) => { + const makeId = (length: number) => { let result = ""; const characters = "abcdefghijklmnopqrstuvwxyz0123456789"; const charactersLength = characters.length; @@ -26,8 +31,8 @@ describe("User Creation", () => { } return result; }; - const username = makeid(8); - const alreadylinkedusersviews = [ + const username = makeId(8); + const alreadyLinkedUsersViews = [ "devdoctor", "devstaff2", "devdistrictadmin", @@ -53,6 +58,25 @@ describe("User Creation", () => { "This field is required", "Please enter valid phone number", ]; + const userName = "devdistrictadmin"; + const firstName = "District Editted"; + const lastName = "Cypress"; + const gender = "Male"; + const email = "test@test.com"; + const password = "Test@123"; + const qualification = "MBBS"; + const experience = "2"; + const regNo = "123456789"; + const newUserFirstName = "cypress test"; + const newUserLastName = "staff user"; + const state = "Kerala"; + const district = "Ernakulam"; + const role = "Doctor"; + const homeFacility = "Dummy Shifting Center"; + const weeklyWorkingHrs = "14"; + const dob = "01011998"; + const formattedDob = "01/01/1998"; + const newUserDob = "25081999"; before(() => { loginPage.loginAsDistrictAdmin(); @@ -66,123 +90,92 @@ describe("User Creation", () => { }); it("Update the existing user profile and verify its reflection", () => { - userCreationPage.clickElementById("user-profile-name"); - userCreationPage.clickElementById("profile-button"); - userCreationPage.verifyElementContainsText( - "username-profile-details", - "devdistrictadmin", - ); - userCreationPage.clickElementById("edit-cancel-profile-button"); - userCreationPage.typeIntoElementByIdPostClear( - "firstName", - "District Editted", - ); - userCreationPage.typeIntoElementByIdPostClear("lastName", "Cypress"); - userCreationPage.selectDropdownOption("gender", "Male"); - userCreationPage.typeIntoElementByIdPostClear("phoneNumber", phone_number); - userCreationPage.typeIntoElementByIdPostClear( - "altPhoneNumber", - emergency_phone_number, - ); - userCreationPage.typeIntoElementByIdPostClear("email", "test@test.com"); - userCreationPage.typeIntoElementByIdPostClear("weekly_working_hours", "14"); - userCreationPage.typeIntoElementByIdPostClearDob( - "date_of_birth", - "01011998", - ); - userCreationPage.clickElementById("submit"); - userCreationPage.verifyElementContainsText( - "contactno-profile-details", - "+91" + phone_number, - ); - userCreationPage.verifyElementContainsText( - "whatsapp-profile-details", - "+91" + emergency_phone_number, - ); - userCreationPage.verifyElementContainsText( - "firstname-profile-details", - "District Editted", - ); - userCreationPage.verifyElementContainsText( - "lastname-profile-details", - "Cypress", - ); - userCreationPage.verifyElementContainsText( - "date_of_birth-profile-details", - "01/01/1998", - ); - userCreationPage.verifyElementContainsText( - "emailid-profile-details", - "test@test.com", - ); - userCreationPage.verifyElementContainsText( - "gender-profile-details", - "Male", - ); - userCreationPage.verifyElementContainsText( - "averageworkinghour-profile-details", - "14", - ); + manageUserPage.navigateToProfile(); + cy.verifyContentPresence("#username-profile-details", [userName]); + userProfilePage.clickEditProfileButton(); + userCreationPage.clearFirstName(); + userCreationPage.typeFirstName(firstName); + userCreationPage.clearLastName(); + userCreationPage.typeLastName(lastName); + userProfilePage.selectGender(gender); + userProfilePage.clearPhoneNumber(); + userProfilePage.typePhoneNumber(phoneNumber); + userProfilePage.clearAltPhoneNumber(); + userProfilePage.typeWhatsappNumber(emergencyPhoneNumber); + userProfilePage.clearEmail(); + userProfilePage.typeEmail(email); + userProfilePage.clearWorkingHours(); + userProfilePage.typeWorkingHours(weeklyWorkingHrs); + userProfilePage.typeDateOfBirth(dob); + cy.intercept("PATCH", "/api/v1/users/*").as("updateUser"); + userProfilePage.clickUpdateButton(); + cy.wait("@updateUser").its("response.statusCode").should("eq", 200); + cy.verifyContentPresence("#contactno-profile-details", [ + "+91" + phoneNumber, + ]); + cy.verifyContentPresence("#whatsapp-profile-details", [ + "+91" + emergencyPhoneNumber, + ]); + cy.verifyContentPresence("#firstname-profile-details", [firstName]); + cy.verifyContentPresence("#lastname-profile-details", [lastName]); + cy.verifyContentPresence("#date_of_birth-profile-details", [formattedDob]); + cy.verifyContentPresence("#emailid-profile-details", [email]); + cy.verifyContentPresence("#gender-profile-details", [gender]); + cy.verifyContentPresence("#averageworkinghour-profile-details", [ + weeklyWorkingHrs, + ]); }); it("Update the existing user profile Form Mandatory File Error", () => { - userCreationPage.clickElementById("user-profile-name"); - userCreationPage.clickElementById("profile-button"); - userCreationPage.clickElementById("edit-cancel-profile-button"); - userCreationPage.clearIntoElementById("firstName"); - userCreationPage.clearIntoElementById("lastName"); - userCreationPage.clearIntoElementById("phoneNumber"); - userCreationPage.clearIntoElementById("altPhoneNumber"); - userCreationPage.clearIntoElementById("weekly_working_hours"); - userCreationPage.clickElementById("submit"); + manageUserPage.navigateToProfile(); + userProfilePage.clickEditProfileButton(); + userCreationPage.clearFirstName(); + userCreationPage.clearLastName(); + userProfilePage.clearPhoneNumber(); + userProfilePage.clearAltPhoneNumber(); + userProfilePage.clearWorkingHours(); + userProfilePage.clickUpdateButton(); userCreationPage.verifyErrorMessages(EXPECTED_PROFILE_ERROR_MESSAGES); }); it("create new user and verify reflection", () => { - userCreationPage.clickElementById("addUserButton"); - userCreationPage.selectFacility("Dummy Shifting Center"); - userCreationPage.typeIntoElementById("username", username); - userCreationPage.typeIntoElementById("password", "Test@123"); - userCreationPage.selectHomeFacility("Dummy Shifting Center"); - userCreationPage.typeIntoElementById("phone_number", phone_number); - userCreationPage.setInputDate("date_of_birth", "25081999"); - userCreationPage.selectDropdownOption("user_type", "Doctor"); - userCreationPage.typeIntoElementById("c_password", "Test@123"); - userCreationPage.typeIntoElementById("qualification", "MBBS"); - userCreationPage.typeIntoElementById("doctor_experience_commenced_on", "2"); - userCreationPage.typeIntoElementById( - "doctor_medical_council_registration", - "123456789", - ); - userCreationPage.typeIntoElementById("first_name", "cypress test"); - userCreationPage.typeIntoElementById("last_name", "staff user"); - userCreationPage.typeIntoElementById("email", "test@test.com"); - userCreationPage.selectDropdownOption("gender", "Male"); - userCreationPage.selectDropdownOption("state", "Kerala"); - userCreationPage.selectDropdownOption("district", "Ernakulam"); - userCreationPage.clickElementById("submit"); - userCreationPage.verifyNotification("User added successfully"); + userCreationPage.clickAddUserButton(); + userCreationPage.selectFacility(homeFacility); + userCreationPage.typeUserName(username); + userCreationPage.typePassword(password); + userCreationPage.typeConfirmPassword(password); + userCreationPage.selectHomeFacility(homeFacility); + userPage.typeInPhoneNumber(phoneNumber); + userProfilePage.typeDateOfBirth(newUserDob); + userCreationPage.selectUserType(role); + userProfilePage.typeQualification(qualification); + userProfilePage.typeDoctorYoE(experience); + userProfilePage.typeMedicalCouncilRegistration(regNo); + userPage.typeInFirstName(newUserFirstName); + userPage.typeInLastName(newUserLastName); + userProfilePage.typeEmail(email); + userCreationPage.selectGender(gender); + userCreationPage.selectState(state); + userCreationPage.selectDistrict(district); + cy.intercept("POST", "/api/v1/users/add_user/").as("createUser"); + userCreationPage.clickSaveUserButton(); + cy.wait("@createUser").its("response.statusCode").should("eq", 201); + cy.verifyNotification("User added successfully"); userPage.typeInSearchInput(username); userPage.checkUsernameText(username); - userCreationPage.verifyElementContainsText("name", "cypress test"); - userCreationPage.verifyElementContainsText("role", "Doctor"); - userCreationPage.verifyElementContainsText("district", "Ernakulam"); - userCreationPage.verifyElementContainsText( - "home_facility", - "Dummy Shifting Center", - ); - userCreationPage.verifyElementContainsText("qualification", "MBBS"); - userCreationPage.verifyElementContainsText("doctor-experience", "2"); - userCreationPage.verifyElementContainsText( - "medical-council-registration", - "123456789", - ); + cy.verifyContentPresence("#name", [newUserFirstName]); + cy.verifyContentPresence("#role", [role]); + cy.verifyContentPresence("#district", [district]); + cy.verifyContentPresence("#home_facility", [homeFacility]); + cy.verifyContentPresence("#qualification", [qualification]); + cy.verifyContentPresence("#doctor-experience", [experience]); + cy.verifyContentPresence("#medical-council-registration", [regNo]); }); it("create new user form throwing mandatory field error", () => { - userCreationPage.clickElementById("addUserButton"); - userCreationPage.clickElementById("submit"); - cy.wait(2000); + userCreationPage.clickAddUserButton(); + userCreationPage.clickSaveUserButton(); + cy.get(".error-text", { timeout: 10000 }).should("be.visible"); userCreationPage.verifyErrorMessages(EXPECTED_ERROR_MESSAGES); }); @@ -194,7 +187,7 @@ describe("User Creation", () => { facilityPage.visitAlreadyCreatedFacility(); facilityPage.clickManageFacilityDropdown(); facilityPage.clickViewUsersOption(); - userPage.verifyMultipleBadgesWithSameId(alreadylinkedusersviews); + userPage.verifyMultipleBadgesWithSameId(alreadyLinkedUsersViews); }); afterEach(() => { diff --git a/cypress/e2e/users_spec/UsersManage.cy.ts b/cypress/e2e/users_spec/UsersManage.cy.ts index 40d436be0a6..74baee3deac 100644 --- a/cypress/e2e/users_spec/UsersManage.cy.ts +++ b/cypress/e2e/users_spec/UsersManage.cy.ts @@ -2,7 +2,6 @@ import { advanceFilters } from "pageobject/utils/advanceFilterHelpers"; import LoginPage from "../../pageobject/Login/LoginPage"; import ManageUserPage from "../../pageobject/Users/ManageUserPage"; -import { UserCreationPage } from "../../pageobject/Users/UserCreation"; import { UserPage } from "../../pageobject/Users/UserSearch"; describe("Manage User", () => { @@ -15,7 +14,6 @@ describe("Manage User", () => { const usernameToLinkSkill = "devdoctor"; const firstNameUserSkill = "Dev"; const lastNameUserSkill = "Doctor"; - const userCreationPage = new UserCreationPage(); const usernameforworkinghour = "devdistrictadmin"; const usernamerealname = "Dummy Doctor"; const facilitytolinkusername = "Dummy Shifting Center"; @@ -48,10 +46,9 @@ describe("Manage User", () => { manageUserPage.clickCloseSlideOver(); cy.wait(5000); manageUserPage.navigateToProfile(); - userCreationPage.verifyElementContainsText( - "username-profile-details", + cy.verifyContentPresence("#username-profile-details", [ usernameforworkinghour, - ); + ]); manageUserPage.assertSkillInAlreadyLinkedSkills(linkedskill); }); diff --git a/cypress/e2e/users_spec/UsersProfile.cy.ts b/cypress/e2e/users_spec/UsersProfile.cy.ts index 35771024180..32b812a188f 100644 --- a/cypress/e2e/users_spec/UsersProfile.cy.ts +++ b/cypress/e2e/users_spec/UsersProfile.cy.ts @@ -32,25 +32,22 @@ describe("Manage User Profile", () => { it("Set Dob, Gender, Email, Phone and Working Hours for a user and verify its reflection in user profile", () => { userProfilePage.clickEditProfileButton(); - userProfilePage.typedate_of_birth(date_of_birth); + userProfilePage.typeDateOfBirth(date_of_birth); userProfilePage.selectGender(gender); userProfilePage.typeEmail(email); - userProfilePage.typePhone(phone); - userProfilePage.typeWhatsApp(phone); + userProfilePage.typePhoneNumber(phone); + userProfilePage.typeWhatsappNumber(phone); userProfilePage.typeWorkingHours(workinghours); userProfilePage.typeQualification(qualification); userProfilePage.typeDoctorYoE(doctorYoE); userProfilePage.typeMedicalCouncilRegistration(medicalCouncilRegistration); - userProfilePage.clickUpdateButton(); - cy.verifyNotification("Details updated successfully"); - - userProfilePage.assertdate_of_birth("01/01/1999"); + userProfilePage.assertDateOfBirth("01/01/1999"); userProfilePage.assertGender(gender); userProfilePage.assertEmail(email); - userProfilePage.assertPhone(phone); - userProfilePage.assertWhatsApp(phone); + userProfilePage.assertPhoneNumber(phone); + userProfilePage.assertAltPhoneNumber(phone); userProfilePage.assertWorkingHours(workinghours); }); diff --git a/cypress/pageobject/Users/UserCreation.ts b/cypress/pageobject/Users/UserCreation.ts index 906c07e797a..72157861f2c 100644 --- a/cypress/pageobject/Users/UserCreation.ts +++ b/cypress/pageobject/Users/UserCreation.ts @@ -1,69 +1,52 @@ // UserCreation.ts export class UserCreationPage { - clickElementById(elementId: string) { - cy.get("#" + elementId).click(); + clickAddUserButton() { + cy.verifyAndClickElement("#addUserButton", "Add New User"); } - - typeIntoElementById(elementId: string, value: string) { - cy.get("#" + elementId) - .click() - .type(value); + typeUserName(username: string) { + cy.get("#username").click().type(username); } - - typeIntoElementByIdPostClear(elementId: string, value: string) { - cy.get("#" + elementId) - .click() - .clear() - .click() - .type(value); + typeFirstName(firstName: string) { + cy.get("#firstName").click().type(firstName); } - typeIntoElementByIdPostClearDob(elementId: string, value: string) { - cy.clickAndTypeDate("#" + elementId, value); + typeLastName(lastName: string) { + cy.get("#lastName").click().type(lastName); } - clearIntoElementById(elementId: string) { - cy.get("#" + elementId) - .click() - .clear(); + typePassword(password: string) { + cy.get("#password").click().type(password); } - - typeIntoInputByName(inputName: string, value: string) { - cy.get("input[name='" + inputName + "']") - .click() - .type(value); + typeConfirmPassword(password: string) { + cy.get("#c_password").click().type(password); } - - selectOptionContainingText(text: string) { - cy.get("[role='option']").contains(text).click(); + clearFirstName() { + cy.get("#firstName").click().clear(); } - - verifyNotification(message: string) { - cy.verifyNotification(message); + clearLastName() { + cy.get("#lastName").click().clear(); } - - selectFacility(name: string) { - this.typeIntoInputByName("facilities", name); - this.selectOptionContainingText(name); - cy.get("input[name='facilities'] + button") - .find("#dropdown-toggle") - .click(); + selectUserType(role: string) { + cy.clickAndSelectOption("#user_type", role); } - selectHomeFacility(name: string) { - this.clickElementById("home_facility"); - this.selectOptionContainingText(name); + cy.clickAndSelectOption("#home_facility", name); } - setInputDate(dateElementId: string, dateValue: string) { - cy.clickAndTypeDate("#" + dateElementId, dateValue); + selectGender(gender: string) { + cy.clickAndSelectOption("#gender", gender); + } + selectState(state: string) { + cy.clickAndSelectOption("#state", state); + } + selectDistrict(district: string) { + cy.clickAndSelectOption("#district", district); } - selectDropdownOption(dropdownId: string, optionText: string) { - this.clickElementById(dropdownId); - this.selectOptionContainingText(optionText); + selectFacility(name: string) { + cy.typeAndSelectOption("input[name='facilities']", name); } - verifyElementContainsText(elementId: string, expectedText: string) { - cy.get("#" + elementId).should("contain.text", expectedText); + clickSaveUserButton() { + cy.clickSubmitButton("Save User"); } verifyErrorMessages(errorMessages: string[]) { diff --git a/cypress/pageobject/Users/UserProfilePage.ts b/cypress/pageobject/Users/UserProfilePage.ts index 3744c5a5d82..882be0b7b9b 100644 --- a/cypress/pageobject/Users/UserProfilePage.ts +++ b/cypress/pageobject/Users/UserProfilePage.ts @@ -12,11 +12,24 @@ export default class UserProfilePage { } clickUpdateButton() { - cy.get("#submit").click(); + cy.clickSubmitButton("Update"); } - typedate_of_birth(date_of_birth: string) { - cy.clickAndTypeDate("#date_of_birth", date_of_birth); + typeDateOfBirth(dob: string) { + cy.clickAndTypeDate("#date_of_birth", dob); + } + + clearPhoneNumber() { + cy.get("#phoneNumber").click().clear(); + } + clearAltPhoneNumber() { + cy.get("#altPhoneNumber").click().clear(); + } + clearWorkingHours() { + cy.get("#weekly_working_hours").click().clear(); + } + clearEmail() { + cy.get("#email").click().clear(); } selectGender(gender: string) { @@ -28,16 +41,16 @@ export default class UserProfilePage { cy.get("#email").click().clear().type(email); } - typePhone(phone: string) { + typePhoneNumber(phone: string) { cy.get("#phoneNumber").click().clear().type(phone); } - typeWhatsApp(phone: string) { + typeWhatsappNumber(phone: string) { cy.get("#altPhoneNumber").click().clear().type(phone); } - typeWorkingHours(workinghours: string) { - cy.get("#weekly_working_hours").click().clear().type(workinghours); + typeWorkingHours(workingHours: string) { + cy.get("#weekly_working_hours").click().clear().type(workingHours); } typeQualification = (qualification: string) => { @@ -55,11 +68,8 @@ export default class UserProfilePage { .type(medicalCouncilRegistration); }; - assertdate_of_birth(date_of_birth: string) { - cy.get("#date_of_birth-profile-details").should( - "contain.text", - date_of_birth, - ); + assertDateOfBirth(dob: string) { + cy.get("#date_of_birth-profile-details").should("contain.text", dob); } assertGender(gender: string) { @@ -70,18 +80,18 @@ export default class UserProfilePage { cy.get("#emailid-profile-details").should("contain.text", email); } - assertPhone(phone: string) { + assertPhoneNumber(phone: string) { cy.get("#contactno-profile-details").should("contain.text", phone); } - assertWhatsApp(phone: string) { + assertAltPhoneNumber(phone: string) { cy.get("#whatsapp-profile-details").should("contain.text", phone); } - assertWorkingHours(workinghours: string) { + assertWorkingHours(workingHours: string) { cy.get("#averageworkinghour-profile-details").should( "contain.text", - workinghours, + workingHours, ); } } diff --git a/cypress/pageobject/utils/constants.ts b/cypress/pageobject/utils/constants.ts index 08411e84b6a..053d0561ce8 100644 --- a/cypress/pageobject/utils/constants.ts +++ b/cypress/pageobject/utils/constants.ts @@ -1,7 +1,10 @@ -export function generatePhoneNumber() { - return "9" + Math.floor(100000000 + Math.random() * 900000000).toString(); +export function generatePhoneNumber(): string { + const array = new Uint32Array(1); + window.crypto.getRandomValues(array); + const randomNum = (array[0] % 900000000) + 100000000; + return "9" + randomNum.toString(); } -export function generateEmergencyPhoneNumber() { - return "9" + Math.floor(100000000 + Math.random() * 900000000).toString(); +export function generateEmergencyPhoneNumber(): string { + return generatePhoneNumber(); } From 7d56fdc69265b21c8ebc60f7fffc97e4ad5612df Mon Sep 17 00:00:00 2001 From: Rajab Shoukath Kunnath <142793649+rayyjeb@users.noreply.github.com> Date: Sat, 30 Nov 2024 09:47:35 +0530 Subject: [PATCH 09/26] Fixed Breadcrumb to Display Detailed Name Instead of ID (#9200) --- src/components/Patient/SampleDetails.tsx | 1 + src/components/Patient/models.tsx | 2 +- src/components/Shifting/ShiftDetails.tsx | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/Patient/SampleDetails.tsx b/src/components/Patient/SampleDetails.tsx index edc0b4d53a6..abf099a6e7d 100644 --- a/src/components/Patient/SampleDetails.tsx +++ b/src/components/Patient/SampleDetails.tsx @@ -300,6 +300,7 @@ export const SampleDetails = ({ id }: DetailRoute) => { return ( From f2a96983f225789bd6758ef4b4ef8682091f71e1 Mon Sep 17 00:00:00 2001 From: Mahendar Chikolla <119734520+Mahendar0701@users.noreply.github.com> Date: Sat, 30 Nov 2024 10:06:09 +0530 Subject: [PATCH 10/26] Fix : Advanced Filters Autofilling on Revisit to Patient Tab (#9251) --- src/components/Patient/ManagePatients.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/Patient/ManagePatients.tsx b/src/components/Patient/ManagePatients.tsx index 0664532b0a1..9507ce3d8d7 100644 --- a/src/components/Patient/ManagePatients.tsx +++ b/src/components/Patient/ManagePatients.tsx @@ -1143,7 +1143,10 @@ export const PatientManager = () => { />
- +
{managePatients}
From 66326dd053cffbb7020f4381ad397217b4de2698 Mon Sep 17 00:00:00 2001 From: Don Xavier <98073418+DonXavierdev@users.noreply.github.com> Date: Sat, 30 Nov 2024 10:09:06 +0530 Subject: [PATCH 11/26] Add edit button to immunisation section; replaced buttons with shadcn buttons across PatientsDetail section (#9245) --- .../Patient/PatientDetailsTab/Demography.tsx | 54 +++++++++---------- .../HealthProfileSummary.tsx | 12 +++-- .../PatientDetailsTab/ImmunisationRecords.tsx | 12 +++-- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/components/Patient/PatientDetailsTab/Demography.tsx b/src/components/Patient/PatientDetailsTab/Demography.tsx index 2a412f03f9a..b9d2b8fece4 100644 --- a/src/components/Patient/PatientDetailsTab/Demography.tsx +++ b/src/components/Patient/PatientDetailsTab/Demography.tsx @@ -5,8 +5,9 @@ import { useTranslation } from "react-i18next"; import Chip from "@/CAREUI/display/Chip"; import CareIcon from "@/CAREUI/icons/CareIcon"; +import AuthorizedChild from "@/CAREUI/misc/AuthorizedChild"; -import ButtonV2 from "@/components/Common/ButtonV2"; +import { Button } from "@/components/ui/button"; import useAuthUser from "@/hooks/useAuthUser"; @@ -312,10 +313,9 @@ export const Demography = (props: PatientProps) => { {t("no_data_found")}
)} - handleEditClick("insurance-details"), @@ -323,7 +323,7 @@ export const Demography = (props: PatientProps) => { > {t("add_insurance_details")} - +
, ], }, @@ -373,21 +373,24 @@ export const Demography = (props: PatientProps) => {
- - navigate( - `/facility/${patientData?.facility}/patient/${id}/update`, - ), + + {({ isAuthorized }) => ( + )} - > - - {t("edit_profile")} - +
{/*
@@ -415,22 +418,19 @@ export const Demography = (props: PatientProps) => { className="group mt-4 rounded-md bg-white pb-2 pl-5 pt-5 shadow" >
-
+

{t(`patient__${subtab.id}`)}

{subtab.allowEdit && ( - + )}
diff --git a/src/components/Patient/PatientDetailsTab/HealthProfileSummary.tsx b/src/components/Patient/PatientDetailsTab/HealthProfileSummary.tsx index 3fb6b60d330..374d5ede08b 100644 --- a/src/components/Patient/PatientDetailsTab/HealthProfileSummary.tsx +++ b/src/components/Patient/PatientDetailsTab/HealthProfileSummary.tsx @@ -3,6 +3,8 @@ import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; +import { Button } from "@/components/ui/button"; + import { UserModel } from "@/components/Users/models"; import useAuthUser from "@/hooks/useAuthUser"; @@ -56,12 +58,12 @@ export const HealthProfileSummary = (props: PatientProps) => {

-
+
{t("medical")}
- +
diff --git a/src/components/Patient/PatientDetailsTab/ImmunisationRecords.tsx b/src/components/Patient/PatientDetailsTab/ImmunisationRecords.tsx index eb298737f3c..7ee828868fc 100644 --- a/src/components/Patient/PatientDetailsTab/ImmunisationRecords.tsx +++ b/src/components/Patient/PatientDetailsTab/ImmunisationRecords.tsx @@ -3,6 +3,8 @@ import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; +import { Button } from "@/components/ui/button"; + import { UserModel } from "@/components/Users/models"; import useAuthUser from "@/hooks/useAuthUser"; @@ -40,10 +42,10 @@ export const ImmunisationRecords = (props: PatientProps) => {

-
+

{t("covid_details")}

- +
From 8118ccfa3c07d883336050b3fb694bffc735c14e Mon Sep 17 00:00:00 2001 From: HITMAN <112652819+ayushpatil2122@users.noreply.github.com> Date: Sat, 30 Nov 2024 16:39:33 +0530 Subject: [PATCH 12/26] phone size responsive issue shifting details page (#9256) --- package-lock.json | 8 ++++---- package.json | 2 +- src/components/Shifting/ShiftDetails.tsx | 13 +++++-------- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c703af8fe1..97073c88ecb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,7 +92,7 @@ "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^5.0.0", "glob": "^11.0.0", - "husky": "^9.1.6", + "husky": "^9.1.7", "jsdom": "^25.0.1", "lint-staged": "^15.2.10", "local-cypress": "^1.2.6", @@ -10449,9 +10449,9 @@ "license": "Unlicense" }, "node_modules/husky": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.6.tgz", - "integrity": "sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==", + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", "dev": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index 020d73f5e65..798c910ea91 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^5.0.0", "glob": "^11.0.0", - "husky": "^9.1.6", + "husky": "^9.1.7", "jsdom": "^25.0.1", "lint-staged": "^15.2.10", "local-cypress": "^1.2.6", diff --git a/src/components/Shifting/ShiftDetails.tsx b/src/components/Shifting/ShiftDetails.tsx index 3eeb440a1b1..bc97b0b0f24 100644 --- a/src/components/Shifting/ShiftDetails.tsx +++ b/src/components/Shifting/ShiftDetails.tsx @@ -483,25 +483,22 @@ export default function ShiftDetails(props: { id: string }) { }} backUrl="/shifting/board" options={ -
+
- navigate(`/shifting/${data?.external_id}/update`) - } + disabled={data?.status === "COMPLETED" || data?.status === "CANCELLED"} + onClick={() => navigate(`/shifting/${data?.external_id}/update`)} > {t("update_status_details")} - setIsPrintMode(true)}> + setIsPrintMode(true)}> {" "} {t("referral_letter")} From f76c6250ec25c6d9216f58088ca4f9833e872743 Mon Sep 17 00:00:00 2001 From: Kamishetty Rishith <119791436+Rishith25@users.noreply.github.com> Date: Sun, 1 Dec 2024 12:21:46 +0530 Subject: [PATCH 13/26] =?UTF-8?q?Fix:=20Reflect=20Updated=20Service=20Note?= =?UTF-8?q?s=20Immediately=20in=20Asset=20Details=20without=C2=A0page?= =?UTF-8?q?=C2=A0reload=20(#9226)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Assets/AssetManage.tsx | 11 +++++++++-- src/components/Shifting/ShiftDetails.tsx | 13 ++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/components/Assets/AssetManage.tsx b/src/components/Assets/AssetManage.tsx index c78be71d627..b4377d2e1aa 100644 --- a/src/components/Assets/AssetManage.tsx +++ b/src/components/Assets/AssetManage.tsx @@ -69,7 +69,11 @@ const AssetManage = (props: AssetManageProps) => { >(); const [transactionFilter, setTransactionFilter] = useState({}); - const { data: asset, loading } = useQuery(routes.getAsset, { + const { + data: asset, + loading, + refetch, + } = useQuery(routes.getAsset, { pathParams: { external_id: assetId, }, @@ -594,7 +598,10 @@ const AssetManage = (props: AssetManageProps) => { handleClose={() => setServiceEditData({ ...serviceEditData, open: false }) } - handleUpdate={() => serviceRefetch()} + handleUpdate={() => { + serviceRefetch(); + refetch(); + }} show={serviceEditData.open} viewOnly={serviceEditData.viewOnly} /> diff --git a/src/components/Shifting/ShiftDetails.tsx b/src/components/Shifting/ShiftDetails.tsx index bc97b0b0f24..cb5140d6ed0 100644 --- a/src/components/Shifting/ShiftDetails.tsx +++ b/src/components/Shifting/ShiftDetails.tsx @@ -492,13 +492,20 @@ export default function ShiftDetails(props: { id: string }) { : "" } tooltipClassName="tooltip-top -translate-x-28 -translate-y-1 text-xs" - disabled={data?.status === "COMPLETED" || data?.status === "CANCELLED"} - onClick={() => navigate(`/shifting/${data?.external_id}/update`)} + disabled={ + data?.status === "COMPLETED" || data?.status === "CANCELLED" + } + onClick={() => + navigate(`/shifting/${data?.external_id}/update`) + } > {t("update_status_details")} - setIsPrintMode(true)}> + setIsPrintMode(true)} + > {" "} {t("referral_letter")} From 2d9669e75f4f5a04b803d64bfaae2e1d1fb2a0d9 Mon Sep 17 00:00:00 2001 From: Jacob John Jeevan <40040905+Jacobjeevan@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:22:44 +0530 Subject: [PATCH 14/26] Camera Preset Not Resetting on Re-selection Bug (#9186) --- public/locale/en.json | 2 + .../ConsultationFeedTab.tsx | 39 ++++++------------- 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index cd921bef06a..7e92d927a64 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -945,6 +945,7 @@ "next_sessions": "Next Sessions", "no": "No", "no_attachments_found": "This communication has no attachments.", + "no_bed_asset_linked_allocated": "No bed/asset linked allocated", "no_bed_types_found": "No Bed Types found", "no_beds_available": "No beds available", "no_changes": "No changes", @@ -1364,6 +1365,7 @@ "update_facility_middleware_success": "Facility middleware updated successfully", "update_log": "Update Log", "update_patient_details": "Update Patient Details", + "update_preset": "Update Preset", "update_preset_position_to_current": "Update preset's position to camera's current position", "update_record": "Update Record", "update_record_for_asset": "Update record for asset", diff --git a/src/components/Facility/ConsultationDetails/ConsultationFeedTab.tsx b/src/components/Facility/ConsultationDetails/ConsultationFeedTab.tsx index 21c6f304cb5..bc518feb02f 100644 --- a/src/components/Facility/ConsultationDetails/ConsultationFeedTab.tsx +++ b/src/components/Facility/ConsultationDetails/ConsultationFeedTab.tsx @@ -34,6 +34,7 @@ export const ConsultationFeedTab = (props: ConsultationTabProps) => { const bed = props.consultationData.current_bed?.bed_object; const feedStateSessionKey = `encounterFeedState[${props.consultationId}]`; const [preset, setPreset] = useState(); + const [selectedPreset, setSelectedPreset] = useState(); const [showPresetSaveConfirmation, setShowPresetSaveConfirmation] = useState(false); const [isUpdatingPreset, setIsUpdatingPreset] = useState(false); @@ -78,28 +79,14 @@ export const ConsultationFeedTab = (props: ConsultationTabProps) => { return presets.find((obj) => obj.id === lastState.value); } if (lastState.type === "position") { - const assetBedObj = presets.find( - (p) => p.asset_bed.id === lastState.assetBed, - )?.asset_bed; - - if (!assetBedObj) { - return; - } - - return { - ...presets[0], - id: "", - asset_bed: assetBedObj, - position: lastState.value, - } satisfies CameraPreset; + return; } } })() ?? presets[0]; - console.log({ preset, presets }); - if (preset) { setPreset(preset); + setSelectedPreset(preset); } }, }); @@ -126,6 +113,7 @@ export const ConsultationFeedTab = (props: ConsultationTabProps) => { await presetsQuery.refetch(); setPreset(updated); + setSelectedPreset(updated); setHasMoved(false); setIsUpdatingPreset(false); setShowPresetSaveConfirmation(false); @@ -154,7 +142,7 @@ export const ConsultationFeedTab = (props: ConsultationTabProps) => { } if (!bed || !asset) { - return No bed/asset linked allocated; + return {t("no_bed_asset_linked_allocated")}; } const cannotSaveToPreset = !hasMoved || !preset?.id; @@ -162,8 +150,8 @@ export const ConsultationFeedTab = (props: ConsultationTabProps) => { return ( setShowPresetSaveConfirmation(false)} @@ -180,11 +168,9 @@ export const ConsultationFeedTab = (props: ConsultationTabProps) => { { - if (!preset) { - return; - } + setSelectedPreset(undefined); setHasMoved(true); setTimeout(async () => { const { data } = await operate({ type: "get_status" }); @@ -193,7 +179,6 @@ export const ConsultationFeedTab = (props: ConsultationTabProps) => { feedStateSessionKey, JSON.stringify({ type: "position", - assetBed: preset.asset_bed.id, value: (data as GetStatusResponse).result.position, } satisfies LastAccessedPosition), ); @@ -222,16 +207,17 @@ export const ConsultationFeedTab = (props: ConsultationTabProps) => { obj.name} - value={preset} + value={selectedPreset} onChange={(value) => { triggerGoal("Camera Preset Clicked", { - presetName: preset?.name, + presetName: selectedPreset?.name, consultationId: props.consultationId, userId: authUser.id, result: "success", }); setHasMoved(false); setPreset(value); + setSelectedPreset(value); }} /> {isUpdatingPreset ? ( @@ -277,7 +263,6 @@ type LastAccessedPreset = { type LastAccessedPosition = { type: "position"; - assetBed: string; value: PTZPayload; }; From 1868edd32cfcd0abfebe8e9c93cf687758e74278 Mon Sep 17 00:00:00 2001 From: Nithish Kumar Siliveru Date: Tue, 3 Dec 2024 20:54:36 +0530 Subject: [PATCH 15/26] Update Sample File Upload and upgrade buttons to Shadcn button (#9157) --- public/locale/en.json | 1 + src/components/Patient/UpdateStatusDialog.tsx | 190 ++++++++---------- src/components/ui/button.tsx | 2 + 3 files changed, 82 insertions(+), 111 deletions(-) diff --git a/public/locale/en.json b/public/locale/en.json index 7e92d927a64..b5f46dd7308 100644 --- a/public/locale/en.json +++ b/public/locale/en.json @@ -1380,6 +1380,7 @@ "upload_headings__patient": "Upload New Patient File", "upload_headings__sample_report": "Upload Sample Report", "upload_headings__supporting_info": "Upload Supporting Info", + "upload_report": "Upload Report", "uploading": "Uploading", "use_existing_abha_address": "Use Existing ABHA Address", "user_deleted_successfuly": "User Deleted Successfuly", diff --git a/src/components/Patient/UpdateStatusDialog.tsx b/src/components/Patient/UpdateStatusDialog.tsx index 9414ba9bb95..e9a767847aa 100644 --- a/src/components/Patient/UpdateStatusDialog.tsx +++ b/src/components/Patient/UpdateStatusDialog.tsx @@ -1,31 +1,28 @@ -import { useEffect, useReducer, useState } from "react"; +import { useEffect, useReducer } from "react"; import { useTranslation } from "react-i18next"; import CareIcon from "@/CAREUI/icons/CareIcon"; -import { Submit } from "@/components/Common/ButtonV2"; +import { Button } from "@/components/ui/button"; + import ConfirmDialog from "@/components/Common/ConfirmDialog"; import { LinearProgressWithLabel } from "@/components/Files/FileUpload"; import CheckBoxFormField from "@/components/Form/FormFields/CheckBoxFormField"; import { SelectFormField } from "@/components/Form/FormFields/SelectFormField"; import TextFormField from "@/components/Form/FormFields/TextFormField"; import { FieldChangeEvent } from "@/components/Form/FormFields/Utils"; -import { - CreateFileResponse, - SampleTestModel, -} from "@/components/Patient/models"; + +import useFileUpload from "@/hooks/useFileUpload"; import { - HEADER_CONTENT_TYPES, SAMPLE_FLOW_RULES, SAMPLE_TEST_RESULT, SAMPLE_TEST_STATUS, } from "@/common/constants"; import * as Notification from "@/Utils/Notifications"; -import routes from "@/Utils/request/api"; -import request from "@/Utils/request/request"; -import uploadFile from "@/Utils/request/uploadFile"; + +import { SampleTestModel } from "./models"; interface Props { sample: SampleTestModel; @@ -34,7 +31,6 @@ interface Props { } const statusChoices = [...SAMPLE_TEST_STATUS]; - const statusFlow = { ...SAMPLE_FLOW_RULES }; const initForm: any = { @@ -60,17 +56,16 @@ const updateStatusReducer = (state = initialState, action: any) => { return state; } }; - const UpdateStatusDialog = (props: Props) => { const { t } = useTranslation(); const { sample, handleOk, handleCancel } = props; const [state, dispatch] = useReducer(updateStatusReducer, initialState); - const [file, setfile] = useState(); - const [contentType, setcontentType] = useState(""); - const [uploadPercent, setUploadPercent] = useState(0); - const [uploadStarted, setUploadStarted] = useState(false); - const [uploadDone, setUploadDone] = useState(false); + const fileUpload = useFileUpload({ + type: "SAMPLE_MANAGEMENT", + allowedExtensions: ["pdf", "jpg", "jpeg", "png"], + allowNameFallback: true, + }); const currentStatus = SAMPLE_TEST_STATUS.find( (i) => i.text === sample.status, ); @@ -104,79 +99,26 @@ const UpdateStatusDialog = (props: Props) => { dispatch({ type: "set_form", form }); }; - const uploadfile = (data: CreateFileResponse) => { - const url = data.signed_url; - const internal_name = data.internal_name; - - const f = file; - if (f === undefined) return; - const newFile = new File([f], `${internal_name}`); - - uploadFile( - url, - newFile, - "PUT", - { - "Content-Type": contentType, - "Content-disposition": "inline", - }, - (xhr: XMLHttpRequest) => { - if (xhr.status >= 200 && xhr.status < 300) { - setUploadStarted(false); - setUploadDone(true); - request(routes.editUpload, { - pathParams: { - id: data.id, - fileType: "SAMPLE_MANAGEMENT", - associatingId: sample.id?.toString() ?? "", - }, - body: { upload_completed: true }, - }); - Notification.Success({ msg: "File Uploaded Successfully" }); + const handleUpload = async () => { + if (fileUpload.files.length > 0) { + if (!fileUpload.fileNames[0]) { + Notification.Error({ + msg: "Please enter a file name before uploading", + }); + return; + } + if (sample.id) { + await fileUpload.handleFileUpload(sample.id); + if (!fileUpload.error) { + return; } else { - setUploadStarted(false); + Notification.Error({ msg: `Upload failed: ${fileUpload.error}` }); } - }, - setUploadPercent, - () => { - setUploadStarted(false); - }, - ); - }; - - const onFileChange = (e: React.ChangeEvent) => { - if (e.target.files == null) { - throw new Error("Error finding e.target.files"); - } - setfile(e.target.files[0]); - const fileName = e.target.files[0].name; - const ext: string = fileName.split(".")[1]; - setcontentType( - HEADER_CONTENT_TYPES[ext as keyof typeof HEADER_CONTENT_TYPES], - ); - return e.target.files[0]; - }; - const handleUpload = async () => { - const f = file; - if (f === undefined) return; - const category = "UNSPECIFIED"; - const name = f.name; - setUploadStarted(true); - setUploadDone(false); - - const { data } = await request(routes.createUpload, { - body: { - original_name: name, - file_type: "SAMPLE_MANAGEMENT", - name: `${sample.patient_name} Sample Report`, - associating_id: sample.id ?? "", - file_category: category, - mime_type: contentType, - }, - }); - - if (data) { - uploadfile(data); + } else { + Notification.Error({ msg: "Sample ID is missing" }); + } + } else { + Notification.Error({ msg: "No file selected for upload" }); } }; @@ -218,32 +160,58 @@ const UpdateStatusDialog = (props: Props) => { onChange={handleChange} /> - Upload Report : + {t("upload_report")}: - {uploadStarted ? ( - - ) : ( -
-