Skip to content

Commit

Permalink
move send and delay claims modals to shared lib
Browse files Browse the repository at this point in the history
  • Loading branch information
usavkov-epam committed Dec 18, 2024
1 parent ff51770 commit e06c4c3
Show file tree
Hide file tree
Showing 18 changed files with 378 additions and 4 deletions.
12 changes: 9 additions & 3 deletions lib/FindRecords/hooks/useRecordsSelect/useRecordsSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,18 @@ export const useRecordsSelect = ({ records }) => {
[selectedRecordsMap],
);

const resetSelectedRecords = useCallback(() => {
setSelectedRecordsMap({});
emitChangeEvent({});
}, [emitChangeEvent]);

return {
allRecordsSelected,
selectedRecordsMap,
isRecordSelected,
resetSelectedRecords,
selectedRecordsLength,
toggleSelectAll,
selectedRecordsMap,
selectRecord,
isRecordSelected,
toggleSelectAll,
};
};
1 change: 1 addition & 0 deletions lib/claiming/components/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './menu-items';
export * from './modals';
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import PropTypes from 'prop-types';
import {
FormattedMessage,
useIntl,
} from 'react-intl';

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

import { ModalFooter } from '../../../../ModalFooter';
import { FieldClaimingDate } from '../../FieldClaimingDate';

const DelayClaimsModal = ({
claimsCount,
onCancel,
handleSubmit,
open,
}) => {
const intl = useIntl();
const modalLabel = intl.formatMessage(
{ id: 'stripes-acq-components.claiming.modal.delayClaim.heading' },
{ count: claimsCount },
);

const start = (
<Button
marginBottom0
onClick={onCancel}
>
<FormattedMessage id="stripes-acq-components.FormFooter.cancel" />
</Button>
);
const end = (
<Button
buttonStyle="primary"
onClick={handleSubmit}
marginBottom0
>
<FormattedMessage id="stripes-acq-components.FormFooter.save" />
</Button>
);

const footer = (
<ModalFooter
renderStart={start}
renderEnd={end}
/>
);

return (
<Modal
open={open}
id="delay-claim-modal"
size="small"
footer={footer}
label={modalLabel}
aria-label={modalLabel}
>
<form onSubmit={handleSubmit}>
<Row>
<Col xs>
<FieldClaimingDate label={<FormattedMessage id="stripes-acq-components.claiming.modal.delayClaim.field.delayTo" />} />
</Col>
</Row>
</form>
</Modal>
);
};

DelayClaimsModal.propTypes = {
claimsCount: PropTypes.number,
handleSubmit: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
open: PropTypes.bool,
};

export default stripesFinalForm({
navigationCheck: true,
subscription: { values: true },
})(DelayClaimsModal);
1 change: 1 addition & 0 deletions lib/claiming/components/modals/DelayClaimsModal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as DelayClaimsModal } from './DelayClaimsModal';
118 changes: 118 additions & 0 deletions lib/claiming/components/modals/SendClaimsModal/SendClaimsModal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import identity from 'lodash/identity';
import PropTypes from 'prop-types';
import { Field } from 'react-final-form';
import {
FormattedMessage,
useIntl,
} from 'react-intl';

import {
Button,
Col,
Modal,
Row,
TextArea,
} from '@folio/stripes/components';
import stripesFinalForm from '@folio/stripes/final-form';

import { ModalFooter } from '../../../../ModalFooter';
import { FieldClaimingDate } from '../../FieldClaimingDate';

const SendClaimsModal = ({
claimsCount,
handleSubmit,
onCancel,
open,
message,
}) => {
const intl = useIntl();
const modalLabel = intl.formatMessage(
{ id: 'stripes-acq-components.claiming.modal.sendClaim.heading' },
{ count: claimsCount },
);

const start = (
<Button
marginBottom0
onClick={onCancel}
>
<FormattedMessage id="stripes-acq-components.FormFooter.cancel" />
</Button>
);
const end = (
<Button
buttonStyle="primary"
marginBottom0
onClick={handleSubmit}
>
<FormattedMessage id="stripes-acq-components.FormFooter.save" />
</Button>
);

const footer = (
<ModalFooter
renderStart={start}
renderEnd={end}
/>
);

return (
<Modal
open={open}
id="send-claim-modal"
footer={footer}
label={modalLabel}
aria-label={modalLabel}
>
<form onSubmit={handleSubmit}>
{message && (
<Row>
<Col xs>
{message}
</Col>
</Row>
)}

<Row>
<Col xs>
<FieldClaimingDate label={<FormattedMessage id="stripes-acq-components.claiming.modal.sendClaim.field.claimExpiryDate" />} />
</Col>
</Row>

<Row>
<Col xs>
<Field
component={TextArea}
fullWidth
label={<FormattedMessage id="stripes-acq-components.claiming.modal.sendClaim.field.internalNote" />}
name="internalNote"
parse={identity}
/>
</Col>
<Col xs>
<Field
component={TextArea}
fullWidth
label={<FormattedMessage id="stripes-acq-components.claiming.modal.sendClaim.field.externalNote" />}
name="externalNote"
parse={identity}
/>
</Col>
</Row>
</form>
</Modal>
);
};

SendClaimsModal.propTypes = {
claimsCount: PropTypes.number,
handleSubmit: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
open: PropTypes.bool,
message: PropTypes.node,
};

export default stripesFinalForm({
navigationCheck: true,
subscription: { values: true },
})(SendClaimsModal);
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { render, screen } from '@testing-library/react';
import user from '@testing-library/user-event';
import { MemoryRouter } from 'react-router-dom';

import { dayjs } from '@folio/stripes/components';

import SendClaimsModal from './SendClaimsModal';

const FORMAT = 'MM/DD/YYYY';
const today = dayjs();

const defaultProps = {
onCancel: jest.fn(),
onSubmit: jest.fn(),
open: true,
};

const renderSendClaimsModal = (props = {}) => render(
<SendClaimsModal
{...defaultProps}
{...props}
/>,
{ wrapper: MemoryRouter },
);

describe('SendClaimsModal', () => {
beforeEach(() => {
defaultProps.onCancel.mockClear();
defaultProps.onSubmit.mockClear();
});

it('should render send claim modal', () => {
renderSendClaimsModal();

expect(screen.getByText('ui-receiving.modal.sendClaim.heading')).toBeInTheDocument();
});

it('should validate "Claim expiry date" field', async () => {
renderSendClaimsModal();

const saveBtn = screen.getByRole('button', { name: 'stripes-acq-components.FormFooter.save' });

await user.click(saveBtn);
expect(screen.getByText('stripes-acq-components.validation.required')).toBeInTheDocument();

await user.type(screen.getByPlaceholderText(FORMAT), today.format(FORMAT));
await user.click(saveBtn);
expect(screen.getByText('ui-receiving.validation.dateAfter')).toBeInTheDocument();
});

it('should submit valid form', async () => {
renderSendClaimsModal();

const date = today.add(5, 'days');
const internalNote = 'Internal';
const externalNote = 'External';

await user.type(screen.getByPlaceholderText(FORMAT), date.format(FORMAT));
await user.type(screen.getByLabelText('ui-receiving.piece.internalNote'), internalNote);
await user.type(screen.getByLabelText('ui-receiving.piece.externalNote'), externalNote);
await user.click(screen.getByRole('button', { name: 'stripes-acq-components.FormFooter.save' }));

expect(defaultProps.onSubmit).toHaveBeenCalledWith(
{
claimingDate: date.format('YYYY-MM-DD'),
internalNote,
externalNote,
},
expect.anything(),
expect.anything(),
);
});

it('should call "onCancel" when the modal dismissed', async () => {
renderSendClaimsModal();

await user.click(screen.getByRole('button', { name: 'stripes-acq-components.FormFooter.cancel' }));

expect(defaultProps.onCancel).toHaveBeenCalled();
});
});
1 change: 1 addition & 0 deletions lib/claiming/components/modals/SendClaimsModal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as SendClaimsModal } from './SendClaimsModal';
2 changes: 2 additions & 0 deletions lib/claiming/components/modals/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { DelayClaimsModal } from './DelayClaimsModal';
export { SendClaimsModal } from './SendClaimsModal';
1 change: 1 addition & 0 deletions lib/claiming/hooks/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { useClaimsDelay } from './useClaimsDelay';
export { useClaimsSend } from './useClaimsSend';
1 change: 1 addition & 0 deletions lib/claiming/hooks/useClaimsDelay/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useClaimsDelay } from './useClaimsDelay';
26 changes: 26 additions & 0 deletions lib/claiming/hooks/useClaimsDelay/useClaimsDelay.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useCallback } from 'react';

import { PIECE_STATUS } from '../../../constants';
import { usePiecesStatusBatchUpdate } from '../../../hooks';

export const useClaimsDelay = () => {
const {
isLoading,
updatePiecesStatus,
} = usePiecesStatusBatchUpdate();

const delayClaims = useCallback(({ claimingInterval, pieceIds }) => {
return updatePiecesStatus({
data: {
claimingInterval,
pieceIds,
receivingStatus: PIECE_STATUS.claimDelayed,
},
});
}, [updatePiecesStatus]);

return {
isLoading,
delayClaims,
};
};
2 changes: 1 addition & 1 deletion lib/claiming/hooks/useClaimsSend/useClaimsSend.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const useClaimsSend = () => {
const ky = useOkapiKy();

const mutationFn = useCallback(({ data }) => {
return ky.post(SEND_CLAIMS_API, { json: data });
return ky.post(SEND_CLAIMS_API, { json: data }).json();
}, [ky]);

const {
Expand Down
1 change: 1 addition & 0 deletions lib/claiming/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './components';
export * from './hooks';
export * from './utils';
7 changes: 7 additions & 0 deletions lib/claiming/utils/getClaimingIntervalFromDate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { dayjs } from '@folio/stripes/components';

export const getClaimingIntervalFromDate = (date) => {
const currentDay = dayjs().startOf('day');

return dayjs(date).diff(currentDay, 'days');
};
12 changes: 12 additions & 0 deletions lib/claiming/utils/getClaimingIntervalFromDate.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { dayjs } from '@folio/stripes/components';

import { getClaimingIntervalFromDate } from './getClaimingIntervalFromDate';

describe('getClaimingIntervalFromDate', () => {
it('should return claiming interval calculated based on provided date', () => {
const today = dayjs().startOf('day');

expect(getClaimingIntervalFromDate(today)).toEqual(0);
expect(getClaimingIntervalFromDate(today.add(5, 'days'))).toEqual(5);
});
});
1 change: 1 addition & 0 deletions lib/claiming/utils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { getClaimingIntervalFromDate } from './getClaimingIntervalFromDate';
Loading

0 comments on commit e06c4c3

Please sign in to comment.