-
Notifications
You must be signed in to change notification settings - Fork 3k
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
ReportAction text for transactions edited in OldDot #30603
Merged
Merged
Changes from all commits
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
94e2dee
ReportAction text for transactions edited in OldDot
cristipaval 6e5d6b0
Make Lint happy.
cristipaval a7f3f38
Run prettier.
cristipaval a445ea6
Merge remote-tracking branch 'origin/main' into cristi_modified-expen…
cristipaval a0a856c
Improve message for MODIFIEDEXPENSE action
cristipaval 960d00a
Add a safety check
cristipaval a4e82a8
Improve MODIFIEDEXPENSE action message
cristipaval b9b7ef4
Improve MODIFIEDEXPENSE action message
cristipaval 5190539
Remove redundancy.
cristipaval b5518be
Update function doc
cristipaval be978f9
Create reusable function
cristipaval b31ba92
Run prettier
cristipaval 376944c
Fix lint.
cristipaval b9f4243
Update src/libs/ReportUtils.js
cristipaval 16df2d9
Merge remote-tracking branch 'origin/main' into cristi_modified-expen…
cristipaval bab1de4
Move logic in a separate unit
cristipaval 4ea44ee
Move policy tags logic to PolicyUtils
cristipaval b9229a7
Better naming
cristipaval 72714ad
Dry up code.
cristipaval 18d1bf0
Run prettier
cristipaval 5444abd
Fix lint errors
cristipaval 371f138
Make it a ts file.
cristipaval ceaa915
Migrate to TS
cristipaval 3bec4fd
Make Lint happy.
cristipaval b350c6b
Update src/libs/ModifiedExpenseMessage.ts
cristipaval 03931a2
Update src/libs/ModifiedExpenseMessage.ts
cristipaval 4e9a118
Update src/libs/ModifiedExpenseMessage.ts
cristipaval d855c90
Merge remote-tracking branch 'origin/main' into cristi_modified-expen…
cristipaval 41f8a94
Resolve conflicts after merge.
cristipaval ceff5c1
Move policyTags to ModifiedExpenseMessage
cristipaval 57f0837
Remove unused function.
cristipaval 7dd7afb
Make lint happy.
cristipaval 1cb7f47
Better checks.
cristipaval 388962f
Update src/libs/ReportUtils.ts
cristipaval 9cc7637
Update src/libs/ModifiedExpenseMessage.ts
cristipaval 60a1493
Improve function doc.
cristipaval 8dd3c99
Add return type declaration
cristipaval 4606a46
Merge remote-tracking branch 'origin/main' into cristi_modified-expen…
cristipaval 0d83c68
Merge remote-tracking branch 'origin/main' into cristi_modified-expen…
cristipaval a136b74
Fix conflicts after merge
cristipaval 262cb52
RUn prettier
cristipaval cd28c61
Performance test for ModifiedExpenseMessage
cristipaval 5219b6a
Fix typecheck failures
cristipaval df90850
Unit test for ModifiedExpenseMessage
cristipaval db1f935
More tests.
cristipaval 8babd0e
One more test
cristipaval 02c09f2
One more test
cristipaval a6a28a6
3 more tests
cristipaval 27945e8
3 more tests
cristipaval 8aad9bd
Make lint happy an run prettier
cristipaval d22c617
Merge remote-tracking branch 'origin/main' into cristi_modified-expen…
cristipaval 13f7b9c
Add changes from main
cristipaval File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,226 @@ | ||||||||||||||
import {format} from 'date-fns'; | ||||||||||||||
import Onyx from 'react-native-onyx'; | ||||||||||||||
import CONST from '@src/CONST'; | ||||||||||||||
import ONYXKEYS from '@src/ONYXKEYS'; | ||||||||||||||
import {PolicyTags, ReportAction} from '@src/types/onyx'; | ||||||||||||||
import * as CurrencyUtils from './CurrencyUtils'; | ||||||||||||||
import * as Localize from './Localize'; | ||||||||||||||
import * as PolicyUtils from './PolicyUtils'; | ||||||||||||||
import * as ReportUtils from './ReportUtils'; | ||||||||||||||
import {ExpenseOriginalMessage} from './ReportUtils'; | ||||||||||||||
|
||||||||||||||
let allPolicyTags: Record<string, PolicyTags | null> = {}; | ||||||||||||||
Onyx.connect({ | ||||||||||||||
key: ONYXKEYS.COLLECTION.POLICY_TAGS, | ||||||||||||||
waitForCollectionCallback: true, | ||||||||||||||
callback: (value) => { | ||||||||||||||
if (!value) { | ||||||||||||||
allPolicyTags = {}; | ||||||||||||||
return; | ||||||||||||||
} | ||||||||||||||
allPolicyTags = value; | ||||||||||||||
}, | ||||||||||||||
}); | ||||||||||||||
|
||||||||||||||
/** | ||||||||||||||
* Builds the partial message fragment for a modified field on the expense. | ||||||||||||||
*/ | ||||||||||||||
function buildMessageFragmentForValue( | ||||||||||||||
newValue: string, | ||||||||||||||
oldValue: string, | ||||||||||||||
valueName: string, | ||||||||||||||
valueInQuotes: boolean, | ||||||||||||||
setFragments: string[], | ||||||||||||||
removalFragments: string[], | ||||||||||||||
changeFragments: string[], | ||||||||||||||
shouldConvertToLowercase = true, | ||||||||||||||
) { | ||||||||||||||
const newValueToDisplay = valueInQuotes ? `"${newValue}"` : newValue; | ||||||||||||||
const oldValueToDisplay = valueInQuotes ? `"${oldValue}"` : oldValue; | ||||||||||||||
const displayValueName = shouldConvertToLowercase ? valueName.toLowerCase() : valueName; | ||||||||||||||
|
||||||||||||||
if (!oldValue) { | ||||||||||||||
const fragment = Localize.translateLocal('iou.setTheRequest', {valueName: displayValueName, newValueToDisplay}); | ||||||||||||||
setFragments.push(fragment); | ||||||||||||||
} else if (!newValue) { | ||||||||||||||
const fragment = Localize.translateLocal('iou.removedTheRequest', {valueName: displayValueName, oldValueToDisplay}); | ||||||||||||||
removalFragments.push(fragment); | ||||||||||||||
} else { | ||||||||||||||
const fragment = Localize.translateLocal('iou.updatedTheRequest', {valueName: displayValueName, newValueToDisplay, oldValueToDisplay}); | ||||||||||||||
changeFragments.push(fragment); | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/** | ||||||||||||||
* Get the message line for a modified expense. | ||||||||||||||
*/ | ||||||||||||||
function getMessageLine(prefix: string, messageFragments: string[]): string { | ||||||||||||||
if (messageFragments.length === 0) { | ||||||||||||||
return ''; | ||||||||||||||
} | ||||||||||||||
return messageFragments.reduce((acc, value, index) => { | ||||||||||||||
if (index === messageFragments.length - 1) { | ||||||||||||||
if (messageFragments.length === 1) { | ||||||||||||||
return `${acc} ${value}.`; | ||||||||||||||
} | ||||||||||||||
if (messageFragments.length === 2) { | ||||||||||||||
return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; | ||||||||||||||
} | ||||||||||||||
return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; | ||||||||||||||
} | ||||||||||||||
if (index === 0) { | ||||||||||||||
return `${acc} ${value}`; | ||||||||||||||
} | ||||||||||||||
return `${acc}, ${value}`; | ||||||||||||||
}, prefix); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
function getForDistanceRequest(newDistance: string, oldDistance: string, newAmount: string, oldAmount: string): string { | ||||||||||||||
if (!oldDistance) { | ||||||||||||||
return Localize.translateLocal('iou.setTheDistance', {newDistanceToDisplay: newDistance, newAmountToDisplay: newAmount}); | ||||||||||||||
} | ||||||||||||||
return Localize.translateLocal('iou.updatedTheDistance', { | ||||||||||||||
newDistanceToDisplay: newDistance, | ||||||||||||||
oldDistanceToDisplay: oldDistance, | ||||||||||||||
newAmountToDisplay: newAmount, | ||||||||||||||
oldAmountToDisplay: oldAmount, | ||||||||||||||
}); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
/** | ||||||||||||||
* Get the report action message when expense has been modified. | ||||||||||||||
* | ||||||||||||||
* ModifiedExpense::getNewDotComment in Web-Expensify should match this. | ||||||||||||||
* If we change this function be sure to update the backend as well. | ||||||||||||||
*/ | ||||||||||||||
function getForReportAction(reportAction: ReportAction): string { | ||||||||||||||
if (reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE) { | ||||||||||||||
return ''; | ||||||||||||||
} | ||||||||||||||
const reportActionOriginalMessage = reportAction.originalMessage as ExpenseOriginalMessage | undefined; | ||||||||||||||
const policyID = ReportUtils.getReportPolicyID(reportAction.reportID) ?? ''; | ||||||||||||||
const policyTags = allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {}; | ||||||||||||||
const policyTagListName = PolicyUtils.getTagListName(policyTags) || Localize.translateLocal('common.tag'); | ||||||||||||||
|
||||||||||||||
const removalFragments: string[] = []; | ||||||||||||||
const setFragments: string[] = []; | ||||||||||||||
const changeFragments: string[] = []; | ||||||||||||||
|
||||||||||||||
const hasModifiedAmount = | ||||||||||||||
reportActionOriginalMessage && | ||||||||||||||
'oldAmount' in reportActionOriginalMessage && | ||||||||||||||
'oldCurrency' in reportActionOriginalMessage && | ||||||||||||||
'amount' in reportActionOriginalMessage && | ||||||||||||||
'currency' in reportActionOriginalMessage; | ||||||||||||||
|
||||||||||||||
const hasModifiedMerchant = reportActionOriginalMessage && 'oldMerchant' in reportActionOriginalMessage && 'merchant' in reportActionOriginalMessage; | ||||||||||||||
if (hasModifiedAmount) { | ||||||||||||||
const oldCurrency = reportActionOriginalMessage?.oldCurrency ?? ''; | ||||||||||||||
const oldAmount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage?.oldAmount ?? 0, oldCurrency); | ||||||||||||||
|
||||||||||||||
const currency = reportActionOriginalMessage?.currency ?? ''; | ||||||||||||||
const amount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage?.amount ?? 0, currency); | ||||||||||||||
|
||||||||||||||
// Only Distance edits should modify amount and merchant (which stores distance) in a single transaction. | ||||||||||||||
// We check the merchant is in distance format (includes @) as a sanity check | ||||||||||||||
if (hasModifiedMerchant && (reportActionOriginalMessage?.merchant ?? '').includes('@')) { | ||||||||||||||
return getForDistanceRequest(reportActionOriginalMessage?.merchant ?? '', reportActionOriginalMessage?.oldMerchant ?? '', amount, oldAmount); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
buildMessageFragmentForValue(amount, oldAmount, Localize.translateLocal('iou.amount'), false, setFragments, removalFragments, changeFragments); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
const hasModifiedComment = reportActionOriginalMessage && 'oldComment' in reportActionOriginalMessage && 'newComment' in reportActionOriginalMessage; | ||||||||||||||
if (hasModifiedComment) { | ||||||||||||||
buildMessageFragmentForValue( | ||||||||||||||
reportActionOriginalMessage?.newComment ?? '', | ||||||||||||||
reportActionOriginalMessage?.oldComment ?? '', | ||||||||||||||
Localize.translateLocal('common.description'), | ||||||||||||||
true, | ||||||||||||||
setFragments, | ||||||||||||||
removalFragments, | ||||||||||||||
changeFragments, | ||||||||||||||
); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
const hasModifiedCreated = reportActionOriginalMessage && 'oldCreated' in reportActionOriginalMessage && 'created' in reportActionOriginalMessage; | ||||||||||||||
if (hasModifiedCreated) { | ||||||||||||||
// Take only the YYYY-MM-DD value as the original date includes timestamp | ||||||||||||||
let formattedOldCreated: Date | string = new Date(reportActionOriginalMessage?.oldCreated ? reportActionOriginalMessage.oldCreated : 0); | ||||||||||||||
formattedOldCreated = format(formattedOldCreated, CONST.DATE.FNS_FORMAT_STRING); | ||||||||||||||
buildMessageFragmentForValue( | ||||||||||||||
reportActionOriginalMessage?.created ?? '', | ||||||||||||||
formattedOldCreated, | ||||||||||||||
Localize.translateLocal('common.date'), | ||||||||||||||
false, | ||||||||||||||
setFragments, | ||||||||||||||
removalFragments, | ||||||||||||||
changeFragments, | ||||||||||||||
); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
if (hasModifiedMerchant) { | ||||||||||||||
buildMessageFragmentForValue( | ||||||||||||||
reportActionOriginalMessage?.merchant ?? '', | ||||||||||||||
reportActionOriginalMessage?.oldMerchant ?? '', | ||||||||||||||
Localize.translateLocal('common.merchant'), | ||||||||||||||
true, | ||||||||||||||
setFragments, | ||||||||||||||
removalFragments, | ||||||||||||||
changeFragments, | ||||||||||||||
); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
const hasModifiedCategory = reportActionOriginalMessage && 'oldCategory' in reportActionOriginalMessage && 'category' in reportActionOriginalMessage; | ||||||||||||||
if (hasModifiedCategory) { | ||||||||||||||
buildMessageFragmentForValue( | ||||||||||||||
reportActionOriginalMessage?.category ?? '', | ||||||||||||||
reportActionOriginalMessage?.oldCategory ?? '', | ||||||||||||||
Localize.translateLocal('common.category'), | ||||||||||||||
true, | ||||||||||||||
setFragments, | ||||||||||||||
removalFragments, | ||||||||||||||
changeFragments, | ||||||||||||||
); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
const hasModifiedTag = reportActionOriginalMessage && 'oldTag' in reportActionOriginalMessage && 'tag' in reportActionOriginalMessage; | ||||||||||||||
if (hasModifiedTag) { | ||||||||||||||
buildMessageFragmentForValue( | ||||||||||||||
reportActionOriginalMessage?.tag ?? '', | ||||||||||||||
reportActionOriginalMessage?.oldTag ?? '', | ||||||||||||||
policyTagListName, | ||||||||||||||
true, | ||||||||||||||
setFragments, | ||||||||||||||
removalFragments, | ||||||||||||||
changeFragments, | ||||||||||||||
policyTagListName === Localize.translateLocal('common.tag'), | ||||||||||||||
); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
const hasModifiedBillable = reportActionOriginalMessage && 'oldBillable' in reportActionOriginalMessage && 'billable' in reportActionOriginalMessage; | ||||||||||||||
if (hasModifiedBillable) { | ||||||||||||||
buildMessageFragmentForValue( | ||||||||||||||
reportActionOriginalMessage?.billable ?? '', | ||||||||||||||
reportActionOriginalMessage?.oldBillable ?? '', | ||||||||||||||
Localize.translateLocal('iou.request'), | ||||||||||||||
true, | ||||||||||||||
setFragments, | ||||||||||||||
removalFragments, | ||||||||||||||
changeFragments, | ||||||||||||||
); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
const message = | ||||||||||||||
getMessageLine(`\n${Localize.translateLocal('iou.changed')}`, changeFragments) + | ||||||||||||||
getMessageLine(`\n${Localize.translateLocal('iou.set')}`, setFragments) + | ||||||||||||||
getMessageLine(`\n${Localize.translateLocal('iou.removed')}`, removalFragments); | ||||||||||||||
if (message === '') { | ||||||||||||||
return Localize.translateLocal('iou.changedTheRequest'); | ||||||||||||||
} | ||||||||||||||
return `${message.substring(1, message.length)}`; | ||||||||||||||
Comment on lines
+218
to
+221
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.
Suggested change
|
||||||||||||||
} | ||||||||||||||
|
||||||||||||||
export default { | ||||||||||||||
getForReportAction, | ||||||||||||||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MODIFIEDEXPENSE
report actions don't have thereportID
property, so we fail to get thepolicyTagListName
here. This caused #33493.