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

Commit

Permalink
feat: making sidebar collapsible
Browse files Browse the repository at this point in the history
this changes make the sidebar collapsible

"fix #1858"
  • Loading branch information
rabbihossain committed Mar 6, 2020
1 parent 886068a commit 168a112
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 16 deletions.
8 changes: 7 additions & 1 deletion src/HospitalRun.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import PrivateRoute from './components/PrivateRoute'
const HospitalRun = () => {
const { title } = useSelector((state: RootState) => state.title)
const { permissions } = useSelector((state: RootState) => state.user)
const { sidebarCollapsed } = useSelector((state: RootState) => state.components)

return (
<div>
Expand All @@ -31,7 +32,12 @@ const HospitalRun = () => {
<Sidebar />
<ButtonBarProvider>
<div className="row">
<main role="main" className="col-md-9 ml-sm-auto col-lg-10 px-4">
<main
role="main"
className={`${
sidebarCollapsed ? 'col-md-10 col-lg-11' : 'col-md-9 col-lg-10'
} ml-sm-auto px-4`}
>
<div className="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 className="h2">{title}</h1>
<ButtonToolBar />
Expand Down
15 changes: 15 additions & 0 deletions src/__tests__/HospitalRun.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [Permissions.WritePatients] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})

const wrapper = mount(
Expand Down Expand Up @@ -62,6 +63,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})}
>
<MemoryRouter initialEntries={['/patients/new']}>
Expand Down Expand Up @@ -94,6 +96,7 @@ describe('HospitalRun', () => {
user: { permissions: [Permissions.WritePatients, Permissions.ReadPatients] },
patient: { patient },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})

const wrapper = mount(
Expand Down Expand Up @@ -123,6 +126,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [Permissions.WritePatients] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})}
>
<MemoryRouter initialEntries={['/patients/edit/123']}>
Expand All @@ -141,6 +145,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [Permissions.ReadPatients] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})}
>
<MemoryRouter initialEntries={['/patients/edit/123']}>
Expand Down Expand Up @@ -173,6 +178,7 @@ describe('HospitalRun', () => {
user: { permissions: [Permissions.ReadPatients] },
patient: { patient },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})

const wrapper = mount(
Expand Down Expand Up @@ -201,6 +207,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})}
>
<MemoryRouter initialEntries={['/patients/123']}>
Expand All @@ -220,6 +227,7 @@ describe('HospitalRun', () => {
user: { permissions: [Permissions.ReadAppointments] },
appointments: { appointments: [] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})

const wrapper = mount(
Expand Down Expand Up @@ -251,6 +259,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})}
>
<MemoryRouter initialEntries={['/appointments']}>
Expand All @@ -269,6 +278,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [Permissions.WriteAppointments] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})

const wrapper = mount(
Expand Down Expand Up @@ -298,6 +308,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})}
>
<MemoryRouter initialEntries={['/appointments/new']}>
Expand Down Expand Up @@ -332,6 +343,7 @@ describe('HospitalRun', () => {
user: { permissions: [Permissions.WriteAppointments, Permissions.ReadAppointments] },
appointment: { appointment, patient: {} as Patient },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})

const wrapper = mount(
Expand Down Expand Up @@ -364,6 +376,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [Permissions.WriteAppointments] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})}
>
<MemoryRouter initialEntries={['/appointments/edit/123']}>
Expand All @@ -382,6 +395,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [Permissions.ReadAppointments] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})}
>
<MemoryRouter initialEntries={['/appointments/edit/123']}>
Expand All @@ -403,6 +417,7 @@ describe('HospitalRun', () => {
title: 'test',
user: { permissions: [Permissions.WritePatients] },
breadcrumbs: { breadcrumbs: [] },
components: { sidebarCollapsed: false },
})}
>
<MemoryRouter initialEntries={['/']}>
Expand Down
30 changes: 20 additions & 10 deletions src/__tests__/components/Sidebar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,25 @@ import Sidebar from 'components/Sidebar'
import { Router } from 'react-router'
import { ListItem } from '@hospitalrun/components'
import { act } from '@testing-library/react'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import { Provider } from 'react-redux'

const mockStore = configureMockStore([thunk])

describe('Sidebar', () => {
let history = createMemoryHistory()
const store = mockStore({
components: { sidebarCollapsed: false },
})
const setup = (location: string) => {
history = createMemoryHistory()
history.push(location)
return mount(
<Router history={history}>
<Sidebar />
<Provider store={store}>
<Sidebar />
</Provider>
</Router>,
)
}
Expand All @@ -27,7 +37,7 @@ describe('Sidebar', () => {

expect(
listItems
.at(0)
.at(1)
.text()
.trim(),
).toEqual('dashboard.label')
Expand All @@ -38,7 +48,7 @@ describe('Sidebar', () => {

const listItems = wrapper.find(ListItem)

expect(listItems.at(0).prop('active')).toBeTruthy()
expect(listItems.at(1).prop('active')).toBeTruthy()
})

it('should navigate to / when the dashboard link is clicked', () => {
Expand All @@ -47,7 +57,7 @@ describe('Sidebar', () => {
const listItems = wrapper.find(ListItem)

act(() => {
;(listItems.at(0).prop('onClick') as any)()
;(listItems.at(1).prop('onClick') as any)()
})

expect(history.location.pathname).toEqual('/')
Expand All @@ -62,7 +72,7 @@ describe('Sidebar', () => {

expect(
listItems
.at(1)
.at(2)
.text()
.trim(),
).toEqual('patients.label')
Expand All @@ -73,7 +83,7 @@ describe('Sidebar', () => {

const listItems = wrapper.find(ListItem)

expect(listItems.at(1).prop('active')).toBeTruthy()
expect(listItems.at(2).prop('active')).toBeTruthy()
})

it('should navigate to /patients when the patients link is clicked', () => {
Expand All @@ -82,7 +92,7 @@ describe('Sidebar', () => {
const listItems = wrapper.find(ListItem)

act(() => {
;(listItems.at(1).prop('onClick') as any)()
;(listItems.at(2).prop('onClick') as any)()
})

expect(history.location.pathname).toEqual('/patients')
Expand All @@ -97,7 +107,7 @@ describe('Sidebar', () => {

expect(
listItems
.at(2)
.at(3)
.text()
.trim(),
).toEqual('scheduling.label')
Expand All @@ -108,7 +118,7 @@ describe('Sidebar', () => {

const listItems = wrapper.find(ListItem)

expect(listItems.at(2).prop('active')).toBeTruthy()
expect(listItems.at(3).prop('active')).toBeTruthy()
})

it('should navigate to /appointments when the scheduling link is clicked', () => {
Expand All @@ -117,7 +127,7 @@ describe('Sidebar', () => {
const listItems = wrapper.find(ListItem)

act(() => {
;(listItems.at(2).prop('onClick') as any)()
;(listItems.at(3).prop('onClick') as any)()
})

expect(history.location.pathname).toEqual('/appointments')
Expand Down
27 changes: 23 additions & 4 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import React, { CSSProperties } from 'react'
import { List, ListItem, Icon } from '@hospitalrun/components'
import { useTranslation } from 'react-i18next'
import { useLocation, useHistory } from 'react-router'
import { useSelector, useDispatch } from 'react-redux'
import { RootState } from '../store'
import { updateSidebar } from './component-slice'

const Sidebar = () => {
const dispatch = useDispatch()
const { sidebarCollapsed } = useSelector((state: RootState) => state.components)

const { t } = useTranslation()
const path = useLocation()
const history = useHistory()
Expand All @@ -18,32 +24,45 @@ const Sidebar = () => {
}

return (
<nav className="col-md-2 d-none d-md-block bg-light sidebar">
<nav
className="col-md-2 d-none d-md-block bg-light sidebar"
style={{ width: sidebarCollapsed ? '56px' : '' }}
>
<div className="sidebar-sticky">
<List layout="flush" className="nav flex-column">
<ListItem
onClick={() => dispatch(updateSidebar())}
className="nav-item"
style={listItemStyle}
>
<Icon
style={{ float: sidebarCollapsed ? 'left' : 'right' }}
icon={sidebarCollapsed ? 'right-arrow' : 'left-arrow'}
/>
</ListItem>
<ListItem
active={pathname === '/'}
onClick={() => navigateTo('/')}
className="nav-item"
style={listItemStyle}
>
<Icon icon="dashboard" /> {t('dashboard.label')}
<Icon icon="dashboard" /> {!sidebarCollapsed && t('dashboard.label')}
</ListItem>
<ListItem
active={pathname.split('/')[1].includes('patient')}
onClick={() => navigateTo('/patients')}
className="nav-item"
style={listItemStyle}
>
<Icon icon="patients" /> {t('patients.label')}
<Icon icon="patients" /> {!sidebarCollapsed && t('patients.label')}
</ListItem>
<ListItem
active={pathname.split('/')[1].includes('appointments')}
onClick={() => navigateTo('/appointments')}
className="nav-item"
style={listItemStyle}
>
<Icon icon="appointment" /> {t('scheduling.label')}
<Icon icon="appointment" /> {!sidebarCollapsed && t('scheduling.label')}
</ListItem>
</List>
</div>
Expand Down
28 changes: 28 additions & 0 deletions src/components/component-slice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { createSlice } from '@reduxjs/toolkit'
import { AppThunk } from '../store'

interface ComponentState {
sidebarCollapsed: boolean
}

const initialState: ComponentState = {
sidebarCollapsed: false,
}

const componentSlice = createSlice({
name: 'components',
initialState,
reducers: {
toggleSidebar(state) {
state.sidebarCollapsed = !state.sidebarCollapsed
},
},
})

export const { toggleSidebar } = componentSlice.actions

export const updateSidebar = (): AppThunk => async (dispatch) => {
dispatch(toggleSidebar())
}

export default componentSlice.reducer
2 changes: 1 addition & 1 deletion src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ code {
left: 0;
z-index: 0; /* Behind the navbar */
padding: 48px 0 0; /* Height of navbar */
box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1);
border-right: 1px solid rgba(0, 0, 0, .1);
}

.sidebar-sticky {
Expand Down
2 changes: 2 additions & 0 deletions src/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import appointments from '../scheduling/appointments/appointments-slice'
import title from '../page-header/title-slice'
import user from '../user/user-slice'
import breadcrumbs from '../breadcrumbs/breadcrumbs-slice'
import components from '../components/component-slice'

const reducer = combineReducers({
patient,
Expand All @@ -16,6 +17,7 @@ const reducer = combineReducers({
appointment,
appointments,
breadcrumbs,
components,
})

const store = configureStore({
Expand Down

0 comments on commit 168a112

Please # to comment.