Skip to content

Commit 861d7e5

Browse files
authored
Merge pull request #51893 from Expensify/ionatan_moverbrworkspacechat
2 parents 2bf7870 + 40d9f8d commit 861d7e5

File tree

12 files changed

+78
-177
lines changed

12 files changed

+78
-177
lines changed

src/components/LHNOptionsList/OptionRowLHNData.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function OptionRowLHNData({
3737

3838
const optionItemRef = useRef<OptionData>();
3939

40-
const shouldDisplayViolations = ReportUtils.shouldDisplayTransactionThreadViolations(fullReport, transactionViolations, parentReportAction);
40+
const shouldDisplayViolations = ReportUtils.shouldDisplayViolationsRBRInLHN(fullReport, transactionViolations);
4141
const shouldDisplayReportViolations = ReportUtils.isReportOwner(fullReport) && ReportUtils.hasReportViolations(reportID);
4242

4343
const optionItem = useMemo(() => {

src/components/ReportActionItem/MoneyRequestPreview/MoneyRequestPreviewContent.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ function MoneyRequestPreviewContent({
115115
const isOnHold = TransactionUtils.isOnHold(transaction);
116116
const isSettlementOrApprovalPartial = !!iouReport?.pendingFields?.partial;
117117
const isPartialHold = isSettlementOrApprovalPartial && isOnHold;
118-
const hasViolations = TransactionUtils.hasViolation(transaction?.transactionID ?? '-1', transactionViolations);
119-
const hasNoticeTypeViolations = TransactionUtils.hasNoticeTypeViolation(transaction?.transactionID ?? '-1', transactionViolations) && ReportUtils.isPaidGroupPolicy(iouReport);
118+
const hasViolations = TransactionUtils.hasViolation(transaction?.transactionID ?? '-1', transactionViolations, true);
119+
const hasNoticeTypeViolations = TransactionUtils.hasNoticeTypeViolation(transaction?.transactionID ?? '-1', transactionViolations, true) && ReportUtils.isPaidGroupPolicy(iouReport);
120120
const hasFieldErrors = TransactionUtils.hasMissingSmartscanFields(transaction);
121121
const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction);
122122
const isFetchingWaypointsFromServer = TransactionUtils.isFetchingWaypointsFromServer(transaction);

src/components/ReportActionItem/ReportPreview.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,9 @@ function ReportPreview({
157157
const hasErrors =
158158
(hasMissingSmartscanFields && !iouSettled) ||
159159
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
160-
ReportUtils.hasViolations(iouReportID, transactionViolations) ||
161-
ReportUtils.hasWarningTypeViolations(iouReportID, transactionViolations) ||
160+
ReportUtils.hasViolations(iouReportID, transactionViolations, true) ||
161+
ReportUtils.hasNoticeTypeViolations(iouReportID, transactionViolations, true) ||
162+
ReportUtils.hasWarningTypeViolations(iouReportID, transactionViolations, true) ||
162163
(ReportUtils.isReportOwner(iouReport) && ReportUtils.hasReportViolations(iouReportID)) ||
163164
ReportUtils.hasActionsWithErrors(iouReportID);
164165
const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3);

src/libs/DebugUtils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ function getReasonForShowingRowInLHN(report: OnyxEntry<Report>, hasRBR = false):
588588
return null;
589589
}
590590

591-
const doesReportHaveViolations = ReportUtils.shouldShowViolations(report, transactionViolations);
591+
const doesReportHaveViolations = ReportUtils.shouldDisplayViolationsRBRInLHN(report, transactionViolations);
592592

593593
const reason = ReportUtils.reasonForReportToBeInOptionList({
594594
report,

src/libs/OptionsListUtils.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1704,7 +1704,7 @@ function getOptions(
17041704
// Filter out all the reports that shouldn't be displayed
17051705
const filteredReportOptions = options.reports.filter((option) => {
17061706
const report = option.item;
1707-
const doesReportHaveViolations = ReportUtils.shouldShowViolations(report, transactionViolations);
1707+
const doesReportHaveViolations = ReportUtils.shouldDisplayViolationsRBRInLHN(report, transactionViolations);
17081708

17091709
return ReportUtils.shouldReportBeInOptionList({
17101710
report,

src/libs/ReportUtils.ts

+30-60
Original file line numberDiff line numberDiff line change
@@ -6324,65 +6324,53 @@ function shouldHideReport(report: OnyxEntry<Report>, currentReportId: string): b
63246324
}
63256325

63266326
/**
6327-
* Checks to see if a report's parentAction is an expense that contains a violation type of either violation or warning
6327+
* Should we display a RBR on the LHN on this report due to violations?
63286328
*/
6329-
function doesTransactionThreadHaveViolations(
6330-
report: OnyxInputOrEntry<Report>,
6331-
transactionViolations: OnyxCollection<TransactionViolation[]>,
6332-
parentReportAction: OnyxInputOrEntry<ReportAction>,
6333-
): boolean {
6334-
if (!ReportActionsUtils.isMoneyRequestAction(parentReportAction)) {
6335-
return false;
6336-
}
6337-
const {IOUTransactionID, IOUReportID} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {};
6338-
if (!IOUTransactionID || !IOUReportID) {
6329+
function shouldDisplayViolationsRBRInLHN(report: OnyxEntry<Report>, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean {
6330+
// We only show the RBR in the highest level, which is the workspace chat
6331+
if (!report || !isPolicyExpenseChat(report)) {
63396332
return false;
63406333
}
6341-
if (!isCurrentUserSubmitter(IOUReportID)) {
6342-
return false;
6343-
}
6344-
if (report?.stateNum !== CONST.REPORT.STATE_NUM.OPEN && report?.stateNum !== CONST.REPORT.STATE_NUM.SUBMITTED) {
6334+
6335+
// We only show the RBR to the submitter
6336+
if (!isCurrentUserSubmitter(report.reportID ?? '')) {
63456337
return false;
63466338
}
6347-
return (
6348-
TransactionUtils.hasViolation(IOUTransactionID, transactionViolations) ||
6349-
TransactionUtils.hasWarningTypeViolation(IOUTransactionID, transactionViolations) ||
6350-
(isPaidGroupPolicy(report) && TransactionUtils.hasModifiedAmountOrDateViolation(IOUTransactionID, transactionViolations))
6339+
6340+
// Get all potential reports, which are the ones that are:
6341+
// - Owned by the same user
6342+
// - Are either open or submitted
6343+
// - Belong to the same workspace
6344+
// And if any have a violation, then it should have a RBR
6345+
const allReports = Object.values(ReportConnection.getAllReports() ?? {}) as Report[];
6346+
const potentialReports = allReports.filter((r) => r.ownerAccountID === currentUserAccountID && (r.stateNum ?? 0) <= 1 && r.policyID === report.policyID);
6347+
return potentialReports.some(
6348+
(potentialReport) => hasViolations(potentialReport.reportID, transactionViolations) || hasWarningTypeViolations(potentialReport.reportID, transactionViolations),
63516349
);
63526350
}
63536351

63546352
/**
6355-
* Checks if we should display violation - we display violations when the expense has violation and it is not settled
6353+
* Checks to see if a report contains a violation
63566354
*/
6357-
function shouldDisplayTransactionThreadViolations(
6358-
report: OnyxEntry<Report>,
6359-
transactionViolations: OnyxCollection<TransactionViolation[]>,
6360-
parentReportAction: OnyxEntry<ReportAction>,
6361-
): boolean {
6362-
if (!ReportActionsUtils.isMoneyRequestAction(parentReportAction)) {
6363-
return false;
6364-
}
6365-
const {IOUReportID} = ReportActionsUtils.getOriginalMessage(parentReportAction) ?? {};
6366-
if (isSettled(IOUReportID) || isReportApproved(IOUReportID?.toString())) {
6367-
return false;
6368-
}
6369-
return doesTransactionThreadHaveViolations(report, transactionViolations, parentReportAction);
6355+
function hasViolations(reportID: string, transactionViolations: OnyxCollection<TransactionViolation[]>, shouldShowInReview?: boolean): boolean {
6356+
const transactions = reportsTransactions[reportID] ?? [];
6357+
return transactions.some((transaction) => TransactionUtils.hasViolation(transaction.transactionID, transactionViolations, shouldShowInReview));
63706358
}
63716359

63726360
/**
6373-
* Checks to see if a report contains a violation
6361+
* Checks to see if a report contains a violation of type `warning`
63746362
*/
6375-
function hasViolations(reportID: string, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean {
6363+
function hasWarningTypeViolations(reportID: string, transactionViolations: OnyxCollection<TransactionViolation[]>, shouldShowInReview?: boolean): boolean {
63766364
const transactions = reportsTransactions[reportID] ?? [];
6377-
return transactions.some((transaction) => TransactionUtils.hasViolation(transaction.transactionID, transactionViolations));
6365+
return transactions.some((transaction) => TransactionUtils.hasWarningTypeViolation(transaction.transactionID, transactionViolations, shouldShowInReview));
63786366
}
63796367

63806368
/**
6381-
* Checks to see if a report contains a violation of type `warning`
6369+
* Checks to see if a report contains a violation of type `notice`
63826370
*/
6383-
function hasWarningTypeViolations(reportID: string, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean {
6371+
function hasNoticeTypeViolations(reportID: string, transactionViolations: OnyxCollection<TransactionViolation[]>, shouldShowInReview?: boolean): boolean {
63846372
const transactions = reportsTransactions[reportID] ?? [];
6385-
return transactions.some((transaction) => TransactionUtils.hasWarningTypeViolation(transaction.transactionID, transactionViolations));
6373+
return transactions.some((transaction) => TransactionUtils.hasNoticeTypeViolation(transaction.transactionID, transactionViolations, shouldShowInReview));
63866374
}
63876375

63886376
function hasReportViolations(reportID: string) {
@@ -6404,23 +6392,6 @@ function shouldAdminsRoomBeVisible(report: OnyxEntry<Report>): boolean {
64046392
return true;
64056393
}
64066394

6407-
/**
6408-
* Check whether report has violations
6409-
*/
6410-
function shouldShowViolations(report: Report, transactionViolations: OnyxCollection<TransactionViolation[]>) {
6411-
const {parentReportID, parentReportActionID} = report ?? {};
6412-
const canGetParentReport = parentReportID && parentReportActionID && allReportActions;
6413-
if (!canGetParentReport) {
6414-
return false;
6415-
}
6416-
const parentReportActions = allReportActions ? allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`] ?? {} : {};
6417-
const parentReportAction = parentReportActions[parentReportActionID] ?? null;
6418-
if (!parentReportAction) {
6419-
return false;
6420-
}
6421-
return shouldDisplayTransactionThreadViolations(report, transactionViolations, parentReportAction);
6422-
}
6423-
64246395
type ReportErrorsAndReportActionThatRequiresAttention = {
64256396
errors: ErrorFields;
64266397
reportAction?: OnyxEntry<ReportAction>;
@@ -6503,7 +6474,7 @@ function hasReportErrorsOtherThanFailedReceipt(report: Report, doesReportHaveVio
65036474
let doesTransactionThreadReportHasViolations = false;
65046475
if (oneTransactionThreadReportID) {
65056476
const transactionReport = getReport(oneTransactionThreadReportID);
6506-
doesTransactionThreadReportHasViolations = !!transactionReport && shouldShowViolations(transactionReport, transactionViolations);
6477+
doesTransactionThreadReportHasViolations = !!transactionReport && shouldDisplayViolationsRBRInLHN(transactionReport, transactionViolations);
65076478
}
65086479
return (
65096480
doesTransactionThreadReportHasViolations ||
@@ -8497,7 +8468,6 @@ export {
84978468
chatIncludesConcierge,
84988469
createDraftTransactionAndNavigateToParticipantSelector,
84998470
doesReportBelongToWorkspace,
8500-
doesTransactionThreadHaveViolations,
85018471
findLastAccessedReport,
85028472
findSelfDMReportID,
85038473
formatReportLastMessageText,
@@ -8601,6 +8571,7 @@ export {
86018571
hasUpdatedTotal,
86028572
hasViolations,
86038573
hasWarningTypeViolations,
8574+
hasNoticeTypeViolations,
86048575
isActionCreator,
86058576
isAdminRoom,
86068577
isAdminsOnlyPostingRoom,
@@ -8702,7 +8673,7 @@ export {
87028673
shouldDisableRename,
87038674
shouldDisableThread,
87048675
shouldDisplayThreadReplies,
8705-
shouldDisplayTransactionThreadViolations,
8676+
shouldDisplayViolationsRBRInLHN,
87068677
shouldReportBeInOptionList,
87078678
shouldReportShowSubscript,
87088679
shouldShowFlagComment,
@@ -8750,7 +8721,6 @@ export {
87508721
buildOptimisticChangeFieldAction,
87518722
isPolicyRelatedReport,
87528723
hasReportErrorsOtherThanFailedReceipt,
8753-
shouldShowViolations,
87548724
getAllReportErrors,
87558725
getAllReportActionsErrorsAndReportActionThatRequiresAttention,
87568726
hasInvoiceReports,

src/libs/SidebarUtils.ts

+5-16
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ function getOrderedReportIDs(
110110
return;
111111
}
112112
const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1');
113-
const doesReportHaveViolations = ReportUtils.shouldShowViolations(report, transactionViolations);
113+
const doesReportHaveViolations = ReportUtils.shouldDisplayViolationsRBRInLHN(report, transactionViolations);
114114
const isHidden = ReportUtils.getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
115115
const isFocused = report.reportID === currentReportId;
116116
const hasErrorsOtherThanFailedReceipt = ReportUtils.hasReportErrorsOtherThanFailedReceipt(report, doesReportHaveViolations, transactionViolations);
@@ -239,22 +239,11 @@ function getReasonAndReportActionThatHasRedBrickRoad(
239239
): ReasonAndReportActionThatHasRedBrickRoad | null {
240240
const {errors, reportAction} = ReportUtils.getAllReportActionsErrorsAndReportActionThatRequiresAttention(report, reportActions);
241241
const hasErrors = Object.keys(errors).length !== 0;
242-
const oneTransactionThreadReportID = ReportActionsUtils.getOneTransactionThreadReportID(report.reportID, ReportActionsUtils.getAllReportActions(report.reportID));
243242

244-
if (oneTransactionThreadReportID) {
245-
const oneTransactionThreadReport = ReportUtils.getReport(oneTransactionThreadReportID);
246-
247-
if (
248-
ReportUtils.shouldDisplayTransactionThreadViolations(
249-
oneTransactionThreadReport,
250-
transactionViolations,
251-
ReportActionsUtils.getAllReportActions(report.reportID)[oneTransactionThreadReport?.parentReportActionID ?? '-1'],
252-
)
253-
) {
254-
return {
255-
reason: CONST.RBR_REASONS.HAS_TRANSACTION_THREAD_VIOLATIONS,
256-
};
257-
}
243+
if (ReportUtils.shouldDisplayViolationsRBRInLHN(report, transactionViolations)) {
244+
return {
245+
reason: CONST.RBR_REASONS.HAS_TRANSACTION_THREAD_VIOLATIONS,
246+
};
258247
}
259248

260249
if (hasErrors) {

src/libs/TransactionUtils/index.ts

+14-19
Original file line numberDiff line numberDiff line change
@@ -866,41 +866,37 @@ function isOnHoldByTransactionID(transactionID: string): boolean {
866866
/**
867867
* Checks if any violations for the provided transaction are of type 'violation'
868868
*/
869-
function hasViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolations>): boolean {
869+
function hasViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolations>, showInReview?: boolean): boolean {
870870
return !!transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some(
871-
(violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.VIOLATION,
871+
(violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.VIOLATION && (showInReview === undefined || showInReview === (violation.showInReview ?? false)),
872872
);
873873
}
874874

875875
/**
876876
* Checks if any violations for the provided transaction are of type 'notice'
877877
*/
878-
function hasNoticeTypeViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean {
879-
return !!transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some((violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.NOTICE);
878+
function hasNoticeTypeViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolation[]>, showInReview?: boolean): boolean {
879+
return !!transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some(
880+
(violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.NOTICE && (showInReview === undefined || showInReview === (violation.showInReview ?? false)),
881+
);
880882
}
881883

882884
/**
883885
* Checks if any violations for the provided transaction are of type 'warning'
884886
*/
885-
function hasWarningTypeViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean {
886-
const warningTypeViolations = transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.filter(
887-
(violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.WARNING,
888-
);
887+
function hasWarningTypeViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolation[]>, showInReview?: boolean | null): boolean {
888+
const violations = transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID];
889+
const warningTypeViolations =
890+
violations?.filter(
891+
(violation: TransactionViolation) => violation.type === CONST.VIOLATION_TYPES.WARNING && (showInReview === null || showInReview === (violation.showInReview ?? false)),
892+
) ?? [];
893+
889894
const hasOnlyDupeDetectionViolation = warningTypeViolations?.every((violation: TransactionViolation) => violation.name === CONST.VIOLATIONS.DUPLICATED_TRANSACTION);
890895
if (!Permissions.canUseDupeDetection(allBetas ?? []) && hasOnlyDupeDetectionViolation) {
891896
return false;
892897
}
893898

894-
return !!warningTypeViolations && warningTypeViolations.length > 0;
895-
}
896-
897-
/**
898-
* Checks if any violations for the provided transaction are of modifiedAmount or modifiedDate
899-
*/
900-
function hasModifiedAmountOrDateViolation(transactionID: string, transactionViolations: OnyxCollection<TransactionViolation[]>): boolean {
901-
return !!transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID]?.some(
902-
(violation: TransactionViolation) => violation.name === CONST.VIOLATIONS.MODIFIED_AMOUNT || violation.name === CONST.VIOLATIONS.MODIFIED_DATE,
903-
);
899+
return warningTypeViolations.length > 0;
904900
}
905901

906902
/**
@@ -1292,7 +1288,6 @@ export {
12921288
shouldShowBrokenConnectionViolation,
12931289
hasNoticeTypeViolation,
12941290
hasWarningTypeViolation,
1295-
hasModifiedAmountOrDateViolation,
12961291
isCustomUnitRateIDForP2P,
12971292
getRateID,
12981293
getTransaction,

src/libs/WorkspacesSettingsUtils.ts

+1-7
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,7 @@ const getBrickRoadForPolicy = (report: Report, altReportActions?: OnyxCollection
7878
if (oneTransactionThreadReportID && !doesReportContainErrors) {
7979
const oneTransactionThreadReport = ReportUtils.getReport(oneTransactionThreadReportID);
8080

81-
if (
82-
ReportUtils.shouldDisplayTransactionThreadViolations(
83-
oneTransactionThreadReport,
84-
allTransactionViolations,
85-
reportActions[oneTransactionThreadReport?.parentReportActionID ?? '-1'],
86-
)
87-
) {
81+
if (ReportUtils.shouldDisplayViolationsRBRInLHN(oneTransactionThreadReport, allTransactionViolations)) {
8882
doesReportContainErrors = CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR;
8983
}
9084
}

src/pages/Debug/Report/DebugReportPage.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,13 @@ function DebugReportPage({
5353
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
5454
const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`);
5555
const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
56-
const [parentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report?.parentReportID ?? '-1'}`);
57-
const parentReportAction = parentReportActions && report?.parentReportID ? parentReportActions[report?.parentReportActionID ?? '-1'] : undefined;
5856

5957
const metadata = useMemo<Metadata[]>(() => {
6058
if (!report) {
6159
return [];
6260
}
6361

64-
const shouldDisplayViolations = ReportUtils.shouldDisplayTransactionThreadViolations(report, transactionViolations, parentReportAction);
62+
const shouldDisplayViolations = ReportUtils.shouldDisplayViolationsRBRInLHN(report, transactionViolations);
6563
const shouldDisplayReportViolations = ReportUtils.isReportOwner(report) && ReportUtils.hasReportViolations(reportID);
6664
const hasViolations = !!shouldDisplayViolations || shouldDisplayReportViolations;
6765
const {reason: reasonGBR, reportAction: reportActionGBR} = DebugUtils.getReasonAndReportActionForGBRInLHNRow(report) ?? {};
@@ -113,7 +111,7 @@ function DebugReportPage({
113111
: undefined,
114112
},
115113
];
116-
}, [parentReportAction, report, reportActions, reportID, transactionViolations, translate]);
114+
}, [report, reportActions, reportID, transactionViolations, translate]);
117115

118116
if (!report) {
119117
return <NotFoundPage />;

src/types/onyx/TransactionViolation.ts

+3
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ type TransactionViolation = {
9292

9393
/** Additional violation information to provide the user */
9494
data?: TransactionViolationData;
95+
96+
/** Indicates if this violation should be shown in review */
97+
showInReview?: boolean;
9598
};
9699

97100
/** Collection of transaction violations */

0 commit comments

Comments
 (0)