diff --git a/src/components/HeaderWithBackButton/types.ts b/src/components/HeaderWithBackButton/types.ts index 9ffb0b5ef2f3..55cc9e708771 100644 --- a/src/components/HeaderWithBackButton/types.ts +++ b/src/components/HeaderWithBackButton/types.ts @@ -7,7 +7,7 @@ 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 = { +type ThreeDotsMenuItem = { /** An icon element displayed on the left side */ icon?: IconAsset; @@ -62,7 +62,7 @@ type HeaderWithBackButtonProps = Partial & { shouldDisableThreeDotsButton?: boolean; /** List of menu items for more(three dots) menu */ - threeDotsMenuItems?: ThreeDotsMenuItems[]; + threeDotsMenuItems?: ThreeDotsMenuItem[]; /** The anchor position of the menu */ threeDotsAnchorPosition?: AnchorPosition; @@ -110,4 +110,5 @@ type HeaderWithBackButtonProps = Partial & { shouldEnableDetailPageNavigation?: boolean; }; +export type {ThreeDotsMenuItem}; export default HeaderWithBackButtonProps; diff --git a/src/components/MoneyReportHeader.js b/src/components/MoneyReportHeader.tsx similarity index 78% rename from src/components/MoneyReportHeader.js rename to src/components/MoneyReportHeader.tsx index ce1c9611c733..a712438bb07c 100644 --- a/src/components/MoneyReportHeader.js +++ b/src/components/MoneyReportHeader.tsx @@ -1,96 +1,66 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; import React, {useCallback, useMemo, useState} from 'react'; import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; -import _ from 'underscore'; import GoogleMeetIcon from '@assets/images/google-meet.svg'; import ZoomIcon from '@assets/images/zoom-icon.svg'; import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; -import compose from '@libs/compose'; import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as HeaderUtils from '@libs/HeaderUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as ReportUtils from '@libs/ReportUtils'; -import iouReportPropTypes from '@pages/iouReportPropTypes'; -import nextStepPropTypes from '@pages/nextStepPropTypes'; -import reportPropTypes from '@pages/reportPropTypes'; import * as IOU from '@userActions/IOU'; import * as Link from '@userActions/Link'; import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; +import type * as OnyxTypes from '@src/types/onyx'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; import Button from './Button'; import ConfirmModal from './ConfirmModal'; import HeaderWithBackButton from './HeaderWithBackButton'; import * as Expensicons from './Icon/Expensicons'; import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar'; -import participantPropTypes from './participantPropTypes'; import SettlementButton from './SettlementButton'; -import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; -const propTypes = { - /** The report currently being looked at */ - report: iouReportPropTypes.isRequired, - - /** The policy tied to the money request report */ - policy: PropTypes.shape({ - /** Name of the policy */ - name: PropTypes.string, - - /** Type of the policy */ - type: PropTypes.string, - - /** The role of the current user in the policy */ - role: PropTypes.string, - - /** Whether Scheduled Submit is turned on for this policy */ - isHarvestingEnabled: PropTypes.bool, - }), +type PaymentType = DeepValueOf; +type MoneyReportHeaderOnyxProps = { /** The chat report this report is linked to */ - chatReport: reportPropTypes, + chatReport: OnyxEntry; /** The next step for the report */ - nextStep: nextStepPropTypes, - - /** Personal details so we can get the ones for the report participants */ - personalDetails: PropTypes.objectOf(participantPropTypes).isRequired, + nextStep: OnyxEntry; /** Session info for the currently logged in user. */ - session: PropTypes.shape({ - /** Currently logged in user email */ - email: PropTypes.string, - }), - - ...windowDimensionsPropTypes, + session: OnyxEntry; }; -const defaultProps = { - chatReport: {}, - nextStep: {}, - session: { - email: null, - }, - policy: { - isHarvestingEnabled: false, - }, +type MoneyReportHeaderProps = MoneyReportHeaderOnyxProps & { + /** The report currently being looked at */ + report: OnyxTypes.Report; + + /** The policy tied to the money request report */ + policy: OnyxTypes.Policy; + + /** Personal details so we can get the ones for the report participants */ + personalDetails: OnyxTypes.PersonalDetailsList; }; -function MoneyReportHeader({session, personalDetails, policy, chatReport, nextStep, report: moneyRequestReport, isSmallScreenWidth}) { +function MoneyReportHeader({session, personalDetails, policy, chatReport, nextStep, report: moneyRequestReport}: MoneyReportHeaderProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const {windowWidth} = useWindowDimensions(); + const {windowWidth, isSmallScreenWidth} = useWindowDimensions(); const reimbursableTotal = ReportUtils.getMoneyRequestReimbursableTotal(moneyRequestReport); const isApproved = ReportUtils.isReportApproved(moneyRequestReport); const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID); - const policyType = lodashGet(policy, 'type'); - const isPolicyAdmin = policyType !== CONST.POLICY.TYPE.PERSONAL && lodashGet(policy, 'role') === CONST.POLICY.ROLE.ADMIN; + const policyType = policy?.type; + const isPolicyAdmin = policyType !== CONST.POLICY.TYPE.PERSONAL && policy?.role === CONST.POLICY.ROLE.ADMIN; const isPaidGroupPolicy = ReportUtils.isPaidGroupPolicy(moneyRequestReport); - const isManager = ReportUtils.isMoneyRequestReport(moneyRequestReport) && lodashGet(session, 'accountID', null) === moneyRequestReport.managerID; + const isManager = ReportUtils.isMoneyRequestReport(moneyRequestReport) && session?.accountID === moneyRequestReport.managerID; const isPayer = isPaidGroupPolicy ? // In a group policy, the admin approver can pay the report directly by skipping the approval step isPolicyAdmin && (isApproved || isManager) @@ -99,6 +69,7 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false); const cancelPayment = useCallback(() => { + // @ts-expect-error TODO: Remove this once IOU (https://github.com/Expensify/App/issues/24926) is migrated to TypeScript. IOU.cancelPayment(moneyRequestReport, chatReport); setIsConfirmModalVisible(false); }, [moneyRequestReport, chatReport]); @@ -116,7 +87,7 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt const shouldShowSettlementButton = shouldShowPayButton || shouldShowApproveButton; const shouldShowSubmitButton = isDraft && reimbursableTotal !== 0; const isFromPaidPolicy = policyType === CONST.POLICY.TYPE.TEAM || policyType === CONST.POLICY.TYPE.CORPORATE; - const shouldShowNextStep = isFromPaidPolicy && nextStep && !_.isEmpty(nextStep.message); + const shouldShowNextStep = isFromPaidPolicy && !!nextStep?.message?.length; const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton || shouldShowNextStep; const bankAccountRoute = ReportUtils.getBankAccountRoute(chatReport); const formattedAmount = CurrencyUtils.convertToDisplayString(reimbursableTotal, moneyRequestReport.currency); @@ -124,8 +95,8 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt // The submit button should be success green colour only if the user is submitter and the policy does not have Scheduled Submit turned on const isWaitingForSubmissionFromCurrentUser = useMemo( - () => chatReport.isOwnPolicyExpenseChat && !policy.isHarvestingEnabled, - [chatReport.isOwnPolicyExpenseChat, policy.isHarvestingEnabled], + () => chatReport?.isOwnPolicyExpenseChat && !policy.isHarvestingEnabled, + [chatReport?.isOwnPolicyExpenseChat, policy.isHarvestingEnabled], ); const threeDotsMenuItems = [HeaderUtils.getPinMenuItem(moneyRequestReport)]; @@ -173,11 +144,13 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt {shouldShowSettlementButton && !isSmallScreenWidth && ( IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)} + // @ts-expect-error TODO: Remove this once IOU (https://github.com/Expensify/App/issues/24926) is migrated to TypeScript. + onPress={(paymentType: PaymentType) => IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} @@ -203,11 +176,13 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt {shouldShowSettlementButton && isSmallScreenWidth && ( IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)} + // @ts-expect-error TODO: Remove this once IOU (https://github.com/Expensify/App/issues/24926) is migrated to TypeScript. + onPress={(paymentType: PaymentType) => IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)} enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS} addBankAccountRoute={bankAccountRoute} shouldHidePaymentOptions={!shouldShowPayButton} @@ -248,20 +223,15 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, nextSt } MoneyReportHeader.displayName = 'MoneyReportHeader'; -MoneyReportHeader.propTypes = propTypes; -MoneyReportHeader.defaultProps = defaultProps; -export default compose( - withWindowDimensions, - withOnyx({ - chatReport: { - key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`, - }, - nextStep: { - key: ({report}) => `${ONYXKEYS.COLLECTION.NEXT_STEP}${report.reportID}`, - }, - session: { - key: ONYXKEYS.SESSION, - }, - }), -)(MoneyReportHeader); +export default withOnyx({ + chatReport: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.chatReportID}`, + }, + nextStep: { + key: ({report}) => `${ONYXKEYS.COLLECTION.NEXT_STEP}${report.reportID}`, + }, + session: { + key: ONYXKEYS.SESSION, + }, +})(MoneyReportHeader); diff --git a/src/libs/HeaderUtils.ts b/src/libs/HeaderUtils.ts index a1822aca00f4..4d58d74169e8 100644 --- a/src/libs/HeaderUtils.ts +++ b/src/libs/HeaderUtils.ts @@ -1,22 +1,11 @@ -import type {OnyxEntry} from 'react-native-onyx'; +import type {ThreeDotsMenuItem} from '@components/HeaderWithBackButton/types'; import * as Expensicons from '@components/Icon/Expensicons'; import type OnyxReport from '@src/types/onyx/Report'; -import type IconAsset from '@src/types/utils/IconAsset'; import * as Report from './actions/Report'; import * as Session from './actions/Session'; import * as Localize from './Localize'; -type MenuItem = { - icon: string | IconAsset; - text: string; - onSelected: () => void; -}; - -function getPinMenuItem(report: OnyxEntry): MenuItem | undefined { - if (!report) { - return; - } - +function getPinMenuItem(report: OnyxReport): ThreeDotsMenuItem { const isPinned = !!report.isPinned; return {