Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update "automatically approved" report action copy #49909

Merged
merged 18 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -914,7 +914,11 @@ const translations = {
managerApprovedAmount: ({manager, amount}: ManagerApprovedAmountParams) => `${manager} approved ${amount}`,
payerSettled: ({amount}: PayerSettledParams) => `paid ${amount}`,
payerSettledWithMissingBankAccount: ({amount}: PayerSettledParams) => `paid ${amount}. Add a bank account to receive your payment.`,
automaticallyApprovedAmount: ({amount}: ApprovedAmountParams) =>
`automatically approved ${amount} via <a href="${CONST.CONFIGURE_REIMBURSEMENT_SETTINGS_HELP_URL}">workspace rules</a>`,
approvedAmount: ({amount}: ApprovedAmountParams) => `approved ${amount}`,
automaticallyForwardedAmount: ({amount}: ForwardedAmountParams) =>
`automatically approved ${amount} via <a href="${CONST.CONFIGURE_REIMBURSEMENT_SETTINGS_HELP_URL}">workspace rules</a>`,
forwardedAmount: ({amount}: ForwardedAmountParams) => `approved ${amount}`,
rejectedThisReport: 'rejected this report',
waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `started settling up. Payment is on hold until ${submitterDisplayName} adds a bank account.`,
Expand Down
4 changes: 4 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,11 @@ const translations = {
managerApprovedAmount: ({manager, amount}: ManagerApprovedAmountParams) => `${manager} aprobó ${amount}`,
payerSettled: ({amount}: PayerSettledParams) => `pagó ${amount}`,
payerSettledWithMissingBankAccount: ({amount}: PayerSettledParams) => `pagó ${amount}. Agrega una cuenta bancaria para recibir tu pago.`,
automaticallyApprovedAmount: ({amount}: ApprovedAmountParams) =>
`aprobado automáticamente ${amount} según las <a href="${CONST.CONFIGURE_REIMBURSEMENT_SETTINGS_HELP_URL}">reglas del espacio de trabajo</a>`,
approvedAmount: ({amount}: ApprovedAmountParams) => `aprobó ${amount}`,
automaticallyForwardedAmount: ({amount}: ForwardedAmountParams) =>
`aprobado automáticamente ${amount} según las <a href="${CONST.CONFIGURE_REIMBURSEMENT_SETTINGS_HELP_URL}">reglas del espacio de trabajo</a>`,
forwardedAmount: ({amount}: ForwardedAmountParams) => `aprobó ${amount}`,
rejectedThisReport: 'rechazó este informe',
waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `inició el pago, pero no se procesará hasta que ${submitterDisplayName} añada una cuenta bancaria`,
Expand Down
18 changes: 14 additions & 4 deletions src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -694,10 +694,20 @@ function getLastMessageTextForReport(report: OnyxEntry<Report>, lastActorDetails
} else {
lastMessageTextFromReport = ReportUtils.getIOUSubmittedMessage(lastReportAction);
}
} else if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.APPROVED) {
lastMessageTextFromReport = ReportUtils.getIOUApprovedMessage(lastReportAction);
} else if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.FORWARDED) {
lastMessageTextFromReport = ReportUtils.getIOUForwardedMessage(lastReportAction, report);
} else if (ReportActionUtils.isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.APPROVED)) {
const {automaticAction} = ReportActionUtils.getOriginalMessage(lastReportAction) ?? {};
if (automaticAction) {
lastMessageTextFromReport = ReportUtils.getReportAutomaticallyApprovedMessage(lastReportAction);
} else {
lastMessageTextFromReport = ReportUtils.getIOUApprovedMessage(lastReportAction);
}
} else if (ReportActionUtils.isActionOfType(lastReportAction, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) {
const {automaticAction} = ReportActionUtils.getOriginalMessage(lastReportAction) ?? {};
if (automaticAction) {
lastMessageTextFromReport = ReportUtils.getReportAutomaticallyForwardedMessage(lastReportAction, reportID);
} else {
lastMessageTextFromReport = ReportUtils.getIOUForwardedMessage(lastReportAction, report);
}
} else if (lastReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) {
lastMessageTextFromReport = ReportUtils.getRejectedReportMessage();
} else if (ReportActionUtils.isActionableAddPaymentCard(lastReportAction)) {
Expand Down
47 changes: 42 additions & 5 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3781,15 +3781,27 @@ function getReportName(
ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED) ||
ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED_AND_CLOSED)
) {
const {harvesting} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {};
if (harvesting) {
return Parser.htmlToText(getReportAutomaticallySubmittedMessage(parentReportAction));
}
return getIOUSubmittedMessage(parentReportAction);
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.FORWARDED) {
if (ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) {
const {automaticAction} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {};
if (automaticAction) {
return Parser.htmlToText(getReportAutomaticallyForwardedMessage(parentReportAction, reportID));
}
return getIOUForwardedMessage(parentReportAction, report);
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) {
return getRejectedReportMessage();
}
if (parentReportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.APPROVED) {
if (ReportActionsUtils.isActionOfType(parentReportAction, CONST.REPORT.ACTIONS.TYPE.APPROVED)) {
const {automaticAction} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {};
if (automaticAction) {
return Parser.htmlToText(getReportAutomaticallyApprovedMessage(parentReportAction));
}
return getIOUApprovedMessage(parentReportAction);
}

Expand Down Expand Up @@ -4540,15 +4552,38 @@ function getIOUSubmittedMessage(reportAction: ReportAction<typeof CONST.REPORT.A
return Localize.translateLocal('iou.submittedAmount', {formattedAmount: getFormattedAmount(reportAction)});
}

function getIOUApprovedMessage(reportAction: ReportAction) {
function getReportAutomaticallyApprovedMessage(reportAction: ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.APPROVED>) {
return Localize.translateLocal('iou.automaticallyApprovedAmount', {amount: getFormattedAmount(reportAction)});
}

function getIOUApprovedMessage(reportAction: ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.APPROVED>) {
return Localize.translateLocal('iou.approvedAmount', {amount: getFormattedAmount(reportAction)});
}

/**
* We pass the reportID as older FORWARDED actions do not have the amount & currency stored in the message
* so we retrieve the amount from the report instead
*/
function getIOUForwardedMessage(reportAction: ReportAction, reportOrID: OnyxInputOrEntry<Report> | string) {
function getReportAutomaticallyForwardedMessage(reportAction: ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.FORWARDED>, reportOrID: OnyxInputOrEntry<Report> | string) {
const expenseReport = typeof reportOrID === 'string' ? getReport(reportOrID) : reportOrID;
const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction) as OriginalMessageIOU;
let formattedAmount;

// Older FORWARDED action might not have the amount stored in the original message, we'll fallback to getting the amount from the report instead.
if (originalMessage?.amount) {
formattedAmount = getFormattedAmount(reportAction);
} else {
formattedAmount = CurrencyUtils.convertToDisplayString(getMoneyRequestSpendBreakdown(expenseReport).totalDisplaySpend, expenseReport?.currency);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: log when we execute this fallback such that, some time from now, we can search up the log and remove this code if it's no longer needed. Create a monthly issue to check back in.

}

return Localize.translateLocal('iou.automaticallyForwardedAmount', {amount: formattedAmount});
}

/**
* We pass the reportID as older FORWARDED actions do not have the amount & currency stored in the message
* so we retrieve the amount from the report instead
*/
function getIOUForwardedMessage(reportAction: ReportAction<typeof CONST.REPORT.ACTIONS.TYPE.FORWARDED>, reportOrID: OnyxInputOrEntry<Report> | string) {
const expenseReport = typeof reportOrID === 'string' ? getReport(reportOrID) : reportOrID;
const originalMessage = ReportActionsUtils.getOriginalMessage(reportAction) as OriginalMessageIOU;
let formattedAmount;
Expand Down Expand Up @@ -7189,7 +7224,7 @@ function getIOUReportActionDisplayMessage(reportAction: OnyxEntry<ReportAction>,

const amount = TransactionUtils.getAmount(transaction, !isEmptyObject(iouReport) && isExpenseReport(iouReport)) ?? 0;
const formattedAmount = CurrencyUtils.convertToDisplayString(amount, TransactionUtils.getCurrency(transaction)) ?? '';
const isRequestSettled = isSettled(originalMessage?.IOUReportID);
const isRequestSettled = isSettled(IOUReportID);
const isApproved = isReportApproved(iouReport);
if (isRequestSettled) {
return Localize.translateLocal('iou.payerSettled', {
Expand Down Expand Up @@ -8125,7 +8160,9 @@ export {
getGroupChatName,
getIOUReportActionDisplayMessage,
getIOUReportActionMessage,
getReportAutomaticallyApprovedMessage,
getIOUApprovedMessage,
getReportAutomaticallyForwardedMessage,
getIOUForwardedMessage,
getRejectedReportMessage,
getWorkspaceNameUpdatedMessage,
Expand Down
28 changes: 23 additions & 5 deletions src/pages/home/report/ContextMenu/ContextMenuActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -443,13 +443,31 @@ const ContextMenuActions: ContextMenuAction[] = [
ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED) ||
ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.SUBMITTED_AND_CLOSED)
) {
const displayMessage = ReportUtils.getIOUSubmittedMessage(reportAction);
const {harvesting} = ReportActionsUtils.getOriginalMessage(reportAction) ?? {};
let displayMessage = '';
if (harvesting) {
displayMessage = ReportUtils.getReportAutomaticallySubmittedMessage(reportAction);
} else {
displayMessage = ReportUtils.getIOUSubmittedMessage(reportAction);
}
Clipboard.setString(displayMessage);
} else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.APPROVED) {
const displayMessage = ReportUtils.getIOUApprovedMessage(reportAction);
} else if (ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.APPROVED)) {
const {automaticAction} = ReportActionsUtils.getOriginalMessage(reportAction) ?? {};
let displayMessage = '';
if (automaticAction) {
displayMessage = ReportUtils.getReportAutomaticallyApprovedMessage(reportAction);
} else {
displayMessage = ReportUtils.getIOUApprovedMessage(reportAction);
}
Clipboard.setString(displayMessage);
} else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.FORWARDED) {
const displayMessage = ReportUtils.getIOUForwardedMessage(reportAction, reportID);
} else if (ReportActionsUtils.isActionOfType(reportAction, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) {
const {automaticAction} = ReportActionsUtils.getOriginalMessage(reportAction) ?? {};
let displayMessage = '';
if (automaticAction) {
displayMessage = ReportUtils.getReportAutomaticallyForwardedMessage(reportAction, reportID);
} else {
displayMessage = ReportUtils.getIOUForwardedMessage(reportAction, reportID);
}
Clipboard.setString(displayMessage);
} else if (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) {
const displayMessage = ReportUtils.getRejectedReportMessage();
Expand Down
26 changes: 22 additions & 4 deletions src/pages/home/report/ReportActionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -646,10 +646,28 @@ function ReportActionItem({
} else {
children = <ReportActionItemBasicMessage message={ReportUtils.getIOUSubmittedMessage(action)} />;
}
} else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.APPROVED) {
children = <ReportActionItemBasicMessage message={ReportUtils.getIOUApprovedMessage(action)} />;
} else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.FORWARDED) {
children = <ReportActionItemBasicMessage message={ReportUtils.getIOUForwardedMessage(action, report)} />;
} else if (ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.APPROVED)) {
const wasAutoApproved = ReportActionsUtils.getOriginalMessage(action)?.automaticAction ?? false;
if (wasAutoApproved) {
children = (
<ReportActionItemBasicMessage message="">
<RenderHTML html={`<comment><muted-text>${ReportUtils.getReportAutomaticallyApprovedMessage(action)}</muted-text></comment>`} />
</ReportActionItemBasicMessage>
);
} else {
children = <ReportActionItemBasicMessage message={ReportUtils.getIOUApprovedMessage(action)} />;
}
} else if (ReportActionsUtils.isActionOfType(action, CONST.REPORT.ACTIONS.TYPE.FORWARDED)) {
const wasAutoForwarded = ReportActionsUtils.getOriginalMessage(action)?.automaticAction ?? false;
if (wasAutoForwarded) {
children = (
<ReportActionItemBasicMessage message="">
<RenderHTML html={`<comment><muted-text>${ReportUtils.getReportAutomaticallyForwardedMessage(action, reportID)}</muted-text></comment>`} />
</ReportActionItemBasicMessage>
);
} else {
children = <ReportActionItemBasicMessage message={ReportUtils.getIOUForwardedMessage(action, report)} />;
}
} else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.REJECTED) {
children = <ReportActionItemBasicMessage message={translate('iou.rejectedThisReport')} />;
} else if (action.actionName === CONST.REPORT.ACTIONS.TYPE.HOLD) {
Expand Down
6 changes: 6 additions & 0 deletions src/types/onyx/OriginalMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,9 @@ type OriginalMessageApproved = {
/** Approved expense amount */
amount: number;

/** Was the action created automatically, not by a human */
automaticAction?: boolean;

/** Currency of the approved expense amount */
currency: string;

Expand All @@ -450,6 +453,9 @@ type OriginalMessageForwarded = {
/** Forwarded expense amount */
amount: number;

/** Was the action created automatically, not by a human */
automaticAction?: boolean;

/** Currency of the forwarded expense amount */
currency: string;

Expand Down
24 changes: 24 additions & 0 deletions tests/unit/ReportUtilsTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,30 @@
});
});
});

describe('ParentReportAction is', () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@roryabraham here's an example getReportName test I am planning to add more of, for the other examples in this PR - I'll probably even add more tests but can you at least let me know if this is what you're thinking for tests / any feedback on this one?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking more along the lines of UI tests rendering <ReportActionItem> using @testing-library/react-native. There are only limited examples in the repo today

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm in that case since there's not much to go on right now, i'd prefer taking this as a follow-up for a contributor or C+ to write up b/c it's going to take me a bit to figure out how that works & that'll keep delaying this PR from getting merged

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's going to take me a bit to figure out how that works & that'll keep delaying this PR from getting merged

Up to you. I'd encourage you to take the time to learn and write the tests, because I don't see this PR as so urgent that we can't wait for tests. Just my opinion though (informed by my observed experience that 90% of the time when we "follow up to add tests", that part just never happens) 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel confident that I can get unit tests written externally, so I created this follow-up #50351

I believe this will be more time efficient because I have more important issues to focus on this week

test('Manually Submitted Report Action', () => {
const threadOfSubmittedReportAction = {
...LHNTestUtils.getFakeReport(),
type: CONST.REPORT.TYPE.EXPENSE,
stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED,
parentReportID: '101',
policyID: policy.id,
};
const submittedParentReportAction = {
actionName: CONST.REPORT.ACTIONS.TYPE.SUBMITTED,
originalMessage: {
amount: 169,
currency: 'USD',
},
} as ReportAction;

expect(

Check failure on line 292 in tests/unit/ReportUtilsTest.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Replace `⏎····················ReportUtils.getReportName(threadOfSubmittedReportAction,·policy,·submittedParentReportAction),⏎················` with `ReportUtils.getReportName(threadOfSubmittedReportAction,·policy,·submittedParentReportAction)`

Check failure on line 292 in tests/unit/ReportUtilsTest.ts

View workflow job for this annotation

GitHub Actions / ESLint check

Replace `⏎····················ReportUtils.getReportName(threadOfSubmittedReportAction,·policy,·submittedParentReportAction),⏎················` with `ReportUtils.getReportName(threadOfSubmittedReportAction,·policy,·submittedParentReportAction)`
ReportUtils.getReportName(threadOfSubmittedReportAction, policy, submittedParentReportAction),
).toBe('submitted $1.69');
});
});
});

describe('requiresAttentionFromCurrentUser', () => {
Expand Down
Loading