From 94e2deee606832478f5d28c22e4bc4226f7b8620 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 30 Oct 2023 20:45:04 +0200 Subject: [PATCH 01/46] ReportAction text for transactions edited in OldDot --- src/libs/ReportUtils.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 0e9091fd6cb2..d14336256894 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1844,6 +1844,8 @@ function getModifiedExpenseMessage(reportAction) { return Localize.translateLocal('iou.changedTheRequest'); } + const messageFragments = []; + const hasModifiedAmount = _.has(reportActionOriginalMessage, 'oldAmount') && _.has(reportActionOriginalMessage, 'oldCurrency') && @@ -1864,12 +1866,12 @@ function getModifiedExpenseMessage(reportAction) { return getProperSchemaForModifiedDistanceMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, amount, oldAmount); } - return getProperSchemaForModifiedExpenseMessage(amount, oldAmount, Localize.translateLocal('iou.amount'), false); + messageFragments.push(getProperSchemaForModifiedExpenseMessage(amount, oldAmount, Localize.translateLocal('iou.amount'), false)); } const hasModifiedComment = _.has(reportActionOriginalMessage, 'oldComment') && _.has(reportActionOriginalMessage, 'newComment'); if (hasModifiedComment) { - return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, Localize.translateLocal('common.description'), true); + messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, Localize.translateLocal('common.description'), true)); } const hasModifiedCreated = _.has(reportActionOriginalMessage, 'oldCreated') && _.has(reportActionOriginalMessage, 'created'); @@ -1877,27 +1879,34 @@ function getModifiedExpenseMessage(reportAction) { // Take only the YYYY-MM-DD value as the original date includes timestamp let formattedOldCreated = new Date(reportActionOriginalMessage.oldCreated); formattedOldCreated = format(formattedOldCreated, CONST.DATE.FNS_FORMAT_STRING); - return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false); + messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false)); } if (hasModifiedMerchant) { - return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, Localize.translateLocal('common.merchant'), true); + messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, Localize.translateLocal('common.merchant'), true)); } const hasModifiedCategory = _.has(reportActionOriginalMessage, 'oldCategory') && _.has(reportActionOriginalMessage, 'category'); if (hasModifiedCategory) { - return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), true); + messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), true)); } const hasModifiedTag = _.has(reportActionOriginalMessage, 'oldTag') && _.has(reportActionOriginalMessage, 'tag'); if (hasModifiedTag) { - return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.tag, reportActionOriginalMessage.oldTag, Localize.translateLocal('common.tag'), true); + messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.tag, reportActionOriginalMessage.oldTag, Localize.translateLocal('common.tag'), true)); } const hasModifiedBillable = _.has(reportActionOriginalMessage, 'oldBillable') && _.has(reportActionOriginalMessage, 'billable'); if (hasModifiedBillable) { - return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.billable, reportActionOriginalMessage.oldBillable, Localize.translateLocal('iou.request'), true); + messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.billable, reportActionOriginalMessage.oldBillable, Localize.translateLocal('iou.request'), true)); } + + return messageFragments.reduce((acc, value, index) => { + if (index == 0) { + return acc + value; + } + return acc + ". " + value.charAt(0).toUpperCase() + value.slice(1); + }, ""); } /** From 6e5d6b04de5cfe67f3179ad65cb4d0d2340e3201 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 30 Oct 2023 21:02:22 +0200 Subject: [PATCH 02/46] Make Lint happy. --- src/libs/ReportUtils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index d14336256894..3e8860543d5f 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1902,10 +1902,10 @@ function getModifiedExpenseMessage(reportAction) { } return messageFragments.reduce((acc, value, index) => { - if (index == 0) { + if (index === 0) { return acc + value; } - return acc + ". " + value.charAt(0).toUpperCase() + value.slice(1); + return `${acc}. ${value.charAt(0).toUpperCase()}${value.slice(1)}`; }, ""); } From a7f3f383524cf5d3b1aef2a31006916aacb56e10 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 30 Oct 2023 21:07:35 +0200 Subject: [PATCH 03/46] Run prettier. --- src/libs/ReportUtils.js | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 3e8860543d5f..49bf6a5f6310 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1871,7 +1871,9 @@ function getModifiedExpenseMessage(reportAction) { const hasModifiedComment = _.has(reportActionOriginalMessage, 'oldComment') && _.has(reportActionOriginalMessage, 'newComment'); if (hasModifiedComment) { - messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, Localize.translateLocal('common.description'), true)); + messageFragments.push( + getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, Localize.translateLocal('common.description'), true), + ); } const hasModifiedCreated = _.has(reportActionOriginalMessage, 'oldCreated') && _.has(reportActionOriginalMessage, 'created'); @@ -1883,12 +1885,16 @@ function getModifiedExpenseMessage(reportAction) { } if (hasModifiedMerchant) { - messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, Localize.translateLocal('common.merchant'), true)); + messageFragments.push( + getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, Localize.translateLocal('common.merchant'), true), + ); } const hasModifiedCategory = _.has(reportActionOriginalMessage, 'oldCategory') && _.has(reportActionOriginalMessage, 'category'); if (hasModifiedCategory) { - messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), true)); + messageFragments.push( + getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), true), + ); } const hasModifiedTag = _.has(reportActionOriginalMessage, 'oldTag') && _.has(reportActionOriginalMessage, 'tag'); @@ -1898,15 +1904,17 @@ function getModifiedExpenseMessage(reportAction) { const hasModifiedBillable = _.has(reportActionOriginalMessage, 'oldBillable') && _.has(reportActionOriginalMessage, 'billable'); if (hasModifiedBillable) { - messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.billable, reportActionOriginalMessage.oldBillable, Localize.translateLocal('iou.request'), true)); + messageFragments.push( + getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.billable, reportActionOriginalMessage.oldBillable, Localize.translateLocal('iou.request'), true), + ); } - + return messageFragments.reduce((acc, value, index) => { if (index === 0) { return acc + value; } return `${acc}. ${value.charAt(0).toUpperCase()}${value.slice(1)}`; - }, ""); + }, ''); } /** From a0a856cddc840617f1f5fd33416766b4b0d502f5 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 8 Nov 2023 00:07:47 +0200 Subject: [PATCH 04/46] Improve message for MODIFIEDEXPENSE action --- src/languages/en.ts | 9 ++-- src/languages/es.ts | 9 ++-- src/libs/ReportUtils.js | 99 ++++++++++++++++++++++++++++++++--------- 3 files changed, 89 insertions(+), 28 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index d99b3c7d04d1..919548a3d918 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -573,11 +573,11 @@ export default { noReimbursableExpenses: 'This report has an invalid amount', pendingConversionMessage: "Total will update when you're back online", changedTheRequest: 'changed the request', - setTheRequest: ({valueName, newValueToDisplay}: SetTheRequestParams) => `set the ${valueName} to ${newValueToDisplay}`, + setTheRequest: ({valueName, newValueToDisplay}: SetTheRequestParams) => `the ${valueName} to ${newValueToDisplay}`, setTheDistance: ({newDistanceToDisplay, newAmountToDisplay}: SetTheDistanceParams) => `set the distance to ${newDistanceToDisplay}, which set the amount to ${newAmountToDisplay}`, - removedTheRequest: ({valueName, oldValueToDisplay}: RemovedTheRequestParams) => `removed the ${valueName} (previously ${oldValueToDisplay})`, + removedTheRequest: ({valueName, oldValueToDisplay}: RemovedTheRequestParams) => `the ${valueName} (previously ${oldValueToDisplay})`, updatedTheRequest: ({valueName, newValueToDisplay, oldValueToDisplay}: UpdatedTheRequestParams) => - `changed the ${valueName} to ${newValueToDisplay} (previously ${oldValueToDisplay})`, + `the ${valueName} to ${newValueToDisplay} (previously ${oldValueToDisplay})`, updatedTheDistance: ({newDistanceToDisplay, oldDistanceToDisplay, newAmountToDisplay, oldAmountToDisplay}: UpdatedTheDistanceParams) => `changed the distance to ${newDistanceToDisplay} (previously ${oldDistanceToDisplay}), which updated the amount to ${newAmountToDisplay} (previously ${oldAmountToDisplay})`, threadRequestReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `${formattedAmount} request${comment ? ` for ${comment}` : ''}`, @@ -597,6 +597,9 @@ export default { }, waitingOnEnabledWallet: ({submitterDisplayName}: WaitingOnBankAccountParams) => `Started settling up, payment is held until ${submitterDisplayName} enables their Wallet`, enableWallet: 'Enable Wallet', + set: 'set', + changed: 'changed', + removed: 'removed', }, notificationPreferencesPage: { header: 'Notification preferences', diff --git a/src/languages/es.ts b/src/languages/es.ts index dea7760a35ce..8d5f678c63e8 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -565,13 +565,13 @@ export default { noReimbursableExpenses: 'El importe de este informe no es válido', pendingConversionMessage: 'El total se actualizará cuando estés online', changedTheRequest: 'cambió la solicitud', - setTheRequest: ({valueName, newValueToDisplay}: SetTheRequestParams) => `estableció ${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} a ${newValueToDisplay}`, + setTheRequest: ({valueName, newValueToDisplay}: SetTheRequestParams) => `${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} a ${newValueToDisplay}`, setTheDistance: ({newDistanceToDisplay, newAmountToDisplay}: SetTheDistanceParams) => `estableció la distancia a ${newDistanceToDisplay}, lo que estableció el importe a ${newAmountToDisplay}`, removedTheRequest: ({valueName, oldValueToDisplay}: RemovedTheRequestParams) => - `eliminó ${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} (previamente ${oldValueToDisplay})`, + `${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} (previamente ${oldValueToDisplay})`, updatedTheRequest: ({valueName, newValueToDisplay, oldValueToDisplay}: UpdatedTheRequestParams) => - `cambió ${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} a ${newValueToDisplay} (previamente ${oldValueToDisplay})`, + `${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} a ${newValueToDisplay} (previamente ${oldValueToDisplay})`, updatedTheDistance: ({newDistanceToDisplay, oldDistanceToDisplay, newAmountToDisplay, oldAmountToDisplay}: UpdatedTheDistanceParams) => `cambió la distancia a ${newDistanceToDisplay} (previamente ${oldDistanceToDisplay}), lo que cambió el importe a ${newAmountToDisplay} (previamente ${oldAmountToDisplay})`, threadRequestReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `Solicitud de ${formattedAmount}${comment ? ` para ${comment}` : ''}`, @@ -591,6 +591,9 @@ export default { }, waitingOnEnabledWallet: ({submitterDisplayName}: WaitingOnBankAccountParams) => `Inició el pago, pero no se procesará hasta que ${submitterDisplayName} active su Billetera`, enableWallet: 'Habilitar Billetera', + set: 'estableció', + changed: 'cambió', + removed: 'eliminó', }, notificationPreferencesPage: { header: 'Preferencias de avisos', diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 1297171d3149..9f4b50965f3e 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1917,7 +1917,9 @@ function getModifiedExpenseMessage(reportAction) { return Localize.translateLocal('iou.changedTheRequest'); } - const messageFragments = []; + const removalFragments = []; + const setFragments = []; + const changeFragments = []; const hasModifiedAmount = _.has(reportActionOriginalMessage, 'oldAmount') && @@ -1939,14 +1941,26 @@ function getModifiedExpenseMessage(reportAction) { return getProperSchemaForModifiedDistanceMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, amount, oldAmount); } - messageFragments.push(getProperSchemaForModifiedExpenseMessage(amount, oldAmount, Localize.translateLocal('iou.amount'), false)); + const fragment = getProperSchemaForModifiedExpenseMessage(amount, oldAmount, Localize.translateLocal('iou.amount'), false); + if (!oldAmount) { + setFragments.push(fragment); + } else if (!amount) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } } const hasModifiedComment = _.has(reportActionOriginalMessage, 'oldComment') && _.has(reportActionOriginalMessage, 'newComment'); if (hasModifiedComment) { - messageFragments.push( - getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, Localize.translateLocal('common.description'), true), - ); + const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, Localize.translateLocal('common.description'), true); + if (!reportActionOriginalMessage.oldComment) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.newComment) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } } const hasModifiedCreated = _.has(reportActionOriginalMessage, 'oldCreated') && _.has(reportActionOriginalMessage, 'created'); @@ -1954,40 +1968,81 @@ function getModifiedExpenseMessage(reportAction) { // Take only the YYYY-MM-DD value as the original date includes timestamp let formattedOldCreated = new Date(reportActionOriginalMessage.oldCreated); formattedOldCreated = format(formattedOldCreated, CONST.DATE.FNS_FORMAT_STRING); - messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false)); + const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false); + if (!formattedOldCreated) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.created) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } } if (hasModifiedMerchant) { - messageFragments.push( - getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, Localize.translateLocal('common.merchant'), true), - ); + const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, Localize.translateLocal('common.merchant'), true); + if (!reportActionOriginalMessage.oldMerchant) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.merchant) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } } const hasModifiedCategory = _.has(reportActionOriginalMessage, 'oldCategory') && _.has(reportActionOriginalMessage, 'category'); if (hasModifiedCategory) { - messageFragments.push( - getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), true), - ); + const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), true); + if (!reportActionOriginalMessage.oldCategory) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.category) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } } const hasModifiedTag = _.has(reportActionOriginalMessage, 'oldTag') && _.has(reportActionOriginalMessage, 'tag'); if (hasModifiedTag) { - messageFragments.push(getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.tag, reportActionOriginalMessage.oldTag, Localize.translateLocal('common.tag'), true)); + const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.tag, reportActionOriginalMessage.oldTag, Localize.translateLocal('common.tag'), true); + if (!reportActionOriginalMessage.oldTag) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.tag) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } } const hasModifiedBillable = _.has(reportActionOriginalMessage, 'oldBillable') && _.has(reportActionOriginalMessage, 'billable'); if (hasModifiedBillable) { - messageFragments.push( - getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.billable, reportActionOriginalMessage.oldBillable, Localize.translateLocal('iou.request'), true), - ); + const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.billable, reportActionOriginalMessage.oldBillable, Localize.translateLocal('iou.request'), true); + if (!reportActionOriginalMessage.oldBillable) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.billable) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } } - return messageFragments.reduce((acc, value, index) => { - if (index === 0) { - return acc + value; - } - return `${acc}. ${value.charAt(0).toUpperCase()}${value.slice(1)}`; - }, ''); + let message = ''; + if (setFragments.length > 0) { + message = setFragments.reduce((acc, value) => { + return `${acc} ${value},`; + }, `${message} ${Localize.translateLocal('iou.set')}`); + } + if (changeFragments.length > 0) { + message = changeFragments.reduce((acc, value) => { + return `${acc} ${value},`; + }, `${message} ${Localize.translateLocal('iou.changed')}`); + } + if (removalFragments.length > 0) { + message = removalFragments.reduce((acc, value) => { + return `${acc} ${value},`; + }, `${message} ${Localize.translateLocal('iou.removed')}`); + } + message = `${message.substring(1, message.length - 1)}.`; + return message; } /** From 960d00a36d28f7f60966df3686d6d2be6f87db68 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 8 Nov 2023 00:09:28 +0200 Subject: [PATCH 05/46] Add a safety check --- src/libs/ReportUtils.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 9f4b50965f3e..97bc468de8eb 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2041,6 +2041,9 @@ function getModifiedExpenseMessage(reportAction) { return `${acc} ${value},`; }, `${message} ${Localize.translateLocal('iou.removed')}`); } + if (message === '') { + return message; + } message = `${message.substring(1, message.length - 1)}.`; return message; } From a4e82a8baaf2eabf78a40848dbaa28179ad96d89 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 8 Nov 2023 00:21:09 +0200 Subject: [PATCH 06/46] Improve MODIFIEDEXPENSE action message --- src/libs/ReportUtils.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 97bc468de8eb..a2de3dc73161 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2026,20 +2026,20 @@ function getModifiedExpenseMessage(reportAction) { } let message = ''; - if (setFragments.length > 0) { - message = setFragments.reduce((acc, value) => { + if (changeFragments.length > 0) { + message = changeFragments.reduce((acc, value, index) => { return `${acc} ${value},`; - }, `${message} ${Localize.translateLocal('iou.set')}`); + }, `${message}\n${Localize.translateLocal('iou.changed')}`); } - if (changeFragments.length > 0) { - message = changeFragments.reduce((acc, value) => { + if (setFragments.length > 0) { + message = setFragments.reduce((acc, value) => { return `${acc} ${value},`; - }, `${message} ${Localize.translateLocal('iou.changed')}`); + }, `${message}\n${Localize.translateLocal('iou.set')}`); } if (removalFragments.length > 0) { message = removalFragments.reduce((acc, value) => { return `${acc} ${value},`; - }, `${message} ${Localize.translateLocal('iou.removed')}`); + }, `${message}\n${Localize.translateLocal('iou.removed')}`); } if (message === '') { return message; From b9b7ef462310e69498e261137bc8ab619af75c98 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 8 Nov 2023 00:33:22 +0200 Subject: [PATCH 07/46] Improve MODIFIEDEXPENSE action message --- src/libs/ReportUtils.js | 43 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index a2de3dc73161..5680ea7b017a 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2028,17 +2028,50 @@ function getModifiedExpenseMessage(reportAction) { let message = ''; if (changeFragments.length > 0) { message = changeFragments.reduce((acc, value, index) => { - return `${acc} ${value},`; + if (index === changeFragments.length - 1) { + if (changeFragments.length === 1) { + return `${acc} ${value}.`; + } else if (changeFragments.length === 2) { + return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; + } else { + return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; + } + } else if (index === 0) { + return `${acc} ${value}`; + } + return `${acc}, ${value}`; }, `${message}\n${Localize.translateLocal('iou.changed')}`); } if (setFragments.length > 0) { - message = setFragments.reduce((acc, value) => { - return `${acc} ${value},`; + message = setFragments.reduce((acc, value, index) => { + if (index === setFragments.length - 1) { + if (setFragments.length === 1) { + return `${acc} ${value}.`; + } else if (setFragments.length === 2) { + return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; + } else { + return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; + } + } else if (index === 0) { + return `${acc} ${value}`; + } + return `${acc}, ${value}`; }, `${message}\n${Localize.translateLocal('iou.set')}`); } if (removalFragments.length > 0) { - message = removalFragments.reduce((acc, value) => { - return `${acc} ${value},`; + message = removalFragments.reduce((acc, value, index) => { + if (index === removalFragments.length - 1) { + if (removalFragments.length === 1) { + return `${acc} ${value}.`; + } else if (removalFragments.length === 2) { + return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; + } else { + return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; + } + } else if (index === 0) { + return `${acc} ${value}`; + } + return `${acc}, ${value}`; }, `${message}\n${Localize.translateLocal('iou.removed')}`); } if (message === '') { From 5190539d1b65224687b503204749623915271deb Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 8 Nov 2023 00:39:25 +0200 Subject: [PATCH 08/46] Remove redundancy. --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 5680ea7b017a..5004e5d87dc0 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -2077,7 +2077,7 @@ function getModifiedExpenseMessage(reportAction) { if (message === '') { return message; } - message = `${message.substring(1, message.length - 1)}.`; + message = `${message.substring(1, message.length)}`; return message; } From b5518be159aa4cea4aad09ee70ddb760e5b42245 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 8 Nov 2023 15:59:14 +0200 Subject: [PATCH 09/46] Update function doc --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 5004e5d87dc0..d5f56bea8c5c 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1857,7 +1857,7 @@ function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceip } /** - * Get the proper message schema for modified expense message. + * Get the proper message schema for a modified field on the expense. * * @param {String} newValue * @param {String} oldValue From be978f9b0138b1474094ae1a3d95ea35eefea982 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 8 Nov 2023 16:17:08 +0200 Subject: [PATCH 10/46] Create reusable function --- src/libs/ReportUtils.js | 84 +++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 50 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index d5f56bea8c5c..13ffeb6432f5 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1857,7 +1857,7 @@ function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceip } /** - * Get the proper message schema for a modified field on the expense. + * Get the proper message schema for a modified a field on the expense. * * @param {String} newValue * @param {String} oldValue @@ -1880,6 +1880,36 @@ function getProperSchemaForModifiedExpenseMessage(newValue, oldValue, valueName, return Localize.translateLocal('iou.updatedTheRequest', {valueName: displayValueName, newValueToDisplay, oldValueToDisplay}); } +/** + * Get the proper message line for a modified expense. + * + * @param {String} newValue + * @param {String} oldValue + * @param {String} valueName + * @param {Boolean} valueInQuotes + * @returns {String} + */ + +function getProperLineForModifiedExpenseMessage(prefix, messageFragments) { + if (messageFragments.length === 0) { + return ''; + } + return messageFragments.reduce((acc, value, index) => { + if (index === messageFragments.length - 1) { + if (messageFragments.length === 1) { + return `${acc} ${value}.`; + } else if (messageFragments.length === 2) { + return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; + } else { + return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; + } + } else if (index === 0) { + return `${acc} ${value}`; + } + return `${acc}, ${value}`; + }, prefix); +} + /** * Get the proper message schema for modified distance message. * @@ -2025,55 +2055,9 @@ function getModifiedExpenseMessage(reportAction) { } } - let message = ''; - if (changeFragments.length > 0) { - message = changeFragments.reduce((acc, value, index) => { - if (index === changeFragments.length - 1) { - if (changeFragments.length === 1) { - return `${acc} ${value}.`; - } else if (changeFragments.length === 2) { - return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; - } else { - return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; - } - } else if (index === 0) { - return `${acc} ${value}`; - } - return `${acc}, ${value}`; - }, `${message}\n${Localize.translateLocal('iou.changed')}`); - } - if (setFragments.length > 0) { - message = setFragments.reduce((acc, value, index) => { - if (index === setFragments.length - 1) { - if (setFragments.length === 1) { - return `${acc} ${value}.`; - } else if (setFragments.length === 2) { - return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; - } else { - return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; - } - } else if (index === 0) { - return `${acc} ${value}`; - } - return `${acc}, ${value}`; - }, `${message}\n${Localize.translateLocal('iou.set')}`); - } - if (removalFragments.length > 0) { - message = removalFragments.reduce((acc, value, index) => { - if (index === removalFragments.length - 1) { - if (removalFragments.length === 1) { - return `${acc} ${value}.`; - } else if (removalFragments.length === 2) { - return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; - } else { - return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; - } - } else if (index === 0) { - return `${acc} ${value}`; - } - return `${acc}, ${value}`; - }, `${message}\n${Localize.translateLocal('iou.removed')}`); - } + let message = getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.changed')}`, changeFragments) + + getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.set')}`, setFragments) + + getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.removed')}`, removalFragments); if (message === '') { return message; } From b31ba92326163585034ac04cd466d39765b7876b Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 8 Nov 2023 16:18:59 +0200 Subject: [PATCH 11/46] Run prettier --- src/languages/en.ts | 3 +-- src/languages/es.ts | 3 +-- src/libs/ReportUtils.js | 51 +++++++++++++++++++++++++++++------------ 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/languages/en.ts b/src/languages/en.ts index 919548a3d918..3be57af83cc5 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -576,8 +576,7 @@ export default { setTheRequest: ({valueName, newValueToDisplay}: SetTheRequestParams) => `the ${valueName} to ${newValueToDisplay}`, setTheDistance: ({newDistanceToDisplay, newAmountToDisplay}: SetTheDistanceParams) => `set the distance to ${newDistanceToDisplay}, which set the amount to ${newAmountToDisplay}`, removedTheRequest: ({valueName, oldValueToDisplay}: RemovedTheRequestParams) => `the ${valueName} (previously ${oldValueToDisplay})`, - updatedTheRequest: ({valueName, newValueToDisplay, oldValueToDisplay}: UpdatedTheRequestParams) => - `the ${valueName} to ${newValueToDisplay} (previously ${oldValueToDisplay})`, + updatedTheRequest: ({valueName, newValueToDisplay, oldValueToDisplay}: UpdatedTheRequestParams) => `the ${valueName} to ${newValueToDisplay} (previously ${oldValueToDisplay})`, updatedTheDistance: ({newDistanceToDisplay, oldDistanceToDisplay, newAmountToDisplay, oldAmountToDisplay}: UpdatedTheDistanceParams) => `changed the distance to ${newDistanceToDisplay} (previously ${oldDistanceToDisplay}), which updated the amount to ${newAmountToDisplay} (previously ${oldAmountToDisplay})`, threadRequestReportName: ({formattedAmount, comment}: ThreadRequestReportNameParams) => `${formattedAmount} request${comment ? ` for ${comment}` : ''}`, diff --git a/src/languages/es.ts b/src/languages/es.ts index 8d5f678c63e8..e2eb899a343a 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -568,8 +568,7 @@ export default { setTheRequest: ({valueName, newValueToDisplay}: SetTheRequestParams) => `${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} a ${newValueToDisplay}`, setTheDistance: ({newDistanceToDisplay, newAmountToDisplay}: SetTheDistanceParams) => `estableció la distancia a ${newDistanceToDisplay}, lo que estableció el importe a ${newAmountToDisplay}`, - removedTheRequest: ({valueName, oldValueToDisplay}: RemovedTheRequestParams) => - `${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} (previamente ${oldValueToDisplay})`, + removedTheRequest: ({valueName, oldValueToDisplay}: RemovedTheRequestParams) => `${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} (previamente ${oldValueToDisplay})`, updatedTheRequest: ({valueName, newValueToDisplay, oldValueToDisplay}: UpdatedTheRequestParams) => `${valueName === 'comerciante' ? 'el' : 'la'} ${valueName} a ${newValueToDisplay} (previamente ${oldValueToDisplay})`, updatedTheDistance: ({newDistanceToDisplay, oldDistanceToDisplay, newAmountToDisplay, oldAmountToDisplay}: UpdatedTheDistanceParams) => diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 13ffeb6432f5..68555644405c 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1897,7 +1897,7 @@ function getProperLineForModifiedExpenseMessage(prefix, messageFragments) { return messageFragments.reduce((acc, value, index) => { if (index === messageFragments.length - 1) { if (messageFragments.length === 1) { - return `${acc} ${value}.`; + return `${acc} ${value}.`; } else if (messageFragments.length === 2) { return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; } else { @@ -1976,19 +1976,24 @@ function getModifiedExpenseMessage(reportAction) { setFragments.push(fragment); } else if (!amount) { removalFragments.push(fragment); - } else { + } else { changeFragments.push(fragment); } } const hasModifiedComment = _.has(reportActionOriginalMessage, 'oldComment') && _.has(reportActionOriginalMessage, 'newComment'); if (hasModifiedComment) { - const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, Localize.translateLocal('common.description'), true); + const fragment = getProperSchemaForModifiedExpenseMessage( + reportActionOriginalMessage.newComment, + reportActionOriginalMessage.oldComment, + Localize.translateLocal('common.description'), + true, + ); if (!reportActionOriginalMessage.oldComment) { setFragments.push(fragment); } else if (!reportActionOriginalMessage.newComment) { removalFragments.push(fragment); - } else { + } else { changeFragments.push(fragment); } } @@ -2003,30 +2008,40 @@ function getModifiedExpenseMessage(reportAction) { setFragments.push(fragment); } else if (!reportActionOriginalMessage.created) { removalFragments.push(fragment); - } else { + } else { changeFragments.push(fragment); } } if (hasModifiedMerchant) { - const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, Localize.translateLocal('common.merchant'), true); + const fragment = getProperSchemaForModifiedExpenseMessage( + reportActionOriginalMessage.merchant, + reportActionOriginalMessage.oldMerchant, + Localize.translateLocal('common.merchant'), + true, + ); if (!reportActionOriginalMessage.oldMerchant) { setFragments.push(fragment); } else if (!reportActionOriginalMessage.merchant) { removalFragments.push(fragment); - } else { + } else { changeFragments.push(fragment); } } const hasModifiedCategory = _.has(reportActionOriginalMessage, 'oldCategory') && _.has(reportActionOriginalMessage, 'category'); if (hasModifiedCategory) { - const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), true); + const fragment = getProperSchemaForModifiedExpenseMessage( + reportActionOriginalMessage.category, + reportActionOriginalMessage.oldCategory, + Localize.translateLocal('common.category'), + true, + ); if (!reportActionOriginalMessage.oldCategory) { setFragments.push(fragment); } else if (!reportActionOriginalMessage.category) { removalFragments.push(fragment); - } else { + } else { changeFragments.push(fragment); } } @@ -2038,26 +2053,32 @@ function getModifiedExpenseMessage(reportAction) { setFragments.push(fragment); } else if (!reportActionOriginalMessage.tag) { removalFragments.push(fragment); - } else { + } else { changeFragments.push(fragment); } } const hasModifiedBillable = _.has(reportActionOriginalMessage, 'oldBillable') && _.has(reportActionOriginalMessage, 'billable'); if (hasModifiedBillable) { - const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.billable, reportActionOriginalMessage.oldBillable, Localize.translateLocal('iou.request'), true); + const fragment = getProperSchemaForModifiedExpenseMessage( + reportActionOriginalMessage.billable, + reportActionOriginalMessage.oldBillable, + Localize.translateLocal('iou.request'), + true, + ); if (!reportActionOriginalMessage.oldBillable) { setFragments.push(fragment); } else if (!reportActionOriginalMessage.billable) { removalFragments.push(fragment); - } else { + } else { changeFragments.push(fragment); } } - let message = getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.changed')}`, changeFragments) + - getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.set')}`, setFragments) + - getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.removed')}`, removalFragments); + let message = + getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.changed')}`, changeFragments) + + getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.set')}`, setFragments) + + getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.removed')}`, removalFragments); if (message === '') { return message; } From 376944c425bc61756f7421bd47ed26f5794b90c8 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 8 Nov 2023 16:22:23 +0200 Subject: [PATCH 12/46] Fix lint. --- src/libs/ReportUtils.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 68555644405c..70487dc0862f 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1898,12 +1898,13 @@ function getProperLineForModifiedExpenseMessage(prefix, messageFragments) { if (index === messageFragments.length - 1) { if (messageFragments.length === 1) { return `${acc} ${value}.`; - } else if (messageFragments.length === 2) { + } + if (messageFragments.length === 2) { return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; - } else { - return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; } - } else if (index === 0) { + return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; + } + if (index === 0) { return `${acc} ${value}`; } return `${acc}, ${value}`; From b9f42439e8ff3ee28402bb3b91f9530445c41cbf Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 8 Nov 2023 18:11:51 +0200 Subject: [PATCH 13/46] Update src/libs/ReportUtils.js Co-authored-by: Tim Golen --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 70487dc0862f..07265d95edc7 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1857,7 +1857,7 @@ function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceip } /** - * Get the proper message schema for a modified a field on the expense. + * Get the proper message schema for a modified field on the expense. * * @param {String} newValue * @param {String} oldValue From bab1de41b8e579d609142d2364659c70c831fcd0 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 20 Nov 2023 18:37:47 +0200 Subject: [PATCH 14/46] Move logic in a separate unit --- src/libs/ModifiedExpenseMessage.ts | 276 ++++++++++++++++++ .../LocalNotification/BrowserNotifications.js | 3 +- src/libs/OptionsListUtils.js | 3 +- src/libs/ReportUtils.js | 264 ----------------- .../report/ContextMenu/ContextMenuActions.js | 3 +- src/pages/home/report/ReportActionItem.js | 3 +- 6 files changed, 284 insertions(+), 268 deletions(-) create mode 100644 src/libs/ModifiedExpenseMessage.ts diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts new file mode 100644 index 000000000000..d323edcd38f8 --- /dev/null +++ b/src/libs/ModifiedExpenseMessage.ts @@ -0,0 +1,276 @@ +import {format} from 'date-fns'; +import lodashGet from 'lodash/get'; +import * as Localize from './Localize'; +import * as PolicyUtils from './PolicyUtils'; +import Onyx from 'react-native-onyx'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import * as ReportUtils from './ReportUtils'; +import * as CurrencyUtils from './CurrencyUtils'; +import _ from 'underscore'; + +let allPolicyTags = {}; + +Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY_TAGS, + waitForCollectionCallback: true, + callback: (value) => { + if (!value) { + allPolicyTags = {}; + return; + } + + allPolicyTags = value; + }, +}); + +function getPolicyTags(policyID: string) { + return lodashGet(allPolicyTags, `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {}); +} + + +/** + * Get the proper message schema for a modified field on the expense. + * + * @param {String} newValue + * @param {String} oldValue + * @param {String} valueName + * @param {Boolean} valueInQuotes + * @param {Boolean} shouldConvertToLowercase + * @returns {String} + */ + +function getProperSchemaForModifiedExpenseMessage(newValue: string, oldValue: string, valueName: string, valueInQuotes: boolean, shouldConvertToLowercase = true) { + const newValueToDisplay = valueInQuotes ? `"${newValue}"` : newValue; + const oldValueToDisplay = valueInQuotes ? `"${oldValue}"` : oldValue; + const displayValueName = shouldConvertToLowercase ? valueName.toLowerCase() : valueName; + + if (!oldValue) { + return Localize.translateLocal('iou.setTheRequest', {valueName: displayValueName, newValueToDisplay}); + } + if (!newValue) { + return Localize.translateLocal('iou.removedTheRequest', {valueName: displayValueName, oldValueToDisplay}); + } + return Localize.translateLocal('iou.updatedTheRequest', {valueName: displayValueName, newValueToDisplay, oldValueToDisplay}); +} + +/** + * Get the proper message line for a modified expense. + * + * @param {String} newValue + * @param {String} oldValue + * @param {String} valueName + * @param {Boolean} valueInQuotes + * @returns {String} + */ + +function getProperLineForModifiedExpenseMessage(prefix: string, messageFragments: Array) { + 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); +} + +/** + * Get the proper message schema for modified distance message. + * + * @param {String} newDistance + * @param {String} oldDistance + * @param {String} newAmount + * @param {String} oldAmount + * @returns {String} + */ + +function getProperSchemaForModifiedDistanceMessage(newDistance: string, oldDistance: string, newAmount: string, oldAmount: 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. + * + * @param {Object} reportAction + * @returns {String} + */ +function getModifiedExpenseMessage(reportAction: Object): string { + const reportActionOriginalMessage: any = lodashGet(reportAction, 'originalMessage', {}); + if (_.isEmpty(reportActionOriginalMessage)) { + return Localize.translateLocal('iou.changedTheRequest'); + } + const reportID = lodashGet(reportAction, 'reportID', ''); + const policyID = lodashGet(ReportUtils.getReport(reportID), 'policyID', ''); + const policyTags = getPolicyTags(policyID); + const policyTag = PolicyUtils.getTag(policyTags); + const policyTagListName = lodashGet(policyTag, 'name', Localize.translateLocal('common.tag')); + + const removalFragments = []; + const setFragments = []; + const changeFragments = []; + + const hasModifiedAmount = + _.has(reportActionOriginalMessage, 'oldAmount') && + _.has(reportActionOriginalMessage, 'oldCurrency') && + _.has(reportActionOriginalMessage, 'amount') && + _.has(reportActionOriginalMessage, 'currency'); + + const hasModifiedMerchant = _.has(reportActionOriginalMessage, 'oldMerchant') && _.has(reportActionOriginalMessage, 'merchant'); + if (hasModifiedAmount) { + const oldCurrency = reportActionOriginalMessage.oldCurrency; + const oldAmount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage.oldAmount, oldCurrency); + + const currency = reportActionOriginalMessage.currency; + const amount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage.amount, 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 getProperSchemaForModifiedDistanceMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, amount, oldAmount); + } + + const fragment = getProperSchemaForModifiedExpenseMessage(amount, oldAmount, Localize.translateLocal('iou.amount'), false); + if (!oldAmount) { + setFragments.push(fragment); + } else if (!amount) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } + } + + const hasModifiedComment = _.has(reportActionOriginalMessage, 'oldComment') && _.has(reportActionOriginalMessage, 'newComment'); + if (hasModifiedComment) { + const fragment = getProperSchemaForModifiedExpenseMessage( + reportActionOriginalMessage.newComment, + reportActionOriginalMessage.oldComment, + Localize.translateLocal('common.description'), + true, + ); + if (!reportActionOriginalMessage.oldComment) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.newComment) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } + } + + const hasModifiedCreated = _.has(reportActionOriginalMessage, 'oldCreated') && _.has(reportActionOriginalMessage, 'created'); + if (hasModifiedCreated) { + // Take only the YYYY-MM-DD value as the original date includes timestamp + let formattedOldCreated = format(new Date(reportActionOriginalMessage.oldCreated), CONST.DATE.FNS_FORMAT_STRING); + const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false); + if (!formattedOldCreated) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.created) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } + } + + if (hasModifiedMerchant) { + const fragment = getProperSchemaForModifiedExpenseMessage( + reportActionOriginalMessage.merchant, + reportActionOriginalMessage.oldMerchant, + Localize.translateLocal('common.merchant'), + true, + ); + if (!reportActionOriginalMessage.oldMerchant) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.merchant) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } + } + + const hasModifiedCategory = _.has(reportActionOriginalMessage, 'oldCategory') && _.has(reportActionOriginalMessage, 'category'); + if (hasModifiedCategory) { + const fragment = getProperSchemaForModifiedExpenseMessage( + reportActionOriginalMessage.category, + reportActionOriginalMessage.oldCategory, + Localize.translateLocal('common.category'), + true, + ); + if (!reportActionOriginalMessage.oldCategory) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.category) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } + } + + const hasModifiedTag = _.has(reportActionOriginalMessage, 'oldTag') && _.has(reportActionOriginalMessage, 'tag'); + if (hasModifiedTag) { + const fragment = getProperSchemaForModifiedExpenseMessage( + reportActionOriginalMessage.tag, + reportActionOriginalMessage.oldTag, + policyTagListName, + true, + policyTagListName === Localize.translateLocal('common.tag'), + ); + if (!reportActionOriginalMessage.oldTag) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.tag) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } + } + + const hasModifiedBillable = _.has(reportActionOriginalMessage, 'oldBillable') && _.has(reportActionOriginalMessage, 'billable'); + if (hasModifiedBillable) { + const fragment = getProperSchemaForModifiedExpenseMessage( + reportActionOriginalMessage.billable, + reportActionOriginalMessage.oldBillable, + Localize.translateLocal('iou.request'), + true, + ); + if (!reportActionOriginalMessage.oldBillable) { + setFragments.push(fragment); + } else if (!reportActionOriginalMessage.billable) { + removalFragments.push(fragment); + } else { + changeFragments.push(fragment); + } + } + + let message = + getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.changed')}`, changeFragments) + + getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.set')}`, setFragments) + + getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.removed')}`, removalFragments); + if (message === '') { + return message; + } + message = `${message.substring(1, message.length)}`; + return message; +} + +export default { + getModifiedExpenseMessage, +}; \ No newline at end of file diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.js index 20d9be48d915..497b686e7d5e 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.js +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.js @@ -4,6 +4,7 @@ import EXPENSIFY_ICON_URL from '@assets/images/expensify-logo-round-clearspace.p import * as ReportUtils from '@libs/ReportUtils'; import * as AppUpdate from '@userActions/AppUpdate'; import focusApp from './focusApp'; +import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; const DEFAULT_DELAY = 4000; @@ -131,7 +132,7 @@ export default { pushModifiedExpenseNotification({reportAction, onClick}, usesIcon = false) { push({ title: _.map(reportAction.person, (f) => f.text).join(', '), - body: ReportUtils.getModifiedExpenseMessage(reportAction), + body: ModifiedExpenseMessage.getModifiedExpenseMessage(reportAction), delay: 0, onClick, icon: usesIcon ? EXPENSIFY_ICON_URL : '', diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 7e0aaa8ffb2f..af0407a18112 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -20,6 +20,7 @@ import * as ReportActionUtils from './ReportActionsUtils'; import * as ReportUtils from './ReportUtils'; import * as TransactionUtils from './TransactionUtils'; import * as UserUtils from './UserUtils'; +import ModifiedExpenseMessage from './ModifiedExpenseMessage'; /** * OptionsListUtils is used to build a list options passed to the OptionsList component. Several different UI views can @@ -402,7 +403,7 @@ function getLastMessageTextForReport(report) { } else if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml, translationKey: report.lastMessageTranslationKey})) { lastMessageTextFromReport = `[${Localize.translateLocal(report.lastMessageTranslationKey || 'common.attachment')}]`; } else if (ReportActionUtils.isModifiedExpenseAction(lastReportAction)) { - const properSchemaForModifiedExpenseMessage = ReportUtils.getModifiedExpenseMessage(lastReportAction); + const properSchemaForModifiedExpenseMessage = ModifiedExpenseMessage.getModifiedExpenseMessage(lastReportAction); lastMessageTextFromReport = ReportUtils.formatReportLastMessageText(properSchemaForModifiedExpenseMessage, true); } else if ( lastActionName === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED || diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 4968fc33b04b..2a3db8437518 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -1,5 +1,4 @@ /* eslint-disable rulesdir/prefer-underscore-method */ -import {format} from 'date-fns'; import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import Str from 'expensify-common/lib/str'; import lodashGet from 'lodash/get'; @@ -81,25 +80,6 @@ Onyx.connect({ callback: (val) => (loginList = val), }); -let allPolicyTags = {}; - -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY_TAGS, - waitForCollectionCallback: true, - callback: (value) => { - if (!value) { - allPolicyTags = {}; - return; - } - - allPolicyTags = value; - }, -}); - -function getPolicyTags(policyID) { - return lodashGet(allPolicyTags, `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {}); -} - function getChatType(report) { return report ? report.chatType : ''; } @@ -1884,249 +1864,6 @@ function getReportPreviewMessage(report, reportAction = {}, shouldConsiderReceip return Localize.translateLocal(containsNonReimbursable ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', {payer: payerName, amount: formattedAmount}); } -/** - * Get the proper message schema for a modified field on the expense. - * - * @param {String} newValue - * @param {String} oldValue - * @param {String} valueName - * @param {Boolean} valueInQuotes - * @param {Boolean} shouldConvertToLowercase - * @returns {String} - */ - -function getProperSchemaForModifiedExpenseMessage(newValue, oldValue, valueName, valueInQuotes, shouldConvertToLowercase = true) { - const newValueToDisplay = valueInQuotes ? `"${newValue}"` : newValue; - const oldValueToDisplay = valueInQuotes ? `"${oldValue}"` : oldValue; - const displayValueName = shouldConvertToLowercase ? valueName.toLowerCase() : valueName; - - if (!oldValue) { - return Localize.translateLocal('iou.setTheRequest', {valueName: displayValueName, newValueToDisplay}); - } - if (!newValue) { - return Localize.translateLocal('iou.removedTheRequest', {valueName: displayValueName, oldValueToDisplay}); - } - return Localize.translateLocal('iou.updatedTheRequest', {valueName: displayValueName, newValueToDisplay, oldValueToDisplay}); -} - -/** - * Get the proper message line for a modified expense. - * - * @param {String} newValue - * @param {String} oldValue - * @param {String} valueName - * @param {Boolean} valueInQuotes - * @returns {String} - */ - -function getProperLineForModifiedExpenseMessage(prefix, messageFragments) { - 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); -} - -/** - * Get the proper message schema for modified distance message. - * - * @param {String} newDistance - * @param {String} oldDistance - * @param {String} newAmount - * @param {String} oldAmount - * @returns {String} - */ - -function getProperSchemaForModifiedDistanceMessage(newDistance, oldDistance, newAmount, oldAmount) { - 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. - * - * @param {Object} reportAction - * @returns {String} - */ -function getModifiedExpenseMessage(reportAction) { - const reportActionOriginalMessage = lodashGet(reportAction, 'originalMessage', {}); - if (_.isEmpty(reportActionOriginalMessage)) { - return Localize.translateLocal('iou.changedTheRequest'); - } - const reportID = lodashGet(reportAction, 'reportID', ''); - const policyID = lodashGet(getReport(reportID), 'policyID', ''); - const policyTags = getPolicyTags(policyID); - const policyTag = PolicyUtils.getTag(policyTags); - const policyTagListName = lodashGet(policyTag, 'name', Localize.translateLocal('common.tag')); - - const removalFragments = []; - const setFragments = []; - const changeFragments = []; - - const hasModifiedAmount = - _.has(reportActionOriginalMessage, 'oldAmount') && - _.has(reportActionOriginalMessage, 'oldCurrency') && - _.has(reportActionOriginalMessage, 'amount') && - _.has(reportActionOriginalMessage, 'currency'); - - const hasModifiedMerchant = _.has(reportActionOriginalMessage, 'oldMerchant') && _.has(reportActionOriginalMessage, 'merchant'); - if (hasModifiedAmount) { - const oldCurrency = reportActionOriginalMessage.oldCurrency; - const oldAmount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage.oldAmount, oldCurrency); - - const currency = reportActionOriginalMessage.currency; - const amount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage.amount, 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 getProperSchemaForModifiedDistanceMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, amount, oldAmount); - } - - const fragment = getProperSchemaForModifiedExpenseMessage(amount, oldAmount, Localize.translateLocal('iou.amount'), false); - if (!oldAmount) { - setFragments.push(fragment); - } else if (!amount) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } - } - - const hasModifiedComment = _.has(reportActionOriginalMessage, 'oldComment') && _.has(reportActionOriginalMessage, 'newComment'); - if (hasModifiedComment) { - const fragment = getProperSchemaForModifiedExpenseMessage( - reportActionOriginalMessage.newComment, - reportActionOriginalMessage.oldComment, - Localize.translateLocal('common.description'), - true, - ); - if (!reportActionOriginalMessage.oldComment) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.newComment) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } - } - - const hasModifiedCreated = _.has(reportActionOriginalMessage, 'oldCreated') && _.has(reportActionOriginalMessage, 'created'); - if (hasModifiedCreated) { - // Take only the YYYY-MM-DD value as the original date includes timestamp - let formattedOldCreated = new Date(reportActionOriginalMessage.oldCreated); - formattedOldCreated = format(formattedOldCreated, CONST.DATE.FNS_FORMAT_STRING); - const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false); - if (!formattedOldCreated) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.created) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } - } - - if (hasModifiedMerchant) { - const fragment = getProperSchemaForModifiedExpenseMessage( - reportActionOriginalMessage.merchant, - reportActionOriginalMessage.oldMerchant, - Localize.translateLocal('common.merchant'), - true, - ); - if (!reportActionOriginalMessage.oldMerchant) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.merchant) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } - } - - const hasModifiedCategory = _.has(reportActionOriginalMessage, 'oldCategory') && _.has(reportActionOriginalMessage, 'category'); - if (hasModifiedCategory) { - const fragment = getProperSchemaForModifiedExpenseMessage( - reportActionOriginalMessage.category, - reportActionOriginalMessage.oldCategory, - Localize.translateLocal('common.category'), - true, - ); - if (!reportActionOriginalMessage.oldCategory) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.category) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } - } - - const hasModifiedTag = _.has(reportActionOriginalMessage, 'oldTag') && _.has(reportActionOriginalMessage, 'tag'); - if (hasModifiedTag) { - const fragment = getProperSchemaForModifiedExpenseMessage( - reportActionOriginalMessage.tag, - reportActionOriginalMessage.oldTag, - policyTagListName, - true, - policyTagListName === Localize.translateLocal('common.tag'), - ); - if (!reportActionOriginalMessage.oldTag) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.tag) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } - } - - const hasModifiedBillable = _.has(reportActionOriginalMessage, 'oldBillable') && _.has(reportActionOriginalMessage, 'billable'); - if (hasModifiedBillable) { - const fragment = getProperSchemaForModifiedExpenseMessage( - reportActionOriginalMessage.billable, - reportActionOriginalMessage.oldBillable, - Localize.translateLocal('iou.request'), - true, - ); - if (!reportActionOriginalMessage.oldBillable) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.billable) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } - } - - let message = - getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.changed')}`, changeFragments) + - getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.set')}`, setFragments) + - getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.removed')}`, removalFragments); - if (message === '') { - return message; - } - message = `${message.substring(1, message.length)}`; - return message; -} - /** * Given the updates user made to the request, compose the originalMessage * object of the modified expense action. @@ -4514,7 +4251,6 @@ export { getParentReport, getRootParentReport, getReportPreviewMessage, - getModifiedExpenseMessage, canUserPerformWriteAction, getOriginalReportID, canAccessReport, diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 4f35926c5957..0d788dbefda4 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -22,6 +22,7 @@ import * as Task from '@userActions/Task'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import {clearActiveReportAction, hideContextMenu, showDeleteModal} from './ReportActionContextMenu'; +import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; /** * Gets the HTML version of the message in an action. @@ -276,7 +277,7 @@ export default [ const displayMessage = ReportUtils.getReportPreviewMessage(iouReport, reportAction); Clipboard.setString(displayMessage); } else if (ReportActionsUtils.isModifiedExpenseAction(reportAction)) { - const modifyExpenseMessage = ReportUtils.getModifiedExpenseMessage(reportAction); + const modifyExpenseMessage = ModifiedExpenseMessage.getModifiedExpenseMessage(reportAction); Clipboard.setString(modifyExpenseMessage); } else if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { const displayMessage = ReportUtils.getIOUReportActionDisplayMessage(reportAction); diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 9f803f72cbbb..ed89e4c2f413 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -74,6 +74,7 @@ import ReportActionItemSingle from './ReportActionItemSingle'; import ReportActionItemThread from './ReportActionItemThread'; import reportActionPropTypes from './reportActionPropTypes'; import ReportAttachmentsContext from './ReportAttachmentsContext'; +import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; const propTypes = { ...windowDimensionsPropTypes, @@ -414,7 +415,7 @@ function ReportActionItem(props) { ); } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE) { - children = ; + children = ; } else { const hasBeenFlagged = !_.contains([CONST.MODERATION.MODERATOR_DECISION_APPROVED, CONST.MODERATION.MODERATOR_DECISION_PENDING], moderationDecision); children = ( From 4ea44ee4d1c1be7f8d79ee0d8388278262d5b681 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 20 Nov 2023 18:43:45 +0200 Subject: [PATCH 15/46] Move policy tags logic to PolicyUtils --- src/libs/ModifiedExpenseMessage.ts | 34 ++++++------------------------ src/libs/PolicyUtils.ts | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index d323edcd38f8..18767c68e010 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -2,42 +2,20 @@ import {format} from 'date-fns'; import lodashGet from 'lodash/get'; import * as Localize from './Localize'; import * as PolicyUtils from './PolicyUtils'; -import Onyx from 'react-native-onyx'; import CONST from '@src/CONST'; -import ONYXKEYS from '@src/ONYXKEYS'; import * as ReportUtils from './ReportUtils'; import * as CurrencyUtils from './CurrencyUtils'; import _ from 'underscore'; -let allPolicyTags = {}; - -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY_TAGS, - waitForCollectionCallback: true, - callback: (value) => { - if (!value) { - allPolicyTags = {}; - return; - } - - allPolicyTags = value; - }, -}); - -function getPolicyTags(policyID: string) { - return lodashGet(allPolicyTags, `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {}); -} - /** * Get the proper message schema for a modified field on the expense. * - * @param {String} newValue - * @param {String} oldValue - * @param {String} valueName - * @param {Boolean} valueInQuotes - * @param {Boolean} shouldConvertToLowercase - * @returns {String} + * @param newValue + * @param oldValue + * @param valueName + * @param valueInQuotes + * @param shouldConvertToLowercase */ function getProperSchemaForModifiedExpenseMessage(newValue: string, oldValue: string, valueName: string, valueInQuotes: boolean, shouldConvertToLowercase = true) { @@ -123,7 +101,7 @@ function getModifiedExpenseMessage(reportAction: Object): string { } const reportID = lodashGet(reportAction, 'reportID', ''); const policyID = lodashGet(ReportUtils.getReport(reportID), 'policyID', ''); - const policyTags = getPolicyTags(policyID); + const policyTags = PolicyUtils.getPolicyTags(policyID); const policyTag = PolicyUtils.getTag(policyTags); const policyTagListName = lodashGet(policyTag, 'name', Localize.translateLocal('common.tag')); diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index 62640a11311a..aa33a74dedf9 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -3,11 +3,32 @@ import {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {PersonalDetails, Policy, PolicyMembers, PolicyTags} from '@src/types/onyx'; +import Onyx from 'react-native-onyx'; +import lodashGet from 'lodash/get'; type MemberEmailsToAccountIDs = Record; type PersonalDetailsList = Record; type UnitRate = {rate: number}; +let allPolicyTags = {}; + +Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY_TAGS, + waitForCollectionCallback: true, + callback: (value) => { + if (!value) { + allPolicyTags = {}; + return; + } + + allPolicyTags = value; + }, +}); + +function getPolicyTags(policyID: string) { + return lodashGet(allPolicyTags, `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {}); +} + /** * Filter out the active policies, which will exclude policies with pending deletion * These are policies that we can use to create reports with in NewDot. @@ -199,6 +220,7 @@ function isPendingDeletePolicy(policy: OnyxEntry): boolean { export { getActivePolicies, + getPolicyTags, hasPolicyMemberError, hasPolicyError, hasPolicyErrorFields, From b9229a774e6919d00cc553c2866a11d02ed1d68d Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 20 Nov 2023 22:35:25 +0200 Subject: [PATCH 16/46] Better naming --- src/libs/ModifiedExpenseMessage.ts | 59 +++++++++---------- .../LocalNotification/BrowserNotifications.js | 2 +- src/libs/OptionsListUtils.js | 2 +- .../report/ContextMenu/ContextMenuActions.js | 2 +- src/pages/home/report/ReportActionItem.js | 2 +- 5 files changed, 32 insertions(+), 35 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 18767c68e010..f95c2ddfef99 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -9,7 +9,7 @@ import _ from 'underscore'; /** - * Get the proper message schema for a modified field on the expense. + * Get the partial message for a modified field on the expense. * * @param newValue * @param oldValue @@ -18,7 +18,7 @@ import _ from 'underscore'; * @param shouldConvertToLowercase */ -function getProperSchemaForModifiedExpenseMessage(newValue: string, oldValue: string, valueName: string, valueInQuotes: boolean, shouldConvertToLowercase = true) { +function getPartialMessageForValue(newValue: string, oldValue: string, valueName: string, valueInQuotes: boolean, shouldConvertToLowercase = true) { const newValueToDisplay = valueInQuotes ? `"${newValue}"` : newValue; const oldValueToDisplay = valueInQuotes ? `"${oldValue}"` : oldValue; const displayValueName = shouldConvertToLowercase ? valueName.toLowerCase() : valueName; @@ -33,16 +33,15 @@ function getProperSchemaForModifiedExpenseMessage(newValue: string, oldValue: st } /** - * Get the proper message line for a modified expense. + * Get the message line for a modified expense. * - * @param {String} newValue - * @param {String} oldValue - * @param {String} valueName - * @param {Boolean} valueInQuotes - * @returns {String} + * @param newValue + * @param oldValue + * @param valueName + * @param valueInQuotes */ -function getProperLineForModifiedExpenseMessage(prefix: string, messageFragments: Array) { +function getMessageLine(prefix: string, messageFragments: Array) { if (messageFragments.length === 0) { return ''; } @@ -64,16 +63,15 @@ function getProperLineForModifiedExpenseMessage(prefix: string, messageFragments } /** - * Get the proper message schema for modified distance message. + * Get the message for a modified distance request. * - * @param {String} newDistance - * @param {String} oldDistance - * @param {String} newAmount - * @param {String} oldAmount - * @returns {String} + * @param newDistance + * @param oldDistance + * @param newAmount + * @param oldAmount */ -function getProperSchemaForModifiedDistanceMessage(newDistance: string, oldDistance: string, newAmount: string, oldAmount: string) { +function getForDistanceRequest(newDistance: string, oldDistance: string, newAmount: string, oldAmount: string) { if (!oldDistance) { return Localize.translateLocal('iou.setTheDistance', {newDistanceToDisplay: newDistance, newAmountToDisplay: newAmount}); } @@ -91,10 +89,9 @@ function getProperSchemaForModifiedDistanceMessage(newDistance: string, oldDista * ModifiedExpense::getNewDotComment in Web-Expensify should match this. * If we change this function be sure to update the backend as well. * - * @param {Object} reportAction - * @returns {String} + * @param reportAction */ -function getModifiedExpenseMessage(reportAction: Object): string { +function getForReportAction(reportAction: Object): string { const reportActionOriginalMessage: any = lodashGet(reportAction, 'originalMessage', {}); if (_.isEmpty(reportActionOriginalMessage)) { return Localize.translateLocal('iou.changedTheRequest'); @@ -126,10 +123,10 @@ function getModifiedExpenseMessage(reportAction: Object): string { // 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 getProperSchemaForModifiedDistanceMessage(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, amount, oldAmount); + return getForDistanceRequest(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, amount, oldAmount); } - const fragment = getProperSchemaForModifiedExpenseMessage(amount, oldAmount, Localize.translateLocal('iou.amount'), false); + const fragment = getPartialMessageForValue(amount, oldAmount, Localize.translateLocal('iou.amount'), false); if (!oldAmount) { setFragments.push(fragment); } else if (!amount) { @@ -141,7 +138,7 @@ function getModifiedExpenseMessage(reportAction: Object): string { const hasModifiedComment = _.has(reportActionOriginalMessage, 'oldComment') && _.has(reportActionOriginalMessage, 'newComment'); if (hasModifiedComment) { - const fragment = getProperSchemaForModifiedExpenseMessage( + const fragment = getPartialMessageForValue( reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, Localize.translateLocal('common.description'), @@ -160,7 +157,7 @@ function getModifiedExpenseMessage(reportAction: Object): string { if (hasModifiedCreated) { // Take only the YYYY-MM-DD value as the original date includes timestamp let formattedOldCreated = format(new Date(reportActionOriginalMessage.oldCreated), CONST.DATE.FNS_FORMAT_STRING); - const fragment = getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false); + const fragment = getPartialMessageForValue(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false); if (!formattedOldCreated) { setFragments.push(fragment); } else if (!reportActionOriginalMessage.created) { @@ -171,7 +168,7 @@ function getModifiedExpenseMessage(reportAction: Object): string { } if (hasModifiedMerchant) { - const fragment = getProperSchemaForModifiedExpenseMessage( + const fragment = getPartialMessageForValue( reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, Localize.translateLocal('common.merchant'), @@ -188,7 +185,7 @@ function getModifiedExpenseMessage(reportAction: Object): string { const hasModifiedCategory = _.has(reportActionOriginalMessage, 'oldCategory') && _.has(reportActionOriginalMessage, 'category'); if (hasModifiedCategory) { - const fragment = getProperSchemaForModifiedExpenseMessage( + const fragment = getPartialMessageForValue( reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), @@ -205,7 +202,7 @@ function getModifiedExpenseMessage(reportAction: Object): string { const hasModifiedTag = _.has(reportActionOriginalMessage, 'oldTag') && _.has(reportActionOriginalMessage, 'tag'); if (hasModifiedTag) { - const fragment = getProperSchemaForModifiedExpenseMessage( + const fragment = getPartialMessageForValue( reportActionOriginalMessage.tag, reportActionOriginalMessage.oldTag, policyTagListName, @@ -223,7 +220,7 @@ function getModifiedExpenseMessage(reportAction: Object): string { const hasModifiedBillable = _.has(reportActionOriginalMessage, 'oldBillable') && _.has(reportActionOriginalMessage, 'billable'); if (hasModifiedBillable) { - const fragment = getProperSchemaForModifiedExpenseMessage( + const fragment = getPartialMessageForValue( reportActionOriginalMessage.billable, reportActionOriginalMessage.oldBillable, Localize.translateLocal('iou.request'), @@ -239,9 +236,9 @@ function getModifiedExpenseMessage(reportAction: Object): string { } let message = - getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.changed')}`, changeFragments) + - getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.set')}`, setFragments) + - getProperLineForModifiedExpenseMessage(`\n${Localize.translateLocal('iou.removed')}`, removalFragments); + getMessageLine(`\n${Localize.translateLocal('iou.changed')}`, changeFragments) + + getMessageLine(`\n${Localize.translateLocal('iou.set')}`, setFragments) + + getMessageLine(`\n${Localize.translateLocal('iou.removed')}`, removalFragments); if (message === '') { return message; } @@ -250,5 +247,5 @@ function getModifiedExpenseMessage(reportAction: Object): string { } export default { - getModifiedExpenseMessage, + getForReportAction, }; \ No newline at end of file diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.js index 497b686e7d5e..853106adafe8 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.js +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.js @@ -132,7 +132,7 @@ export default { pushModifiedExpenseNotification({reportAction, onClick}, usesIcon = false) { push({ title: _.map(reportAction.person, (f) => f.text).join(', '), - body: ModifiedExpenseMessage.getModifiedExpenseMessage(reportAction), + body: ModifiedExpenseMessage.getForReportAction(reportAction), delay: 0, onClick, icon: usesIcon ? EXPENSIFY_ICON_URL : '', diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index af0407a18112..fd6031f5c901 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -403,7 +403,7 @@ function getLastMessageTextForReport(report) { } else if (ReportUtils.isReportMessageAttachment({text: report.lastMessageText, html: report.lastMessageHtml, translationKey: report.lastMessageTranslationKey})) { lastMessageTextFromReport = `[${Localize.translateLocal(report.lastMessageTranslationKey || 'common.attachment')}]`; } else if (ReportActionUtils.isModifiedExpenseAction(lastReportAction)) { - const properSchemaForModifiedExpenseMessage = ModifiedExpenseMessage.getModifiedExpenseMessage(lastReportAction); + const properSchemaForModifiedExpenseMessage = ModifiedExpenseMessage.getForReportAction(lastReportAction); lastMessageTextFromReport = ReportUtils.formatReportLastMessageText(properSchemaForModifiedExpenseMessage, true); } else if ( lastActionName === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED || diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 0d788dbefda4..bebb2e2688c5 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -277,7 +277,7 @@ export default [ const displayMessage = ReportUtils.getReportPreviewMessage(iouReport, reportAction); Clipboard.setString(displayMessage); } else if (ReportActionsUtils.isModifiedExpenseAction(reportAction)) { - const modifyExpenseMessage = ModifiedExpenseMessage.getModifiedExpenseMessage(reportAction); + const modifyExpenseMessage = ModifiedExpenseMessage.getForReportAction(reportAction); Clipboard.setString(modifyExpenseMessage); } else if (ReportActionsUtils.isMoneyRequestAction(reportAction)) { const displayMessage = ReportUtils.getIOUReportActionDisplayMessage(reportAction); diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index ed89e4c2f413..ce4c151bf2d6 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -415,7 +415,7 @@ function ReportActionItem(props) { ); } else if (props.action.actionName === CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE) { - children = ; + children = ; } else { const hasBeenFlagged = !_.contains([CONST.MODERATION.MODERATOR_DECISION_APPROVED, CONST.MODERATION.MODERATOR_DECISION_PENDING], moderationDecision); children = ( From 72714adfc3730fd32f9e2d551b0ad9ed8016de8b Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 20 Nov 2023 22:44:31 +0200 Subject: [PATCH 17/46] Dry up code. --- src/libs/ModifiedExpenseMessage.ts | 103 ++++++++++------------------- 1 file changed, 34 insertions(+), 69 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index f95c2ddfef99..d3f0b07cbcb8 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -9,7 +9,7 @@ import _ from 'underscore'; /** - * Get the partial message for a modified field on the expense. + * Builds the partial message fragment for a modified field on the expense. * * @param newValue * @param oldValue @@ -18,18 +18,30 @@ import _ from 'underscore'; * @param shouldConvertToLowercase */ -function getPartialMessageForValue(newValue: string, oldValue: string, valueName: string, valueInQuotes: boolean, shouldConvertToLowercase = true) { +function buildMessageFragmentForValue( + newValue: string, + oldValue: string, + valueName: string, + valueInQuotes: boolean, + setFragments: Array, + removalFragments: Array, + changeFragments: Array, + shouldConvertToLowercase = true +) { const newValueToDisplay = valueInQuotes ? `"${newValue}"` : newValue; const oldValueToDisplay = valueInQuotes ? `"${oldValue}"` : oldValue; const displayValueName = shouldConvertToLowercase ? valueName.toLowerCase() : valueName; if (!oldValue) { - return Localize.translateLocal('iou.setTheRequest', {valueName: displayValueName, newValueToDisplay}); + 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); } - if (!newValue) { - return Localize.translateLocal('iou.removedTheRequest', {valueName: displayValueName, oldValueToDisplay}); - } - return Localize.translateLocal('iou.updatedTheRequest', {valueName: displayValueName, newValueToDisplay, oldValueToDisplay}); } /** @@ -102,9 +114,9 @@ function getForReportAction(reportAction: Object): string { const policyTag = PolicyUtils.getTag(policyTags); const policyTagListName = lodashGet(policyTag, 'name', Localize.translateLocal('common.tag')); - const removalFragments = []; - const setFragments = []; - const changeFragments = []; + const removalFragments: Array = []; + const setFragments: Array = []; + const changeFragments: Array = []; const hasModifiedAmount = _.has(reportActionOriginalMessage, 'oldAmount') && @@ -126,113 +138,66 @@ function getForReportAction(reportAction: Object): string { return getForDistanceRequest(reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, amount, oldAmount); } - const fragment = getPartialMessageForValue(amount, oldAmount, Localize.translateLocal('iou.amount'), false); - if (!oldAmount) { - setFragments.push(fragment); - } else if (!amount) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } + buildMessageFragmentForValue(amount, oldAmount, Localize.translateLocal('iou.amount'), false, setFragments, removalFragments, changeFragments); } const hasModifiedComment = _.has(reportActionOriginalMessage, 'oldComment') && _.has(reportActionOriginalMessage, 'newComment'); if (hasModifiedComment) { - const fragment = getPartialMessageForValue( + buildMessageFragmentForValue( reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, Localize.translateLocal('common.description'), - true, + true, setFragments, removalFragments, changeFragments ); - if (!reportActionOriginalMessage.oldComment) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.newComment) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } } const hasModifiedCreated = _.has(reportActionOriginalMessage, 'oldCreated') && _.has(reportActionOriginalMessage, 'created'); if (hasModifiedCreated) { // Take only the YYYY-MM-DD value as the original date includes timestamp let formattedOldCreated = format(new Date(reportActionOriginalMessage.oldCreated), CONST.DATE.FNS_FORMAT_STRING); - const fragment = getPartialMessageForValue(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false); - if (!formattedOldCreated) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.created) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } + buildMessageFragmentForValue(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false, setFragments, removalFragments, changeFragments); } if (hasModifiedMerchant) { - const fragment = getPartialMessageForValue( + buildMessageFragmentForValue( reportActionOriginalMessage.merchant, reportActionOriginalMessage.oldMerchant, Localize.translateLocal('common.merchant'), true, + setFragments, removalFragments, changeFragments ); - if (!reportActionOriginalMessage.oldMerchant) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.merchant) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } } const hasModifiedCategory = _.has(reportActionOriginalMessage, 'oldCategory') && _.has(reportActionOriginalMessage, 'category'); if (hasModifiedCategory) { - const fragment = getPartialMessageForValue( + buildMessageFragmentForValue( reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), - true, + true, setFragments, removalFragments, changeFragments ); - if (!reportActionOriginalMessage.oldCategory) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.category) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } } const hasModifiedTag = _.has(reportActionOriginalMessage, 'oldTag') && _.has(reportActionOriginalMessage, 'tag'); if (hasModifiedTag) { - const fragment = getPartialMessageForValue( + buildMessageFragmentForValue( reportActionOriginalMessage.tag, reportActionOriginalMessage.oldTag, policyTagListName, true, + setFragments, removalFragments, changeFragments, policyTagListName === Localize.translateLocal('common.tag'), ); - if (!reportActionOriginalMessage.oldTag) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.tag) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } } const hasModifiedBillable = _.has(reportActionOriginalMessage, 'oldBillable') && _.has(reportActionOriginalMessage, 'billable'); if (hasModifiedBillable) { - const fragment = getPartialMessageForValue( + buildMessageFragmentForValue( reportActionOriginalMessage.billable, reportActionOriginalMessage.oldBillable, Localize.translateLocal('iou.request'), - true, + true, setFragments, removalFragments, changeFragments ); - if (!reportActionOriginalMessage.oldBillable) { - setFragments.push(fragment); - } else if (!reportActionOriginalMessage.billable) { - removalFragments.push(fragment); - } else { - changeFragments.push(fragment); - } } let message = From 18d1bf0fb300c9eac3c69ec8ff4e72d8097a0f77 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 20 Nov 2023 22:50:10 +0200 Subject: [PATCH 18/46] Run prettier --- src/libs/ModifiedExpenseMessage.ts | 66 ++++++++++++------- .../LocalNotification/BrowserNotifications.js | 2 +- src/libs/OptionsListUtils.js | 2 +- src/libs/PolicyUtils.ts | 4 +- .../report/ContextMenu/ContextMenuActions.js | 2 +- src/pages/home/report/ReportActionItem.js | 2 +- 6 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index d3f0b07cbcb8..d0ebce1275b5 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -1,12 +1,11 @@ import {format} from 'date-fns'; import lodashGet from 'lodash/get'; +import _ from 'underscore'; +import CONST from '@src/CONST'; +import * as CurrencyUtils from './CurrencyUtils'; import * as Localize from './Localize'; import * as PolicyUtils from './PolicyUtils'; -import CONST from '@src/CONST'; import * as ReportUtils from './ReportUtils'; -import * as CurrencyUtils from './CurrencyUtils'; -import _ from 'underscore'; - /** * Builds the partial message fragment for a modified field on the expense. @@ -19,14 +18,14 @@ import _ from 'underscore'; */ function buildMessageFragmentForValue( - newValue: string, - oldValue: string, - valueName: string, - valueInQuotes: boolean, - setFragments: Array, - removalFragments: Array, - changeFragments: Array, - shouldConvertToLowercase = true + 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; @@ -53,7 +52,7 @@ function buildMessageFragmentForValue( * @param valueInQuotes */ -function getMessageLine(prefix: string, messageFragments: Array) { +function getMessageLine(prefix: string, messageFragments: string[]) { if (messageFragments.length === 0) { return ''; } @@ -114,9 +113,9 @@ function getForReportAction(reportAction: Object): string { const policyTag = PolicyUtils.getTag(policyTags); const policyTagListName = lodashGet(policyTag, 'name', Localize.translateLocal('common.tag')); - const removalFragments: Array = []; - const setFragments: Array = []; - const changeFragments: Array = []; + const removalFragments: string[] = []; + const setFragments: string[] = []; + const changeFragments: string[] = []; const hasModifiedAmount = _.has(reportActionOriginalMessage, 'oldAmount') && @@ -147,7 +146,10 @@ function getForReportAction(reportAction: Object): string { reportActionOriginalMessage.newComment, reportActionOriginalMessage.oldComment, Localize.translateLocal('common.description'), - true, setFragments, removalFragments, changeFragments + true, + setFragments, + removalFragments, + changeFragments, ); } @@ -155,7 +157,15 @@ function getForReportAction(reportAction: Object): string { if (hasModifiedCreated) { // Take only the YYYY-MM-DD value as the original date includes timestamp let formattedOldCreated = format(new Date(reportActionOriginalMessage.oldCreated), CONST.DATE.FNS_FORMAT_STRING); - buildMessageFragmentForValue(reportActionOriginalMessage.created, formattedOldCreated, Localize.translateLocal('common.date'), false, setFragments, removalFragments, changeFragments); + buildMessageFragmentForValue( + reportActionOriginalMessage.created, + formattedOldCreated, + Localize.translateLocal('common.date'), + false, + setFragments, + removalFragments, + changeFragments, + ); } if (hasModifiedMerchant) { @@ -164,7 +174,9 @@ function getForReportAction(reportAction: Object): string { reportActionOriginalMessage.oldMerchant, Localize.translateLocal('common.merchant'), true, - setFragments, removalFragments, changeFragments + setFragments, + removalFragments, + changeFragments, ); } @@ -174,7 +186,10 @@ function getForReportAction(reportAction: Object): string { reportActionOriginalMessage.category, reportActionOriginalMessage.oldCategory, Localize.translateLocal('common.category'), - true, setFragments, removalFragments, changeFragments + true, + setFragments, + removalFragments, + changeFragments, ); } @@ -185,7 +200,9 @@ function getForReportAction(reportAction: Object): string { reportActionOriginalMessage.oldTag, policyTagListName, true, - setFragments, removalFragments, changeFragments, + setFragments, + removalFragments, + changeFragments, policyTagListName === Localize.translateLocal('common.tag'), ); } @@ -196,7 +213,10 @@ function getForReportAction(reportAction: Object): string { reportActionOriginalMessage.billable, reportActionOriginalMessage.oldBillable, Localize.translateLocal('iou.request'), - true, setFragments, removalFragments, changeFragments + true, + setFragments, + removalFragments, + changeFragments, ); } @@ -213,4 +233,4 @@ function getForReportAction(reportAction: Object): string { export default { getForReportAction, -}; \ No newline at end of file +}; diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.js index 853106adafe8..4c990a87878c 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.js +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.js @@ -1,10 +1,10 @@ // Web and desktop implementation only. Do not import for direct use. Use LocalNotification. import _ from 'underscore'; import EXPENSIFY_ICON_URL from '@assets/images/expensify-logo-round-clearspace.png'; +import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; import * as ReportUtils from '@libs/ReportUtils'; import * as AppUpdate from '@userActions/AppUpdate'; import focusApp from './focusApp'; -import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; const DEFAULT_DELAY = 4000; diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index fd6031f5c901..9f0780c6a909 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -13,6 +13,7 @@ import * as ErrorUtils from './ErrorUtils'; import * as LocalePhoneNumber from './LocalePhoneNumber'; import * as Localize from './Localize'; import * as LoginUtils from './LoginUtils'; +import ModifiedExpenseMessage from './ModifiedExpenseMessage'; import Navigation from './Navigation/Navigation'; import Permissions from './Permissions'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; @@ -20,7 +21,6 @@ import * as ReportActionUtils from './ReportActionsUtils'; import * as ReportUtils from './ReportUtils'; import * as TransactionUtils from './TransactionUtils'; import * as UserUtils from './UserUtils'; -import ModifiedExpenseMessage from './ModifiedExpenseMessage'; /** * OptionsListUtils is used to build a list options passed to the OptionsList component. Several different UI views can diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index aa33a74dedf9..ead8d20f838e 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -1,10 +1,10 @@ import Str from 'expensify-common/lib/str'; +import lodashGet from 'lodash/get'; import {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import Onyx from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {PersonalDetails, Policy, PolicyMembers, PolicyTags} from '@src/types/onyx'; -import Onyx from 'react-native-onyx'; -import lodashGet from 'lodash/get'; type MemberEmailsToAccountIDs = Record; type PersonalDetailsList = Record; diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index bebb2e2688c5..8be004cbe6a5 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -10,6 +10,7 @@ import Clipboard from '@libs/Clipboard'; import * as Environment from '@libs/Environment/Environment'; import fileDownload from '@libs/fileDownload'; import getAttachmentDetails from '@libs/fileDownload/getAttachmentDetails'; +import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; import Navigation from '@libs/Navigation/Navigation'; import Permissions from '@libs/Permissions'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; @@ -22,7 +23,6 @@ import * as Task from '@userActions/Task'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; import {clearActiveReportAction, hideContextMenu, showDeleteModal} from './ReportActionContextMenu'; -import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; /** * Gets the HTML version of the message in an action. diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index ce4c151bf2d6..6ae2241093e4 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -36,6 +36,7 @@ import compose from '@libs/compose'; import ControlSelection from '@libs/ControlSelection'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import focusTextInputAfterAnimation from '@libs/focusTextInputAfterAnimation'; +import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; import Navigation from '@libs/Navigation/Navigation'; import Permissions from '@libs/Permissions'; import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils'; @@ -74,7 +75,6 @@ import ReportActionItemSingle from './ReportActionItemSingle'; import ReportActionItemThread from './ReportActionItemThread'; import reportActionPropTypes from './reportActionPropTypes'; import ReportAttachmentsContext from './ReportAttachmentsContext'; -import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; const propTypes = { ...windowDimensionsPropTypes, From 5444abd6030d0c45df9a3ff0a4c88b432f234ecf Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Tue, 21 Nov 2023 01:33:08 +0200 Subject: [PATCH 19/46] Fix lint errors --- ...seMessage.ts => ModifiedExpenseMessage.js} | 64 +++++++++---------- src/libs/PolicyUtils.ts | 13 ++-- 2 files changed, 34 insertions(+), 43 deletions(-) rename src/libs/{ModifiedExpenseMessage.ts => ModifiedExpenseMessage.js} (82%) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.js similarity index 82% rename from src/libs/ModifiedExpenseMessage.ts rename to src/libs/ModifiedExpenseMessage.js index d0ebce1275b5..5428413efb96 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.js @@ -17,16 +17,7 @@ import * as ReportUtils from './ReportUtils'; * @param shouldConvertToLowercase */ -function buildMessageFragmentForValue( - newValue: string, - oldValue: string, - valueName: string, - valueInQuotes: boolean, - setFragments: string[], - removalFragments: string[], - changeFragments: string[], - shouldConvertToLowercase = true, -) { +function buildMessageFragmentForValue(newValue, oldValue, valueName, valueInQuotes, setFragments, removalFragments, changeFragments, shouldConvertToLowercase = true) { const newValueToDisplay = valueInQuotes ? `"${newValue}"` : newValue; const oldValueToDisplay = valueInQuotes ? `"${oldValue}"` : oldValue; const displayValueName = shouldConvertToLowercase ? valueName.toLowerCase() : valueName; @@ -52,25 +43,29 @@ function buildMessageFragmentForValue( * @param valueInQuotes */ -function getMessageLine(prefix: string, messageFragments: string[]) { +function getMessageLine(prefix, messageFragments) { if (messageFragments.length === 0) { return ''; } - return messageFragments.reduce((acc, value, index) => { - if (index === messageFragments.length - 1) { - if (messageFragments.length === 1) { - return `${acc} ${value}.`; + return _.reduce( + messageFragments, + (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 (messageFragments.length === 2) { - return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; + if (index === 0) { + return `${acc} ${value}`; } - return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; - } - if (index === 0) { - return `${acc} ${value}`; - } - return `${acc}, ${value}`; - }, prefix); + return `${acc}, ${value}`; + }, + prefix, + ); } /** @@ -80,9 +75,10 @@ function getMessageLine(prefix: string, messageFragments: string[]) { * @param oldDistance * @param newAmount * @param oldAmount + * @returns {String} */ -function getForDistanceRequest(newDistance: string, oldDistance: string, newAmount: string, oldAmount: string) { +function getForDistanceRequest(newDistance, oldDistance, newAmount, oldAmount) { if (!oldDistance) { return Localize.translateLocal('iou.setTheDistance', {newDistanceToDisplay: newDistance, newAmountToDisplay: newAmount}); } @@ -100,22 +96,22 @@ function getForDistanceRequest(newDistance: string, oldDistance: string, newAmou * ModifiedExpense::getNewDotComment in Web-Expensify should match this. * If we change this function be sure to update the backend as well. * - * @param reportAction + * @param {Object} reportAction + * @returns {String} */ -function getForReportAction(reportAction: Object): string { - const reportActionOriginalMessage: any = lodashGet(reportAction, 'originalMessage', {}); +function getForReportAction(reportAction) { + const reportActionOriginalMessage = lodashGet(reportAction, 'originalMessage', {}); if (_.isEmpty(reportActionOriginalMessage)) { return Localize.translateLocal('iou.changedTheRequest'); } const reportID = lodashGet(reportAction, 'reportID', ''); const policyID = lodashGet(ReportUtils.getReport(reportID), 'policyID', ''); const policyTags = PolicyUtils.getPolicyTags(policyID); - const policyTag = PolicyUtils.getTag(policyTags); - const policyTagListName = lodashGet(policyTag, 'name', Localize.translateLocal('common.tag')); + const policyTagListName = PolicyUtils.getTagListName(policyTags) || Localize.translateLocal('common.tag'); - const removalFragments: string[] = []; - const setFragments: string[] = []; - const changeFragments: string[] = []; + const removalFragments = []; + const setFragments = []; + const changeFragments = []; const hasModifiedAmount = _.has(reportActionOriginalMessage, 'oldAmount') && @@ -156,7 +152,7 @@ function getForReportAction(reportAction: Object): string { const hasModifiedCreated = _.has(reportActionOriginalMessage, 'oldCreated') && _.has(reportActionOriginalMessage, 'created'); if (hasModifiedCreated) { // Take only the YYYY-MM-DD value as the original date includes timestamp - let formattedOldCreated = format(new Date(reportActionOriginalMessage.oldCreated), CONST.DATE.FNS_FORMAT_STRING); + const formattedOldCreated = format(new Date(reportActionOriginalMessage.oldCreated), CONST.DATE.FNS_FORMAT_STRING); buildMessageFragmentForValue( reportActionOriginalMessage.created, formattedOldCreated, diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index ead8d20f838e..ee1243cc573d 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -1,7 +1,5 @@ import Str from 'expensify-common/lib/str'; -import lodashGet from 'lodash/get'; -import {OnyxCollection, OnyxEntry} from 'react-native-onyx'; -import Onyx from 'react-native-onyx'; +import Onyx, {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {PersonalDetails, Policy, PolicyMembers, PolicyTags} from '@src/types/onyx'; @@ -10,23 +8,20 @@ type MemberEmailsToAccountIDs = Record; type PersonalDetailsList = Record; type UnitRate = {rate: number}; -let allPolicyTags = {}; - +let allPolicyTags: OnyxCollection = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY_TAGS, waitForCollectionCallback: true, callback: (value) => { if (!value) { - allPolicyTags = {}; return; } - - allPolicyTags = value; + allPolicyTags = Object.fromEntries(Object.entries(value).filter(([, policyTags]) => !!policyTags)); }, }); function getPolicyTags(policyID: string) { - return lodashGet(allPolicyTags, `${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`, {}); + return allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {}; } /** From 371f138602ffb8f5ce4fb72d3d060bd46738e6ec Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Tue, 21 Nov 2023 02:04:39 +0200 Subject: [PATCH 20/46] Make it a ts file. --- src/libs/{ModifiedExpenseMessage.js => ModifiedExpenseMessage.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/libs/{ModifiedExpenseMessage.js => ModifiedExpenseMessage.ts} (100%) diff --git a/src/libs/ModifiedExpenseMessage.js b/src/libs/ModifiedExpenseMessage.ts similarity index 100% rename from src/libs/ModifiedExpenseMessage.js rename to src/libs/ModifiedExpenseMessage.ts From ceaa9156cf5b12284654b0c790509e9ee0423933 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Tue, 21 Nov 2023 02:49:30 +0200 Subject: [PATCH 21/46] Migrate to TS --- src/libs/ModifiedExpenseMessage.ts | 120 ++++++++++++++--------------- src/types/onyx/OriginalMessage.ts | 21 ++++- 2 files changed, 79 insertions(+), 62 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 5428413efb96..6ac50cc2984a 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -1,7 +1,7 @@ import {format} from 'date-fns'; import lodashGet from 'lodash/get'; -import _ from 'underscore'; import CONST from '@src/CONST'; +import {ReportAction} from '@src/types/onyx'; import * as CurrencyUtils from './CurrencyUtils'; import * as Localize from './Localize'; import * as PolicyUtils from './PolicyUtils'; @@ -17,7 +17,16 @@ import * as ReportUtils from './ReportUtils'; * @param shouldConvertToLowercase */ -function buildMessageFragmentForValue(newValue, oldValue, valueName, valueInQuotes, setFragments, removalFragments, changeFragments, shouldConvertToLowercase = true) { +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; @@ -43,29 +52,25 @@ function buildMessageFragmentForValue(newValue, oldValue, valueName, valueInQuot * @param valueInQuotes */ -function getMessageLine(prefix, messageFragments) { +function getMessageLine(prefix: string, messageFragments: string[]) { if (messageFragments.length === 0) { return ''; } - return _.reduce( - messageFragments, - (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}.`; + return messageFragments.reduce((acc, value, index) => { + if (index === messageFragments.length - 1) { + if (messageFragments.length === 1) { + return `${acc} ${value}.`; } - if (index === 0) { - return `${acc} ${value}`; + if (messageFragments.length === 2) { + return `${acc} ${Localize.translateLocal('common.and')} ${value}.`; } - return `${acc}, ${value}`; - }, - prefix, - ); + return `${acc}, ${Localize.translateLocal('common.and')} ${value}.`; + } + if (index === 0) { + return `${acc} ${value}`; + } + return `${acc}, ${value}`; + }, prefix); } /** @@ -78,7 +83,7 @@ function getMessageLine(prefix, messageFragments) { * @returns {String} */ -function getForDistanceRequest(newDistance, oldDistance, newAmount, oldAmount) { +function getForDistanceRequest(newDistance: string, oldDistance: string, newAmount: string, oldAmount: string) { if (!oldDistance) { return Localize.translateLocal('iou.setTheDistance', {newDistanceToDisplay: newDistance, newAmountToDisplay: newAmount}); } @@ -96,51 +101,46 @@ function getForDistanceRequest(newDistance, oldDistance, newAmount, oldAmount) { * ModifiedExpense::getNewDotComment in Web-Expensify should match this. * If we change this function be sure to update the backend as well. * - * @param {Object} reportAction - * @returns {String} + * @param reportAction */ -function getForReportAction(reportAction) { - const reportActionOriginalMessage = lodashGet(reportAction, 'originalMessage', {}); - if (_.isEmpty(reportActionOriginalMessage)) { - return Localize.translateLocal('iou.changedTheRequest'); +function getForReportAction(reportAction: ReportAction) { + if (reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE) { + return ''; } + const reportActionOriginalMessage = reportAction.originalMessage; const reportID = lodashGet(reportAction, 'reportID', ''); const policyID = lodashGet(ReportUtils.getReport(reportID), 'policyID', ''); const policyTags = PolicyUtils.getPolicyTags(policyID); const policyTagListName = PolicyUtils.getTagListName(policyTags) || Localize.translateLocal('common.tag'); - const removalFragments = []; - const setFragments = []; - const changeFragments = []; + const removalFragments: string[] = []; + const setFragments: string[] = []; + const changeFragments: string[] = []; - const hasModifiedAmount = - _.has(reportActionOriginalMessage, 'oldAmount') && - _.has(reportActionOriginalMessage, 'oldCurrency') && - _.has(reportActionOriginalMessage, 'amount') && - _.has(reportActionOriginalMessage, 'currency'); + const hasModifiedAmount = reportActionOriginalMessage.oldAmount && reportActionOriginalMessage.oldCurrency && reportActionOriginalMessage.amount && reportActionOriginalMessage.currency; - const hasModifiedMerchant = _.has(reportActionOriginalMessage, 'oldMerchant') && _.has(reportActionOriginalMessage, 'merchant'); + const hasModifiedMerchant = reportActionOriginalMessage.oldMerchant && reportActionOriginalMessage.merchant; if (hasModifiedAmount) { - const oldCurrency = reportActionOriginalMessage.oldCurrency; - const oldAmount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage.oldAmount, oldCurrency); + const oldCurrency = reportActionOriginalMessage.oldCurrency ?? ''; + const oldAmount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage.oldAmount ?? 0, oldCurrency); - const currency = reportActionOriginalMessage.currency; - const amount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage.amount, currency); + 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); + 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 = _.has(reportActionOriginalMessage, 'oldComment') && _.has(reportActionOriginalMessage, 'newComment'); + const hasModifiedComment = reportActionOriginalMessage.oldComment && reportActionOriginalMessage.newComment; if (hasModifiedComment) { buildMessageFragmentForValue( - reportActionOriginalMessage.newComment, - reportActionOriginalMessage.oldComment, + reportActionOriginalMessage.newComment ?? '', + reportActionOriginalMessage.oldComment ?? '', Localize.translateLocal('common.description'), true, setFragments, @@ -149,12 +149,12 @@ function getForReportAction(reportAction) { ); } - const hasModifiedCreated = _.has(reportActionOriginalMessage, 'oldCreated') && _.has(reportActionOriginalMessage, 'created'); + const hasModifiedCreated = reportActionOriginalMessage.oldCreated && reportActionOriginalMessage.created; if (hasModifiedCreated) { // Take only the YYYY-MM-DD value as the original date includes timestamp - const formattedOldCreated = format(new Date(reportActionOriginalMessage.oldCreated), CONST.DATE.FNS_FORMAT_STRING); + const formattedOldCreated = format(new Date(reportActionOriginalMessage.oldCreated ?? ''), CONST.DATE.FNS_FORMAT_STRING); buildMessageFragmentForValue( - reportActionOriginalMessage.created, + reportActionOriginalMessage.created ?? '', formattedOldCreated, Localize.translateLocal('common.date'), false, @@ -166,8 +166,8 @@ function getForReportAction(reportAction) { if (hasModifiedMerchant) { buildMessageFragmentForValue( - reportActionOriginalMessage.merchant, - reportActionOriginalMessage.oldMerchant, + reportActionOriginalMessage.merchant ?? '', + reportActionOriginalMessage.oldMerchant ?? '', Localize.translateLocal('common.merchant'), true, setFragments, @@ -176,11 +176,11 @@ function getForReportAction(reportAction) { ); } - const hasModifiedCategory = _.has(reportActionOriginalMessage, 'oldCategory') && _.has(reportActionOriginalMessage, 'category'); + const hasModifiedCategory = reportActionOriginalMessage.oldCategory && reportActionOriginalMessage.category; if (hasModifiedCategory) { buildMessageFragmentForValue( - reportActionOriginalMessage.category, - reportActionOriginalMessage.oldCategory, + reportActionOriginalMessage.category ?? '', + reportActionOriginalMessage.oldCategory ?? '', Localize.translateLocal('common.category'), true, setFragments, @@ -189,11 +189,11 @@ function getForReportAction(reportAction) { ); } - const hasModifiedTag = _.has(reportActionOriginalMessage, 'oldTag') && _.has(reportActionOriginalMessage, 'tag'); + const hasModifiedTag = reportActionOriginalMessage.oldTag && reportActionOriginalMessage.tag; if (hasModifiedTag) { buildMessageFragmentForValue( - reportActionOriginalMessage.tag, - reportActionOriginalMessage.oldTag, + reportActionOriginalMessage.tag ?? '', + reportActionOriginalMessage.oldTag ?? '', policyTagListName, true, setFragments, @@ -203,11 +203,11 @@ function getForReportAction(reportAction) { ); } - const hasModifiedBillable = _.has(reportActionOriginalMessage, 'oldBillable') && _.has(reportActionOriginalMessage, 'billable'); + const hasModifiedBillable = reportActionOriginalMessage.oldBillable && reportActionOriginalMessage.billable; if (hasModifiedBillable) { buildMessageFragmentForValue( - reportActionOriginalMessage.billable, - reportActionOriginalMessage.oldBillable, + reportActionOriginalMessage.billable ?? '', + reportActionOriginalMessage.oldBillable ?? '', Localize.translateLocal('iou.request'), true, setFragments, @@ -221,7 +221,7 @@ function getForReportAction(reportAction) { getMessageLine(`\n${Localize.translateLocal('iou.set')}`, setFragments) + getMessageLine(`\n${Localize.translateLocal('iou.removed')}`, removalFragments); if (message === '') { - return message; + return Localize.translateLocal('iou.changedTheRequest'); } message = `${message.substring(1, message.length)}`; return message; diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index b5e4b25a6508..c8ee5d5771de 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -171,7 +171,24 @@ type OriginalMessagePolicyTask = { type OriginalMessageModifiedExpense = { actionName: typeof CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE; - originalMessage: unknown; + originalMessage: { + oldMerchant?: string; + merchant?: string; + oldCurrency?: string; + currency?: string; + oldAmount?: number; + amount?: number; + oldComment?: string; + newComment?: string; + oldCreated?: string; + created?: string; + oldCategory?: string; + category?: string; + oldTag?: string; + tag?: string; + oldBillable?: string; + billable?: string; + }; }; type OriginalMessageReimbursementQueued = { @@ -196,4 +213,4 @@ type OriginalMessage = | OriginalMessageReimbursementQueued; export default OriginalMessage; -export type {ChronosOOOEvent, Decision, Reaction, ActionName}; +export type {ChronosOOOEvent, Decision, Reaction, ActionName, OriginalMessageModifiedExpense}; From 3bec4fd1f562b596cbb6f327f77aee3a210e8ab6 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Tue, 21 Nov 2023 03:42:23 +0200 Subject: [PATCH 22/46] Make Lint happy. --- src/libs/ModifiedExpenseMessage.ts | 5 +---- src/libs/ReportUtils.js | 11 +++++++++++ src/types/onyx/OriginalMessage.ts | 2 +- src/types/onyx/ReportAction.ts | 1 + 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 6ac50cc2984a..44259180f4eb 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -1,5 +1,4 @@ import {format} from 'date-fns'; -import lodashGet from 'lodash/get'; import CONST from '@src/CONST'; import {ReportAction} from '@src/types/onyx'; import * as CurrencyUtils from './CurrencyUtils'; @@ -80,7 +79,6 @@ function getMessageLine(prefix: string, messageFragments: string[]) { * @param oldDistance * @param newAmount * @param oldAmount - * @returns {String} */ function getForDistanceRequest(newDistance: string, oldDistance: string, newAmount: string, oldAmount: string) { @@ -108,8 +106,7 @@ function getForReportAction(reportAction: ReportAction) { return ''; } const reportActionOriginalMessage = reportAction.originalMessage; - const reportID = lodashGet(reportAction, 'reportID', ''); - const policyID = lodashGet(ReportUtils.getReport(reportID), 'policyID', ''); + const policyID = ReportUtils.getReportPolicyID(reportAction.reportID ?? ''); const policyTags = PolicyUtils.getPolicyTags(policyID); const policyTagListName = PolicyUtils.getTagListName(policyTags) || Localize.translateLocal('common.tag'); diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 2a3db8437518..248df849ca52 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -823,6 +823,16 @@ function getReport(reportID) { return lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {}) || {}; } +/** + * Get the report policyID given a reportID + * + * @param {String} reportID + * @returns {String} + */ +function getReportPolicyID(reportID) { + return getReport(reportID).policyID || ''; +} + /** * Get the notification preference given a report * @@ -4173,6 +4183,7 @@ export { getDisplayNamesWithTooltips, getDisplayNamesStringFromTooltips, getReportName, + getReportPolicyID, getReport, getReportNotificationPreference, getReportIDFromLink, diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index c8ee5d5771de..5e1bdfb7cf81 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -213,4 +213,4 @@ type OriginalMessage = | OriginalMessageReimbursementQueued; export default OriginalMessage; -export type {ChronosOOOEvent, Decision, Reaction, ActionName, OriginalMessageModifiedExpense}; +export type {ChronosOOOEvent, Decision, Reaction, ActionName}; diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 2195c4e3ff0b..e67c075e54f1 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -90,6 +90,7 @@ type ReportActionBase = { avatar?: string; automatic?: boolean; shouldShow?: boolean; + reportID?: string; childReportID?: string; childReportName?: string; childType?: string; From b350c6b9fcfde9eb5aa68cea5ba0d881bce6ec7c Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 00:36:24 +0200 Subject: [PATCH 23/46] Update src/libs/ModifiedExpenseMessage.ts Co-authored-by: Tim Golen --- src/libs/ModifiedExpenseMessage.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 44259180f4eb..544ced26cc28 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -72,15 +72,6 @@ function getMessageLine(prefix: string, messageFragments: string[]) { }, prefix); } -/** - * Get the message for a modified distance request. - * - * @param newDistance - * @param oldDistance - * @param newAmount - * @param oldAmount - */ - function getForDistanceRequest(newDistance: string, oldDistance: string, newAmount: string, oldAmount: string) { if (!oldDistance) { return Localize.translateLocal('iou.setTheDistance', {newDistanceToDisplay: newDistance, newAmountToDisplay: newAmount}); From 03931a24e14d0746eada51c63a4a3f630fff5c75 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 00:36:33 +0200 Subject: [PATCH 24/46] Update src/libs/ModifiedExpenseMessage.ts Co-authored-by: Tim Golen --- src/libs/ModifiedExpenseMessage.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 544ced26cc28..e82c037cf632 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -89,8 +89,6 @@ function getForDistanceRequest(newDistance: string, oldDistance: string, newAmou * * ModifiedExpense::getNewDotComment in Web-Expensify should match this. * If we change this function be sure to update the backend as well. - * - * @param reportAction */ function getForReportAction(reportAction: ReportAction) { if (reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE) { From 4e9a118da27b1233123d9c5552925d5f71475b5f Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 00:36:41 +0200 Subject: [PATCH 25/46] Update src/libs/ModifiedExpenseMessage.ts Co-authored-by: Tim Golen --- src/libs/ModifiedExpenseMessage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index e82c037cf632..8e7b27b55ce4 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -90,7 +90,7 @@ function getForDistanceRequest(newDistance: string, oldDistance: string, newAmou * 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) { +function getForReportAction(reportAction: ReportAction): string { if (reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE) { return ''; } From 41f8a94198a6eb74f4662e1edd4f17b6fe46c88f Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 17:26:37 +0200 Subject: [PATCH 26/46] Resolve conflicts after merge. --- src/libs/ReportUtils.ts | 143 ++------------------------------- src/types/onyx/ReportAction.ts | 1 - 2 files changed, 8 insertions(+), 136 deletions(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index d93661778b83..da00bc1c5c18 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1953,140 +1953,6 @@ function getReportPreviewMessage( return Localize.translateLocal(containsNonReimbursable ? 'iou.payerSpentAmount' : 'iou.payerOwesAmount', {payer: payerName ?? '', amount: formattedAmount}); } -/** - * Get the proper message schema for modified expense message. - */ - -function getProperSchemaForModifiedExpenseMessage(newValue: string, oldValue: string, valueName: string, valueInQuotes: boolean, shouldConvertToLowercase = true): string { - const newValueToDisplay = valueInQuotes ? `"${newValue}"` : newValue; - const oldValueToDisplay = valueInQuotes ? `"${oldValue}"` : oldValue; - const displayValueName = shouldConvertToLowercase ? valueName.toLowerCase() : valueName; - - if (!oldValue) { - return Localize.translateLocal('iou.setTheRequest', {valueName: displayValueName, newValueToDisplay}); - } - if (!newValue) { - return Localize.translateLocal('iou.removedTheRequest', {valueName: displayValueName, oldValueToDisplay}); - } - return Localize.translateLocal('iou.updatedTheRequest', {valueName: displayValueName, newValueToDisplay, oldValueToDisplay}); -} - -/** - * Get the proper message schema for modified distance message. - */ -function getProperSchemaForModifiedDistanceMessage(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 getModifiedExpenseMessage(reportAction: OnyxEntry): string | undefined { - const reportActionOriginalMessage = reportAction?.originalMessage as ExpenseOriginalMessage | undefined; - if (isEmptyObject(reportActionOriginalMessage)) { - return Localize.translateLocal('iou.changedTheRequest'); - } - const reportID = reportAction?.reportID ?? ''; - const policyID = getReport(reportID)?.policyID ?? ''; - const policyTags = getPolicyTags(policyID); - const policyTag = PolicyUtils.getTag(policyTags); - const policyTagListName = policyTag?.name ?? Localize.translateLocal('common.tag'); - - 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 getProperSchemaForModifiedDistanceMessage(reportActionOriginalMessage?.merchant, reportActionOriginalMessage?.oldMerchant ?? '', amount, oldAmount); - } - - return getProperSchemaForModifiedExpenseMessage(amount, oldAmount, Localize.translateLocal('iou.amount'), false); - } - - const hasModifiedComment = reportActionOriginalMessage && 'oldComment' in reportActionOriginalMessage && 'newComment' in reportActionOriginalMessage; - if (hasModifiedComment) { - return getProperSchemaForModifiedExpenseMessage( - reportActionOriginalMessage?.newComment ?? '', - reportActionOriginalMessage?.oldComment ?? '', - Localize.translateLocal('common.description'), - true, - ); - } - - 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 ?? 0); - formattedOldCreated = format(formattedOldCreated, CONST.DATE.FNS_FORMAT_STRING); - - return getProperSchemaForModifiedExpenseMessage(reportActionOriginalMessage?.created ?? '', formattedOldCreated?.toString?.(), Localize.translateLocal('common.date'), false); - } - - if (hasModifiedMerchant) { - return getProperSchemaForModifiedExpenseMessage( - reportActionOriginalMessage?.merchant ?? '', - reportActionOriginalMessage?.oldMerchant ?? '', - Localize.translateLocal('common.merchant'), - true, - ); - } - - const hasModifiedCategory = reportActionOriginalMessage && 'oldCategory' in reportActionOriginalMessage && 'category' in reportActionOriginalMessage; - if (hasModifiedCategory) { - return getProperSchemaForModifiedExpenseMessage( - reportActionOriginalMessage?.category ?? '', - reportActionOriginalMessage?.oldCategory ?? '', - Localize.translateLocal('common.category'), - true, - ); - } - - const hasModifiedTag = reportActionOriginalMessage && 'oldTag' in reportActionOriginalMessage && 'tag' in reportActionOriginalMessage; - if (hasModifiedTag) { - return getProperSchemaForModifiedExpenseMessage( - reportActionOriginalMessage.tag ?? '', - reportActionOriginalMessage.oldTag ?? '', - policyTagListName, - true, - policyTagListName === Localize.translateLocal('common.tag'), - ); - } - - const hasModifiedBillable = reportActionOriginalMessage && 'oldBillable' in reportActionOriginalMessage && 'billable' in reportActionOriginalMessage; - if (hasModifiedBillable) { - return getProperSchemaForModifiedExpenseMessage( - reportActionOriginalMessage?.billable ?? '', - reportActionOriginalMessage?.oldBillable ?? '', - Localize.translateLocal('iou.request'), - true, - ); - } -} - /** * Given the updates user made to the request, compose the originalMessage * object of the modified expense action. @@ -3650,6 +3516,13 @@ function getReportIDFromLink(url: string | null): string { return reportID; } +/** + * Get the report policyID given a reportID + */ +function getReportPolicyID(reportID: string | undefined): string|undefined { + return getReport(reportID)?.policyID; +} + /** * Check if the chat report is linked to an iou that is waiting for the current user to add a credit bank account. */ @@ -4267,6 +4140,7 @@ export { getReport, getReportNotificationPreference, getReportIDFromLink, + getReportPolicyID, getRouteFromLink, getDeletedParentActionMessageForChatReport, getLastVisibleMessage, @@ -4342,7 +4216,6 @@ export { getParentReport, getRootParentReport, getReportPreviewMessage, - getModifiedExpenseMessage, canUserPerformWriteAction, getOriginalReportID, canAccessReport, diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index 95f5574e5432..891a0ffcb7b8 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -90,7 +90,6 @@ type ReportActionBase = { automatic?: boolean; shouldShow?: boolean; - reportID?: string; /** The ID of childReport */ childReportID?: string; From ceff5c197b0301bd3dd95e0e5cd45389b76d9cb1 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 17:36:56 +0200 Subject: [PATCH 27/46] Move policyTags to ModifiedExpenseMessage --- src/libs/ModifiedExpenseMessage.ts | 21 ++++++++++++++++++--- src/libs/PolicyUtils.ts | 19 +------------------ 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 8e7b27b55ce4..decc4c5a9863 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -1,11 +1,26 @@ import {format} from 'date-fns'; import CONST from '@src/CONST'; -import {ReportAction} from '@src/types/onyx'; +import {PolicyTags, ReportAction} from '@src/types/onyx'; +import Onyx, {OnyxCollection} from 'react-native-onyx'; +import ONYXKEYS from '@src/ONYXKEYS'; import * as CurrencyUtils from './CurrencyUtils'; import * as Localize from './Localize'; import * as PolicyUtils from './PolicyUtils'; import * as ReportUtils from './ReportUtils'; + +let allPolicyTags: OnyxCollection = {}; +Onyx.connect({ + key: ONYXKEYS.COLLECTION.POLICY_TAGS, + waitForCollectionCallback: true, + callback: (value) => { + if (!value) { + return; + } + allPolicyTags = Object.fromEntries(Object.entries(value).filter(([, policyTags]) => !!policyTags)); + }, +}); + /** * Builds the partial message fragment for a modified field on the expense. * @@ -95,8 +110,8 @@ function getForReportAction(reportAction: ReportAction): string { return ''; } const reportActionOriginalMessage = reportAction.originalMessage; - const policyID = ReportUtils.getReportPolicyID(reportAction.reportID ?? ''); - const policyTags = PolicyUtils.getPolicyTags(policyID); + 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[] = []; diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts index e7328972cfa1..19129959d016 100644 --- a/src/libs/PolicyUtils.ts +++ b/src/libs/PolicyUtils.ts @@ -1,5 +1,5 @@ import Str from 'expensify-common/lib/str'; -import Onyx, {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import {OnyxCollection, OnyxEntry} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {PersonalDetails, Policy, PolicyMembers, PolicyTag, PolicyTags} from '@src/types/onyx'; @@ -9,22 +9,6 @@ type MemberEmailsToAccountIDs = Record; type PersonalDetailsList = Record; type UnitRate = {rate: number}; -let allPolicyTags: OnyxCollection = {}; -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY_TAGS, - waitForCollectionCallback: true, - callback: (value) => { - if (!value) { - return; - } - allPolicyTags = Object.fromEntries(Object.entries(value).filter(([, policyTags]) => !!policyTags)); - }, -}); - -function getPolicyTags(policyID: string) { - return allPolicyTags?.[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {}; -} - /** * Filter out the active policies, which will exclude policies with pending deletion * These are policies that we can use to create reports with in NewDot. @@ -216,7 +200,6 @@ function isPendingDeletePolicy(policy: OnyxEntry): boolean { export { getActivePolicies, - getPolicyTags, hasPolicyMemberError, hasPolicyError, hasPolicyErrorFields, From 57f083782f1e8ebbfc36ead4f7d0f49854262e99 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 17:55:30 +0200 Subject: [PATCH 28/46] Remove unused function. --- src/libs/ModifiedExpenseMessage.ts | 7 ++++--- src/libs/ReportUtils.ts | 19 ------------------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index decc4c5a9863..293411972858 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -1,7 +1,7 @@ import {format} from 'date-fns'; import CONST from '@src/CONST'; import {PolicyTags, ReportAction} from '@src/types/onyx'; -import Onyx, {OnyxCollection} from 'react-native-onyx'; +import Onyx from 'react-native-onyx'; import ONYXKEYS from '@src/ONYXKEYS'; import * as CurrencyUtils from './CurrencyUtils'; import * as Localize from './Localize'; @@ -9,15 +9,16 @@ import * as PolicyUtils from './PolicyUtils'; import * as ReportUtils from './ReportUtils'; -let allPolicyTags: OnyxCollection = {}; +let allPolicyTags: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY_TAGS, waitForCollectionCallback: true, callback: (value) => { if (!value) { + allPolicyTags = {}; return; } - allPolicyTags = Object.fromEntries(Object.entries(value).filter(([, policyTags]) => !!policyTags)); + allPolicyTags = value; }, }); diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index da00bc1c5c18..2280f3283b80 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -400,25 +400,6 @@ Onyx.connect({ callback: (value) => (loginList = value), }); -let allPolicyTags: Record = {}; - -Onyx.connect({ - key: ONYXKEYS.COLLECTION.POLICY_TAGS, - waitForCollectionCallback: true, - callback: (value) => { - if (!value) { - allPolicyTags = {}; - return; - } - - allPolicyTags = value; - }, -}); - -function getPolicyTags(policyID: string) { - return allPolicyTags[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${policyID}`] ?? {}; -} - function getChatType(report: OnyxEntry): ValueOf | undefined { return report?.chatType; } From 7dd7afb9265cc2d10eaab94313b72520749738b0 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 18:25:48 +0200 Subject: [PATCH 29/46] Make lint happy. --- src/libs/ModifiedExpenseMessage.ts | 5 ++--- src/libs/ReportUtils.ts | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 293411972858..558409fe3a51 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -1,14 +1,13 @@ import {format} from 'date-fns'; -import CONST from '@src/CONST'; -import {PolicyTags, ReportAction} from '@src/types/onyx'; 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'; - let allPolicyTags: Record = {}; Onyx.connect({ key: ONYXKEYS.COLLECTION.POLICY_TAGS, diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 2280f3283b80..dabfa271f7c7 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1,4 +1,3 @@ -import {format} from 'date-fns'; import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import Str from 'expensify-common/lib/str'; import lodashEscape from 'lodash/escape'; @@ -14,7 +13,7 @@ import CONST from '@src/CONST'; import {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import {Beta, Login, PersonalDetails, Policy, PolicyTags, Report, ReportAction, Transaction} from '@src/types/onyx'; +import {Beta, Login, PersonalDetails, Policy, Report, ReportAction, Transaction} from '@src/types/onyx'; import {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; import {ChangeLog, IOUMessage, OriginalMessageActionName} from '@src/types/onyx/OriginalMessage'; import {Message, ReportActions} from '@src/types/onyx/ReportAction'; @@ -3500,7 +3499,7 @@ function getReportIDFromLink(url: string | null): string { /** * Get the report policyID given a reportID */ -function getReportPolicyID(reportID: string | undefined): string|undefined { +function getReportPolicyID(reportID: string | undefined): string | undefined { return getReport(reportID)?.policyID; } From 1cb7f4751f3b99d9e462a871e2a33d821c50c761 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 18:33:51 +0200 Subject: [PATCH 30/46] Better checks. --- src/libs/ModifiedExpenseMessage.ts | 57 ++++++++++++++++-------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 558409fe3a51..aaa6cd10f656 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -118,30 +118,35 @@ function getForReportAction(reportAction: ReportAction): string { const setFragments: string[] = []; const changeFragments: string[] = []; - const hasModifiedAmount = reportActionOriginalMessage.oldAmount && reportActionOriginalMessage.oldCurrency && reportActionOriginalMessage.amount && reportActionOriginalMessage.currency; - - const hasModifiedMerchant = reportActionOriginalMessage.oldMerchant && reportActionOriginalMessage.merchant; + 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 oldCurrency = reportActionOriginalMessage?.oldCurrency ?? ''; + const oldAmount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage?.oldAmount ?? 0, oldCurrency); - const currency = reportActionOriginalMessage.currency ?? ''; - const amount = CurrencyUtils.convertToDisplayString(reportActionOriginalMessage.amount ?? 0, currency); + 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); + 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 && reportActionOriginalMessage.newComment; + const hasModifiedComment = reportActionOriginalMessage && 'oldComment' in reportActionOriginalMessage && 'newComment' in reportActionOriginalMessage; if (hasModifiedComment) { buildMessageFragmentForValue( - reportActionOriginalMessage.newComment ?? '', - reportActionOriginalMessage.oldComment ?? '', + reportActionOriginalMessage?.newComment ?? '', + reportActionOriginalMessage?.oldComment ?? '', Localize.translateLocal('common.description'), true, setFragments, @@ -150,12 +155,12 @@ function getForReportAction(reportAction: ReportAction): string { ); } - const hasModifiedCreated = reportActionOriginalMessage.oldCreated && reportActionOriginalMessage.created; + const hasModifiedCreated = reportActionOriginalMessage && 'oldCreated' in reportActionOriginalMessage && 'created' in reportActionOriginalMessage; if (hasModifiedCreated) { // Take only the YYYY-MM-DD value as the original date includes timestamp - const formattedOldCreated = format(new Date(reportActionOriginalMessage.oldCreated ?? ''), CONST.DATE.FNS_FORMAT_STRING); + const formattedOldCreated = format(new Date(reportActionOriginalMessage?.oldCreated ?? ''), CONST.DATE.FNS_FORMAT_STRING); buildMessageFragmentForValue( - reportActionOriginalMessage.created ?? '', + reportActionOriginalMessage?.created ?? '', formattedOldCreated, Localize.translateLocal('common.date'), false, @@ -167,8 +172,8 @@ function getForReportAction(reportAction: ReportAction): string { if (hasModifiedMerchant) { buildMessageFragmentForValue( - reportActionOriginalMessage.merchant ?? '', - reportActionOriginalMessage.oldMerchant ?? '', + reportActionOriginalMessage?.merchant ?? '', + reportActionOriginalMessage?.oldMerchant ?? '', Localize.translateLocal('common.merchant'), true, setFragments, @@ -177,11 +182,11 @@ function getForReportAction(reportAction: ReportAction): string { ); } - const hasModifiedCategory = reportActionOriginalMessage.oldCategory && reportActionOriginalMessage.category; + const hasModifiedCategory = reportActionOriginalMessage && 'oldCategory' in reportActionOriginalMessage && 'category' in reportActionOriginalMessage; if (hasModifiedCategory) { buildMessageFragmentForValue( - reportActionOriginalMessage.category ?? '', - reportActionOriginalMessage.oldCategory ?? '', + reportActionOriginalMessage?.category ?? '', + reportActionOriginalMessage?.oldCategory ?? '', Localize.translateLocal('common.category'), true, setFragments, @@ -190,11 +195,11 @@ function getForReportAction(reportAction: ReportAction): string { ); } - const hasModifiedTag = reportActionOriginalMessage.oldTag && reportActionOriginalMessage.tag; + const hasModifiedTag = reportActionOriginalMessage && 'oldTag' in reportActionOriginalMessage && 'tag' in reportActionOriginalMessage; if (hasModifiedTag) { buildMessageFragmentForValue( - reportActionOriginalMessage.tag ?? '', - reportActionOriginalMessage.oldTag ?? '', + reportActionOriginalMessage?.tag ?? '', + reportActionOriginalMessage?.oldTag ?? '', policyTagListName, true, setFragments, @@ -204,11 +209,11 @@ function getForReportAction(reportAction: ReportAction): string { ); } - const hasModifiedBillable = reportActionOriginalMessage.oldBillable && reportActionOriginalMessage.billable; + const hasModifiedBillable = reportActionOriginalMessage && 'oldBillable' in reportActionOriginalMessage && 'billable' in reportActionOriginalMessage; if (hasModifiedBillable) { buildMessageFragmentForValue( - reportActionOriginalMessage.billable ?? '', - reportActionOriginalMessage.oldBillable ?? '', + reportActionOriginalMessage?.billable ?? '', + reportActionOriginalMessage?.oldBillable ?? '', Localize.translateLocal('iou.request'), true, setFragments, From 388962f32841fc35c16534edc62acc12b33ca2d8 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 18:58:40 +0200 Subject: [PATCH 31/46] Update src/libs/ReportUtils.ts Co-authored-by: Tim Golen --- src/libs/ReportUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index dabfa271f7c7..6f6514cbd3cb 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3499,7 +3499,7 @@ function getReportIDFromLink(url: string | null): string { /** * Get the report policyID given a reportID */ -function getReportPolicyID(reportID: string | undefined): string | undefined { +function getReportPolicyID(reportID?: string)?: string { return getReport(reportID)?.policyID; } From 9cc76370e105259bc2a74a74536e3dbca233237c Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 18:59:04 +0200 Subject: [PATCH 32/46] Update src/libs/ModifiedExpenseMessage.ts Co-authored-by: Tim Golen --- src/libs/ModifiedExpenseMessage.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index aaa6cd10f656..644002bc2503 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -229,8 +229,7 @@ function getForReportAction(reportAction: ReportAction): string { if (message === '') { return Localize.translateLocal('iou.changedTheRequest'); } - message = `${message.substring(1, message.length)}`; - return message; + return `${message.substring(1, message.length)}`; } export default { From 60a1493613d22e702556bb9898049413be27a979 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 19:00:28 +0200 Subject: [PATCH 33/46] Improve function doc. --- src/libs/ModifiedExpenseMessage.ts | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index 644002bc2503..f60cd2222ae7 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -23,14 +23,7 @@ Onyx.connect({ /** * Builds the partial message fragment for a modified field on the expense. - * - * @param newValue - * @param oldValue - * @param valueName - * @param valueInQuotes - * @param shouldConvertToLowercase */ - function buildMessageFragmentForValue( newValue: string, oldValue: string, @@ -59,13 +52,7 @@ function buildMessageFragmentForValue( /** * Get the message line for a modified expense. - * - * @param newValue - * @param oldValue - * @param valueName - * @param valueInQuotes */ - function getMessageLine(prefix: string, messageFragments: string[]) { if (messageFragments.length === 0) { return ''; From 8dd3c9992bdb78f8e4fbaa56feeee9e5779fc425 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Wed, 29 Nov 2023 19:06:27 +0200 Subject: [PATCH 34/46] Add return type declaration --- src/libs/ModifiedExpenseMessage.ts | 6 +++--- src/libs/ReportUtils.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index f60cd2222ae7..e0c4860c9d49 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -53,7 +53,7 @@ function buildMessageFragmentForValue( /** * Get the message line for a modified expense. */ -function getMessageLine(prefix: string, messageFragments: string[]) { +function getMessageLine(prefix: string, messageFragments: string[]): string { if (messageFragments.length === 0) { return ''; } @@ -74,7 +74,7 @@ function getMessageLine(prefix: string, messageFragments: string[]) { }, prefix); } -function getForDistanceRequest(newDistance: string, oldDistance: string, newAmount: string, oldAmount: string) { +function getForDistanceRequest(newDistance: string, oldDistance: string, newAmount: string, oldAmount: string): string { if (!oldDistance) { return Localize.translateLocal('iou.setTheDistance', {newDistanceToDisplay: newDistance, newAmountToDisplay: newAmount}); } @@ -209,7 +209,7 @@ function getForReportAction(reportAction: ReportAction): string { ); } - let message = + const message = getMessageLine(`\n${Localize.translateLocal('iou.changed')}`, changeFragments) + getMessageLine(`\n${Localize.translateLocal('iou.set')}`, setFragments) + getMessageLine(`\n${Localize.translateLocal('iou.removed')}`, removalFragments); diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6f6514cbd3cb..f55b576f5e6c 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -3499,7 +3499,7 @@ function getReportIDFromLink(url: string | null): string { /** * Get the report policyID given a reportID */ -function getReportPolicyID(reportID?: string)?: string { +function getReportPolicyID(reportID?: string): string | undefined { return getReport(reportID)?.policyID; } From a136b74b3a7231a78d8d183c3fb5cb3e8d9c062d Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 00:14:09 +0200 Subject: [PATCH 35/46] Fix conflicts after merge --- .../Notification/LocalNotification/BrowserNotifications.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.ts b/src/libs/Notification/LocalNotification/BrowserNotifications.ts index dd07ddbb5e33..35ebf4e0988d 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.ts +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.ts @@ -2,6 +2,7 @@ import EXPENSIFY_ICON_URL from '@assets/images/expensify-logo-round-clearspace.png'; import * as ReportUtils from '@libs/ReportUtils'; import * as AppUpdate from '@userActions/AppUpdate'; +import * as ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage' import focusApp from './focusApp'; import {PushParams, ReportCommentParams} from './types'; @@ -115,7 +116,7 @@ export default { pushModifiedExpenseNotification({reportAction, onClick}: ReportCommentParams, usesIcon = false) { push({ title: reportAction.person?.map((f) => f.text).join(', ') ?? '', - body: ReportUtils.getModifiedExpenseMessage(reportAction), + body: ModifiedExpenseMessage.getForReportAction(reportAction), delay: 0, onClick, icon: usesIcon ? EXPENSIFY_ICON_URL : '', From 262cb52236d4bc5689c951007ce69f0cc465002a Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 00:41:20 +0200 Subject: [PATCH 36/46] RUn prettier --- src/libs/Notification/LocalNotification/BrowserNotifications.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.ts b/src/libs/Notification/LocalNotification/BrowserNotifications.ts index 35ebf4e0988d..3a35a7812e1d 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.ts +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.ts @@ -1,8 +1,8 @@ // Web and desktop implementation only. Do not import for direct use. Use LocalNotification. import EXPENSIFY_ICON_URL from '@assets/images/expensify-logo-round-clearspace.png'; +import * as ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; import * as ReportUtils from '@libs/ReportUtils'; import * as AppUpdate from '@userActions/AppUpdate'; -import * as ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage' import focusApp from './focusApp'; import {PushParams, ReportCommentParams} from './types'; From cd28c6173d7378e74776b3b48ec1cc4ce331448f Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 01:13:19 +0200 Subject: [PATCH 37/46] Performance test for ModifiedExpenseMessage --- .../ModifiedExpenseMessage.perf-test.ts | 66 +++++++++++++++++++ tests/perf-test/ReportUtils.perf-test.ts | 24 ------- 2 files changed, 66 insertions(+), 24 deletions(-) create mode 100644 tests/perf-test/ModifiedExpenseMessage.perf-test.ts diff --git a/tests/perf-test/ModifiedExpenseMessage.perf-test.ts b/tests/perf-test/ModifiedExpenseMessage.perf-test.ts new file mode 100644 index 000000000000..19cccfb94126 --- /dev/null +++ b/tests/perf-test/ModifiedExpenseMessage.perf-test.ts @@ -0,0 +1,66 @@ +import {randAmount} from '@ngneat/falso'; +import Onyx from 'react-native-onyx'; +import {measureFunction} from 'reassure'; +import CONST from '@src/CONST'; +import ONYXKEYS from '@src/ONYXKEYS'; +import {Policy, Report} from '@src/types/onyx'; +import ModifiedExpenseMessage from '../../src/libs/ModifiedExpenseMessage'; +import createCollection from '../utils/collections/createCollection'; +import createRandomPolicy from '../utils/collections/policies'; +import createRandomReportAction from '../utils/collections/reportActions'; +import createRandomReport from '../utils/collections/reports'; +import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; + +const runs = CONST.PERFORMANCE_TESTS.RUNS; + +beforeAll(() => + Onyx.init({ + keys: ONYXKEYS, + safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], + }), +); + +// Clear out Onyx after each test so that each test starts with a clean state +afterEach(() => { + Onyx.clear(); +}); + +const getMockedReports = (length = 500) => + createCollection( + (item) => `${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`, + (index) => createRandomReport(index), + length, + ); + +const getMockedPolicies = (length = 500) => + createCollection( + (item) => `${ONYXKEYS.COLLECTION.POLICY}${item.id}`, + (index) => createRandomPolicy(index), + length, + ); + +const mockedReportsMap = getMockedReports(5000) as Record<`${typeof ONYXKEYS.COLLECTION.REPORT}`, Report>; +const mockedPoliciesMap = getMockedPolicies(5000) as Record<`${typeof ONYXKEYS.COLLECTION.POLICY}`, Policy>; + +test('[ModifiedExpenseMessage] getForReportAction on 5k reports and policies', async () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + originalMessage: { + amount: randAmount(), + currency: CONST.CURRENCY.USD, + oldAmount: randAmount(), + oldCurrency: CONST.CURRENCY.USD, + }, + }, + }; + + await Onyx.multiSet({ + ...mockedPoliciesMap, + ...mockedReportsMap, + }); + + await waitForBatchedUpdates(); + await measureFunction(() => ModifiedExpenseMessage.getForReportAction(reportAction), {runs}); +}); diff --git a/tests/perf-test/ReportUtils.perf-test.ts b/tests/perf-test/ReportUtils.perf-test.ts index ab6ee72a0082..b931ae85a7da 100644 --- a/tests/perf-test/ReportUtils.perf-test.ts +++ b/tests/perf-test/ReportUtils.perf-test.ts @@ -1,4 +1,3 @@ -import {randAmount} from '@ngneat/falso'; import Onyx from 'react-native-onyx'; import {measureFunction} from 'reassure'; import * as ReportUtils from '@libs/ReportUtils'; @@ -133,29 +132,6 @@ test('[ReportUtils] getReportPreviewMessage on 5k policies', async () => { await measureFunction(() => ReportUtils.getReportPreviewMessage(report, reportAction, shouldConsiderReceiptBeingScanned, isPreviewMessageForParentChatReport, policy), {runs}); }); -test('[ReportUtils] getModifiedExpenseMessage on 5k reports and policies', async () => { - const reportAction = { - ...createRandomReportAction(1), - actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, - originalMessage: { - originalMessage: { - amount: randAmount(), - currency: CONST.CURRENCY.USD, - oldAmount: randAmount(), - oldCurrency: CONST.CURRENCY.USD, - }, - }, - }; - - await Onyx.multiSet({ - ...mockedPoliciesMap, - ...mockedReportsMap, - }); - - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getModifiedExpenseMessage(reportAction), {runs}); -}); - test('[ReportUtils] getReportName on 1k participants', async () => { const report = {...createRandomReport(1), chatType: undefined, participantAccountIDs}; const policy = createRandomPolicy(1); From 5219b6a7d31c9e938234ae912f0f6360a4879ebc Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 01:34:21 +0200 Subject: [PATCH 38/46] Fix typecheck failures --- src/libs/ModifiedExpenseMessage.ts | 3 ++- .../Notification/LocalNotification/BrowserNotifications.ts | 2 +- src/libs/ReportUtils.ts | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index e0c4860c9d49..aa1604f9536a 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -7,6 +7,7 @@ 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 = {}; Onyx.connect({ @@ -96,7 +97,7 @@ function getForReportAction(reportAction: ReportAction): string { if (reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE) { return ''; } - const reportActionOriginalMessage = reportAction.originalMessage; + 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'); diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.ts b/src/libs/Notification/LocalNotification/BrowserNotifications.ts index 3a35a7812e1d..7e3142576f68 100644 --- a/src/libs/Notification/LocalNotification/BrowserNotifications.ts +++ b/src/libs/Notification/LocalNotification/BrowserNotifications.ts @@ -1,6 +1,6 @@ // Web and desktop implementation only. Do not import for direct use. Use LocalNotification. import EXPENSIFY_ICON_URL from '@assets/images/expensify-logo-round-clearspace.png'; -import * as ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; +import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; import * as ReportUtils from '@libs/ReportUtils'; import * as AppUpdate from '@userActions/AppUpdate'; import focusApp from './focusApp'; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 6b11234d93e0..038ce5f25111 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -4340,4 +4340,4 @@ export { shouldAutoFocusOnKeyPress, }; -export type {OptionData, OptimisticChatReport}; +export type {ExpenseOriginalMessage, OptionData, OptimisticChatReport}; From df908501cd5efec6efee5dd07af48fdc0f6fff78 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 02:03:35 +0200 Subject: [PATCH 39/46] Unit test for ModifiedExpenseMessage --- .../ModifiedExpenseMessage.perf-test.ts | 10 ++- tests/unit/ModifiedExpenseMessageTest.ts | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 tests/unit/ModifiedExpenseMessageTest.ts diff --git a/tests/perf-test/ModifiedExpenseMessage.perf-test.ts b/tests/perf-test/ModifiedExpenseMessage.perf-test.ts index 19cccfb94126..1997d55d8a05 100644 --- a/tests/perf-test/ModifiedExpenseMessage.perf-test.ts +++ b/tests/perf-test/ModifiedExpenseMessage.perf-test.ts @@ -47,12 +47,10 @@ test('[ModifiedExpenseMessage] getForReportAction on 5k reports and policies', a ...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, originalMessage: { - originalMessage: { - amount: randAmount(), - currency: CONST.CURRENCY.USD, - oldAmount: randAmount(), - oldCurrency: CONST.CURRENCY.USD, - }, + amount: randAmount(), + currency: CONST.CURRENCY.USD, + oldAmount: randAmount(), + oldCurrency: CONST.CURRENCY.USD, }, }; diff --git a/tests/unit/ModifiedExpenseMessageTest.ts b/tests/unit/ModifiedExpenseMessageTest.ts new file mode 100644 index 000000000000..65ba1238a302 --- /dev/null +++ b/tests/unit/ModifiedExpenseMessageTest.ts @@ -0,0 +1,65 @@ +import {randAmount} from '@ngneat/falso'; +import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; +import CONST from '@src/CONST'; +import * as TransactionUtils from '../../src/libs/TransactionUtils'; +import type {Transaction} from '../../src/types/onyx'; +import createRandomReportAction from '../utils/collections/reportActions'; + +function generateTransaction(values: Partial = {}): Transaction { + const reportID = '1'; + const amount = 100; + const currency = 'USD'; + const comment = ''; + const created = '2023-10-01'; + const baseValues = TransactionUtils.buildOptimisticTransaction(amount, currency, reportID, comment, created); + + return {...baseValues, ...values}; +} + +describe('ModifiedExpenseMessage', () => { + describe('getForAction', () => { + describe('when the amount is changed', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + amount: 1800, + currency: CONST.CURRENCY.USD, + oldAmount: 1255, + oldCurrency: CONST.CURRENCY.USD, + }, + }; + + it('returns the correct text message', () => { + const expectedResult = `changed the amount to $18.00 (previously $12.55).`; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('when the amount is changed and the description is removed', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + amount: 1800, + currency: CONST.CURRENCY.USD, + oldAmount: 1255, + oldCurrency: CONST.CURRENCY.USD, + newComment: '', + oldComment: 'this is for the shuttle', + }, + }; + + it('returns the correct text message', () => { + const expectedResult = 'changed the amount to $18.00 (previously $12.55).' + '\nremoved the description (previously "this is for the shuttle").'; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); + }); +}); From db1f935d0ec6034824d56ae59ebff87508d5c383 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 02:08:39 +0200 Subject: [PATCH 40/46] More tests. --- tests/unit/ModifiedExpenseMessageTest.ts | 52 ++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/unit/ModifiedExpenseMessageTest.ts b/tests/unit/ModifiedExpenseMessageTest.ts index 65ba1238a302..ec11d3ad9572 100644 --- a/tests/unit/ModifiedExpenseMessageTest.ts +++ b/tests/unit/ModifiedExpenseMessageTest.ts @@ -61,5 +61,57 @@ describe('ModifiedExpenseMessage', () => { expect(result).toEqual(expectedResult); }); }); + + describe('when the amount is changed, the description is removed, and category is set', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + amount: 1800, + currency: CONST.CURRENCY.USD, + oldAmount: 1255, + oldCurrency: CONST.CURRENCY.USD, + newComment: '', + oldComment: 'this is for the shuttle', + category: 'Benefits', + oldCategory: '', + }, + }; + + it('returns the correct text message', () => { + const expectedResult = 'changed the amount to $18.00 (previously $12.55).' + '\nset the category to "Benefits".' + '\nremoved the description (previously "this is for the shuttle").'; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('when the amount and merchant are changed, the description is removed, and category is set', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + merchant: 'Taco Bell', + oldMerchant: 'Big Belly', + amount: 1800, + currency: CONST.CURRENCY.USD, + oldAmount: 1255, + oldCurrency: CONST.CURRENCY.USD, + newComment: '', + oldComment: 'this is for the shuttle', + category: 'Benefits', + oldCategory: '', + }, + }; + + it('returns the correct text message', () => { + const expectedResult = 'changed the amount to $18.00 (previously $12.55) and the merchant to "Taco Bell" (previously "Big Belly").' + '\nset the category to "Benefits".' + '\nremoved the description (previously "this is for the shuttle").'; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); }); }); From 8babd0ea22e98ac5e4ca9cc04df98b0f206cb844 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 02:10:40 +0200 Subject: [PATCH 41/46] One more test --- tests/unit/ModifiedExpenseMessageTest.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/unit/ModifiedExpenseMessageTest.ts b/tests/unit/ModifiedExpenseMessageTest.ts index ec11d3ad9572..fc8e8cbbeef8 100644 --- a/tests/unit/ModifiedExpenseMessageTest.ts +++ b/tests/unit/ModifiedExpenseMessageTest.ts @@ -87,6 +87,29 @@ describe('ModifiedExpenseMessage', () => { }); }); + describe('when the amount and merchant are changed', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + merchant: 'Taco Bell', + oldMerchant: 'Big Belly', + amount: 1800, + currency: CONST.CURRENCY.USD, + oldAmount: 1255, + oldCurrency: CONST.CURRENCY.USD, + }, + }; + + it('returns the correct text message', () => { + const expectedResult = 'changed the amount to $18.00 (previously $12.55) and the merchant to "Taco Bell" (previously "Big Belly").'; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); + describe('when the amount and merchant are changed, the description is removed, and category is set', () => { const reportAction = { ...createRandomReportAction(1), From 02c09f2a4c3fd22aa9322308beb5cdccd421cbae Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 02:13:03 +0200 Subject: [PATCH 42/46] One more test --- tests/unit/ModifiedExpenseMessageTest.ts | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/unit/ModifiedExpenseMessageTest.ts b/tests/unit/ModifiedExpenseMessageTest.ts index fc8e8cbbeef8..d30a429f759a 100644 --- a/tests/unit/ModifiedExpenseMessageTest.ts +++ b/tests/unit/ModifiedExpenseMessageTest.ts @@ -136,5 +136,30 @@ describe('ModifiedExpenseMessage', () => { expect(result).toEqual(expectedResult); }); }); + + describe('when the amount, comment and merchant are changed', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + merchant: 'Taco Bell', + oldMerchant: 'Big Belly', + amount: 1800, + currency: CONST.CURRENCY.USD, + oldAmount: 1255, + oldCurrency: CONST.CURRENCY.USD, + newComment: 'I bought it on the way', + oldComment: 'from the business trip', + }, + }; + + it('returns the correct text message', () => { + const expectedResult = 'changed the amount to $18.00 (previously $12.55), the description to "I bought it on the way" (previously "from the business trip"), and the merchant to "Taco Bell" (previously "Big Belly").'; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); }); }); From a6a28a658522f57c2bc1a32aa68d5a6c107b67f5 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 02:19:13 +0200 Subject: [PATCH 43/46] 3 more tests --- tests/unit/ModifiedExpenseMessageTest.ts | 63 ++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/unit/ModifiedExpenseMessageTest.ts b/tests/unit/ModifiedExpenseMessageTest.ts index d30a429f759a..8ffc5eaa6dbd 100644 --- a/tests/unit/ModifiedExpenseMessageTest.ts +++ b/tests/unit/ModifiedExpenseMessageTest.ts @@ -161,5 +161,68 @@ describe('ModifiedExpenseMessage', () => { expect(result).toEqual(expectedResult); }); }); + + describe('when the merchant is removed', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + merchant: '', + oldMerchant: 'Big Belly', + }, + }; + + it('returns the correct text message', () => { + const expectedResult = `removed the merchant (previously "Big Belly").`; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('when the merchant and the description are removed', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + merchant: '', + oldMerchant: 'Big Belly', + newComment: '', + oldComment: 'minishore', + }, + }; + + it('returns the correct text message', () => { + const expectedResult = `removed the description (previously "minishore") and the merchant (previously "Big Belly").`; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('when the merchant, the category and the description are removed', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + merchant: '', + oldMerchant: 'Big Belly', + newComment: '', + oldComment: 'minishore', + category: '', + oldCategory: 'Benefits', + }, + }; + + it('returns the correct text message', () => { + const expectedResult = `removed the description (previously "minishore"), the merchant (previously "Big Belly"), and the category (previously "Benefits").`; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); }); }); From 27945e8f5412cd307063979214c1dde5418aa448 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 02:22:23 +0200 Subject: [PATCH 44/46] 3 more tests --- tests/unit/ModifiedExpenseMessageTest.ts | 63 ++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/unit/ModifiedExpenseMessageTest.ts b/tests/unit/ModifiedExpenseMessageTest.ts index 8ffc5eaa6dbd..63f88415a2a3 100644 --- a/tests/unit/ModifiedExpenseMessageTest.ts +++ b/tests/unit/ModifiedExpenseMessageTest.ts @@ -224,5 +224,68 @@ describe('ModifiedExpenseMessage', () => { expect(result).toEqual(expectedResult); }); }); + + describe('when the merchant is set', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + oldMerchant: '', + merchant: 'Big Belly', + }, + }; + + it('returns the correct text message', () => { + const expectedResult = `set the merchant to "Big Belly".`; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('when the merchant and the description are set', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + oldMerchant: '', + merchant: 'Big Belly', + oldComment: '', + newComment: 'minishore', + }, + }; + + it('returns the correct text message', () => { + const expectedResult = `set the description to "minishore" and the merchant to "Big Belly".`; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('when the merchant, the category and the description are set', () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.MODIFIEDEXPENSE, + originalMessage: { + oldMerchant: '', + merchant: 'Big Belly', + oldComment: '', + newComment: 'minishore', + oldCategory: '', + category: 'Benefits', + }, + }; + + it('returns the correct text message', () => { + const expectedResult = `set the description to "minishore", the merchant to "Big Belly", and the category to "Benefits".`; + + const result = ModifiedExpenseMessage.getForReportAction(reportAction); + + expect(result).toEqual(expectedResult); + }); + }); }); }); From 8aad9bd7d78e9303b67712897d1d611217946d70 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Thu, 14 Dec 2023 02:25:39 +0200 Subject: [PATCH 45/46] Make lint happy an run prettier --- tests/unit/ModifiedExpenseMessageTest.ts | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/tests/unit/ModifiedExpenseMessageTest.ts b/tests/unit/ModifiedExpenseMessageTest.ts index 63f88415a2a3..02990aa5c751 100644 --- a/tests/unit/ModifiedExpenseMessageTest.ts +++ b/tests/unit/ModifiedExpenseMessageTest.ts @@ -1,21 +1,7 @@ -import {randAmount} from '@ngneat/falso'; import ModifiedExpenseMessage from '@libs/ModifiedExpenseMessage'; import CONST from '@src/CONST'; -import * as TransactionUtils from '../../src/libs/TransactionUtils'; -import type {Transaction} from '../../src/types/onyx'; import createRandomReportAction from '../utils/collections/reportActions'; -function generateTransaction(values: Partial = {}): Transaction { - const reportID = '1'; - const amount = 100; - const currency = 'USD'; - const comment = ''; - const created = '2023-10-01'; - const baseValues = TransactionUtils.buildOptimisticTransaction(amount, currency, reportID, comment, created); - - return {...baseValues, ...values}; -} - describe('ModifiedExpenseMessage', () => { describe('getForAction', () => { describe('when the amount is changed', () => { @@ -54,7 +40,7 @@ describe('ModifiedExpenseMessage', () => { }; it('returns the correct text message', () => { - const expectedResult = 'changed the amount to $18.00 (previously $12.55).' + '\nremoved the description (previously "this is for the shuttle").'; + const expectedResult = 'changed the amount to $18.00 (previously $12.55).\nremoved the description (previously "this is for the shuttle").'; const result = ModifiedExpenseMessage.getForReportAction(reportAction); @@ -79,7 +65,7 @@ describe('ModifiedExpenseMessage', () => { }; it('returns the correct text message', () => { - const expectedResult = 'changed the amount to $18.00 (previously $12.55).' + '\nset the category to "Benefits".' + '\nremoved the description (previously "this is for the shuttle").'; + const expectedResult = 'changed the amount to $18.00 (previously $12.55).\nset the category to "Benefits".\nremoved the description (previously "this is for the shuttle").'; const result = ModifiedExpenseMessage.getForReportAction(reportAction); @@ -129,7 +115,8 @@ describe('ModifiedExpenseMessage', () => { }; it('returns the correct text message', () => { - const expectedResult = 'changed the amount to $18.00 (previously $12.55) and the merchant to "Taco Bell" (previously "Big Belly").' + '\nset the category to "Benefits".' + '\nremoved the description (previously "this is for the shuttle").'; + const expectedResult = + 'changed the amount to $18.00 (previously $12.55) and the merchant to "Taco Bell" (previously "Big Belly").\nset the category to "Benefits".\nremoved the description (previously "this is for the shuttle").'; const result = ModifiedExpenseMessage.getForReportAction(reportAction); @@ -154,7 +141,8 @@ describe('ModifiedExpenseMessage', () => { }; it('returns the correct text message', () => { - const expectedResult = 'changed the amount to $18.00 (previously $12.55), the description to "I bought it on the way" (previously "from the business trip"), and the merchant to "Taco Bell" (previously "Big Belly").'; + const expectedResult = + 'changed the amount to $18.00 (previously $12.55), the description to "I bought it on the way" (previously "from the business trip"), and the merchant to "Taco Bell" (previously "Big Belly").'; const result = ModifiedExpenseMessage.getForReportAction(reportAction); From 13f7b9c78fb5c122be011ef1178dfc4a35dfda24 Mon Sep 17 00:00:00 2001 From: Cristi Paval Date: Mon, 18 Dec 2023 15:05:03 +0200 Subject: [PATCH 46/46] Add changes from main --- src/libs/ModifiedExpenseMessage.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/ModifiedExpenseMessage.ts b/src/libs/ModifiedExpenseMessage.ts index aa1604f9536a..c3d9b0a85339 100644 --- a/src/libs/ModifiedExpenseMessage.ts +++ b/src/libs/ModifiedExpenseMessage.ts @@ -146,7 +146,8 @@ function getForReportAction(reportAction: ReportAction): string { const hasModifiedCreated = reportActionOriginalMessage && 'oldCreated' in reportActionOriginalMessage && 'created' in reportActionOriginalMessage; if (hasModifiedCreated) { // Take only the YYYY-MM-DD value as the original date includes timestamp - const formattedOldCreated = format(new Date(reportActionOriginalMessage?.oldCreated ?? ''), CONST.DATE.FNS_FORMAT_STRING); + let formattedOldCreated: Date | string = new Date(reportActionOriginalMessage?.oldCreated ? reportActionOriginalMessage.oldCreated : 0); + formattedOldCreated = format(formattedOldCreated, CONST.DATE.FNS_FORMAT_STRING); buildMessageFragmentForValue( reportActionOriginalMessage?.created ?? '', formattedOldCreated,