Skip to content

Commit

Permalink
Merge pull request Expensify#32730 from VickyStash/ts-migration/repor…
Browse files Browse the repository at this point in the history
…tActionItemMessage-component

[TS migration] Migrate 'ReportActionItemMessage.js' component to TypeScript
  • Loading branch information
Gonals authored Dec 20, 2023
2 parents 84d6278 + aeabb56 commit bd852c5
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 53 deletions.
2 changes: 1 addition & 1 deletion src/libs/ReportUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1938,7 +1938,7 @@ function getTransactionReportName(reportAction: OnyxEntry<ReportAction>): string
* @param [reportAction] This can be either a report preview action or the IOU action
*/
function getReportPreviewMessage(
report: OnyxEntry<Report>,
report: OnyxEntry<Report> | EmptyObject,
reportAction: OnyxEntry<ReportAction> | EmptyObject = {},
shouldConsiderReceiptBeingScanned = false,
isPreviewMessageForParentChatReport = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -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<ViewStyle>;

/** 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 (
<TextCommentFragment
fragment={fragment}
displayAsGroup={props.displayAsGroup}
style={props.style}
displayAsGroup={displayAsGroup}
style={style}
source=""
styleAsDeleted={false}
/>
);
}

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) => (
<ReportActionItemFragment
key={`actionFragment-${props.action.reportActionID}-${index}`}
/* eslint-disable-next-line react/no-array-index-key */
key={`actionFragment-${action.reportActionID}-${index}`}
fragment={fragment}
iouMessage={iouMessage}
isThreadParentMessage={ReportActionsUtils.isThreadParentMessage(props.action, props.reportID)}
attachmentInfo={props.action.attachmentInfo}
pendingAction={props.action.pendingAction}
source={lodashGet(props.action, 'originalMessage.source')}
accountID={props.action.actorAccountID}
style={props.style}
displayAsGroup={props.displayAsGroup}
isThreadParentMessage={ReportActionsUtils.isThreadParentMessage(action, reportID)}
attachmentInfo={action.attachmentInfo}
pendingAction={action.pendingAction}
source={(action.originalMessage as OriginalMessageAddComment['originalMessage'])?.source}
accountID={action.actorAccountID}
style={style}
displayAsGroup={displayAsGroup}
isApprovedOrSubmittedReportAction={isApprovedOrSubmittedReportAction}
// Since system messages from Old Dot begin with the person who performed the action,
// the first fragment will contain the person's display name and their email. We'll use this
Expand All @@ -99,18 +94,16 @@ function ReportActionItemMessage(props) {
};

return (
<View style={[styles.chatItemMessage, ...props.style]}>
{!props.isHidden ? (
<View style={[styles.chatItemMessage, style]}>
{!isHidden ? (
renderReportActionItemFragments(isApprovedOrSubmittedReportAction)
) : (
<Text style={[styles.textLabelSupporting, styles.lh20]}>{props.translate('moderation.flaggedContent')}</Text>
<Text style={[styles.textLabelSupporting, styles.lh20]}>{translate('moderation.flaggedContent')}</Text>
)}
</View>
);
}

ReportActionItemMessage.propTypes = propTypes;
ReportActionItemMessage.defaultProps = defaultProps;
ReportActionItemMessage.displayName = 'ReportActionItemMessage';

export default withLocalize(ReportActionItemMessage);
export default ReportActionItemMessage;
16 changes: 15 additions & 1 deletion src/types/onyx/OriginalMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -95,6 +96,7 @@ type OriginalMessageAddComment = {
actionName: typeof CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT;
originalMessage: {
html: string;
source?: OriginalMessageSource;
lastModified?: string;
taskReportID?: string;
edits?: string[];
Expand Down Expand Up @@ -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,
};
4 changes: 3 additions & 1 deletion src/types/utils/EmptyObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import Falsy from './Falsy';

type EmptyObject = Record<string, never>;

type EmptyValue = EmptyObject | null | undefined;

// eslint-disable-next-line rulesdir/no-negated-variables
function isNotEmptyObject<T extends Record<string, unknown> | Falsy>(arg: T | EmptyObject): arg is NonNullable<T> {
return Object.keys(arg ?? {}).length > 0;
}

function isEmptyObject<T>(obj: T): boolean {
function isEmptyObject<T>(obj: T | EmptyValue): obj is EmptyValue {
return Object.keys(obj ?? {}).length === 0;
}

Expand Down

0 comments on commit bd852c5

Please sign in to comment.