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

Update MoneyRequestView.js to show Violations #32594

Merged
merged 83 commits into from
Jan 4, 2024

Conversation

trevor-coleman
Copy link
Contributor

@trevor-coleman trevor-coleman commented Dec 6, 2023

Details

This adds Violations warnings and RBR indicators to fields in the MoneyRequestView.

Notes on Implementation:

  1. Created FieldViolationMessages component -- The violation messages display is repeated 8 times on
    the MoneyRequestView page, which is enough that it should be encapsulated in a component. It takes a single prop --
    the list of violations for that field -- which it then maps to a list of <Text> components

  2. CONST.VIOLATIONS -- The list of violation names is defined in the CONST file, and other types are derived from
    there. This way there is a single place to add/remove violations and the type system would provide helpful errors if
    other changes to be made.

  3. Onyx Keys -- added ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS with the value transactionViolation_ -- this
    seemed to follow the pattern

  4. Prop Types -- created propTypes objects for a transactionViolation and array of transactionViolations --
    put them in @libs/Violations in case some other component needs to use them later.

  5. Clean-up -- cleaned up some imports I wrote in the ViolationUtils PR to match the repo style. Also added some
    JSDoc comments for things

Fixed Issues

$ #31084

Tests

Unfortunately the Violations API is not yet working on the back end, so testing this requires changing the code to add
some test data.

Adding Test Violations

In @src/hooks/useViolations.ts add the following snippet anywhere below the definition of violationFields:

function getTestViolations({violations, fields}: { violations?: ViolationName[]; fields?: ViolationField[] } = {}) {
    const allViolations = Object.keys(violationFields) as ViolationName[];
    return allViolations
        .filter((key) => violations?.includes(key) ?? true)
        .filter((key) => fields?.includes(violationFields[key]) ?? true)
        .map((key) => ({name: key, type: `violation.${key}.type`, userMessage: `violation.${key}.userData`} as TransactionViolation));
}

Then, define a testViolations variable and use it in place of violations in the violationsByField factory
function. For instance this will add all violations on the amount field:

 const violationsByField = useMemo((): ViolationsMap => {
    const violationGroups = new Map<ViolationField, TransactionViolation[]>();
    
    const testViolations = getTestViolations({field: 'amount'});      // <--- ADD THIS (change the field to the one you want to test)

    // for (const violation of violations ?? []) {                     // <--- REPLACE THIS LINE
    for (const violation of testViolations) {                         // <---WITH THIS LINE
        const field = violationFields[violation.name];
        const existingViolations = violationGroups.get(field) ?? [];
        violationGroups.set(field, [...existingViolations, violation]);
    }

    return violationGroups ?? new Map();
}, [violations]);

This will allow you to select which violations are shown by redefining testViolations in the test.

As no native code has changed you will not need to rebuild the app between tests. Simply adjust the value of
testViolations and it should hot-reload.

Billable, Category, and Tags Violations

To test the violations on the Billable, Category and Tag violations, we need to be in a report with a policy -- make
sure the policy has Billable Expenses, Categories, and Tags enabled.

Alternatively, if you have access to the code, you can edit the MoneyRequestView component and set the values
of shouldShowBillable, shouldShowCategory, and shouldShowTags in the to true to test these violations.

Tax Violations

The MoneyRequestView component does not currently support Tax violations, so there is no way to test them.

Testing violations are displayed correctly for each field:

  1. Set up the test data to include all violations on the amount Field:

       const testViolations = getTestViolations('amount');
  2. Create a new Money Request without a Receipt
    a. Open the app
    b. Click the + button
    c. Touch Create New Money Request
    d. Select the "Manual" tab
    e. Enter a random amount
    f. Touch the Next button
    g. Select a policy to request money from
    h. Enter a description
    i. Touch the Request ${amount} button
    j. When you are taken to the chat, touch the Report Preview to open the report
    k. Touch the money request you just created to view it

  3. For the amount field, check that:
    a. the correct violations are displayed in red text under the associated field
    b. that the RBR indicator is displayed next to the chevron (when applicable)
    c. that the field can be edited as normal
    d. that the screen matches the screenshot below for the amount field

  4. Repeat for each additional field in the table below. You can do this

    Field Violations RBR Indicator
    tag dummy.violations.allTagLevelsRequired
    dummy.violations.missingTag
    dummy.violations.someTagLevelsRequired
    dummy.violations.tagOutOfPolicy
    merchant dummy.violations.autoReportedRejectedExpense
    dummy.violations.customUnitOutOfPolicy
    dummy.violations.duplicatedTransaction
    dummy.violations.fieldRequired
    dummy.violations.nonExpensiworksExpense
    dummy.violations.rter
    billable dummy.violations.billableExpense
    receipt dummy.violations.cashExpenseWithNoReceipt
    dummy.violations.receiptNotSmartScanned
    dummy.violations.receiptRequired
    dummy.violations.smartscanFailed
    category dummy.violations.categoryOutOfPolicy
    dummy.violations.missingCategory
    amount dummy.violations.conversionSurcharge
    dummy.violations.invoiceMarkup
    dummy.violations.modifiedAmount
    dummy.violations.overAutoApprovalLimit
    dummy.violations.overCategoryLimit
    dummy.violations.overLimit
    dummy.violations.overLimitAttendee
    dummy.violations.perDayLimit
    date dummy.violations.futureDate
    dummy.violations.maxAge
    dummy.violations.modifiedDate
    comment dummy.violations.missingComment

Test that NO violations are displayed when there are no violations

  1. Create a new Money Request with a Receipt
    a. Open the app
    b. Click the + button
    c. Touch Create New Money Request
    d. Scan or select a receipt image
    e. Select a policy to request money from
    f. Complete each field on the request with any valid input
    g. Touch the Request button
    h. Touch the Money Request to navigate to the Money Request View
  2. Set the value of testViolations to an empty array:
       const testViolations = [];
  3. For each field in the table above, check that no violations are displayed.
  • Verify that no errors appear in the JS console

Offline tests

This PR does not have any offline behaviour, as it only specifies where/how error messages should appear in the display.

QA Steps

  1. Create a new Money Request with a Receipt
    a. Open the app
    b. Click the + button
    c. Touch Create New Money Request
    d. Scan or select a receipt image
    e. Select a policy to request money from
    f. Complete each field on the request with any valid input
    g. Touch the Request button
    h. Touch the Money Request to navigate to the Money Request View
  2. View the money request and ensure that it looks the same as usual. The violations should not be displayed as the back
    end is not implemented yet.
  3. Touch the fields on the money request to edit them, this behaviour should be the same as usual.
  • 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

Amount
android-amount

BIllable
android-billable

Category
android-category

Date
android-date

Merchant
android-merchant

Receipt
android-receipt

Tag
android-tag

Android: mWeb Chrome Amount ![web-android-amount](https://github.com/Expensify/App/assets/22041394/e1faeb20-7493-47e0-a606-1718b502c966)

Billable
web-android-billable

Comment
web-android-comment

Date
web-android-date

Merchant
web-android-merchant

Receipt
web-android-receipt

Tag
web-android-tag

iOS: Native

Amount
ios-amount

Billable
ios-billable

Category
ios-category

Comment
ios-comment

Date
ios-date

Merchant
ios-merchant

Receipt
ios-receipt

Tag
ios-tag

iOS: mWeb Safari Amount ![ios-web-amount](https://github.com/Expensify/App/assets/22041394/8139d956-c980-49a1-918b-81d5a689d450)

Billable
ios-web-billable

Category
ios-web-category

Comment
ios-web-comment

Date
ios-web-date

Merchant
ios-web-merchant

Receipt
ios-web-receipt

Tag
ios-web-tag

MacOS: Chrome / Safari **Chrome**

Amount
web-desktop-amount

Billable
web-desktop-billable

Category
web-desktop-category

Comment
web-desktop-comment

Date
web-desktop-date

Merchant
![web-desktop-merchant]
(https://github.com/Expensify/App/assets/22041394/ed300c94-4ba4-4a51-a974-ad068df7ee9d)

Receipt
web-desktop-receipt

Tag
web-desktop-tag

MacOS: Desktop

MacOS Desktop is currently crashing on
launch due to an unrelated issue, so I have been
unable to test it. Given the scope of the changes I am highly confident that there will not be any errors specific to
that platform.

…-fields

# Conflicts:
#	src/ONYXKEYS.ts
#	src/components/ReportActionItem/MoneyRequestView.js
#	src/languages/en.ts
…w, and move translation to the display component.
…equest-view-fields

# Conflicts:
#	package-lock.json
#	src/ONYXKEYS.ts
#	src/languages/en.ts
#	src/libs/Violations/ViolationsUtils.ts
#	src/libs/Violations/useViolations.ts
#	src/types/onyx/TransactionViolation.ts
@trevor-coleman
Copy link
Contributor Author

Resolved conflicts.

@aimane-chnaif
Copy link
Contributor

aimane-chnaif commented Jan 3, 2024

@trevor-coleman please complete missing checklist

authorChecklist

src/languages/en.ts Outdated Show resolved Hide resolved
src/languages/es.ts Outdated Show resolved Hide resolved
@trevor-coleman
Copy link
Contributor Author

Main merged, conflicts resolved, translations updated, checkboxes checked. I think this is good to go.

@cead22 cead22 merged commit 8c19e21 into Expensify:main Jan 4, 2024
15 checks passed
@situchan situchan mentioned this pull request Jan 4, 2024
48 tasks
@OSBotify
Copy link
Contributor

OSBotify commented Jan 4, 2024

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

@OSBotify
Copy link
Contributor

OSBotify commented Jan 4, 2024

🚀 Deployed to staging by https://github.com/cead22 in version: 1.4.22-0 🚀

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

@OSBotify
Copy link
Contributor

OSBotify commented Jan 4, 2024

🚀 Deployed to staging by https://github.com/cead22 in version: 1.4.22-0 🚀

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

@OSBotify
Copy link
Contributor

OSBotify commented Jan 9, 2024

🚀 Deployed to production by https://github.com/thienlnam in version: 1.4.22-6 🚀

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

@@ -349,5 +403,15 @@ export default compose(
return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`;
},
},
transactionViolation: {
Copy link
Contributor

Choose a reason for hiding this comment

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

there's a typo here which I'm fixing here if you can review please @trevor-coleman . I was able to see the violations once I fixed it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good catch! Let me review

},
smartscanFailed: 'Receipt scanning failed. Enter details manually.',
someTagLevelsRequired: 'Missing tag',
tagOutOfPolicy: ({tagName}: ViolationsTagOutOfPolicyParams) => `${tagName ?? ''} no longer valid`,
Copy link
Contributor

@s77rt s77rt Feb 13, 2024

Choose a reason for hiding this comment

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

If tagName is not available we should have fallen back to Tag instead of an empty string for consistency with categoryOutOfPolicy and also because no longer valid message on its own is not clear

Copy link
Contributor

Choose a reason for hiding this comment

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

Same for tax

@@ -349,5 +403,15 @@ export default compose(
return `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`;
},
},
transactionViolation: {
key: ({report}) => {
const parentReportAction = ReportActionsUtils.getParentReportAction(report);
Copy link
Contributor

Choose a reason for hiding this comment

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

@trevor-coleman ReportActionsUtils.getParentReportAction is a deprecated method. I'm trying to remove these in #27262. Can you please create a PR to clean this up and remove the usage of the deprecated method?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi, I was a paid contractor and I'm no longer on this project.

Copy link
Contributor

Choose a reason for hiding this comment

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

@tgolen can you do this as part of one of your PRs removing the method?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'll add it to the list.

Thanks for responding @trevor-coleman and I hope you come back at some point! 👋

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks!

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.