diff --git a/cypress/e2e/users_spec/user_creation.cy.ts b/cypress/e2e/users_spec/user_creation.cy.ts
index 62a4bd53601..0e2707b921d 100644
--- a/cypress/e2e/users_spec/user_creation.cy.ts
+++ b/cypress/e2e/users_spec/user_creation.cy.ts
@@ -1,10 +1,10 @@
-import { UserCreation } from "../../pageObject/Users/UserCreation";
-import { FacilityCreation } from "../../pageObject/facility/FacilityCreation";
+import { UserCreation } from "pageObject/Users/UserCreation";
+import { FacilityCreation } from "pageObject/facility/FacilityCreation";
import {
generateName,
generatePhoneNumber,
generateUsername,
-} from "../../utils/commonUtils";
+} from "utils/commonUtils";
describe("User Creation", () => {
const facilityCreation = new FacilityCreation();
@@ -30,7 +30,6 @@ describe("User Creation", () => {
confirmPassword: defaultPassword,
email: `${generateUsername(firstName)}@test.com`,
phoneNumber: generatePhoneNumber(),
- dateOfBirth: "1990-01-01",
userType: "Doctor",
state: "Kerala",
district: "Ernakulam",
diff --git a/cypress/pageObject/Users/UserCreation.ts b/cypress/pageObject/Users/UserCreation.ts
index 181ad9d0649..c85b5998343 100644
--- a/cypress/pageObject/Users/UserCreation.ts
+++ b/cypress/pageObject/Users/UserCreation.ts
@@ -5,7 +5,6 @@ export interface UserData {
password?: string;
email?: string;
phoneNumber?: string;
- dateOfBirth?: string;
userType?: string;
state?: string;
district?: string;
@@ -78,17 +77,11 @@ export class UserCreation {
label: "Alternate Phone Number",
message: "Phone number must start with +91 followed by 10 digits",
},
- { label: "Date of Birth", message: "Required" },
{ label: "State", message: "Required" },
]);
return this;
}
- fillDateOfBirth(dateOfBirth: string) {
- cy.typeIntoField('[data-cy="dob-input"]', dateOfBirth);
- return this;
- }
-
selectUserType(userType: string) {
cy.clickAndSelectOption('[data-cy="user-type-select"]', userType);
return this;
@@ -125,7 +118,6 @@ export class UserCreation {
}
if (userData.email) this.fillEmail(userData.email);
if (userData.phoneNumber) this.fillPhoneNumber(userData.phoneNumber);
- if (userData.dateOfBirth) this.fillDateOfBirth(userData.dateOfBirth);
if (userData.state) this.selectState(userData.state);
if (userData.district) this.selectDistrict(userData.district);
if (userData.localBody) this.selectLocalBody(userData.localBody);
diff --git a/package-lock.json b/package-lock.json
index 1699ecaff7b..bd5d23bae55 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -40,7 +40,7 @@
"@radix-ui/react-tooltip": "^1.1.6",
"@sentry/browser": "^8.50.0",
"@tanstack/react-query": "^5.64.1",
- "@tanstack/react-query-devtools": "^5.64.0",
+ "@tanstack/react-query-devtools": "^5.64.2",
"@vitejs/plugin-react": "^4.3.4",
"@yudiel/react-qr-scanner": "^2.1.0",
"bowser": "^2.11.0",
@@ -64,7 +64,7 @@
"i18next-http-backend": "^3.0.1",
"input-otp": "^1.4.2",
"lodash-es": "^4.17.21",
- "lucide-react": "^0.471.1",
+ "lucide-react": "^0.473.0",
"markdown-it": "^14.1.0",
"next-themes": "^0.4.3",
"postcss-loader": "^8.1.1",
@@ -6288,9 +6288,9 @@
}
},
"node_modules/@tanstack/query-core": {
- "version": "5.64.1",
- "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.64.1.tgz",
- "integrity": "sha512-978Wx4Wl4UJZbmvU/rkaM9cQtXXrbhK0lsz/UZhYIbyKYA8E4LdomTwyh2GHZ4oU0BKKoDH4YlKk2VscCUgNmg==",
+ "version": "5.64.2",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.64.2.tgz",
+ "integrity": "sha512-hdO8SZpWXoADNTWXV9We8CwTkXU88OVWRBcsiFrk7xJQnhm6WRlweDzMD+uH+GnuieTBVSML6xFa17C2cNV8+g==",
"license": "MIT",
"funding": {
"type": "github",
@@ -6298,9 +6298,9 @@
}
},
"node_modules/@tanstack/query-devtools": {
- "version": "5.62.16",
- "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.62.16.tgz",
- "integrity": "sha512-3ff6UBJr0H3nIhfLSl9911rvKqXf0u4B58jl0uYdDWLqPk9pCvYIbxC35cGxK2+8INl4IaFVUHb/IdgWrNkg3Q==",
+ "version": "5.64.2",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.64.2.tgz",
+ "integrity": "sha512-3DautR5UpVZdk/qNIhioZVF7g8fdQZ1U98sBEEk4Tzz3tihSBNMPgwlP40nzgbPEDBIrn/j/oyyvNBVSo083Vw==",
"license": "MIT",
"funding": {
"type": "github",
@@ -6308,12 +6308,12 @@
}
},
"node_modules/@tanstack/react-query": {
- "version": "5.64.1",
- "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.64.1.tgz",
- "integrity": "sha512-vW5ggHpIO2Yjj44b4sB+Fd3cdnlMJppXRBJkEHvld6FXh3j5dwWJoQo7mGtKI2RbSFyiyu/PhGAy0+Vv5ev9Eg==",
+ "version": "5.64.2",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.64.2.tgz",
+ "integrity": "sha512-3pakNscZNm8KJkxmovvtZ4RaXLyiYYobwleTMvpIGUoKRa8j8VlrQKNl5W8VUEfVfZKkikvXVddLuWMbcSCA1Q==",
"license": "MIT",
"dependencies": {
- "@tanstack/query-core": "5.64.1"
+ "@tanstack/query-core": "5.64.2"
},
"funding": {
"type": "github",
@@ -6324,19 +6324,19 @@
}
},
"node_modules/@tanstack/react-query-devtools": {
- "version": "5.64.0",
- "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.64.0.tgz",
- "integrity": "sha512-XORJjlbcBwPJaNbWBfZudaVVMi5TtlN1lYkHYU71hlG2c/jYpceO2yfAhZfgeyTNtqmTJ7jXOitgoGqtunsBAA==",
+ "version": "5.64.2",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.64.2.tgz",
+ "integrity": "sha512-+ZjJVnPzc8BUV/Eklu2k9T/IAyAyvwoCHqOaOrk2sbU33LFhM52BpX4eyENXn0bx5LwV3DJZgEQlIzucoemfGQ==",
"license": "MIT",
"dependencies": {
- "@tanstack/query-devtools": "5.62.16"
+ "@tanstack/query-devtools": "5.64.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
- "@tanstack/react-query": "^5.64.0",
+ "@tanstack/react-query": "^5.64.2",
"react": "^18 || ^19"
}
},
@@ -13805,9 +13805,9 @@
}
},
"node_modules/lucide-react": {
- "version": "0.471.1",
- "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.471.1.tgz",
- "integrity": "sha512-syOxwPhf62gg2YOsz72HRn+CIpeudFy67AeKnSR8Hn/fIIF4ubhNbRF+pQ2CaJrl+X9Os4PL87z2DXQi3DVeDA==",
+ "version": "0.473.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.473.0.tgz",
+ "integrity": "sha512-KW6u5AKeIjkvrxXZ6WuCu9zHE/gEYSXCay+Gre2ZoInD0Je/e3RBtP4OHpJVJ40nDklSvjVKjgH7VU8/e2dzRw==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
diff --git a/package.json b/package.json
index bf233d16823..24c9c3fef89 100644
--- a/package.json
+++ b/package.json
@@ -78,7 +78,7 @@
"@radix-ui/react-tooltip": "^1.1.6",
"@sentry/browser": "^8.50.0",
"@tanstack/react-query": "^5.64.1",
- "@tanstack/react-query-devtools": "^5.64.0",
+ "@tanstack/react-query-devtools": "^5.64.2",
"@vitejs/plugin-react": "^4.3.4",
"@yudiel/react-qr-scanner": "^2.1.0",
"bowser": "^2.11.0",
@@ -102,7 +102,7 @@
"i18next-http-backend": "^3.0.1",
"input-otp": "^1.4.2",
"lodash-es": "^4.17.21",
- "lucide-react": "^0.471.1",
+ "lucide-react": "^0.473.0",
"markdown-it": "^14.1.0",
"next-themes": "^0.4.3",
"postcss-loader": "^8.1.1",
diff --git a/public/locale/en.json b/public/locale/en.json
index 1ec66f4c093..3959e0fe9ae 100644
--- a/public/locale/en.json
+++ b/public/locale/en.json
@@ -349,6 +349,7 @@
"add_skill": "Add Skill",
"add_spoke": "Add Spoke Facility",
"add_tags": "Add Tags",
+ "add_user": "Add User",
"additional_information": "Additional Information",
"additional_instructions": "Additional Instructions",
"address": "Address",
@@ -675,8 +676,8 @@
"copying_is_not_allowed": "Copying is not allowed",
"could_not_load_page": "We are facing some difficulties showing the Page you were looking for. Our Engineers have been notified and we'll make sure that this is resolved on the fly!",
"countries_travelled": "Countries travelled",
- "cover_image_deleted.": "Cover image deleted.",
- "cover_image_updated.": "Cover image updated.",
+ "cover_image_deleted": "Cover Image Deleted",
+ "cover_image_updated": "Cover Image Updated",
"covid_19_cat_gov": "Covid_19 Clinical Category as per Govt. of Kerala guideline (A/B/C)",
"covid_19_death_reporting_form_1": "Covid-19 Death Reporting : Form 1",
"covid_details": "Covid Details",
@@ -702,6 +703,7 @@
"create_tag": "Create Tag",
"create_template": "Create Template",
"create_user": "Create User",
+ "create_user_and_add_to_org": "Create a new user and add them to the organization.",
"created": "Created",
"created_by": "Created By",
"created_date": "Created Date",
@@ -831,6 +833,7 @@
"edit_profile": "Edit Profile",
"edit_role": "Edit Role",
"edit_schedule_template": "Edit Schedule Template",
+ "edit_user": "Edit User",
"edit_user_profile": "Edit Profile",
"edit_user_role": "Edit User Role",
"edited_by": "Edited by",
@@ -961,6 +964,7 @@
"enter_aadhaar_otp": "Enter OTP sent to the registered mobile with Aadhaar",
"enter_abha_address": "Enter ABHA Address",
"enter_any_id": "Enter any ID linked with your ABHA number",
+ "enter_dosage_instructions": "Enter Dosage Instructions",
"enter_file_name": "Enter File Name",
"enter_message": "Start typing...",
"enter_mobile_number": "Enter Mobile Number",
@@ -1161,6 +1165,7 @@
"insurance__policy_name": "Policy ID / Policy Name",
"insurance_details_detail": "Include details of all the Insurance Policies held by the Patient for smooth insurance processing",
"insurer_name_required": "Insurer Name is required",
+ "intended": "Intended",
"intent": "Intent",
"international_mobile": "International Mobile",
"invalid_asset_id_msg": "Oops! The asset ID you entered does not appear to be valid.",
@@ -1312,6 +1317,7 @@
"medical_council_registration_required": "Medical Council Registration is required",
"medical_records": "Medical Records",
"medical_worker": "Medical Worker",
+ "medication": "Medication",
"medication_taken_between": "Medication Taken Between",
"medicine": "Medicine",
"medicine_administration_history": "Medicine Administration History",
@@ -1444,6 +1450,8 @@
"noshow": "No-show",
"not_eligible": "Not Eligible",
"not_specified": "Not Specified",
+ "not_taken": "Not Taken",
+ "note": "Note",
"notes": "Notes",
"notes_placeholder": "Type your Notes",
"notice_board": "Notice Board",
@@ -1467,6 +1475,7 @@
"old_password": "Current Password",
"on": "on",
"on_emergency_basis": " on emergency basis",
+ "on_hold": "On Hold",
"ongoing_medications": "Ongoing Medications",
"only_indian_mobile_numbers_supported": "Currently only Indian numbers are supported",
"op_encounter": "OP Encounter",
@@ -1661,6 +1670,7 @@
"priority": "Priority",
"prn_prescription": "PRN Prescription",
"prn_prescriptions": "PRN Prescriptions",
+ "prn_reason": "PRN Reason",
"procedure_suggestions": "Procedure Suggestions",
"procedures_select_placeholder": "Select procedures to add details",
"professional_info": "Professional Information",
@@ -1716,6 +1726,7 @@
"register_patient": "Register Patient",
"reject": "Reject",
"rejected": "Rejected",
+ "related_person": "Related Person",
"reload": "Reload",
"remarks": "Remarks",
"remarks_placeholder": "Enter remarks",
@@ -1869,6 +1880,7 @@
"select_eligible_policy": "Select an Eligible Insurance Policy",
"select_facility": "Select Facility",
"select_facility_description": "Select the healthcare facility that will provide the requested resource.",
+ "select_facility_feature": "Select Facility Features",
"select_facility_for_discharged_patients_warning": "Facility needs to be selected to view discharged patients.",
"select_facility_type": "Select Facility Type",
"select_for_administration": "Select for Administration",
@@ -1986,6 +1998,7 @@
"status": "Status",
"stop": "Stop",
"stop_recording": "Stop Recording",
+ "stopped": "Stopped",
"stream_stop_due_to_inativity": "The live feed will stop streaming due to inactivity",
"stream_stopped_due_to_inativity": "The live feed has stopped streaming due to inactivity",
"stream_uuid": "Stream UUID",
@@ -2126,6 +2139,7 @@
"update_shift_request": "Update Shift Request",
"update_status": "Update Status",
"update_status_details": "Update Status/Details",
+ "update_user": "Update User",
"update_user_role_organization": "Update the role for this user in the organization",
"update_volunteer": "Reassign Volunteer",
"updated": "Updated",
@@ -2163,6 +2177,7 @@
"user_removed_success": "User removed from organization successfully",
"user_role_update_success": "User role updated successfully",
"user_type": "User Type",
+ "user_updated_successfully": "User updated successfully",
"username": "Username",
"username_already_exists": "This username already exists",
"username_available": "Username is available",
diff --git a/src/common/constants.tsx b/src/common/constants.tsx
index a88b50e35b0..bf0c68def2f 100644
--- a/src/common/constants.tsx
+++ b/src/common/constants.tsx
@@ -104,6 +104,10 @@ export const GENDER_TYPES = [
{ id: "non_binary", text: "Non Binary", icon: "TRANS" },
] as const;
+export const GENDERS = GENDER_TYPES.map((gender) => gender.id) as [
+ (typeof GENDER_TYPES)[number]["id"],
+];
+
export const CONSULTATION_SUGGESTION = [
{ id: "HI", text: "Home Isolation", deprecated: true }, // # Deprecated. Preserving option for backward compatibility (use only for readonly operations)
{ id: "A", text: "Admission" },
diff --git a/src/components/Common/ComboboxQuantityInput.tsx b/src/components/Common/ComboboxQuantityInput.tsx
index 20cb540ed13..db7b8caa4d2 100644
--- a/src/components/Common/ComboboxQuantityInput.tsx
+++ b/src/components/Common/ComboboxQuantityInput.tsx
@@ -92,6 +92,14 @@ export function ComboboxQuantityInput({
}
};
+ React.useEffect(() => {
+ setInputValue(quantity?.value.toString() || "");
+ }, [quantity?.value]);
+
+ React.useEffect(() => {
+ setSelectedUnit(quantity?.unit);
+ }, [quantity?.unit]);
+
return (
diff --git a/src/components/Facility/FacilityForm.tsx b/src/components/Facility/FacilityForm.tsx
index 858842bcd41..4d5250804c9 100644
--- a/src/components/Facility/FacilityForm.tsx
+++ b/src/components/Facility/FacilityForm.tsx
@@ -19,6 +19,7 @@ import {
FormMessage,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
+import { MultiSelect } from "@/components/ui/multi-select";
import {
Select,
SelectContent,
@@ -29,7 +30,6 @@ import {
import { Textarea } from "@/components/ui/textarea";
import { FacilityModel } from "@/components/Facility/models";
-import { MultiSelectFormField } from "@/components/Form/FormFields/SelectFormField";
import { useStateAndDistrictFromPincode } from "@/hooks/useStateAndDistrictFromPincode";
@@ -47,6 +47,7 @@ import { parsePhoneNumber } from "@/Utils/utils";
import GovtOrganizationSelector from "@/pages/Organization/components/GovtOrganizationSelector";
import { BaseFacility } from "@/types/facility/facility";
import { Organization } from "@/types/organization/organization";
+import organizationApi from "@/types/organization/organizationApi";
interface FacilityProps {
organizationId?: string;
@@ -58,7 +59,7 @@ export default function FacilityForm(props: FacilityProps) {
const { t } = useTranslation();
const queryClient = useQueryClient();
const [isGettingLocation, setIsGettingLocation] = useState(false);
- const { facilityId, onSubmitSuccess } = props;
+ const { facilityId, organizationId, onSubmitSuccess } = props;
const [selectedLevels, setSelectedLevels] = useState([]);
const [showAutoFilledPincode, setShowAutoFilledPincode] = useState(false);
@@ -112,14 +113,18 @@ export default function FacilityForm(props: FacilityProps) {
onSubmitSuccess?.();
},
});
-
const { mutate: updateFacility, isPending: isUpdatePending } = useMutation({
mutationFn: mutate(routes.updateFacility, {
pathParams: { id: facilityId || "" },
}),
onSuccess: (_data: FacilityModel) => {
toast.success(t("facility_updated_successfully"));
- queryClient.invalidateQueries({ queryKey: ["organizationFacilities"] });
+ queryClient.invalidateQueries({
+ queryKey: ["organizationFacilities"],
+ });
+ queryClient.invalidateQueries({
+ queryKey: ["facility"],
+ });
form.reset();
onSubmitSuccess?.();
},
@@ -148,8 +153,8 @@ export default function FacilityForm(props: FacilityProps) {
}
};
- const handleFeatureChange = (value: any) => {
- const { value: features }: { value: Array } = value;
+ const handleFeatureChange = (value: string[]) => {
+ const features = value.map((val) => Number(val));
form.setValue("features", features);
};
@@ -178,11 +183,21 @@ export default function FacilityForm(props: FacilityProps) {
pincode: form.watch("pincode")?.toString() || "",
});
+ const { data: org } = useQuery({
+ queryKey: ["organization", organizationId],
+ queryFn: query(organizationApi.get, {
+ pathParams: { id: organizationId },
+ }),
+ enabled: !!organizationId && !facilityId,
+ });
+
useEffect(() => {
if (facilityId) return;
const levels: Organization[] = [];
if (stateOrg) levels.push(stateOrg);
if (districtOrg) levels.push(districtOrg);
+ if (!stateOrg && !districtOrg && org) levels.push(org);
+
setSelectedLevels(levels);
if (levels.length == 2) {
@@ -193,7 +208,7 @@ export default function FacilityForm(props: FacilityProps) {
return () => clearTimeout(timer);
}
return () => setShowAutoFilledPincode(false);
- }, [stateOrg, districtOrg, facilityId]);
+ }, [stateOrg, districtOrg, organizationId, facilityId]);
// Update form when facility data is loaded
useEffect(() => {
@@ -273,7 +288,6 @@ export default function FacilityForm(props: FacilityProps) {
)}
/>
-
)}
/>
-
(
-
- Features
-
- o.name}
- optionValue={(o) => o.id}
- onChange={handleFeatureChange}
- error={form.formState.errors.features?.message}
- id="facility-features"
- />
-
-
-
- )}
+ render={({ field }) => {
+ return (
+
+ {t("features")}
+
+ ({
+ value: obj.id.toString(),
+ label: obj.name,
+ icon: obj.icon,
+ }))}
+ onValueChange={handleFeatureChange}
+ value={field.value.map((val) => val.toString())}
+ placeholder={t("select_facility_feature")}
+ id="facility-features"
+ />
+
+
+
+ );
+ }}
/>
@@ -519,6 +534,7 @@ export default function FacilityForm(props: FacilityProps) {