Skip to content

Commit

Permalink
Phani | A-1206089785593460 | Refactor Patient search in appointments (#…
Browse files Browse the repository at this point in the history
…313)

* Phani | Refactor Patient Search to use ComboBox

* Phani | Refactor Tests

* Phani | Rename component

* Phani | Update tests

* Phani | Fix test

* Phani | Update Date format to DD/MM/YYYY

* Phani | Fix Patient Search default value

* Phani | Fix Appointment Recurring End date
  • Loading branch information
Phanindra-tw authored Dec 14, 2023
1 parent e37f415 commit 8a9d50d
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 196 deletions.
4 changes: 3 additions & 1 deletion ui/i18n/appointments/locale_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
"APPOINTMENT_CREATE_OUTOF": "out of",
"APPOINTMENT_PATIENT_ID": "Patient ID",
"APPOINTMENT_PATIENT_NAME": "Patient Name",
"APPOINTMENT_PATIENT_SEARCH_LABEL": "Search Patient",
"APPOINTMENT_CHECKIN_TIME_KEY": "Check in time",
"APPOINTMENT_SERVICE_TYPE_FULL": "Service Appointment Type",
"APPOINTMENT_WALK_IN": "Walk In",
Expand Down Expand Up @@ -162,7 +163,8 @@
"SELECT_APPOINTMENT_PROVIDER": "Select Provider",
"INVITED_PROVIDERS": "Invitees",
"APPOINTMENT_PROVIDER_REMOVE_ACTION": "Remove",
"DROPDOWN_NO_OPTIONS_MESSAGE" : "Type to search",
"DROPDOWN_TYPE_TO_SEARCH_MESSAGE" : "Type to search",
"DROPDOWN_NO_OPTIONS_MESSAGE" : "No Patients Found",
"DROPDOWN_LOADING_MESSAGE" : "Loading...",
"APPOINTMENT_TIME_LABEL": "Choose a time slot",
"APPOINTMENT_TIME_FROM_LABEL": "Start time",
Expand Down
4 changes: 2 additions & 2 deletions ui/react-components/carbon-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ $css--body: false;
.bx--radio-button:checked+.bx--radio-button__label .bx--radio-button__appearance::before {
background-color: #0a74ff;
}
.bx--list-box__wrapper{
max-width: 250px;
.bx--list-box__menu-item[disabled] .bx--list-box__menu-item__option {
color: #363463;
}
.bx--number__control-btn{
border: none;
Expand Down
17 changes: 10 additions & 7 deletions ui/react-components/components/AddAppointment/AddAppointment.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
teleconsultation,
overlay,
close,
closeIcon,
firstBlock,
recurringContainerBlock,
} from './AddAppointment.module.scss';
Expand Down Expand Up @@ -149,6 +150,7 @@ const AddAppointment = props => {
const [disableSaveButton, setDisableSaveButton] = useState(false);
const [requiredFields, setRequiredFields] = useState(initialRequired);
const [showHolidayWarning, setShowHolidayWarning] = useState(false);
const today = new Date(moment().startOf("day"))

useEffect(()=>{
setAppointmentTouched((prevState)=>{
Expand Down Expand Up @@ -559,15 +561,17 @@ const AddAppointment = props => {
}
}

const closeButton = <div className={classNames(close)}>
const closeButton = <span className={classNames(closeIcon)}>
<Close24/>
</div>
</span>
if(showSuccessPopup){
return <Notification showMessage={showSuccessPopup} title={"Appointment Created!"} onClose={React.useContext(AppContext).onBack}/>
}
return (<div className={classNames(overlay)}>
<div data-testid="appointment-editor" className={classNames(appointmentEditor, appointmentDetails.appointmentType === RECURRING_APPOINTMENT_TYPE ? isRecurring : '')}>
<CancelConfirmation onBack={React.useContext(AppContext).onBack} triggerComponent={closeButton} skipConfirm={appointmentTouched !== "touched"}/>
<div className={classNames(close)}>
<CancelConfirmation onBack={React.useContext(AppContext).onBack} triggerComponent={closeButton} skipConfirm={appointmentTouched !== "touched"}/>
</div>
<AppointmentEditorCommonFieldsWrapper appointmentDetails={appointmentDetails}
updateAppointmentDetails={updateAppointmentDetails}
updateErrorIndicators={updateErrorIndicators}
Expand Down Expand Up @@ -610,7 +614,7 @@ const AddAppointment = props => {
updateAppointmentDetails({recurringStartDate: null, selectedRecurringStartDate: null});
}
}}
minDate={moment().format("MM-DD-YYYY")}
minDate={today}
isRequired={requiredFields.recurringStartDate}
intl={intl}
title={"Appointment start date"}/>
Expand Down Expand Up @@ -735,8 +739,7 @@ const AddAppointment = props => {
}}
width={"160px"}
intl={intl}
minDate = { (appointmentDetails.recurringStartDate && moment(appointmentDetails.recurringStartDate).format("MM-DD-YYYY"))
|| moment().format("MM-DD-YYYY")}
minDate = { (appointmentDetails.recurringStartDate && new Date(moment(appointmentDetails.recurringStartDate).startOf("day")).toISOString()) || today}
testId={"recurring-end-date-selector"}/>:
<div className={classNames(recurringContainerBlock)}>
<div style={{width: "140px", marginRight: "5px"}}>
Expand Down Expand Up @@ -809,7 +812,7 @@ const AddAppointment = props => {
find((priority) => priority === appointmentDetails.priority) &&
updateErrorIndicators({appointmentDateError: !date[0]});
}}
minDate={moment().format("MM-DD-YYYY")}
minDate={today}
isRequired={requiredFields.appointmentStartDate}
showWarning={showHolidayWarning}
intl={intl}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@
border: none;
text-align: right;
padding: 10px 0;
}

.closeIcon{
cursor: pointer;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const clickOnFirstDayOfNextMonth = (container) => {
const nextMonth = moment().add(1, 'month'); // Get the moment object for the next month
const firstDayNextMonth = nextMonth.startOf('month');
const datePickerInput = container.querySelector('.bx--date-picker__input');
fireEvent.change(datePickerInput, {target: {value: firstDayNextMonth.format("MM/DD/YYYY") }});
fireEvent.change(datePickerInput, {target: {value: firstDayNextMonth.format("DD/MM/YYYY") }});
fireEvent.blur(datePickerInput)
return firstDayNextMonth;
};
Expand Down Expand Up @@ -77,9 +77,9 @@ describe('Add Appointment', () => {
"enableServiceTypes": true
};
const {container, getByTestId} = renderWithReactIntl(<AddAppointment appConfig={config}/>);
expect(container.querySelector('.bx--search-input')).not.toBeNull();
expect(container.querySelector('.bx--text-input')).not.toBeNull();
expect(container.querySelector('.bx--list-box')).not.toBeNull();
expect(container.querySelectorAll('.bx--list-box').length).toEqual(4);
expect(container.querySelectorAll('.bx--list-box').length).toEqual(5);
expect(getByTestId('search-patient')).not.toBeNull();
expect(getByTestId('service-search')).not.toBeNull();
expect(() => getByTestId('speciality-search')).toThrow();
Expand All @@ -93,9 +93,9 @@ describe('Add Appointment', () => {
"enableServiceTypes": true
};
const {container, getByTestId} = renderWithReactIntl(<AddAppointment appConfig={config}/>);
expect(container.querySelector('.bx--search-input')).not.toBeNull();
expect(container.querySelector('.bx--text-input')).not.toBeNull();
expect(container.querySelector('.bx--list-box')).not.toBeNull();
expect(container.querySelectorAll('.bx--list-box').length).toEqual(5);
expect(container.querySelectorAll('.bx--list-box').length).toEqual(6);
expect(getByTestId('patient-search')).not.toBeNull();
expect(getByTestId('service-search')).not.toBeNull();
expect(getByTestId('speciality-search')).not.toBeNull();
Expand Down Expand Up @@ -136,18 +136,17 @@ describe('Add Appointment', () => {

//select patient
const targetPatient = '9DEC74AB 9DEC74B7 (IQ1110)';
const inputBox = container.querySelector('.bx--search-input');
fireEvent.blur(inputBox);
const inputBox = container.querySelector('.bx--text-input');
fireEvent.change(inputBox, { target: { value: "abc" } });
await waitForElement(
() => (container.querySelector('.bx--tile--clickable'))
() => (container.querySelector('.bx--list-box__menu-item'))
);
fireEvent.click(container.querySelector('.bx--tile--clickable'))
fireEvent.click(container.querySelector('.bx--list-box__menu-item'))


//select service
const targetService = 'Physiotherapy OPD';
const inputBoxService = container.querySelector('.bx--text-input');
const inputBoxService = container.querySelectorAll('.bx--text-input')[1];
fireEvent.change(inputBoxService, { target: { value: "Phy" } });
await waitForElement(() => (container.querySelector('.bx--list-box__menu')));
const option = getByText(targetService);
Expand All @@ -157,7 +156,7 @@ describe('Add Appointment', () => {
const selectedDate = clickOnFirstDayOfNextMonth(container)

const dateInputField = container.querySelector('.bx--date-picker__input');
expect(dateInputField.value).toBe(selectedDate.format('MM/DD/YYYY'));
expect(dateInputField.value).toBe(selectedDate.format('DD/MM/YYYY'));

fireEvent.click(getByText('Check and Save'));

Expand Down Expand Up @@ -231,8 +230,8 @@ describe('Add Appointment', () => {
"defaultNumberOfOccurrences": 10
}
};
const today = moment().format("MM/DD/YYYY");
const fiveDaysFromToday = moment().add(5, 'days').format("MM/DD/YYYY");
const today = moment().format("DD/MM/YYYY");
const fiveDaysFromToday = moment().add(5, 'days').format("DD/MM/YYYY");
const {getByText, container, queryAllByText, getByTestId, queryByText} = renderWithReactIntl(<AddAppointment
appConfig={config}/>);
const saveAppointmentSpy = jest.spyOn(addAppointmentService, 'saveRecurring');
Expand Down Expand Up @@ -426,8 +425,8 @@ describe('Add Appointment', () => {
appointmentParams={appointmentParams}/>);
expect(container.querySelectorAll('.bx--time-picker__input-field')[0].value).toBe(today.format('h:mm').toLowerCase());
expect(container.querySelectorAll('.bx--time-picker__input-field')[1].value).toBe(addTwoHoursFromNow.format('h:mm').toLowerCase());
const dateInputField = getByPlaceholderText('mm/dd/yyyy');
expect(dateInputField.value).toBe(today.format('MM/DD/YYYY'));
const dateInputField = getByPlaceholderText('dd/mm/yyyy');
expect(dateInputField.value).toBe(today.format('DD/MM/YYYY'));
});

it('should populate the start date, start time and end time coming as prop for recurring appointment', function () {
Expand All @@ -446,9 +445,9 @@ describe('Add Appointment', () => {
expect(container.querySelectorAll('.bx--time-picker__input-field')[0].value).toBe(today.format('h:mm').toLowerCase());
expect(container.querySelectorAll('.bx--time-picker__input-field')[1].value).toBe(addTwoHoursFromNow.format('h:mm').toLowerCase());

const dateInputField = getAllByPlaceholderText('mm/dd/yyyy')[0];
const dateInputField = getAllByPlaceholderText('dd/mm/yyyy')[0];

expect(dateInputField.value).toBe(today.format('MM/DD/YYYY'));
expect(dateInputField.value).toBe(today.format('DD/MM/YYYY'));
});

it('should not add second provider when maxAppointmentProvidersAllowed is 1', async () => {
Expand Down Expand Up @@ -494,9 +493,9 @@ describe('Add Appointment', () => {

expect(queryByText("Provider One")).not.toBeNull();
getByText("Please select maximum of 1 provider(s)");
expect(setTimeout).toHaveBeenLastCalledWith(expect.any(Function), 200);
jest.runAllTimers();
expect(queryByText("Please select maximum of 1 provider(s)")).toBeNull();
setTimeout(() => {
expect(queryByText("Please select maximum of 1 provider(s)")).toBeNull();
}, 3000);
});

it('should hide service appointment type if enableServiceTypes is undefined', () => {
Expand Down Expand Up @@ -550,14 +549,10 @@ describe('Add Appointment', () => {
const {container, getByPlaceholderText, queryByText} = renderWithReactIntl(<AddAppointment appConfig={config}/>);
const selectedDate = clickOnFirstDayOfNextMonth(container);

const dateInputField = getByPlaceholderText('mm/dd/yyyy');
expect(dateInputField.value).toBe(selectedDate.format('MM/DD/YYYY'));
const dateInputField = getByPlaceholderText('dd/mm/yyyy');
expect(dateInputField.value).toBe(selectedDate.format('DD/MM/YYYY'));

});
it('should fetch patient details on load if patient is present in url params', () => {
const {findByText} = renderWithReactIntl(<AddAppointment urlParams={{patient:"6bb24e7e-5c04-4561-9e7a-2d2bbf8074ad"}}/>);
expect(findByText('Test Patient')).not.toBeNull();
});
});

describe('Add appointment with appointment request enabled', () => {
Expand All @@ -566,12 +561,11 @@ describe('Add appointment with appointment request enabled', () => {

const selectPatient = async (container, getByText) => {
const targetPatient = '9DEC74AB 9DEC74B7 (IQ1110)';
const inputBox = container.querySelector('.bx--search-input');
fireEvent.blur(inputBox);
const inputBox = container.querySelector('.bx--text-input');
fireEvent.change(inputBox, { target: { value: "abc" } });
let searchedPatient;
await waitForElement(
() => (searchedPatient = container.querySelector('.bx--tile--clickable'))
() => (searchedPatient = container.querySelector('.bx--list-box__menu-item'))
);
expect(getByText(targetPatient)).toBeTruthy();
fireEvent.click(searchedPatient);
Expand Down Expand Up @@ -627,13 +621,13 @@ describe('Add appointment with appointment request enabled', () => {
});

it('should update the appointment status and provider responses if the AppointmentRequest is Enabled', async () => {
const {container, getByText, getByTestId, queryByText} = renderWithReactIntl(
const {container, queryAllByText, getByText, getByTestId, queryByText} = renderWithReactIntl(
<AppContext.Provider value={{setViewDate: jest.fn()}}>
<AddAppointment appConfig={config} appointmentParams={appointmentTime} currentProvider={currentProvider}/>
</AppContext.Provider>

);
await selectPatient(container, getByText);
await selectPatient(container, queryAllByText);
await selectService(getByTestId, getByText);
await selectProvider(getByTestId, getByText, "Two", "Provider Two");
await selectProvider(getByTestId, getByText, "Three", "Provider Three");
Expand Down Expand Up @@ -678,6 +672,11 @@ describe('Add appointment with appointment request enabled', () => {
expect(appointmentRequestData.providers[0].response).toEqual("ACCEPTED");
expect(appointmentRequestData.providers[1].name).toEqual("Provider Two");
expect(appointmentRequestData.providers[1].response).toEqual("AWAITING");
})
});

it('should fetch patient details on load if patient is present in url params', () => {
const {findByText} = renderWithReactIntl(<AddAppointment urlParams={{patient:"6bb24e7e-5c04-4561-9e7a-2d2bbf8074ad"}}/>);
expect(findByText('Test Patient')).not.toBeNull();
});
});

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const DatePickerCarbon = props => {
const {onChange, value, title, minDate, testId, width, isDisabled, isRequired, showWarning, intl} = props;
let defaultTime = value;
if( value && value instanceof moment){
defaultTime = value.format("MM/DD/YYYY");
defaultTime = new Date(value.toISOString());
}
let titleText= title && <Title text={title} isRequired={isRequired}/>
const warningText = intl.formatMessage({
Expand All @@ -17,10 +17,10 @@ const DatePickerCarbon = props => {
});
return (
<div data-testid={testId || "datePicker"}>
<DatePicker datePickerType={"single"} onChange={onChange} disabled={isDisabled} minDate={minDate} value={defaultTime}>
<DatePicker datePickerType={"single"} onChange={onChange} disabled={isDisabled} minDate={minDate} value={defaultTime} dateFormat={"d/m/Y"}>
<DatePickerInput
id={"Appointment Date"}
placeholder={"mm/dd/yyyy"}
placeholder={"dd/mm/yyyy"}
labelText={titleText}
size={"md"}
style={{width: width || "250px"}}
Expand Down
19 changes: 11 additions & 8 deletions ui/react-components/components/EditAppointment/EditAppointment.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
teleconsultation,
overlay,
recurringContainerBlock,
close
close,
closeIcon
} from "../AddAppointment/AddAppointment.module.scss";
import AppointmentEditorCommonFieldsWrapper
from "../AppointmentEditorCommonFieldsWrapper/AppointmentEditorCommonFieldsWrapper.jsx";
Expand Down Expand Up @@ -571,17 +572,17 @@ const EditAppointment = props => {
}, [appConfig]);


const closeButton = <div className={classNames(close)}>
const closeButton = <span className={classNames(closeIcon)}>
<Close20/>
</div>
</span>
const getMinDate = (date) => {
if(appointmentDetails.status === APPOINTMENT_STATUSES.WaitList){
return undefined;
}
if( moment(date).isBefore(moment().startOf("day"))){
return moment(date).format("MM-DD-YYYY");
return moment(date).format("DD-MM-YYYY");
}
return moment().format("MM-DD-YYYY")
return moment().format("DD-MM-YYYY")
}

const handleStatusChange = value => {
Expand Down Expand Up @@ -615,7 +616,9 @@ const EditAppointment = props => {
return (<div className={classNames(overlay)}>
<div data-testid="appointment-editor"
className={classNames(appointmentEditor, editAppointment, appointmentDetails.appointmentType === RECURRING_APPOINTMENT_TYPE ? recurring : '')}>
<CancelConfirmation onBack={React.useContext(AppContext).onBack} triggerComponent={closeButton} skipConfirm={appointmentTouched !== "touched"}/>
<div className={classNames(close)}>
<CancelConfirmation onBack={React.useContext(AppContext).onBack} triggerComponent={closeButton} skipConfirm={appointmentTouched !== "touched"}/>
</div>
<AppointmentEditorCommonFieldsWrapper appointmentDetails={appointmentDetails} errors={errors}
updateErrorIndicators={updateErrorIndicators}
endTimeBasedOnService={endTimeBasedOnService}
Expand Down Expand Up @@ -780,8 +783,8 @@ const EditAppointment = props => {
value={appointmentDetails.recurringEndDate}
isDisabled={componentsDisableStatus.endDate}
intl={intl}
minDate={(appointmentDetails.appointmentDate && moment(appointmentDetails.appointmentDate).format("MM-DD-YYYY"))
|| moment().format("MM-DD-YYYY")}
minDate={(appointmentDetails.appointmentDate && moment(appointmentDetails.appointmentDate).format("DD-MM-YYYY"))
|| moment().format("DD-MM-YYYY")}
testId={"recurring-end-date-selector"}/>
</div>)}
<div className={classNames(recurringContainerBlock)}>
Expand Down
Loading

0 comments on commit 8a9d50d

Please sign in to comment.