diff --git a/android/app/build.gradle b/android/app/build.gradle
index aaa6aaeb7a78..ddef060e3a96 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -96,8 +96,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1001042200
- versionName "1.4.22-0"
+ versionCode 1001042202
+ versionName "1.4.22-2"
}
flavorDimensions "default"
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index ecf3b8c9cad9..1c4a33d37b91 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -40,7 +40,7 @@
CFBundleVersion
- 1.4.22.0
+ 1.4.22.2
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 1ec1aeb6ce14..31fdafe32980 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -19,6 +19,6 @@
CFBundleSignature
????
CFBundleVersion
- 1.4.22.0
+ 1.4.22.2
diff --git a/package-lock.json b/package-lock.json
index 2c1da1670e19..065fc0055291 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.4.22-0",
+ "version": "1.4.22-2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.4.22-0",
+ "version": "1.4.22-2",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
diff --git a/package.json b/package.json
index 118f63e45879..f6d401a8266b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.4.22-0",
+ "version": "1.4.22-2",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js
index 25e1ce6f05ec..231a99f0e6a6 100644
--- a/src/components/AmountTextInput.js
+++ b/src/components/AmountTextInput.js
@@ -32,7 +32,7 @@ const propTypes = {
style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
/** Style for the container */
- containerStyles: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
+ touchableInputWrapperStyle: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
/** Function to call to handle key presses in the text input */
onKeyPress: PropTypes.func,
@@ -44,7 +44,7 @@ const defaultProps = {
onSelectionChange: () => {},
onKeyPress: () => {},
style: {},
- containerStyles: {},
+ touchableInputWrapperStyle: {},
};
function AmountTextInput(props) {
@@ -67,7 +67,7 @@ function AmountTextInput(props) {
onSelectionChange={props.onSelectionChange}
role={CONST.ROLE.PRESENTATION}
onKeyPress={props.onKeyPress}
- containerStyles={[...StyleUtils.parseStyleAsArray(props.containerStyles)]}
+ touchableInputWrapperStyle={props.touchableInputWrapperStyle}
/>
);
}
diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js
index d24d1e18907f..e5b605dd3ff2 100755
--- a/src/components/AttachmentModal.js
+++ b/src/components/AttachmentModal.js
@@ -19,7 +19,6 @@ import fileDownload from '@libs/fileDownload';
import * as FileUtils from '@libs/fileDownload/FileUtils';
import Navigation from '@libs/Navigation/Navigation';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
-import * as ReportUtils from '@libs/ReportUtils';
import * as TransactionUtils from '@libs/TransactionUtils';
import useNativeDriver from '@libs/useNativeDriver';
import reportPropTypes from '@pages/reportPropTypes';
@@ -95,6 +94,9 @@ const propTypes = {
/** Whether it is a receipt attachment or not */
isReceiptAttachment: PropTypes.bool,
+
+ /** Whether the receipt can be replaced */
+ canEditReceipt: PropTypes.bool,
};
const defaultProps = {
@@ -113,6 +115,7 @@ const defaultProps = {
onCarouselAttachmentChange: () => {},
isWorkspaceAvatar: false,
isReceiptAttachment: false,
+ canEditReceipt: false,
};
function AttachmentModal(props) {
@@ -372,13 +375,9 @@ function AttachmentModal(props) {
if (!props.isReceiptAttachment || !props.parentReport || !props.parentReportActions) {
return [];
}
- const menuItems = [];
- const parentReportAction = props.parentReportActions[props.report.parentReportActionID];
- const canEdit =
- ReportUtils.canEditFieldOfMoneyRequest(parentReportAction, props.parentReport.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT, props.transaction) &&
- !TransactionUtils.isDistanceRequest(props.transaction);
- if (canEdit) {
+ const menuItems = [];
+ if (props.canEditReceipt) {
menuItems.push({
icon: Expensicons.Camera,
text: props.translate('common.replace'),
@@ -393,7 +392,7 @@ function AttachmentModal(props) {
text: props.translate('common.download'),
onSelected: () => downloadAttachment(source),
});
- if (TransactionUtils.hasReceipt(props.transaction) && !TransactionUtils.isReceiptBeingScanned(props.transaction) && canEdit) {
+ if (TransactionUtils.hasReceipt(props.transaction) && !TransactionUtils.isReceiptBeingScanned(props.transaction) && props.canEditReceipt) {
menuItems.push({
icon: Expensicons.Trashcan,
text: props.translate('receipt.deleteReceipt'),
diff --git a/src/components/HeaderPageLayout.js b/src/components/HeaderPageLayout.tsx
similarity index 55%
rename from src/components/HeaderPageLayout.js
rename to src/components/HeaderPageLayout.tsx
index 9ef5d4f83a06..304bb2ce49b1 100644
--- a/src/components/HeaderPageLayout.js
+++ b/src/components/HeaderPageLayout.tsx
@@ -1,56 +1,54 @@
-import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
+import type {ReactNode} from 'react';
import {ScrollView, View} from 'react-native';
-import _ from 'underscore';
+import type {StyleProp, ViewStyle} from 'react-native';
import useNetwork from '@hooks/useNetwork';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import * as Browser from '@libs/Browser';
+import type ChildrenProps from '@src/types/utils/ChildrenProps';
import FixedFooter from './FixedFooter';
import HeaderWithBackButton from './HeaderWithBackButton';
-import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
+import type HeaderWithBackButtonProps from './HeaderWithBackButton/types';
import ScreenWrapper from './ScreenWrapper';
-const propTypes = {
- ...headerWithBackButtonPropTypes,
+type HeaderPageLayoutProps = ChildrenProps &
+ HeaderWithBackButtonProps & {
+ /** The background color to apply in the upper half of the screen. */
+ backgroundColor?: string;
- /** Children to display in the lower half of the page (below the header section w/ an animation) */
- children: PropTypes.node.isRequired,
+ /** A fixed footer to display at the bottom of the page. */
+ footer?: ReactNode;
- /** The background color to apply in the upper half of the screen. */
- backgroundColor: PropTypes.string,
+ /** The image to display in the upper half of the screen. */
+ headerContent?: ReactNode;
- /** A fixed footer to display at the bottom of the page. */
- footer: PropTypes.node,
+ /** Style to apply to the header image container */
+ headerContainerStyles?: StyleProp;
- /** The image to display in the upper half of the screen. */
- header: PropTypes.node,
+ /** Style to apply to the ScrollView container */
+ scrollViewContainerStyles?: StyleProp;
- /** Style to apply to the header image container */
- // eslint-disable-next-line react/forbid-prop-types
- headerContainerStyles: PropTypes.arrayOf(PropTypes.object),
+ /** Style to apply to the children container */
+ childrenContainerStyles?: StyleProp;
- /** Style to apply to the ScrollView container */
- // eslint-disable-next-line react/forbid-prop-types
- scrollViewContainerStyles: PropTypes.arrayOf(PropTypes.object),
+ /** Style to apply to the whole section container */
+ style?: StyleProp;
+ };
- /** Style to apply to the children container */
- // eslint-disable-next-line react/forbid-prop-types
- childrenContainerStyles: PropTypes.arrayOf(PropTypes.object),
-};
-
-const defaultProps = {
- backgroundColor: undefined,
- header: null,
- headerContainerStyles: [],
- scrollViewContainerStyles: [],
- childrenContainerStyles: [],
- footer: null,
-};
-
-function HeaderPageLayout({backgroundColor, children, footer, headerContainerStyles, scrollViewContainerStyles, childrenContainerStyles, style, headerContent, ...propsToPassToHeader}) {
+function HeaderPageLayout({
+ backgroundColor,
+ children,
+ footer,
+ headerContainerStyles,
+ scrollViewContainerStyles,
+ childrenContainerStyles,
+ style,
+ headerContent,
+ ...rest
+}: HeaderPageLayoutProps) {
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
@@ -58,7 +56,7 @@ function HeaderPageLayout({backgroundColor, children, footer, headerContainerSty
const {isOffline} = useNetwork();
const appBGColor = StyleUtils.getBackgroundColorStyle(theme.appBG);
const {titleColor, iconFill} = useMemo(() => {
- const isColorfulBackground = (backgroundColor || theme.appBG) !== theme.appBG && (backgroundColor || theme.highlightBG) !== theme.highlightBG;
+ const isColorfulBackground = (backgroundColor ?? theme.appBG) !== theme.appBG && (backgroundColor ?? theme.highlightBG) !== theme.highlightBG;
return {
titleColor: isColorfulBackground ? theme.textColorfulBackground : undefined,
iconFill: isColorfulBackground ? theme.iconColorfulBackground : undefined,
@@ -67,7 +65,7 @@ function HeaderPageLayout({backgroundColor, children, footer, headerContainerSty
return (
-
+
{/** Safari on ios/mac has a bug where overscrolling the page scrollview shows green background color. This is a workaround to fix that. https://github.com/Expensify/App/issues/23422 */}
{Browser.isSafari() && (
-
+
)}
-
- {!Browser.isSafari() && }
-
+
+ {!Browser.isSafari() && }
+
{headerContent}
{children}
- {!_.isNull(footer) && {footer}}
+ {!!footer && {footer}}
>
)}
@@ -107,8 +102,7 @@ function HeaderPageLayout({backgroundColor, children, footer, headerContainerSty
);
}
-HeaderPageLayout.propTypes = propTypes;
-HeaderPageLayout.defaultProps = defaultProps;
HeaderPageLayout.displayName = 'HeaderPageLayout';
+export type {HeaderPageLayoutProps};
export default HeaderPageLayout;
diff --git a/src/components/HoldMenuSectionList.tsx b/src/components/HoldMenuSectionList.tsx
index 9a9857f037f2..aa5dd75ce159 100644
--- a/src/components/HoldMenuSectionList.tsx
+++ b/src/components/HoldMenuSectionList.tsx
@@ -1,10 +1,11 @@
import React from 'react';
-import {ImageSourcePropType, View} from 'react-native';
-import {SvgProps} from 'react-native-svg';
+import {View} from 'react-native';
+import type {ImageSourcePropType} from 'react-native';
+import type {SvgProps} from 'react-native-svg';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import variables from '@styles/variables';
-import {TranslationPaths} from '@src/languages/types';
+import type {TranslationPaths} from '@src/languages/types';
import Icon from './Icon';
import * as Illustrations from './Icon/Illustrations';
import Text from './Text';
diff --git a/src/components/IllustratedHeaderPageLayout.js b/src/components/IllustratedHeaderPageLayout.js
deleted file mode 100644
index 9980d8a7879a..000000000000
--- a/src/components/IllustratedHeaderPageLayout.js
+++ /dev/null
@@ -1,67 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import useTheme from '@hooks/useTheme';
-import useThemeStyles from '@hooks/useThemeStyles';
-import HeaderPageLayout from './HeaderPageLayout';
-import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
-import Lottie from './Lottie';
-
-const propTypes = {
- ...headerWithBackButtonPropTypes,
-
- /** Children to display in the lower half of the page (below the header section w/ an animation) */
- children: PropTypes.node.isRequired,
-
- /** The illustration to display in the header. Can be either an SVG component or a JSON object representing a Lottie animation. */
- illustration: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
-
- /** The background color to apply in the upper half of the screen. */
- backgroundColor: PropTypes.string,
-
- /** A fixed footer to display at the bottom of the page. */
- footer: PropTypes.node,
-
- /** Overlay content to display on top of animation */
- overlayContent: PropTypes.func,
-};
-
-const defaultProps = {
- backgroundColor: undefined,
- footer: null,
- overlayContent: null,
-};
-
-function IllustratedHeaderPageLayout({backgroundColor, children, illustration, footer, overlayContent, ...propsToPassToHeader}) {
- const theme = useTheme();
- const styles = useThemeStyles();
- return (
-
-
- {overlayContent && overlayContent()}
- >
- }
- headerContainerStyles={[styles.justifyContentCenter, styles.w100]}
- footer={footer}
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...propsToPassToHeader}
- >
- {children}
-
- );
-}
-
-IllustratedHeaderPageLayout.propTypes = propTypes;
-IllustratedHeaderPageLayout.defaultProps = defaultProps;
-IllustratedHeaderPageLayout.displayName = 'IllustratedHeaderPageLayout';
-
-export default IllustratedHeaderPageLayout;
diff --git a/src/components/IllustratedHeaderPageLayout.tsx b/src/components/IllustratedHeaderPageLayout.tsx
new file mode 100644
index 000000000000..72ec0adf7672
--- /dev/null
+++ b/src/components/IllustratedHeaderPageLayout.tsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import type {ReactNode} from 'react';
+import useTheme from '@hooks/useTheme';
+import useThemeStyles from '@hooks/useThemeStyles';
+import HeaderPageLayout from './HeaderPageLayout';
+import type {HeaderPageLayoutProps} from './HeaderPageLayout';
+import Lottie from './Lottie';
+import type DotLottieAnimation from './LottieAnimations/types';
+
+type IllustratedHeaderPageLayoutProps = HeaderPageLayoutProps & {
+ /** The illustration to display in the header. Can be a JSON object representing a Lottie animation. */
+ illustration: DotLottieAnimation;
+
+ /** The background color to apply in the upper half of the screen. */
+ backgroundColor?: string;
+
+ /** Overlay content to display on top of animation */
+ overlayContent?: () => ReactNode;
+};
+
+function IllustratedHeaderPageLayout({backgroundColor, children, illustration, overlayContent, ...rest}: IllustratedHeaderPageLayoutProps) {
+ const theme = useTheme();
+ const styles = useThemeStyles();
+ return (
+
+
+ {overlayContent?.()}
+ >
+ }
+ headerContainerStyles={[styles.justifyContentCenter, styles.w100]}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...rest}
+ >
+ {children}
+
+ );
+}
+
+IllustratedHeaderPageLayout.displayName = 'IllustratedHeaderPageLayout';
+
+export default IllustratedHeaderPageLayout;
diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx
index 34d60418d3ab..86e77ae4bfc3 100644
--- a/src/components/MenuItem.tsx
+++ b/src/components/MenuItem.tsx
@@ -35,20 +35,6 @@ import RenderHTML from './RenderHTML';
import SelectCircle from './SelectCircle';
import Text from './Text';
-type ResponsiveProps = {
- /** Function to fire when component is pressed */
- onPress: (event: GestureResponderEvent | KeyboardEvent) => void;
-
- interactive?: true;
-};
-
-type UnresponsiveProps = {
- onPress?: undefined;
-
- /** Whether the menu item should be interactive at all */
- interactive: false;
-};
-
type IconProps = {
/** Flag to choose between avatar image or an icon */
iconType?: typeof CONST.ICON_TYPE_ICON;
@@ -69,170 +55,175 @@ type NoIcon = {
icon?: undefined;
};
-type MenuItemProps = (ResponsiveProps | UnresponsiveProps) &
- (IconProps | AvatarProps | NoIcon) & {
- /** Text to be shown as badge near the right end. */
- badgeText?: string;
+type MenuItemProps = (IconProps | AvatarProps | NoIcon) & {
+ /** Function to fire when component is pressed */
+ onPress?: (event: GestureResponderEvent | KeyboardEvent) => void;
- /** Used to apply offline styles to child text components */
- style?: ViewStyle;
+ /** Whether the menu item should be interactive at all */
+ interactive?: boolean;
- /** Any additional styles to apply */
- wrapperStyle?: StyleProp;
+ /** Text to be shown as badge near the right end. */
+ badgeText?: string;
- /** Any additional styles to apply on the outer element */
- containerStyle?: StyleProp;
+ /** Used to apply offline styles to child text components */
+ style?: ViewStyle;
- /** Used to apply styles specifically to the title */
- titleStyle?: ViewStyle;
+ /** Any additional styles to apply */
+ wrapperStyle?: StyleProp;
- /** Any adjustments to style when menu item is hovered or pressed */
- hoverAndPressStyle?: StyleProp>;
+ /** Any additional styles to apply on the outer element */
+ containerStyle?: StyleProp;
- /** Additional styles to style the description text below the title */
- descriptionTextStyle?: StyleProp;
+ /** Used to apply styles specifically to the title */
+ titleStyle?: ViewStyle;
- /** The fill color to pass into the icon. */
- iconFill?: string;
+ /** Any adjustments to style when menu item is hovered or pressed */
+ hoverAndPressStyle?: StyleProp>;
- /** Secondary icon to display on the left side of component, right of the icon */
- secondaryIcon?: IconAsset;
+ /** Additional styles to style the description text below the title */
+ descriptionTextStyle?: StyleProp;
- /** The fill color to pass into the secondary icon. */
- secondaryIconFill?: string;
+ /** The fill color to pass into the icon. */
+ iconFill?: string;
- /** Icon Width */
- iconWidth?: number;
+ /** Secondary icon to display on the left side of component, right of the icon */
+ secondaryIcon?: IconAsset;
- /** Icon Height */
- iconHeight?: number;
+ /** The fill color to pass into the secondary icon. */
+ secondaryIconFill?: string;
- /** Any additional styles to pass to the icon container. */
- iconStyles?: StyleProp;
+ /** Icon Width */
+ iconWidth?: number;
- /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
- fallbackIcon?: IconAsset;
+ /** Icon Height */
+ iconHeight?: number;
- /** An icon to display under the main item */
- furtherDetailsIcon?: IconAsset;
+ /** Any additional styles to pass to the icon container. */
+ iconStyles?: StyleProp;
- /** Boolean whether to display the title right icon */
- shouldShowTitleIcon?: boolean;
+ /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */
+ fallbackIcon?: IconAsset;
- /** Icon to display at right side of title */
- titleIcon?: IconAsset;
+ /** An icon to display under the main item */
+ furtherDetailsIcon?: IconAsset;
- /** Boolean whether to display the right icon */
- shouldShowRightIcon?: boolean;
+ /** Boolean whether to display the title right icon */
+ shouldShowTitleIcon?: boolean;
- /** Overrides the icon for shouldShowRightIcon */
- iconRight?: IconAsset;
+ /** Icon to display at right side of title */
+ titleIcon?: IconAsset;
- /** Should render component on the right */
- shouldShowRightComponent?: boolean;
+ /** Boolean whether to display the right icon */
+ shouldShowRightIcon?: boolean;
- /** Component to be displayed on the right */
- rightComponent?: ReactNode;
+ /** Overrides the icon for shouldShowRightIcon */
+ iconRight?: IconAsset;
- /** A description text to show under the title */
- description?: string;
+ /** Should render component on the right */
+ shouldShowRightComponent?: boolean;
- /** Should the description be shown above the title (instead of the other way around) */
- shouldShowDescriptionOnTop?: boolean;
+ /** Component to be displayed on the right */
+ rightComponent?: ReactNode;
- /** Error to display below the title */
- error?: string;
+ /** A description text to show under the title */
+ description?: string;
- /** Error to display at the bottom of the component */
- errorText?: string;
+ /** Should the description be shown above the title (instead of the other way around) */
+ shouldShowDescriptionOnTop?: boolean;
- /** A boolean flag that gives the icon a green fill if true */
- success?: boolean;
+ /** Error to display below the title */
+ error?: string;
- /** Whether item is focused or active */
- focused?: boolean;
+ /** Error to display at the bottom of the component */
+ errorText?: string;
- /** Should we disable this menu item? */
- disabled?: boolean;
+ /** A boolean flag that gives the icon a green fill if true */
+ success?: boolean;
- /** Text that appears above the title */
- label?: string;
+ /** Whether item is focused or active */
+ focused?: boolean;
- /** Label to be displayed on the right */
- rightLabel?: string;
+ /** Should we disable this menu item? */
+ disabled?: boolean;
- /** Text to display for the item */
- title?: string;
+ /** Text that appears above the title */
+ label?: string;
- /** A right-aligned subtitle for this menu option */
- subtitle?: string | number;
+ /** Label to be displayed on the right */
+ rightLabel?: string;
- /** Should the title show with normal font weight (not bold) */
- shouldShowBasicTitle?: boolean;
+ /** Text to display for the item */
+ title?: string;
- /** Should we make this selectable with a checkbox */
- shouldShowSelectedState?: boolean;
+ /** A right-aligned subtitle for this menu option */
+ subtitle?: string | number;
- /** Whether this item is selected */
- isSelected?: boolean;
+ /** Should the title show with normal font weight (not bold) */
+ shouldShowBasicTitle?: boolean;
- /** Prop to identify if we should load avatars vertically instead of diagonally */
- shouldStackHorizontally?: boolean;
+ /** Should we make this selectable with a checkbox */
+ shouldShowSelectedState?: boolean;
- /** Prop to represent the size of the avatar images to be shown */
- avatarSize?: (typeof CONST.AVATAR_SIZE)[keyof typeof CONST.AVATAR_SIZE];
+ /** Whether this item is selected */
+ isSelected?: boolean;
- /** Avatars to show on the right of the menu item */
- floatRightAvatars?: IconType[];
+ /** Prop to identify if we should load avatars vertically instead of diagonally */
+ shouldStackHorizontally?: boolean;
- /** Prop to represent the size of the float right avatar images to be shown */
- floatRightAvatarSize?: ValueOf;
+ /** Prop to represent the size of the avatar images to be shown */
+ avatarSize?: (typeof CONST.AVATAR_SIZE)[keyof typeof CONST.AVATAR_SIZE];
- /** Affects avatar size */
- viewMode?: ValueOf;
+ /** Avatars to show on the right of the menu item */
+ floatRightAvatars?: IconType[];
- /** Used to truncate the text with an ellipsis after computing the text layout */
- numberOfLinesTitle?: number;
+ /** Prop to represent the size of the float right avatar images to be shown */
+ floatRightAvatarSize?: ValueOf;
- /** Whether we should use small avatar subscript sizing the for menu item */
- isSmallAvatarSubscriptMenu?: boolean;
+ /** Affects avatar size */
+ viewMode?: ValueOf;
- /** The type of brick road indicator to show. */
- brickRoadIndicator?: ValueOf;
+ /** Used to truncate the text with an ellipsis after computing the text layout */
+ numberOfLinesTitle?: number;
- /** Should render the content in HTML format */
- shouldRenderAsHTML?: boolean;
+ /** Whether we should use small avatar subscript sizing the for menu item */
+ isSmallAvatarSubscriptMenu?: boolean;
- /** Should we grey out the menu item when it is disabled? */
- shouldGreyOutWhenDisabled?: boolean;
+ /** The type of brick road indicator to show. */
+ brickRoadIndicator?: ValueOf;
- /** The action accept for anonymous user or not */
- isAnonymousAction?: boolean;
+ /** Should render the content in HTML format */
+ shouldRenderAsHTML?: boolean;
- /** Flag to indicate whether or not text selection should be disabled from long-pressing the menu item. */
- shouldBlockSelection?: boolean;
+ /** Should we grey out the menu item when it is disabled? */
+ shouldGreyOutWhenDisabled?: boolean;
- /** Whether should render title as HTML or as Text */
- shouldParseTitle?: false;
+ /** The action accept for anonymous user or not */
+ isAnonymousAction?: boolean;
- /** Should check anonymous user in onPress function */
- shouldCheckActionAllowedOnPress?: boolean;
+ /** Flag to indicate whether or not text selection should be disabled from long-pressing the menu item. */
+ shouldBlockSelection?: boolean;
- /** Text to display under the main item */
- furtherDetails?: string;
+ /** Whether should render title as HTML or as Text */
+ shouldParseTitle?: false;
- /** The function that should be called when this component is LongPressed or right-clicked. */
- onSecondaryInteraction?: () => void;
+ /** Should check anonymous user in onPress function */
+ shouldCheckActionAllowedOnPress?: boolean;
- /** Array of objects that map display names to their corresponding tooltip */
- titleWithTooltips?: DisplayNameWithTooltip[];
+ /** Text to display under the main item */
+ furtherDetails?: string;
- /** Icon should be displayed in its own color */
- displayInDefaultIconColor?: boolean;
+ /** The function that should be called when this component is LongPressed or right-clicked. */
+ onSecondaryInteraction?: (event: GestureResponderEvent | MouseEvent) => void;
- /** Determines how the icon should be resized to fit its container */
- contentFit?: ImageContentFit;
- };
+ /** Array of objects that map display names to their corresponding tooltip */
+ titleWithTooltips?: DisplayNameWithTooltip[];
+
+ /** Icon should be displayed in its own color */
+ displayInDefaultIconColor?: boolean;
+
+ /** Determines how the icon should be resized to fit its container */
+ contentFit?: ImageContentFit;
+};
function MenuItem(
{
diff --git a/src/components/MenuItemList.js b/src/components/MenuItemList.js
deleted file mode 100644
index c9eee8e888e1..000000000000
--- a/src/components/MenuItemList.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import _ from 'underscore';
-import useSingleExecution from '@hooks/useSingleExecution';
-import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu';
-import CONST from '@src/CONST';
-import MenuItem from './MenuItem';
-import menuItemPropTypes from './menuItemPropTypes';
-
-const propTypes = {
- /** An array of props that are pass to individual MenuItem components */
- menuItems: PropTypes.arrayOf(PropTypes.shape(menuItemPropTypes)),
-
- /** Whether or not to use the single execution hook */
- shouldUseSingleExecution: PropTypes.bool,
-};
-const defaultProps = {
- menuItems: [],
- shouldUseSingleExecution: false,
-};
-
-function MenuItemList(props) {
- let popoverAnchor;
- const {isExecuting, singleExecution} = useSingleExecution();
-
- /**
- * Handle the secondary interaction for a menu item.
- *
- * @param {*} link the menu item link or function to get the link
- * @param {Event} e the interaction event
- */
- const secondaryInteraction = (link, e) => {
- if (typeof link === 'function') {
- link().then((url) => ReportActionContextMenu.showContextMenu(CONST.CONTEXT_MENU_TYPES.LINK, e, url, popoverAnchor));
- } else if (!_.isEmpty(link)) {
- ReportActionContextMenu.showContextMenu(CONST.CONTEXT_MENU_TYPES.LINK, e, link, popoverAnchor);
- }
- };
-
- return (
- <>
- {_.map(props.menuItems, (menuItemProps) => (
-