Skip to content
Open
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
302 changes: 156 additions & 146 deletions src/components/PatronRequests/PatronRequests.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
PaneMenu,
} from '@folio/stripes/components';
import { AppIcon, IfPermission, useOkapiKy } from '@folio/stripes/core';
import { SearchAndSortQuery, PersistedPaneset } from '@folio/stripes/smart-components';
import { SearchAndSortQuery, PersistedPaneset, ColumnManager } from '@folio/stripes/smart-components';
import { MenuSection } from '@folio/stripes/components';
import { useIntlCallout } from '@projectreshare/stripes-reshare';
import AppNameContext from '../../AppNameContext';
import Filters from './Filters';
Expand All @@ -27,12 +28,6 @@ import Search from './Search';
const appDetails = {
request: {
title: 'Requests',
visibleColumns: [
'flags', 'hrid',
'dateCreated', 'lastUpdated', 'selectedItemBarcode', 'patronIdentifier', 'state', 'serviceType',
'supplyingInstitutionSymbol', 'pickupLocation',
'title',
],
extraFilter: 'r.true',
intlId: 'supplier',
institutionFilterId: 'supplier',
Expand All @@ -41,12 +36,6 @@ const appDetails = {
},
supply: {
title: 'Supply',
visibleColumns: [
'flags', 'hrid',
'dateCreated', 'lastUpdated', 'state', 'serviceType',
'requestingInstitutionSymbol', 'selectedItemBarcode', 'pickLocation',
'pickShelvingLocation', 'title'
],
extraFilter: 'r.false',
intlId: 'requester',
institutionFilterId: 'requester',
Expand All @@ -55,6 +44,10 @@ const appDetails = {
},
};

const SUPPLY_VISIBLE_COLUMNS_STORAGE_KEY = 'supply-visible-columns';
const REQUEST_VISIBLE_COLUMNS_STORAGE_KEY = 'request-visible-columns';
const NON_TOGGLEABLE_COLUMNS = ['flags'];

const PatronRequests = ({ requestsQuery, queryGetter, querySetter, filterOptions, searchParams, children }) => {
const appName = useContext(AppNameContext);
const sendCallout = useIntlCallout();
Expand Down Expand Up @@ -92,22 +85,47 @@ const PatronRequests = ({ requestsQuery, queryGetter, querySetter, filterOptions
});
};

const getActionMenu = () => (
<FormattedMessage id="ui-rs.printAllPullSlips">
{ariaLabel => (
<Button
id="clickable-print-pull-slips"
aria-label={ariaLabel[0]}
buttonStyle="dropdownItem"
onClick={onPrintAll}
>
<Icon icon="print"><FormattedMessage id="ui-rs.printPullSlips" /></Icon>
</Button>
)}
</FormattedMessage>
const getActionMenu = renderColumnsMenu => () => (
<>
<MenuSection label={
<FormattedMessage id="ui-rs.printAllPullSlips">
{ariaLabel => (
<Button
id="clickable-print-pull-slips"
aria-label={ariaLabel[0]}
buttonStyle="dropdownItem"
onClick={onPrintAll}
>
<Icon icon="print"><FormattedMessage id="ui-rs.printPullSlips" /></Icon>
</Button>
)}
</FormattedMessage>} id="columns-menu-section">
</MenuSection>
{renderColumnsMenu}
</>
);

const { title, visibleColumns, createPerm } = appDetails[appName];
const getColumnMapping = () => {
return {
flags: '',
hrid: <FormattedMessage id="ui-rs.patronrequests.id" />,
isRequester: <FormattedMessage id="ui-rs.patronrequests.isRequester" />,
dateCreated: <FormattedMessage id="ui-rs.patronrequests.dateCreated" />,
lastUpdated: <FormattedMessage id="ui-rs.patronrequests.lastUpdated" />,
title: <FormattedMessage id="ui-rs.patronrequests.title" />,
patronIdentifier: <FormattedMessage id="ui-rs.patronrequests.patronIdentifier" />,
state: <FormattedMessage id="ui-rs.patronrequests.state" />,
serviceType: <FormattedMessage id="ui-rs.patronrequests.serviceType" />,
requestingInstitutionSymbol: <FormattedMessage id="ui-rs.patronrequests.requestingInstitutionSymbol" />,
supplyingInstitutionSymbol: <FormattedMessage id="ui-rs.patronrequests.supplyingInstitutionSymbol" />,
selectedItemBarcode: <FormattedMessage id="ui-rs.patronrequests.selectedItemBarcode" />,
pickLocation: <FormattedMessage id="ui-rs.patronrequests.pickLocation" />,
pickShelvingLocation: <FormattedMessage id="ui-rs.patronrequests.pickShelvingLocation" />,
pickupLocation: <FormattedMessage id="ui-rs.patronrequests.pickupLocation" />,
};
}

const { title, createPerm } = appDetails[appName];

return (
<SearchAndSortQuery
Expand Down Expand Up @@ -157,125 +175,117 @@ const PatronRequests = ({ requestsQuery, queryGetter, querySetter, filterOptions
</form>
</Pane>
{requestsQuery.isSuccess ?
<Pane
actionMenu={getActionMenu}
appIcon={<AppIcon app={appName} iconKey="app" size="small" />}
defaultWidth="fill"
lastMenu={(
<PaneMenu>
{(appName === 'request') &&
<IfPermission perm={createPerm}>
<Button
buttonStyle="primary"
id="clickable-new-patron-request"
marginBottom0
to={`requests/create${location.search}`}
>
<FormattedMessage id="ui-rs.createPatronRequest" />
</Button>
</IfPermission>
}
</PaneMenu>
)}
noOverflow
padContent={false}
paneSub={requestsQuery?.isSuccess ?
<FormattedMessage
id="ui-rs.patronrequests.found"
values={{ number: totalCount }}
/> : ''}
paneTitle={title}
>
<MultiColumnList
autosize
columnMapping={{
flags: '',
hrid: <FormattedMessage id="ui-rs.patronrequests.id" />,
isRequester: <FormattedMessage id="ui-rs.patronrequests.isRequester" />,
dateCreated: <FormattedMessage id="ui-rs.patronrequests.dateCreated" />,
lastUpdated: <FormattedMessage id="ui-rs.patronrequests.lastUpdated" />,
title: <FormattedMessage id="ui-rs.patronrequests.title" />,
patronIdentifier: <FormattedMessage id="ui-rs.patronrequests.patronIdentifier" />,
state: <FormattedMessage id="ui-rs.patronrequests.state" />,
serviceType: <FormattedMessage id="ui-rs.patronrequests.serviceType" />,
requestingInstitutionSymbol: <FormattedMessage id="ui-rs.patronrequests.requestingInstitutionSymbol" />,
supplyingInstitutionSymbol: <FormattedMessage id="ui-rs.patronrequests.supplyingInstitutionSymbol" />,
selectedItemBarcode: <FormattedMessage id="ui-rs.patronrequests.selectedItemBarcode" />,
pickLocation: <FormattedMessage id="ui-rs.patronrequests.pickLocation" />,
pickShelvingLocation: <FormattedMessage id="ui-rs.patronrequests.pickShelvingLocation" />,
pickupLocation: <FormattedMessage id="ui-rs.patronrequests.pickupLocation" />,
}}
columnWidths={{
flags: '48px',
id: { max: 115 },
dateCreated: '96px',
state: { min: 84 },
serviceType: { max: 80 },
selectedItemBarcode: '130px',
}}
contentData={requests}
formatter={{
flags: a => {
const needsAttention = a?.state?.needsAttention;
if (a?.unreadMessageCount > 0) {
if (needsAttention) {
return (
<Badge
color="red"
aria-label={intl.formatMessage({ id: 'ui-rs.needsAttention' }) + intl.formatMessage({ id: 'ui-rs.unread' })}
>
{`${a.unreadMessageCount}!`}
</Badge>
);
}
return <Badge color="primary" aria-label={intl.formatMessage({ id: 'ui-rs.unread' })}>{a.unreadMessageCount}</Badge>;
} else if (needsAttention) return <Badge color="red" aria-label={intl.formatMessage({ id: 'ui-rs.needsAttention' })}>!</Badge>;
return '';
},
isRequester: a => (a.isRequester === true ? '✓' : a.isRequester === false ? '✗' : ''),
dateCreated: a => (new Date(a.dateCreated).toLocaleDateString() === new Date().toLocaleDateString()
? <FormattedTime value={a.dateCreated} />
: <FormattedDate value={a.dateCreated} />),
lastUpdated: a => (new Date(a.lastUpdated).toLocaleDateString() === new Date().toLocaleDateString()
? <FormattedTime value={a.lastUpdated} />
: <FormattedDate value={a.lastUpdated} />),
patronIdentifier: a => {
const { patronGivenName, patronSurname } = a;
if (patronGivenName && patronSurname) return `${patronSurname}, ${patronGivenName}`;
if (patronSurname) return patronSurname;
if (patronGivenName) return patronGivenName;
return a.patronIdentifier;
},
state: a => <FormattedMessage id={`stripes-reshare.states.${a.state?.code}`} />,
serviceType: a => a.serviceType && a.serviceType.value,
supplyingInstitutionSymbol: a => (a?.resolvedSupplier?.owner?.symbolSummary ?? '').replace(/,.*/, ''),
pickLocation: a => a.pickLocation && a.pickLocation.name,
pickShelvingLocation: a => a.pickShelvingLocation && a.pickShelvingLocation.name,
selectedItemBarcode: a => (a.volumes?.length <= 1 ? (a.volumes[0]?.itemId || a.selectedItemBarcode) : <FormattedMessage id="ui-rs.flow.info.itemBarcode.multiVolRequest" />)
}}
hasMargin
isEmptyMessage={
<>
<FormattedMessage id="ui-rs.patronrequests.notFound" /><br />
{location?.search?.includes('filter') &&
<Link to={queryString.exclude(`${location.pathname}${location.search}`, ['filters'])}>
<FormattedMessage id="ui-rs.patronrequests.withoutFilter" />
</Link>
}
</>
}
key={requestsQuery?.dataUpdatedAt}
loading={requestsQuery?.isFetching}
onHeaderClick={onSort}
onNeedMoreData={fetchMore}
onRowClick={(_e, rowData) => history.push(`${match.url}/view/${rowData.id}${location.search}`)}
sortOrder={sortOrder.replace(/^-/, '').replace(/,.*/, '')}
sortDirection={sortOrder.startsWith('-') ? 'descending' : 'ascending'}
totalCount={totalCount}
virtualize
visibleColumns={visibleColumns}
/>
</Pane>
<ColumnManager
id={appName === 'request' ? REQUEST_VISIBLE_COLUMNS_STORAGE_KEY : SUPPLY_VISIBLE_COLUMNS_STORAGE_KEY}
columnMapping={getColumnMapping()}
excludeKeys={NON_TOGGLEABLE_COLUMNS}
>
{({ renderColumnsMenu, visibleColumns }) => (
<Pane
actionMenu={getActionMenu(renderColumnsMenu)}
appIcon={<AppIcon app={appName} iconKey="app" size="small" />}
defaultWidth="fill"
lastMenu={(
<PaneMenu>
{(appName === 'request') &&
<IfPermission perm={createPerm}>
<Button
buttonStyle="primary"
id="clickable-new-patron-request"
marginBottom0
to={`requests/create${location.search}`}
>
<FormattedMessage id="ui-rs.createPatronRequest" />
</Button>
</IfPermission>
}
</PaneMenu>
)}
noOverflow
padContent={false}
paneSub={requestsQuery?.isSuccess ?
<FormattedMessage
id="ui-rs.patronrequests.found"
values={{ number: totalCount }}
/> : ''}
paneTitle={title}
>
<MultiColumnList
autosize
columnMapping={getColumnMapping()}
columnWidths={{
flags: '48px',
id: { max: 115 },
dateCreated: '96px',
state: { min: 84 },
serviceType: { max: 80 },
selectedItemBarcode: '130px',
}}
contentData={requests}
formatter={{
flags: a => {
const needsAttention = a?.state?.needsAttention;
if (a?.unreadMessageCount > 0) {
if (needsAttention) {
return (
<Badge
color="red"
aria-label={intl.formatMessage({ id: 'ui-rs.needsAttention' }) + intl.formatMessage({ id: 'ui-rs.unread' })}
>
{`${a.unreadMessageCount}!`}
</Badge>
);
}
return <Badge color="primary" aria-label={intl.formatMessage({ id: 'ui-rs.unread' })}>{a.unreadMessageCount}</Badge>;
} else if (needsAttention) return <Badge color="red" aria-label={intl.formatMessage({ id: 'ui-rs.needsAttention' })}>!</Badge>;
return '';
},
isRequester: a => (a.isRequester === true ? '✓' : a.isRequester === false ? '✗' : ''),
dateCreated: a => (new Date(a.dateCreated).toLocaleDateString() === new Date().toLocaleDateString()
? <FormattedTime value={a.dateCreated} />
: <FormattedDate value={a.dateCreated} />),
lastUpdated: a => (new Date(a.lastUpdated).toLocaleDateString() === new Date().toLocaleDateString()
? <FormattedTime value={a.lastUpdated} />
: <FormattedDate value={a.lastUpdated} />),
patronIdentifier: a => {
const { patronGivenName, patronSurname } = a;
if (patronGivenName && patronSurname) return `${patronSurname}, ${patronGivenName}`;
if (patronSurname) return patronSurname;
if (patronGivenName) return patronGivenName;
return a.patronIdentifier;
},
state: a => <FormattedMessage id={`stripes-reshare.states.${a.state?.code}`} />,
serviceType: a => a.serviceType && a.serviceType.value,
supplyingInstitutionSymbol: a => (a?.resolvedSupplier?.owner?.symbolSummary ?? '').replace(/,.*/, ''),
pickLocation: a => a.pickLocation && a.pickLocation.name,
pickShelvingLocation: a => a.pickShelvingLocation && a.pickShelvingLocation.name,
selectedItemBarcode: a => (a.volumes?.length <= 1 ? (a.volumes[0]?.itemId || a.selectedItemBarcode) : <FormattedMessage id="ui-rs.flow.info.itemBarcode.multiVolRequest" />)
}}
hasMargin
isEmptyMessage={
<>
<FormattedMessage id="ui-rs.patronrequests.notFound" /><br />
{location?.search?.includes('filter') &&
<Link to={queryString.exclude(`${location.pathname}${location.search}`, ['filters'])}>
<FormattedMessage id="ui-rs.patronrequests.withoutFilter" />
</Link>
}
</>
}
key={requestsQuery?.dataUpdatedAt}
loading={requestsQuery?.isFetching}
onHeaderClick={onSort}
onNeedMoreData={fetchMore}
onRowClick={(_e, rowData) => history.push(`${match.url}/view/${rowData.id}${location.search}`)}
sortOrder={sortOrder.replace(/^-/, '').replace(/,.*/, '')}
sortDirection={sortOrder.startsWith('-') ? 'descending' : 'ascending'}
totalCount={totalCount}
virtualize
visibleColumns={visibleColumns}
/>
</Pane>
)}
</ColumnManager>
: <LoadingPane />
}
{children}
Expand Down