Skip to content

Commit

Permalink
UICIRC-1118: Implement feature toggle for ECS and not ECS envs
Browse files Browse the repository at this point in the history
  • Loading branch information
Dmitriy-Litvinenko committed Nov 16, 2024
1 parent 1cab325 commit f8786dc
Show file tree
Hide file tree
Showing 15 changed files with 883 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Create a new setting - Enable ECS title level requests. Refs UICIRC-1040.
* Add view permissions for Circulation settings. Refs UICIRC-1056.
* Fix DOMPurify import. Refs UICIRC-1122.
* Implement feature toggle for ECS and not ECS envs. Refs UICIRC-1118.

## [9.2.0](https://github.com/folio-org/ui-circulation/tree/v9.2.0) (2024-10-30)
[Full Changelog](https://github.com/folio-org/ui-circulation/compare/v9.1.0...v9.2.0)
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,8 @@
"mod-settings.global.read.circulation",
"mod-settings.entries.collection.get",
"mod-settings.entries.item.get",
"circulation.requests.collection.get"
"circulation.requests.collection.get",
"configuration.entries.collection.get"
]
},
{
Expand All @@ -403,7 +404,9 @@
"ui-circulation.settings.view-titleLevelRequests",
"mod-settings.global.write.circulation",
"mod-settings.entries.item.put",
"mod-settings.entries.item.post"
"mod-settings.entries.item.post",
"configuration.entries.item.post",
"configuration.entries.item.put"
],
"visible": true
},
Expand Down
58 changes: 58 additions & 0 deletions src/deprecated/settings/TitleLevelRequests/TitleLevelRequests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl } from 'react-intl';

import { ConfigManager } from '@folio/stripes/smart-components';
import {
withStripes,
TitleManager,
} from '@folio/stripes/core';

import TitleLevelRequestsForm from './TitleLevelRequestsForm';
import {
getInitialValues,
normalizeData,
} from './utils';
import {
MODULE_NAMES,
} from '../../../constants';

export const CONFIG_NAMES = {
TLR: 'TLR',
PRINT_HOLD_REQUESTS: 'PRINT_HOLD_REQUESTS',
};

const TitleLevelRequests = ({
stripes,
intl: {
formatMessage,
},
}) => {
const ConnectedConfigManager = stripes.connect(ConfigManager);

return (
<TitleManager
page={formatMessage({ id: 'ui-circulation.settings.title.general' })}
record={formatMessage({ id: 'ui-circulation.settings.title.titleLevelRequests' })}
>
<ConnectedConfigManager
label={formatMessage({ id: 'ui-circulation.settings.titleLevelRequests.paneTitle' })}
moduleName={MODULE_NAMES.SETTINGS}
configName={CONFIG_NAMES.TLR}
configFormComponent={TitleLevelRequestsForm}
stripes={stripes}
getInitialValues={getInitialValues}
onBeforeSave={normalizeData}
/>
</TitleManager>
);
};

TitleLevelRequests.propTypes = {
stripes: PropTypes.shape({
connect: PropTypes.func.isRequired,
}).isRequired,
intl: PropTypes.object.isRequired,
};

export default withStripes(injectIntl(TitleLevelRequests));
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
render,
} from '@folio/jest-config-stripes/testing-library/react';
import { ConfigManager } from '@folio/stripes/smart-components';
import { TitleManager } from '@folio/stripes/core';

import TitleLevelRequests, {
CONFIG_NAMES,
} from './TitleLevelRequests';
import TitleLevelRequestsForm from './TitleLevelRequestsForm';
import {
getInitialValues,
normalizeData,
} from './utils';
import {
MODULE_NAMES,
} from '../../../constants';

describe('deprecated TitleLevelRequests', () => {
const paneTitleLabelId = 'ui-circulation.settings.titleLevelRequests.paneTitle';
const mockedStripes = {
connect: jest.fn((component) => component),
};
const labelIds = {
generalTitle: 'ui-circulation.settings.title.general',
titleLevelRequestsTitle: 'ui-circulation.settings.title.titleLevelRequests',
};

beforeEach(() => {
render(
<TitleLevelRequests
stripes={mockedStripes}
/>
);
});

afterEach(() => {
ConfigManager.mockClear();
mockedStripes.connect.mockClear();
});

it('should connect "ConfigManager" to stripes', () => {
expect(mockedStripes.connect).toHaveBeenLastCalledWith(ConfigManager);
});

it('should execute "ConfigManager" with passed props', () => {
const expectedResult = {
label: paneTitleLabelId,
moduleName: MODULE_NAMES.SETTINGS,
configName: CONFIG_NAMES.TLR,
configFormComponent: TitleLevelRequestsForm,
stripes: mockedStripes,
getInitialValues,
onBeforeSave: normalizeData,
};

expect(ConfigManager).toHaveBeenLastCalledWith(expectedResult, {});
});

it('should trigger TitleManager with correct props', () => {
const expectedProps = {
page: labelIds.generalTitle,
record: labelIds.titleLevelRequestsTitle,
};

expect(TitleManager).toHaveBeenCalledWith(expect.objectContaining(expectedProps), {});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.titleLevelRequestsForm {
height: 100%;
}

.tlrSettings {
margin: 1.5em 0 2em;
}
212 changes: 212 additions & 0 deletions src/deprecated/settings/TitleLevelRequests/TitleLevelRequestsForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { injectIntl } from 'react-intl';

import { Field } from 'react-final-form';

import stripesFinalForm from '@folio/stripes/final-form';
import { stripesConnect } from '@folio/stripes/core';
import {
Button,
Checkbox,
Col,
Pane,
Row,
PaneFooter,
Modal,
} from '@folio/stripes/components';

import NoticeTemplates from '../../../settings/TLRPatronNotices/NoticeTemplates';
import {
patronNoticeCategoryIds,
MAX_UNPAGED_RESOURCE_COUNT,
TITLE_LEVEL_REQUESTS,
OPEN_REQUESTS_STATUSES,
REQUEST_LEVEL,
} from '../../../constants';

import css from './TitleLevelRequestsForm.css';

const statusesQueryPart = OPEN_REQUESTS_STATUSES.map(status => `status=="${status}"`).join(' OR ');

const TitleLevelRequestsForm = (props) => {
const {
handleSubmit,
intl: { formatMessage },
label,
pristine,
submitting,
form,
resources,
mutator,
} = props;

const [isErrorModalOpen, setIsErrorModalOpen] = useState(false);
const templates = resources.templates?.records || [];
const { values: titleLevelRequestsValues } = form.getState();

const renderFooter = () => (
<PaneFooter
renderEnd={(
<Button
type="submit"
buttonStyle="primary paneHeaderNewButton"
disabled={pristine || submitting}
marginBottom0
>
{formatMessage({ id: 'stripes-core.button.save' })}
</Button>
)}
/>
);

const handleTlrCheckboxClick = async () => {
if (!titleLevelRequestsValues[TITLE_LEVEL_REQUESTS.TLR_ENABLED]) {
form.change(TITLE_LEVEL_REQUESTS.TLR_ENABLED, true);

return;
}

const activeTitleRequests = await mutator.requests.GET();

if (activeTitleRequests.length) {
setIsErrorModalOpen(true);

return;
}

form.change(TITLE_LEVEL_REQUESTS.TLR_ENABLED, false);
};

const handleModalClose = () => setIsErrorModalOpen(false);

const modalFooter = (
<Button
onClick={handleModalClose}
buttonStyle="primary"
>
{formatMessage({ id: 'stripes-core.button.close' })}
</Button>
);

return (
<form
data-testid="tlrForm"
id="title-level-requests-form"
className={css.titleLevelRequestsForm}
noValidate
onSubmit={handleSubmit}
>
<Pane
id="title-level-requests-pane"
data-testid="tlrPane"
defaultWidth="fill"
fluidContentWidth
paneTitle={label}
footer={renderFooter()}
>
<Row>
<Col xs={12}>
<Field
data-testid="tlrSwitchCheckbox"
name={TITLE_LEVEL_REQUESTS.TLR_ENABLED}
type="checkbox"
label={formatMessage({ id: 'ui-circulation.settings.titleLevelRequests.allow' })}
component={Checkbox}
onChange={handleTlrCheckboxClick}
/>
</Col>
</Row>
{
titleLevelRequestsValues[TITLE_LEVEL_REQUESTS.TLR_ENABLED] &&
<>
<div className={css.tlrSettings}>
<Field
name={TITLE_LEVEL_REQUESTS.CREATE_TLR_BY_DEFAULT}
type="checkbox"
label={formatMessage({ id: 'ui-circulation.settings.titleLevelRequests.createTLR' })}
component={Checkbox}
/>
<Field
name={TITLE_LEVEL_REQUESTS.TLR_HOLD_SHOULD_FOLLOW_CIRCULATION_RULES}
type="checkbox"
label={formatMessage({ id: 'ui-circulation.settings.titleLevelRequests.tlrHoldShouldFollowCirculationRules' })}
component={Checkbox}
/>
</div>
<div className={css.tlrNoticeSection}>
<NoticeTemplates
templates={templates}
/>
</div>
</>
}
<Modal
data-testid="forbiddenDisableTlrModal"
label={formatMessage({ id: 'ui-circulation.settings.titleLevelRequests.forbiddenDisableTlrModal.title' })}
open={isErrorModalOpen}
onClose={handleModalClose}
dismissible
footer={modalFooter}
>
{formatMessage({ id: 'ui-circulation.settings.titleLevelRequests.forbiddenDisableTlrModal.description' })}
</Modal>
</Pane>
</form>
);
};

TitleLevelRequestsForm.manifest = Object.freeze({
templates: {
type: 'okapi',
path: 'templates',
records: 'templates',
params: {
query: `cql.allRecords=1 AND category="${patronNoticeCategoryIds.REQUEST}" AND active="true"`,
},
perRequest: MAX_UNPAGED_RESOURCE_COUNT,
},
requests: {
type: 'okapi',
path: 'circulation/requests',
records: 'requests',
accumulate: true,
fetch: false,
params: {
query: `${statusesQueryPart} AND requestLevel=="${REQUEST_LEVEL.TITLE}"`,
limit: '1',
},
},
});

TitleLevelRequestsForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
label: PropTypes.string.isRequired,
pristine: PropTypes.bool.isRequired,
submitting: PropTypes.bool.isRequired,
form: PropTypes.object.isRequired,
resources: PropTypes.shape({
templates: PropTypes.shape({
records: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
})),
}),
requests: PropTypes.shape({
records: PropTypes.arrayOf(PropTypes.object).isRequired,
}).isRequired,
}).isRequired,
mutator: PropTypes.shape({
requests: PropTypes.shape({
GET: PropTypes.func.isRequired,
}).isRequired,
}).isRequired,
};

const withStripes = stripesConnect(TitleLevelRequestsForm);

export default injectIntl(stripesFinalForm({
navigationCheck: true,
subscription: { values: true },
})(withStripes));
Loading

0 comments on commit f8786dc

Please sign in to comment.