diff --git a/__tests__/src/actions/companionWindow.test.js b/__tests__/src/actions/companionWindow.test.js index 9cd364ea793266ba1d506857aea4364ea498b99c..183949b736913b742482af63cadf42810fb99f51 100644 --- a/__tests__/src/actions/companionWindow.test.js +++ b/__tests__/src/actions/companionWindow.test.js @@ -9,7 +9,20 @@ describe('companionWindow actions', () => { position: 'right', foo: 'bar', }; - const action = actions.addCompanionWindow(payload); + const mockState = { + windows: { + abc123: { companionWindowIds: [] }, + }, + companionWindows: {}, + }; + + const mockDispatch = jest.fn(() => ({})); + const mockGetState = jest.fn(() => mockState); + const thunk = actions.addCompanionWindow('abc123', payload); + thunk(mockDispatch, mockGetState); + + const action = mockDispatch.mock.calls[0][0]; + expect(action.type).toBe(ActionTypes.ADD_COMPANION_WINDOW); expect(action.payload).toMatchObject(payload); expect(action.payload.id).toMatch(/cw-.*/); @@ -18,14 +31,42 @@ describe('companionWindow actions', () => { it('should set the correct default values', () => { const payload = {}; const defaults = { foo: 'bar' }; - const action = actions.addCompanionWindow(payload, defaults); + + const mockState = { + windows: { + abc123: { companionWindowIds: [] }, + }, + companionWindows: {}, + }; + + const mockDispatch = jest.fn(() => ({})); + const mockGetState = jest.fn(() => mockState); + const thunk = actions.addCompanionWindow('abc123', payload, defaults); + thunk(mockDispatch, mockGetState); + + const action = mockDispatch.mock.calls[0][0]; + expect(action.payload.foo).toBe('bar'); }); it('should generate a new companionWindow ID', () => { const payload = {}; - expect(actions.addCompanionWindow(payload).id).toEqual( + const mockState = { + windows: { + abc123: { companionWindowIds: [] }, + }, + companionWindows: {}, + }; + + const mockDispatch = jest.fn(() => ({})); + const mockGetState = jest.fn(() => mockState); + + const thunk = actions.addCompanionWindow('abc123', payload); + thunk(mockDispatch, mockGetState); + const action = mockDispatch.mock.calls[0][0]; + + expect(action.id).toEqual( expect.stringMatching(/^cw-\w+-\w+/), ); }); @@ -33,45 +74,17 @@ describe('companionWindow actions', () => { describe('updateCompanionWindow', () => { it('should return correct action object', () => { - const mockState = { - windows: { - abc123: { - companionWindowIds: ['cw-1', 'cw-2'], - }, - }, - companionWindows: { - 'cw-1': { position: 'right' }, - 'cw-2': { position: 'not-right' }, - }, - }; - const payload = { content: 'info', position: 'right', + foo: 'bar', }; - const thunk = actions.updateCompanionWindow('abc123', 'cw-123', payload); - - const mockDispatch = jest.fn(() => {}); - const mockGetState = jest.fn(() => mockState); - - thunk(mockDispatch, mockGetState); - expect(mockDispatch).toHaveBeenNthCalledWith(1, { - type: ActionTypes.REMOVE_COMPANION_WINDOW, - id: 'cw-1', - }); + const action = actions.updateCompanionWindow('abc123', 'cw-123', payload); - expect(mockDispatch).toHaveBeenNthCalledWith(2, { - type: ActionTypes.UPDATE_WINDOW, - id: 'abc123', - payload: { companionWindowIds: ['cw-2'] }, - }); - - const updateCompanionWindowAction = mockDispatch.mock.calls[2][0]; - - expect(updateCompanionWindowAction.type).toBe(ActionTypes.UPDATE_COMPANION_WINDOW); - expect(updateCompanionWindowAction.id).toBe('cw-123'); - expect(updateCompanionWindowAction.payload).toEqual(payload); + expect(action.type).toBe(ActionTypes.UPDATE_COMPANION_WINDOW); + expect(action.id).toBe('cw-123'); + expect(action.payload).toEqual(payload); }); }); @@ -82,74 +95,4 @@ describe('companionWindow actions', () => { expect(action.id).toBe('cw-123'); }); }); - - describe('popOutCompanionWindow', () => { - it('returns a thunk which dispatches the appropriate actions', () => { - const mockState = { - windows: { - abc123: { - companionWindowIds: ['cw-1', 'cw-2'], - }, - }, - companionWindows: { - 'cw-1': { position: 'right' }, - 'cw-2': { position: 'not-right' }, - }, - }; - const mockDispatch = jest.fn(() => ({ id: 'cw-3' })); - const mockGetState = jest.fn(() => mockState); - const windowId = 'abc123'; - const panelType = 'info'; - const position = 'right'; - const thunk = actions.popOutCompanionWindow(windowId, panelType, position); - - expect(typeof thunk).toEqual('function'); - thunk(mockDispatch, mockGetState); - - expect(mockDispatch).toHaveBeenNthCalledWith(1, { - type: ActionTypes.REMOVE_COMPANION_WINDOW, - id: 'cw-1', - }); - - const addCompanionWindowAction = mockDispatch.mock.calls[1][0]; - expect(addCompanionWindowAction.type).toBe(ActionTypes.ADD_COMPANION_WINDOW); - expect(addCompanionWindowAction.payload).toMatchObject({ content: 'info', position: 'right' }); - expect(addCompanionWindowAction.id.startsWith('cw-')).toBe(true); - - expect(mockDispatch).toHaveBeenNthCalledWith(3, { - type: ActionTypes.UPDATE_WINDOW, - id: 'abc123', - payload: { companionWindowIds: ['cw-2', 'cw-3'] }, - }); - }); - - it('sets the window sidebar panel type if the companion window appears in the left position', () => { - const mockState = { - windows: { - abc123: { companionWindowIds: [] }, - }, - companionWindows: {}, - }; - - const mockDispatch = jest.fn(() => ({ id: 'cw-3' })); - const mockGetState = jest.fn(() => mockState); - const windowId = 'abc123'; - const panelType = 'info'; - const position = 'left'; - const thunk = actions.popOutCompanionWindow(windowId, panelType, position); - thunk(mockDispatch, mockGetState); - - expect(mockDispatch).toHaveBeenNthCalledWith(1, { - type: ActionTypes.SET_WINDOW_SIDE_BAR_PANEL, - windowId: 'abc123', - panelType: 'info', - }); - - expect(mockDispatch).toHaveBeenNthCalledWith(2, { - type: ActionTypes.UPDATE_WINDOW, - id: 'abc123', - payload: { companionAreaOpen: true }, - }); - }); - }); }); diff --git a/__tests__/src/reducers/windows.test.js b/__tests__/src/reducers/windows.test.js index fd0dbf384bfc2a1a14e882a76c9989d8a97de308..d39aad6e4f52231ac67ffe8649af5fbfbf33ae02 100644 --- a/__tests__/src/reducers/windows.test.js +++ b/__tests__/src/reducers/windows.test.js @@ -245,4 +245,52 @@ describe('windows reducer', () => { }, }); }); + + it('should handle ADD_COMPANION_WINDOW', () => { + // on the right, just tacks the new id on + expect(windowsReducer({ + abc123: { + id: 'abc123', + companionWindowIds: ['123'], + }, + }, { + type: ActionTypes.ADD_COMPANION_WINDOW, + id: 'xyz', + windowId: 'abc123', + payload: { + position: 'right', + }, + })).toEqual({ + abc123: { + id: 'abc123', + companionWindowIds: ['123', 'xyz'], + }, + }); + + // on the left, replaces all ids of windows in that position and sets some additional properties + expect(windowsReducer({ + abc123: { + id: 'abc123', + companionWindowIds: ['left123'], + }, + }, { + type: ActionTypes.ADD_COMPANION_WINDOW, + id: 'xyz', + windowId: 'abc123', + companionWindows: { + left123: { position: 'left' }, + }, + payload: { + content: 'content', + position: 'left', + }, + })).toEqual({ + abc123: { + id: 'abc123', + companionAreaOpen: true, + sideBarPanel: 'content', + companionWindowIds: ['xyz'], + }, + }); + }); }); diff --git a/src/containers/WindowSideBarButtons.js b/src/containers/WindowSideBarButtons.js index a485d635581948b26a6d895846da68ce64a609a0..96116259a8413b5a9e1d211abb9b4bec3de0c60a 100644 --- a/src/containers/WindowSideBarButtons.js +++ b/src/containers/WindowSideBarButtons.js @@ -19,8 +19,8 @@ import { WindowSideBarButtons } from '../components/WindowSideBarButtons'; * @private */ const mapDispatchToProps = (dispatch, { windowId }) => ({ - addCompanionWindow: panelType => dispatch( - actions.popOutCompanionWindow(windowId, panelType, 'left'), + addCompanionWindow: content => dispatch( + actions.addCompanionWindow(windowId, { content, position: 'left' }), ), }); diff --git a/src/state/actions/companionWindow.js b/src/state/actions/companionWindow.js index 81ea10c5f162c36547a46dac7c9e5781e1c210cb..044bbc648e4e5811b361fa1b2534d186859f9b2d 100644 --- a/src/state/actions/companionWindow.js +++ b/src/state/actions/companionWindow.js @@ -1,6 +1,6 @@ import uuid from 'uuid/v4'; import ActionTypes from './action-types'; -import { updateWindow, setCompanionAreaOpen, setWindowSideBarPanel } from './window'; +import { updateWindow } from './window'; const defaultProps = { content: null, @@ -8,29 +8,28 @@ const defaultProps = { }; /** */ -export function addCompanionWindow(payload, defaults = defaultProps) { - const id = `cw-${uuid()}`; - - return { - type: ActionTypes.ADD_COMPANION_WINDOW, - id, - payload: { ...defaults, ...payload, id }, +export function addCompanionWindow(windowId, payload, defaults = defaultProps) { + return (dispatch, getState) => { + const { companionWindows } = getState(); + const id = `cw-${uuid()}`; + + dispatch({ + type: ActionTypes.ADD_COMPANION_WINDOW, + id, + windowId, + companionWindows, + payload: { ...defaults, ...payload, id }, + }); }; } /** */ export function updateCompanionWindow(windowId, id, payload) { - return (dispatch, getState) => { - if (payload.position === 'left') { - const { windows, companionWindows } = getState(); - const { companionWindowIds } = windows[windowId]; - - companionWindowIds - .filter(cwid => companionWindows[cwid].position === payload.position) - .map(cwid => closeCompanionWindow(windowId, cwid)(dispatch, getState)); - } - - dispatch({ type: ActionTypes.UPDATE_COMPANION_WINDOW, id, payload }); + return { + type: ActionTypes.UPDATE_COMPANION_WINDOW, + windowId, + id, + payload, }; } @@ -50,46 +49,3 @@ export function closeCompanionWindow(windowId, companionWindowId) { dispatch(updateWindow(windowId, { companionWindowIds })); }; } - -/** - * popOutCompanionWindow - action creator - * - * @param {String} windowId - * @param {String} panelType The type of panel content to be rendered - * in the companion window (e.g. info, canvas_navigation) - * @param {String} position The position of the companion window to - * set content for (e.g. right, bottom) - * @memberof ActionCreators - */ -export function popOutCompanionWindow(windowId, panelType, position) { - return (dispatch, getState) => { - const { windows, companionWindows } = getState(); - const { companionWindowIds } = windows[windowId]; - - if (position === 'left') { - companionWindowIds - .filter(id => companionWindows[id].position === position) - .map(id => dispatch(removeCompanionWindow(id))); - - dispatch(setWindowSideBarPanel(windowId, panelType)); - - dispatch(setCompanionAreaOpen(windowId, true)); - } - - const action = dispatch(addCompanionWindow({ content: panelType, position })); - - const companionWindowId = action.id; - let existingCompanionWindowIds; - - if (position === 'left') { - existingCompanionWindowIds = companionWindowIds - .filter(id => (companionWindows[id].position !== position)); - } else { - existingCompanionWindowIds = companionWindowIds; - } - - dispatch(updateWindow(windowId, { - companionWindowIds: existingCompanionWindowIds.concat([companionWindowId]), - })); - }; -} diff --git a/src/state/reducers/windows.js b/src/state/reducers/windows.js index d38020744ec8beb66428215a6dd7d979dd587e90..597ba21112fe54eb027bee6829b3904319528ff6 100644 --- a/src/state/reducers/windows.js +++ b/src/state/reducers/windows.js @@ -96,6 +96,31 @@ export const windowsReducer = (state = {}, action) => { return setCanvasIndex(state, action.windowId, currentIndex => currentIndex - 1); case ActionTypes.SET_CANVAS: return setCanvasIndex(state, action.windowId, currentIndex => action.canvasIndex); + case ActionTypes.ADD_COMPANION_WINDOW: + if (action.payload.position === 'left') { + const { companionWindowIds } = state[action.windowId]; + const { companionWindows } = action; + const newCompanionWindowIds = companionWindowIds + .filter(id => companionWindows[id].position !== action.payload.position); + + return { + ...state, + [action.windowId]: { + ...state[action.windowId], + companionAreaOpen: true, + sideBarPanel: action.payload.content, + companionWindowIds: newCompanionWindowIds.concat([action.id]), + }, + }; + } + + return { + ...state, + [action.windowId]: { + ...state[action.windowId], + companionWindowIds: state[action.windowId].companionWindowIds.concat([action.id]), + }, + }; default: return state; }