Skip to content
This repository has been archived by the owner on Jan 9, 2023. It is now read-only.

feat(patients): added live search to the patients search #1970

Merged
merged 6 commits into from
Apr 7, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 9 additions & 19 deletions src/__tests__/patients/list/Patients.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import '../../../__mocks__/matchMediaMock'
import React from 'react'
import { mount } from 'enzyme'
import { TextInput, Button, Spinner, ListItem } from '@hospitalrun/components'
import { TextInput, Spinner, ListItem } from '@hospitalrun/components'
import { MemoryRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
Expand Down Expand Up @@ -47,15 +47,6 @@ describe('Patients', () => {
jest.restoreAllMocks()
})

it('should render a search input with button', () => {
const wrapper = setup()
const searchInput = wrapper.find(TextInput)
const searchButton = wrapper.find(Button)
expect(searchInput).toHaveLength(1)
expect(searchInput.prop('placeholder')).toEqual('actions.search')
expect(searchButton.text().trim()).toEqual('actions.search')
})

it('should render a loading bar if it is loading', () => {
const wrapper = setup(true)

Expand Down Expand Up @@ -83,10 +74,15 @@ describe('Patients', () => {
})

describe('search functionality', () => {
it('should call the searchPatients() action with the correct data', () => {
beforeEach(() => jest.useFakeTimers())

afterEach(() => jest.useRealTimers())

it('should search for patients after the search text has not changed for 500 milliseconds', () => {
const searchPatientsSpy = jest.spyOn(patientSlice, 'searchPatients')
const expectedSearchText = 'search text'
const wrapper = setup()
searchPatientsSpy.mockClear()
const expectedSearchText = 'search text'

act(() => {
;(wrapper.find(TextInput).prop('onChange') as any)({
Expand All @@ -99,14 +95,8 @@ describe('Patients', () => {
} as React.ChangeEvent<HTMLInputElement>)
})

wrapper.update()

act(() => {
;(wrapper.find(Button).prop('onClick') as any)({
preventDefault(): void {
// noop
},
} as React.MouseEvent<HTMLButtonElement>)
jest.advanceTimersByTime(500)
})

wrapper.update()
Expand Down
58 changes: 31 additions & 27 deletions src/patients/list/Patients.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ import useAddBreadcrumbs from '../../breadcrumbs/useAddBreadcrumbs'

const breadcrumbs = [{ i18nKey: 'patients.label', location: '/patients' }]

function useDebounce(value: any, delayInMilliseconds: number) {
hd-genius marked this conversation as resolved.
Show resolved Hide resolved
const [debouncedValue, setDebouncedValue] = useState(value)

useEffect(() => {
const debounceHandler = setTimeout(() => setDebouncedValue(value), delayInMilliseconds)

return () => clearTimeout(debounceHandler)
}, [value, delayInMilliseconds])

return debouncedValue
}

const Patients = () => {
const { t } = useTranslation()
const history = useHistory()
Expand All @@ -43,6 +55,12 @@ const Patients = () => {

const [searchText, setSearchText] = useState<string>('')

const debouncedSearchText = useDebounce(searchText, 500)

useEffect(() => {
dispatch(searchPatients(debouncedSearchText))
}, [dispatch, debouncedSearchText])

useEffect(() => {
dispatch(fetchPatients())

Expand All @@ -51,9 +69,7 @@ const Patients = () => {
}
}, [dispatch, setButtonToolBar])

if (isLoading) {
return <Spinner color="blue" loading size={[10, 25]} type="ScaleLoader" />
}
const loadingIndicator = <Spinner color="blue" loading size={[10, 25]} type="ScaleLoader" />

const list = (
<ul>
Expand All @@ -69,35 +85,23 @@ const Patients = () => {
setSearchText(event.target.value)
}

const onSearchFormSubmit = (event: React.FormEvent | React.MouseEvent) => {
event.preventDefault()
dispatch(searchPatients(searchText))
}

return (
<Container>
<form className="form" onSubmit={onSearchFormSubmit}>
<Row>
<Column md={10}>
<TextInput
size="lg"
type="text"
onChange={onSearchBoxChange}
value={searchText}
placeholder={t('actions.search')}
/>
</Column>
<Column md={2}>
<Button size="large" onClick={onSearchFormSubmit}>
{t('actions.search')}
</Button>
</Column>
</Row>
</form>
<Row>
<Column md={12}>
<TextInput
size="lg"
type="text"
onChange={onSearchBoxChange}
value={searchText}
placeholder={t('actions.search')}
/>
</Column>
</Row>

<Row>
<List layout="flush" style={{ width: '100%', marginTop: '10px', marginLeft: '-25px' }}>
{list}
{isLoading ? loadingIndicator : list}
</List>
</Row>
</Container>
Expand Down