diff --git a/cypress/pageobject/Patient/PatientCreation.ts b/cypress/pageobject/Patient/PatientCreation.ts
index a38b8ab6a5c..36d41194019 100644
--- a/cypress/pageobject/Patient/PatientCreation.ts
+++ b/cypress/pageobject/Patient/PatientCreation.ts
@@ -11,7 +11,8 @@ export class PatientPage {
}
visitPatient(patientName: string) {
- cy.get("#name").click().type(patientName);
+ cy.get("button").contains("Name").click();
+ cy.get("#name").type(patientName); // Type the patient name
cy.intercept("GET", "**/api/v1/consultation/**").as("getPatient");
cy.get("#patient-name-list").contains(patientName).click();
cy.wait(2000);
@@ -66,6 +67,7 @@ export class PatientPage {
}
typePatientNameList(patientName: string) {
+ cy.get("button").contains("Name").click();
cy.get("#name").click().type(patientName);
}
diff --git a/package-lock.json b/package-lock.json
index 63af1164ef0..62be47f6bdc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,8 +19,12 @@
"@hello-pangea/dnd": "^17.0.0",
"@pnotify/core": "^5.2.0",
"@pnotify/mobile": "^5.2.0",
+ "@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
- "@radix-ui/react-icons": "^1.3.1",
+ "@radix-ui/react-icons": "^1.3.0",
+ "@radix-ui/react-label": "^2.1.0",
+ "@radix-ui/react-popover": "^1.1.2",
+ "@radix-ui/react-scroll-area": "^1.2.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-toast": "^1.2.2",
"@radix-ui/react-tooltip": "^1.1.3",
@@ -32,6 +36,7 @@
"browserslist-useragent-regexp": "^4.1.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
+ "cmdk": "^1.0.0",
"cross-env": "^7.0.3",
"cypress": "^13.15.2",
"dayjs": "^1.11.13",
@@ -114,6 +119,30 @@
"node": ">=22.11.0"
}
},
+ "apps/care_abdm_fe": {
+ "version": "1.0.0",
+ "license": "ISC",
+ "devDependencies": {
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ },
+ "peerDependencies": {
+ "react": "18.3.1",
+ "react-dom": "18.3.1"
+ }
+ },
+ "apps/care_hcx_fe": {
+ "version": "1.0.0",
+ "license": "ISC",
+ "devDependencies": {
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ },
+ "peerDependencies": {
+ "react": "18.3.1",
+ "react-dom": "18.3.1"
+ }
+ },
"apps/care_livekit_fe": {
"name": "care-livekit",
"version": "0.0.1",
@@ -3626,6 +3655,11 @@
"validator": "^13.9.0"
}
},
+ "node_modules/@radix-ui/number": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz",
+ "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ=="
+ },
"node_modules/@radix-ui/primitive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz",
@@ -3726,6 +3760,41 @@
}
}
},
+ "node_modules/@radix-ui/react-dialog": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz",
+ "integrity": "sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.0",
+ "@radix-ui/react-compose-refs": "1.1.0",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.1",
+ "@radix-ui/react-focus-guards": "1.1.1",
+ "@radix-ui/react-focus-scope": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-portal": "1.1.2",
+ "@radix-ui/react-presence": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.0",
+ "@radix-ui/react-slot": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "aria-hidden": "^1.1.1",
+ "react-remove-scroll": "2.6.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-direction": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
@@ -3864,6 +3933,28 @@
}
}
},
+ "node_modules/@radix-ui/react-label": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.0.tgz",
+ "integrity": "sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.0.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-menu": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.2.tgz",
@@ -3904,6 +3995,42 @@
}
}
},
+ "node_modules/@radix-ui/react-popover": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.2.tgz",
+ "integrity": "sha512-u2HRUyWW+lOiA2g0Le0tMmT55FGOEWHwPFt1EPfbLly7uXQExFo5duNKqG2DzmFXIdqOeNd+TpE8baHWJCyP9w==",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.0",
+ "@radix-ui/react-compose-refs": "1.1.0",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.1",
+ "@radix-ui/react-focus-guards": "1.1.1",
+ "@radix-ui/react-focus-scope": "1.1.0",
+ "@radix-ui/react-id": "1.1.0",
+ "@radix-ui/react-popper": "1.2.0",
+ "@radix-ui/react-portal": "1.1.2",
+ "@radix-ui/react-presence": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.0",
+ "@radix-ui/react-slot": "1.1.0",
+ "@radix-ui/react-use-controllable-state": "1.1.0",
+ "aria-hidden": "^1.1.1",
+ "react-remove-scroll": "2.6.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-popper": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz",
@@ -4068,6 +4195,36 @@
}
}
},
+ "node_modules/@radix-ui/react-scroll-area": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.0.tgz",
+ "integrity": "sha512-q2jMBdsJ9zB7QG6ngQNzNwlvxLQqONyL58QbEGwuyRZZb/ARQwk3uQVbCF7GvQVOtV6EU/pDxAw3zRzJZI3rpQ==",
+ "dependencies": {
+ "@radix-ui/number": "1.1.0",
+ "@radix-ui/primitive": "1.1.0",
+ "@radix-ui/react-compose-refs": "1.1.0",
+ "@radix-ui/react-context": "1.1.1",
+ "@radix-ui/react-direction": "1.1.0",
+ "@radix-ui/react-presence": "1.1.1",
+ "@radix-ui/react-primitive": "2.0.0",
+ "@radix-ui/react-use-callback-ref": "1.1.0",
+ "@radix-ui/react-use-layout-effect": "1.1.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-slot": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
@@ -7104,6 +7261,14 @@
"node": ">=6"
}
},
+ "node_modules/care_abdm_fe": {
+ "resolved": "apps/care_abdm_fe",
+ "link": true
+ },
+ "node_modules/care_hcx_fe": {
+ "resolved": "apps/care_hcx_fe",
+ "link": true
+ },
"node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -7392,6 +7557,366 @@
"node": ">=6"
}
},
+ "node_modules/cmdk": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz",
+ "integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==",
+ "dependencies": {
+ "@radix-ui/react-dialog": "1.0.5",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/primitive": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
+ "integrity": "sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz",
+ "integrity": "sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-context": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz",
+ "integrity": "sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-dialog": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz",
+ "integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-context": "1.0.1",
+ "@radix-ui/react-dismissable-layer": "1.0.5",
+ "@radix-ui/react-focus-guards": "1.0.1",
+ "@radix-ui/react-focus-scope": "1.0.4",
+ "@radix-ui/react-id": "1.0.1",
+ "@radix-ui/react-portal": "1.0.4",
+ "@radix-ui/react-presence": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-slot": "1.0.2",
+ "@radix-ui/react-use-controllable-state": "1.0.1",
+ "aria-hidden": "^1.1.1",
+ "react-remove-scroll": "2.5.5"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz",
+ "integrity": "sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/primitive": "1.0.1",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1",
+ "@radix-ui/react-use-escape-keydown": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-focus-guards": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz",
+ "integrity": "sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz",
+ "integrity": "sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-primitive": "1.0.3",
+ "@radix-ui/react-use-callback-ref": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-id": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz",
+ "integrity": "sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-use-layout-effect": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-portal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz",
+ "integrity": "sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-primitive": "1.0.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-presence": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz",
+ "integrity": "sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.1",
+ "@radix-ui/react-use-layout-effect": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-primitive": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz",
+ "integrity": "sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-slot": "1.0.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0",
+ "react-dom": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-slot": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
+ "integrity": "sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-compose-refs": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-use-callback-ref": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz",
+ "integrity": "sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz",
+ "integrity": "sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-use-callback-ref": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-use-escape-keydown": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz",
+ "integrity": "sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10",
+ "@radix-ui/react-use-callback-ref": "1.0.1"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz",
+ "integrity": "sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==",
+ "dependencies": {
+ "@babel/runtime": "^7.13.10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/cmdk/node_modules/react-remove-scroll": {
+ "version": "2.5.5",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz",
+ "integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==",
+ "dependencies": {
+ "react-remove-scroll-bar": "^2.3.3",
+ "react-style-singleton": "^2.2.1",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.0",
+ "use-sidecar": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/codepage": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
@@ -12335,8 +12860,7 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
- "dev": true,
- "license": "MIT"
+ "dev": true
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
@@ -20862,4 +21386,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/package.json b/package.json
index 020d73f5e65..2b00fe56e6a 100644
--- a/package.json
+++ b/package.json
@@ -58,8 +58,12 @@
"@hello-pangea/dnd": "^17.0.0",
"@pnotify/core": "^5.2.0",
"@pnotify/mobile": "^5.2.0",
+ "@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
- "@radix-ui/react-icons": "^1.3.1",
+ "@radix-ui/react-icons": "^1.3.0",
+ "@radix-ui/react-label": "^2.1.0",
+ "@radix-ui/react-popover": "^1.1.2",
+ "@radix-ui/react-scroll-area": "^1.2.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-toast": "^1.2.2",
"@radix-ui/react-tooltip": "^1.1.3",
@@ -71,6 +75,7 @@
"browserslist-useragent-regexp": "^4.1.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
+ "cmdk": "^1.0.0",
"cross-env": "^7.0.3",
"cypress": "^13.15.2",
"dayjs": "^1.11.13",
diff --git a/public/locale/en.json b/public/locale/en.json
index 8a4a36a1a5c..f4e1a995509 100644
--- a/public/locale/en.json
+++ b/public/locale/en.json
@@ -627,7 +627,7 @@
"email_discharge_summary_description": "Enter your valid email address to receive the discharge summary",
"email_success": "We will be sending an email shortly. Please check your inbox.",
"emergency": "Emergency",
- "emergency_contact_number": "Emergency Contact Number",
+ "emergency_phone_number": "Emergency Phone Number",
"empty_date_time": "--:-- --; --/--/----",
"encounter_date_field_label__A": "Date & Time of Admission to the Facility",
"encounter_date_field_label__DC": "Date & Time of Domiciliary Care commencement",
@@ -1142,8 +1142,10 @@
"save_and_continue": "Save and Continue",
"save_investigation": "Save Investigation",
"scan_asset_qr": "Scan Asset QR!",
- "scribe__reviewing_field": "Reviewing field {{currentField}} / {{totalFields}}",
- "scribe_error": "Could not autofill fields",
+ "search_by_emergency_contact_phone_number": "Search by Emergency Contact Phone Number",
+ "search_by_patient_name": "Search by Patient Name",
+ "search_by_patient_no": "Search by Patient Number",
+ "search_by_phone_number": "Search by Phone Number",
"search_by_username": "Search by username",
"search_for_facility": "Search for Facility",
"search_icd11_placeholder": "Search for ICD-11 Diagnoses",
@@ -1240,6 +1242,7 @@
"to_be_conducted": "To be conducted",
"total_amount": "Total Amount",
"total_beds": "Total Beds",
+ "total_patients": "Total Patients",
"total_staff": "Total Staff",
"total_users": "Total Users",
"transcript_edit_info": "You can update this if we made an error",
diff --git a/public/locale/mr.json b/public/locale/mr.json
index 06e9c5bbbde..47df5718d90 100644
--- a/public/locale/mr.json
+++ b/public/locale/mr.json
@@ -63,4 +63,4 @@
"sign_out": "साइन आउट",
"something_wrong": "काहीतरी चूक झाली! पुन्हा प्रयत्न करा",
"username": "युजरनेम"
-}
+}
\ No newline at end of file
diff --git a/src/components/Common/Page.tsx b/src/components/Common/Page.tsx
index 5d542a4fcbc..b7617233e7f 100644
--- a/src/components/Common/Page.tsx
+++ b/src/components/Common/Page.tsx
@@ -1,10 +1,10 @@
import { RefObject, useContext, useEffect } from "react";
+import { cn } from "@/lib/utils";
+
import PageTitle, { PageTitleProps } from "@/components/Common/PageTitle";
import { SidebarShrinkContext } from "@/components/Common/Sidebar/Sidebar";
-import { classNames } from "@/Utils/utils";
-
interface PageProps extends PageTitleProps {
children: React.ReactNode | React.ReactNode[];
options?: React.ReactNode | React.ReactNode[];
@@ -38,7 +38,7 @@ export default function Page(props: PageProps) {
}
return (
-
+
;
+}
+
+interface SearchByMultipleFieldsProps {
+ options: SearchOption[];
+ onSearch: (key: string, value: string) => void;
+ initialOption?: SearchOption;
+ className?: string;
+ inputClassName?: string;
+ buttonClassName?: string;
+ clearSearch?: { value: boolean; params?: string[] };
+}
+
+type EventType = {
+ value: string;
+ target?: { value: string };
+};
+
+const SearchByMultipleFields: React.FC = ({
+ options,
+ onSearch,
+ initialOption,
+ className,
+ inputClassName,
+ buttonClassName,
+ clearSearch,
+}) => {
+ const { t } = useTranslation();
+ const [selectedOption, setSelectedOption] = useState(
+ initialOption || options[0],
+ );
+ const [searchValue, setSearchValue] = useState(selectedOption.value || "");
+ const [open, setOpen] = useState(false);
+ const inputRef = useRef(null);
+ const [focusedIndex, setFocusedIndex] = useState(0);
+ const [error, setError] = useState();
+
+ useEffect(() => {
+ if (clearSearch?.value) {
+ const clearinput = options
+ .map((op) => op.key)
+ .some((element) => clearSearch.params?.includes(element));
+ clearinput ? setSearchValue("") : null;
+ inputRef.current?.focus();
+ }
+ }, [clearSearch]);
+
+ const handleOptionChange = useCallback(
+ (option: SearchOption) => {
+ setSelectedOption(option);
+ setSearchValue(option.value || "");
+ setFocusedIndex(options.findIndex((op) => op.key === option.key));
+ setOpen(false);
+ inputRef.current?.focus();
+ setError(false);
+ onSearch(option.key, option.value);
+ },
+ [onSearch],
+ );
+
+ useEffect(() => {
+ const handleKeyDown = (e: KeyboardEvent) => {
+ if (
+ e.key === "/" &&
+ !(document.activeElement instanceof HTMLInputElement)
+ ) {
+ e.preventDefault();
+ setOpen(true);
+ }
+ if (open) {
+ if (e.key === "ArrowDown") {
+ setFocusedIndex((prevIndex) =>
+ prevIndex === options.length - 1 ? 0 : prevIndex + 1,
+ );
+ } else if (e.key === "ArrowUp") {
+ setFocusedIndex((prevIndex) =>
+ prevIndex === 0 ? options.length - 1 : prevIndex - 1,
+ );
+ } else if (e.key === "Enter") {
+ handleOptionChange(options[focusedIndex]);
+ }
+
+ if (e.key === "Escape") {
+ inputRef.current?.focus();
+ setOpen(false);
+ }
+
+ options.forEach((option) => {
+ if (
+ e.key.toLocaleLowerCase() ===
+ option.shortcutKey.toLocaleLowerCase() &&
+ open
+ ) {
+ e.preventDefault();
+ handleOptionChange(option);
+ }
+ });
+ }
+ };
+
+ document.addEventListener("keydown", handleKeyDown);
+ return () => document.removeEventListener("keydown", handleKeyDown);
+ }, [focusedIndex, open, handleOptionChange, options]);
+
+ useEffect(() => {
+ if (inputRef.current) {
+ inputRef.current.focus();
+ }
+ }, [selectedOption]);
+
+ const handleSearchChange = useCallback(
+ (value: string) => {
+ setSearchValue(value);
+ onSearch(selectedOption.key, value);
+ },
+ [selectedOption, onSearch],
+ );
+
+ const renderSearchInput = useMemo(() => {
+ const commonProps = {
+ ref: inputRef,
+ value: searchValue,
+ onChange: (e: EventType) =>
+ handleSearchChange(e.target ? e.target.value : e.value),
+ className: cn(
+ "flex-grow border-none shadow-none focus-visible:ring-0 h-10",
+ inputClassName,
+ ),
+ };
+
+ switch (selectedOption.type) {
+ case "phone":
+ return (
+ setError(error)}
+ />
+ );
+ default:
+ return (
+
+ );
+ }
+ }, [selectedOption, searchValue, handleSearchChange, t, inputClassName]);
+
+ return (
+
+
+
+
+ setOpen(true)}
+ >
+ /
+
+
+
+
+
+
+ {options.map((option, index) => (
+ handleOptionChange(option)}
+ className={cn({
+ "bg-gray-100": focusedIndex === index,
+ "hover:bg-secondary-100": true,
+ })}
+ >
+
+ {t(option.key)}
+
+ {option.label.charAt(0).toUpperCase()}
+
+
+ ))}
+
+
+
+
+
+ {renderSearchInput}
+
+ {error && (
+
+ {t("invalid_phone_number")}
+
+ )}
+
+ {options.map((option) => (
+ handleOptionChange(option)}
+ variant="outline"
+ size="xs"
+ className={cn(
+ selectedOption.key === option.key
+ ? "bg-primary-100 text-primary-700 hover:bg-primary-200 border-primary-400"
+ : "bg-gray-100 text-gray-700 hover:bg-gray-200",
+ buttonClassName,
+ )}
+ >
+ {t(option.key)}
+
+ ))}
+
+
+ );
+};
+
+export default SearchByMultipleFields;
diff --git a/src/components/Form/FormFields/PhoneNumberFormField.tsx b/src/components/Form/FormFields/PhoneNumberFormField.tsx
index f96854f4a4a..0fd6f914035 100644
--- a/src/components/Form/FormFields/PhoneNumberFormField.tsx
+++ b/src/components/Form/FormFields/PhoneNumberFormField.tsx
@@ -1,5 +1,6 @@
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/react";
import { useCallback, useEffect, useMemo, useState } from "react";
+import React from "react";
import { useTranslation } from "react-i18next";
import CareIcon from "@/CAREUI/icons/CareIcon";
@@ -29,136 +30,144 @@ import {
const phoneCodes: Record = phoneCodesJson;
interface Props extends FormFieldBaseProps {
+ onError?: (error: FieldError) => void;
+ hideHelp?: boolean;
types: PhoneNumberType[];
placeholder?: string;
autoComplete?: string;
disableValidation?: boolean;
}
-export default function PhoneNumberFormField(props: Props) {
- const field = useFormFieldPropsResolver(props);
- const [error, setError] = useState();
- const [country, setCountry] = useState({
- flag: "🇮🇳",
- name: "India",
- code: "91",
- });
- const validator = useMemo(
- () => PhoneNumberValidator(props.types),
- [props.types],
- );
+const PhoneNumberFormField = React.forwardRef(
+ (props, ref) => {
+ const field = useFormFieldPropsResolver(props);
+ const [error, setError] = useState();
+ const [country, setCountry] = useState({
+ flag: "🇮🇳",
+ name: "India",
+ code: "91",
+ });
+ const validator = useMemo(
+ () => PhoneNumberValidator(props.types),
+ [props.types],
+ );
- const validate = useMemo(
- () => (value: string | undefined, event: "blur" | "change") => {
- if (!value || props.disableValidation) {
- return;
- }
+ const validate = useMemo(
+ () => (value: string | undefined, event: "blur" | "change") => {
+ if (!value || props.disableValidation) {
+ return;
+ }
- const newError = validator(value);
+ const newError = validator(value);
- if (!newError) {
- return;
- } else if (event === "blur") {
- return newError;
- }
- },
- [props.disableValidation],
- );
+ if (!newError) {
+ return;
+ } else if (event === "blur") {
+ return newError;
+ }
+ },
+ [props.disableValidation],
+ );
- const setValue = useCallback(
- (value: string) => {
- value = value.replaceAll(/[^0-9+]/g, "");
- if (value.length > 12 && value.startsWith("+910")) {
- value = "+91" + value.slice(4);
- }
+ const setValue = useCallback(
+ (value: string) => {
+ value = value.replaceAll(/[^0-9+]/g, "");
+ if (value.length > 12 && value.startsWith("+910")) {
+ value = "+91" + value.slice(4);
+ }
- const error = validate(value, "change");
- field.handleChange(value);
+ const error = validate(value, "change");
+ field.handleChange(value);
- setError(error);
- },
- [field, validate],
- );
-
- const handleCountryChange = (value: CountryData): void => {
- setCountry(value);
- setValue(conditionPhoneCode(value.code));
- };
-
- useEffect(() => {
- if (field.value && field.value.length > 0) {
- if (field.value.startsWith("1800")) {
- setCountry({ flag: "📞", name: "Support", code: "1800" });
- return;
- }
- if (field.value === "+") {
- setCountry({ flag: "🌍", name: "Other", code: "+" });
- return;
+ setError(error);
+ },
+ [field, validate, error],
+ );
+ useEffect(() => {
+ if (props.onError) {
+ props.onError(error);
}
- setCountry(phoneCodes[getCountryCode(field.value)!]);
- }
- }, [setValue]);
+ }, [error]);
+ const handleCountryChange = (value: CountryData): void => {
+ setCountry(value);
+ setValue(conditionPhoneCode(value.code));
+ };
- return (
-
- ),
- }}
- >
-
-
- {({ open }: { open: boolean }) => {
- return (
- <>
-
-
-
- {country?.flag ?? "🇮🇳"}
-
-
-
-
- setValue(e.target.value)}
- disabled={field.disabled}
- onBlur={() => setError(validate(field.value, "blur"))}
- />
-
- {({ close }) => (
-
- )}
-
- >
- );
- }}
-
-
-
- );
-}
+ useEffect(() => {
+ if (field.value && field.value.length > 0) {
+ if (field.value.startsWith("1800")) {
+ setCountry({ flag: "📞", name: "Support", code: "1800" });
+ return;
+ }
+ if (field.value === "+") {
+ setCountry({ flag: "🌍", name: "Other", code: "+" });
+ return;
+ }
+ setCountry(phoneCodes[getCountryCode(field.value)!]);
+ }
+ }, [setValue]);
+ return (
+
+ )),
+ }}
+ >
+
+
+ {({ open }: { open: boolean }) => {
+ return (
+ <>
+
+
+ {country?.flag}
+
+
+
+ setValue(e.target.value)}
+ disabled={field.disabled}
+ onBlur={() => setError(validate(field.value, "blur"))}
+ ref={ref}
+ />
+
+ {({ close }) => (
+
+ )}
+
+ >
+ );
+ }}
+
+
+
+ );
+ },
+);
const PhoneNumberTypesHelp = (props: { types: PhoneNumberType[] }) => {
const { t } = useTranslation();
@@ -175,7 +184,6 @@ const PhoneNumberTypesHelp = (props: { types: PhoneNumberType[] }) => {
);
};
-
const conditionPhoneCode = (code: string) => {
code = code.split(" ")[0];
return code.startsWith("+") ? code : "+" + code;
@@ -280,3 +288,4 @@ const CountryCodesList = ({
);
};
+export default PhoneNumberFormField;
diff --git a/src/components/Patient/ManagePatients.tsx b/src/components/Patient/ManagePatients.tsx
index 0664532b0a1..82ce219d4ff 100644
--- a/src/components/Patient/ManagePatients.tsx
+++ b/src/components/Patient/ManagePatients.tsx
@@ -1,38 +1,16 @@
import dayjs from "dayjs";
import { Link, navigate } from "raviger";
-import { ReactNode, useEffect, useState } from "react";
+import { ReactNode, useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
-import Chip from "@/CAREUI/display/Chip";
-import CountBlock from "@/CAREUI/display/Count";
-import FilterBadge from "@/CAREUI/display/FilterBadge";
-import RecordMeta from "@/CAREUI/display/RecordMeta";
-import CareIcon from "@/CAREUI/icons/CareIcon";
-import { AdvancedFilterButton } from "@/CAREUI/interactive/FiltersSlideover";
-
import { Avatar } from "@/components/Common/Avatar";
import ButtonV2 from "@/components/Common/ButtonV2";
import { ExportMenu } from "@/components/Common/Export";
import Loading from "@/components/Common/Loading";
import Page from "@/components/Common/Page";
+import SearchByMultipleFields from "@/components/Common/SearchByMultipleFields";
import SortDropdownMenu from "@/components/Common/SortDropdown";
import Tabs from "@/components/Common/Tabs";
-import { ICD11DiagnosisModel } from "@/components/Diagnosis/types";
-import { getDiagnosesByIds } from "@/components/Diagnosis/utils";
-import FacilitiesSelectDialogue from "@/components/ExternalResult/FacilitiesSelectDialogue";
-import DoctorVideoSlideover from "@/components/Facility/DoctorVideoSlideover";
-import { FacilityModel, PatientCategory } from "@/components/Facility/models";
-import { PhoneNumberValidator } from "@/components/Form/FieldValidators";
-import PhoneNumberFormField from "@/components/Form/FormFields/PhoneNumberFormField";
-import { FieldChangeEvent } from "@/components/Form/FormFields/Utils";
-import SearchInput from "@/components/Form/SearchInput";
-import {
- DIAGNOSES_FILTER_LABELS,
- DiagnosesFilterKey,
- FILTER_BY_DIAGNOSES_KEYS,
-} from "@/components/Patient/DiagnosesFilter";
-import PatientFilter from "@/components/Patient/PatientFilter";
-import { isPatientMandatoryDataFilled } from "@/components/Patient/Utils";
import useAuthUser from "@/hooks/useAuthUser";
import useFilters from "@/hooks/useFilters";
@@ -49,17 +27,36 @@ import {
} from "@/common/constants";
import { parseOptionId } from "@/common/utils";
-import { triggerGoal } from "@/Integrations/Plausible";
-import * as Notification from "@/Utils/Notifications";
import routes from "@/Utils/request/api";
-import request from "@/Utils/request/request";
-import useQuery from "@/Utils/request/useQuery";
+
+import Chip from "../../CAREUI/display/Chip";
+import CountBlock from "../../CAREUI/display/Count";
+import FilterBadge from "../../CAREUI/display/FilterBadge";
+import RecordMeta from "../../CAREUI/display/RecordMeta";
+import CareIcon from "../../CAREUI/icons/CareIcon";
+import { AdvancedFilterButton } from "../../CAREUI/interactive/FiltersSlideover";
+import { triggerGoal } from "../../Integrations/Plausible";
+import * as Notification from "../../Utils/Notifications";
+import request from "../../Utils/request/request";
+import useQuery from "../../Utils/request/useQuery";
import {
formatPatientAge,
humanizeStrings,
isAntenatal,
parsePhoneNumber,
-} from "@/Utils/utils";
+} from "../../Utils/utils";
+import { ICD11DiagnosisModel } from "../Diagnosis/types";
+import { getDiagnosesByIds } from "../Diagnosis/utils";
+import FacilitiesSelectDialogue from "../ExternalResult/FacilitiesSelectDialogue";
+import DoctorVideoSlideover from "../Facility/DoctorVideoSlideover";
+import { FacilityModel, PatientCategory } from "../Facility/models";
+import {
+ DIAGNOSES_FILTER_LABELS,
+ DiagnosesFilterKey,
+ FILTER_BY_DIAGNOSES_KEYS,
+} from "./DiagnosesFilter";
+import PatientFilter from "./PatientFilter";
+import { isPatientMandatoryDataFilled } from "./Utils";
interface TabPanelProps {
children?: ReactNode;
@@ -93,6 +90,7 @@ export const PatientManager = () => {
Pagination,
FilterBadges,
resultsPerPage,
+ clearSearch,
} = useFilters({
limit: 12,
cacheBlacklist: [
@@ -109,30 +107,6 @@ export const PatientManager = () => {
const [diagnoses, setDiagnoses] = useState
([]);
const [showDialog, setShowDialog] = useState<"create" | "list-discharged">();
const [showDoctors, setShowDoctors] = useState(false);
- const [phoneNumber, _setPhoneNumber] = useState("");
- const [emergencyPhoneNumber, _setEmergencyPhoneNumber] = useState("");
-
- const setPhoneNumber = (value: string) => {
- _setPhoneNumber(value);
- const error = PhoneNumberValidator()(value);
- if (!error) {
- updateQuery({ phone_number: value });
- }
- if ((value === "+91" || value === "") && qParams.phone_number) {
- updateQuery({ phone_number: null });
- }
- };
-
- const setEmergencyPhoneNumber = (value: string) => {
- _setEmergencyPhoneNumber(value);
- const error = PhoneNumberValidator()(value);
- if (!error) {
- updateQuery({ emergency_phone_number: value });
- }
- if ((value === "+91" || value === "") && qParams.emergency_phone_number) {
- updateQuery({ emergency_phone_number: null });
- }
- };
const tabValue =
qParams.last_consultation__new_discharge_reason ||
@@ -213,6 +187,12 @@ export const PatientManager = () => {
diagnoses_differential: qParams.diagnoses_differential || undefined,
review_missed: qParams.review_missed || undefined,
};
+ const [debouncedSearchParams, setDebouncedSearchParams] = useState(params);
+
+ useEffect(() => {
+ const timeout = setTimeout(() => setDebouncedSearchParams(params), 1000);
+ return () => clearTimeout(timeout);
+ }, [params]);
useEffect(() => {
const ids: string[] = [];
@@ -318,15 +298,7 @@ export const PatientManager = () => {
};
const { loading: isLoading, data } = useQuery(routes.patientList, {
- query: params,
- onResponse: () => {
- if (!params.phone_number) {
- _setPhoneNumber("+91");
- }
- if (!params.emergency_phone_number) {
- _setEmergencyPhoneNumber("+91");
- }
- },
+ query: debouncedSearchParams,
});
const getTheCategoryFromId = () => {
@@ -779,22 +751,74 @@ export const PatientManager = () => {
);
}
- const queryField = (name: string, defaultValue?: T) => {
- return {
- name,
- value: qParams[name] || defaultValue,
- onChange: (e: FieldChangeEvent) => updateQuery({ [e.name]: e.value }),
- };
- };
-
const onlyAccessibleFacility =
permittedFacilities?.count === 1 ? permittedFacilities.results[0] : null;
+ const searchOptions = [
+ {
+ key: "phone_number",
+ label: "Phone Number",
+ type: "phone" as const,
+ placeholder: "Search_by_phone_number",
+ value: qParams.phone_number || "",
+ shortcutKey: "p",
+ },
+ {
+ key: "name",
+ label: "Name",
+ type: "text" as const,
+ placeholder: "search_by_patient_name",
+ value: qParams.name || "",
+ shortcutKey: "n",
+ },
+ {
+ key: "patient_no",
+ label: "IP/OP No",
+ type: "text" as const,
+ placeholder: "search_by_patient_no",
+ value: qParams.patient_no || "",
+ shortcutKey: "u",
+ },
+ {
+ key: "emergency_phone_number",
+ label: "Emergency Contact Phone Number",
+ type: "phone" as const,
+ placeholder: "search_by_emergency_phone_number",
+ value: qParams.emergency_phone_number || "",
+ shortcutKey: "e",
+ },
+ ];
+
+ const handleSearch = useCallback(
+ (key: string, value: string) => {
+ const updatedQuery = {
+ phone_number:
+ key === "phone_number"
+ ? value.length >= 13 || value === ""
+ ? value
+ : undefined
+ : undefined,
+ name: key === "name" ? value : undefined,
+ patient_no: key === "patient_no" ? value : undefined,
+ emergency_phone_number:
+ key === "emergency_phone_number"
+ ? value.length >= 13 || value === ""
+ ? value
+ : undefined
+ : undefined,
+ };
+
+ updateQuery(updatedQuery);
+ },
+ [updateQuery],
+ );
+
return (
@@ -973,57 +997,25 @@ export const PatientManager = () => {
}}
/>
-
+
-
-
-
-
-
-
-
setPhoneNumber(e.value)}
- types={["mobile", "landline"]}
- className="w-full grow"
- error={((phoneNumber || "+91") === "+91" && "") || undefined}
- />
- setEmergencyPhoneNumber(e.value)}
- types={["mobile", "landline"]}
- className="w-full"
- error={
- ((emergencyPhoneNumber || "+91") === "+91" && "") || undefined
- }
- />
-
+
+
diff --git a/src/components/ui/command.tsx b/src/components/ui/command.tsx
new file mode 100644
index 00000000000..29703e26108
--- /dev/null
+++ b/src/components/ui/command.tsx
@@ -0,0 +1,154 @@
+import { type DialogProps } from "@radix-ui/react-dialog";
+import { MagnifyingGlassIcon } from "@radix-ui/react-icons";
+import { Command as CommandPrimitive } from "cmdk";
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+import { Dialog, DialogContent } from "@/components/ui/dialog";
+
+const Command = React.forwardRef<
+ React.ElementRef
,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+Command.displayName = CommandPrimitive.displayName;
+
+interface CommandDialogProps extends DialogProps {}
+
+const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
+ return (
+
+
+
+ {children}
+
+
+
+ );
+};
+
+const CommandInput = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+));
+
+CommandInput.displayName = CommandPrimitive.Input.displayName;
+
+const CommandList = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+
+CommandList.displayName = CommandPrimitive.List.displayName;
+
+const CommandEmpty = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>((props, ref) => (
+
+));
+
+CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
+
+const CommandGroup = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+
+CommandGroup.displayName = CommandPrimitive.Group.displayName;
+
+const CommandSeparator = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
+
+const CommandItem = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+
+CommandItem.displayName = CommandPrimitive.Item.displayName;
+
+const CommandShortcut = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => {
+ return (
+
+ );
+};
+CommandShortcut.displayName = "CommandShortcut";
+
+export {
+ Command,
+ CommandDialog,
+ CommandInput,
+ CommandList,
+ CommandEmpty,
+ CommandGroup,
+ CommandItem,
+ CommandShortcut,
+ CommandSeparator,
+};
diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx
new file mode 100644
index 00000000000..94698f9b5e7
--- /dev/null
+++ b/src/components/ui/dialog.tsx
@@ -0,0 +1,120 @@
+import * as DialogPrimitive from "@radix-ui/react-dialog";
+import { Cross2Icon } from "@radix-ui/react-icons";
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const Dialog = DialogPrimitive.Root;
+
+const DialogTrigger = DialogPrimitive.Trigger;
+
+const DialogPortal = DialogPrimitive.Portal;
+
+const DialogClose = DialogPrimitive.Close;
+
+const DialogOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
+
+const DialogContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+
+ {children}
+
+
+ Close
+
+
+
+));
+DialogContent.displayName = DialogPrimitive.Content.displayName;
+
+const DialogHeader = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+);
+DialogHeader.displayName = "DialogHeader";
+
+const DialogFooter = ({
+ className,
+ ...props
+}: React.HTMLAttributes) => (
+
+);
+DialogFooter.displayName = "DialogFooter";
+
+const DialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogTitle.displayName = DialogPrimitive.Title.displayName;
+
+const DialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+));
+DialogDescription.displayName = DialogPrimitive.Description.displayName;
+
+export {
+ Dialog,
+ DialogPortal,
+ DialogOverlay,
+ DialogTrigger,
+ DialogClose,
+ DialogContent,
+ DialogHeader,
+ DialogFooter,
+ DialogTitle,
+ DialogDescription,
+};
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
new file mode 100644
index 00000000000..dade8c7d2ee
--- /dev/null
+++ b/src/components/ui/input.tsx
@@ -0,0 +1,26 @@
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+export interface InputProps
+ extends Omit, "onChange"> {}
+
+const Input = React.forwardRef(
+ ({ className, type, ...props }, ref) => {
+ return (
+
+ );
+ },
+);
+Input.displayName = "Input";
+
+export { Input };
diff --git a/src/components/ui/label.tsx b/src/components/ui/label.tsx
new file mode 100644
index 00000000000..a115d28af1e
--- /dev/null
+++ b/src/components/ui/label.tsx
@@ -0,0 +1,24 @@
+import * as LabelPrimitive from "@radix-ui/react-label";
+import { type VariantProps, cva } from "class-variance-authority";
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const labelVariants = cva(
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
+);
+
+const Label = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef &
+ VariantProps
+>(({ className, ...props }, ref) => (
+
+));
+Label.displayName = LabelPrimitive.Root.displayName;
+
+export { Label };
diff --git a/src/components/ui/popover.tsx b/src/components/ui/popover.tsx
new file mode 100644
index 00000000000..466e7226e36
--- /dev/null
+++ b/src/components/ui/popover.tsx
@@ -0,0 +1,31 @@
+import * as PopoverPrimitive from "@radix-ui/react-popover";
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const Popover = PopoverPrimitive.Root;
+
+const PopoverTrigger = PopoverPrimitive.Trigger;
+
+const PopoverAnchor = PopoverPrimitive.Anchor;
+
+const PopoverContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
+
+
+
+));
+PopoverContent.displayName = PopoverPrimitive.Content.displayName;
+
+export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
diff --git a/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx
new file mode 100644
index 00000000000..d0c4d3ac63b
--- /dev/null
+++ b/src/components/ui/scroll-area.tsx
@@ -0,0 +1,46 @@
+import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area";
+import * as React from "react";
+
+import { cn } from "@/lib/utils";
+
+const ScrollArea = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, children, ...props }, ref) => (
+
+
+ {children}
+
+
+
+
+));
+ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName;
+
+const ScrollBar = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, orientation = "vertical", ...props }, ref) => (
+
+
+
+));
+ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName;
+
+export { ScrollArea, ScrollBar };
diff --git a/src/hooks/useFilters.tsx b/src/hooks/useFilters.tsx
index b67474045ef..63ffa58822e 100644
--- a/src/hooks/useFilters.tsx
+++ b/src/hooks/useFilters.tsx
@@ -34,6 +34,10 @@ export default function useFilters({
const hasPagination = limit > 0;
const [showFilters, setShowFilters] = useState(false);
const [qParams, _setQueryParams] = useQueryParams();
+ const [clearSearch, setClearSearch] = useState<{
+ value: boolean;
+ params?: string[];
+ }>({ value: false });
const updateCache = (query: QueryParam) => {
const blacklist = FILTERS_CACHE_BLACKLIST.concat(cacheBlacklist);
@@ -63,6 +67,7 @@ export default function useFilters({
const updateQuery = (filter: FilterState) => {
filter = hasPagination ? { page: 1, limit, ...filter } : filter;
setQueryParams(Object.assign({}, qParams, filter), { replace: true });
+ setClearSearch({ value: false });
};
const updatePage = (page: number) => {
if (!hasPagination) return;
@@ -71,6 +76,7 @@ export default function useFilters({
const removeFilters = (params?: string[]) => {
params ??= Object.keys(qParams);
setQueryParams(removeFromQuery(qParams, params));
+ setClearSearch({ value: true, params: params });
};
const removeFilter = (param: string) => removeFilters([param]);
@@ -203,7 +209,7 @@ export default function useFilters({
return (
{compiledBadges.map((props) => (
@@ -268,6 +274,7 @@ export default function useFilters({
* @param param is the key of the filter to be removed.
*/
removeFilter,
+ clearSearch,
/**
* Removes multiple filters from query param