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 'HeaderWithBackButton' component to TypeScript #33214

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,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 = undefined,
iconFill,
guidesCallTaskID = '',
onBackButtonPress = () => Navigation.goBack(ROUTES.HOME),
onCloseButtonPress = () => Navigation.dismissModal(),
onDownloadButtonPress = () => {},
onThreeDotsButtonPress = () => {},
report = null,
policy = {},
personalDetails = {},
policy,
personalDetails,
shouldShowAvatarWithDisplay = false,
shouldShowBackButton = true,
shouldShowBorderBottom = false,
Expand All @@ -40,10 +40,10 @@ function HeaderWithBackButton({
shouldShowPinButton = false,
shouldShowThreeDotsButton = false,
shouldDisableThreeDotsButton = false,
stepCounter = null,
stepCounter,
subtitle = '',
title = '',
titleColor = undefined,
titleColor,
threeDotsAnchorPosition = {
vertical: 0,
horizontal: 0,
Expand All @@ -54,13 +54,15 @@ function HeaderWithBackButton({
shouldOverlay = false,
singleExecution = (func) => func,
shouldNavigateToTopMostReport = false,
}) {
}: HeaderWithBackButtonProps) {
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 (
<View
// Hover on some part of close icons will not work on Electron if dragArea is true
Expand Down Expand Up @@ -114,25 +116,25 @@ function HeaderWithBackButton({
{shouldShowDownloadButton && (
<Tooltip text={translate('common.download')}>
<PressableWithoutFeedback
onPress={(e) => {
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"
accessibilityLabel={translate('common.download')}
>
<Icon
src={Expensicons.Download}
fill={iconFill || StyleUtils.getIconFillColor(getButtonState(false, false, !isDownloadButtonActive))}
fill={iconFill ?? StyleUtils.getIconFillColor(getButtonState(false, false, !isDownloadButtonActive))}
/>
</PressableWithoutFeedback>
</Tooltip>
Expand All @@ -153,7 +155,7 @@ function HeaderWithBackButton({
</PressableWithoutFeedback>
</Tooltip>
)}
{shouldShowPinButton && <PinButton report={report} />}
{shouldShowPinButton && !!report && <PinButton report={report} />}
{shouldShowThreeDotsButton && (
<ThreeDotsMenu
disabled={shouldDisableThreeDotsButton}
Expand Down Expand Up @@ -184,7 +186,6 @@ function HeaderWithBackButton({
);
}

HeaderWithBackButton.propTypes = headerWithBackButtonPropTypes;
HeaderWithBackButton.displayName = 'HeaderWithBackButton';

export default HeaderWithBackButton;
120 changes: 120 additions & 0 deletions src/components/HeaderWithBackButton/types.ts
VickyStash marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import React, {ReactElement} from 'react';
import {OnyxCollection, OnyxEntry} from 'react-native-onyx';
import type {SvgProps} from 'react-native-svg';
import type {Action} from '@hooks/useSingleExecution';
import type {StepCounterParams} from '@src/languages/types';
import type {PersonalDetails, Policy, Report} from '@src/types/onyx';
import type ChildrenProps from '@src/types/utils/ChildrenProps';

type ThreeDotsAnchorPosition = {
VickyStash marked this conversation as resolved.
Show resolved Hide resolved
/** The vertical anchor position of the three dots menu */
vertical: number;

/** The horizontal anchor position of the three dots menu */
horizontal: number;
};

type ThreeDotsMenuItems = {
/** An icon element displayed on the left side */
icon?: React.FC<SvgProps>;
VickyStash marked this conversation as resolved.
Show resolved Hide resolved

/** 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: string | ReactElement;
VickyStash marked this conversation as resolved.
Show resolved Hide resolved

/** 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?: ThreeDotsAnchorPosition;

/** 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>;

/** Report, if we're showing the details for one and using AvatarWithDisplay */
report?: OnyxEntry<Report>;

/** The report's policy, if we're showing the details for a report and need info about it for AvatarWithDisplay */
policy?: OnyxEntry<Policy>;

/** Policies, if we're showing the details for a report and need participant details for AvatarWithDisplay */
personalDetails: OnyxCollection<PersonalDetails>;
VickyStash marked this conversation as resolved.
Show resolved Hide resolved

/** Single execution function to prevent concurrent navigation actions */
singleExecution: <T extends unknown[]>(action: Action<T>) => Action<T>;

/** 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;
2 changes: 1 addition & 1 deletion src/components/Pressable/GenericPressable/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type PressableProps = RNPressableProps &
/**
* onPress callback
*/
onPress: (event?: GestureResponderEvent | KeyboardEvent) => void;
onPress: (event?: GestureResponderEvent | KeyboardEvent) => void | Promise<void>;

/**
* Specifies keyboard shortcut to trigger onPressHandler
Expand Down
2 changes: 2 additions & 0 deletions src/hooks/useSingleExecution/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@ export default function useSingleExecution() {

return {isExecuting: false, singleExecution};
}

export type {Action};
Loading