Skip to content

Commit

Permalink
Use organizations-storage settings api
Browse files Browse the repository at this point in the history
  • Loading branch information
alb3rtino committed Dec 9, 2024
1 parent b398e75 commit d643304
Show file tree
Hide file tree
Showing 12 changed files with 281 additions and 65 deletions.
23 changes: 10 additions & 13 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@
"organizations-storage.interfaces": "2.1",
"organizations-storage.phone-numbers": "2.0",
"organizations-storage.privileged-contacts": "1.0",
"organizations-storage.settings": "1.0",
"organizations-storage.settings": "1.1",
"organizations-storage.urls": "1.1",
"settings": "1.1",
"tags": "1.0",
"users": "15.1 16.0"
},
"optionalOkapiInterfaces": {
"servint": "4.0"
},
"queryResource": "query",
"icons": [
{
Expand Down Expand Up @@ -66,7 +68,9 @@
{
"permissionName": "ui-organizations.third-party-services.execute",
"displayName": "Organizations: Permissions required to call services apart from mod-organizations-storage",
"replaces": ["ui-organizations.third-party-services"],
"replaces": [
"ui-organizations.third-party-services"
],
"visible": false,
"subPermissions": [
"acquisition.organization.events.get",
Expand All @@ -87,8 +91,6 @@
"data-export.config.collection.get",
"data-export.config.item.get",
"erm.agreements.collection.get",
"mod-settings.entries.collection.get",
"mod-settings.global.read.ui-organizations.vendor-generator-setting",
"orders.acquisition-methods.collection.get",
"orders.acquisition-method.item.get",
"organizations.organizations.collection.get",
Expand Down Expand Up @@ -307,11 +309,9 @@
"displayName": "Settings (Organizations): Manage number generator options",
"subPermissions": [
"settings.organizations.enabled",
"mod-settings.entries.collection.get",
"mod-settings.entries.item.post",
"mod-settings.entries.item.put",
"mod-settings.global.read.ui-organizations.vendor-generator-setting",
"mod-settings.global.write.ui-organizations.vendor-generator-setting"
"organizations-storage.settings.collection.get",
"organizations-storage.settings.item.post",
"organizations-storage.settings.item.put"
],
"visible": true
}
Expand Down Expand Up @@ -399,8 +399,5 @@
"optionalDependencies": {
"@folio/plugin-find-contact": "^5.0.0",
"@folio/plugin-find-interface": "^5.0.0"
},
"optionalOkapiInterfaces": {
"servint": "4.0"
}
}
52 changes: 52 additions & 0 deletions src/Settings/NumberGeneratorSettings/NumberGeneratorSettings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { FormattedMessage } from 'react-intl';

import { Loading } from '@folio/stripes/components';
import { useOkapiKy } from '@folio/stripes/core';
import { useShowCallout } from '@folio/stripes-acq-components';

import NumberGeneratorSettingsForm from './NumberGeneratorSettingsForm';
import { SETTINGS_API } from '../../common/constants/api';
import { VENDOR_CODE_GENERATOR_SETTINGS_KEY } from '../../common/constants/numberGenerator';
import { useVendorCodeGeneratorSettings } from '../../common/hooks/useVendorCodeGeneratorSettings';

const NumberGeneratorSettings = () => {
const { vendorCodeSetting, isLoading } = useVendorCodeGeneratorSettings();
const ky = useOkapiKy();
const sendCallout = useShowCallout();

const onSubmit = async ({ [VENDOR_CODE_GENERATOR_SETTINGS_KEY]: value }) => {
try {
if (vendorCodeSetting) {
await ky.put(`${SETTINGS_API}/${vendorCodeSetting.id}`, {
json: { ...vendorCodeSetting, value },
});
} else {
await ky.post(SETTINGS_API, {
json: { key: VENDOR_CODE_GENERATOR_SETTINGS_KEY, value },
});
}

sendCallout({
message: <FormattedMessage id="ui-organizations.settings.numberGeneratorOptions.save.success" />,
});
} catch (error) {
sendCallout({
type: 'error',
message: <FormattedMessage id="ui-organizations.settings.numberGeneratorOptions.save.error" />,
});
}
};

if (isLoading) {
return <Loading />;
}

return (
<NumberGeneratorSettingsForm
initialValues={{ [VENDOR_CODE_GENERATOR_SETTINGS_KEY]: vendorCodeSetting?.value }}
onSubmit={onSubmit}
/>
);
};

export default NumberGeneratorSettings;
117 changes: 117 additions & 0 deletions src/Settings/NumberGeneratorSettings/NumberGeneratorSettings.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { FormattedMessage } from 'react-intl';

import {
render,
screen,
} from '@folio/jest-config-stripes/testing-library/react';
import userEvent from '@folio/jest-config-stripes/testing-library/user-event';
import { useOkapiKy } from '@folio/stripes/core';
import { useShowCallout } from '@folio/stripes-acq-components';

import NumberGeneratorSettings from './NumberGeneratorSettings';
import { SETTINGS_API } from '../../common/constants/api';
import { useVendorCodeGeneratorSettings } from '../../common/hooks/useVendorCodeGeneratorSettings';

jest.mock('@folio/stripes/core', () => ({
useOkapiKy: jest.fn(),
}));

jest.mock('@folio/stripes-acq-components', () => ({
useShowCallout: jest.fn(),
}));

jest.mock('../../common/hooks/useVendorCodeGeneratorSettings');

jest.mock('@folio/stripes/components', () => ({
Loading: () => <div>Loading</div>,
}));

jest.mock('../../common/constants/numberGenerator', () => ({
...jest.requireActual('../../common/constants/numberGenerator'),
VENDOR_CODE_GENERATOR_SETTINGS_KEY: 'testKey',
}));

jest.mock('./NumberGeneratorSettingsForm', () => jest.fn(({ onSubmit }) => (
<button
onClick={() => onSubmit({
testKey: 'testValue',
})}
type="button"
>
Submit
</button>
)));

const renderComponent = () => render(<NumberGeneratorSettings />);

describe('NumberGeneratorSettings', () => {
const mockKyPut = jest.fn();
const mockKyPost = jest.fn();
const mockSendCallout = jest.fn();

beforeEach(() => {
useOkapiKy.mockReturnValue({
put: mockKyPut,
post: mockKyPost,
});
useShowCallout.mockReturnValue(mockSendCallout);
});

it('should render Loading', () => {
useVendorCodeGeneratorSettings.mockReturnValue({ isLoading: true });
renderComponent();
expect(screen.getByText('Loading')).toBeInTheDocument();
});

it('should render NumberGeneratorSettingsForm', () => {
useVendorCodeGeneratorSettings.mockReturnValue({ isLoading: false });
renderComponent();
expect(screen.getByText('Submit')).toBeInTheDocument();
});

it('should call ky.post when no setting is present', async () => {
useVendorCodeGeneratorSettings.mockReturnValue({ isLoading: false });
renderComponent();

await userEvent.click(screen.getByText('Submit'));

expect(mockKyPost).toHaveBeenCalledWith(SETTINGS_API, {
json: { key: 'testKey', value: 'testValue' },
});
expect(mockSendCallout).toHaveBeenCalledWith({
message: <FormattedMessage id="ui-organizations.settings.numberGeneratorOptions.save.success" />,
});
});

it('should call ky.put when setting exists', async () => {
const vendorCodeSetting = { id: '123', key: 'testKey', value: 'someValue', _version: 1 };

useVendorCodeGeneratorSettings.mockReturnValue({
isLoading: false,
vendorCodeSetting,
});
renderComponent();

await userEvent.click(screen.getByText('Submit'));

expect(mockKyPut).toHaveBeenCalledWith(`${SETTINGS_API}/${vendorCodeSetting.id}`, {
json: { ...vendorCodeSetting, value: 'testValue' },
});
expect(mockSendCallout).toHaveBeenCalledWith({
message: <FormattedMessage id="ui-organizations.settings.numberGeneratorOptions.save.success" />,
});
});

it('should show error callout when submission fails', async () => {
useVendorCodeGeneratorSettings.mockReturnValue({ isLoading: false });
mockKyPost.mockRejectedValue(new Error());
renderComponent();

await userEvent.click(screen.getByText('Submit'));

expect(mockSendCallout).toHaveBeenCalledWith({
type: 'error',
message: <FormattedMessage id="ui-organizations.settings.numberGeneratorOptions.save.error" />,
});
});
});
62 changes: 43 additions & 19 deletions src/Settings/NumberGeneratorSettings/NumberGeneratorSettingsForm.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,51 @@
import { useMemo } from 'react';
import PropTypes from 'prop-types';
import { Field } from 'react-final-form';
import { FormattedMessage } from 'react-intl';

import {
Button,
Col,
MessageBanner,
Pane,
PaneFooter,
PaneHeader,
RadioButton,
Row,
} from '@folio/stripes/components';
import { useStripes } from '@folio/stripes/core';
import { ConfigManager } from '@folio/stripes/smart-components';
import stripesFinalForm from '@folio/stripes/final-form';

import css from './NumberGeneratorSettingsForm.css';
import {
VENDOR_CODE_GENERATOR_OPTIONS,
VENDOR_CODE_GENERATOR_SETTINGS_KEY,
VENDOR_CODE_GENERATOR_SETTINGS_SCOPE,
} from '../../common/constants/numberGenerator';

export const NumberGeneratorSettingsForm = () => {
const stripes = useStripes();
const ConnectedConfigManager = useMemo(() => stripes.connect(ConfigManager), [stripes]);
const NumberGeneratorSettingsForm = ({ handleSubmit, pristine, submitting }) => {
const paneHeader = (renderProps) => (
<PaneHeader
{...renderProps}
paneTitle={<FormattedMessage id="ui-organizations.settings.numberGeneratorOptions" />}
/>
);

const beforeSave = (data) => data[VENDOR_CODE_GENERATOR_SETTINGS_KEY] || '';
const getInitialValues = (items) => ({ [VENDOR_CODE_GENERATOR_SETTINGS_KEY]: items?.[0]?.value || '' });
const paneFooter = (
<PaneFooter
renderEnd={
<Button
buttonStyle="primary mega"
disabled={pristine || submitting}
id="clickable-save-number-generator-settings"
onClick={handleSubmit}
type="submit"
>
<FormattedMessage id="stripes-core.button.save" />
</Button>
}
/>
);

return (
<ConnectedConfigManager
configName={VENDOR_CODE_GENERATOR_SETTINGS_KEY}
formType="final-form"
getInitialValues={getInitialValues}
label={<FormattedMessage id="ui-organizations.settings.numberGeneratorOptions" />}
onBeforeSave={beforeSave}
scope={VENDOR_CODE_GENERATOR_SETTINGS_SCOPE}
stripes={stripes}
>
<Pane defaultWidth="fill" footer={paneFooter} id="vendor-code-settings" renderHeader={paneHeader}>
<Row>
<Col xs={12}>
<div className={css.marginBottomGutter}>
Expand Down Expand Up @@ -72,6 +83,19 @@ export const NumberGeneratorSettingsForm = () => {
/>
</Col>
</Row>
</ConnectedConfigManager>
</Pane>
);
};

NumberGeneratorSettingsForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
pristine: PropTypes.bool.isRequired,
submitting: PropTypes.bool.isRequired,
};

export default stripesFinalForm({
enableReinitialize: true,
keepDirtyOnReinitialize: true,
navigationCheck: true,
subscription: { values: true },
})(NumberGeneratorSettingsForm);
Loading

0 comments on commit d643304

Please sign in to comment.