From dce66bc50232c43f3e23403401ca458a20d1c61d Mon Sep 17 00:00:00 2001 From: Mohammed Nihal <57055998+nihal467@users.noreply.github.com> Date: Sat, 11 Jan 2025 19:51:37 +0530 Subject: [PATCH 1/5] patient registration and encounter creation (#9902) --- .../e2e/patient_spec/patient_creation.cy.ts | 74 +++++++++ cypress/e2e/patient_spec/patient_search.cy.ts | 23 --- cypress/fixtures/users.json | 6 +- .../pageObject/Patients/PatientCreation.ts | 156 ++++++++++++++++++ .../pageObject/Patients/PatientDashboard.ts | 8 + cypress/pageObject/Patients/PatientSearch.ts | 41 ----- cypress/pageObject/Patients/PatientVerify.ts | 63 +++++++ cypress/support/commands.ts | 39 +++-- cypress/support/index.ts | 2 +- cypress/utils/commonUtils.ts | 66 +++++++- .../Encounter/CreateEncounterForm.tsx | 5 +- src/components/Patient/PatientIndex.tsx | 1 + .../Patient/PatientRegistration.tsx | 17 +- src/components/ui/autocomplete.tsx | 3 + .../components/OrganizationSelector.tsx | 13 +- src/pages/Patients/VerifyPatient.tsx | 3 +- 16 files changed, 427 insertions(+), 93 deletions(-) create mode 100644 cypress/e2e/patient_spec/patient_creation.cy.ts delete mode 100644 cypress/e2e/patient_spec/patient_search.cy.ts create mode 100644 cypress/pageObject/Patients/PatientCreation.ts create mode 100644 cypress/pageObject/Patients/PatientDashboard.ts delete mode 100644 cypress/pageObject/Patients/PatientSearch.ts create mode 100644 cypress/pageObject/Patients/PatientVerify.ts diff --git a/cypress/e2e/patient_spec/patient_creation.cy.ts b/cypress/e2e/patient_spec/patient_creation.cy.ts new file mode 100644 index 00000000000..941da15b51d --- /dev/null +++ b/cypress/e2e/patient_spec/patient_creation.cy.ts @@ -0,0 +1,74 @@ +import { patientCreation } from "pageObject/Patients/PatientCreation"; +import { patientDashboard } from "pageObject/Patients/PatientDashboard"; +import { patientVerify } from "pageObject/Patients/PatientVerify"; + +import { + generateAddress, + generatePatientName, + generatePhoneNumber, +} from "../../utils/commonUtils"; + +const ENCOUNTER_TYPE = "Observation"; +const ENCOUNTER_STATUS = "In Progress"; +const ENCOUNTER_PRIORITY = "ASAP"; + +describe("Patient Management", () => { + const TEST_PHONE = "9495031234"; + const PATIENT_DETAILS = { + name: "Nihal", + sex: "Male", + phone: TEST_PHONE, + }; + + const testPatientData = { + name: generatePatientName(), + phoneNumber: generatePhoneNumber(), + gender: "male", + bloodGroup: "B+", + dateOfBirth: "01-01-1990", + address: generateAddress(), + pincode: "682001", + state: "Kerala", + district: "Ernakulam", + localBody: "Aluva", + ward: "4", + }; + + beforeEach(() => { + cy.visit("/login"); + }); + + it("create a new patient and verify details", () => { + cy.loginByApi("doctor"); + patientCreation + .selectFacility("Arike") + .clickSearchPatients() + .clickCreateNewPatient() + .fillPatientDetails(testPatientData) + .submitPatientForm() + .assertPatientRegistrationSuccess(); + patientVerify + .verifyPatientName(testPatientData.name) + .verifyCreateEncounterButton() + .clickCreateEncounter() + .selectEncounterType(ENCOUNTER_TYPE) + .selectEncounterStatus(ENCOUNTER_STATUS) + .selectEncounterPriority(ENCOUNTER_PRIORITY) + .clickSubmitEncounter() + .assertEncounterCreationSuccess(); + patientDashboard.verifyEncounterPatientInfo([ + ENCOUNTER_TYPE, + ENCOUNTER_STATUS, + ENCOUNTER_PRIORITY, + ]); + }); + + it("search patient with phone number and verifies details", () => { + cy.loginByApi("staff"); + patientCreation + .selectFacility("Arike") + .clickSearchPatients() + .searchPatient(TEST_PHONE) + .verifySearchResults(PATIENT_DETAILS); + }); +}); diff --git a/cypress/e2e/patient_spec/patient_search.cy.ts b/cypress/e2e/patient_spec/patient_search.cy.ts deleted file mode 100644 index f17aecab310..00000000000 --- a/cypress/e2e/patient_spec/patient_search.cy.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { patientSearch } from "../../pageObject/Patients/PatientSearch"; - -describe("Patient Search", () => { - const TEST_PHONE = "9495031234"; - const PATIENT_DETAILS = { - name: "Nihal", - sex: "Male", - phone: TEST_PHONE, - }; - - beforeEach(() => { - cy.visit("/login"); - cy.loginByApi("staff"); - }); - - it("search patient with phone number and verifies details", () => { - patientSearch - .selectFacility("Arike") - .clickSearchPatients() - .searchPatient(TEST_PHONE) - .verifySearchResults(PATIENT_DETAILS); - }); -}); diff --git a/cypress/fixtures/users.json b/cypress/fixtures/users.json index 7fe744d7edc..2c859370d91 100644 --- a/cypress/fixtures/users.json +++ b/cypress/fixtures/users.json @@ -7,8 +7,12 @@ "username": "nihal-nurse", "password": "Test@123" }, + "doctor": { + "username": "arjun-doctor", + "password": "Test@123" + }, "staff": { "username": "nihal-staff", "password": "Test@123" } -} \ No newline at end of file +} diff --git a/cypress/pageObject/Patients/PatientCreation.ts b/cypress/pageObject/Patients/PatientCreation.ts new file mode 100644 index 00000000000..05adc98e328 --- /dev/null +++ b/cypress/pageObject/Patients/PatientCreation.ts @@ -0,0 +1,156 @@ +interface PatientFormData { + name: string; + phoneNumber: string; + dateOfBirth: string; + gender: string; + bloodGroup: string; + address: string; + pincode: string; + state: string; + district: string; + localBody: string; + ward: string; +} + +export class PatientCreation { + // Selectors + private selectors = { + patientsButton: '[data-cy="patients-button"]', + searchInput: "#patient-search", + patientCard: "#patient-search-results", + patientName: '[data-cy="patient-name"]', + patientDetails: "#patient-search-results", + createNewPatientButton: '[data-cy="create-new-patient-button"]', + }; + + // Actions + clickCreateNewPatient() { + cy.get(this.selectors.createNewPatientButton).click(); + cy.url().should("include", "/patient/create"); + return this; + } + + searchPatient(searchQuery: string) { + cy.get(this.selectors.searchInput).type(searchQuery); + + // Wait for results to load + cy.get(this.selectors.patientCard).should("be.visible"); + return this; + } + + verifySearchResults(patientDetails: { + name: string; + sex: string; + phone: string; + }) { + // Convert object values to an array of strings + const detailsArray = Object.values(patientDetails); + cy.verifyContentPresence(this.selectors.patientDetails, detailsArray); + } + + selectFacility(facilityName: string) { + cy.verifyAndClickElement("[data-cy='facility-list']", facilityName); + return this; + } + + clickSearchPatients() { + cy.get('[data-sidebar="content"]').contains("Search Patients").click(); + return this; + } + + enterName(name: string) { + cy.typeIntoField('[data-cy="patient-name-input"]', name); + return this; + } + + enterPhoneNumber(phoneNumber: string) { + cy.typeIntoField('[data-cy="patient-phone-input"]', phoneNumber, { + skipVerification: true, + }); + return this; + } + + enterDateOfBirth(dateString: string) { + // Split the date string (expected format: "DD-MM-YYYY") + const [day, month, year] = dateString.split("-"); + + cy.get('[data-cy="dob-day-input"]').type(day); + cy.get('[data-cy="dob-month-input"]').type(month); + cy.get('[data-cy="dob-year-input"]').type(year); + + return this; + } + + selectGender(gender: string) { + const lowercaseGender = gender.toLowerCase(); + cy.get(`[data-cy="gender-radio-${lowercaseGender}"]`).click(); + return this; + } + + selectBloodGroup(bloodGroup: string) { + cy.clickAndSelectOption('[data-cy="blood-group-select"]', bloodGroup); + return this; + } + + enterAddress(address: string) { + cy.typeIntoField('[data-cy="current-address-input"]', address); + return this; + } + + enterPincode(pincode: string) { + cy.typeIntoField('[data-cy="pincode-input"]', pincode); + return this; + } + + fillPatientDetails(patient: PatientFormData) { + return this.enterName(patient.name) + .enterPhoneNumber(patient.phoneNumber) + .clickSamePhoneNumberCheckbox() + .selectGender(patient.gender) + .selectBloodGroup(patient.bloodGroup) + .enterDateOfBirth(patient.dateOfBirth) + .enterAddress(patient.address) + .enterPincode(patient.pincode) + .selectState(patient.state) + .selectDistrict(patient.district) + .selectLocalBody(patient.localBody) + .selectWard(patient.ward); + } + + selectState(state: string) { + cy.typeAndSelectOption('[data-cy="select-state"]', state); + return this; + } + + selectDistrict(district: string) { + cy.typeAndSelectOption('[data-cy="select-district"]', district); + return this; + } + + selectLocalBody(localBody: string) { + cy.typeAndSelectOption('[data-cy="select-local_body"]', localBody); + return this; + } + + selectWard(ward: string) { + cy.typeAndSelectOption('[data-cy="select-ward"]', ward); + return this; + } + + submitPatientForm() { + cy.clickSubmitButton("Save and Continue"); + return this; + } + + clickSamePhoneNumberCheckbox() { + cy.get('[data-cy="same-phone-number-checkbox"]').click(); + return this; + } + + assertPatientRegistrationSuccess() { + cy.verifyNotification("Patient Registered Successfully"); + return this; + } +} + +export const patientCreation = new PatientCreation(); diff --git a/cypress/pageObject/Patients/PatientDashboard.ts b/cypress/pageObject/Patients/PatientDashboard.ts new file mode 100644 index 00000000000..9d608b17ea6 --- /dev/null +++ b/cypress/pageObject/Patients/PatientDashboard.ts @@ -0,0 +1,8 @@ +class PatientDashboard { + verifyEncounterPatientInfo(contents: string[]) { + cy.verifyContentPresence("#patient-infobadges", contents); + return this; + } +} + +export const patientDashboard = new PatientDashboard(); diff --git a/cypress/pageObject/Patients/PatientSearch.ts b/cypress/pageObject/Patients/PatientSearch.ts deleted file mode 100644 index 24e369e9b6e..00000000000 --- a/cypress/pageObject/Patients/PatientSearch.ts +++ /dev/null @@ -1,41 +0,0 @@ -export class PatientSearch { - // Selectors - private selectors = { - patientsButton: '[data-cy="patients-button"]', - searchInput: "#patient-search", - patientCard: "#patient-search-results", - patientName: '[data-cy="patient-name"]', - patientDetails: "#patient-search-results", - }; - - // Actions - searchPatient(searchQuery: string) { - cy.get(this.selectors.searchInput).type(searchQuery); - - // Wait for results to load - cy.get(this.selectors.patientCard).should("be.visible"); - return this; - } - - verifySearchResults(patientDetails: { - name: string; - sex: string; - phone: string; - }) { - // Convert object values to an array of strings - const detailsArray = Object.values(patientDetails); - cy.verifyContentPresence(this.selectors.patientDetails, detailsArray); - } - - selectFacility(facilityName: string) { - cy.verifyAndClickElement("[data-cy='facility-list']", facilityName); - return this; - } - - clickSearchPatients() { - cy.get('[data-sidebar="content"]').contains("Search Patients").click(); - return this; - } -} - -export const patientSearch = new PatientSearch(); diff --git a/cypress/pageObject/Patients/PatientVerify.ts b/cypress/pageObject/Patients/PatientVerify.ts new file mode 100644 index 00000000000..de98d9d8d61 --- /dev/null +++ b/cypress/pageObject/Patients/PatientVerify.ts @@ -0,0 +1,63 @@ +class PatientVerify { + verifyPatientName(expectedName: string) { + cy.get('[data-cy="verify-patient-name"]').should("contain", expectedName); + return this; + } + + verifyCreateEncounterButton() { + cy.get('[data-cy="create-encounter-button"]').should( + "contain", + "Create Encounter", + ); + return this; + } + + clickCreateEncounter() { + cy.verifyAndClickElement( + '[data-cy="create-encounter-button"]', + "Create Encounter", + ); + return this; + } + + // Map display text to data-cy values for better maintainability + private encounterTypeMap = { + Observation: "obsenc", + Inpatient: "imp", + Ambulatory: "amb", + Emergency: "emer", + Virtual: "vr", + "Home Health": "hh", + }; + + selectEncounterType(displayText: string) { + const dataCyValue = this.encounterTypeMap[displayText]; + cy.verifyAndClickElement( + `[data-cy="encounter-type-${dataCyValue}"]`, + displayText, + ); + return this; + } + + selectEncounterStatus(status: string) { + cy.clickAndSelectOption('[data-cy="encounter-status"]', status); + return this; + } + + selectEncounterPriority(priority: string) { + cy.clickAndSelectOption('[data-cy="encounter-priority"]', priority); + return this; + } + + clickSubmitEncounter() { + cy.clickSubmitButton("Create Encounter"); + return this; + } + + assertEncounterCreationSuccess() { + cy.verifyNotification("Encounter created successfully"); + return this; + } +} + +export const patientVerify = new PatientVerify(); diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index c8c0dbbd3d8..5af8df3a8ec 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -85,7 +85,11 @@ Cypress.Commands.add("verifyNotification", (text: string) => { return cy .get("li[data-sonner-toast] div[data-title]") .should("exist") - .contains(text); + .contains(text) + .should("be.visible") + .then(() => { + cy.closeNotification(); + }); }); Cypress.Commands.add("clearAllFilters", () => { @@ -104,13 +108,19 @@ Cypress.Commands.add("clickCancelButton", (buttonText = "Cancel") => { Cypress.Commands.add( "typeAndSelectOption", - (element: string, reference: string) => { - cy.get(element) - .click() - .type(reference) - .then(() => { - cy.get("[role='option']").contains(reference).click(); - }); + (selector: string, value: string) => { + // Click to open the dropdown + cy.get(selector).click(); + + // Type in the command input + cy.get("[cmdk-input]").should("be.visible").clear().type(value); + + // Select the filtered option from command menu + cy.get("[cmdk-list]") + .find("[cmdk-item]") + .contains(value) + .should("be.visible") + .click(); }, ); @@ -192,10 +202,15 @@ Cypress.Commands.add("preventPrint", () => { }); Cypress.Commands.add("closeNotification", () => { - cy.get(".pnotify") - .should("exist") - .each(($div) => { - cy.wrap($div).click(); + return cy + .get("li[data-sonner-toast] div[data-title]") + .first() + .parents("li[data-sonner-toast]") + .then(($toast) => { + cy.wrap($toast) + .find('button[aria-label="Close toast"]', { timeout: 5000 }) + .should("be.visible") + .click(); }); }); diff --git a/cypress/support/index.ts b/cypress/support/index.ts index cfa6266439c..22839037dae 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -39,7 +39,7 @@ declare global { reference: string, ): Chainable; preventPrint(): Chainable; - closeNotification(): Chainable; + closeNotification(): Chainable>; verifyContentPresence( selector: string, texts: string[], diff --git a/cypress/utils/commonUtils.ts b/cypress/utils/commonUtils.ts index c6cddc66840..2b1eb76b5cb 100644 --- a/cypress/utils/commonUtils.ts +++ b/cypress/utils/commonUtils.ts @@ -1,21 +1,71 @@ -export function generatePhoneNumber(): string { - // Create a new Uint8Array to store our random bytes +// Utility Functions +function getRandomIndex(max: number): number { const randomBytes = new Uint8Array(1); - // Get a cryptographically secure random value crypto.getRandomValues(randomBytes); + return randomBytes[0] % max; +} + +// Data Generators +export function generatePatientName(): string { + const firstNames = [ + "John", + "Jane", + "Alex", + "Sarah", + "Michael", + "Emma", + "David", + "Maria", + ]; + const lastNames = [ + "Smith", + "Johnson", + "Williams", + "Brown", + "Jones", + "Garcia", + "Miller", + ]; + + const randomFirst = firstNames[getRandomIndex(firstNames.length)]; + const randomLast = lastNames[getRandomIndex(lastNames.length)]; + + return `${randomFirst} ${randomLast}`; +} - // First digit should be 6, 7, 8, or 9 for Indian mobile numbers +export function generatePhoneNumber(): string { const validFirstDigits = [6, 7, 8, 9]; - const firstDigit = validFirstDigits[randomBytes[0] % validFirstDigits.length]; + const firstDigit = validFirstDigits[getRandomIndex(validFirstDigits.length)]; - // Generate remaining 9 digits using crypto const remainingDigits = new Uint8Array(9); crypto.getRandomValues(remainingDigits); - - // Convert to string and ensure each digit is 0-9 const remainingDigitsStr = Array.from(remainingDigits) .map((byte) => byte % 10) .join(""); return `${firstDigit}${remainingDigitsStr}`; } + +export function generateAddress(): string { + const houseNumbers = ["123", "45A", "67B", "89", "234"]; + const streets = [ + "Main Street", + "Park Avenue", + "Oak Road", + "Church Street", + "Hill Road", + ]; + const areas = [ + "Downtown", + "Westside", + "North Colony", + "South Extension", + "East End", + ]; + + const randomHouse = houseNumbers[getRandomIndex(houseNumbers.length)]; + const randomStreet = streets[getRandomIndex(streets.length)]; + const randomArea = areas[getRandomIndex(areas.length)]; + + return `${randomHouse}, ${randomStreet}, ${randomArea}`; +} diff --git a/src/components/Encounter/CreateEncounterForm.tsx b/src/components/Encounter/CreateEncounterForm.tsx index 39a5e8363e2..0bbb85cd8a4 100644 --- a/src/components/Encounter/CreateEncounterForm.tsx +++ b/src/components/Encounter/CreateEncounterForm.tsx @@ -216,6 +216,7 @@ export default function CreateEncounterForm({ @@ -153,6 +157,11 @@ export default function OrganizationSelector(props: OrganizationSelectorProps) { handleLevelChange(value, selectedLevels.length) } onSearch={setSearchQuery} + data-cy={`select-${ + lastLevel?.metadata?.govt_org_children_type?.toLowerCase() || + lastLevel?.metadata?.govt_org_type?.toLowerCase() || + "state" + }`} /> )} diff --git a/src/pages/Patients/VerifyPatient.tsx b/src/pages/Patients/VerifyPatient.tsx index 9e1594032a2..965e9ac5f8d 100644 --- a/src/pages/Patients/VerifyPatient.tsx +++ b/src/pages/Patients/VerifyPatient.tsx @@ -87,7 +87,7 @@ export default function VerifyPatient(props: { facilityId: string }) {

{patientData.name} @@ -152,6 +152,7 @@ export default function VerifyPatient(props: { facilityId: string }) { trigger={ - )} + }} + disabled={disabled} + > + + + + + {t("as_needed_prn")} + {Object.entries(FREQUENCY_OPTIONS).map(([key, option]) => ( + + {option.display} + + ))} + +

- -
-
-
- - + + { + if (value?.unit) { + setBoundsDurationUnit( + value?.unit as (typeof BOUNDS_DURATION_UNITS)[number], + ); } - onChange={(value) => + if (dosageInstruction?.timing?.repeat) { + let updatedBoundsDuration: BoundsDuration | undefined = + undefined; + const updatedValue = value.value; + if (updatedValue === undefined || updatedValue === 0) { + updatedBoundsDuration = undefined; + } else { + updatedBoundsDuration = { + value: updatedValue, + unit: value?.unit as (typeof BOUNDS_DURATION_UNITS)[number], + }; + } handleUpdateDosageInstruction({ - dose_and_rate: { type: "ordered", dose_quantity: value }, - }) + timing: { + ...dosageInstruction.timing, + repeat: { + ...dosageInstruction.timing.repeat, + bounds_duration: updatedBoundsDuration, + }, + }, + }); } - disabled={disabled} - /> -
-
- - handleUpdateDosageInstruction({ route })} - placeholder="Select route" - disabled={disabled} - /> -
-
- - handleUpdateDosageInstruction({ method })} - placeholder="Select method" - disabled={disabled} - count={20} - /> -
+ }} + disabled={disabled || !isFrequencySet || as_needed_boolean} + />
-
-
- - handleUpdateDosageInstruction({ site })} - placeholder="Select site" - disabled={disabled} - /> -
+ {/* Instructions */} +
+ + + handleUpdateDosageInstruction({ as_needed_for: reason }) + } + placeholder={t("select_prn_reason")} + disabled={disabled || !dosageInstruction?.as_needed_boolean} + wrapTextForSmallScreen={true} + />
-
- + {/* Additional Instructions */} +
+ + handleUpdateDosageInstruction({ - as_needed_boolean: !!checked, - as_needed_for: checked - ? medication.dosage_instruction[0]?.as_needed_for - : undefined, + additional_instruction: [instruction], }) } + placeholder={t("select_additional_instructions")} + disabled={disabled} + /> +
+ + {/* Route */} +
+ + handleUpdateDosageInstruction({ route })} + placeholder={t("select_route")} disabled={disabled} /> -
+ + {/* Site */} +
+ + handleUpdateDosageInstruction({ site })} + placeholder={t("select_site")} + disabled={disabled} + wrapTextForSmallScreen={true} + /> +
+ + {/* Method */} +
+ + handleUpdateDosageInstruction({ method })} + placeholder={t("select_method")} + disabled={disabled} + count={20} + />
- {medication.dosage_instruction[0]?.as_needed_boolean ? ( -
-
- - handleUpdateDosageInstruction({ as_needed_for: reason }) - } - placeholder="Select reason or indicator for PRN" - disabled={disabled} + {/* Intent */} +
+ + - handleUpdateDosageInstruction({ - timing: FREQUENCY_OPTIONS[value].timing, - }) - } - disabled={disabled} - > - - - - - {Object.entries(FREQUENCY_OPTIONS).map(([key, option]) => ( - - {option.display} - - ))} - - -
-
- - -
-
- )} + + + {MEDICATION_REQUEST_INTENT.map((intent) => ( + + {intent.replace(/_/g, " ")} + + ))} + + +
-
-
- - - onUpdate?.({ - dosage_instruction: [ - { - ...medication.dosage_instruction[0], - additional_instruction: [additionalInstruction], - }, - ], - }) - } - disabled={disabled} - /> -
+ {/* Remove Button - Desktop */} +
+
- - {/*
- {JSON.stringify(medication, null, 2)} -
*/}
); }; @@ -360,41 +599,73 @@ const reverseFrequencyOption = ( // TODO: verify period_unit is correct const FREQUENCY_OPTIONS = { - BD: { - display: "Twice daily", + BID: { + display: "Two times a day", timing: { repeat: { frequency: 2, period: 1, period_unit: "d" } }, }, - HS: { - display: "Night only", + TID: { + display: "Three times a day", + timing: { repeat: { frequency: 3, period: 1, period_unit: "d" } }, + }, + QID: { + display: "Four times a day", + timing: { repeat: { frequency: 4, period: 1, period_unit: "d" } }, + }, + AM: { + display: "Every morning", + timing: { repeat: { frequency: 1, period: 1, period_unit: "d" } }, + }, + PM: { + display: "Every afternoon", timing: { repeat: { frequency: 1, period: 1, period_unit: "d" } }, }, - OD: { - display: "Once daily", + QD: { + display: "Every day", timing: { repeat: { frequency: 1, period: 1, period_unit: "d" } }, }, + QOD: { + display: "Every other day", + timing: { repeat: { frequency: 1, period: 2, period_unit: "d" } }, + }, + Q1H: { + display: "Every hour", + timing: { repeat: { frequency: 24, period: 1, period_unit: "d" } }, + }, + Q2H: { + display: "Every 2 hours", + timing: { repeat: { frequency: 12, period: 1, period_unit: "d" } }, + }, + Q3H: { + display: "Every 3 hours", + timing: { repeat: { frequency: 8, period: 1, period_unit: "d" } }, + }, Q4H: { - display: "4th hourly", - timing: { repeat: { frequency: 4, period: 1, period_unit: "h" } }, + display: "Every 4 hours", + timing: { repeat: { frequency: 6, period: 1, period_unit: "d" } }, }, - QID: { - display: "6th hourly", - timing: { repeat: { frequency: 6, period: 1, period_unit: "h" } }, + Q6H: { + display: "Every 6 hours", + timing: { repeat: { frequency: 4, period: 1, period_unit: "d" } }, }, - QOD: { - display: "Alternate day", - timing: { repeat: { frequency: 2, period: 1, period_unit: "d" } }, + Q8H: { + display: "Every 8 hours", + timing: { repeat: { frequency: 3, period: 1, period_unit: "d" } }, + }, + BED: { + display: "At bedtime", + timing: { repeat: { frequency: 1, period: 1, period_unit: "d" } }, }, - QWK: { - display: "Once a week", + WK: { + display: "Weekly", timing: { repeat: { frequency: 1, period: 1, period_unit: "wk" } }, }, - STAT: { - display: "Imediately", - timing: { repeat: { frequency: 1, period: 1, period_unit: "s" } }, + MO: { + display: "Monthly", + timing: { repeat: { frequency: 1, period: 1, period_unit: "mo" } }, }, - TID: { - display: "8th hourly", - timing: { repeat: { frequency: 8, period: 1, period_unit: "h" } }, + STAT: { + display: "Immediately", + timing: { repeat: { frequency: 1, period: 1, period_unit: "s" } }, // One-time }, } as const satisfies Record< string, diff --git a/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx b/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx index 0f09a72f62e..a356164711b 100644 --- a/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx +++ b/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx @@ -1,3 +1,5 @@ +import { cn } from "@/lib/utils"; + import CareIcon from "@/CAREUI/icons/CareIcon"; import { Button } from "@/components/ui/button"; @@ -164,8 +166,14 @@ export function QuestionInput({ ); return ( -
-
+
+
{index === 0 && } {renderSingleInput(index)}
diff --git a/src/components/Questionnaire/QuestionnaireForm.tsx b/src/components/Questionnaire/QuestionnaireForm.tsx index 6c3256633fe..34e67e9eb02 100644 --- a/src/components/Questionnaire/QuestionnaireForm.tsx +++ b/src/components/Questionnaire/QuestionnaireForm.tsx @@ -296,14 +296,14 @@ export function QuestionnaireForm({ formState={questionnaireForms} setFormState={setQuestionnaireForms} /> -
+
{/* Questionnaire Forms */} {questionnaireForms.map((form, index) => (
-
+

{form.questionnaire.title} @@ -373,7 +373,7 @@ export function QuestionnaireForm({ {/* Search and Add Questionnaire */} -
+
{ @@ -400,7 +400,7 @@ export function QuestionnaireForm({ {/* Submit and Cancel Buttons */} {questionnaireForms.length > 0 && ( -
+