From a71f87b82185a7381421703e29e556587dfdbd05 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Thu, 14 Aug 2025 21:57:39 +0700 Subject: [PATCH 1/4] Tag - violation remains after switching tag level and selecting new tag --- src/pages/iou/request/step/IOURequestStepTag.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pages/iou/request/step/IOURequestStepTag.tsx b/src/pages/iou/request/step/IOURequestStepTag.tsx index 85a31f546810..27fea1289ec7 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.tsx +++ b/src/pages/iou/request/step/IOURequestStepTag.tsx @@ -104,6 +104,8 @@ function IOURequestStepTag({ } updatedTag = tagParts.join(':'); + } else if (!policy?.hasMultipleTagLists) { + updatedTag = isSelectedTag ? '' : searchText; } else { // Independent tags (fallback): use comma-separated list updatedTag = insertTagIntoTransactionTagsString(transactionTag, isSelectedTag ? '' : searchText, tagListIndex); From e8659e10e12bf46ef860fd6af1117265df67b6b0 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Fri, 15 Aug 2025 10:04:49 +0700 Subject: [PATCH 2/4] add test for insertTagIntoTransactionTagsString --- src/libs/IOUUtils.ts | 7 ++++++- src/pages/iou/request/step/IOURequestStepTag.tsx | 4 +--- tests/unit/IOUUtilsTest.ts | 8 ++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index 3fdffbe33c24..ca1948dbf754 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -162,9 +162,14 @@ function isValidMoneyRequestType(iouType: string): boolean { * @param transactionTags - currently selected tags for a report * @param tag - a newly selected tag, that should be added to the transactionTags * @param tagIndex - the index of a tag list + * @param hasMultipleTagLists - whether the policy has multiple levels tag * @returns */ -function insertTagIntoTransactionTagsString(transactionTags: string, tag: string, tagIndex: number): string { +function insertTagIntoTransactionTagsString(transactionTags: string, tag: string, tagIndex: number, hasMultipleTagLists?: boolean): string { + if (!hasMultipleTagLists) { + return tag; + } + const tagArray = getTagArrayFromName(transactionTags); tagArray[tagIndex] = tag; diff --git a/src/pages/iou/request/step/IOURequestStepTag.tsx b/src/pages/iou/request/step/IOURequestStepTag.tsx index 27fea1289ec7..ca4e0dcd64e0 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.tsx +++ b/src/pages/iou/request/step/IOURequestStepTag.tsx @@ -104,11 +104,9 @@ function IOURequestStepTag({ } updatedTag = tagParts.join(':'); - } else if (!policy?.hasMultipleTagLists) { - updatedTag = isSelectedTag ? '' : searchText; } else { // Independent tags (fallback): use comma-separated list - updatedTag = insertTagIntoTransactionTagsString(transactionTag, isSelectedTag ? '' : searchText, tagListIndex); + updatedTag = insertTagIntoTransactionTagsString(transactionTag, isSelectedTag ? '' : searchText, tagListIndex, policy?.hasMultipleTagLists); } if (isEditingSplit) { diff --git a/tests/unit/IOUUtilsTest.ts b/tests/unit/IOUUtilsTest.ts index acbf0e0c4408..ddbed6eaf345 100644 --- a/tests/unit/IOUUtilsTest.ts +++ b/tests/unit/IOUUtilsTest.ts @@ -169,6 +169,14 @@ describe('IOUUtils', () => { test('Remove a tag from tagString', () => { expect(IOUUtils.insertTagIntoTransactionTagsString('East:City \\: \\::California', '', 1)).toBe('East::California'); }); + + test('Return single tag directly when hasMultipleTagLists is false', () => { + expect(IOUUtils.insertTagIntoTransactionTagsString('East:NY:California', 'NewTag', 1, false)).toBe('NewTag'); + }); + + test('Return multiple tags when hasMultipleTagLists is true', () => { + expect(IOUUtils.insertTagIntoTransactionTagsString('East:NY:California', 'NewTag', 1, true)).toBe('East:NewTag:California'); + }); }); }); From 7b982c426defe29828921928617a822ec537129e Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Fri, 15 Aug 2025 10:18:01 +0700 Subject: [PATCH 3/4] update test --- src/components/MoneyRequestConfirmationList.tsx | 2 +- src/pages/Debug/DebugTagPicker.tsx | 5 +++-- tests/unit/IOUUtilsTest.ts | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 3698ee5f50e4..6b3288c35326 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -874,7 +874,7 @@ function MoneyRequestConfirmationList({ if (enabledTags.length !== 1 || getTag(transaction, index)) { return; } - updatedTagsString = insertTagIntoTransactionTagsString(updatedTagsString, enabledTags.at(0)?.name ?? '', index); + updatedTagsString = insertTagIntoTransactionTagsString(updatedTagsString, enabledTags.at(0)?.name ?? '', index, policy?.hasMultipleTagLists); }); if (updatedTagsString !== getTag(transaction) && updatedTagsString) { setMoneyRequestTag(transactionID, updatedTagsString); diff --git a/src/pages/Debug/DebugTagPicker.tsx b/src/pages/Debug/DebugTagPicker.tsx index cd16b37941fa..425b19124e14 100644 --- a/src/pages/Debug/DebugTagPicker.tsx +++ b/src/pages/Debug/DebugTagPicker.tsx @@ -31,17 +31,18 @@ function DebugTagPicker({policyID, tagName = '', onSubmit}: DebugTagPickerProps) const [policyTags] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {canBeMissing: true}); const policyTagLists = useMemo(() => getTagLists(policyTags), [policyTags]); + const [hasMultipleTagLists] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {canBeMissing: true, selector: (policy) => policy?.hasMultipleTagLists}); const updateTagName = useCallback( (index: number) => ({text}: ListItem) => { const newTag = text === selectedTags.at(index) ? undefined : text; - const updatedTagName = insertTagIntoTransactionTagsString(newTagName, newTag ?? '', index); + const updatedTagName = insertTagIntoTransactionTagsString(newTagName, newTag ?? '', index, hasMultipleTagLists); if (policyTagLists.length === 1) { return onSubmit({text: updatedTagName}); } setNewTagName(updatedTagName); }, - [newTagName, onSubmit, policyTagLists.length, selectedTags], + [newTagName, onSubmit, policyTagLists.length, selectedTags, hasMultipleTagLists], ); const submitTag = useCallback(() => { diff --git a/tests/unit/IOUUtilsTest.ts b/tests/unit/IOUUtilsTest.ts index ddbed6eaf345..86da9b2d6ec9 100644 --- a/tests/unit/IOUUtilsTest.ts +++ b/tests/unit/IOUUtilsTest.ts @@ -155,19 +155,19 @@ describe('IOUUtils', () => { describe('insertTagIntoTransactionTagsString', () => { test('Inserting a tag into tag string should update the tag', () => { - expect(IOUUtils.insertTagIntoTransactionTagsString(':NY:Texas', 'California', 2)).toBe(':NY:California'); + expect(IOUUtils.insertTagIntoTransactionTagsString(':NY:Texas', 'California', 2, true)).toBe(':NY:California'); }); test('Inserting a tag into an index with no tags should update the tag', () => { - expect(IOUUtils.insertTagIntoTransactionTagsString('::California', 'NY', 1)).toBe(':NY:California'); + expect(IOUUtils.insertTagIntoTransactionTagsString('::California', 'NY', 1, true)).toBe(':NY:California'); }); test('Inserting a tag with colon in name into tag string should keep the colon in tag', () => { - expect(IOUUtils.insertTagIntoTransactionTagsString('East:NY:California', 'City \\: \\:', 1)).toBe('East:City \\: \\::California'); + expect(IOUUtils.insertTagIntoTransactionTagsString('East:NY:California', 'City \\: \\:', 1, true)).toBe('East:City \\: \\::California'); }); test('Remove a tag from tagString', () => { - expect(IOUUtils.insertTagIntoTransactionTagsString('East:City \\: \\::California', '', 1)).toBe('East::California'); + expect(IOUUtils.insertTagIntoTransactionTagsString('East:City \\: \\::California', '', 1, true)).toBe('East::California'); }); test('Return single tag directly when hasMultipleTagLists is false', () => { From 7bf2ef3f4a67c00f2fb8cbceadfc9449cf483938 Mon Sep 17 00:00:00 2001 From: nkdengineer Date: Mon, 18 Aug 2025 11:51:04 +0700 Subject: [PATCH 4/4] make hasMultipleTagLists required --- src/components/MoneyRequestConfirmationList.tsx | 2 +- src/libs/IOUUtils.ts | 2 +- src/pages/Debug/DebugTagPicker.tsx | 2 +- src/pages/iou/request/step/IOURequestStepTag.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/MoneyRequestConfirmationList.tsx b/src/components/MoneyRequestConfirmationList.tsx index 6b3288c35326..9a2904c61e9c 100755 --- a/src/components/MoneyRequestConfirmationList.tsx +++ b/src/components/MoneyRequestConfirmationList.tsx @@ -874,7 +874,7 @@ function MoneyRequestConfirmationList({ if (enabledTags.length !== 1 || getTag(transaction, index)) { return; } - updatedTagsString = insertTagIntoTransactionTagsString(updatedTagsString, enabledTags.at(0)?.name ?? '', index, policy?.hasMultipleTagLists); + updatedTagsString = insertTagIntoTransactionTagsString(updatedTagsString, enabledTags.at(0)?.name ?? '', index, policy?.hasMultipleTagLists ?? false); }); if (updatedTagsString !== getTag(transaction) && updatedTagsString) { setMoneyRequestTag(transactionID, updatedTagsString); diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index ca1948dbf754..d16b091f5832 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -165,7 +165,7 @@ function isValidMoneyRequestType(iouType: string): boolean { * @param hasMultipleTagLists - whether the policy has multiple levels tag * @returns */ -function insertTagIntoTransactionTagsString(transactionTags: string, tag: string, tagIndex: number, hasMultipleTagLists?: boolean): string { +function insertTagIntoTransactionTagsString(transactionTags: string, tag: string, tagIndex: number, hasMultipleTagLists: boolean): string { if (!hasMultipleTagLists) { return tag; } diff --git a/src/pages/Debug/DebugTagPicker.tsx b/src/pages/Debug/DebugTagPicker.tsx index 425b19124e14..209f86777744 100644 --- a/src/pages/Debug/DebugTagPicker.tsx +++ b/src/pages/Debug/DebugTagPicker.tsx @@ -36,7 +36,7 @@ function DebugTagPicker({policyID, tagName = '', onSubmit}: DebugTagPickerProps) (index: number) => ({text}: ListItem) => { const newTag = text === selectedTags.at(index) ? undefined : text; - const updatedTagName = insertTagIntoTransactionTagsString(newTagName, newTag ?? '', index, hasMultipleTagLists); + const updatedTagName = insertTagIntoTransactionTagsString(newTagName, newTag ?? '', index, hasMultipleTagLists ?? false); if (policyTagLists.length === 1) { return onSubmit({text: updatedTagName}); } diff --git a/src/pages/iou/request/step/IOURequestStepTag.tsx b/src/pages/iou/request/step/IOURequestStepTag.tsx index ca4e0dcd64e0..7eb29c7f1fdb 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.tsx +++ b/src/pages/iou/request/step/IOURequestStepTag.tsx @@ -106,7 +106,7 @@ function IOURequestStepTag({ updatedTag = tagParts.join(':'); } else { // Independent tags (fallback): use comma-separated list - updatedTag = insertTagIntoTransactionTagsString(transactionTag, isSelectedTag ? '' : searchText, tagListIndex, policy?.hasMultipleTagLists); + updatedTag = insertTagIntoTransactionTagsString(transactionTag, isSelectedTag ? '' : searchText, tagListIndex, policy?.hasMultipleTagLists ?? false); } if (isEditingSplit) {