Expensify / App

Welcome to New Expensify: a complete re-imagination of financial collaboration, centered around chat. Help us build the next generation of Expensify by sharing feedback and contributing to the code.
https://new.expensify.com
MIT License
3.66k stars 2.93k forks source link

Track expense - App crashes on report details RHP after submitting track expense to workspace #53547

Open IuliiaHerets opened 11 hours ago

IuliiaHerets commented 11 hours ago

If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!


Version Number: 9.0.71-0 Reproducible in staging?: Yes Reproducible in production?: Yes If this was caught on HybridApp, is this reproducible on New Expensify Standalone?: Yes If this was caught during regression testing, add the test name, ID and link from TestRail: Exp https://expensify.testrail.io/index.php?/tests/view/5299012 Email or phone of affected tester (no customers): applausetester+kh1311020@applause.expensifail.com Issue reported by: Applause Internal Team

Action Performed:

Precondition:

  1. Go to staging.new.expensify.com
  2. Go offline.
  3. Go to self DM.
  4. Track a manual expense.
  5. Click Categorize it from the actionable whisper.
  6. Select a category, enter merchant and submit the expense.
  7. Go to transaction thread in the workspace chat.
  8. Click on the report header.
  9. Go online while staying on the report details RHP.

Expected Result:

App will not crash.

Actual Result:

App crashes. Tester's devices where the issue occurs: macOS Ventura 13.4 - Chrome Samsung Galaxy Z Fold4 - Android 14, Apple iPhone 15 Pro Max - iOS 18.1 Beta.

Workaround:

Unknown

Platforms:

Screenshots/Videos

https://github.com/user-attachments/assets/5fd0d11d-a540-4be4-a0b3-68e7c2df5d70

Bug6684140_1733307605993!staging.new.expensify.com-1733307405873.txt

View all open jobs on GitHub

melvin-bot[bot] commented 11 hours ago

Triggered auto assignment to @adelekennedy (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

mkzie2 commented 10 hours ago

Proposal

Please re-state the problem that we are trying to solve in this issue.

Track expense - App crashes on report details RHP after submitting track expense to workspace

What is the root cause of that problem?

The parentReportID change to empty string which cause the crash app when we use useOnyx here

https://github.com/Expensify/App/blob/146204878d1b9d4358d91e9a0a81169a7819d96f/src/components/ParentNavigationSubtitle.tsx#L35

What changes do you think we should make in order to solve the problem?

Fallback the parentReportID to -1 here to prevent the crash app

const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${parentReportID || '-1'}`);

https://github.com/Expensify/App/blob/146204878d1b9d4358d91e9a0a81169a7819d96f/src/components/ParentNavigationSubtitle.tsx#L35

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

What alternative solutions did you explore? (Optional)

Reminder: Please use plain English, be brief and avoid jargon. Feel free to use images, charts or pseudo-code if necessary. Do not post large multi-line diffs or write walls of text. Do not create PRs unless you have been hired for this job.

saifelance commented 9 hours ago

Please re-state the problem that we are trying to solve in this issue.

The app crashes on the report details Right-Hand Panel (RHP) after submitting a tracked expense to a workspace offline and going online, disrupting user access to the report.

What is the root cause of that problem?

  1. Offline-to-Online Transition: State changes during this transition are not handled, causing invalid or incomplete data rendering.
  2. Undefined Data: Missing or incomplete report or parentAction objects cause crashes when accessed.

What changes do you think we should make in order to solve the problem?

src/components/ParentNavigationSubtitle.tsx

function ParentNavigationSubtitle({
    parentNavigationSubtitleData,
    parentReportActionID,
    parentReportID = '',
    pressableStyles,
}: ParentNavigationSubtitleProps) {
    const styles = useThemeStyles();
    const { workspaceName, reportName } = parentNavigationSubtitleData;
    const { isOffline } = useNetwork();
    const { translate } = useLocalize();
    const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${parentReportID}`);
    const canUserPerformWriteAction = ReportUtils.canUserPerformWriteAction(report);

    // Guard clause for missing report name
    if (!reportName) {
        return;
    }

    // Validate report and parentAction
    if (!report || !reportName) {
        console.error("Missing report data", { parentReportID });
        return;
    }

    const parentAction = ReportActionsUtils.getReportAction(parentReportID, parentReportActionID ?? '-1');
    if (!parentAction) {
        console.error("Missing parent action data", { parentReportID, parentReportActionID });
        return;
    }

    // Prevent navigation if offline
    if (isOffline) {
        console.warn("Cannot navigate while offline");
        return;
    }

    return (
        <PressableWithoutFeedback
            onPress={() => {
                const isVisibleAction = ReportActionsUtils.shouldReportActionBeVisible(
                    parentAction, parentAction?.reportActionID ?? '-1', canUserPerformWriteAction
                );

                // Pop the thread report screen before navigating to the chat report.
                Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID));

                if (isVisibleAction) {
                    // Pop the chat report screen before navigating to the linked report action.
                    Navigation.goBack(ROUTES.REPORT_WITH_ID.getRoute(parentReportID, parentReportActionID), true);
                } else {
                    console.warn("Report action is not visible");
                }
            }}
            accessibilityLabel={translate('threads.parentNavigationSummary', { reportName, workspaceName })}
            role={CONST.ROLE.LINK}
            style={pressableStyles}
        >
            <Text
                style={[styles.optionAlternateText, styles.textLabelSupporting]}
                numberOfLines={1}
            >
                {!!reportName && (
                    <>
                        <Text style={[styles.optionAlternateText, styles.textLabelSupporting]}>{`${translate('threads.from')} `}</Text>
                        <Text style={[styles.optionAlternateText, styles.textLabelSupporting, styles.link]}>{reportName}</Text>
                    </>
                )}
                {!!workspaceName && <Text style={[styles.optionAlternateText, styles.textLabelSupporting]}>{` ${translate('threads.in')} ${workspaceName}`}</Text>}
            </Text>
        </PressableWithoutFeedback>
    );
}

What alternative solutions did you explore? (Optional)

  1. Defer Navigation: Wait until all data is loaded before rendering or navigating.
  2. Server-Side Validation: Use server-side checks to mitigate client-side data issues.
  3. Error Boundary: Implement an error boundary to catch crashes and prevent app failure.