diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index 8ac32675bb4e..ade0c7ae8a45 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -1938,7 +1938,7 @@ function getTransactionReportName(reportAction: OnyxEntry): string * @param [reportAction] This can be either a report preview action or the IOU action */ function getReportPreviewMessage( - report: OnyxEntry, + report: OnyxEntry | EmptyObject, reportAction: OnyxEntry | EmptyObject = {}, shouldConsiderReceiptBeingScanned = false, isPreviewMessageForParentChatReport = false, diff --git a/src/pages/home/report/ReportActionItemMessage.js b/src/pages/home/report/ReportActionItemMessage.tsx similarity index 50% rename from src/pages/home/report/ReportActionItemMessage.js rename to src/pages/home/report/ReportActionItemMessage.tsx index b47d941f40b5..89d0aaa1523b 100644 --- a/src/pages/home/report/ReportActionItemMessage.js +++ b/src/pages/home/report/ReportActionItemMessage.tsx @@ -1,88 +1,83 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import React from 'react'; -import {Text, View} from 'react-native'; -import _ from 'underscore'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import React, {ReactElement} from 'react'; +import {StyleProp, Text, View, ViewStyle} from 'react-native'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import * as ReportUtils from '@libs/ReportUtils'; import CONST from '@src/CONST'; +import type {ReportAction} from '@src/types/onyx'; +import type {OriginalMessageAddComment} from '@src/types/onyx/OriginalMessage'; import TextCommentFragment from './comment/TextCommentFragment'; import ReportActionItemFragment from './ReportActionItemFragment'; -import reportActionPropTypes from './reportActionPropTypes'; -const propTypes = { +type ReportActionItemMessageProps = { /** The report action */ - action: PropTypes.shape(reportActionPropTypes).isRequired, + action: ReportAction; /** Should the comment have the appearance of being grouped with the previous comment? */ - displayAsGroup: PropTypes.bool.isRequired, + displayAsGroup: boolean; /** Additional styles to add after local styles. */ - style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), + style?: StyleProp; /** Whether or not the message is hidden by moderation */ - isHidden: PropTypes.bool, + isHidden?: boolean; /** The ID of the report */ - reportID: PropTypes.string.isRequired, - - /** localization props */ - ...withLocalizePropTypes, -}; - -const defaultProps = { - style: [], - isHidden: false, + reportID: string; }; -function ReportActionItemMessage(props) { +function ReportActionItemMessage({action, displayAsGroup, reportID, style, isHidden = false}: ReportActionItemMessageProps) { const styles = useThemeStyles(); - const fragments = _.compact(props.action.previousMessage || props.action.message); - const isIOUReport = ReportActionsUtils.isMoneyRequestAction(props.action); - if (ReportActionsUtils.isMemberChangeAction(props.action)) { - const fragment = ReportActionsUtils.getMemberChangeMessageFragment(props.action); + const {translate} = useLocalize(); + + const fragments = (action.previousMessage ?? action.message ?? []).filter((item) => !!item); + const isIOUReport = ReportActionsUtils.isMoneyRequestAction(action); + + if (ReportActionsUtils.isMemberChangeAction(action)) { + const fragment = ReportActionsUtils.getMemberChangeMessageFragment(action); return ( ); } - let iouMessage; + let iouMessage: string | undefined; if (isIOUReport) { - const iouReportID = lodashGet(props.action, 'originalMessage.IOUReportID'); + const originalMessage = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU ? action.originalMessage : null; + const iouReportID = originalMessage?.IOUReportID; if (iouReportID) { - iouMessage = ReportUtils.getReportPreviewMessage(ReportUtils.getReport(iouReportID), props.action); + iouMessage = ReportUtils.getReportPreviewMessage(ReportUtils.getReport(iouReportID), action); } } - const isApprovedOrSubmittedReportAction = _.contains([CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.SUBMITTED], props.action.actionName); + const isApprovedOrSubmittedReportAction = [CONST.REPORT.ACTIONS.TYPE.APPROVED, CONST.REPORT.ACTIONS.TYPE.SUBMITTED].some((type) => type === action.actionName); /** * Get the ReportActionItemFragments - * @param {Boolean} shouldWrapInText determines whether the fragments are wrapped in a Text component - * @returns {Object} report action item fragments + * @param shouldWrapInText determines whether the fragments are wrapped in a Text component + * @returns report action item fragments */ - const renderReportActionItemFragments = (shouldWrapInText) => { - const reportActionItemFragments = _.map(fragments, (fragment, index) => ( + const renderReportActionItemFragments = (shouldWrapInText: boolean): ReactElement | ReactElement[] => { + const reportActionItemFragments = fragments.map((fragment, index) => ( - {!props.isHidden ? ( + + {!isHidden ? ( renderReportActionItemFragments(isApprovedOrSubmittedReportAction) ) : ( - {props.translate('moderation.flaggedContent')} + {translate('moderation.flaggedContent')} )} ); } -ReportActionItemMessage.propTypes = propTypes; -ReportActionItemMessage.defaultProps = defaultProps; ReportActionItemMessage.displayName = 'ReportActionItemMessage'; -export default withLocalize(ReportActionItemMessage); +export default ReportActionItemMessage; diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts index 19b3e75ca74c..767f724dd571 100644 --- a/src/types/onyx/OriginalMessage.ts +++ b/src/types/onyx/OriginalMessage.ts @@ -24,6 +24,7 @@ type OriginalMessageApproved = { actionName: typeof CONST.REPORT.ACTIONS.TYPE.APPROVED; originalMessage: unknown; }; +type OriginalMessageSource = 'Chronos' | 'email' | 'ios' | 'android' | 'web' | ''; type IOUDetails = { amount: number; @@ -95,6 +96,7 @@ type OriginalMessageAddComment = { actionName: typeof CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT; originalMessage: { html: string; + source?: OriginalMessageSource; lastModified?: string; taskReportID?: string; edits?: string[]; @@ -252,4 +254,16 @@ type OriginalMessage = | OriginalMessageMoved; export default OriginalMessage; -export type {ChronosOOOEvent, Decision, Reaction, ActionName, IOUMessage, Closed, OriginalMessageActionName, ChangeLog, OriginalMessageIOU, OriginalMessageCreated}; +export type { + ChronosOOOEvent, + Decision, + Reaction, + ActionName, + IOUMessage, + Closed, + OriginalMessageActionName, + ChangeLog, + OriginalMessageIOU, + OriginalMessageCreated, + OriginalMessageAddComment, +}; diff --git a/src/types/utils/EmptyObject.ts b/src/types/utils/EmptyObject.ts index 9b9f3244a5f8..aa8b538499cd 100644 --- a/src/types/utils/EmptyObject.ts +++ b/src/types/utils/EmptyObject.ts @@ -2,12 +2,14 @@ import Falsy from './Falsy'; type EmptyObject = Record; +type EmptyValue = EmptyObject | null | undefined; + // eslint-disable-next-line rulesdir/no-negated-variables function isNotEmptyObject | Falsy>(arg: T | EmptyObject): arg is NonNullable { return Object.keys(arg ?? {}).length > 0; } -function isEmptyObject(obj: T): boolean { +function isEmptyObject(obj: T | EmptyValue): obj is EmptyValue { return Object.keys(obj ?? {}).length === 0; }