From b1a8cdf3e3288f6084592f583407ea89cebd5134 Mon Sep 17 00:00:00 2001 From: kumikokashii Date: Fri, 29 May 2020 16:48:37 -0700 Subject: [PATCH 1/4] feat(navbar): add shortcut icon to the create pages --- src/components/Navbar.tsx | 54 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 2283873055..dd56391e7e 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,11 +1,53 @@ import { Navbar as HospitalRunNavbar } from '@hospitalrun/components' import React from 'react' import { useTranslation } from 'react-i18next' +import { useSelector } from 'react-redux' import { useHistory } from 'react-router-dom' +import Permissions from '../model/Permissions' +import { RootState } from '../store' + const Navbar = () => { + const { permissions } = useSelector((state: RootState) => state.user) const { t } = useTranslation() const history = useHistory() + + const addPages = [ + { + permission: Permissions.WritePatients, + label: t('patients.newPatient'), + path: '/patients/new', + }, + { + permission: Permissions.WriteAppointments, + label: t('scheduling.appointments.new'), + path: '/appointments/new', + }, + { + permission: Permissions.RequestLab, + label: t('labs.requests.new'), + path: '/labs/new', + }, + { + permission: Permissions.ReportIncident, + label: t('incidents.reports.new'), + path: '/incidents/new', + }, + ] + + const addDropdownList: { type: string; label: string; onClick: () => void }[] = [] + addPages.forEach((page) => { + if (permissions.includes(page.permission)) { + addDropdownList.push({ + type: 'link', + label: page.label, + onClick: () => { + history.push(page.path) + }, + }) + } + }) + return ( { onClickButton: () => undefined, onChangeInput: () => undefined, }, + { + type: 'link-list-icon', + alignRight: true, + children: addDropdownList, + className: 'pl-4', + iconClassName: 'align-bottom', + label: 'Add', + name: 'add', + size: 'lg', + }, { type: 'link-list-icon', alignRight: true, @@ -112,7 +164,7 @@ const Navbar = () => { }, }, ], - className: 'pl-4', + className: 'pl-2', iconClassName: 'align-bottom', label: 'Patient', name: 'patient', From ea1eef9601e37faf821cb6c56fd6abc565dee602 Mon Sep 17 00:00:00 2001 From: kumikokashii Date: Fri, 29 May 2020 19:41:21 -0700 Subject: [PATCH 2/4] test(navbar): add permissions to test --- src/__tests__/components/Navbar.test.tsx | 66 ++++++++++++++++++++++-- src/components/Navbar.tsx | 2 +- 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/__tests__/components/Navbar.test.tsx b/src/__tests__/components/Navbar.test.tsx index a345692aa6..b1cc9a6ddc 100644 --- a/src/__tests__/components/Navbar.test.tsx +++ b/src/__tests__/components/Navbar.test.tsx @@ -3,23 +3,59 @@ import '../../__mocks__/matchMediaMock' import { Navbar as HospitalRunNavbar } from '@hospitalrun/components' import { mount } from 'enzyme' import { createMemoryHistory } from 'history' +import _ from 'lodash' import React from 'react' import { act } from 'react-dom/test-utils' +import { Provider } from 'react-redux' import { Router } from 'react-router-dom' +import createMockStore from 'redux-mock-store' +import thunk from 'redux-thunk' import Navbar from '../../components/Navbar' +import Permissions from '../../model/Permissions' +import { RootState } from '../../store' + +const mockStore = createMockStore([thunk]) describe('Navbar', () => { const history = createMemoryHistory() - const setup = () => - mount( + + const setup = (permissions: Permissions[]) => { + const store = mockStore({ + title: '', + user: { permissions }, + } as any) + + const wrapper = mount( - + + + , ) - - const wrapper = setup() + return wrapper + } + + const allPermissions = [ + Permissions.ReadPatients, + Permissions.WritePatients, + Permissions.ReadAppointments, + Permissions.WriteAppointments, + Permissions.DeleteAppointment, + Permissions.AddAllergy, + Permissions.AddDiagnosis, + Permissions.RequestLab, + Permissions.CancelLab, + Permissions.CompleteLab, + Permissions.ViewLab, + Permissions.ViewLabs, + Permissions.ViewIncidents, + Permissions.ViewIncident, + Permissions.ReportIncident, + ] + const wrapper = setup(allPermissions) const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const wrapperNoLabIncidentPermission = setup(_.cloneDeep(allPermissions).slice(0, 6)) it('should render a HospitalRun Navbar', () => { expect(hospitalRunNavbar).toHaveLength(1) @@ -142,4 +178,24 @@ describe('Navbar', () => { expect(children.props.children[1].props.children).toEqual('actions.search') }) }) + + describe('add new', () => { + let addNew = hospitalRunNavbar.find('.add-new') + let children = addNew.first().props().children as any + + it('should show a shortcut if user has a permission', () => { + expect(children[0].props.children).toEqual('patients.newPatient') + }) + + // Without Lab or Incident permissions + addNew = wrapperNoLabIncidentPermission.find(HospitalRunNavbar).find('.add-new') + children = addNew.first().props().children as any + + it('should not show a shortcut if user does not have a permission', () => { + children.forEach((option: any) => { + expect(option.props.children).not.toEqual('labs.requests.new') + expect(option.props.children).not.toEqual('incidents.requests.new') + }) + }) + }) }) diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index dd56391e7e..5cf618ff0d 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -146,7 +146,7 @@ const Navbar = () => { type: 'link-list-icon', alignRight: true, children: addDropdownList, - className: 'pl-4', + className: 'pl-4 add-new', iconClassName: 'align-bottom', label: 'Add', name: 'add', From cd9e4bd6e289ca15f3c9e092a873aeb1ede2cf6b Mon Sep 17 00:00:00 2001 From: kumikokashii Date: Fri, 29 May 2020 19:56:42 -0700 Subject: [PATCH 3/4] refactor(navbar): optimize addDropdownList generation --- src/components/Navbar.tsx | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 5cf618ff0d..24018f6645 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -35,18 +35,15 @@ const Navbar = () => { }, ] - const addDropdownList: { type: string; label: string; onClick: () => void }[] = [] - addPages.forEach((page) => { - if (permissions.includes(page.permission)) { - addDropdownList.push({ - type: 'link', - label: page.label, - onClick: () => { - history.push(page.path) - }, - }) - } - }) + const addDropdownList: { type: string; label: string; onClick: () => void }[] = addPages + .filter((page) => permissions.includes(page.permission)) + .map((page) => ({ + type: 'link', + label: page.label, + onClick: () => { + history.push(page.path) + }, + })) return ( Date: Fri, 29 May 2020 20:52:25 -0700 Subject: [PATCH 4/4] test(navbar): each it gets its own wrapper --- src/__tests__/components/Navbar.test.tsx | 115 ++++++++++++++++------- 1 file changed, 81 insertions(+), 34 deletions(-) diff --git a/src/__tests__/components/Navbar.test.tsx b/src/__tests__/components/Navbar.test.tsx index b1cc9a6ddc..fea954f6cf 100644 --- a/src/__tests__/components/Navbar.test.tsx +++ b/src/__tests__/components/Navbar.test.tsx @@ -3,7 +3,7 @@ import '../../__mocks__/matchMediaMock' import { Navbar as HospitalRunNavbar } from '@hospitalrun/components' import { mount } from 'enzyme' import { createMemoryHistory } from 'history' -import _ from 'lodash' +import cloneDeep from 'lodash/cloneDeep' import React from 'react' import { act } from 'react-dom/test-utils' import { Provider } from 'react-redux' @@ -53,22 +53,27 @@ describe('Navbar', () => { Permissions.ViewIncident, Permissions.ReportIncident, ] - const wrapper = setup(allPermissions) - const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) - const wrapperNoLabIncidentPermission = setup(_.cloneDeep(allPermissions).slice(0, 6)) it('should render a HospitalRun Navbar', () => { + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + expect(hospitalRunNavbar).toHaveLength(1) }) describe('header', () => { - const header = wrapper.find('.nav-header') - const { children } = header.first().props() as any - it('should render a HospitalRun Navbar with the navbar header', () => { + const wrapper = setup(allPermissions) + const header = wrapper.find('.nav-header') + const { children } = header.first().props() as any + expect(children.props.children).toEqual('HospitalRun') }) + it('should navigate to / when the header is clicked', () => { + const wrapper = setup(allPermissions) + const header = wrapper.find('.nav-header') + act(() => { const onClick = header.first().prop('onClick') as any onClick() @@ -79,22 +84,36 @@ describe('Navbar', () => { }) describe('patients', () => { - const patientsLinkList = hospitalRunNavbar.find('.patients-link-list') - const { children } = patientsLinkList.first().props() as any - it('should render a patients link list', () => { + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const patientsLinkList = hospitalRunNavbar.find('.patients-link-list') + const { children } = patientsLinkList.first().props() as any + expect(patientsLinkList.first().props().title).toEqual('patients.label') expect(children[0].props.children).toEqual('actions.list') expect(children[1].props.children).toEqual('actions.new') }) + it('should navigate to /patients when the list option is selected', () => { + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const patientsLinkList = hospitalRunNavbar.find('.patients-link-list') + const { children } = patientsLinkList.first().props() as any + act(() => { children[0].props.onClick() }) expect(history.location.pathname).toEqual('/patients') }) + it('should navigate to /patients/new when the list option is selected', () => { + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const patientsLinkList = hospitalRunNavbar.find('.patients-link-list') + const { children } = patientsLinkList.first().props() as any + act(() => { children[1].props.onClick() }) @@ -104,32 +123,37 @@ describe('Navbar', () => { }) describe('scheduling', () => { - const scheduleLinkList = hospitalRunNavbar.find('.scheduling-link-list') - it('should render a scheduling dropdown', () => { - expect(scheduleLinkList.first().props().title).toEqual('scheduling.label') - - const children = scheduleLinkList.first().props().children as any[] - const firstChild = children[0] as any - const secondChild = children[1] as any + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const scheduleLinkList = hospitalRunNavbar.find('.scheduling-link-list') + const { children } = scheduleLinkList.first().props() as any + expect(scheduleLinkList.first().props().title).toEqual('scheduling.label') if (scheduleLinkList.first().props().children) { - expect(firstChild.props.children).toEqual('scheduling.appointments.label') - expect(secondChild.props.children).toEqual('scheduling.appointments.new') + expect(children[0].props.children).toEqual('scheduling.appointments.label') + expect(children[1].props.children).toEqual('scheduling.appointments.new') } }) it('should navigate to to /appointments when the appointment list option is selected', () => { - const children = scheduleLinkList.first().props().children as any[] + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const scheduleLinkList = hospitalRunNavbar.find('.scheduling-link-list') + const { children } = scheduleLinkList.first().props() as any act(() => { children[0].props.onClick() }) + expect(history.location.pathname).toEqual('/appointments') }) it('should navigate to /appointments/new when the new appointment list option is selected', () => { - const children = scheduleLinkList.first().props().children as any[] + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const scheduleLinkList = hospitalRunNavbar.find('.scheduling-link-list') + const { children } = scheduleLinkList.first().props() as any act(() => { children[1].props.onClick() @@ -140,16 +164,23 @@ describe('Navbar', () => { }) describe('labs', () => { - const labsLinkList = hospitalRunNavbar.find('.labs-link-list') - const { children } = labsLinkList.first().props() as any - it('should render a labs dropdown', () => { + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const labsLinkList = hospitalRunNavbar.find('.labs-link-list') + const { children } = labsLinkList.first().props() as any + expect(labsLinkList.first().props().title).toEqual('labs.label') expect(children[0].props.children).toEqual('labs.label') expect(children[1].props.children).toEqual('labs.requests.new') }) it('should navigate to to /labs when the labs list option is selected', () => { + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const labsLinkList = hospitalRunNavbar.find('.labs-link-list') + const { children } = labsLinkList.first().props() as any + act(() => { children[0].props.onClick() }) @@ -158,6 +189,11 @@ describe('Navbar', () => { }) it('should navigate to /labs/new when the new labs list option is selected', () => { + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const labsLinkList = hospitalRunNavbar.find('.labs-link-list') + const { children } = labsLinkList.first().props() as any + act(() => { children[1].props.onClick() }) @@ -167,31 +203,42 @@ describe('Navbar', () => { }) describe('search', () => { - const navSearch = hospitalRunNavbar.find('.nav-search') - const { children } = navSearch.first().props() as any - it('should render Search as the search box placeholder', () => { + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const navSearch = hospitalRunNavbar.find('.nav-search') + const { children } = navSearch.first().props() as any + expect(children.props.children[0].props.placeholder).toEqual('actions.search') }) it('should render Search as the search button label', () => { + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const navSearch = hospitalRunNavbar.find('.nav-search') + const { children } = navSearch.first().props() as any + expect(children.props.children[1].props.children).toEqual('actions.search') }) }) describe('add new', () => { - let addNew = hospitalRunNavbar.find('.add-new') - let children = addNew.first().props().children as any - it('should show a shortcut if user has a permission', () => { + const wrapper = setup(allPermissions) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const addNew = hospitalRunNavbar.find('.add-new') + const { children } = addNew.first().props() as any + expect(children[0].props.children).toEqual('patients.newPatient') }) - // Without Lab or Incident permissions - addNew = wrapperNoLabIncidentPermission.find(HospitalRunNavbar).find('.add-new') - children = addNew.first().props().children as any - it('should not show a shortcut if user does not have a permission', () => { + // exclude labs and incidents permissions + const wrapper = setup(cloneDeep(allPermissions).slice(0, 6)) + const hospitalRunNavbar = wrapper.find(HospitalRunNavbar) + const addNew = hospitalRunNavbar.find('.add-new') + const { children } = addNew.first().props() as any + children.forEach((option: any) => { expect(option.props.children).not.toEqual('labs.requests.new') expect(option.props.children).not.toEqual('incidents.requests.new')