diff --git a/CHANGELOG.md b/CHANGELOG.md index 1646c31..4685bc5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 1.1.0 (IN PROGRESS) * Update github actions. Refs UIREQMED-14. +* Add landing page actions: Confirm item arrival, Mediated requests activities and Send item in transit. Refs UIREQMED-2. ## 1.0.0 - * New app created with stripes-cli. Updated module after created with stripes-cli. Refs UIREQMED-1. diff --git a/README.md b/README.md index 4c7b2b3..2a743e3 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,6 @@ Copyright (C) 2023 The Open Library Foundation This software is distributed under the terms of the Apache License, Version 2.0. See the file "[LICENSE](LICENSE)" for more information. -## Introduction - -Congratulations on creating a new Stripes UI app module! Follow the instructions below to run ui-requests-mediated and start your development. - -TODO: Modify this README to replace these sections about getting started. - -## Prerequisites - -In order to view and log into the platform being served up, a suitable Okapi backend will need to be running. The [testing-backend](https://app.vagrantup.com/folio/boxes/testing-backend) Vagrant box should work if your app does not yet have its own backend module. - ## Run your new app Run the following from the ui-requests-mediated directory to serve your new app using a development server: @@ -35,18 +25,19 @@ stripes serve --okapi http://my-okapi.example.com:9130 --tenant my-tenant-id Run the included UI tests with the following command: ``` -stripes test karma +yarn run test:jest" ``` -## What to do next? - -Now that your new app is running, search the code for "`new-app`" to find comments and subbed placeholders that may need your attention. +## Introduction -Please remove or customize the sample strings in `en.json` (lines 3-10) before merging this file to master; the translators do not need to be providing translations for these sample strings. +This is a [Stripes](https://github.com/folio-org/stripes-core/) UI module +for making requests on items. -Read the [Stripes Module Developer's Guide](https://github.com/folio-org/stripes/blob/master/doc/dev-guide.md). +## Additional information -When your new UI app is ready and being built by CI, then adjust its Jenkinsfile to remove the `npmDeploy = 'no'` parameter (which is then superfluous). +Other [modules](https://dev.folio.org/source-code/#client-side). -TODO: Modify this README to replace these sections about getting started, link to your issue tracker, etc. +See project [UIREQMED](https://issues.folio.org/browse/UIREQMED) +at the [FOLIO issue tracker](https://dev.folio.org/guidelines/issue-tracker). +Other FOLIO Developer documentation is at [dev.folio.org](https://dev.folio.org/) diff --git a/package.json b/package.json index 9fb11aa..57cebc3 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,39 @@ "settings.enabled" ], "visible": true + }, + { + "permissionName": "ui-requests-mediated.view", + "displayName": "Mediated requests: View", + "subPermissions": [ + "module.requests-mediated.enabled", + "settings.requests-mediated.enabled" + ], + "visible": true + }, + { + "permissionName": "ui-requests-mediated.view-create", + "displayName": "Mediated requests: View, create", + "subPermissions": [ + "ui-requests-mediated.view" + ], + "visible": true + }, + { + "permissionName": "ui-requests-mediated.view-edit-cancel", + "displayName": "Mediated requests: View, edit, cancel", + "subPermissions": [ + "ui-requests-mediated.view-create" + ], + "visible": true + }, + { + "permissionName": "ui-requests-mediated.all", + "displayName": "Mediated requests: All permissions", + "subPermissions": [ + "ui-requests-mediated.view-edit-cancel" + ], + "visible": true } ] } diff --git a/src/components/ConfirmItemArrival/ConfirmItemArrival.js b/src/components/ConfirmItemArrival/ConfirmItemArrival.js new file mode 100644 index 0000000..2c04838 --- /dev/null +++ b/src/components/ConfirmItemArrival/ConfirmItemArrival.js @@ -0,0 +1,33 @@ +import { FormattedMessage } from 'react-intl'; + +import { + Pane, + Paneset, +} from '@folio/stripes/components'; + +import NavigationMenu from '../NavigationMenu'; + +import { + FILTER_PANE_WIDTH, + getConfirmItemArrivalUrl, +} from '../../constants'; + +const ConfirmItemArrival = () => { + return ( + + } + > + + + } + /> + + ); +}; + +export default ConfirmItemArrival; diff --git a/src/components/ConfirmItemArrival/ConfirmItemArrival.test.js b/src/components/ConfirmItemArrival/ConfirmItemArrival.test.js new file mode 100644 index 0000000..fab0145 --- /dev/null +++ b/src/components/ConfirmItemArrival/ConfirmItemArrival.test.js @@ -0,0 +1,43 @@ +import { + render, + screen, +} from '@folio/jest-config-stripes/testing-library/react'; + +import ConfirmItemArrival from './ConfirmItemArrival'; +import NavigationMenu from '../NavigationMenu'; + +import { getConfirmItemArrivalUrl } from '../../constants'; + +jest.mock('../NavigationMenu', () => jest.fn((props) => (
))); + +const testIds = { + confirmItemArrivalPaneSet: 'confirmItemArrivalPaneSet', + confirmItemArrivalPane: 'confirmItemArrivalPane', +}; +const labelIds = { + paneTitle: 'ui-requests-mediated.app.confirmItemArrival.paneTitle', +}; + +describe('ConfirmItemArrival', () => { + beforeEach(() => { + render(); + }); + + it('should render pane set', () => { + expect(screen.getByTestId(testIds.confirmItemArrivalPaneSet)).toBeInTheDocument(); + }); + + it('should render pane', () => { + expect(screen.getByTestId(testIds.confirmItemArrivalPane)).toBeInTheDocument(); + }); + + it('should render pane title', () => { + expect(screen.getByText(labelIds.paneTitle)).toBeVisible(); + }); + + it('should trigger NavigationMenu with correct props', () => { + expect(NavigationMenu).toHaveBeenCalledWith(expect.objectContaining({ + value: getConfirmItemArrivalUrl(), + }), {}); + }); +}); diff --git a/src/components/ConfirmItemArrival/index.js b/src/components/ConfirmItemArrival/index.js new file mode 100644 index 0000000..e44e27e --- /dev/null +++ b/src/components/ConfirmItemArrival/index.js @@ -0,0 +1 @@ +export { default } from './ConfirmItemArrival'; diff --git a/src/components/MediatedRequestsActivities/MediatedRequestsActivities.js b/src/components/MediatedRequestsActivities/MediatedRequestsActivities.js new file mode 100644 index 0000000..3b734b0 --- /dev/null +++ b/src/components/MediatedRequestsActivities/MediatedRequestsActivities.js @@ -0,0 +1,37 @@ +import { FormattedMessage } from 'react-intl'; + +import { AppIcon } from '@folio/stripes/core'; + +import { + Pane, + Paneset, +} from '@folio/stripes/components'; + +import NavigationMenu from '../NavigationMenu'; + +import { + APP_ICON_NAME, + FILTER_PANE_WIDTH, + getMediatedRequestsActivitiesUrl, +} from '../../constants'; + +const MediatedRequestsActivities = () => { + return ( + + } + > + + + } + paneTitle={} + /> + + ); +}; + +export default MediatedRequestsActivities; diff --git a/src/components/MediatedRequestsActivities/MediatedRequestsActivities.test.js b/src/components/MediatedRequestsActivities/MediatedRequestsActivities.test.js new file mode 100644 index 0000000..e36994d --- /dev/null +++ b/src/components/MediatedRequestsActivities/MediatedRequestsActivities.test.js @@ -0,0 +1,43 @@ +import { + render, + screen, +} from '@folio/jest-config-stripes/testing-library/react'; + +import MediatedRequestsActivities from './MediatedRequestsActivities'; +import NavigationMenu from '../NavigationMenu'; + +import { getMediatedRequestsActivitiesUrl } from '../../constants'; + +jest.mock('../NavigationMenu', () => jest.fn((props) => (
))); + +const testIds = { + mediatedRequestsActivitiesPaneSet: 'mediatedRequestsActivitiesPaneSet', + mediatedRequestsActivitiesPane: 'mediatedRequestsActivitiesPane', +}; +const labelIds = { + paneTitle: 'ui-requests-mediated.app.mediatedRequestsActivities.paneTitle', +}; + +describe('MediatedRequestsActivities', () => { + beforeEach(() => { + render(); + }); + + it('should render pane set', () => { + expect(screen.getByTestId(testIds.mediatedRequestsActivitiesPaneSet)).toBeInTheDocument(); + }); + + it('should render pane', () => { + expect(screen.getByTestId(testIds.mediatedRequestsActivitiesPane)).toBeInTheDocument(); + }); + + it('should render pane title', () => { + expect(screen.getByText(labelIds.paneTitle)).toBeVisible(); + }); + + it('should trigger NavigationMenu with correct props', () => { + expect(NavigationMenu).toHaveBeenCalledWith(expect.objectContaining({ + value: getMediatedRequestsActivitiesUrl(), + }), {}); + }); +}); diff --git a/src/components/MediatedRequestsActivities/index.js b/src/components/MediatedRequestsActivities/index.js new file mode 100644 index 0000000..6e0b47e --- /dev/null +++ b/src/components/MediatedRequestsActivities/index.js @@ -0,0 +1 @@ +export { default } from './MediatedRequestsActivities'; diff --git a/src/components/NavigationMenu/NavigationMenu.js b/src/components/NavigationMenu/NavigationMenu.js new file mode 100644 index 0000000..bb6b89f --- /dev/null +++ b/src/components/NavigationMenu/NavigationMenu.js @@ -0,0 +1,68 @@ +import PropTypes from 'prop-types'; +import { useIntl } from 'react-intl'; +import { + useHistory, + useLocation, +} from 'react-router-dom'; + +import { Select } from '@folio/stripes/components'; + +import { + getConfirmItemArrivalUrl, + getMediatedRequestsActivitiesUrl, + getSendItemInTransitUrl, +} from '../../constants'; + +export const getDataOptions = (intl) => ([ + { + label: intl.formatMessage({ id: 'ui-requests-mediated.app.mediatedRequestsActivities.navigation' }), + value: getMediatedRequestsActivitiesUrl(), + }, + { + label: intl.formatMessage({ id: 'ui-requests-mediated.app.confirmItemArrival.navigation' }), + value: getConfirmItemArrivalUrl(), + }, + { + label: intl.formatMessage({ id: 'ui-requests-mediated.app.sendItemInTransit.navigation' }), + value: getSendItemInTransitUrl(), + }, +]); + +export const handleChangeMenu = (event, location, history) => { + const pathname = event.target.value; + const destination = { + pathname, + state: location.state, + }; + + if (pathname === getMediatedRequestsActivitiesUrl()) { + destination.search = location.state; + } else { + destination.state = location.search; + } + + history.push(destination); +}; + +const NavigationMenu = ({ + value, +}) => { + const intl = useIntl(); + const history = useHistory(); + const location = useLocation(); + + return ( + - {dataOptions.forEach((option, i) => ( - ))} - - {children} -
- )), + Select: jest.fn(({ + children, + 'data-testid': testId, + dataOptions, + }) => { + const selectTestId = testId || 'selectTestId'; + const selectOptionTestId = `${selectTestId}selectOption`; + + return ( +
+ + {children} +
+ ); + }), })); diff --git a/translations/ui-requests-mediated/en.json b/translations/ui-requests-mediated/en.json index faebe7d..cfc6cc8 100644 --- a/translations/ui-requests-mediated/en.json +++ b/translations/ui-requests-mediated/en.json @@ -1,7 +1,20 @@ { "meta.title": "Mediated requests", - "app.index.paneTitle": "Mediated requests", + "permission.view": "Mediated requests: View", + "permission.view-create": "Mediated requests: View, create", + "permission.view-create-edit": "Mediated requests: View, edit, cancel", + "permission.all": "Mediated requests: All permissions", + + "app.filterPane.selectActivity": "Select activity", + + "app.confirmItemArrival.navigation": "Confirm item arrival", + "app.mediatedRequestsActivities.navigation": "Mediated requests activities", + "app.sendItemInTransit.navigation": "Send item in transit", + + "app.confirmItemArrival.paneTitle": "Confirm item arrival", + "app.mediatedRequestsActivities.paneTitle": "Mediated requests", + "app.sendItemInTransit.paneTitle": "Send item in transit", "settings.index.paneTitle": "Mediated requests", "settings.general": "General",