Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
6 changes: 6 additions & 0 deletions src/libs/API/parameters/DismissExportErrorParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type DismissExportErrorParams = {
reportID: string;
reportActionID: string;
};

export default DismissExportErrorParams;
1 change: 1 addition & 0 deletions src/libs/API/parameters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ export type {default as ShareTrackedExpenseParams} from './ShareTrackedExpensePa
export type {default as CategorizeTrackedExpenseParams} from './CategorizeTrackedExpenseParams';
export type {default as LeavePolicyParams} from './LeavePolicyParams';
export type {default as OpenPolicyAccountingPageParams} from './OpenPolicyAccountingPageParams';
export type {default as DismissExportErrorParams} from './DismissExportErrorParams';
export type {default as DismissViolationParams} from './DismissViolationParams';
export type {default as SearchParams} from './Search';
export type {default as SendInvoiceParams} from './SendInvoiceParams';
Expand Down
2 changes: 2 additions & 0 deletions src/libs/API/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@ const WRITE_COMMANDS = {
CATEGORIZE_TRACKED_EXPENSE: 'CategorizeTrackedExpense',
SHARE_TRACKED_EXPENSE: 'ShareTrackedExpense',
LEAVE_POLICY: 'LeavePolicy',
DISMISS_EXPORT_ERROR: 'DismissExportError',
DISMISS_VIOLATION: 'DismissViolation',
SEND_INVOICE: 'SendInvoice',
PAY_INVOICE: 'PayInvoice',
Expand Down Expand Up @@ -882,6 +883,7 @@ type WriteCommandParameters = {
[WRITE_COMMANDS.CATEGORIZE_TRACKED_EXPENSE]: Parameters.CategorizeTrackedExpenseParams;
[WRITE_COMMANDS.SHARE_TRACKED_EXPENSE]: Parameters.ShareTrackedExpenseParams;
[WRITE_COMMANDS.LEAVE_POLICY]: Parameters.LeavePolicyParams;
[WRITE_COMMANDS.DISMISS_EXPORT_ERROR]: Parameters.DismissExportErrorParams;
[WRITE_COMMANDS.DISMISS_VIOLATION]: Parameters.DismissViolationParams;
[WRITE_COMMANDS.SEND_INVOICE]: Parameters.SendInvoiceParams;
[WRITE_COMMANDS.PAY_INVOICE]: Parameters.PayInvoiceParams;
Expand Down
50 changes: 46 additions & 4 deletions src/libs/actions/ReportActions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type {OnyxCollection} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import * as API from '@libs/API';
import {WRITE_COMMANDS} from '@libs/API/types';
import {getLinkedTransactionID, getReportAction, getReportActionMessage, isCreatedTaskReportAction} from '@libs/ReportActionsUtils';
import {getOriginalReportID} from '@libs/ReportUtils';
import CONST from '@src/CONST';
Expand All @@ -11,14 +13,14 @@
type IgnoreDirection = 'parent' | 'child';

let allReportActions: OnyxCollection<OnyxTypes.ReportActions>;
Onyx.connect({

Check warning on line 16 in src/libs/actions/ReportActions.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
waitForCollectionCallback: true,
callback: (value) => (allReportActions = value),
});

let allReports: OnyxCollection<OnyxTypes.Report>;
Onyx.connect({

Check warning on line 23 in src/libs/actions/ReportActions.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (value) => {
Expand Down Expand Up @@ -105,8 +107,48 @@
}
}

/**
* Dismiss an export error action (INTEGRATIONS_MESSAGE) from the chat.
* This removes the action from the UI and marks it as dismissed in the database.
*
* @param reportID - The report ID containing the action
* @param reportActionID - The report action ID to dismiss
*/
function dismissExportError(reportID: string, reportActionID: string) {
// Optimistically remove the action from the UI
const optimisticData = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: {
[reportActionID]: null,
},
},
];

// If the request fails, restore the action (we'd need the original action data here)
// For now, we'll rely on the server to push the correct state
const failureData = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,
value: {
[reportActionID]: {
errors: {
[Date.now()]: 'Failed to dismiss export error. Please try again.',
},
},
},
},
];

const parameters = {
reportID,
reportActionID,
};

API.write(WRITE_COMMANDS.DISMISS_EXPORT_ERROR, parameters, {optimisticData, failureData});

Check failure on line 150 in src/libs/actions/ReportActions.ts

View workflow job for this annotation

GitHub Actions / typecheck

Type '{ onyxMethod: "merge"; key: string; value: { [x: string]: { errors: { [x: number]: string; }; }; }; }[]' is not assignable to type 'OnyxUpdate[]'.

Check failure on line 150 in src/libs/actions/ReportActions.ts

View workflow job for this annotation

GitHub Actions / typecheck

Type '{ onyxMethod: "merge"; key: string; value: { [x: string]: null; }; }[]' is not assignable to type 'OnyxUpdate[]'.
}

export type {IgnoreDirection};
export {
// eslint-disable-next-line import/prefer-default-export
clearAllRelatedReportActionErrors,
};
export {clearAllRelatedReportActionErrors, dismissExportError};
8 changes: 8 additions & 0 deletions src/pages/home/report/PureReportActionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import {canUseTouchScreen} from '@libs/DeviceCapabilities';
import type {OnyxDataWithErrors} from '@libs/ErrorUtils';
import {getLatestErrorMessageField, isReceiptError} from '@libs/ErrorUtils';
import {dismissExportError} from '@libs/actions/ReportActions';
import focusComposerWithDelay from '@libs/focusComposerWithDelay';
import {isReportMessageAttachment} from '@libs/isReportMessageAttachment';
import Navigation from '@libs/Navigation/Navigation';
Expand Down Expand Up @@ -130,6 +131,7 @@
isCreatedTaskReportAction,
isDeletedAction,
isDeletedParentAction as isDeletedParentActionUtils,
isIntegrationMessageAction,
isIOURequestReportAction,
isMarkAsClosedAction,
isMessageDeleted,
Expand Down Expand Up @@ -559,6 +561,12 @@

const [showConfirmDismissReceiptError, setShowConfirmDismissReceiptError] = useState(false);
const dismissError = useCallback(() => {
// For INTEGRATIONS_MESSAGE actions (export errors), dismiss the entire action
if (isIntegrationMessageAction(action) && action.reportActionID) {
dismissExportError(reportID, action.reportActionID);

Check failure on line 566 in src/pages/home/report/PureReportActionItem.tsx

View workflow job for this annotation

GitHub Actions / typecheck

Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
return;
}

const transactionID = isMoneyRequestAction(action) ? getOriginalMessage(action)?.IOUTransactionID : undefined;
if (transactionID) {
clearError(transactionID);
Expand Down
20 changes: 15 additions & 5 deletions src/pages/home/sidebar/SidebarLinks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ import type {EdgeInsets} from 'react-native-safe-area-context';
import type {ValueOf} from 'type-fest';
import LHNOptionsList from '@components/LHNOptionsList/LHNOptionsList';
import OptionsListSkeletonView from '@components/OptionsListSkeletonView';
import useOnyx from '@hooks/useOnyx';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import {confirmReadyToOpenApp, setSidebarLoaded} from '@libs/actions/App';
import Navigation from '@libs/Navigation/Navigation';
import {getAllReportActionsErrorsAndReportActionThatRequiresAttention} from '@libs/ReportUtils';
import {cancelSpan} from '@libs/telemetry/activeSpans';
import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {Report} from '@src/types/onyx';

Expand All @@ -37,6 +40,7 @@ function SidebarLinks({insets, optionListItems, isLoading, priorityMode = CONST.
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const {shouldUseNarrowLayout} = useResponsiveLayout();
const [reportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, {canBeMissing: false});

useEffect(() => {
confirmReadyToOpenApp();
Expand All @@ -56,23 +60,29 @@ function SidebarLinks({insets, optionListItems, isLoading, priorityMode = CONST.
// or when clicking the active LHN row on large screens
// or when continuously clicking different LHNs, only apply to small screen
// since getTopmostReportId always returns on other devices
const reportActionID = Navigation.getTopmostReportActionId();
const currentReportActionID = Navigation.getTopmostReportActionId();

// Prevent opening a new Report page if the user quickly taps on another conversation
// before the first one is displayed.
const shouldBlockReportNavigation = Navigation.getActiveRoute() !== '/home' && shouldUseNarrowLayout;

if (
(option.reportID === Navigation.getTopmostReportId() && !reportActionID) ||
(shouldUseNarrowLayout && isActiveReport(option.reportID) && !reportActionID) ||
(option.reportID === Navigation.getTopmostReportId() && !currentReportActionID) ||
(shouldUseNarrowLayout && isActiveReport(option.reportID) && !currentReportActionID) ||
shouldBlockReportNavigation
) {
cancelSpan(`${CONST.TELEMETRY.SPAN_OPEN_REPORT}_${option.reportID}`);
return;
}
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(option.reportID));

// Check if this report has a report action with errors (RBR) and navigate to that action
const reportActionsForReport = reportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${option.reportID}`];
const {reportAction: errorReportAction} = getAllReportActionsErrorsAndReportActionThatRequiresAttention(option, reportActionsForReport);
const errorReportActionID = errorReportAction?.reportActionID;

Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(option.reportID, errorReportActionID));
},
[shouldUseNarrowLayout, isActiveReport],
[shouldUseNarrowLayout, isActiveReport, reportActions],
);

const viewMode = priorityMode === CONST.PRIORITY_MODE.GSD ? CONST.OPTION_MODE.COMPACT : CONST.OPTION_MODE.DEFAULT;
Expand Down
Loading