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

Disable Submit/Approve buttons when self approving is disabled and user is trying to self approve #37348

Merged
merged 25 commits into from
Mar 22, 2024

Conversation

barros001
Copy link
Contributor

@barros001 barros001 commented Feb 27, 2024

Details

Fixed Issues

$ #36425
PROPOSAL: #36425 (comment)

Tests

Precondition:

Admin is in the Collect workspace.
"Prevent Self-Approval" is enabled.

  1. Login as collect workspace admin
  2. Navigate to the collect workspace
  3. Click + Request Money
  4. Fill in the required fields and click Request
  5. Verify that the Submit button is disabled
  6. Click on the money request to open it
  7. Verify that the Submit button is also disabled
  8. On OD, set "Prevent Self-Approval" to disabled
  9. On ND, navigate back to the collect workspace
  10. Verify that the submit button is now enabled
  11. Click Submit to submit the request
  12. Verify that the "Approve" button is enabled
  13. On OD, set "Prevent Self-Approval" back to enabled
  14. On ND, navigate back to the collect workspace
  15. Verify that the "Approve" button is disabled
  16. Click on the money request to open it
  17. Verify that the "Approve" button is also disabled
  • Verify that no errors appear in the JS console

Offline tests

Precondition:

Admin is in the Collect workspace.
"Prevent Self-Approval" is enabled.

  1. Login as collect workspace admin
  2. Navigate to the collect workspace
  3. Click + Request Money
  4. Fill in the required fields and click Request
  5. Verify that the Submit button is disabled
  6. Click on the money request to open it
  7. Verify that the Submit button is also disabled

QA Steps

Precondition:

Admin is in the Collect workspace.
"Prevent Self-Approval" is enabled.

  1. Login as collect workspace admin
  2. Navigate to the collect workspace
  3. Click + Request Money
  4. Fill in the required fields and click Request
  5. Verify that the Submit button is disabled
  6. Click on the money request to open it
  7. Verify that the Submit button is also disabled
  8. On OD, set "Prevent Self-Approval" to disabled
  9. On ND, navigate back to the collect workspace
  10. Verify that the submit button is now enabled
  11. Click Submit to submit the request
  12. Verify that the "Approve" button is enabled
  13. On OD, set "Prevent Self-Approval" back to enabled
  14. On ND, navigate back to the collect workspace
  15. Verify that the "Approve" button is disabled
  16. Click on the money request to open it
  17. Verify that the "Approve" button is also disabled
  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that the left part of a conditional rendering a React component is a boolean and NOT a string, e.g. myBool && <MyComponent />.
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
      • If any non-english text was added/modified, I verified the translation was requested/reviewed in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is approved by marketing by adding the Waiting for Copy label for a copy review on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
android.webm
Android: mWeb Chrome
android-web.webm
iOS: Native

Uploading ios.mp4…

iOS: mWeb Safari
ios-web.mp4
MacOS: Chrome / Safari
web.mov
MacOS: Desktop
desktop.mov

@barros001 barros001 changed the title Fix/36425 Disable Submit/Approve buttons when self approving is disabled and user is trying to self approve Feb 29, 2024
@barros001 barros001 marked this pull request as ready for review February 29, 2024 11:17
@barros001 barros001 requested a review from a team as a code owner February 29, 2024 11:17
@melvin-bot melvin-bot bot removed the request for review from a team February 29, 2024 11:22
Copy link

melvin-bot bot commented Feb 29, 2024

@alitoshmatov Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@barros001
Copy link
Contributor Author

I marked the PR as ready for review but it's still a working in progress (mostly done at this point) as I wanted to go over a few things.

We're dealing with two separate issues here (when self-approval is disabled):

  1. The submit button needs to be disabled when self-submitting
  2. The approve button also needs to be disabled when self-approving

As for 1., it's is straight forward and it's done. As per my proposal I added a isAllowedToSubmitDraftExpenseReport and then disabled the Submit button here, here and here.

Now as for 2., I wanted to clarify a few assumptions that I made:

  • The pay buttons should not be shown before the report is approved (meaning, when status is SUBMITTED). On production right now when a report is waiting to be approved, the settlement drop-down shows with two pay buttons (with Expensify and somewhere else) and the approve button. I mentioned that in the issue and it looks like we do not want the pay buttons but rather only the approve button. I did this by modifying the shouldShowPayButton to not show it if shouldShowApproveButton is true (if report is not yet approved, no pay button).
  • To determine if user is self-approving, I added a new function isAllowedToApproveExpenseReport. It's pretty much the same as isAllowedToSubmitDraftExpenseReport except that it also checks is the current user is the owner of the report. That's because my understanding is that it's not enough to check if submitsTo === currentUserAccountID as someone else could've submitted it to the user for approval and that condition will be true, but that does not mean self approval. I believe we can get away with it for the submit flow because only the owner can submit their reports so the isOwner is implicit. If this assumption is correct, we can merge both isAllowedToSubmitDraftExpenseReport and isAllowedToApproveExpenseReport into a single function (we'll discard isAllowedToSubmitDraftExpenseReport in favor of isAllowedToApproveExpenseReport which has a more strict set of rules, potentially renaming it).
  • Finally, this flow haven't been accounted for on the backend when it comes to next steps description, although it IS enforced and a user cannot approve its own report. If we land on this flow and a user is trying to self approve, the next steps description will say "Waiting for you to review expenses" while the approve button is disabled. I included new rules on NextStepUtils.ts to account for that but that generates only the optimistic data when a report transitions from open to submitted, which realistically will not happen (it would take a user landing on a report while self-approval is enabled, submitting it, and sometime in the middle of the request self-approval is disabled. otherwise user wouldn't be able to submit in the first place - I do not think this is a possible scenario). A more realistically (still very edge case and unlikely) flow would be a user submits its own report to themselves while self-approval is enabled, then later on comes back to approve it after self-approval is disabled. At that point the next steps description will come from the BE. If we want to handle this scenario, a BE change will be needed (or we can ignore this and handle it on a separate issue).

The PR is pretty much done based on the assumptions above. Let me know your thoughts on this and I'll do any final modifications needed and push the final version.

cc: @lakchote @alitoshmatov

@alitoshmatov
Copy link
Contributor

@barros001

  1. I don't think we should not modify pay button logic which is not in the scope of this issue and might lead to unexpected behavior.
  2. That looks great
  3. Same here it is not in the scope of this issue. If needed we should open another issue to handle this case. Provided it is an edge case I don't think backend changes would be worth it and we shouldn't change anything too.

I think we should just handle disabling approve button

@barros001
Copy link
Contributor Author

I think we should just handle disabling approve button

So should we just disable the submit AND approve buttons but keep the pay buttons intact?

@lakchote
Copy link
Contributor

lakchote commented Mar 4, 2024

The pay buttons should not be shown before the report is approved (meaning, when status is SUBMITTED). On production right now when a report is waiting to be approved, the settlement drop-down shows with two pay buttons (with Expensify and somewhere else) and the approve button. I mentioned that in the issue and it looks like we do not want the pay buttons but rather only the approve button. I did this by modifying the shouldShowPayButton to not show it if shouldShowApproveButton is true (if report is not yet approved, no pay button).

@kevinksullivan could we have your input on this please? Basically, in the context of self-approval, do we want to hide the pay buttons in the dropdown if the Submit and Approve buttons are disabled?

@barros001
Copy link
Contributor Author

barros001 commented Mar 8, 2024

The pay buttons should not be shown before the report is approved (meaning, when status is SUBMITTED). On production right now when a report is waiting to be approved, the settlement drop-down shows with two pay buttons (with Expensify and somewhere else) and the approve button. I mentioned that in the issue and it looks like we do not want the pay buttons but rather only the approve button. I did this by modifying the shouldShowPayButton to not show it if shouldShowApproveButton is true (if report is not yet approved, no pay button).

@kevinksullivan could we have your input on this please? Basically, in the context of self-approval, do we want to hide the pay buttons in the dropdown if the Submit and Approve buttons are disabled?

@lakchote I noticed that the Pay buttons are no longer displayed on staging when for reports that are not yet approved. Here's the PR that made the change. I'd say we no longer need to worry about this and we can focus again on disabling the Submit and Approve buttons accordingly (as @alitoshmatov had already suggested).

I'll make the necessary changes to the PR to simplify it and remove all changes that deal with hiding payment buttons.

As for disabling the Approve button, are we considering this part of this issue, or out of scope? If we should treat it as out of scope, then my comments/questions below won't really matter. If part of the issue, then:

I'll update the logic to disable the Approve button when ReportUtils.isAllowedToApproveExpenseReport , without worrying about showing/hiding the extra Pay buttons. Also, as for the issue I previously mentioned - item 3 on the list, I'll revert the changes I originally made to populate the optimistic data with a "oops, you can't approve your own reports" because this scenario is actually impossible (or at best extremely unlikely and can be safely ignored) to happen. We might still want to handle this on the BE but it's out of the scope of this issue.

  1. That looks great

@alitoshmatov when you said this, did you mean you agree that we could get rid of isAllowedToSubmitDraftExpenseReport and use isAllowedToApproveExpenseReport (which also checks if isOwner)? Only thing is I'm having a hard time coming up with a good name for this function as we'll be calling it to check if user can submit and also if user can approve. Behind the scenes they do the exact same thing but in terms of code readability I can see it being more clear to have two separate methods even if they do the same (or very similar) thing.

@alitoshmatov
Copy link
Contributor

As for disabling the Approve button, are we considering this part of this issue, or out of scope?
Part of this issue

Behind the scenes they do the exact same thing but in terms of code readability I can see it being more clear to have two separate methods even if they do the same (or very similar) thing.

I agree with you on this.

@lakchote
Copy link
Contributor

lakchote commented Mar 8, 2024

I'll update the logic to disable the Approve button when ReportUtils.isAllowedToApproveExpenseReport , without worrying about showing/hiding the extra Pay buttons.

I'd say yes @barros001. In BE, there's already checks that prevent self-approval actually.

@barros001
Copy link
Contributor Author

@alitoshmatov Ok, here's the final version of the PR.

When disabling the "Approve" button, we have the either disable the entire SettlementButton or only the Approve item inside of the dropdown menu. On my tests the Approve button always showed by itself but following the code it is possible that the Approve button would show along with the Pay options. IMO it would not make sense to allow for Payment but not Approval but for the sake of not making assumptions that could break things down the road, I introduced a new "disabled" option to the DropDownButton component (which honestly can come handy in the future). Here's how the Approve would look like if Pay buttons are also present:

Screenshot 2024-03-11 at 5 40 05 PM

Other than that, I made changes to the isAllowedToSubmitDraftExpenseReport and isAllowedToApproveExpenseReport which solved my dilemma with the two functions. After analyzing the logic I came to the conclusion that a report cannot be submitted to someone that is not allowed to approve it. In this case, if someone is submitting a report to the owner of that report for approval and self-approval is disabled. I came to this solution after I realized that an employee in the workspace can request money and an admin is allowed to submit it on behalf of the owner, but if they are submitting to themselves for approval and self-approval is not allowed, then they should not be able to submit (I verified and the BE handles this scenario).

@alitoshmatov
Copy link
Contributor

alitoshmatov commented Mar 13, 2024

I am noticing that changing Prevent Self-Approval in OD is not picked up in ND. Even after refreshing the page the submit button is still disabled(should be enabled already), I tried waiting for some time and moving around reports but no luck. Only after creating draft money request the state of buttons changed. I think it is because of isPreventSelfApprovalEnabled not being sent by backend when it changes in OD.

Screenshot 2024-03-13 at 5 05 08 PM

Here is the video as you can see even if I change self approval in OD nothing changes in our app.

Screen.Recording.2024-03-13.at.5.02.28.PM.mov

I see isPreventSelfApprovalEnabled is deprecated, maybe this is the reason it is falling behind onyx updates. Can we avoid using this?

@barros001

@barros001
Copy link
Contributor Author

barros001 commented Mar 13, 2024 via email

@barros001
Copy link
Contributor Author

@alitoshmatov you're right, it's an issue with isPreventSelfApprovalEnabled. I pushed an update. It was working before but at some point it stopped, likely a BE update. The reason I used isPreventSelfApprovalEnabled ?? preventSelfApproval is because the same is done here:

if ((isPreventSelfApprovalEnabled ?? preventSelfApproval) && isSelfApproval) {

This is the last place using the deprecated isPreventSelfApprovalEnabled, we should really get rid of it but wanted to get your thoughts first as it's technically not in scope. I don't really see much that can go wrong by removing it.

@alitoshmatov
Copy link
Contributor

@barros001 Are we good to proceed?

@barros001
Copy link
Contributor Author

@alitoshmatov yes. I was just waiting to hear from you if you think we should kill the deprecated usage I mentioned on the other comment.

I'll merge main and solve conflicts shortly.

@alitoshmatov
Copy link
Contributor

Yes as far as I understand removing it does not affect our solution. Let's just not use it in our solution and leave everything else the same related to isPreventSelfApprovalEnabled

@barros001
Copy link
Contributor Author

@alitoshmatov main merged and conflicts resolved.

@alitoshmatov
Copy link
Contributor

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified tests pass on all platforms & I tested again on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • I verified that the left part of a conditional rendering a React component is a boolean and NOT a string, e.g. myBool && <MyComponent />.
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is approved by marketing by adding the Waiting for Copy label for a copy review on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: Native
approve-android.mov
Android: mWeb Chrome
iOS: Native
approve-ios.mp4
iOS: mWeb Safari
approve-safari.mp4
MacOS: Chrome / Safari
approve-web.mov
MacOS: Desktop
approve-desktop.mov

Copy link
Contributor

@alitoshmatov alitoshmatov left a comment

Choose a reason for hiding this comment

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

LGTM. I think we can finally merge this PR

@melvin-bot melvin-bot bot requested a review from lakchote March 21, 2024 10:32
@lakchote
Copy link
Contributor

LGTM. Thank you both @barros001 and @alitoshmatov for your involvement in this.

@lakchote lakchote merged commit 1f3e31f into Expensify:main Mar 22, 2024
16 checks passed
@melvin-bot melvin-bot bot added the Emergency label Mar 22, 2024
Copy link

melvin-bot bot commented Mar 22, 2024

@lakchote looks like this was merged without a test passing. Please add a note explaining why this was done and remove the Emergency label if this is not an emergency.

@OSBotify
Copy link
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@lakchote
Copy link
Contributor

@lakchote looks like this was merged without a test passing. Please add a note explaining why this was done and remove the Emergency label if this is not an emergency.

Not an emergency, tests are passing. It's related to imgbot and affects the other PRs (example).

@OSBotify
Copy link
Contributor

🚀 Deployed to staging by https://github.com/lakchote in version: 1.4.56-0 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@OSBotify
Copy link
Contributor

🚀 Deployed to production by https://github.com/yuwenmemon in version: 1.4.56-8 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants