Skip to content

OBPIH-7186 Display lot numbers expiration date mismatch in modal#5575

Merged
alannadolny merged 5 commits intodevelopfrom
feature/OBPIH-7186
Oct 31, 2025
Merged

OBPIH-7186 Display lot numbers expiration date mismatch in modal#5575
alannadolny merged 5 commits intodevelopfrom
feature/OBPIH-7186

Conversation

@SebastianLib
Copy link
Collaborator

@SebastianLib SebastianLib commented Oct 28, 2025

✨ Description of Change

Link to GitHub issue or Jira ticket:
https://pihemr.atlassian.net/browse/OBPIH-7186

Description:
At this moment, in this PR I didn't add this functionality to the old inbound, because it will be replaced by the new inbound. Once this PR is merged, I will create a new ticket to add this functionality to the new inbound refactor as well.


📷 Screenshots & Recordings (optional)

image

@github-actions github-actions bot added type: feature A new piece of functionality for the app domain: frontend Changes or discussions relating to the frontend UI domain: l10n Changes or discussions relating to localization & Internationalization labels Oct 28, 2025
@codecov
Copy link

codecov bot commented Oct 28, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 8.50%. Comparing base (1bb7314) to head (158e6c8).
⚠️ Report is 170 commits behind head on develop.

Additional details and impacted files
@@             Coverage Diff              @@
##             develop   #5575      +/-   ##
============================================
- Coverage       9.12%   8.50%   -0.62%     
+ Complexity      1170    1113      -57     
============================================
  Files            701     707       +6     
  Lines          45281   45448     +167     
  Branches       10851   10885      +34     
============================================
- Hits            4131    3867     -264     
- Misses         40497   41007     +510     
+ Partials         653     574      -79     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Collaborator

@kchelstowski kchelstowski left a comment

Choose a reason for hiding this comment

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

I still need more time for this one, but will submit my initial review

&__header {
display: flex;
flex-direction: column;
margin-left: 6px;
Copy link
Collaborator

@kchelstowski kchelstowski Oct 29, 2025

Choose a reason for hiding this comment

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

I am against using margins. Can we somehow use padding instead?

display: flex;
justify-content: flex-end;
gap: 8px;
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

a question to all of those styles - don't they impact all modals in the system?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Those styles shouldn’t affect all modals in the system because they don’t have classNames like modal-content__header, modal-content__main etc.

import useConfirmExpirationDateModal from 'hooks/useConfirmExpirationDateModal';
import useTranslate from 'hooks/useTranslate';

const ConfirmExpirationDateModal = ({
Copy link
Collaborator

Choose a reason for hiding this comment

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

it feels like this could be a reusable modal with a table inside, so how about making it a reusable component like ModalWithTable/ModalTable/TableBasedModal - let's decide on the naming .

I mean - we can take the common part to the reusable component, but keep the ConfirmExpirationDateModal component for things that are "unique" for this modal, so calling all the hooks etc. but then just call the reusable component with proper props

const itemsWithMismatchedExpiry = [];

lines.map((line) => {
const oldItem = _.find(this.state.formValues.lines, (item) =>
Copy link
Collaborator

Choose a reason for hiding this comment

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

you shouldn't call .find in a loop. The map should be built above so that you have O(1) access here.
(No need to refactor it here as it was existing code)

return new Promise((resolve) => {
this.setState({
isExpirationModalOpen: true,
resolveExpirationModal: resolve,
Copy link
Collaborator

Choose a reason for hiding this comment

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

this feels weird, I would like to understand more context of it that we set a state with a promise 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I know it looks a bit weird, but we store the resolve function in the state so that onSave can await the modal response:

const shouldUpdateExpirationDate =
        await this.confirmExpirationDateSave(itemsWithMismatchedExpiry);
      if (!shouldUpdateExpirationDate) {
        return Promise.reject();
      }

When the user responds in the modal ("No"/"Yes"), method handleExpirationModalResponse calls:

    // Resolve the promise returned by confirmExpirationDateSave.
    if (this.state.resolveExpirationModal) {
      this.state.resolveExpirationModal(shouldUpdate);
    }

and this works because we passed "resolve" reference in method confirmExpirationDateSave to this resolveExpirationModal state

and after this we reset the modal state:

    // Close the modal and reset its state.
    this.setState({
      isExpirationModalOpen: false,
      resolveExpirationModal: null,
      itemsWithMismatchedExpiry: [],
    });

I actually was inspired by a similar pattern in AddItemsPage.jsx (inbound return), where confirmAlert returns a Promise and resolves it directly via button callbacks, for example:

  confirmExpirationDateSave() {
    return new Promise((resolve) => {
      confirmAlert({
        title: this.props.translate('react.inboundReturns.message.confirmSave.label', 'Confirm save'),
        message: this.props.translate(
          'react.stockMovement.confirmExpiryDateUpdate.message',
          'This will update the expiry date across all depots in the system. Are you sure you want to proceed?',
        ),
        willUnmount: () => resolve(false),
        buttons: [
          {
            label: this.props.translate('react.default.yes.label', 'Yes'),
            onClick: () => resolve(true),
          },
          {
            label: this.props.translate('react.default.no.label', 'No'),
            onClick: () => resolve(false),
          },
        ],
      });
    });
  }

but I can't (probably) do the same here so I needed to store the resolve in state

Copy link
Collaborator

Choose a reason for hiding this comment

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

thanks for the explanation @SebastianLib. I still don't like it, but on the other hand I don't have any quick idea how to resolve this issue in those old class components.

// After finding at least a single instance where expiration date we are trying to save
// does not match the existing inventoryItem expiration date, we want to inform the user
// that certain updates to th expiration date in the system will be performed
const shouldUpdateLotExpirationDate =
Copy link
Collaborator

Choose a reason for hiding this comment

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

decide on the naming, either use the *expirationDate everywhere only or *lotExpirationDate

Comment on lines +4829 to +4835
react.confirmExpirationDate.modal.title.label=Confirm save
react.confirmExpirationDate.modal.subtitle.label=This will update the expiry date across all depots in the system for the lots listed below. Are you sure you want to proceed?
react.confirmExpirationDate.modal.code.label=Code
react.confirmExpirationDate.modal.productName.label=Product Name
react.confirmExpirationDate.modal.lot.label=Lot
react.confirmExpirationDate.modal.previousExpiry.label=Previous Expiry
react.confirmExpirationDate.modal.newExpiry.label=New Expiry
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are those translations fetched?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I didn't fetch translations, but I will change that

@github-actions github-actions bot added the domain: backend Changes or discussions relating to the backend server label Oct 30, 2025
return new Promise((resolve) => {
this.setState({
isExpirationModalOpen: true,
resolveExpirationModal: resolve,
Copy link
Collaborator

Choose a reason for hiding this comment

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

thanks for the explanation @SebastianLib. I still don't like it, but on the other hand I don't have any quick idea how to resolve this issue in those old class components.

@alannadolny alannadolny merged commit 6f48e3a into develop Oct 31, 2025
7 checks passed
@alannadolny alannadolny deleted the feature/OBPIH-7186 branch October 31, 2025 10:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain: backend Changes or discussions relating to the backend server domain: frontend Changes or discussions relating to the frontend UI domain: l10n Changes or discussions relating to localization & Internationalization type: feature A new piece of functionality for the app

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants