diff --git a/CHANGELOG.md b/CHANGELOG.md
index d6798acea..f767bc131 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@
## [10.1.0] IN PROGRESS
* Don't display affiliations of users with types `patron` or `dcb`. Refs UIU-2967.
+* Make the `username` field required for users with the `staff` type in ECS mode. Refs UIU-2970.
## [10.0.0](https://github.com/folio-org/ui-users/tree/v10.0.0) (2023-10-13)
[Full Changelog](https://github.com/folio-org/ui-users/compare/v9.0.3...v10.0.0)
diff --git a/src/components/EditSections/EditExtendedInfo/EditExtendedInfo.js b/src/components/EditSections/EditExtendedInfo/EditExtendedInfo.js
index 8829ce510..dd98c3e5a 100644
--- a/src/components/EditSections/EditExtendedInfo/EditExtendedInfo.js
+++ b/src/components/EditSections/EditExtendedInfo/EditExtendedInfo.js
@@ -12,7 +12,10 @@ import {
Datepicker,
Headline,
} from '@folio/stripes/components';
-import { IfPermission } from '@folio/stripes/core';
+import {
+ IfPermission,
+ stripesShape,
+} from '@folio/stripes/core';
import { withFormValues } from '../../Wrappers';
import asyncValidateField from '../../validators/asyncValidateField';
@@ -21,6 +24,10 @@ import {
addressTypesShape,
departmentsShape,
} from '../../../shapes';
+import {
+ isConsortiumEnabled,
+ isStaffUser,
+} from '../../util';
import CreateResetPasswordControl from './CreateResetPasswordControl';
import RequestPreferencesEdit from './RequestPreferencesEdit';
@@ -41,6 +48,7 @@ class EditExtendedInfo extends Component {
values: PropTypes.object,
uniquenessValidator: PropTypes.object,
disabled: PropTypes.bool,
+ stripes: stripesShape,
};
buildAccordionHeader = () => {
@@ -85,6 +93,8 @@ class EditExtendedInfo extends Component {
change,
uniquenessValidator,
disabled,
+ values,
+ stripes,
} = this.props;
const accordionHeader = this.buildAccordionHeader();
@@ -92,6 +102,7 @@ class EditExtendedInfo extends Component {
const addresses = this.getAddresses();
const defaultDeliveryAddressTypeId = this.getDefaultDeliveryAddressTypeId();
const deliveryAvailable = this.isDeliveryAvailable();
+ const isUsernameFieldRequired = isConsortiumEnabled(stripes) && isStaffUser(values);
return (
diff --git a/src/components/EditSections/EditExtendedInfo/EditExtendedInfo.test.js b/src/components/EditSections/EditExtendedInfo/EditExtendedInfo.test.js
index 37cb243c6..20553a94b 100644
--- a/src/components/EditSections/EditExtendedInfo/EditExtendedInfo.test.js
+++ b/src/components/EditSections/EditExtendedInfo/EditExtendedInfo.test.js
@@ -2,7 +2,9 @@ import { screen } from '@folio/jest-config-stripes/testing-library/react';
import { Form } from 'react-final-form';
import PropTypes from 'prop-types';
+import buildStripes from '__mock__/stripes.mock';
import renderWithRouter from 'helpers/renderWithRouter';
+import { USER_TYPES } from '../../../constants';
import EditExtendedInfo from './EditExtendedInfo';
jest.unmock('@folio/stripes/components');
@@ -22,7 +24,7 @@ const arrayMutators = {
update: jest.fn()
};
-const renderEditExtendedInfo = (props) => {
+const renderEditExtendedInfo = (props, initialValues) => {
const component = () => (
<>
@@ -35,6 +37,7 @@ const renderEditExtendedInfo = (props) => {
mutators={{
...arrayMutators
}}
+ initialValues={initialValues}
onSubmit={onSubmit}
render={component}
/>
@@ -67,6 +70,7 @@ const props = {
}],
values: {},
uniquenessValidator: {},
+ stripes: buildStripes(),
};
const DepartmentsName = ({ departments }) => {
return departments.map((dep) => {
@@ -125,4 +129,51 @@ describe('Render Extended User Information component', () => {
renderEditExtendedInfo({ ...props, disabled: true });
expect(screen.getAllByRole('textbox')[0]).toBeDisabled();
});
+
+ describe('Username field', () => {
+ it('should be required for users with the \'staff\' type in ECS mode', () => {
+ renderEditExtendedInfo(
+ {
+ ...props,
+ stripes: {
+ ...props.stripes,
+ hasInterface: () => true,
+ },
+ },
+ { type: USER_TYPES.STAFF }
+ );
+
+ expect(screen.getByRole('textbox', { name: 'ui-users.information.username' })).toBeRequired();
+ });
+
+ it('should NOT be required if user type is other than \'staff\' in ECS mode', () => {
+ renderEditExtendedInfo(
+ {
+ ...props,
+ stripes: {
+ ...props.stripes,
+ hasInterface: () => true,
+ },
+ },
+ { type: USER_TYPES.PATRON }
+ );
+
+ expect(screen.getByRole('textbox', { name: 'ui-users.information.username' })).not.toBeRequired();
+ });
+
+ it('should NOT be required in default mode (non ECS)', () => {
+ renderEditExtendedInfo(
+ {
+ ...props,
+ stripes: {
+ ...props.stripes,
+ hasInterface: (i) => i !== 'consortia',
+ },
+ },
+ { type: USER_TYPES.STAFF }
+ );
+
+ expect(screen.getByRole('textbox', { name: 'ui-users.information.username' })).not.toBeRequired();
+ });
+ });
});
diff --git a/src/components/util/util.js b/src/components/util/util.js
index aa4d1ce03..64bcf990c 100644
--- a/src/components/util/util.js
+++ b/src/components/util/util.js
@@ -203,6 +203,7 @@ export const getRequestUrl = (barcode, userId) => {
export const isPatronUser = (user) => user?.type === USER_TYPES.PATRON;
export const isDcbUser = (user) => user?.type === USER_TYPES.DCB;
+export const isStaffUser = (user) => user?.type === USER_TYPES.STAFF;
export const isAffiliationsEnabled = (user) => {
return !isPatronUser(user) && !isDcbUser(user);
diff --git a/src/views/UserEdit/UserForm.js b/src/views/UserEdit/UserForm.js
index f96fb888f..98c5d75b2 100644
--- a/src/views/UserEdit/UserForm.js
+++ b/src/views/UserEdit/UserForm.js
@@ -369,6 +369,7 @@ class UserForm extends React.Component {
departments={formData.departments}
uniquenessValidator={uniquenessValidator}
disabled={isShadowUser}
+ stripes={stripes}
/>