-
Notifications
You must be signed in to change notification settings - Fork 3.9k
[Better Expense Report View] Keep the Report fields at the top of the table report view #59724
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
Changes from all commits
2463522
d60056d
86d8bd5
35cf242
bfa7128
dfef4ff
3719d45
6cb2e5b
73f2d42
4a13222
e6f3fc5
a69d44f
3923245
e467075
e664797
94cc706
63ba48b
1ee23a3
0ea989b
29f44fb
addbef0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,132 @@ | ||||||||
| import {Str} from 'expensify-common'; | ||||||||
| import React, {useMemo} from 'react'; | ||||||||
| import {useOnyx} from 'react-native-onyx'; | ||||||||
| import type {OnyxEntry} from 'react-native-onyx'; | ||||||||
| import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; | ||||||||
| import OfflineWithFeedback from '@components/OfflineWithFeedback'; | ||||||||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||||||||
| import {clearReportFieldKeyErrors} from '@libs/actions/Report'; | ||||||||
| import Navigation from '@libs/Navigation/Navigation'; | ||||||||
| import { | ||||||||
| getAvailableReportFields, | ||||||||
| getFieldViolation, | ||||||||
| getFieldViolationTranslation, | ||||||||
| getReportFieldKey, | ||||||||
| isInvoiceReport as isInvoiceReportUtils, | ||||||||
| isPaidGroupPolicyExpenseReport as isPaidGroupPolicyExpenseReportUtils, | ||||||||
| isReportFieldDisabled, | ||||||||
| isReportFieldOfTypeTitle, | ||||||||
| } from '@libs/ReportUtils'; | ||||||||
| import type {ThemeStyles} from '@styles/index'; | ||||||||
| import CONST from '@src/CONST'; | ||||||||
| import ONYXKEYS from '@src/ONYXKEYS'; | ||||||||
| import ROUTES from '@src/ROUTES'; | ||||||||
| import type {Policy, PolicyReportField, Report, ReportViolationName} from '@src/types/onyx'; | ||||||||
| import type {PendingAction} from '@src/types/onyx/OnyxCommon'; | ||||||||
|
|
||||||||
| type MoneyRequestViewReportFieldsProps = { | ||||||||
| /** The report currently being looked at */ | ||||||||
| report: OnyxEntry<Report>; | ||||||||
|
|
||||||||
| /** Policy that the report belongs to */ | ||||||||
| policy: OnyxEntry<Policy>; | ||||||||
|
|
||||||||
| /** Indicates whether the IOU report is a combined report */ | ||||||||
| isCombinedReport?: boolean; | ||||||||
|
|
||||||||
| /** Indicates whether we have any pending actions from parent component */ | ||||||||
| pendingAction?: PendingAction; | ||||||||
|
borys3kk marked this conversation as resolved.
|
||||||||
| }; | ||||||||
|
|
||||||||
| type EnrichedPolicyReportField = { | ||||||||
| fieldValue: string; | ||||||||
| isFieldDisabled: boolean; | ||||||||
| fieldKey: string; | ||||||||
| violation: ReportViolationName | undefined; | ||||||||
| violationTranslation: string; | ||||||||
| } & PolicyReportField; | ||||||||
|
|
||||||||
| function ReportFieldView(reportField: EnrichedPolicyReportField, report: OnyxEntry<Report>, styles: ThemeStyles, pendingAction?: PendingAction) { | ||||||||
| return ( | ||||||||
| <OfflineWithFeedback | ||||||||
| // Need to return undefined when we have pendingAction to avoid the duplicate pending action | ||||||||
| pendingAction={pendingAction ? undefined : report?.pendingFields?.[reportField.fieldKey as keyof typeof report.pendingFields]} | ||||||||
| errorRowStyles={styles.ph5} | ||||||||
| key={`menuItem-${reportField.fieldKey}`} | ||||||||
| onClose={() => clearReportFieldKeyErrors(report?.reportID, reportField.fieldKey)} | ||||||||
| > | ||||||||
| <MenuItemWithTopDescription | ||||||||
| description={Str.UCFirst(reportField.name)} | ||||||||
| title={reportField.fieldValue} | ||||||||
| onPress={() => { | ||||||||
| Navigation.navigate(ROUTES.EDIT_REPORT_FIELD_REQUEST.getRoute(report?.reportID, report?.policyID, reportField.fieldID, Navigation.getActiveRoute())); | ||||||||
| }} | ||||||||
| shouldShowRightIcon | ||||||||
| disabled={reportField.isFieldDisabled} | ||||||||
|
Comment on lines
+64
to
+65
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. caused this minor bug: #62035 |
||||||||
| wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]} | ||||||||
| shouldGreyOutWhenDisabled={false} | ||||||||
| numberOfLinesTitle={0} | ||||||||
| interactive={!reportField.isFieldDisabled} | ||||||||
| shouldStackHorizontally={false} | ||||||||
| onSecondaryInteraction={() => {}} | ||||||||
| titleWithTooltips={[]} | ||||||||
| brickRoadIndicator={reportField.violation ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : undefined} | ||||||||
| errorText={reportField.violationTranslation} | ||||||||
| /> | ||||||||
| </OfflineWithFeedback> | ||||||||
| ); | ||||||||
| } | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| function MoneyRequestViewReportFields({report, policy, isCombinedReport = false, pendingAction}: MoneyRequestViewReportFieldsProps) { | ||||||||
| const styles = useThemeStyles(); | ||||||||
|
|
||||||||
| const [violations] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_VIOLATIONS}${report?.reportID}`, {canBeMissing: true}); | ||||||||
|
|
||||||||
| const shouldHideSingleReportField = (reportField: PolicyReportField) => { | ||||||||
| const fieldValue = reportField.value ?? reportField.defaultValue; | ||||||||
| const hasEnableOption = reportField.type !== CONST.REPORT_FIELD_TYPES.LIST || reportField.disabledOptions.some((option) => !option); | ||||||||
|
|
||||||||
| return isReportFieldOfTypeTitle(reportField) || (!fieldValue && !hasEnableOption); | ||||||||
| }; | ||||||||
|
|
||||||||
| const sortedPolicyReportFields = useMemo<EnrichedPolicyReportField[]>((): EnrichedPolicyReportField[] => { | ||||||||
| const fields = getAvailableReportFields(report, Object.values(policy?.fieldList ?? {})); | ||||||||
| return fields | ||||||||
| .filter((field) => field.target === report?.type) | ||||||||
|
borys3kk marked this conversation as resolved.
|
||||||||
| .filter((reportField) => !shouldHideSingleReportField(reportField)) | ||||||||
| .sort(({orderWeight: firstOrderWeight}, {orderWeight: secondOrderWeight}) => firstOrderWeight - secondOrderWeight) | ||||||||
| .map((field): EnrichedPolicyReportField => { | ||||||||
| const fieldValue = field.value ?? field.defaultValue; | ||||||||
| const isFieldDisabled = isReportFieldDisabled(report, field, policy); | ||||||||
| const fieldKey = getReportFieldKey(field.fieldID); | ||||||||
|
|
||||||||
| const violation = getFieldViolation(violations, field); | ||||||||
| const violationTranslation = getFieldViolationTranslation(field, violation); | ||||||||
|
|
||||||||
| return { | ||||||||
| ...field, | ||||||||
| fieldValue, | ||||||||
| isFieldDisabled, | ||||||||
| fieldKey, | ||||||||
| violation, | ||||||||
| violationTranslation, | ||||||||
| }; | ||||||||
| }); | ||||||||
| }, [policy, report, violations]); | ||||||||
|
|
||||||||
| const enabledReportFields = sortedPolicyReportFields.filter((reportField) => !isReportFieldDisabled(report, reportField, policy)); | ||||||||
| const isOnlyTitleFieldEnabled = enabledReportFields.length === 1 && isReportFieldOfTypeTitle(enabledReportFields.at(0)); | ||||||||
| const isPaidGroupPolicyExpenseReport = isPaidGroupPolicyExpenseReportUtils(report); | ||||||||
| const isInvoiceReport = isInvoiceReportUtils(report); | ||||||||
|
borys3kk marked this conversation as resolved.
|
||||||||
|
|
||||||||
| const shouldDisplayReportFields = (isPaidGroupPolicyExpenseReport || isInvoiceReport) && policy?.areReportFieldsEnabled && (!isOnlyTitleFieldEnabled || !isCombinedReport); | ||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if in general it would be cleaner to refactor this method to do early returns so we can stop the execution immediately we know the report fields should not be displayed, for example if |
||||||||
|
|
||||||||
| return ( | ||||||||
| shouldDisplayReportFields && | ||||||||
| sortedPolicyReportFields.map((reportField) => { | ||||||||
| return ReportFieldView(reportField, report, styles, pendingAction); | ||||||||
| }) | ||||||||
| ); | ||||||||
| } | ||||||||
| MoneyRequestViewReportFields.displayName = 'MoneyRequestViewReportFields'; | ||||||||
|
|
||||||||
| export default MoneyRequestViewReportFields; | ||||||||
Uh oh!
There was an error while loading. Please reload this page.