-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Move RBR to workspace chats instead of transaction threads #51893
Changes from all commits
4b8f300
f698ec4
d236fdd
025083e
15bc38a
01a8f9f
83df3b7
38dd386
454aef3
f36e9f6
89b545b
cde8f33
40d9f8d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6316,65 +6316,53 @@ function shouldHideReport(report: OnyxEntry<Report>, currentReportId: string): b | |
} | ||
|
||
/** | ||
* Checks to see if a report's parentAction is an expense that contains a violation type of either violation or warning | ||
* Should we display a RBR on the LHN on this report due to violations? | ||
*/ | ||
function doesTransactionThreadHaveViolations( | ||
report: OnyxInputOrEntry<Report>, | ||
transactionViolations: OnyxCollection<TransactionViolation[]>, | ||
parentReportAction: OnyxInputOrEntry<ReportAction>, | ||
): boolean { | ||
if (!ReportActionsUtils.isMoneyRequestAction(parentReportAction)) { | ||
return false; | ||
} | ||
const {IOUTransactionID, IOUReportID} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; | ||
if (!IOUTransactionID || !IOUReportID) { | ||
function shouldDisplayViolationsRBRInLHN(report: OnyxEntry<Report>, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean { | ||
// We only show the RBR in the highest level, which is the workspace chat | ||
if (!report || !isPolicyExpenseChat(report)) { | ||
return false; | ||
} | ||
if (!isCurrentUserSubmitter(IOUReportID)) { | ||
return false; | ||
} | ||
if (report?.stateNum !== CONST.REPORT.STATE_NUM.OPEN && report?.stateNum !== CONST.REPORT.STATE_NUM.SUBMITTED) { | ||
|
||
// We only show the RBR to the submitter | ||
if (!isCurrentUserSubmitter(report.reportID ?? '')) { | ||
return false; | ||
} | ||
return ( | ||
TransactionUtils.hasViolation(IOUTransactionID, transactionViolations) || | ||
TransactionUtils.hasWarningTypeViolation(IOUTransactionID, transactionViolations) || | ||
(isPaidGroupPolicy(report) && TransactionUtils.hasModifiedAmountOrDateViolation(IOUTransactionID, transactionViolations)) | ||
|
||
// Get all potential reports, which are the ones that are: | ||
// - Owned by the same user | ||
// - Are either open or submitted | ||
// - Belong to the same workspace | ||
// And if any have a violation, then it should have a RBR | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see this condition was deleted There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's done with |
||
const allReports = Object.values(ReportConnection.getAllReports() ?? {}) as Report[]; | ||
const potentialReports = allReports.filter((r) => r.ownerAccountID === currentUserAccountID && (r.stateNum ?? 0) <= 1 && r.policyID === report.policyID); | ||
return potentialReports.some( | ||
(potentialReport) => hasViolations(potentialReport.reportID, transactionViolations) || hasWarningTypeViolations(potentialReport.reportID, transactionViolations), | ||
); | ||
} | ||
|
||
/** | ||
* Checks if we should display violation - we display violations when the expense has violation and it is not settled | ||
* Checks to see if a report contains a violation | ||
*/ | ||
function shouldDisplayTransactionThreadViolations( | ||
report: OnyxEntry<Report>, | ||
transactionViolations: OnyxCollection<TransactionViolation[]>, | ||
parentReportAction: OnyxEntry<ReportAction>, | ||
): boolean { | ||
if (!ReportActionsUtils.isMoneyRequestAction(parentReportAction)) { | ||
return false; | ||
} | ||
const {IOUReportID} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {}; | ||
if (isSettled(IOUReportID) || isReportApproved(IOUReportID?.toString())) { | ||
return false; | ||
} | ||
return doesTransactionThreadHaveViolations(report, transactionViolations, parentReportAction); | ||
function hasViolations(reportID: string, transactionViolations: OnyxCollection<TransactionViolation[]>, shouldShowInReview?: boolean): boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make the last param mandatory? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the places we are calling this that I did not update, we do not care about the state of this variable, so no. |
||
const transactions = reportsTransactions[reportID] ?? []; | ||
return transactions.some((transaction) => TransactionUtils.hasViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); | ||
} | ||
|
||
/** | ||
* Checks to see if a report contains a violation | ||
* Checks to see if a report contains a violation of type `warning` | ||
*/ | ||
function hasViolations(reportID: string, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean { | ||
function hasWarningTypeViolations(reportID: string, transactionViolations: OnyxCollection<TransactionViolation[]>, shouldShowInReview?: boolean): boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make the last param mandatory? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
const transactions = reportsTransactions[reportID] ?? []; | ||
return transactions.some((transaction) => TransactionUtils.hasViolation(transaction.transactionID, transactionViolations)); | ||
return transactions.some((transaction) => TransactionUtils.hasWarningTypeViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); | ||
} | ||
|
||
/** | ||
* Checks to see if a report contains a violation of type `warning` | ||
* Checks to see if a report contains a violation of type `notice` | ||
*/ | ||
function hasWarningTypeViolations(reportID: string, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean { | ||
function hasNoticeTypeViolations(reportID: string, transactionViolations: OnyxCollection<TransactionViolation[]>, shouldShowInReview?: boolean): boolean { | ||
const transactions = reportsTransactions[reportID] ?? []; | ||
return transactions.some((transaction) => TransactionUtils.hasWarningTypeViolation(transaction.transactionID, transactionViolations)); | ||
return transactions.some((transaction) => TransactionUtils.hasNoticeTypeViolation(transaction.transactionID, transactionViolations, shouldShowInReview)); | ||
} | ||
|
||
function hasReportViolations(reportID: string) { | ||
|
@@ -6396,23 +6384,6 @@ function shouldAdminsRoomBeVisible(report: OnyxEntry<Report>): boolean { | |
return true; | ||
} | ||
|
||
/** | ||
* Check whether report has violations | ||
*/ | ||
function shouldShowViolations(report: Report, transactionViolations: OnyxCollection<TransactionViolation[]>) { | ||
const {parentReportID, parentReportActionID} = report ?? {}; | ||
const canGetParentReport = parentReportID && parentReportActionID && allReportActions; | ||
if (!canGetParentReport) { | ||
return false; | ||
} | ||
const parentReportActions = allReportActions ? allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`] ?? {} : {}; | ||
const parentReportAction = parentReportActions[parentReportActionID] ?? null; | ||
if (!parentReportAction) { | ||
return false; | ||
} | ||
return shouldDisplayTransactionThreadViolations(report, transactionViolations, parentReportAction); | ||
} | ||
|
||
type ReportErrorsAndReportActionThatRequiresAttention = { | ||
errors: ErrorFields; | ||
reportAction?: OnyxEntry<ReportAction>; | ||
|
@@ -6495,7 +6466,7 @@ function hasReportErrorsOtherThanFailedReceipt(report: Report, doesReportHaveVio | |
let doesTransactionThreadReportHasViolations = false; | ||
if (oneTransactionThreadReportID) { | ||
const transactionReport = getReport(oneTransactionThreadReportID); | ||
doesTransactionThreadReportHasViolations = !!transactionReport && shouldShowViolations(transactionReport, transactionViolations); | ||
doesTransactionThreadReportHasViolations = !!transactionReport && shouldDisplayViolationsRBRInLHN(transactionReport, transactionViolations); | ||
} | ||
return ( | ||
doesTransactionThreadReportHasViolations || | ||
|
@@ -8489,7 +8460,6 @@ export { | |
chatIncludesConcierge, | ||
createDraftTransactionAndNavigateToParticipantSelector, | ||
doesReportBelongToWorkspace, | ||
doesTransactionThreadHaveViolations, | ||
findLastAccessedReport, | ||
findSelfDMReportID, | ||
formatReportLastMessageText, | ||
|
@@ -8592,6 +8562,7 @@ export { | |
hasUpdatedTotal, | ||
hasViolations, | ||
hasWarningTypeViolations, | ||
hasNoticeTypeViolations, | ||
isActionCreator, | ||
isAdminRoom, | ||
isAdminsOnlyPostingRoom, | ||
|
@@ -8693,7 +8664,7 @@ export { | |
shouldDisableRename, | ||
shouldDisableThread, | ||
shouldDisplayThreadReplies, | ||
shouldDisplayTransactionThreadViolations, | ||
shouldDisplayViolationsRBRInLHN, | ||
shouldReportBeInOptionList, | ||
shouldReportShowSubscript, | ||
shouldShowFlagComment, | ||
|
@@ -8741,7 +8712,6 @@ export { | |
buildOptimisticChangeFieldAction, | ||
isPolicyRelatedReport, | ||
hasReportErrorsOtherThanFailedReceipt, | ||
shouldShowViolations, | ||
getAllReportErrors, | ||
getAllReportActionsErrorsAndReportActionThatRequiresAttention, | ||
hasInvoiceReports, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -814,41 +814,37 @@ function isOnHoldByTransactionID(transactionID: string): boolean { | |
/** | ||
* Checks if any violations for the provided transaction are of type 'violation' | ||
*/ | ||
function hasViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolations>): boolean { | ||
function hasViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolations>, showInReview?: boolean): boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make the last param mandatory? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
return !!transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some( | ||
(violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.VIOLATION, | ||
(violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.VIOLATION && (showInReview === undefined || showInReview === (violation.showInReview ?? false)), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic is confusing. If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
); | ||
} | ||
|
||
/** | ||
* Checks if any violations for the provided transaction are of type 'notice' | ||
*/ | ||
function hasNoticeTypeViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean { | ||
return !!transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some((violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.NOTICE); | ||
function hasNoticeTypeViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolation[]>, showInReview?: boolean): boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make the last param mandatory? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
return !!transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some( | ||
(violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.NOTICE && (showInReview === undefined || showInReview === (violation.showInReview ?? false)), | ||
); | ||
} | ||
|
||
/** | ||
* Checks if any violations for the provided transaction are of type 'warning' | ||
*/ | ||
function hasWarningTypeViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean { | ||
const warningTypeViolations = transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.filter( | ||
(violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.WARNING, | ||
); | ||
function hasWarningTypeViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolation[]>, showInReview?: boolean | null): boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we make the last param mandatory? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above |
||
const violations = transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]; | ||
const warningTypeViolations = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NAB but break this down to make it more readable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like how? I had it formatted more readable but then the styler changed it to this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Putting There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did that, not sure if it makes it any better though 🤷 |
||
violations?.filter( | ||
(violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.WARNING && (showInReview === null || showInReview === (violation.showInReview ?? false)), | ||
) ?? []; | ||
|
||
const hasOnlyDupeDetectionViolation = warningTypeViolations?.every((violation: TransactionViolation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION); | ||
if (!Permissions.canUseDupeDetection(allBetas ?? []) && hasOnlyDupeDetectionViolation) { | ||
return false; | ||
} | ||
|
||
return !!warningTypeViolations && warningTypeViolations.length > 0; | ||
} | ||
|
||
/** | ||
* Checks if any violations for the provided transaction are of modifiedAmount or modifiedDate | ||
*/ | ||
function hasModifiedAmountOrDateViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean { | ||
return !!transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some( | ||
(violation: TransactionViolation) => violation.name === CONST.VIOLATIONS.MODIFIED_AMOUNT || violation.name === CONST.VIOLATIONS.MODIFIED_DATE, | ||
); | ||
return warningTypeViolations.length > 0; | ||
} | ||
|
||
/** | ||
|
@@ -1284,7 +1280,6 @@ export { | |
shouldShowBrokenConnectionViolation, | ||
hasNoticeTypeViolation, | ||
hasWarningTypeViolation, | ||
hasModifiedAmountOrDateViolation, | ||
isCustomUnitRateIDForP2P, | ||
getRateID, | ||
getTransaction, | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -92,6 +92,9 @@ type TransactionViolation = { | |||||||
|
||||||||
/** Additional violation information to provide the user */ | ||||||||
data?: TransactionViolationData; | ||||||||
|
||||||||
/** Indicates if this violation should be shown in review */ | ||||||||
showInReview?: boolean; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this need to be optional? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, because I am not sending it from PHP when it is not There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This should be required to be set (and still allow for undefined). This is needed so we create the correct optimistic data. Not doing so led to a regression #54510 However, now we need to know which violations has There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why would this need to be set for optimistic actions to work? 😕
I don't think there's a list, there's a bunch of logic controlling this property's value. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If we don't then expenses created offline that violate policy rules won't have the red dot set on their previews. This is due to this logic App/src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx Line 120 in ad99c20
showInReview=true
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah ok, so let's add that property to the optimistic actions (assuming the property will be removed when the data from the server is returned), but no need to mark this prop as required There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem with not making this required is that the bug could resurface (one could simply forget to add the field). Do you think we shouldn't optimize for this case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you think it actually prevents bugs? Allowing undefined gives the same signal to code authors as allowing it to not be passed, no? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see your point. Forcing the field to be set can reduce the occurrence of such bugs as you will get a chance to put in the correct value but it won't 100% prevent the bug. We will keep the types untouched. |
||||||||
}; | ||||||||
|
||||||||
/** Collection of transaction violations */ | ||||||||
|
This comment was marked as resolved.
Sorry, something went wrong.