diff --git a/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js b/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.tsx similarity index 67% rename from src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js rename to src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.tsx index dd2713a38b2b..d46dce1a3658 100644 --- a/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js +++ b/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.tsx @@ -1,19 +1,14 @@ -import PropTypes from 'prop-types'; import React from 'react'; -import {PixelRatio, View} from 'react-native'; +import {PixelRatio, StyleProp, View, ViewStyle} from 'react-native'; import useWindowDimensions from '@hooks/useWindowDimensions'; import useThemeStyles from '@styles/useThemeStyles'; -const propTypes = { +type AttachmentCarouselCellRendererProps = { /** Cell Container styles */ - style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]), + style: StyleProp; }; -const defaultProps = { - style: [], -}; - -function AttachmentCarouselCellRenderer(props) { +function AttachmentCarouselCellRenderer(props: AttachmentCarouselCellRendererProps) { const styles = useThemeStyles(); const {windowWidth, isSmallScreenWidth} = useWindowDimensions(); const modalStyles = styles.centeredModalStyles(isSmallScreenWidth, true); @@ -28,8 +23,6 @@ function AttachmentCarouselCellRenderer(props) { ); } -AttachmentCarouselCellRenderer.propTypes = propTypes; -AttachmentCarouselCellRenderer.defaultProps = defaultProps; AttachmentCarouselCellRenderer.displayName = 'AttachmentCarouselCellRenderer'; export default React.memo(AttachmentCarouselCellRenderer); diff --git a/src/components/Attachments/AttachmentCarousel/CarouselActions.js b/src/components/Attachments/AttachmentCarousel/CarouselActions.js deleted file mode 100644 index cf5309222c4e..000000000000 --- a/src/components/Attachments/AttachmentCarousel/CarouselActions.js +++ /dev/null @@ -1,55 +0,0 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; -import {useEffect} from 'react'; -import KeyboardShortcut from '@libs/KeyboardShortcut'; -import CONST from '@src/CONST'; - -const propTypes = { - /** Callback to cycle through attachments */ - onCycleThroughAttachments: PropTypes.func.isRequired, -}; - -function CarouselActions({onCycleThroughAttachments}) { - useEffect(() => { - const shortcutLeftConfig = CONST.KEYBOARD_SHORTCUTS.ARROW_LEFT; - const unsubscribeLeftKey = KeyboardShortcut.subscribe( - shortcutLeftConfig.shortcutKey, - (e) => { - if (lodashGet(e, 'target.blur')) { - // prevents focus from highlighting around the modal - e.target.blur(); - } - - onCycleThroughAttachments(-1); - }, - shortcutLeftConfig.descriptionKey, - shortcutLeftConfig.modifiers, - ); - - const shortcutRightConfig = CONST.KEYBOARD_SHORTCUTS.ARROW_RIGHT; - const unsubscribeRightKey = KeyboardShortcut.subscribe( - shortcutRightConfig.shortcutKey, - (e) => { - if (lodashGet(e, 'target.blur')) { - // prevents focus from highlighting around the modal - e.target.blur(); - } - - onCycleThroughAttachments(1); - }, - shortcutRightConfig.descriptionKey, - shortcutRightConfig.modifiers, - ); - - return () => { - unsubscribeLeftKey(); - unsubscribeRightKey(); - }; - }, [onCycleThroughAttachments]); - - return null; -} - -CarouselActions.propTypes = propTypes; - -export default CarouselActions; diff --git a/src/components/Attachments/AttachmentCarousel/CarouselActions.tsx b/src/components/Attachments/AttachmentCarousel/CarouselActions.tsx new file mode 100644 index 000000000000..bdc181b6be9d --- /dev/null +++ b/src/components/Attachments/AttachmentCarousel/CarouselActions.tsx @@ -0,0 +1,33 @@ +import useKeyboardShortcut from '@hooks/useKeyboardShortcut'; +import CONST from '@src/CONST'; + +type CarouselActionsProps = { + onCycleThroughAttachments: (direction: number) => void; +}; + +const shortcutLeftConfig = CONST.KEYBOARD_SHORTCUTS.ARROW_LEFT; +const shortcutRightConfig = CONST.KEYBOARD_SHORTCUTS.ARROW_RIGHT; + +function CarouselActions({onCycleThroughAttachments}: CarouselActionsProps) { + useKeyboardShortcut(shortcutLeftConfig, (e) => { + const target = e?.target as HTMLElement; + // prevents focus from highlighting around the modal + target?.blur(); + + onCycleThroughAttachments(-1); + }); + + useKeyboardShortcut(shortcutRightConfig, (e) => { + const target = e?.target as HTMLElement; + // prevents focus from highlighting around the modal + target?.blur(); + + onCycleThroughAttachments(1); + }); + + return null; +} + +CarouselActions.displayName = 'CarouselActions'; + +export default CarouselActions; diff --git a/src/components/Attachments/AttachmentCarousel/CarouselButtons.js b/src/components/Attachments/AttachmentCarousel/CarouselButtons.tsx similarity index 69% rename from src/components/Attachments/AttachmentCarousel/CarouselButtons.js rename to src/components/Attachments/AttachmentCarousel/CarouselButtons.tsx index 14a6ea268468..8d6bac6bf8b5 100644 --- a/src/components/Attachments/AttachmentCarousel/CarouselButtons.js +++ b/src/components/Attachments/AttachmentCarousel/CarouselButtons.tsx @@ -1,8 +1,5 @@ -import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; -import _ from 'underscore'; -import * as AttachmentCarouselViewPropTypes from '@components/Attachments/propTypes'; import Button from '@components/Button'; import * as Expensicons from '@components/Icon/Expensicons'; import Tooltip from '@components/Tooltip'; @@ -10,36 +7,23 @@ import useLocalize from '@hooks/useLocalize'; import useWindowDimensions from '@hooks/useWindowDimensions'; import useTheme from '@styles/themes/useTheme'; import useThemeStyles from '@styles/useThemeStyles'; +import {Attachment} from './CarouselItem'; -const propTypes = { - /** Where the arrows should be visible */ - shouldShowArrows: PropTypes.bool.isRequired, - - /** The current page index */ - page: PropTypes.number.isRequired, - - /** The attachments from the carousel */ - attachments: AttachmentCarouselViewPropTypes.attachmentsPropType.isRequired, - - /** Callback to go one page back */ - onBack: PropTypes.func.isRequired, - /** Callback to go one page forward */ - onForward: PropTypes.func.isRequired, - - autoHideArrow: PropTypes.func, - cancelAutoHideArrow: PropTypes.func, -}; - -const defaultProps = { - autoHideArrow: () => {}, - cancelAutoHideArrow: () => {}, +type CarouselButtonsProps = { + shouldShowArrows: boolean; + page: number; + attachments: Attachment[]; + onBack: () => void; + onForward: () => void; + autoHideArrow?: () => void; + cancelAutoHideArrow?: () => void; }; -function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward, cancelAutoHideArrow, autoHideArrow}) { +function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward, cancelAutoHideArrow = () => {}, autoHideArrow = () => {}}: CarouselButtonsProps) { const theme = useTheme(); const styles = useThemeStyles(); const isBackDisabled = page === 0; - const isForwardDisabled = page === _.size(attachments) - 1; + const isForwardDisabled = page === attachments.length - 1; const {translate} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); @@ -58,6 +42,7 @@ function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward onPress={onBack} onPressIn={cancelAutoHideArrow} onPressOut={autoHideArrow} + text="" /> @@ -74,6 +59,7 @@ function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward onPress={onForward} onPressIn={cancelAutoHideArrow} onPressOut={autoHideArrow} + text="" /> @@ -82,8 +68,6 @@ function CarouselButtons({page, attachments, shouldShowArrows, onBack, onForward ) : null; } -CarouselButtons.propTypes = propTypes; -CarouselButtons.defaultProps = defaultProps; CarouselButtons.displayName = 'CarouselButtons'; export default CarouselButtons; diff --git a/src/components/Attachments/AttachmentCarousel/CarouselItem.js b/src/components/Attachments/AttachmentCarousel/CarouselItem.tsx similarity index 65% rename from src/components/Attachments/AttachmentCarousel/CarouselItem.js rename to src/components/Attachments/AttachmentCarousel/CarouselItem.tsx index b6cc0cbf21a4..49f48283dfb3 100644 --- a/src/components/Attachments/AttachmentCarousel/CarouselItem.js +++ b/src/components/Attachments/AttachmentCarousel/CarouselItem.tsx @@ -1,8 +1,6 @@ -import PropTypes from 'prop-types'; import React, {useContext, useState} from 'react'; -import {View} from 'react-native'; +import {Role, StyleProp, View, ViewStyle} from 'react-native'; import AttachmentView from '@components/Attachments/AttachmentView'; -import * as AttachmentsPropTypes from '@components/Attachments/propTypes'; import Button from '@components/Button'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import SafeAreaConsumer from '@components/SafeAreaConsumer'; @@ -11,51 +9,26 @@ import useLocalize from '@hooks/useLocalize'; import ReportAttachmentsContext from '@pages/home/report/ReportAttachmentsContext'; import useThemeStyles from '@styles/useThemeStyles'; import CONST from '@src/CONST'; +import {Attachment} from './types'; -const propTypes = { +type CarouselItemProps = { /** Attachment required information such as the source and file name */ - item: PropTypes.shape({ - /** Report action ID of the attachment */ - reportActionID: PropTypes.string, - - /** Whether source URL requires authentication */ - isAuthTokenRequired: PropTypes.bool, - - /** URL to full-sized attachment or SVG function */ - source: AttachmentsPropTypes.attachmentSourcePropType.isRequired, - - /** Additional information about the attachment file */ - file: PropTypes.shape({ - /** File name of the attachment */ - name: PropTypes.string, - }), - - /** Whether the attachment has been flagged */ - hasBeenFlagged: PropTypes.bool, - - /** The id of the transaction related to the attachment */ - transactionID: PropTypes.string, - }).isRequired, + item: Attachment; /** Whether the attachment is currently being viewed in the carousel */ - isFocused: PropTypes.bool.isRequired, + isFocused: boolean; /** onPress callback */ - onPress: PropTypes.func, -}; - -const defaultProps = { - onPress: undefined, + onPress?: () => void; }; -function CarouselItem({item, isFocused, onPress}) { +function CarouselItem({item, isFocused, onPress = undefined}: CarouselItemProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const {isAttachmentHidden} = useContext(ReportAttachmentsContext); - // eslint-disable-next-line es/no-nullish-coalescing-operators - const [isHidden, setIsHidden] = useState(() => isAttachmentHidden(item.reportActionID) ?? item.hasBeenFlagged); + const reportAttachmentsContext = useContext(ReportAttachmentsContext); + const [isHidden, setIsHidden] = useState(() => !!reportAttachmentsContext?.isAttachmentHidden(item.reportActionID ?? '') ?? item.hasBeenFlagged); - const renderButton = (style) => ( + const renderButton = (style: StyleProp) => (