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

Move RBR to workspace chats instead of transaction threads #51893

Merged
merged 13 commits into from
Nov 12, 2024
2 changes: 1 addition & 1 deletion src/components/LHNOptionsList/OptionRowLHNData.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function OptionRowLHNData({

const optionItemRef = useRef<OptionData>();

const shouldDisplayViolations = ReportUtils.shouldDisplayTransactionThreadViolations(fullReport, transactionViolations, parentReportAction);
const shouldDisplayViolations = ReportUtils.shouldDisplayViolationsRBRInLHN(fullReport, transactionViolations);
const shouldDisplayReportViolations = ReportUtils.isReportOwner(fullReport) && ReportUtils.hasReportViolations(reportID);

const optionItem = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ function MoneyRequestPreviewContent({
const isOnHold = TransactionUtils.isOnHold(transaction);
const isSettlementOrApprovalPartial = !!iouReport?.pendingFields?.partial;
const isPartialHold = isSettlementOrApprovalPartial && isOnHold;
const hasViolations = TransactionUtils.hasViolation(transaction?.transactionID ?? '-1', transactionViolations);
const hasNoticeTypeViolations = TransactionUtils.hasNoticeTypeViolation(transaction?.transactionID ?? '-1', transactionViolations) && ReportUtils.isPaidGroupPolicy(iouReport);
const hasViolations = TransactionUtils.hasViolation(transaction?.transactionID ?? '-1', transactionViolations, true);
const hasNoticeTypeViolations = TransactionUtils.hasNoticeTypeViolation(transaction?.transactionID ?? '-1', transactionViolations, true) && ReportUtils.isPaidGroupPolicy(iouReport);
const hasFieldErrors = TransactionUtils.hasMissingSmartscanFields(transaction);
const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction);
const isFetchingWaypointsFromServer = TransactionUtils.isFetchingWaypointsFromServer(transaction);
Expand Down
5 changes: 3 additions & 2 deletions src/components/ReportActionItem/ReportPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,9 @@ function ReportPreview({
const hasErrors =
(hasMissingSmartscanFields && !iouSettled) ||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
ReportUtils.hasViolations(iouReportID, transactionViolations) ||
ReportUtils.hasWarningTypeViolations(iouReportID, transactionViolations) ||
ReportUtils.hasViolations(iouReportID, transactionViolations, true) ||
ReportUtils.hasNoticeTypeViolations(iouReportID, transactionViolations, true) ||
ReportUtils.hasWarningTypeViolations(iouReportID, transactionViolations, true) ||
(ReportUtils.isReportOwner(iouReport) && ReportUtils.hasReportViolations(iouReportID)) ||
ReportUtils.hasActionsWithErrors(iouReportID);
const lastThreeTransactionsWithReceipts = transactionsWithReceipts.slice(-3);
Expand Down
2 changes: 1 addition & 1 deletion src/libs/DebugUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ function getReasonForShowingRowInLHN(report: OnyxEntry<Report>, hasRBR = false):
return null;
}

const doesReportHaveViolations = ReportUtils.shouldShowViolations(report, transactionViolations);
const doesReportHaveViolations = ReportUtils.shouldDisplayViolationsRBRInLHN(report, transactionViolations);

const reason = ReportUtils.reasonForReportToBeInOptionList({
report,
Expand Down
2 changes: 1 addition & 1 deletion src/libs/OptionsListUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1800,7 +1800,7 @@ function getOptions(
// Filter out all the reports that shouldn't be displayed
const filteredReportOptions = options.reports.filter((option) => {
const report = option.item;
const doesReportHaveViolations = ReportUtils.shouldShowViolations(report, transactionViolations);
const doesReportHaveViolations = ReportUtils.shouldDisplayViolationsRBRInLHN(report, transactionViolations);

return ReportUtils.shouldReportBeInOptionList({
report,
Expand Down
90 changes: 30 additions & 60 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Comment on lines +6322 to 6325

This comment was marked as resolved.

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
Copy link
Contributor

Choose a reason for hiding this comment

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

I see this condition was deleted if (isSettled(IOUReportID) || isReportApproved(IOUReportID?.toString())) {, but should we be checking for settled/approved reports, and only show RBR on workspace chats if there's an expense report on the same policy of the workspace chat that isn't approved or settled?

Copy link
Contributor Author

@iwiznia iwiznia Nov 8, 2024

Choose a reason for hiding this comment

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

That's done with (r.stateNum ?? 0) <= 1 below

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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make the last param mandatory?

Copy link
Contributor Author

@iwiznia iwiznia Nov 8, 2024

Choose a reason for hiding this comment

The 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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make the last param mandatory?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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) {
Expand All @@ -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>;
Expand Down Expand Up @@ -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 ||
Expand Down Expand Up @@ -8489,7 +8460,6 @@ export {
chatIncludesConcierge,
createDraftTransactionAndNavigateToParticipantSelector,
doesReportBelongToWorkspace,
doesTransactionThreadHaveViolations,
findLastAccessedReport,
findSelfDMReportID,
formatReportLastMessageText,
Expand Down Expand Up @@ -8592,6 +8562,7 @@ export {
hasUpdatedTotal,
hasViolations,
hasWarningTypeViolations,
hasNoticeTypeViolations,
isActionCreator,
isAdminRoom,
isAdminsOnlyPostingRoom,
Expand Down Expand Up @@ -8693,7 +8664,7 @@ export {
shouldDisableRename,
shouldDisableThread,
shouldDisplayThreadReplies,
shouldDisplayTransactionThreadViolations,
shouldDisplayViolationsRBRInLHN,
shouldReportBeInOptionList,
shouldReportShowSubscript,
shouldShowFlagComment,
Expand Down Expand Up @@ -8741,7 +8712,6 @@ export {
buildOptimisticChangeFieldAction,
isPolicyRelatedReport,
hasReportErrorsOtherThanFailedReceipt,
shouldShowViolations,
getAllReportErrors,
getAllReportActionsErrorsAndReportActionThatRequiresAttention,
hasInvoiceReports,
Expand Down
21 changes: 5 additions & 16 deletions src/libs/SidebarUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ function getOrderedReportIDs(
return;
}
const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1');
const doesReportHaveViolations = ReportUtils.shouldShowViolations(report, transactionViolations);
const doesReportHaveViolations = ReportUtils.shouldDisplayViolationsRBRInLHN(report, transactionViolations);
const isHidden = ReportUtils.getReportNotificationPreference(report) === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
const isFocused = report.reportID === currentReportId;
const hasErrorsOtherThanFailedReceipt = ReportUtils.hasReportErrorsOtherThanFailedReceipt(report, doesReportHaveViolations, transactionViolations);
Expand Down Expand Up @@ -239,22 +239,11 @@ function getReasonAndReportActionThatHasRedBrickRoad(
): ReasonAndReportActionThatHasRedBrickRoad | null {
const {errors, reportAction} = ReportUtils.getAllReportActionsErrorsAndReportActionThatRequiresAttention(report, reportActions);
const hasErrors = Object.keys(errors).length !== 0;
const oneTransactionThreadReportID = ReportActionsUtils.getOneTransactionThreadReportID(report.reportID, ReportActionsUtils.getAllReportActions(report.reportID));

if (oneTransactionThreadReportID) {
const oneTransactionThreadReport = ReportUtils.getReport(oneTransactionThreadReportID);

if (
ReportUtils.shouldDisplayTransactionThreadViolations(
oneTransactionThreadReport,
transactionViolations,
ReportActionsUtils.getAllReportActions(report.reportID)[oneTransactionThreadReport?.parentReportActionID ?? '-1'],
)
) {
return {
reason: CONST.RBR_REASONS.HAS_TRANSACTION_THREAD_VIOLATIONS,
};
}
if (ReportUtils.shouldDisplayViolationsRBRInLHN(report, transactionViolations)) {
return {
reason: CONST.RBR_REASONS.HAS_TRANSACTION_THREAD_VIOLATIONS,
};
}

if (hasErrors) {
Expand Down
33 changes: 14 additions & 19 deletions src/libs/TransactionUtils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make the last param mandatory?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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)),
Copy link
Contributor

Choose a reason for hiding this comment

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

This logic is confusing. If showInReview is false and violation.showInReview is unset (not sent by BE). Then we will end up showing this in review? (false === false)

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah I see it now, that's a filter.

);
}

/**
* 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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make the last param mandatory?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make the last param mandatory?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 =
Copy link
Contributor

Choose a reason for hiding this comment

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

NAB but break this down to make it more readable

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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

Copy link
Contributor

Choose a reason for hiding this comment

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

Putting transactionViolations?.[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS + transactionID] in a variable

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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;
}

/**
Expand Down Expand Up @@ -1284,7 +1280,6 @@ export {
shouldShowBrokenConnectionViolation,
hasNoticeTypeViolation,
hasWarningTypeViolation,
hasModifiedAmountOrDateViolation,
isCustomUnitRateIDForP2P,
getRateID,
getTransaction,
Expand Down
8 changes: 1 addition & 7 deletions src/libs/WorkspacesSettingsUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,7 @@ const getBrickRoadForPolicy = (report: Report, altReportActions?: OnyxCollection
if (oneTransactionThreadReportID) {
const oneTransactionThreadReport = ReportUtils.getReport(oneTransactionThreadReportID);

if (
ReportUtils.shouldDisplayTransactionThreadViolations(
oneTransactionThreadReport,
allTransactionViolations,
reportActions[oneTransactionThreadReport?.parentReportActionID ?? '-1'],
)
) {
if (ReportUtils.shouldDisplayViolationsRBRInLHN(oneTransactionThreadReport, allTransactionViolations)) {
doesReportContainErrors = CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR;
}
}
Expand Down
6 changes: 2 additions & 4 deletions src/pages/Debug/Report/DebugReportPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,13 @@ function DebugReportPage({
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`);
const [transactionViolations] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS);
const [parentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report?.parentReportID ?? '-1'}`);
const parentReportAction = parentReportActions && report?.parentReportID ? parentReportActions[report?.parentReportActionID ?? '-1'] : undefined;

const metadata = useMemo<Metadata[]>(() => {
if (!report) {
return [];
}

const shouldDisplayViolations = ReportUtils.shouldDisplayTransactionThreadViolations(report, transactionViolations, parentReportAction);
const shouldDisplayViolations = ReportUtils.shouldDisplayViolationsRBRInLHN(report, transactionViolations);
const shouldDisplayReportViolations = ReportUtils.isReportOwner(report) && ReportUtils.hasReportViolations(reportID);
const hasViolations = !!shouldDisplayViolations || shouldDisplayReportViolations;
const {reason: reasonGBR, reportAction: reportActionGBR} = DebugUtils.getReasonAndReportActionForGBRInLHNRow(report) ?? {};
Expand Down Expand Up @@ -113,7 +111,7 @@ function DebugReportPage({
: undefined,
},
];
}, [parentReportAction, report, reportActions, reportID, transactionViolations, translate]);
}, [report, reportActions, reportID, transactionViolations, translate]);

if (!report) {
return <NotFoundPage />;
Expand Down
3 changes: 3 additions & 0 deletions src/types/onyx/TransactionViolation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this need to be optional?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 true

Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
showInReview?: boolean;
showInReview: boolean | undefined;

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 showInReview=true. Can you please provide a list?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Why would this need to be set for optimistic actions to work? 😕

However, now we need to know which violations has showInReview=true. Can you please provide a list?

I don't think there's a list, there's a bunch of logic controlling this property's value.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why would this need to be set for optimistic actions to work?

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

const hasViolations = TransactionUtils.hasViolation(transaction?.transactionID ?? '-1', transactionViolations, true);
that only take into account violations with showInReview=true

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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

Copy link
Contributor

Choose a reason for hiding this comment

The 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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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?

Copy link
Contributor

Choose a reason for hiding this comment

The 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 */
Expand Down
Loading
Loading