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

[Details Revamp] Allow Editing Report Title from Details Page #44671

Merged
5 changes: 5 additions & 0 deletions src/components/MenuItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,9 @@ type MenuItemBaseProps = {
/** Text to display under the main item */
furtherDetails?: string;

/** Render custom content under the main item */
furtherDetailsComponent?: ReactElement;

/** The function that should be called when this component is LongPressed or right-clicked. */
onSecondaryInteraction?: (event: GestureResponderEvent | MouseEvent) => void;

Expand Down Expand Up @@ -338,6 +341,7 @@ function MenuItem(
iconRight = Expensicons.ArrowRight,
furtherDetailsIcon,
furtherDetails,
furtherDetailsComponent,
description,
helperText,
helperTextStyle,
Expand Down Expand Up @@ -702,6 +706,7 @@ function MenuItem(
</Text>
</View>
)}
{!!furtherDetailsComponent && <View style={[styles.flexRow, styles.alignItemsCenter]}>{furtherDetailsComponent}</View>}
{titleComponent}
</View>
</View>
Expand Down
7 changes: 5 additions & 2 deletions src/components/ReportActionItem/MoneyReportView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,11 @@ function MoneyReportView({report, policy}: MoneyReportViewProps) {
<>
{ReportUtils.reportFieldsEnabled(report) &&
sortedPolicyReportFields.map((reportField) => {
const isTitleField = ReportUtils.isReportFieldOfTypeTitle(reportField);
const fieldValue = isTitleField ? report.reportName : reportField.value ?? reportField.defaultValue;
if (ReportUtils.isReportFieldOfTypeTitle(reportField)) {
return null;
}

const fieldValue = reportField.value ?? reportField.defaultValue;
const isFieldDisabled = ReportUtils.isReportFieldDisabled(report, reportField, policy);
const fieldKey = ReportUtils.getReportFieldKey(reportField.fieldID);

Expand Down
7 changes: 7 additions & 0 deletions src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6888,6 +6888,12 @@ function isNonAdminOrOwnerOfPolicyExpenseChat(report: OnyxInputOrEntry<Report>,
return isPolicyExpenseChat(report) && !(PolicyUtils.isPolicyAdmin(policy) || PolicyUtils.isPolicyOwner(policy, currentUserAccountID ?? -1) || isReportOwner(report));
}

function isAdminOwnerApproverOrReportOwner(report: OnyxEntry<Report>, policy: OnyxEntry<Policy>): boolean {
const isApprover = isMoneyRequestReport(report) && report?.managerID !== null && currentUserPersonalDetails?.accountID === report?.managerID;

return PolicyUtils.isPolicyAdmin(policy) || PolicyUtils.isPolicyOwner(policy, currentUserAccountID ?? -1) || isReportOwner(report) || isApprover;
}

/**
* Whether the user can join a report
*/
Expand Down Expand Up @@ -7347,6 +7353,7 @@ export {
isCurrentUserInvoiceReceiver,
isDraftReport,
changeMoneyRequestHoldStatus,
isAdminOwnerApproverOrReportOwner,
createDraftWorkspaceAndNavigateToConfirmationScreen,
isChatUsedForOnboarding,
getChatUsedForOnboarding,
Expand Down
72 changes: 58 additions & 14 deletions src/pages/ReportDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {StackScreenProps} from '@react-navigation/stack';
import {Str} from 'expensify-common';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
Expand Down Expand Up @@ -472,7 +473,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
return result;
}, [report, parentReportAction, canJoin, isExpenseReport, shouldShowHoldAction, canHoldUnholdReportAction.canHoldRequest]);

const nameSectionExpenseIOU = (
const nameSectionStatic = (
<View style={[styles.reportDetailsRoomInfo, styles.mw100]}>
{shouldDisableRename && (
<>
Expand Down Expand Up @@ -515,23 +516,66 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
</View>
);

const nameSectionGroupWorkspace = (
const titleField = useMemo<OnyxTypes.PolicyReportField | undefined>((): OnyxTypes.PolicyReportField | undefined => {
const fields = ReportUtils.getAvailableReportFields(report, Object.values(policy?.fieldList ?? {}));
return fields.find((reportField) => ReportUtils.isReportFieldOfTypeTitle(reportField));
}, [report, policy?.fieldList]);
const fieldKey = ReportUtils.getReportFieldKey(titleField?.fieldID ?? '-1');
const isFieldDisabled = ReportUtils.isReportFieldDisabled(report, titleField, policy);

const shouldShowTitleField = caseID !== CASES.MONEY_REQUEST && !isFieldDisabled && ReportUtils.isAdminOwnerApproverOrReportOwner(report, policy);

const nameSectionFurtherDetailsContent = (
<ParentNavigationSubtitle
parentNavigationSubtitleData={parentNavigationSubtitleData}
parentReportID={report?.parentReportID}
parentReportActionID={report?.parentReportActionID}
pressableStyles={[styles.mt1, styles.mw100]}
/>
);

const editableSectionParams = {
[CASES.MONEY_REPORT]: {
pendingAction: report.pendingFields?.[fieldKey],
errors: report.errorFields?.[fieldKey],
errorRowStyles: styles.ph5,
onClose: () => titleField && Report.clearReportFieldErrors(report.reportID, titleField),
disabled: isFieldDisabled,
onPress: () => Navigation.navigate(ROUTES.EDIT_REPORT_FIELD_REQUEST.getRoute(report.reportID, report.policyID ?? '-1', titleField?.fieldID ?? '-1')),
furtherDetailsComponent: nameSectionFurtherDetailsContent,
description: Str.UCFirst(titleField?.name ?? ''),
},
[CASES.DEFAULT]: {
pendingAction: report?.pendingFields?.reportName,
errors: report?.errorFields?.reportName,
errorRowStyles: styles.ph5,
onClose: () => Report.clearPolicyRoomNameErrors(report?.reportID),
disabled: shouldDisableRename,
containerStyle: !shouldDisableRename && styles.mt3,
onPress: () => Navigation.navigate(ROUTES.REPORT_SETTINGS_NAME.getRoute(report.reportID)),
furtherDetails: chatRoomSubtitle && !isGroupChat ? additionalRoomDetails : '',
description: !shouldDisableRename ? roomDescription : '',
},
};
cdOut marked this conversation as resolved.
Show resolved Hide resolved

const nameSectionEditable = (
<OfflineWithFeedback
pendingAction={report?.pendingFields?.reportName}
errors={report?.errorFields?.reportName}
errorRowStyles={[styles.ph5]}
onClose={() => Report.clearPolicyRoomNameErrors(report?.reportID)}
pendingAction={editableSectionParams[caseID].pendingAction}
cdOut marked this conversation as resolved.
Show resolved Hide resolved
errors={editableSectionParams[caseID].errors}
errorRowStyles={editableSectionParams[caseID].errorRowStyles}
onClose={editableSectionParams[caseID].onClose}
>
<View style={[styles.flex1, !shouldDisableRename && styles.mt3]}>
<View style={[styles.flex1, editableSectionParams[caseID].containerStyle]}>
<MenuItemWithTopDescription
shouldShowRightIcon={!shouldDisableRename}
interactive={!shouldDisableRename}
shouldShowRightIcon={!editableSectionParams[caseID].disabled}
interactive={!editableSectionParams[caseID].disabled}
title={reportName}
titleStyle={styles.newKansasLarge}
shouldCheckActionAllowedOnPress={false}
description={!shouldDisableRename ? roomDescription : ''}
furtherDetails={chatRoomSubtitle && !isGroupChat ? additionalRoomDetails : ''}
onPress={() => Navigation.navigate(ROUTES.REPORT_SETTINGS_NAME.getRoute(report.reportID))}
description={editableSectionParams[caseID].description}
onPress={editableSectionParams[caseID].onPress}
furtherDetails={editableSectionParams[caseID].furtherDetails}
furtherDetailsComponent={editableSectionParams[caseID].furtherDetailsComponent}
/>
</View>
</OfflineWithFeedback>
Expand Down Expand Up @@ -565,10 +609,10 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
<ScrollView style={[styles.flex1]}>
<View style={[styles.reportDetailsTitleContainer, styles.pb0]}>
{renderedAvatar}
{isExpenseReport && nameSectionExpenseIOU}
{isExpenseReport && !shouldShowTitleField && nameSectionStatic}
</View>

{!isExpenseReport && nameSectionGroupWorkspace}
{!isExpenseReport || (isExpenseReport && shouldShowTitleField && nameSectionEditable)}

{shouldShowReportDescription && (
<OfflineWithFeedback pendingAction={report.pendingFields?.description}>
Expand Down
Loading