diff --git a/src/CONST.ts b/src/CONST.ts index cec7cbc0b8a5..0c98645511d4 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -512,6 +512,7 @@ const CONST = { CLOSED: 'CLOSED', CREATED: 'CREATED', IOU: 'IOU', + MARKEDREIMBURSED: 'MARKEDREIMBURSED', MODIFIEDEXPENSE: 'MODIFIEDEXPENSE', MOVED: 'MOVED', REIMBURSEMENTQUEUED: 'REIMBURSEMENTQUEUED', diff --git a/src/NAVIGATORS.ts b/src/NAVIGATORS.ts index a3a041e65684..c68a950d3501 100644 --- a/src/NAVIGATORS.ts +++ b/src/NAVIGATORS.ts @@ -4,6 +4,7 @@ * */ export default { CENTRAL_PANE_NAVIGATOR: 'CentralPaneNavigator', + LEFT_MODAL_NAVIGATOR: 'LeftModalNavigator', RIGHT_MODAL_NAVIGATOR: 'RightModalNavigator', FULL_SCREEN_NAVIGATOR: 'FullScreenNavigator', } as const; diff --git a/src/SCREENS.ts b/src/SCREENS.ts index d86b7f893901..26a23e7efadc 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -81,10 +81,12 @@ const SCREENS = { SAVE_THE_WORLD: { ROOT: 'SaveTheWorld_Root', }, + LEFT_MODAL: { + SEARCH: 'Search', + }, RIGHT_MODAL: { SETTINGS: 'Settings', NEW_CHAT: 'NewChat', - SEARCH: 'Search', DETAILS: 'Details', PROFILE: 'Profile', REPORT_DETAILS: 'Report_Details', diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js index 51912c04eb31..d24d1e18907f 100755 --- a/src/components/AttachmentModal.js +++ b/src/components/AttachmentModal.js @@ -366,7 +366,7 @@ function AttachmentModal(props) { setIsAuthTokenRequired(props.isAuthTokenRequired); }, [props.isAuthTokenRequired]); - const sourceForAttachmentView = props.source || source; + const sourceForAttachmentView = source || props.source; const threeDotsMenuItems = useMemo(() => { if (!props.isReceiptAttachment || !props.parentReport || !props.parentReportActions) { diff --git a/src/components/Button/index.tsx b/src/components/Button/index.tsx index cdafd0b0b93b..c6f6cd619c09 100644 --- a/src/components/Button/index.tsx +++ b/src/components/Button/index.tsx @@ -221,7 +221,7 @@ function Button( @@ -232,7 +232,7 @@ function Button( diff --git a/src/components/CurrencySymbolButton.js b/src/components/CurrencySymbolButton.tsx similarity index 83% rename from src/components/CurrencySymbolButton.js rename to src/components/CurrencySymbolButton.tsx index d03834fc1fd6..18955bb0b391 100644 --- a/src/components/CurrencySymbolButton.js +++ b/src/components/CurrencySymbolButton.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import React from 'react'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -7,15 +6,15 @@ import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; import Text from './Text'; import Tooltip from './Tooltip'; -const propTypes = { +type CurrencySymbolButtonProps = { /** Currency symbol of selected currency */ - currencySymbol: PropTypes.string.isRequired, + currencySymbol: string; /** Function to call when currency button is pressed */ - onCurrencyButtonPress: PropTypes.func.isRequired, + onCurrencyButtonPress: () => void; }; -function CurrencySymbolButton({onCurrencyButtonPress, currencySymbol}) { +function CurrencySymbolButton({onCurrencyButtonPress, currencySymbol}: CurrencySymbolButtonProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); return ( @@ -31,7 +30,6 @@ function CurrencySymbolButton({onCurrencyButtonPress, currencySymbol}) { ); } -CurrencySymbolButton.propTypes = propTypes; CurrencySymbolButton.displayName = 'CurrencySymbolButton'; export default CurrencySymbolButton; diff --git a/src/components/DotIndicatorMessage.tsx b/src/components/DotIndicatorMessage.tsx index 65afe8c7e4eb..2787804c5f76 100644 --- a/src/components/DotIndicatorMessage.tsx +++ b/src/components/DotIndicatorMessage.tsx @@ -84,9 +84,9 @@ function DotIndicatorMessage({messages = {}, style, type, textStyles}: DotIndica key={i} style={styles.offlineFeedback.text} > - {Localize.translateLocal('iou.error.receiptFailureMessage')} - {Localize.translateLocal('iou.error.saveFileMessage')} - {Localize.translateLocal('iou.error.loseFileMessage')} + {Localize.translateLocal('iou.error.receiptFailureMessage')} + {Localize.translateLocal('iou.error.saveFileMessage')} + {Localize.translateLocal('iou.error.loseFileMessage')} ) : ( diff --git a/src/components/LocationErrorMessage/BaseLocationErrorMessage.js b/src/components/LocationErrorMessage/BaseLocationErrorMessage.tsx similarity index 81% rename from src/components/LocationErrorMessage/BaseLocationErrorMessage.js rename to src/components/LocationErrorMessage/BaseLocationErrorMessage.tsx index d90783d94ad5..ceeb33d5e6bc 100644 --- a/src/components/LocationErrorMessage/BaseLocationErrorMessage.js +++ b/src/components/LocationErrorMessage/BaseLocationErrorMessage.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; import Icon from '@components/Icon'; @@ -7,29 +6,25 @@ import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeed import Text from '@components/Text'; import TextLink from '@components/TextLink'; import Tooltip from '@components/Tooltip'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import colors from '@styles/theme/colors'; import CONST from '@src/CONST'; -import * as locationErrorMessagePropTypes from './locationErrorMessagePropTypes'; +import LocationErrorMessageProps from './types'; -const propTypes = { +type BaseLocationErrorMessageProps = LocationErrorMessageProps & { /** A callback that runs when 'allow location permission' link is pressed */ - onAllowLocationLinkPress: PropTypes.func.isRequired, - - // eslint-disable-next-line react/forbid-foreign-prop-types - ...locationErrorMessagePropTypes.propTypes, - - /* Onyx Props */ - ...withLocalizePropTypes, + onAllowLocationLinkPress: () => void; }; -function BaseLocationErrorMessage({onClose, onAllowLocationLinkPress, locationErrorCode, translate}) { +function BaseLocationErrorMessage({onClose, onAllowLocationLinkPress, locationErrorCode}: BaseLocationErrorMessageProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); + const {translate} = useLocalize(); + if (!locationErrorCode) { return null; } @@ -81,6 +76,5 @@ function BaseLocationErrorMessage({onClose, onAllowLocationLinkPress, locationEr } BaseLocationErrorMessage.displayName = 'BaseLocationErrorMessage'; -BaseLocationErrorMessage.propTypes = propTypes; -BaseLocationErrorMessage.defaultProps = locationErrorMessagePropTypes.defaultProps; -export default withLocalize(BaseLocationErrorMessage); + +export default BaseLocationErrorMessage; diff --git a/src/components/LocationErrorMessage/index.native.js b/src/components/LocationErrorMessage/index.native.tsx similarity index 67% rename from src/components/LocationErrorMessage/index.native.js rename to src/components/LocationErrorMessage/index.native.tsx index 467018538b6e..3f3813084a47 100644 --- a/src/components/LocationErrorMessage/index.native.js +++ b/src/components/LocationErrorMessage/index.native.tsx @@ -1,14 +1,14 @@ import React from 'react'; import {Linking} from 'react-native'; import BaseLocationErrorMessage from './BaseLocationErrorMessage'; -import * as locationErrorMessagePropTypes from './locationErrorMessagePropTypes'; +import LocationErrorMessageProps from './types'; /** Opens app level settings from the native system settings */ const openAppSettings = () => { Linking.openSettings(); }; -function LocationErrorMessage(props) { +function LocationErrorMessage(props: LocationErrorMessageProps) { return ( { Linking.openURL(CONST.NEWHELP_URL); }; -function LocationErrorMessage(props) { +function LocationErrorMessage(props: LocationErrorMessageProps) { return ( void; /** * The location error code from onyx @@ -11,11 +9,7 @@ const propTypes = { * - code 2 = location is unavailable or there is some connection issue * - code 3 = location fetch timeout */ - locationErrorCode: PropTypes.oneOf([-1, 1, 2, 3]), -}; - -const defaultProps = { - locationErrorCode: null, + locationErrorCode?: -1 | 1 | 2 | 3; }; -export {propTypes, defaultProps}; +export default LocationErrorMessageProps; diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index db150d55f0d2..9faabc403c75 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -49,14 +49,14 @@ type UnresponsiveProps = { type IconProps = { /** Flag to choose between avatar image or an icon */ - iconType: typeof CONST.ICON_TYPE_ICON; + iconType?: typeof CONST.ICON_TYPE_ICON; /** Icon to display on the left side of component */ icon: IconAsset; }; type AvatarProps = { - iconType: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE; + iconType?: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE; icon: AvatarSource; }; @@ -85,7 +85,7 @@ type MenuItemProps = (ResponsiveProps | UnresponsiveProps) & titleStyle?: ViewStyle; /** Any adjustments to style when menu item is hovered or pressed */ - hoverAndPressStyle: StyleProp>; + hoverAndPressStyle?: StyleProp>; /** Additional styles to style the description text below the title */ descriptionTextStyle?: StyleProp; @@ -175,7 +175,7 @@ type MenuItemProps = (ResponsiveProps | UnresponsiveProps) & isSelected?: boolean; /** Prop to identify if we should load avatars vertically instead of diagonally */ - shouldStackHorizontally: boolean; + shouldStackHorizontally?: boolean; /** Prop to represent the size of the avatar images to be shown */ avatarSize?: (typeof CONST.AVATAR_SIZE)[keyof typeof CONST.AVATAR_SIZE]; @@ -220,10 +220,10 @@ type MenuItemProps = (ResponsiveProps | UnresponsiveProps) & furtherDetails?: string; /** The function that should be called when this component is LongPressed or right-clicked. */ - onSecondaryInteraction: () => void; + onSecondaryInteraction?: () => void; /** Array of objects that map display names to their corresponding tooltip */ - titleWithTooltips: DisplayNameWithTooltip[]; + titleWithTooltips?: DisplayNameWithTooltip[]; /** Icon should be displayed in its own color */ displayInDefaultIconColor?: boolean; diff --git a/src/components/Popover/popoverPropTypes.js b/src/components/Popover/popoverPropTypes.js index c13fd8fa0b85..c758c4e6d311 100644 --- a/src/components/Popover/popoverPropTypes.js +++ b/src/components/Popover/popoverPropTypes.js @@ -26,6 +26,9 @@ const propTypes = { /** The ref of the popover */ withoutOverlayRef: refPropTypes, + + /** Whether we want to show the popover on the right side of the screen */ + fromSidebarMediumScreen: PropTypes.bool, }; const defaultProps = { diff --git a/src/components/Popover/types.ts b/src/components/Popover/types.ts index 7f7e2829770c..7890ce5555f0 100644 --- a/src/components/Popover/types.ts +++ b/src/components/Popover/types.ts @@ -1,7 +1,15 @@ +import type {ValueOf} from 'type-fest'; import BaseModalProps, {PopoverAnchorPosition} from '@components/Modal/types'; import {WindowDimensionsProps} from '@components/withWindowDimensions/types'; +import CONST from '@src/CONST'; -type AnchorAlignment = {horizontal: string; vertical: string}; +type AnchorAlignment = { + /** The horizontal anchor alignment of the popover */ + horizontal: ValueOf; + + /** The vertical anchor alignment of the popover */ + vertical: ValueOf; +}; type PopoverDimensions = { width: number; @@ -39,4 +47,4 @@ type PopoverProps = BaseModalProps & { type PopoverWithWindowDimensionsProps = PopoverProps & WindowDimensionsProps; -export type {PopoverProps, PopoverWithWindowDimensionsProps}; +export type {PopoverProps, PopoverWithWindowDimensionsProps, AnchorAlignment}; diff --git a/src/components/PopoverMenu.tsx b/src/components/PopoverMenu.tsx new file mode 100644 index 000000000000..2c85b80534ca --- /dev/null +++ b/src/components/PopoverMenu.tsx @@ -0,0 +1,176 @@ +import type {ImageContentFit} from 'expo-image'; +import React, {RefObject, useRef} from 'react'; +import {View} from 'react-native'; +import type {ModalProps} from 'react-native-modal'; +import type {SvgProps} from 'react-native-svg'; +import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager'; +import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; +import useThemeStyles from '@hooks/useThemeStyles'; +import useWindowDimensions from '@hooks/useWindowDimensions'; +import CONST from '@src/CONST'; +import type {AnchorPosition} from '@src/styles'; +import MenuItem from './MenuItem'; +import type {AnchorAlignment} from './Popover/types'; +import PopoverWithMeasuredContent from './PopoverWithMeasuredContent'; +import Text from './Text'; + +type PopoverMenuItem = { + /** An icon element displayed on the left side */ + icon: React.FC; + + /** Text label */ + text: string; + + /** A callback triggered when this item is selected */ + onSelected: () => void; + + /** A description text to show under the title */ + description?: string; + + /** The fill color to pass into the icon. */ + iconFill?: string; + + /** Icon Width */ + iconWidth?: number; + + /** Icon Height */ + iconHeight?: number; + + /** Icon should be displayed in its own color */ + displayInDefaultIconColor?: boolean; + + /** Determines how the icon should be resized to fit its container */ + contentFit?: ImageContentFit; +}; + +type PopoverModalProps = Pick; + +type PopoverMenuProps = PopoverModalProps & { + /** Callback method fired when the user requests to close the modal */ + onClose: () => void; + + /** State that determines whether to display the modal or not */ + isVisible: boolean; + + /** Callback to fire when a CreateMenu item is selected */ + onItemSelected: (selectedItem: PopoverMenuItem, index: number) => void; + + /** Menu items to be rendered on the list */ + menuItems: PopoverMenuItem[]; + + /** Optional non-interactive text to display as a header for any create menu */ + headerText?: string; + + /** Whether disable the animations */ + disableAnimation?: boolean; + + /** The horizontal and vertical anchors points for the popover */ + anchorPosition: AnchorPosition; + + /** Ref of the anchor */ + anchorRef: RefObject; + + /** Where the popover should be positioned relative to the anchor points. */ + anchorAlignment?: AnchorAlignment; + + /** Whether we don't want to show overlay */ + withoutOverlay?: boolean; + + /** Should we announce the Modal visibility changes? */ + shouldSetModalVisibility?: boolean; + + /** Whether we want to show the popover on the right side of the screen */ + fromSidebarMediumScreen?: boolean; +}; + +function PopoverMenu({ + menuItems, + onItemSelected, + isVisible, + anchorPosition, + anchorRef, + onClose, + headerText, + fromSidebarMediumScreen, + anchorAlignment = { + horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, + vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, + }, + animationIn = 'fadeIn', + animationOut = 'fadeOut', + animationInTiming = CONST.ANIMATED_TRANSITION, + disableAnimation = true, + withoutOverlay = false, + shouldSetModalVisibility = true, +}: PopoverMenuProps) { + const styles = useThemeStyles(); + const {isSmallScreenWidth} = useWindowDimensions(); + const selectedItemIndex = useRef(null); + const [focusedIndex, setFocusedIndex] = useArrowKeyFocusManager({initialFocusedIndex: -1, maxIndex: menuItems.length - 1, isActive: isVisible}); + + const selectItem = (index: number) => { + const selectedItem = menuItems[index]; + onItemSelected(selectedItem, index); + selectedItemIndex.current = index; + }; + + useKeyboardShortcut( + CONST.KEYBOARD_SHORTCUTS.ENTER, + () => { + if (focusedIndex === -1) { + return; + } + selectItem(focusedIndex); + setFocusedIndex(-1); // Reset the focusedIndex on selecting any menu + }, + {isActive: isVisible}, + ); + + return ( + { + setFocusedIndex(-1); + if (selectedItemIndex.current !== null) { + menuItems[selectedItemIndex.current].onSelected(); + selectedItemIndex.current = null; + } + }} + animationIn={animationIn} + animationOut={animationOut} + animationInTiming={animationInTiming} + disableAnimation={disableAnimation} + fromSidebarMediumScreen={fromSidebarMediumScreen} + withoutOverlay={withoutOverlay} + shouldSetModalVisibility={shouldSetModalVisibility} + > + + {!!headerText && {headerText}} + {menuItems.map((item, menuIndex) => ( + selectItem(menuIndex)} + focused={focusedIndex === menuIndex} + displayInDefaultIconColor={item.displayInDefaultIconColor} + /> + ))} + + + ); +} + +PopoverMenu.displayName = 'PopoverMenu'; + +export default React.memo(PopoverMenu); diff --git a/src/components/PopoverMenu/index.js b/src/components/PopoverMenu/index.js deleted file mode 100644 index 597105173b4c..000000000000 --- a/src/components/PopoverMenu/index.js +++ /dev/null @@ -1,114 +0,0 @@ -import PropTypes from 'prop-types'; -import React, {useRef} from 'react'; -import {View} from 'react-native'; -import _ from 'underscore'; -import MenuItem from '@components/MenuItem'; -import PopoverWithMeasuredContent from '@components/PopoverWithMeasuredContent'; -import refPropTypes from '@components/refPropTypes'; -import Text from '@components/Text'; -import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions'; -import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager'; -import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; -import useThemeStyles from '@hooks/useThemeStyles'; -import useWindowDimensions from '@hooks/useWindowDimensions'; -import CONST from '@src/CONST'; -import {defaultProps as createMenuDefaultProps, propTypes as createMenuPropTypes} from './popoverMenuPropTypes'; - -const propTypes = { - ...createMenuPropTypes, - ...windowDimensionsPropTypes, - - /** Ref of the anchor */ - anchorRef: refPropTypes, - - withoutOverlay: PropTypes.bool, - - /** Should we announce the Modal visibility changes? */ - shouldSetModalVisibility: PropTypes.bool, -}; - -const defaultProps = { - ...createMenuDefaultProps, - anchorAlignment: { - horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, - vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, - }, - anchorRef: () => {}, - withoutOverlay: false, - shouldSetModalVisibility: true, -}; - -function PopoverMenu(props) { - const styles = useThemeStyles(); - const {isSmallScreenWidth} = useWindowDimensions(); - const selectedItemIndex = useRef(null); - const [focusedIndex, setFocusedIndex] = useArrowKeyFocusManager({initialFocusedIndex: -1, maxIndex: props.menuItems.length - 1, isActive: props.isVisible}); - - const selectItem = (index) => { - const selectedItem = props.menuItems[index]; - props.onItemSelected(selectedItem, index); - selectedItemIndex.current = index; - }; - - useKeyboardShortcut( - CONST.KEYBOARD_SHORTCUTS.ENTER, - () => { - if (focusedIndex === -1) { - return; - } - selectItem(focusedIndex); - setFocusedIndex(-1); // Reset the focusedIndex on selecting any menu - }, - {isActive: props.isVisible}, - ); - - return ( - { - setFocusedIndex(-1); - if (selectedItemIndex.current !== null) { - props.menuItems[selectedItemIndex.current].onSelected(); - selectedItemIndex.current = null; - } - }} - animationIn={props.animationIn} - animationOut={props.animationOut} - animationInTiming={props.animationInTiming} - disableAnimation={props.disableAnimation} - fromSidebarMediumScreen={props.fromSidebarMediumScreen} - withoutOverlay={props.withoutOverlay} - shouldSetModalVisibility={props.shouldSetModalVisibility} - > - - {!_.isEmpty(props.headerText) && {props.headerText}} - {_.map(props.menuItems, (item, menuIndex) => ( - selectItem(menuIndex)} - focused={focusedIndex === menuIndex} - displayInDefaultIconColor={item.displayInDefaultIconColor} - /> - ))} - - - ); -} - -PopoverMenu.propTypes = propTypes; -PopoverMenu.defaultProps = defaultProps; -PopoverMenu.displayName = 'PopoverMenu'; - -export default React.memo(withWindowDimensions(PopoverMenu)); diff --git a/src/components/PopoverMenu/popoverMenuPropTypes.js b/src/components/PopoverMenu/popoverMenuPropTypes.js deleted file mode 100644 index 53eeb63b05e7..000000000000 --- a/src/components/PopoverMenu/popoverMenuPropTypes.js +++ /dev/null @@ -1,71 +0,0 @@ -import PropTypes from 'prop-types'; -import _ from 'underscore'; -import sourcePropTypes from '@components/Image/sourcePropTypes'; -import CONST from '@src/CONST'; - -const propTypes = { - /** Callback method fired when the user requests to close the modal */ - onClose: PropTypes.func.isRequired, - - /** State that determines whether to display the modal or not */ - isVisible: PropTypes.bool.isRequired, - - /** Callback to fire when a CreateMenu item is selected */ - onItemSelected: PropTypes.func.isRequired, - - /** Menu items to be rendered on the list */ - menuItems: PropTypes.arrayOf( - PropTypes.shape({ - /** An icon element displayed on the left side */ - icon: sourcePropTypes, - - /** Text label */ - text: PropTypes.string.isRequired, - - /** A callback triggered when this item is selected */ - onSelected: PropTypes.func.isRequired, - }), - ).isRequired, - - /** The anchor position of the CreateMenu popover */ - anchorPosition: PropTypes.shape({ - top: PropTypes.number, - right: PropTypes.number, - bottom: PropTypes.number, - left: PropTypes.number, - }).isRequired, - - /** Where the popover should be positioned relative to the anchor points. */ - anchorAlignment: PropTypes.shape({ - horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)), - vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)), - }), - - /** The anchor reference of the CreateMenu popover */ - anchorRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired, - - /** A react-native-animatable animation definition for the modal display animation. */ - animationIn: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - - /** A react-native-animatable animation definition for the modal hide animation. */ - animationOut: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - - /** A react-native-animatable animation timing for the modal display animation. */ - animationInTiming: PropTypes.number, - - /** Optional non-interactive text to display as a header for any create menu */ - headerText: PropTypes.string, - - /** Whether disable the animations */ - disableAnimation: PropTypes.bool, -}; - -const defaultProps = { - animationIn: 'fadeIn', - animationOut: 'fadeOut', - animationInTiming: CONST.ANIMATED_TRANSITION, - headerText: undefined, - disableAnimation: true, -}; - -export {propTypes, defaultProps}; diff --git a/src/components/PopoverWithMeasuredContent.tsx b/src/components/PopoverWithMeasuredContent.tsx index 9d10f7869f8a..206a33181605 100644 --- a/src/components/PopoverWithMeasuredContent.tsx +++ b/src/components/PopoverWithMeasuredContent.tsx @@ -8,8 +8,9 @@ import CONST from '@src/CONST'; import type {AnchorPosition} from '@src/styles'; import Popover from './Popover'; import {PopoverProps} from './Popover/types'; +import type {WindowDimensionsProps} from './withWindowDimensions/types'; -type PopoverWithMeasuredContentProps = Omit & { +type PopoverWithMeasuredContentProps = Omit & { /** The horizontal and vertical anchors points for the popover */ anchorPosition: AnchorPosition; }; diff --git a/src/components/ReportActionItem/ReportActionItemImage.js b/src/components/ReportActionItem/ReportActionItemImage.js index 2c5ef22b1b8e..4336a5eddd8a 100644 --- a/src/components/ReportActionItem/ReportActionItemImage.js +++ b/src/components/ReportActionItem/ReportActionItemImage.js @@ -1,3 +1,4 @@ +import Str from 'expensify-common/lib/str'; import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; @@ -60,7 +61,7 @@ function ReportActionItemImage({thumbnail, image, enablePreviewModal, transactio ); - } else if (thumbnail && !isLocalFile) { + } else if (thumbnail && !isLocalFile && !Str.isPDF(imageSource)) { receiptImageComponent = ( - { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(props.iouReportID)); - }} - onPressIn={() => DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} - onPressOut={() => ControlSelection.unblock()} - onLongPress={(event) => showContextMenuForReport(event, props.contextMenuAnchor, props.chatReportID, props.action, props.checkIfContextMenuActive)} - style={[styles.flexRow, styles.justifyContentBetween, styles.reportPreviewBox]} - role="button" - accessibilityLabel={props.translate('iou.viewDetails')} - > - - {hasReceipts && ( - - )} - - - - {getPreviewMessage()} - - {!iouSettled && hasErrors && ( - - )} - - - - {getDisplayAmount()} - {ReportUtils.isSettled(props.iouReportID) && ( - - - + + + { + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(props.iouReportID)); + }} + onPressIn={() => DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()} + onPressOut={() => ControlSelection.unblock()} + onLongPress={(event) => showContextMenuForReport(event, props.contextMenuAnchor, props.chatReportID, props.action, props.checkIfContextMenuActive)} + style={[styles.flexRow, styles.justifyContentBetween, styles.reportPreviewBox]} + role="button" + accessibilityLabel={props.translate('iou.viewDetails')} + > + + {hasReceipts && ( + + )} + + + + {getPreviewMessage()} + + {!iouSettled && hasErrors && ( + )} - - {!isScanning && (numberOfRequests > 1 || hasReceipts) && ( - {previewSubtitle || moneyRequestComment} + {getDisplayAmount()} + {ReportUtils.isSettled(props.iouReportID) && ( + + + + )} - )} - {shouldShowSettlementButton && ( - IOU.payMoneyRequest(paymentType, props.chatReport, props.iouReport)} - enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} - addBankAccountRoute={bankAccountRoute} - shouldHidePaymentOptions={!shouldShowPayButton} - shouldShowApproveButton={shouldShowApproveButton} - style={[styles.mt3]} - kycWallAnchorAlignment={{ - horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, - vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, - }} - paymentMethodDropdownAnchorAlignment={{ - horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, - vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.BOTTOM, - }} - /> - )} - {shouldShowSubmitButton && ( -