diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 67628d414c8..3c9d6aa28cb 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -11,6 +11,10 @@ on: - master workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: IMAGE_NAME: care_fe AWS_DEFAULT_REGION: ap-south-1 diff --git a/cypress/e2e/patient_spec/patient_crud.cy.ts b/cypress/e2e/patient_spec/patient_crud.cy.ts index 4fef861aeab..57bae83a880 100644 --- a/cypress/e2e/patient_spec/patient_crud.cy.ts +++ b/cypress/e2e/patient_spec/patient_crud.cy.ts @@ -111,7 +111,9 @@ describe("Patient Creation with consultation", () => { updatePatientPage.visitConsultationPage(); patientPage.verifyStatusCode(); patientConsultationPage.fillIllnessHistory("history"); - patientConsultationPage.selectConsultationStatus("Out-patient (walk in)"); + patientConsultationPage.selectConsultationStatus( + "Outpatient/Emergency Room" + ); patientConsultationPage.selectSymptoms("ASYMPTOMATIC"); patientConsultationPage.enterConsultationDetails( @@ -140,9 +142,6 @@ describe("Patient Creation with consultation", () => { updatePatientPage.visitUpdatedPatient(); patientConsultationPage.visitEditConsultationPage(); patientConsultationPage.fillIllnessHistory("editted"); - patientConsultationPage.selectConsultationStatus( - "Referred from other hospital" - ); patientConsultationPage.updateSymptoms("FEVER"); patientConsultationPage.setSymptomsDate("01082023"); patientConsultationPage.updateConsultation(); diff --git a/cypress/pageobject/Patient/PatientConsultation.ts b/cypress/pageobject/Patient/PatientConsultation.ts index ce1fdc1e393..4fb299a4965 100644 --- a/cypress/pageobject/Patient/PatientConsultation.ts +++ b/cypress/pageobject/Patient/PatientConsultation.ts @@ -1,8 +1,8 @@ export class PatientConsultationPage { selectConsultationStatus(status: string) { - cy.get("#consultation_status").scrollIntoView(); - cy.get("#consultation_status").should("be.visible"); - cy.get("#consultation_status") + cy.get("#route_to_facility").scrollIntoView(); + cy.get("#route_to_facility").should("be.visible"); + cy.get("#route_to_facility") .click() .then(() => { cy.get("[role='option']").contains(status).click(); @@ -60,7 +60,7 @@ export class PatientConsultationPage { cy.get("#principal-diagnosis-select [role='option']").first().click(); cy.get("#consultation_notes").click().type(consulationNotes); - cy.get("#verified_by") + cy.get("#treating_physician") .click() .type(verificationBy) .then(() => { @@ -203,12 +203,13 @@ export class PatientConsultationPage { } addDoctorsNotes(notes: string) { + cy.get("#expand_doctor_notes").click(); cy.get("#doctor_notes_textarea").type(notes); } postDoctorNotes() { cy.intercept("POST", "**/api/v1/patient/*/notes").as("postDoctorNotes"); - cy.get("#submit").contains("Post Your Note").click(); + cy.get("#add_doctor_note_button").click(); cy.wait("@postDoctorNotes").its("response.statusCode").should("eq", 201); } diff --git a/package-lock.json b/package-lock.json index d65f617ec05..ebb35bc465c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,6 +46,7 @@ "react-dom": "18.2.0", "react-google-recaptcha": "^3.1.0", "react-i18next": "^13.0.1", + "react-infinite-scroll-component": "^6.1.0", "react-markdown": "^8.0.7", "react-player": "^2.13.0", "react-qr-reader": "^2.2.1", @@ -19399,6 +19400,17 @@ } } }, + "node_modules/react-infinite-scroll-component": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz", + "integrity": "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ==", + "dependencies": { + "throttle-debounce": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.0.0" + } + }, "node_modules/react-inspector": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-6.0.2.tgz", @@ -21527,6 +21539,14 @@ "node": ">=0.8" } }, + "node_modules/throttle-debounce": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz", + "integrity": "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ==", + "engines": { + "node": ">=8" + } + }, "node_modules/throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", diff --git a/package.json b/package.json index ca3f6920a12..cbe2267c40d 100644 --- a/package.json +++ b/package.json @@ -86,6 +86,7 @@ "react-dom": "18.2.0", "react-google-recaptcha": "^3.1.0", "react-i18next": "^13.0.1", + "react-infinite-scroll-component": "^6.1.0", "react-markdown": "^8.0.7", "react-player": "^2.13.0", "react-qr-reader": "^2.2.1", diff --git a/src/CAREUI/icons/UniconPaths.json b/src/CAREUI/icons/UniconPaths.json index 9a2673695aa..c2ed7ecf467 100644 --- a/src/CAREUI/icons/UniconPaths.json +++ b/src/CAREUI/icons/UniconPaths.json @@ -3107,10 +3107,7 @@ 24, "M19,2H5A3,3,0,0,0,2,5V19a3,3,0,0,0,3,3H19a3,3,0,0,0,3-3V5A3,3,0,0,0,19,2Zm1,17a1,1,0,0,1-1,1H5a1,1,0,0,1-1-1V5A1,1,0,0,1,5,4H19a1,1,0,0,1,1,1Zm-4-8H8a1,1,0,0,0,0,2h8a1,1,0,0,0,0-2Z" ], - "l-minus": [ - 24, - "M19,11H5a1,1,0,0,0,0,2H19a1,1,0,0,0,0-2Z" - ], + "l-minus": [24, "M19,11H5a1,1,0,0,0,0,2H19a1,1,0,0,0,0-2Z"], "l-missed-call": [ 24, "M6,7.49a1,1,0,0,0,1-1V5.9L9.88,8.78a3,3,0,0,0,4.24,0l4.59-4.59a1,1,0,0,0,0-1.41,1,1,0,0,0-1.42,0L12.71,7.36a1,1,0,0,1-1.42,0L8.41,4.49H9a1,1,0,0,0,0-2H6a1,1,0,0,0-.92.61A1.09,1.09,0,0,0,5,3.49v3A1,1,0,0,0,6,7.49Zm15.94,7.36a16.27,16.27,0,0,0-19.88,0,2.69,2.69,0,0,0-1,2,2.66,2.66,0,0,0,.78,2.07L3.6,20.72A2.68,2.68,0,0,0,7.06,21l.47-.32a8.13,8.13,0,0,1,1-.55,1.85,1.85,0,0,0,1-2.3l-.09-.24a10.49,10.49,0,0,1,5.22,0l-.09.24a1.85,1.85,0,0,0,1,2.3,8.13,8.13,0,0,1,1,.55l.47.32a2.58,2.58,0,0,0,1.54.5,2.72,2.72,0,0,0,1.92-.79l1.81-1.82A2.66,2.66,0,0,0,23,16.83,2.69,2.69,0,0,0,21.94,14.85ZM20.8,17.49,19,19.3a.68.68,0,0,1-.86.1c-.19-.14-.38-.27-.59-.4a11.65,11.65,0,0,0-1.09-.61l.4-1.09a1,1,0,0,0-.6-1.28,12.42,12.42,0,0,0-8.5,0,1,1,0,0,0-.6,1.28l.4,1.1a9.8,9.8,0,0,0-1.1.6l-.58.4A.66.66,0,0,1,5,19.3L3.2,17.49A.67.67,0,0,1,3,17a.76.76,0,0,1,.28-.53,14.29,14.29,0,0,1,17.44,0A.76.76,0,0,1,21,17,.67.67,0,0,1,20.8,17.49Z" @@ -4295,10 +4292,7 @@ 24, "M15,13H9a1,1,0,0,0,0,2h2v2a1,1,0,0,0,2,0V15h2a1,1,0,0,0,0-2Zm2-7H7A1,1,0,0,0,7,8h4v2a1,1,0,0,0,2,0V8h4a1,1,0,0,0,0-2Z" ], - "l-text": [ - 24, - "M17,6H7A1,1,0,0,0,7,8h4v9a1,1,0,0,0,2,0V8h4a1,1,0,0,0,0-2Z" - ], + "l-text": [24, "M17,6H7A1,1,0,0,0,7,8h4v9a1,1,0,0,0,2,0V8h4a1,1,0,0,0,0-2Z"], "l-th-large": [ 24, "M20,3H4A1,1,0,0,0,3,4V20a1,1,0,0,0,1,1H20a1,1,0,0,0,1-1V4A1,1,0,0,0,20,3ZM11,19H5V13h6Zm0-8H5V5h6Zm8,8H13V13h6Zm0-8H13V5h6Z" @@ -4841,4 +4835,4 @@ 256, "M204.73 51.85A108.07 108.07 0 0 0 20 128v56a28 28 0 0 0 28 28h16a28 28 0 0 0 28-28v-40a28 28 0 0 0-28-28H44.84A84.05 84.05 0 0 1 128 44h.64a83.7 83.7 0 0 1 82.52 72H192a28 28 0 0 0-28 28v40a28 28 0 0 0 28 28h19.6a20 20 0 0 1-19.6 16h-56a12 12 0 0 0 0 24h56a44.05 44.05 0 0 0 44-44v-80a107.34 107.34 0 0 0-31.27-76.15ZM64 140a4 4 0 0 1 4 4v40a4 4 0 0 1-4 4H48a4 4 0 0 1-4-4v-44Zm124 44v-40a4 4 0 0 1 4-4h20v48h-20a4 4 0 0 1-4-4Z" ] -} \ No newline at end of file +} diff --git a/src/CAREUI/misc/PaginatedList.tsx b/src/CAREUI/misc/PaginatedList.tsx index 0d2445ffbc9..02ee0e3d90e 100644 --- a/src/CAREUI/misc/PaginatedList.tsx +++ b/src/CAREUI/misc/PaginatedList.tsx @@ -121,7 +121,7 @@ PaginatedList.Refresh = Refresh; interface ItemsProps { className?: string; - children: (item: TItem) => JSX.Element | JSX.Element[]; + children: (item: TItem, items: TItem[]) => JSX.Element | JSX.Element[]; shimmer?: JSX.Element; shimmerCount?: number; } @@ -137,9 +137,9 @@ const Items = (props: ItemsProps) => { {props.shimmer} )) - : items.map((item, index) => ( + : items.map((item, index, items) => (
  • - {props.children(item)} + {props.children(item, items)}
  • ))} diff --git a/src/Common/constants.tsx b/src/Common/constants.tsx index aa1e018bb86..069a39e1539 100644 --- a/src/Common/constants.tsx +++ b/src/Common/constants.tsx @@ -332,14 +332,6 @@ export const CONSULTATION_SUGGESTION = [ { id: "DD", text: "Declare Death" }, ]; -export const CONSULTATION_STATUS = [ - { id: "1", text: "Brought Dead" }, - { id: "2", text: "Transferred from ward" }, - { id: "3", text: "Transferred from ICU" }, - { id: "4", text: "Referred from other hospital" }, - { id: "5", text: "Out-patient (walk in)" }, -]; - export const ADMITTED_TO = [ { id: "1", text: "Isolation" }, { id: "2", text: "ICU" }, @@ -610,6 +602,11 @@ export const NOTIFICATION_EVENTS = [ text: "Shifting Updated", icon: "fa-solid fa-truck-medical", }, + { + id: "PATIENT_NOTE_ADDED", + text: "Patient Note Added", + icon: "fa-solid fa-message", + }, ]; export const BREATHLESSNESS_LEVEL = [ @@ -1023,6 +1020,23 @@ export const XLSXAssetImportSchema = { }, }; +export const USER_TYPES_MAP = { + Pharmacist: "Pharmacist", + Volunteer: "Volunteer", + StaffReadOnly: "Staff", + Staff: "Staff", + Doctor: "Doctor", + WardAdmin: "Ward Admin", + LocalBodyAdmin: "Local Body Admin", + DistrictLabAdmin: "District Lab Admin", + DistrictReadOnlyAdmin: "District Admin", + DistrictAdmin: "District Admin", + StateLabAdmin: "State Lab Admin", + StateReadOnlyAdmin: "State Admin", + StateAdmin: "State Admin", + RemoteSpecialist: "Remote Specialist", +}; + export const AREACODES: Record = { CA: [ "403", diff --git a/src/Components/ABDM/ConfigureHealthFacility.tsx b/src/Components/ABDM/ConfigureHealthFacility.tsx index 16e6bf90ea4..a84e4b6d4b9 100644 --- a/src/Components/ABDM/ConfigureHealthFacility.tsx +++ b/src/Components/ABDM/ConfigureHealthFacility.tsx @@ -1,7 +1,7 @@ import { lazy, useReducer, useState } from "react"; import * as Notification from "../../Utils/Notifications.js"; import { navigate } from "raviger"; -import { Cancel, Submit } from "../Common/components/ButtonV2"; +import { Submit } from "../Common/components/ButtonV2"; import TextFormField from "../Form/FormFields/TextFormField"; import { classNames } from "../../Utils/utils"; import useQuery from "../../Utils/request/useQuery"; @@ -218,7 +218,6 @@ export const ConfigureHealthFacility = (props: any) => {
    - navigate(`/facility/${facilityId}`)} /> { if ( dayjs(date.value).format("YYYY-MM-DD") > diff --git a/src/Components/Assets/AssetsList.tsx b/src/Components/Assets/AssetsList.tsx index 8c19928fbee..447bff1c1d0 100644 --- a/src/Components/Assets/AssetsList.tsx +++ b/src/Components/Assets/AssetsList.tsx @@ -63,6 +63,10 @@ const AssetsList = () => { asset_class: qParams.asset_class || "", location: qParams.facility ? qParams.location || "" : "", status: qParams.status || "", + warranty_amc_end_of_validity_before: + qParams.warranty_amc_end_of_validity_before || "", + warranty_amc_end_of_validity_after: + qParams.warranty_amc_end_of_validity_after || "", }; const { loading } = useQuery(routes.listAssets, { @@ -189,12 +193,12 @@ const AssetsList = () => {

    diff --git a/src/Components/Common/DateInputV2.tsx b/src/Components/Common/DateInputV2.tsx index 95652e68638..da974fbe0e9 100644 --- a/src/Components/Common/DateInputV2.tsx +++ b/src/Components/Common/DateInputV2.tsx @@ -4,6 +4,8 @@ import CareIcon from "../../CAREUI/icons/CareIcon"; import { Popover } from "@headlessui/react"; import { classNames } from "../../Utils/utils"; import dayjs from "../../Utils/dayjs"; +import * as Notification from "../../Utils/Notifications.js"; +import { t } from "i18next"; type DatePickerType = "date" | "month" | "year"; export type DatePickerPosition = "LEFT" | "RIGHT" | "CENTER"; @@ -16,6 +18,7 @@ interface Props { value: Date | undefined; min?: Date; max?: Date; + outOfLimitsErrorMessage?: string; onChange: (date: Date) => void; position?: DatePickerPosition; disabled?: boolean; @@ -34,6 +37,7 @@ const DateInputV2: React.FC = ({ value, min, max, + outOfLimitsErrorMessage, onChange, position, disabled, @@ -100,16 +104,21 @@ const DateInputV2: React.FC = ({ ) => void; const setDateValue = (date: number, close: CloseFunction) => () => { - isDateWithinConstraints(date) && - onChange( - new Date( - datePickerHeaderDate.getFullYear(), - datePickerHeaderDate.getMonth(), - date - ) - ); - close(); - setIsOpen?.(false); + isDateWithinConstraints(date) + ? (() => { + onChange( + new Date( + datePickerHeaderDate.getFullYear(), + datePickerHeaderDate.getMonth(), + date + ) + ); + close(); + setIsOpen?.(false); + })() + : Notification.Error({ + msg: outOfLimitsErrorMessage ?? "Cannot select date out of range", + }); }; const getDayCount = (date: Date) => { @@ -220,7 +229,7 @@ const DateInputV2: React.FC = ({ readOnly disabled={disabled} className={`cui-input-base cursor-pointer disabled:cursor-not-allowed ${className}`} - placeholder={placeholder ?? "Select date"} + placeholder={placeholder ?? t("select_date")} value={value && dayjs(value).format("DD/MM/YYYY")} />

    @@ -248,7 +257,7 @@ const DateInputV2: React.FC = ({ [dd, mm, yyyy].filter(Boolean).join("/") ) || "" } // Display the value in DD/MM/YYYY format - placeholder="DD/MM/YYYY" + placeholder={t("DD/MM/YYYY")} onChange={(e) => { setDisplayValue(e.target.value.replaceAll("/", "")); const value = dayjs(e.target.value, "DD/MM/YYYY", true); @@ -330,26 +339,41 @@ const DateInputV2: React.FC = ({ className="aspect-square w-[14.26%] border border-transparent p-1 text-center text-sm" /> ))} - {dayCount.map((d, i) => ( -
    + {dayCount.map((d, i) => { + const withinConstraints = isDateWithinConstraints(d); + const selected = value && isSelectedDate(d); + + const baseClasses = + "flex h-full items-center justify-center rounded text-center text-sm leading-loose transition duration-100 ease-in-out"; + let conditionalClasses = ""; + + if (withinConstraints) { + if (selected) { + conditionalClasses = + "bg-primary-500 font-bold text-white"; + } else { + conditionalClasses = + "hover:bg-gray-300 cursor-pointer"; + } + } else { + conditionalClasses = + "!cursor-not-allowed !text-gray-400"; + } + return (
    - {d} +
    + {d} +
    -
    - ))} + ); + })}
    )} diff --git a/src/Components/Common/FilePreviewDialog.tsx b/src/Components/Common/FilePreviewDialog.tsx index b7eda93930e..90dde50a249 100644 --- a/src/Components/Common/FilePreviewDialog.tsx +++ b/src/Components/Common/FilePreviewDialog.tsx @@ -192,6 +192,7 @@ const FilePreviewDialog = (props: FilePreviewProps) => { /> ) : (