diff --git a/src/components/Header.tsx b/src/components/Header.tsx index c02f21d7c6f2..4eac2c7a6994 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,4 +1,4 @@ -import React, {ReactElement} from 'react'; +import React, {ReactNode} from 'react'; import {StyleProp, TextStyle, View} from 'react-native'; import useThemeStyles from '@hooks/useThemeStyles'; import EnvironmentBadge from './EnvironmentBadge'; @@ -6,10 +6,10 @@ import Text from './Text'; type HeaderProps = { /** Title of the Header */ - title?: string | ReactElement; + title?: ReactNode; /** Subtitle of the header */ - subtitle?: string | ReactElement; + subtitle?: ReactNode; /** Should we show the environment badge (dev/stg)? */ shouldShowEnvironmentBadge?: boolean; diff --git a/src/components/HeaderWithBackButton/index.js b/src/components/HeaderWithBackButton/index.tsx similarity index 91% rename from src/components/HeaderWithBackButton/index.js rename to src/components/HeaderWithBackButton/index.tsx index 738afbfaeeba..9ec8bca55a95 100755 --- a/src/components/HeaderWithBackButton/index.js +++ b/src/components/HeaderWithBackButton/index.tsx @@ -19,18 +19,18 @@ import getButtonState from '@libs/getButtonState'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; -import headerWithBackButtonPropTypes from './headerWithBackButtonPropTypes'; +import HeaderWithBackButtonProps from './types'; function HeaderWithBackButton({ - iconFill = null, + iconFill, guidesCallTaskID = '', onBackButtonPress = () => Navigation.goBack(ROUTES.HOME), onCloseButtonPress = () => Navigation.dismissModal(), onDownloadButtonPress = () => {}, onThreeDotsButtonPress = () => {}, report = null, - policy = {}, - personalDetails = {}, + policy, + personalDetails = null, shouldShowAvatarWithDisplay = false, shouldShowBackButton = true, shouldShowBorderBottom = false, @@ -41,10 +41,10 @@ function HeaderWithBackButton({ shouldShowPinButton = false, shouldShowThreeDotsButton = false, shouldDisableThreeDotsButton = false, - stepCounter = null, + stepCounter, subtitle = '', title = '', - titleColor = undefined, + titleColor, threeDotsAnchorPosition = { vertical: 0, horizontal: 0, @@ -55,14 +55,16 @@ function HeaderWithBackButton({ shouldOverlay = false, singleExecution = (func) => func, shouldNavigateToTopMostReport = false, -}) { +}: HeaderWithBackButtonProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const [isDownloadButtonActive, temporarilyDisableDownloadButton] = useThrottledButtonState(); const {translate} = useLocalize(); + // @ts-expect-error TODO: Remove this once useKeyboardState (https://github.com/Expensify/App/issues/24941) is migrated to TypeScript. const {isKeyboardShown} = useKeyboardState(); const waitForNavigate = useWaitForNavigation(); + return ( @@ -116,17 +118,17 @@ function HeaderWithBackButton({ {shouldShowDownloadButton && ( { + onPress={(event) => { // Blur the pressable in case this button triggers a Growl notification // We do not want to overlap Growl with the Tooltip (#15271) - e.currentTarget.blur(); + (event?.currentTarget as HTMLElement)?.blur(); if (!isDownloadButtonActive) { return; } onDownloadButtonPress(); - temporarilyDisableDownloadButton(true); + temporarilyDisableDownloadButton(); }} style={[styles.touchableButtonImage]} role="button" @@ -134,7 +136,7 @@ function HeaderWithBackButton({ > @@ -150,12 +152,12 @@ function HeaderWithBackButton({ > )} - {shouldShowPinButton && } + {shouldShowPinButton && !!report && } {shouldShowThreeDotsButton && ( @@ -186,7 +188,6 @@ function HeaderWithBackButton({ ); } -HeaderWithBackButton.propTypes = headerWithBackButtonPropTypes; HeaderWithBackButton.displayName = 'HeaderWithBackButton'; export default HeaderWithBackButton; diff --git a/src/components/HeaderWithBackButton/types.ts b/src/components/HeaderWithBackButton/types.ts new file mode 100644 index 000000000000..939b2530fa3d --- /dev/null +++ b/src/components/HeaderWithBackButton/types.ts @@ -0,0 +1,113 @@ +import {ReactNode} from 'react'; +import {OnyxCollection, OnyxEntry} from 'react-native-onyx'; +import type {Action} from '@hooks/useSingleExecution'; +import type {StepCounterParams} from '@src/languages/types'; +import type {AnchorPosition} from '@src/styles'; +import type {PersonalDetails, Policy, Report} from '@src/types/onyx'; +import type ChildrenProps from '@src/types/utils/ChildrenProps'; +import type IconAsset from '@src/types/utils/IconAsset'; + +type ThreeDotsMenuItems = { + /** An icon element displayed on the left side */ + icon?: IconAsset; + + /** Text label */ + text: string; + + /** A callback triggered when the item is selected */ + onSelected: () => void; +}; + +type HeaderWithBackButtonProps = ChildrenProps & { + /** Title of the Header */ + title?: string; + + /** Subtitle of the header */ + subtitle?: ReactNode; + + /** Title color */ + titleColor?: string; + + /** Method to trigger when pressing download button of the header */ + onDownloadButtonPress?: () => void; + + /** Method to trigger when pressing close button of the header */ + onCloseButtonPress?: () => void; + + /** Method to trigger when pressing back button of the header */ + onBackButtonPress?: () => void; + + /** Method to trigger when pressing more options button of the header */ + onThreeDotsButtonPress?: () => void; + + /** Whether we should show a border on the bottom of the Header */ + shouldShowBorderBottom?: boolean; + + /** Whether we should show a download button */ + shouldShowDownloadButton?: boolean; + + /** Whether we should show a get assistance (question mark) button */ + shouldShowGetAssistanceButton?: boolean; + + /** Whether we should disable the get assistance button */ + shouldDisableGetAssistanceButton?: boolean; + + /** Whether we should show a pin button */ + shouldShowPinButton?: boolean; + + /** Whether we should show a more options (threedots) button */ + shouldShowThreeDotsButton?: boolean; + + /** Whether we should disable threedots button */ + shouldDisableThreeDotsButton?: boolean; + + /** List of menu items for more(three dots) menu */ + threeDotsMenuItems?: ThreeDotsMenuItems[]; + + /** The anchor position of the menu */ + threeDotsAnchorPosition?: AnchorPosition; + + /** Whether we should show a close button */ + shouldShowCloseButton?: boolean; + + /** Whether we should show a back button */ + shouldShowBackButton?: boolean; + + /** The guides call taskID to associate with the get assistance button, if we show it */ + guidesCallTaskID?: string; + + /** Data to display a step counter in the header */ + stepCounter?: StepCounterParams; + + /** Whether we should show an avatar */ + shouldShowAvatarWithDisplay?: boolean; + + /** Parent report, if provided it will override props.report for AvatarWithDisplay */ + parentReport?: OnyxEntry; + + /** Report, if we're showing the details for one and using AvatarWithDisplay */ + report?: OnyxEntry; + + /** The report's policy, if we're showing the details for a report and need info about it for AvatarWithDisplay */ + policy?: OnyxEntry; + + /** Policies, if we're showing the details for a report and need participant details for AvatarWithDisplay */ + personalDetails?: OnyxCollection; + + /** Single execution function to prevent concurrent navigation actions */ + singleExecution?: (action: Action) => Action; + + /** Whether we should navigate to report page when the route have a topMostReport */ + shouldNavigateToTopMostReport?: boolean; + + /** The fill color for the icon. Can be hex, rgb, rgba, or valid react-native named color such as 'red' or 'blue'. */ + iconFill?: string; + + /** Whether the popover menu should overlay the current view */ + shouldOverlay?: boolean; + + /** Whether we should enable detail page navigation */ + shouldEnableDetailPageNavigation?: boolean; +}; + +export default HeaderWithBackButtonProps; diff --git a/src/components/Pressable/GenericPressable/types.ts b/src/components/Pressable/GenericPressable/types.ts index bff5f651ac9f..cdb9a8624114 100644 --- a/src/components/Pressable/GenericPressable/types.ts +++ b/src/components/Pressable/GenericPressable/types.ts @@ -40,7 +40,7 @@ type PressableProps = RNPressableProps & /** * onPress callback */ - onPress: (event?: GestureResponderEvent | KeyboardEvent) => void; + onPress: (event?: GestureResponderEvent | KeyboardEvent) => void | Promise; /** * Specifies keyboard shortcut to trigger onPressHandler diff --git a/src/hooks/useSingleExecution/index.ts b/src/hooks/useSingleExecution/index.ts index c37087d27c5f..f1be359f0355 100644 --- a/src/hooks/useSingleExecution/index.ts +++ b/src/hooks/useSingleExecution/index.ts @@ -18,3 +18,5 @@ export default function useSingleExecution() { return {isExecuting: false, singleExecution}; } + +export type {Action}; diff --git a/src/styles/index.ts b/src/styles/index.ts index 0d1b47235347..5456f940e048 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -4117,4 +4117,4 @@ const defaultStyles = styles(defaultTheme); export default styles; export {defaultStyles}; -export type {Styles, ThemeStyles, StatusBarStyle, ColorScheme}; +export type {Styles, ThemeStyles, StatusBarStyle, ColorScheme, AnchorPosition};