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 'SettlementButton.js' component to TypeScript #33866

Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
10cb535
Migrate SettlementButton.js component to TypeScript
ZhenjaHorbach Jan 3, 2024
53e4b00
Update types
ZhenjaHorbach Jan 3, 2024
b9ff896
Update branch
ZhenjaHorbach Jan 5, 2024
dcdf95b
Update types
ZhenjaHorbach Jan 5, 2024
f3004da
Update types x2
ZhenjaHorbach Jan 5, 2024
79046f0
Update branch
ZhenjaHorbach Jan 8, 2024
c92cde7
Fix ts issue
ZhenjaHorbach Jan 8, 2024
3fec057
Fix comments
ZhenjaHorbach Jan 9, 2024
5754adc
Update type imports
ZhenjaHorbach Jan 10, 2024
ef7487a
Fix comments
ZhenjaHorbach Jan 10, 2024
c2d9c88
Fix comments x2
ZhenjaHorbach Jan 10, 2024
a579a3b
Update branch
ZhenjaHorbach Jan 12, 2024
9cde0a6
Update branch
ZhenjaHorbach Jan 16, 2024
baf50f2
Refactor types
ZhenjaHorbach Jan 16, 2024
58ef4e6
Update branch
ZhenjaHorbach Jan 17, 2024
753fdc9
Update branch
ZhenjaHorbach Jan 19, 2024
d078c10
Update types PART-1
ZhenjaHorbach Jan 19, 2024
2d7f408
Update types PART-2
ZhenjaHorbach Jan 21, 2024
44e688c
Update types PART-3
ZhenjaHorbach Jan 22, 2024
3fadd8a
Update types PART-4
ZhenjaHorbach Jan 22, 2024
907ece0
Update types PART-5
ZhenjaHorbach Jan 22, 2024
9cb7f8a
Update types PART-6
ZhenjaHorbach Jan 22, 2024
04d9399
Update branch
ZhenjaHorbach Jan 22, 2024
085e17d
Update branch
ZhenjaHorbach Jan 24, 2024
8e934fa
Update createWorkspaceFromIOUPayment
ZhenjaHorbach Jan 24, 2024
df8eea2
Update branch
ZhenjaHorbach Jan 25, 2024
47b8c2a
Fix ts issue
ZhenjaHorbach Jan 25, 2024
48748d1
Fix comments
ZhenjaHorbach Jan 25, 2024
3ea1082
Update branch
ZhenjaHorbach Jan 31, 2024
000d9ab
Update types
ZhenjaHorbach Jan 31, 2024
2976d2f
Merge branch 'main' into migrate-settlementbutton-component-to-ts
ZhenjaHorbach Jan 31, 2024
807230f
Update branch
ZhenjaHorbach Feb 1, 2024
e645f46
Fix lint issue
ZhenjaHorbach Feb 1, 2024
2ebbbf0
Update branch
ZhenjaHorbach Feb 4, 2024
056dea9
Update branch
ZhenjaHorbach Feb 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/components/KYCWall/kycWallPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ const propTypes = {

/** Whether the personal bank account option should be shown */
shouldShowPersonalBankAccountOption: PropTypes.bool,

/** Callback to execute when KYC is successful */
onSuccessfulKYC: PropTypes.func.isRequired,

children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired,
};

const defaultProps = {
Expand Down
13 changes: 2 additions & 11 deletions src/components/Popover/types.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,7 @@
import type {ValueOf} from 'type-fest';
import type {PopoverAnchorPosition} from '@components/Modal/types';
import type BaseModalProps from '@components/Modal/types';
import type {WindowDimensionsProps} from '@components/withWindowDimensions/types';
import type CONST from '@src/CONST';

type AnchorAlignment = {
/** The horizontal anchor alignment of the popover */
horizontal: ValueOf<typeof CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL>;

/** The vertical anchor alignment of the popover */
vertical: ValueOf<typeof CONST.MODAL.ANCHOR_ORIGIN_VERTICAL>;
};
import type {AnchorAlignment} from '@src/types/onyx';

type PopoverDimensions = {
width: number;
Expand Down Expand Up @@ -48,4 +39,4 @@ type PopoverProps = BaseModalProps & {

type PopoverWithWindowDimensionsProps = PopoverProps & WindowDimensionsProps;

export type {PopoverProps, PopoverWithWindowDimensionsProps, AnchorAlignment};
export type {PopoverProps, PopoverWithWindowDimensionsProps};
2 changes: 1 addition & 1 deletion src/components/PopoverMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import CONST from '@src/CONST';
import type {AnchorPosition} from '@src/styles';
import type {AnchorAlignment} from '@src/types/onyx';
import MenuItem from './MenuItem';
import type {AnchorAlignment} from './Popover/types';
import PopoverWithMeasuredContent from './PopoverWithMeasuredContent';
import Text from './Text';

Expand Down
2 changes: 1 addition & 1 deletion src/components/ProcessMoneyRequestHoldMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React from 'react';
import {View} from 'react-native';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import type {AnchorAlignment} from '@src/types/onyx';
import Button from './Button';
import HoldMenuSectionList from './HoldMenuSectionList';
import type {PopoverAnchorPosition} from './Modal/types';
import Popover from './Popover';
import type {AnchorAlignment} from './Popover/types';
import Text from './Text';
import TextPill from './TextPill';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,143 +1,125 @@
import PropTypes from 'prop-types';
import type {MutableRefObject} from 'react';
import React, {useEffect, useMemo} from 'react';
import type {GestureResponderEvent, StyleProp, View, ViewStyle} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import compose from '@libs/compose';
import * as ReportUtils from '@libs/ReportUtils';
import iouReportPropTypes from '@pages/iouReportPropTypes';
import * as BankAccounts from '@userActions/BankAccounts';
import * as IOU from '@userActions/IOU';
import * as PaymentMethods from '@userActions/PaymentMethods';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {ButtonSizeValue} from '@src/styles/utils/types';
import type {AnchorAlignment, LastPaymentMethod, Report} from '@src/types/onyx';
import type DeepValueOf from '@src/types/utils/DeepValueOf';
import type {EmptyObject} from '@src/types/utils/EmptyObject';
import ButtonWithDropdownMenu from './ButtonWithDropdownMenu';
import * as Expensicons from './Icon/Expensicons';
import KYCWall from './KYCWall';
import withNavigation from './withNavigation';

const propTypes = {
type KYCFlowEvent = GestureResponderEvent | KeyboardEvent;

type TriggerKYCFlow = (event: KYCFlowEvent, iouPaymentType: string) => void;

type PaymentType = DeepValueOf<typeof CONST.IOU.PAYMENT_TYPE | typeof CONST.IOU.REPORT_ACTION_TYPE>;

type SettlementButtonOnyxProps = {
/** The last payment method used per policy */
nvpLastPaymentMethod?: OnyxEntry<LastPaymentMethod>;
};

type SettlementButtonProps = SettlementButtonOnyxProps & {
/** Callback to execute when this button is pressed. Receives a single payment type argument. */
onPress: PropTypes.func.isRequired,
onPress: (paymentType: PaymentType) => void;

/** The route to redirect if user does not have a payment method setup */
enablePaymentsRoute: typeof ROUTES.ENABLE_PAYMENTS | typeof ROUTES.IOU_SEND_ENABLE_PAYMENTS | typeof ROUTES.SETTINGS_ENABLE_PAYMENTS;
ZhenjaHorbach marked this conversation as resolved.
Show resolved Hide resolved

ZhenjaHorbach marked this conversation as resolved.
Show resolved Hide resolved
/** Call the onPress function on main button when Enter key is pressed */
pressOnEnter: PropTypes.bool,
pressOnEnter?: boolean;

/** Settlement currency type */
currency: PropTypes.string,
currency?: string;

/** When the button is opened via an IOU, ID for the chatReport that the IOU is linked to */
chatReportID: PropTypes.string,
chatReportID?: string;

/** The IOU/Expense report we are paying */
iouReport: iouReportPropTypes,

/** The route to redirect if user does not have a payment method setup */
enablePaymentsRoute: PropTypes.string.isRequired,

/** Should we show the approve button? */
shouldHidePaymentOptions: PropTypes.bool,
iouReport?: OnyxEntry<Report> | EmptyObject;

/** Should we show the payment options? */
shouldShowApproveButton: PropTypes.bool,
shouldHidePaymentOptions?: boolean;

/** The last payment method used per policy */
nvp_lastPaymentMethod: PropTypes.objectOf(PropTypes.string),
/** Should we show the payment options? */
shouldShowApproveButton?: boolean;

/** The policyID of the report we are paying */
policyID: PropTypes.string,
policyID?: string;

/** Additional styles to add to the component */
style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
style?: StyleProp<ViewStyle>;

/** Total money amount in form <currency><amount> */
formattedAmount: PropTypes.string,
formattedAmount?: string;

/** The size of button size */
buttonSize: PropTypes.oneOf(_.values(CONST.DROPDOWN_BUTTON_SIZE)),
buttonSize?: ButtonSizeValue;

/** Route for the Add Bank Account screen for a given navigation stack */
addBankAccountRoute: PropTypes.string,
addBankAccountRoute?: string;

/** Route for the Add Debit Card screen for a given navigation stack */
addDebitCardRoute: PropTypes.string,
addDebitCardRoute?: string;

/** Whether the button should be disabled */
isDisabled: PropTypes.bool,
isDisabled?: boolean;

/** Whether we should show a loading state for the main button */
isLoading: PropTypes.bool,
isLoading?: boolean;

/** The anchor alignment of the popover menu for payment method dropdown */
paymentMethodDropdownAnchorAlignment: PropTypes.shape({
horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)),
vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)),
}),
paymentMethodDropdownAnchorAlignment?: AnchorAlignment;

/** The anchor alignment of the popover menu for KYC wall popover */
kycWallAnchorAlignment: PropTypes.shape({
horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)),
vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)),
}),
kycWallAnchorAlignment?: AnchorAlignment;

/** Whether the personal bank account option should be shown */
shouldShowPersonalBankAccountOption: PropTypes.bool,
shouldShowPersonalBankAccountOption?: boolean;
};

const defaultProps = {
isLoading: false,
isDisabled: false,
pressOnEnter: false,
addBankAccountRoute: '',
addDebitCardRoute: '',
currency: CONST.CURRENCY.USD,
chatReportID: '',

// The "iouReport" and "nvp_lastPaymentMethod" objects needs to be stable to prevent the "useMemo"
// hook from being recreated unnecessarily, hence the use of CONST.EMPTY_ARRAY and CONST.EMPTY_OBJECT
iouReport: CONST.EMPTY_OBJECT,
nvp_lastPaymentMethod: CONST.EMPTY_OBJECT,
shouldHidePaymentOptions: false,
shouldShowApproveButton: false,
style: [],
policyID: '',
formattedAmount: '',
buttonSize: CONST.DROPDOWN_BUTTON_SIZE.MEDIUM,
kycWallAnchorAlignment: {
function SettlementButton({
addDebitCardRoute = '',
addBankAccountRoute = '',
kycWallAnchorAlignment = {
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT, // button is at left, so horizontal anchor is at LEFT
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP, // we assume that popover menu opens below the button, anchor is at TOP
},
paymentMethodDropdownAnchorAlignment: {
paymentMethodDropdownAnchorAlignment = {
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT, // caret for dropdown is at right, so horizontal anchor is at RIGHT
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP, // we assume that popover menu opens below the button, anchor is at TOP
},
shouldShowPersonalBankAccountOption: false,
};

function SettlementButton({
addDebitCardRoute,
addBankAccountRoute,
kycWallAnchorAlignment,
paymentMethodDropdownAnchorAlignment,
buttonSize,
chatReportID,
currency,
buttonSize = CONST.DROPDOWN_BUTTON_SIZE.MEDIUM,
chatReportID = '',
currency = CONST.CURRENCY.USD,
enablePaymentsRoute,
iouReport,
isDisabled,
isLoading,
formattedAmount,
nvp_lastPaymentMethod,
// The "iouReport" and "nvpLastPaymentMethod" objects needs to be stable to prevent the "useMemo"
// hook from being recreated unnecessarily, hence the use of CONST.EMPTY_ARRAY and CONST.EMPTY_OBJECT
iouReport = CONST.EMPTY_OBJECT,
nvpLastPaymentMethod = CONST.EMPTY_OBJECT,
isDisabled = false,
isLoading = false,
formattedAmount = '',
onPress,
pressOnEnter,
policyID,
shouldHidePaymentOptions,
shouldShowApproveButton,
pressOnEnter = false,
policyID = '',
shouldHidePaymentOptions = false,
shouldShowApproveButton = false,
style,
shouldShowPersonalBankAccountOption,
}) {
shouldShowPersonalBankAccountOption = false,
}: SettlementButtonProps) {
const {translate} = useLocalize();
const {isOffline} = useNetwork();

Expand Down Expand Up @@ -179,7 +161,7 @@ function SettlementButton({

// To achieve the one tap pay experience we need to choose the correct payment type as default,
// if user already paid for some request or expense, let's use the last payment method or use default.
const paymentMethod = nvp_lastPaymentMethod[policyID] || '';
const paymentMethod = nvpLastPaymentMethod?.[policyID] ?? '';
if (canUseWallet) {
buttonOptions.push(paymentMethods[CONST.IOU.PAYMENT_TYPE.EXPENSIFY]);
}
Expand All @@ -194,12 +176,12 @@ function SettlementButton({

// Put the preferred payment method to the front of the array so its shown as default
if (paymentMethod) {
return _.sortBy(buttonOptions, (method) => (method.value === paymentMethod ? 0 : 1));
return buttonOptions.sort((method) => (method.value === paymentMethod ? 0 : 1));
}
Copy link
Contributor

@ishpaul777 ishpaul777 Feb 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This caused a regression here #36066, RC- syntax different between Array.sort and sortBy

return buttonOptions;
}, [currency, formattedAmount, iouReport, nvp_lastPaymentMethod, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton]);
}, [currency, formattedAmount, iouReport, nvpLastPaymentMethod, policyID, translate, shouldHidePaymentOptions, shouldShowApproveButton]);

const selectPaymentType = (event, iouPaymentType, triggerKYCFlow) => {
const selectPaymentType = (event: KYCFlowEvent, iouPaymentType: PaymentType, triggerKYCFlow: TriggerKYCFlow) => {
if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) {
triggerKYCFlow(event, iouPaymentType);
BankAccounts.setPersonalBankAccountContinueKYCOnSuccess(ROUTES.ENABLE_PAYMENTS);
Expand Down Expand Up @@ -227,14 +209,15 @@ function SettlementButton({
anchorAlignment={kycWallAnchorAlignment}
shouldShowPersonalBankAccountOption={shouldShowPersonalBankAccountOption}
>
{(triggerKYCFlow, buttonRef) => (
{(triggerKYCFlow: TriggerKYCFlow, buttonRef: MutableRefObject<HTMLDivElement | View | null>) => (
<ButtonWithDropdownMenu
buttonRef={buttonRef}
isDisabled={isDisabled}
isLoading={isLoading}
onPress={(event, iouPaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)}
onPress={(event: KYCFlowEvent, iouPaymentType: PaymentType) => selectPaymentType(event, iouPaymentType, triggerKYCFlow)}
pressOnEnter={pressOnEnter}
ZhenjaHorbach marked this conversation as resolved.
Show resolved Hide resolved
options={paymentButtonOptions}
// @ts-expect-error TODO: Remove this once OptionsListUtils (https://github.com/Expensify/App/issues/25065) is migrated to TypeScript.
style={style}
buttonSize={buttonSize}
anchorAlignment={paymentMethodDropdownAnchorAlignment}
Expand All @@ -244,15 +227,11 @@ function SettlementButton({
);
}

SettlementButton.propTypes = propTypes;
SettlementButton.defaultProps = defaultProps;
SettlementButton.displayName = 'SettlementButton';

export default compose(
withNavigation,
withOnyx({
nvp_lastPaymentMethod: {
key: ONYXKEYS.NVP_LAST_PAYMENT_METHOD,
},
}),
)(SettlementButton);
export default withOnyx<SettlementButtonProps, SettlementButtonOnyxProps>({
nvpLastPaymentMethod: {
key: ONYXKEYS.NVP_LAST_PAYMENT_METHOD,
ZhenjaHorbach marked this conversation as resolved.
Show resolved Hide resolved
selector: (paymentMethod) => paymentMethod ?? {},
},
})(SettlementButton);
12 changes: 12 additions & 0 deletions src/types/onyx/AnchorAlignment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type {ValueOf} from 'type-fest';
import type CONST from '@src/CONST';

type AnchorAlignment = {
/** The horizontal anchor alignment of the popover */
horizontal: ValueOf<typeof CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL>;

/** The vertical anchor alignment of the popover */
vertical: ValueOf<typeof CONST.MODAL.ANCHOR_ORIGIN_VERTICAL>;
};

export default AnchorAlignment;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder that is it correct place to put type AnchorAlignment here? Should it be in src/types/utils?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It makes sense
Done )

3 changes: 3 additions & 0 deletions src/types/onyx/LastPaymentMethod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
type LastPaymentMethod = Record<string, string>;

export default LastPaymentMethod;
ZhenjaHorbach marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 4 additions & 0 deletions src/types/onyx/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type Account from './Account';
import type AccountData from './AccountData';
import type AnchorAlignment from './AnchorAlignment';
import type {BankAccountList} from './BankAccount';
import type BankAccount from './BankAccount';
import type Beta from './Beta';
Expand All @@ -15,6 +16,7 @@ import type FrequentlyUsedEmoji from './FrequentlyUsedEmoji';
import type {FundList} from './Fund';
import type Fund from './Fund';
import type IOU from './IOU';
import type LastPaymentMethod from './LastPaymentMethod';
import type Locale from './Locale';
import type {LoginList} from './Login';
import type Login from './Login';
Expand Down Expand Up @@ -137,4 +139,6 @@ export type {
ReportUserIsTyping,
PolicyReportField,
RecentlyUsedReportFields,
LastPaymentMethod,
AnchorAlignment,
};
Loading