@inveniosoftware/react-invenio-app-ils 2.0.2 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/index.js CHANGED
@@ -4359,6 +4359,14 @@ const prettyPrintBooleanValue = value => {
4359
4359
  const screenIsWiderThan = pixels => {
4360
4360
  return window.matchMedia(`(max-width: ${pixels}px)`).matches ? false : true;
4361
4361
  };
4362
+ const isPrivilegedUser = () => {
4363
+ const roles = _get__default["default"](sessionManager, 'user.roles', []);
4364
+ return roles.includes('admin') || roles.includes('librarian');
4365
+ };
4366
+ const isDocumentOverbooked = async documentPid => {
4367
+ const response = await documentApi.get(documentPid);
4368
+ return _get__default["default"](response, 'data.metadata.circulation.overbooked', false);
4369
+ };
4362
4370
 
4363
4371
  class MetadataTable extends React.Component {
4364
4372
  renderRows() {
@@ -29547,19 +29555,108 @@ const mapDispatchToProps$v = dispatch => ({
29547
29555
  });
29548
29556
  const LocationList = reactRedux.connect(mapStateToProps$G, mapDispatchToProps$v)(LocationList$1);
29549
29557
 
29558
+ const OverbookedConfirmModal = _ref => {
29559
+ let {
29560
+ open,
29561
+ onClose,
29562
+ onConfirm,
29563
+ overbookedDocuments
29564
+ } = _ref;
29565
+ const isMultiple = overbookedDocuments.length > 1;
29566
+ return /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Modal, {
29567
+ size: "small",
29568
+ open: open,
29569
+ onClose: onClose
29570
+ }, /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Modal.Header, null, "Item in high demand!"), /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Modal.Content, null, overbookedDocuments.map((doc, index) => /*#__PURE__*/React__default["default"].createElement("p", {
29571
+ key: doc.loanRequestId || doc.title || index
29572
+ }, "There is another patron waiting for \"", /*#__PURE__*/React__default["default"].createElement("strong", null, doc.title), "\"", ' ', doc.loanRequestId && /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, "(", /*#__PURE__*/React__default["default"].createElement("a", {
29573
+ href: `/backoffice/loans/${doc.loanRequestId}`
29574
+ }, "See loan request"), ")"), ".")), /*#__PURE__*/React__default["default"].createElement("p", null, /*#__PURE__*/React__default["default"].createElement("strong", null, "Do you still want to extend your ", isMultiple ? 'loans' : 'loan', "?"))), /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Modal.Actions, null, /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Button, {
29575
+ secondary: true,
29576
+ onClick: onClose
29577
+ }, "Cancel"), /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Button, {
29578
+ primary: true,
29579
+ onClick: onConfirm
29580
+ }, "Extend")));
29581
+ };
29582
+
29550
29583
  class PatronBulkExtendLoans$1 extends React.Component {
29551
29584
  constructor() {
29552
29585
  super(...arguments);
29553
29586
  this.state = {
29554
- open: false
29587
+ open: false,
29588
+ showOverbookedConfirm: false,
29589
+ overbookedDocuments: [],
29590
+ isChecking: false
29591
+ };
29592
+ this.open = async () => {
29593
+ this.setState({
29594
+ open: true
29595
+ });
29596
+ if (!isPrivilegedUser()) return;
29597
+ this.setState({
29598
+ isChecking: true
29599
+ });
29600
+ try {
29601
+ const {
29602
+ patronPid
29603
+ } = this.props;
29604
+ // Get all active loans for the patron
29605
+ const query = loanApi.query().withPatronPid(patronPid).withState(invenioConfig.CIRCULATION.loanActiveStates).withSize(invenioConfig.APP.PATRON_PROFILE_MAX_RESULTS_SIZE).sortByNewest().qs();
29606
+ const response = await loanApi.list(query);
29607
+ const loans = response.data.hits;
29608
+ const checks = loans.map(async loan => {
29609
+ const documentPid = _get__default["default"](loan, 'metadata.document.pid');
29610
+ const isOverbooked = await isDocumentOverbooked(documentPid);
29611
+ if (isOverbooked) {
29612
+ return {
29613
+ title: loan.metadata.document.title,
29614
+ loanRequestId: loan.id
29615
+ };
29616
+ }
29617
+ return null;
29618
+ });
29619
+ const results = await Promise.all(checks);
29620
+ const overbookedDocuments = results.filter(Boolean);
29621
+ this.setState({
29622
+ overbookedDocuments,
29623
+ isChecking: false
29624
+ });
29625
+ } catch (error) {
29626
+ console.error('Failed to fetch overbooked documents', error);
29627
+ this.setState({
29628
+ isChecking: false
29629
+ });
29630
+ }
29631
+ };
29632
+ this.close = () => {
29633
+ this.setState({
29634
+ open: false,
29635
+ showOverbookedConfirm: false,
29636
+ overbookedDocuments: []
29637
+ });
29555
29638
  };
29556
- this.open = () => this.setState({
29557
- open: true
29558
- });
29559
- this.close = () => this.setState({
29560
- open: false
29561
- });
29562
29639
  this.handleSubmitExtend = () => {
29640
+ const {
29641
+ bulkLoanExtension,
29642
+ patronPid
29643
+ } = this.props;
29644
+ const {
29645
+ overbookedDocuments
29646
+ } = this.state;
29647
+
29648
+ // If the user is privileged and there are overbooked docs
29649
+ if (isPrivilegedUser() && overbookedDocuments.length > 0) {
29650
+ this.setState({
29651
+ showOverbookedConfirm: true
29652
+ });
29653
+ return;
29654
+ }
29655
+ // Otherwise extend directly
29656
+ bulkLoanExtension(patronPid);
29657
+ this.close();
29658
+ };
29659
+ this.confirmBulkExtension = () => {
29563
29660
  const {
29564
29661
  bulkLoanExtension,
29565
29662
  patronPid
@@ -29570,16 +29667,26 @@ class PatronBulkExtendLoans$1 extends React.Component {
29570
29667
  }
29571
29668
  render() {
29572
29669
  const {
29573
- patronPid,
29574
- bulkLoanExtension,
29575
29670
  isLoading,
29576
29671
  disabled,
29672
+ patronPid,
29673
+ bulkLoanExtension,
29577
29674
  ...uiProps
29578
29675
  } = this.props;
29579
29676
  const {
29580
- open
29677
+ open,
29678
+ showOverbookedConfirm,
29679
+ overbookedDocuments,
29680
+ isChecking
29581
29681
  } = this.state;
29582
- return /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Modal, {
29682
+ return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, /*#__PURE__*/React__default["default"].createElement(OverbookedConfirmModal, {
29683
+ open: showOverbookedConfirm,
29684
+ onClose: () => this.setState({
29685
+ showOverbookedConfirm: false
29686
+ }),
29687
+ onConfirm: this.confirmBulkExtension,
29688
+ overbookedDocuments: overbookedDocuments
29689
+ }), /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Modal, {
29583
29690
  open: open,
29584
29691
  onClose: this.close,
29585
29692
  onOpen: this.open,
@@ -29599,8 +29706,9 @@ class PatronBulkExtendLoans$1 extends React.Component {
29599
29706
  onClick: this.close
29600
29707
  }, "Cancel"), /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Button, {
29601
29708
  onClick: this.handleSubmitExtend,
29602
- primary: true
29603
- }, "Extend the loans")));
29709
+ primary: true,
29710
+ loading: isChecking
29711
+ }, "Extend the loans"))));
29604
29712
  }
29605
29713
  }
29606
29714
  PatronBulkExtendLoans$1.defaultProps = {
@@ -38948,6 +39056,36 @@ class LoanExtendButton extends React.Component {
38948
39056
  constructor(props) {
38949
39057
  super(props);
38950
39058
  this.triggerExtension = async () => {
39059
+ const {
39060
+ loan,
39061
+ onError
39062
+ } = this.props;
39063
+ const isUserPrivileged = isPrivilegedUser();
39064
+ if (isUserPrivileged) {
39065
+ this.setState({
39066
+ isLoading: true
39067
+ });
39068
+ try {
39069
+ const documentPid = _get__default["default"](loan, 'metadata.document.pid');
39070
+ const isOverbooked = await isDocumentOverbooked(documentPid);
39071
+ if (isOverbooked) {
39072
+ this.setState({
39073
+ isLoading: false,
39074
+ showOverbookedConfirm: true
39075
+ });
39076
+ return;
39077
+ }
39078
+ } catch (error) {
39079
+ onError('Something went wrong while checking if the literature is overbooked.', error);
39080
+ this.setState({
39081
+ isLoading: false
39082
+ });
39083
+ return;
39084
+ }
39085
+ }
39086
+ await this.performExtension();
39087
+ };
39088
+ this.performExtension = async () => {
38951
39089
  const {
38952
39090
  loan,
38953
39091
  onSuccess,
@@ -38965,7 +39103,8 @@ class LoanExtendButton extends React.Component {
38965
39103
  this.cancellableExtendLoan = withCancel(this.extendLoan(extendUrl, document.pid, patronPid));
38966
39104
  const response = await this.cancellableExtendLoan.promise;
38967
39105
  this.setState({
38968
- isLoading: false
39106
+ isLoading: false,
39107
+ showOverbookedConfirm: false
38969
39108
  });
38970
39109
  const documentTitle = document.title;
38971
39110
  onSuccess(INFO_MESSAGES.SUCCESS(documentTitle, luxon.DateTime.fromISO(response.data.metadata.end_date)));
@@ -38976,6 +39115,11 @@ class LoanExtendButton extends React.Component {
38976
39115
  onError(error.response.data.message);
38977
39116
  }
38978
39117
  };
39118
+ this.hideOverbookedConfirm = () => {
39119
+ this.setState({
39120
+ showOverbookedConfirm: false
39121
+ });
39122
+ };
38979
39123
  this.validate = loan => {
38980
39124
  const hasExtendAction = _has__default["default"](loan, 'availableActions.extend');
38981
39125
  if (!hasExtendAction) return {
@@ -39003,7 +39147,8 @@ class LoanExtendButton extends React.Component {
39003
39147
  };
39004
39148
  };
39005
39149
  this.state = {
39006
- isLoading: false
39150
+ isLoading: false,
39151
+ showOverbookedConfirm: false
39007
39152
  };
39008
39153
  }
39009
39154
  componentWillUnmount() {
@@ -39022,11 +39167,21 @@ class LoanExtendButton extends React.Component {
39022
39167
  loan
39023
39168
  } = this.props;
39024
39169
  const {
39025
- isLoading
39170
+ isLoading,
39171
+ showOverbookedConfirm
39026
39172
  } = this.state;
39027
39173
  const validation = this.validate(loan);
39028
39174
  const isDisabled = !validation.isValid;
39029
- return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, isDisabled && /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Popup, {
39175
+ const overbookedDocuments = [{
39176
+ title: _get__default["default"](loan, 'metadata.document.title', 'Unknown title'),
39177
+ loanRequestId: loan.id
39178
+ }];
39179
+ return /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, showOverbookedConfirm && /*#__PURE__*/React__default["default"].createElement(OverbookedConfirmModal, {
39180
+ open: showOverbookedConfirm,
39181
+ onClose: this.hideOverbookedConfirm,
39182
+ onConfirm: this.performExtension,
39183
+ overbookedDocuments: overbookedDocuments
39184
+ }), isDisabled && /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Popup, {
39030
39185
  content: validation.msg,
39031
39186
  trigger: /*#__PURE__*/React__default["default"].createElement(semanticUiReact.Icon, {
39032
39187
  name: "info"