-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Tags - Violation for unselected dependent tags displays tag name briefly then changes to "tag" #40741
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
Tags - Violation for unselected dependent tags displays tag name briefly then changes to "tag" #40741
Changes from all commits
43e030b
b9a8d90
b9d8b24
fcdc252
0a0cac1
7a3db00
a174c60
47bf6f2
72f8575
5c7e16c
3d6478f
0ab716d
e297686
a8ef1c3
5e36ed7
94c657c
b873788
2e4f7f8
d958c37
8558f65
5e20695
525be58
d67febb
30189ca
4cd7802
492a672
df3326a
e54d678
e7f175f
df5e19f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,12 +62,12 @@ function useViolations(violations: TransactionViolation[]) { | |
| }, [violations]); | ||
|
|
||
| const getViolationsForField = useCallback( | ||
| (field: ViolationField, data?: TransactionViolation['data']) => { | ||
| (field: ViolationField, data?: TransactionViolation['data'], policyHasDependentTags = false, tagValue?: string) => { | ||
| const currentViolations = violationsByField.get(field) ?? []; | ||
|
|
||
| // someTagLevelsRequired has special logic becase data.errorIndexes is a bit unique in how it denotes the tag list that has the violation | ||
| // tagListIndex can be 0 so we compare with undefined | ||
| if (currentViolations[0]?.name === 'someTagLevelsRequired' && data?.tagListIndex !== undefined && Array.isArray(currentViolations[0]?.data?.errorIndexes)) { | ||
| if (currentViolations[0]?.name === CONST.VIOLATIONS.SOME_TAG_LEVELS_REQUIRED && data?.tagListIndex !== undefined && Array.isArray(currentViolations[0]?.data?.errorIndexes)) { | ||
| return currentViolations | ||
| .filter((violation) => violation.data?.errorIndexes?.includes(data?.tagListIndex ?? -1)) | ||
| .map((violation) => ({ | ||
|
|
@@ -79,8 +79,28 @@ function useViolations(violations: TransactionViolation[]) { | |
| })); | ||
| } | ||
|
|
||
| // missingTag has special logic for policies with dependent tags, because only one violation is returned for all tags | ||
| // when no tags are present, so the tag name isn't set in the violation data. That's why we add it here | ||
| if (policyHasDependentTags && currentViolations[0]?.name === CONST.VIOLATIONS.MISSING_TAG && data?.tagListName) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a suggestion: |
||
| return [ | ||
| { | ||
| ...currentViolations[0], | ||
| data: { | ||
| ...currentViolations[0].data, | ||
| tagName: data?.tagListName, | ||
| }, | ||
| }, | ||
| ]; | ||
| } | ||
|
|
||
| // tagOutOfPolicy has special logic because we have to account for multi-level tags and use tagName to find the right tag to put the violation on | ||
| if (currentViolations[0]?.name === 'tagOutOfPolicy' && data?.tagListName !== undefined && currentViolations[0]?.data?.tagName) { | ||
| if (currentViolations[0]?.name === CONST.VIOLATIONS.TAG_OUT_OF_POLICY && data?.tagListName !== undefined && currentViolations[0]?.data?.tagName) { | ||
| return currentViolations.filter((violation) => violation.data?.tagName === data?.tagListName); | ||
| } | ||
|
|
||
| // allTagLevelsRequired has special logic because it is returned when one but not all the tags are set, | ||
| // so we need to return the violation for the tag fields without a tag set | ||
| if (currentViolations[0]?.name === CONST.VIOLATIONS.ALL_TAG_LEVELS_REQUIRED && tagValue) { | ||
| return currentViolations.filter((violation) => violation.data?.tagName === data?.tagListName); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,7 @@ import * as TransactionUtils from '@libs/TransactionUtils'; | |
| import CONST from '@src/CONST'; | ||
| import type {TranslationPaths} from '@src/languages/types'; | ||
| import ONYXKEYS from '@src/ONYXKEYS'; | ||
| import type {PolicyCategories, PolicyTagList, Transaction, TransactionViolation} from '@src/types/onyx'; | ||
| import type {PolicyCategories, PolicyTagList, Transaction, TransactionViolation, ViolationName} from '@src/types/onyx'; | ||
|
|
||
| /** | ||
| * Calculates tag out of policy and missing tag violations for the given transaction | ||
|
|
@@ -49,17 +49,41 @@ function getTagViolationsForSingleLevelTags( | |
| } | ||
|
|
||
| /** | ||
| * Calculates some tag levels required and missing tag violations for the given transaction | ||
| * Calculates missing tag violations for policies with dependent tags | ||
| */ | ||
| function getTagViolationsForMultiLevelTags( | ||
| updatedTransaction: Transaction, | ||
| transactionViolations: TransactionViolation[], | ||
| policyRequiresTags: boolean, | ||
| policyTagList: PolicyTagList, | ||
| ): TransactionViolation[] { | ||
| function getTagViolationsForDependentTags(policyTagList: PolicyTagList, transactionViolations: TransactionViolation[], tagName: string) { | ||
| const tagViolations = [...transactionViolations]; | ||
|
|
||
| if (!tagName) { | ||
| Object.values(policyTagList).forEach((tagList) => | ||
| tagViolations.push({ | ||
| name: CONST.VIOLATIONS.MISSING_TAG, | ||
| type: CONST.VIOLATION_TYPES.VIOLATION, | ||
| data: {tagName: tagList.name}, | ||
| }), | ||
| ); | ||
| } else { | ||
| const tags = TransactionUtils.getTagArrayFromName(tagName); | ||
| if (Object.keys(policyTagList).length !== tags.length || tags.includes('')) { | ||
| tagViolations.push({ | ||
| name: CONST.VIOLATIONS.ALL_TAG_LEVELS_REQUIRED, | ||
| type: CONST.VIOLATION_TYPES.VIOLATION, | ||
| data: {}, | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| return tagViolations; | ||
| } | ||
|
|
||
| /** | ||
| * Calculates missing tag violations for policies with independent tags | ||
| */ | ||
| function getTagViolationForIndependentTags(policyTagList: PolicyTagList, transactionViolations: TransactionViolation[], transaction: Transaction) { | ||
| const policyTagKeys = getSortedTagKeys(policyTagList); | ||
| const selectedTags = updatedTransaction.tag?.split(CONST.COLON) ?? []; | ||
| const selectedTags = transaction.tag?.split(CONST.COLON) ?? []; | ||
| let newTransactionViolations = [...transactionViolations]; | ||
|
|
||
| newTransactionViolations = newTransactionViolations.filter( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why was this removed? I think we should keep it so we're not adding SOME_TAG_LEVELS_REQUIRED to an array of violations that already has it
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @cead22 I removed it because we're already filtering those in the function that calls this one 😅 |
||
| (violation) => violation.name !== CONST.VIOLATIONS.SOME_TAG_LEVELS_REQUIRED && violation.name !== CONST.VIOLATIONS.TAG_OUT_OF_POLICY, | ||
| ); | ||
|
|
@@ -109,6 +133,30 @@ function getTagViolationsForMultiLevelTags( | |
| return newTransactionViolations; | ||
| } | ||
|
|
||
| /** | ||
| * Calculates tag violations for a transaction on a policy with multi level tags | ||
| */ | ||
| function getTagViolationsForMultiLevelTags( | ||
| updatedTransaction: Transaction, | ||
| transactionViolations: TransactionViolation[], | ||
| policyTagList: PolicyTagList, | ||
| hasDependentTags: boolean, | ||
| ): TransactionViolation[] { | ||
| const tagViolations = [ | ||
| CONST.VIOLATIONS.SOME_TAG_LEVELS_REQUIRED, | ||
| CONST.VIOLATIONS.TAG_OUT_OF_POLICY, | ||
| CONST.VIOLATIONS.MISSING_TAG, | ||
| CONST.VIOLATIONS.ALL_TAG_LEVELS_REQUIRED, | ||
| ] as ViolationName[]; | ||
| const filteredTransactionViolations = transactionViolations.filter((violation) => !tagViolations.includes(violation.name)); | ||
|
|
||
| if (hasDependentTags) { | ||
| return getTagViolationsForDependentTags(policyTagList, filteredTransactionViolations, updatedTransaction.tag ?? ''); | ||
| } | ||
|
|
||
| return getTagViolationForIndependentTags(policyTagList, filteredTransactionViolations, updatedTransaction); | ||
| } | ||
|
|
||
| const ViolationsUtils = { | ||
| /** | ||
| * Checks a transaction for policy violations and returns an object with Onyx method, key and updated transaction | ||
|
|
@@ -121,6 +169,7 @@ const ViolationsUtils = { | |
| policyTagList: PolicyTagList, | ||
| policyRequiresCategories: boolean, | ||
| policyCategories: PolicyCategories, | ||
| hasDependentTags: boolean, | ||
| ): OnyxUpdate { | ||
| const isPartialTransaction = TransactionUtils.isPartialMerchant(TransactionUtils.getMerchant(updatedTransaction)) && TransactionUtils.isAmountMissing(updatedTransaction); | ||
| if (isPartialTransaction) { | ||
|
|
@@ -166,7 +215,7 @@ const ViolationsUtils = { | |
| newTransactionViolations = | ||
| Object.keys(policyTagList).length === 1 | ||
| ? getTagViolationsForSingleLevelTags(updatedTransaction, newTransactionViolations, policyRequiresTags, policyTagList) | ||
| : getTagViolationsForMultiLevelTags(updatedTransaction, newTransactionViolations, policyRequiresTags, policyTagList); | ||
| : getTagViolationsForMultiLevelTags(updatedTransaction, newTransactionViolations, policyTagList, hasDependentTags); | ||
| } | ||
|
|
||
| return { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.