From 56097445d343c0b0f3b8a45189b014ef28429910 Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Tue, 20 Feb 2024 16:30:33 -0800 Subject: [PATCH 1/5] Implement same tag splitting logic we have in the API --- src/libs/IOUUtils.ts | 16 +++++----- src/libs/ModifiedExpenseMessage.ts | 5 +-- src/libs/TransactionUtils.ts | 31 ++++++++++++++++++- src/libs/Violations/ViolationsUtils.ts | 3 +- src/libs/actions/Policy.ts | 6 ++-- src/pages/EditRequestPage.js | 2 +- .../iou/request/step/IOURequestStepTag.js | 2 +- 7 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts index 0bd5d3162236..56ac47676a37 100644 --- a/src/libs/IOUUtils.ts +++ b/src/libs/IOUUtils.ts @@ -109,18 +109,18 @@ function isValidMoneyRequestType(iouType: string): boolean { } /** - * Inserts a newly selected tag into the already existed report tags like a string + * Inserts a newly selected tag into the already existing tags like a string * - * @param reportTags - currently selected tags for a report - * @param tag - a newly selected tag, that should be added to the reportTags + * @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 * @returns */ -function insertTagIntoReportTagsString(reportTags: string, tag: string, tagIndex: number): string { - const splittedReportTags = reportTags.split(CONST.COLON); - splittedReportTags[tagIndex] = tag; +function insertTagIntoTransactionTagsString(transactionTags: string, tag: string, tagIndex: number): string { + const tagArray = TransactionUtils.getTagArrayFromName(transactionTags); + tagArray[tagIndex] = tag; - return splittedReportTags.join(CONST.COLON).replace(/:*$/, ''); + return tagArray.join(CONST.COLON).replace(/:*$/, ''); } -export {calculateAmount, updateIOUOwnerAndTotal, isIOUReportPendingCurrencyConversion, isValidMoneyRequestType, navigateToStartMoneyRequestStep, insertTagIntoReportTagsString}; +export {calculateAmount, updateIOUOwnerAndTotal, isIOUReportPendingCurrencyConversion, isValidMoneyRequestType, navigateToStartMoneyRequestStep, insertTagIntoTransactionTagsString}; diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 13a58834860b..f501244a725d 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -9,6 +9,7 @@ import * as Localize from './Localize'; import * as PolicyUtils from './PolicyUtils'; import * as ReportUtils from './ReportUtils'; import type {ExpenseOriginalMessage} from './ReportUtils'; +import * as TransactionUtils from './TransactionUtils'; let allPolicyTags: OnyxCollection = {}; Onyx.connect({ @@ -189,8 +190,8 @@ function getForReportAction(reportID: string | undefined, reportAction: OnyxEntr const policyTags = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {}; const transactionTag = reportActionOriginalMessage?.tag ?? ''; const oldTransactionTag = reportActionOriginalMessage?.oldTag ?? ''; - const splittedTag = transactionTag.split(CONST.COLON); - const splittedOldTag = oldTransactionTag.split(CONST.COLON); + const splittedTag = TransactionUtils.getTagArrayFromName(transactionTag); + const splittedOldTag = TransactionUtils.getTagArrayFromName(oldTransactionTag); const localizedTagListName = Localize.translateLocal('common.tag'); Object.keys(policyTags).forEach((policyTagKey, index) => { diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index d3eafc6554db..b8bfd940158b 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -364,13 +364,41 @@ function getBillable(transaction: OnyxEntry): boolean { return transaction?.billable ?? false; } +/** + * Return a colon-delimited tag string as an array, considering escaped colons and double backslashes. + */ +function getTagArrayFromName(tagName: string): string[] { + // WAIT!!!!!!!!!!!!!!!!!! + // You need to keep this in sync with TransactionUtils.php + + // We need to be able to preserve double backslashes in the original string + // and not have it interfere with splitting on a colon (:). + // So, let's replace it with something absurd to begin with, do our split, and + // then replace the double backslashes in the end. + const tagWithoutDoubleSlashes = tagName.replace(/\\\\/g, '☠'); + const tagWithoutEscapedColons = tagWithoutDoubleSlashes.replace(/\\:/g, '☢'); + + // Do our split + const matches = tagWithoutEscapedColons.split(':'); + const newMatches: string[] = []; + + for (const item of matches) { + const tagWithEscapedColons = item.replace(/☢/g, '\\:'); + const tagWithDoubleSlashes = tagWithEscapedColons.replace(/☠/g, '\\\\'); + newMatches.push(tagWithDoubleSlashes); + } + + return newMatches; +} + /** * Return the tag from the transaction. When the tagIndex is passed, return the tag based on the index. * This "tag" field has no "modified" complement. */ function getTag(transaction: OnyxEntry, tagIndex?: number): string { if (tagIndex !== undefined) { - return transaction?.tag?.split(CONST.COLON)[tagIndex] ?? ''; + const tagsArray = getTagArrayFromName(transaction?.tag ?? ''); + return tagsArray[tagIndex] ?? ''; } return transaction?.tag ?? ''; @@ -606,6 +634,7 @@ export { getBillable, getTag, getTransactionViolations, + getTagArrayFromName, getLinkedTransaction, getAllReportTransactions, hasReceipt, diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index a1cd001badee..faefc553026b 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -6,6 +6,7 @@ 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 * as TransactionUtils from '../TransactionUtils'; const ViolationsUtils = { /** @@ -50,7 +51,7 @@ const ViolationsUtils = { } if (policyRequiresTags) { - const selectedTags = updatedTransaction.tag?.split(CONST.COLON) ?? []; + const selectedTags = TransactionUtils.getTagArrayFromName(updatedTransaction.tag ?? '') ?? []; const policyTagKeys = Object.keys(policyTagList); if (policyTagKeys.length === 0) { diff --git a/src/libs/actions/Policy.ts b/src/libs/actions/Policy.ts index 9e6745bbc291..6f8421ace41a 100644 --- a/src/libs/actions/Policy.ts +++ b/src/libs/actions/Policy.ts @@ -1633,8 +1633,8 @@ function buildOptimisticPolicyRecentlyUsedCategories(policyID?: string, category return lodashUnion([category], policyRecentlyUsedCategories); } -function buildOptimisticPolicyRecentlyUsedTags(policyID?: string, reportTags?: string): RecentlyUsedTags { - if (!policyID || !reportTags) { +function buildOptimisticPolicyRecentlyUsedTags(policyID?: string, transactionTags?: string): RecentlyUsedTags { + if (!policyID || !transactionTags) { return {}; } @@ -1643,7 +1643,7 @@ function buildOptimisticPolicyRecentlyUsedTags(policyID?: string, reportTags?: s const policyRecentlyUsedTags = allRecentlyUsedTags?.[`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`] ?? {}; const newOptimisticPolicyRecentlyUsedTags: RecentlyUsedTags = {}; - reportTags.split(CONST.COLON).forEach((tag, index) => { + TransactionUtils.getTagArrayFromName(transactionTags).forEach((tag, index) => { if (!tag) { return; } diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index 29917154a527..d52436fbbf4f 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -135,7 +135,7 @@ function EditRequestPage({report, route, policy, policyCategories, policyTags, p IOU.updateMoneyRequestTag( transaction.transactionID, report.reportID, - IOUUtils.insertTagIntoReportTagsString(transactionTag, updatedTag, tagIndex), + IOUUtils.insertTagIntoTransactionTagsString(transactionTag, updatedTag, tagIndex), policy, policyTags, policyCategories, diff --git a/src/pages/iou/request/step/IOURequestStepTag.js b/src/pages/iou/request/step/IOURequestStepTag.js index 20ab92d3d446..572663160090 100644 --- a/src/pages/iou/request/step/IOURequestStepTag.js +++ b/src/pages/iou/request/step/IOURequestStepTag.js @@ -82,7 +82,7 @@ function IOURequestStepTag({ */ const updateTag = (selectedTag) => { const isSelectedTag = selectedTag.searchText === tag; - const updatedTag = IOUUtils.insertTagIntoReportTagsString(transactionTag, isSelectedTag ? '' : selectedTag.searchText, tagIndex); + const updatedTag = IOUUtils.insertTagIntoTransactionTagsString(transactionTag, isSelectedTag ? '' : selectedTag.searchText, tagIndex); if (isSplitBill && isEditing) { IOU.setDraftSplitTransaction(transactionID, {tag: updatedTag}); navigateBack(); From b1ec77c430946e4fed372be6b865cdb85550dada Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Tue, 20 Feb 2024 16:45:09 -0800 Subject: [PATCH 2/5] Linter --- src/libs/Violations/ViolationsUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index faefc553026b..73867bce800d 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -6,7 +6,7 @@ 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 * as TransactionUtils from '../TransactionUtils'; +import * as TransactionUtils from '@libs/TransactionUtils'; const ViolationsUtils = { /** From 0095f2cd4bddfa5019bcf55a5aa30619e6ad0452 Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Tue, 20 Feb 2024 16:58:27 -0800 Subject: [PATCH 3/5] Escape leading slash when displaying tag name --- src/components/ReportActionItem/MoneyRequestView.tsx | 3 ++- src/libs/TransactionUtils.ts | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index d3c86698f910..a01ef3b9bea7 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -38,6 +38,7 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction'; import ReportActionItemImage from './ReportActionItemImage'; +import {getTagForDisplay} from "@libs/TransactionUtils"; type MoneyRequestViewTransactionOnyxProps = { /** The transaction associated with the transactionThread */ @@ -379,7 +380,7 @@ function MoneyRequestView({ > , tagIndex?: number): string return transaction?.tag ?? ''; } +function getTagForDisplay(transaction: OnyxEntry, tagIndex?: number): string { + return _.unescape(getTag(transaction, tagIndex).replace(/[\\\\]:/g, ':')); +} + /** * Return the created field from the transaction, return the modifiedCreated if present. */ @@ -633,8 +637,9 @@ export { getCategory, getBillable, getTag, - getTransactionViolations, getTagArrayFromName, + getTagForDisplay, + getTransactionViolations, getLinkedTransaction, getAllReportTransactions, hasReceipt, From 13583b5a8e82a9274a8303ed7e8192d616c3a01e Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Tue, 20 Feb 2024 17:04:38 -0800 Subject: [PATCH 4/5] Prettier --- src/components/ReportActionItem/MoneyRequestView.tsx | 1 - src/libs/TransactionUtils.ts | 2 +- src/libs/Violations/ViolationsUtils.ts | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ReportActionItem/MoneyRequestView.tsx b/src/components/ReportActionItem/MoneyRequestView.tsx index a01ef3b9bea7..84a734846ce7 100644 --- a/src/components/ReportActionItem/MoneyRequestView.tsx +++ b/src/components/ReportActionItem/MoneyRequestView.tsx @@ -38,7 +38,6 @@ import ROUTES from '@src/ROUTES'; import type * as OnyxTypes from '@src/types/onyx'; import type {TransactionPendingFieldsKey} from '@src/types/onyx/Transaction'; import ReportActionItemImage from './ReportActionItemImage'; -import {getTagForDisplay} from "@libs/TransactionUtils"; type MoneyRequestViewTransactionOnyxProps = { /** The transaction associated with the transactionThread */ diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index 0c33f52b8c89..3ff2c39859c2 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -405,7 +405,7 @@ function getTag(transaction: OnyxEntry, tagIndex?: number): string } function getTagForDisplay(transaction: OnyxEntry, tagIndex?: number): string { - return _.unescape(getTag(transaction, tagIndex).replace(/[\\\\]:/g, ':')); + return getTag(transaction, tagIndex).replace(/[\\\\]:/g, ':'); } /** diff --git a/src/libs/Violations/ViolationsUtils.ts b/src/libs/Violations/ViolationsUtils.ts index 73867bce800d..16b428549156 100644 --- a/src/libs/Violations/ViolationsUtils.ts +++ b/src/libs/Violations/ViolationsUtils.ts @@ -2,11 +2,11 @@ import reject from 'lodash/reject'; import Onyx from 'react-native-onyx'; import type {OnyxUpdate} from 'react-native-onyx'; import type {Phrase, PhraseParameters} from '@libs/Localize'; +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 * as TransactionUtils from '@libs/TransactionUtils'; const ViolationsUtils = { /** From ddb29cc82c642f760ad34c9c8bd9170211edb0f9 Mon Sep 17 00:00:00 2001 From: Yuwen Memon Date: Wed, 21 Feb 2024 09:29:16 -0800 Subject: [PATCH 5/5] Add get tag for display in MoneyTemporaryForRefactorRequestConfirmationList --- .../MoneyTemporaryForRefactorRequestConfirmationList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js index 3939e847707d..291c32511bfd 100755 --- a/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js +++ b/src/components/MoneyTemporaryForRefactorRequestConfirmationList.js @@ -763,7 +763,7 @@ function MoneyTemporaryForRefactorRequestConfirmationList({