From 5a71266bcc3a6743c6c974c020acf762e25d714d Mon Sep 17 00:00:00 2001 From: Anastasia Hahanova <43647240+anastasiaHahanova@users.noreply.github.com> Date: Mon, 17 Dec 2018 16:38:35 +0200 Subject: [PATCH] UIU-754: Users App: Implement Pane header dropdown on Detail Records (#638) * Implement pane header dropdown on detail records --- src/UserForm.js | 69 +++++++++++++++++-- src/ViewUser.js | 45 ++++++++++-- test/bigtest/interactors/user-form-page.js | 28 ++++++++ test/bigtest/interactors/user-view-page.js | 21 ++++++ .../network/factories/user-personal.js | 2 - test/bigtest/network/factories/user.js | 6 +- test/bigtest/tests/user-create-page-test.js | 42 +++++++++++ test/bigtest/tests/user-edit-page-test.js | 46 +++++++++++++ test/bigtest/tests/user-view-page-test.js | 42 +++++++++++ test/bigtest/tests/users-show-all-test.js | 4 +- translations/ui-users/en.json | 1 + 11 files changed, 288 insertions(+), 18 deletions(-) create mode 100644 test/bigtest/interactors/user-form-page.js create mode 100644 test/bigtest/interactors/user-view-page.js create mode 100644 test/bigtest/tests/user-create-page-test.js create mode 100644 test/bigtest/tests/user-edit-page-test.js create mode 100644 test/bigtest/tests/user-view-page-test.js diff --git a/src/UserForm.js b/src/UserForm.js index f27880a4d..ac260f32b 100644 --- a/src/UserForm.js +++ b/src/UserForm.js @@ -2,10 +2,12 @@ import cloneDeep from 'lodash/cloneDeep'; import React from 'react'; import { FormattedMessage } from 'react-intl'; import PropTypes from 'prop-types'; + import { Paneset, Pane, PaneMenu, + Icon, IconButton, Button, ExpandAllButton, @@ -172,7 +174,7 @@ class UserForm extends React.Component { return ( - { ariaLabel => ( + {ariaLabel => ( @@ -217,6 +222,7 @@ class UserForm extends React.Component { this.setState((curState) => { const newState = cloneDeep(curState); newState.sections[id] = !newState.sections[id]; + return newState; }); } @@ -224,6 +230,7 @@ class UserForm extends React.Component { toggleAllSections(expand) { this.setState((curState) => { const newSections = expandAllFunction(curState.sections, expand); + return { sections: newSections }; @@ -246,11 +253,36 @@ class UserForm extends React.Component { } executeSave() { - const { handleSubmit, onSubmit } = this.props; + const { + handleSubmit, + onSubmit, + } = this.props; + const submitter = handleSubmit(onSubmit); + submitter(); } + getActionMenu = ({ onToggle }) => { + const { onCancel } = this.props; + const handleClick = () => { + onCancel(); + onToggle(); + }; + + return ( + + ); + }; + render() { const { initialValues, @@ -259,25 +291,48 @@ class UserForm extends React.Component { connect, }, } = this.props; + const { sections } = this.state; const firstMenu = this.getAddFirstMenu(); const paneTitle = initialValues.id ? getFullName(initialValues) : ; + const lastMenu = initialValues.id ? this.getLastMenu('clickable-updateuser', ) : this.getLastMenu('clickable-createnewuser', ); return ( -
+ - +
- {getFullName(initialValues)} + + {getFullName(initialValues)} + - + diff --git a/src/ViewUser.js b/src/ViewUser.js index d5bcd8c13..fff684ae7 100644 --- a/src/ViewUser.js +++ b/src/ViewUser.js @@ -11,6 +11,7 @@ import { TitleManager, } from '@folio/stripes/core'; import { + Button, Pane, PaneMenu, IconButton, @@ -250,7 +251,7 @@ class ViewUser extends React.Component { }, { name: 'expandAllSections', - handler: this.expandAllSections, + handler: this.expandAllSections, }, ]; } @@ -701,7 +702,7 @@ class ViewUser extends React.Component { handleAddRecords={this.handleAddRecords} stripes={stripes} onCancel={this.onClickCloseAccountActionsHistory} - // when navigating away to another user, clear all loan-related state + // when navigating away to another user, clear all loan-related state onClickUser={() => { this.onClickCloseAccountActionsHistory(); this.onClickCloseAccountsHistory(); }} /> @@ -869,6 +870,26 @@ class ViewUser extends React.Component { ); } + getActionMenu = ({ onToggle }) => { + const { onEdit } = this.props; + const handleClick = () => { + onEdit(); + onToggle(); + }; + + return ( + + ); + } + renderUser(user) { const { resources, @@ -891,19 +912,30 @@ class ViewUser extends React.Component { const patronBlocks = get(resources, ['hasPatronBlocks', 'records'], []); const patronGroup = this.getPatronGroup(user); const detailMenu = this.renderDetailMenu(user); + return ( {getFullName(user)}} + paneTitle={( + + {getFullName(user)} + + )} lastMenu={detailMenu} dismissible onClose={onClose} appIcon={{ app: 'users' }} + actionMenu={this.getActionMenu} > - {getFullName(user)} + + {getFullName(user)} + {(hasPatronBlocks === 1 && totalPatronBlocks > 0) @@ -911,7 +943,10 @@ class ViewUser extends React.Component { : ''} - + diff --git a/test/bigtest/interactors/user-form-page.js b/test/bigtest/interactors/user-form-page.js new file mode 100644 index 000000000..ec567f3bb --- /dev/null +++ b/test/bigtest/interactors/user-form-page.js @@ -0,0 +1,28 @@ +import { + interactor, + clickable, + text, + isPresent, +} from '@bigtest/interactor'; + +@interactor class HeaderDropdown { + click = clickable('button'); +} + +@interactor class HeaderDropdownMenu { + clickCancel = clickable('[data-test-cancel-user-form-action]'); +} + +@interactor class UserFormPage { + isLoaded = isPresent('[class*=paneTitleLabel---]'); + + whenLoaded() { + return this.when(() => this.isLoaded); + } + + title = text('[class*=paneTitleLabel---]'); + headerDropdown = new HeaderDropdown('[class*=paneHeaderCenterInner---] [class*=dropdown---]'); + headerDropdownMenu = new HeaderDropdownMenu(); +} + +export default new UserFormPage('[data-test-form-page]'); diff --git a/test/bigtest/interactors/user-view-page.js b/test/bigtest/interactors/user-view-page.js new file mode 100644 index 000000000..760e35770 --- /dev/null +++ b/test/bigtest/interactors/user-view-page.js @@ -0,0 +1,21 @@ +import { + interactor, + clickable, + text, +} from '@bigtest/interactor'; + +@interactor class HeaderDropdown { + click = clickable('button'); +} + +@interactor class HeaderDropdownMenu { + clickEdit = clickable('[data-test-user-instance-edit-action]'); +} + +@interactor class InstanceViewPage { + title = text('[data-test-header-title]'); + headerDropdown = new HeaderDropdown('[class*=paneHeaderCenterInner---] [class*=dropdown---]'); + headerDropdownMenu = new HeaderDropdownMenu(); +} + +export default new InstanceViewPage('[data-test-instance-details]'); diff --git a/test/bigtest/network/factories/user-personal.js b/test/bigtest/network/factories/user-personal.js index b7170f5a3..229b8d758 100644 --- a/test/bigtest/network/factories/user-personal.js +++ b/test/bigtest/network/factories/user-personal.js @@ -1,8 +1,6 @@ import { Factory, faker } from '@bigtest/mirage'; export default Factory.extend({ - lastName: () => faker.name.lastName(), - firstName: () => faker.name.firstName(), email: () => faker.internet.email(), phone: () => faker.phone.phoneNumber(), mobilePhone: () => faker.phone.phoneNumber(), diff --git a/test/bigtest/network/factories/user.js b/test/bigtest/network/factories/user.js index e0de58289..98cbe4665 100644 --- a/test/bigtest/network/factories/user.js +++ b/test/bigtest/network/factories/user.js @@ -18,6 +18,7 @@ export default Factory.extend({ expirationDate: () => '2020-04-07T00:00:00.000+0000', createdDate: () => '2018-11-20T11:42:53.385+0000', updatedDate: () => '2018-11-20T20:00:47.409+0000', + afterCreate(user, server) { server.create('service-points-user', { 'userId': user.id, @@ -26,10 +27,11 @@ export default Factory.extend({ }); const personal = server.create('user-personal', { - lastName: 'test', - firstName: 'test' + lastName: faker.name.lastName(), + firstName: faker.name.firstName(), }); + user.update('username', `${personal.lastName}, ${personal.firstName}`); user.update('personal', personal.toJSON()); user.save(); } diff --git a/test/bigtest/tests/user-create-page-test.js b/test/bigtest/tests/user-create-page-test.js new file mode 100644 index 000000000..1589a7065 --- /dev/null +++ b/test/bigtest/tests/user-create-page-test.js @@ -0,0 +1,42 @@ +import { + beforeEach, + describe, + it, +} from '@bigtest/mocha'; +import { expect } from 'chai'; + +import setupApplication from '../helpers/setup-application'; +import UserFormPage from '../interactors/user-form-page'; +import UsersInteractor from '../interactors/users'; + +describe('ItemCreatePage', () => { + setupApplication(); + + const users = new UsersInteractor(); + + beforeEach(async function () { + this.visit('/users?layer=create'); + }); + + describe('visiting the create user page', () => { + it('displays the title in the pane header', () => { + expect(UserFormPage.title).to.equal('Create User'); + }); + + describe('pane header menu', () => { + beforeEach(async () => { + await UserFormPage.headerDropdown.click(); + }); + + describe('clicking on cancel', () => { + beforeEach(async () => { + await UserFormPage.headerDropdownMenu.clickCancel(); + }); + + it('should redirect to view users page after click', () => { + expect(users.$root).to.exist; + }); + }); + }); + }); +}); diff --git a/test/bigtest/tests/user-edit-page-test.js b/test/bigtest/tests/user-edit-page-test.js new file mode 100644 index 000000000..7adee7edd --- /dev/null +++ b/test/bigtest/tests/user-edit-page-test.js @@ -0,0 +1,46 @@ +import { + beforeEach, + describe, + it, +} from '@bigtest/mocha'; +import { expect } from 'chai'; + +import setupApplication from '../helpers/setup-application'; +import UserFormPage from '../interactors/user-form-page'; +import UsersInteractor from '../interactors/users'; + +describe('ItemEditPage', () => { + setupApplication(); + + const users = new UsersInteractor(); + let user; + + beforeEach(async function () { + user = this.server.create('user'); + + this.visit(`/users/view/${user.id}?layer=edit`); + await UserFormPage.whenLoaded(); + }); + + describe('visiting the edit user page', () => { + it('displays the title in the pane header', () => { + expect(UserFormPage.title).to.equal(user.username); + }); + + describe('pane header menu', () => { + beforeEach(async () => { + await UserFormPage.headerDropdown.click(); + }); + + describe('clicking on cancel', () => { + beforeEach(async () => { + await UserFormPage.headerDropdownMenu.clickCancel(); + }); + + it('should redirect to view users page after click', () => { + expect(users.$root).to.exist; + }); + }); + }); + }); +}); diff --git a/test/bigtest/tests/user-view-page-test.js b/test/bigtest/tests/user-view-page-test.js new file mode 100644 index 000000000..898297106 --- /dev/null +++ b/test/bigtest/tests/user-view-page-test.js @@ -0,0 +1,42 @@ +import { + beforeEach, + describe, + it, +} from '@bigtest/mocha'; +import { expect } from 'chai'; + +import setupApplication from '../helpers/setup-application'; +import InstanceViewPage from '../interactors/user-view-page'; +import UserFormPage from '../interactors/user-form-page'; + +describe('UserViewPage', () => { + setupApplication(); + + let user; + + beforeEach(async function () { + user = this.server.create('user'); + + this.visit(`/users/view/${user.id}`); + }); + + it('displays the instance title in the pane header', () => { + expect(InstanceViewPage.title).to.equal(user.username); + }); + + describe('pane header dropdown menu', () => { + beforeEach(async () => { + await InstanceViewPage.headerDropdown.click(); + }); + + describe('clicking on edit', () => { + beforeEach(async () => { + await InstanceViewPage.headerDropdownMenu.clickEdit(); + }); + + it('should redirect to instance edit page', () => { + expect(UserFormPage.$root).to.exist; + }); + }); + }); +}); diff --git a/test/bigtest/tests/users-show-all-test.js b/test/bigtest/tests/users-show-all-test.js index 7e05759a8..cb13c1f63 100644 --- a/test/bigtest/tests/users-show-all-test.js +++ b/test/bigtest/tests/users-show-all-test.js @@ -11,7 +11,7 @@ describe('Users', () => { const users = new UsersInteractor(); beforeEach(async function () { - this.server.createList('user', 20); + this.server.createList('user', 3); this.visit('/users?filters=active.Include%20inactive%20users&sort=Name'); }); @@ -20,7 +20,7 @@ describe('Users', () => { }); it('renders each user instance', () => { - expect(users.instances().length).to.be.equal(20); + expect(users.instances().length).to.be.equal(3); }); describe('clicking on the first user item', function () { diff --git a/translations/ui-users/en.json b/translations/ui-users/en.json index 4bc0b15e3..a250d926a 100644 --- a/translations/ui-users/en.json +++ b/translations/ui-users/en.json @@ -474,6 +474,7 @@ "saveAndClose": "Save & close", "edit": "Edit", "okay": "OK", + "cancel": "Cancel", "description": "Description", "duplicated": "{field} already exists", "showTags": "Show Tags",