Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

self-checkout: make barcode always uppercase #646

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions src/lib/pages/frontsite/SelfCheckout/ManualCheckout.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class ManualCheckout extends React.Component {
super(props);

this.state = {
manualBarcode: null,
manualBarcode: '',
};
this.inputRef = React.createRef();
}
Expand All @@ -22,25 +22,29 @@ export class ManualCheckout extends React.Component {
}

render() {
const { show, onChange, label } = this.props;
const { show, onBarcodeInput, label } = this.props;
const { manualBarcode } = this.state;
if (show) {
return (
<Container className="pt-1 center">
<Message compact>
<Header className="pb-1" as="h5">
{label} Add the barcode manually:
{label} Insert the barcode manually:
</Header>
<Input
id="barcodeInput"
type="text"
placeholder="Barcode..."
className="pb-1"
ref={this.inputRef}
onChange={(e) => this.setState({ manualBarcode: e.target.value })}
value={manualBarcode}
onChange={(e) =>
this.setState({ manualBarcode: e.target.value?.toUpperCase() })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automatic uppercase on typing

}
/>
<Button
onClick={() => onChange(manualBarcode)}
onClick={() => manualBarcode && onBarcodeInput(manualBarcode)}
disabled={!manualBarcode}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disable the btn if no barcode inserted

className="ml-10"
type="submit"
>
Expand All @@ -57,13 +61,13 @@ export class ManualCheckout extends React.Component {

ManualCheckout.propTypes = {
show: PropTypes.bool,
onChange: PropTypes.func.isRequired,
onBarcodeInput: PropTypes.func.isRequired,
label: PropTypes.string,
autofocus: PropTypes.bool,
};

ManualCheckout.defaultProps = {
show: false,
label: 'Cant scan the barcode?',
label: "Can't scan the barcode?",
autofocus: false,
};
9 changes: 5 additions & 4 deletions src/lib/pages/frontsite/SelfCheckout/SelfCheckout.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class SelfCheckout extends React.Component {

isItemLoanable = (itemBarcode) => {
const { user, item, notifyResultMessage } = this.props;
var resultMessage = `Book with barcode: ${itemBarcode} doesn't exist.`;
var resultMessage = `Book with barcode ${itemBarcode} not found.`;

if (!_isEmpty(item)) {
if (this.itemStatus(item).canCirculate()) {
Expand Down Expand Up @@ -147,11 +147,12 @@ class SelfCheckout extends React.Component {
<Header as="h1">SELF-CHECKOUT</Header>
<Container>
<BarcodeScanner onBarcodeDetected={this.onBarcodeDetected} />
<ManualCheckout show onChange={this.onBarcodeDetected} />
<ManualCheckout show onBarcodeInput={this.onBarcodeDetected} />
<Message warning compact>
If your browser isn't able to scan the barcode, try
Barcode not detected while scanning?
<br />
using another browser. (Recommended: Chrome)
Try using another browser. (Recommended:{' '}
<a href="https://www.google.com/chrome/">Google Chrome</a>)
</Message>
</Container>
<SelfCheckoutModal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export default class SelfCheckoutModal extends React.Component {
label="Wrong book?"
autofocus
show
onChange={onBarcodeDetected}
onBarcodeInput={onBarcodeDetected}
/>
</Modal.Content>
<Modal.Actions>
Expand Down
12 changes: 7 additions & 5 deletions src/lib/pages/frontsite/SelfCheckout/state/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ export const notifyResultMessage = (message) => {
};

const searchItem = async (dispatch, term) => {
const response = await itemApi.list(itemApi.query().withBarcode(term).qs());
const upperCasedTerm = term.toUpperCase();
const response = await itemApi.list(
itemApi.query().withBarcode(upperCasedTerm).qs()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not be needed, but just in case....

);
const item = _first(response.data.hits) || null;

dispatch({
Expand Down Expand Up @@ -59,10 +62,9 @@ export const checkoutItem = (documentPid, itemPid, patronPid) => {
const { pid } = response.data.metadata;
const linkToLoan = (
<p>
The loan {pid} has been created by you!{' '}
<Link to={FrontSiteRoutes.patronProfile}>
You can now view the loan details.
</Link>
The loan {pid} has been created by you! You can view all your current
loans on your <Link to={FrontSiteRoutes.patronProfile}>profile</Link>{' '}
page.
</p>
);
dispatch(sendSuccessNotification('Success!', linkToLoan));
Expand Down
45 changes: 37 additions & 8 deletions src/lib/pages/frontsite/SelfCheckout/state/actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,30 @@ import { itemApi } from '@api/items';
const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);

const mockList = jest.fn();
itemApi.list = mockList;
const itemApiListMock = jest.fn();
itemApi.list = itemApiListMock;

const response = { data: {} };
const expectedPayload = null;
const lowerCasedBarcode = 'cm-145123';
const upperCasedBarcode = lowerCasedBarcode.toUpperCase();

const expectedPayload = { pid: 'item-pid', barcode: upperCasedBarcode };
const response = {
data: {
hits: [expectedPayload],
},
};

let store;
beforeEach(() => {
mockList.mockClear();
itemApiListMock.mockClear();

store = mockStore(initialState);
store.clearActions();
});

describe('SelfCheck Out test', () => {
it('should dispatch an action updating the payloadresult item', async () => {
mockList.mockResolvedValue(response);
it('should dispatch an action updating the payload result item', async () => {
itemApiListMock.mockResolvedValue(response);

const expectedAction1 = {
type: actions.SEARCH_IS_LOADING,
Expand All @@ -32,7 +39,29 @@ describe('SelfCheck Out test', () => {
type: actions.SEARCH_ITEM_SUCCESS,
payload: expectedPayload,
};
await store.dispatch(actions.selfCheckOutSearch('123'));
await store.dispatch(actions.selfCheckOutSearch(lowerCasedBarcode));
expect(store.getActions()[0]).toEqual(expectedAction1);
expect(store.getActions()[1]).toEqual(expectedAction2);
expect(itemApiListMock).toHaveBeenCalledWith(
itemApi.query().withBarcode(upperCasedBarcode).qs()
);
});

it('should dispatch an error action when the search fails', async () => {
const errorMsg = 'Error message';
itemApiListMock.mockImplementation(() => {
throw new Error(errorMsg);
});

const expectedAction1 = {
type: actions.SEARCH_IS_LOADING,
};
const expectedAction2 = {
type: actions.SEARCH_HAS_ERROR,
payload: new Error(errorMsg),
};

await store.dispatch(actions.selfCheckOutSearch('syntax error query'));
expect(store.getActions()[0]).toEqual(expectedAction1);
expect(store.getActions()[1]).toEqual(expectedAction2);
});
Expand Down
Loading