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

[TS migration] Migrate 'ReportActionItemMoneyRequest' component to TypeScript #34564

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a56bce1
Migrate MoneyRequestAction to TypeScript
VickyStash Jan 15, 2024
0f627ba
Migrate MoneyRequestPreview to TypeScript
VickyStash Jan 16, 2024
02296e8
Migrate MoneyRequestView to TypeScript
VickyStash Jan 16, 2024
6b8c3a3
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 16, 2024
03a0c4c
Fix lint errors
VickyStash Jan 16, 2024
7a64f0c
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 16, 2024
6c8137a
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 17, 2024
6637583
Use ContextMenuAnchor type for anchor typing
VickyStash Jan 17, 2024
e1e39e1
Code improvements
VickyStash Jan 17, 2024
ccef5e0
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 18, 2024
fb3f8d1
Update getDisplayDeleteAmountText function, move transactionViolation…
VickyStash Jan 18, 2024
60d8105
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 19, 2024
69a4df4
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 22, 2024
be37558
TS fixes after merging main
VickyStash Jan 22, 2024
c8438bf
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 23, 2024
01fa104
Fix TS issues
VickyStash Jan 23, 2024
f65fbe0
Update image typing
VickyStash Jan 23, 2024
73e5685
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 25, 2024
696f337
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 26, 2024
c07a39e
TS fixes after merging OptionsListUtils migration
VickyStash Jan 26, 2024
a5f3dba
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 26, 2024
eb4631e
TS fixes after merging main
VickyStash Jan 26, 2024
8b9bac8
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 29, 2024
00c5436
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 30, 2024
15cffe2
Fix Onyx types import
VickyStash Jan 30, 2024
dedfe12
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Jan 31, 2024
e7ff217
Fix TS issues after merging main
VickyStash Jan 31, 2024
5e1e232
Merge branch 'main' into ts-migration/reportActionItemMoneyRequest-co…
VickyStash Feb 2, 2024
d3f64c9
Retry performance test
VickyStash Feb 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,7 @@ type OnyxValues = {
[ONYXKEYS.COLLECTION.DOWNLOAD]: OnyxTypes.Download;
[ONYXKEYS.COLLECTION.POLICY]: OnyxTypes.Policy;
[ONYXKEYS.COLLECTION.POLICY_DRAFTS]: OnyxTypes.Policy;
[ONYXKEYS.COLLECTION.POLICY_CATEGORIES]: OnyxTypes.PolicyCategory;
[ONYXKEYS.COLLECTION.POLICY_CATEGORIES]: OnyxTypes.PolicyCategories;
[ONYXKEYS.COLLECTION.POLICY_TAGS]: OnyxTypes.PolicyTags;
[ONYXKEYS.COLLECTION.POLICY_MEMBERS]: OnyxTypes.PolicyMembers;
[ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS]: OnyxTypes.PolicyMember;
Expand All @@ -479,6 +479,7 @@ type OnyxValues = {
[ONYXKEYS.COLLECTION.SECURITY_GROUP]: OnyxTypes.SecurityGroup;
[ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction;
[ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.Transaction;
[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolations;
[ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags;
[ONYXKEYS.COLLECTION.SELECTED_TAB]: string;
[ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolation[];
Expand Down
5 changes: 2 additions & 3 deletions src/components/DotIndicatorMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,12 @@ import useThemeStyles from '@hooks/useThemeStyles';
import fileDownload from '@libs/fileDownload';
import * as Localize from '@libs/Localize';
import CONST from '@src/CONST';
import type {ReceiptError} from '@src/types/onyx/Transaction';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import {PressableWithoutFeedback} from './Pressable';
import Text from './Text';

type ReceiptError = {error?: string; source: string; filename: string};

type DotIndicatorMessageProps = {
/**
* In most cases this should just be errors from onxyData
Expand All @@ -23,7 +22,7 @@ type DotIndicatorMessageProps = {
* timestamp: 'message',
* }
*/
messages: Record<string, Localize.MaybePhraseKey>;
messages: Record<string, Localize.MaybePhraseKey | ReceiptError>;

/** The type of message, 'error' shows a red dot, 'success' shows a green dot */
type: 'error' | 'success';
Expand Down
3 changes: 2 additions & 1 deletion src/components/MessagesRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import type * as Localize from '@libs/Localize';
import CONST from '@src/CONST';
import type {ReceiptError} from '@src/types/onyx/Transaction';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import DotIndicatorMessage from './DotIndicatorMessage';
import Icon from './Icon';
Expand All @@ -15,7 +16,7 @@ import Tooltip from './Tooltip';

type MessagesRowProps = {
/** The messages to display */
messages: Record<string, Localize.MaybePhraseKey>;
messages: Record<string, Localize.MaybePhraseKey | ReceiptError>;

/** The type of message, 'error' shows a red dot, 'success' shows a green dot */
type: 'error' | 'success';
Expand Down
5 changes: 3 additions & 2 deletions src/components/OfflineWithFeedback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import mapChildrenFlat from '@libs/mapChildrenFlat';
import shouldRenderOffscreen from '@libs/shouldRenderOffscreen';
import CONST from '@src/CONST';
import type * as OnyxCommon from '@src/types/onyx/OnyxCommon';
import type {ReceiptError, ReceiptErrors} from '@src/types/onyx/Transaction';
import type ChildrenProps from '@src/types/utils/ChildrenProps';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import MessagesRow from './MessagesRow';
Expand All @@ -26,7 +27,7 @@ type OfflineWithFeedbackProps = ChildrenProps & {
shouldHideOnDelete?: boolean;

/** The errors to display */
errors?: OnyxCommon.Errors | null;
errors?: OnyxCommon.Errors | ReceiptErrors | null;

/** Whether we should show the error messages */
shouldShowErrorMessages?: boolean;
Expand Down Expand Up @@ -84,7 +85,7 @@ function OfflineWithFeedback({

const hasErrors = !isEmptyObject(errors ?? {});
// Some errors have a null message. This is used to apply opacity only and to avoid showing redundant messages.
const errorMessages = omitBy(errors, (e) => e === null);
const errorMessages = omitBy(errors, (e: string | ReceiptError) => e === null);
const hasErrorMessages = !isEmptyObject(errorMessages);
const isOfflinePendingAction = !!isOffline && !!pendingAction;
const isUpdateOrDeleteError = hasErrors && (pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,83 +1,66 @@
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React from 'react';
import type {StyleProp, ViewStyle} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import networkPropTypes from '@components/networkPropTypes';
import {withNetwork} from '@components/OnyxProvider';
import refPropTypes from '@components/refPropTypes';
import type {OnyxEntry} from 'react-native-onyx';
import RenderHTML from '@components/RenderHTML';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useThemeStyles from '@hooks/useThemeStyles';
import compose from '@libs/compose';
import * as IOUUtils from '@libs/IOUUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import * as ReportUtils from '@libs/ReportUtils';
import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
import iouReportPropTypes from '@pages/iouReportPropTypes';
import reportPropTypes from '@pages/reportPropTypes';
import type {ContextMenuAnchor} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
import * as Report from '@userActions/Report';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type * as OnyxTypes from '@src/types/onyx';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import MoneyRequestPreview from './MoneyRequestPreview';

const propTypes = {
type MoneyRequestActionOnyxProps = {
/** Chat report associated with iouReport */
chatReport: OnyxEntry<OnyxTypes.Report>;

/** IOU report data object */
iouReport: OnyxEntry<OnyxTypes.Report>;

/** Report actions for this report */
reportActions: OnyxEntry<OnyxTypes.ReportActions>;
};

type MoneyRequestActionProps = MoneyRequestActionOnyxProps & {
/** All the data of the action */
action: PropTypes.shape(reportActionPropTypes).isRequired,
action: OnyxTypes.ReportAction;

/** The ID of the associated chatReport */
chatReportID: PropTypes.string.isRequired,
chatReportID: string;

/** The ID of the associated request report */
requestReportID: PropTypes.string.isRequired,
requestReportID: string;

/** The ID of the current report */
reportID: PropTypes.string.isRequired,
reportID: string;

/** Is this IOUACTION the most recent? */
isMostRecentIOUReportAction: PropTypes.bool.isRequired,
isMostRecentIOUReportAction: boolean;

/** Popover context menu anchor, used for showing context menu */
contextMenuAnchor: refPropTypes,
contextMenuAnchor?: ContextMenuAnchor;

/** Callback for updating context menu active state, used for showing context menu */
checkIfContextMenuActive: PropTypes.func,

/* Onyx Props */
/** chatReport associated with iouReport */
chatReport: reportPropTypes,

/** IOU report data object */
iouReport: iouReportPropTypes,

/** Array of report actions for this report */
reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)),
checkIfContextMenuActive?: () => void;

/** Whether the IOU is hovered so we can modify its style */
isHovered: PropTypes.bool,

network: networkPropTypes.isRequired,
isHovered?: boolean;

/** Whether a message is a whisper */
isWhisper: PropTypes.bool,
isWhisper?: boolean;

/** Styles to be assigned to Container */
// eslint-disable-next-line react/forbid-prop-types
style: PropTypes.arrayOf(PropTypes.object),
};

const defaultProps = {
contextMenuAnchor: undefined,
checkIfContextMenuActive: () => {},
chatReport: {},
iouReport: {},
reportActions: {},
isHovered: false,
style: [],
isWhisper: false,
style?: StyleProp<ViewStyle>;
};

function MoneyRequestAction({
Expand All @@ -87,31 +70,32 @@ function MoneyRequestAction({
reportID,
isMostRecentIOUReportAction,
contextMenuAnchor,
checkIfContextMenuActive,
checkIfContextMenuActive = () => {},
chatReport,
iouReport,
reportActions,
isHovered,
network,
isHovered = false,
style,
isWhisper,
}) {
isWhisper = false,
}: MoneyRequestActionProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const isSplitBillAction = lodashGet(action, 'originalMessage.type', '') === CONST.IOU.REPORT_ACTION_TYPE.SPLIT;
const {isOffline} = useNetwork();

const isSplitBillAction = action.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && action.originalMessage.type === CONST.IOU.REPORT_ACTION_TYPE.SPLIT;

const onMoneyRequestPreviewPressed = () => {
if (isSplitBillAction) {
const reportActionID = lodashGet(action, 'reportActionID', '0');
const reportActionID = action.reportActionID ?? '0';
Navigation.navigate(ROUTES.SPLIT_BILL_DETAILS.getRoute(chatReportID, reportActionID));
return;
}

// If the childReportID is not present, we need to create a new thread
const childReportID = lodashGet(action, 'childReportID', 0);
const childReportID = action?.childReportID ?? '0';
Copy link
Contributor

@youssef-lr youssef-lr Feb 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@VickyStash heads up! All IDs must be numbers, this created this bug #35904. :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

accountIDs are numbers and reportIDs are strings, right? 🤔

Copy link
Contributor

@aldo-expensify aldo-expensify Feb 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@youssef-lr reportIDs are expected to be string, otherwise they can overflow, right?
Unless this changed lately

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah sorry my bad, they are all numbers in the backend, but in JS reportIDs & reportActionIDs are strings. In this specific example it doesn't make sense to use '0', because the condition below this line evaluates to false when it should evaluate to true if (!childReportID) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@youssef-lr you are right, my bad!

Copy link
Contributor

@aldo-expensify aldo-expensify Feb 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented in your PR @youssef-lr , I don't think we should default to 0 either

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that sounds good, updated.

if (!childReportID) {
const thread = ReportUtils.buildTransactionThread(action, requestReportID);
const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(thread.participantAccountIDs);
const userLogins = PersonalDetailsUtils.getLoginsByAccountIDs(thread.participantAccountIDs ?? []);
Report.openReport(thread.reportID, userLogins, thread, action.reportActionID);
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(thread.reportID));
return;
Expand All @@ -124,12 +108,12 @@ function MoneyRequestAction({
const isDeletedParentAction = ReportActionsUtils.isDeletedParentAction(action);
const isReversedTransaction = ReportActionsUtils.isReversedTransaction(action);
if (
!_.isEmpty(iouReport) &&
!_.isEmpty(reportActions) &&
chatReport.iouReportID &&
!isEmptyObject(iouReport) &&
!isEmptyObject(reportActions) &&
chatReport?.iouReportID &&
isMostRecentIOUReportAction &&
action.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD &&
network.isOffline
isOffline
) {
shouldShowPendingConversionMessage = IOUUtils.isIOUReportPendingCurrencyConversion(iouReport);
}
Expand All @@ -147,29 +131,24 @@ function MoneyRequestAction({
checkIfContextMenuActive={checkIfContextMenuActive}
shouldShowPendingConversionMessage={shouldShowPendingConversionMessage}
onPreviewPressed={onMoneyRequestPreviewPressed}
containerStyles={[styles.cursorPointer, isHovered ? styles.reportPreviewBoxHoverBorder : undefined, ...style]}
containerStyles={[styles.cursorPointer, isHovered ? styles.reportPreviewBoxHoverBorder : undefined, style]}
isHovered={isHovered}
isWhisper={isWhisper}
/>
);
}

MoneyRequestAction.propTypes = propTypes;
MoneyRequestAction.defaultProps = defaultProps;
MoneyRequestAction.displayName = 'MoneyRequestAction';

export default compose(
withOnyx({
chatReport: {
key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`,
},
iouReport: {
key: ({requestReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`,
},
reportActions: {
key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`,
canEvict: false,
},
}),
withNetwork(),
)(MoneyRequestAction);
export default withOnyx<MoneyRequestActionProps, MoneyRequestActionOnyxProps>({
chatReport: {
key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`,
},
iouReport: {
key: ({requestReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${requestReportID}`,
},
reportActions: {
key: ({chatReportID}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReportID}`,
canEvict: false,
},
})(MoneyRequestAction);
Loading
Loading