Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 3 additions & 3 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6925,9 +6925,9 @@ const CONST = {
},
LAST_PAYMENT_METHOD: {
LAST_USED: 'lastUsed',
IOU: 'iou',
EXPENSE: 'expense',
INVOICE: 'invoice',
IOU: 'Iou',
EXPENSE: 'Expense',
INVOICE: 'Invoice',
},
SKIPPABLE_COLLECTION_MEMBER_IDS: [String(DEFAULT_NUMBER_ID), '-1', 'undefined', 'null', 'NaN'] as string[],
SETUP_SPECIALIST_LOGIN: 'Setup Specialist',
Expand Down
14 changes: 1 addition & 13 deletions src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -310,19 +310,7 @@ function Button(
const textComponent = secondLineText ? (
<View style={[styles.alignItemsCenter, styles.flexColumn, styles.flexShrink1]}>
{primaryText}
<Text
style={[
isLoading && styles.opacity0,
styles.pointerEventsNone,
styles.fontWeightNormal,
styles.textDoubleDecker,
!!secondLineText && styles.textExtraSmallSupporting,
styles.textWhite,
styles.textBold,
]}
>
{secondLineText}
</Text>
<Text style={[isLoading && styles.opacity0, styles.pointerEventsNone, styles.fontWeightNormal, styles.textDoubleDecker]}>{secondLineText}</Text>
</View>
) : (
primaryText
Expand Down
45 changes: 8 additions & 37 deletions src/components/ButtonWithDropdownMenu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import mergeRefs from '@libs/mergeRefs';
import variables from '@styles/variables';
import CONST from '@src/CONST';
import type {AnchorPosition} from '@src/styles';
import type {ButtonWithDropdownMenuProps} from './types';
Expand Down Expand Up @@ -57,10 +56,7 @@ function ButtonWithDropdownMenuInner<IValueType>(props: ButtonWithDropdownMenuPr
testID,
secondLineText = '',
icon,
shouldPopoverUseScrollView = false,
containerStyles,
shouldUseModalPaddingStyle = true,
shouldUseShortForm = false,
shouldUseOptionIcon = false,
} = props;

Expand All @@ -83,14 +79,9 @@ function ButtonWithDropdownMenuInner<IValueType>(props: ButtonWithDropdownMenuPr
const areAllOptionsDisabled = options.every((option) => option.disabled);
const innerStyleDropButton = StyleUtils.getDropDownButtonHeight(buttonSize);
const isButtonSizeLarge = buttonSize === CONST.DROPDOWN_BUTTON_SIZE.LARGE;
const isButtonSizeSmall = buttonSize === CONST.DROPDOWN_BUTTON_SIZE.SMALL;
const nullCheckRef = (refParam: RefObject<View | null>) => refParam ?? null;
const shouldShowButtonRightIcon = !!options.at(0)?.shouldShowButtonRightIcon;

useEffect(() => {
setSelectedItemIndex(defaultSelectedIndex);
}, [defaultSelectedIndex]);

const {paddingBottom} = useSafeAreaPaddings(true);

useEffect(() => {
Expand Down Expand Up @@ -162,7 +153,6 @@ function ButtonWithDropdownMenuInner<IValueType>(props: ButtonWithDropdownMenuPr
},
);
const splitButtonWrapperStyle = isSplitButton ? [styles.flexRow, styles.justifyContentBetween, styles.alignItemsCenter] : {};
const isTextTooLong = customText && customText?.length > 6;

const handlePress = useCallback(
(event?: GestureResponderEvent | KeyboardEvent) => {
Expand Down Expand Up @@ -196,13 +186,12 @@ function ButtonWithDropdownMenuInner<IValueType>(props: ButtonWithDropdownMenuPr
large={buttonSize === CONST.DROPDOWN_BUTTON_SIZE.LARGE}
medium={buttonSize === CONST.DROPDOWN_BUTTON_SIZE.MEDIUM}
small={buttonSize === CONST.DROPDOWN_BUTTON_SIZE.SMALL}
innerStyles={[innerStyleDropButton, !isSplitButton && styles.dropDownButtonCartIconView, isTextTooLong && shouldUseShortForm && {...styles.pl2, ...styles.pr1}]}
innerStyles={[innerStyleDropButton, !isSplitButton && styles.dropDownButtonCartIconView]}
enterKeyEventListenerPriority={enterKeyEventListenerPriority}
iconRight={Expensicons.DownArrow}
shouldShowRightIcon={!isSplitButton}
isSplitButton={isSplitButton}
testID={testID}
textStyles={[isTextTooLong && shouldUseShortForm ? {...styles.textExtraSmall, ...styles.textBold} : {}]}
secondLineText={secondLineText}
icon={icon}
/>
Expand All @@ -218,25 +207,16 @@ function ButtonWithDropdownMenuInner<IValueType>(props: ButtonWithDropdownMenuPr
large={buttonSize === CONST.DROPDOWN_BUTTON_SIZE.LARGE}
medium={buttonSize === CONST.DROPDOWN_BUTTON_SIZE.MEDIUM}
small={buttonSize === CONST.DROPDOWN_BUTTON_SIZE.SMALL}
innerStyles={[styles.dropDownButtonCartIconContainerPadding, innerStyleDropButton, isButtonSizeSmall && styles.dropDownButtonCartIcon]}
innerStyles={[styles.dropDownButtonCartIconContainerPadding, innerStyleDropButton]}
enterKeyEventListenerPriority={enterKeyEventListenerPriority}
>
<View style={[styles.dropDownButtonCartIconView, innerStyleDropButton]}>
<View style={[success ? styles.buttonSuccessDivider : styles.buttonDivider]} />
<View
style={[
isButtonSizeLarge && styles.dropDownLargeButtonArrowContain,
isButtonSizeSmall && shouldUseShortForm ? styles.dropDownSmallButtonArrowContain : styles.dropDownMediumButtonArrowContain,
]}
>
<View style={[isButtonSizeLarge ? styles.dropDownLargeButtonArrowContain : styles.dropDownMediumButtonArrowContain]}>
<Icon
medium={isButtonSizeLarge}
small={!isButtonSizeLarge && !shouldUseShortForm}
inline={shouldUseShortForm}
width={shouldUseShortForm ? variables.iconSizeExtraSmall : undefined}
height={shouldUseShortForm ? variables.iconSizeExtraSmall : undefined}
small={!isButtonSizeLarge}
src={Expensicons.DownArrow}
additionalStyles={shouldUseShortForm ? [styles.pRelative, styles.t0] : undefined}
fill={success ? theme.buttonSuccessText : theme.icon}
/>
</View>
Expand Down Expand Up @@ -286,27 +266,18 @@ function ButtonWithDropdownMenuInner<IValueType>(props: ButtonWithDropdownMenuPr
shouldShowSelectedItemCheck={shouldShowSelectedItemCheck}
// eslint-disable-next-line react-compiler/react-compiler
anchorRef={nullCheckRef(dropdownAnchor)}
withoutOverlay
shouldUseScrollView
scrollContainerStyle={!shouldUseModalPaddingStyle && isSmallScreenWidth && {...styles.pt4, paddingBottom}}
anchorAlignment={anchorAlignment}
shouldUseModalPaddingStyle={shouldUseModalPaddingStyle}
anchorAlignment={anchorAlignment}
headerText={menuHeaderText}
shouldUseScrollView={shouldPopoverUseScrollView}
containerStyles={containerStyles}
menuItems={options.map((item, index) => ({
...item,
onSelected: item.onSelected
? () => {
item.onSelected?.();
if (item.shouldUpdateSelectedIndex) {
setSelectedItemIndex(index);
}
}
? () => item.onSelected?.()
: () => {
onOptionSelected?.(item);
if (item.shouldUpdateSelectedIndex === false) {
return;
}

setSelectedItemIndex(index);
},
shouldCallAfterModalHide: true,
Expand Down
11 changes: 0 additions & 11 deletions src/components/ButtonWithDropdownMenu/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ type DropdownOption<TValueType> = {
descriptionTextStyle?: StyleProp<TextStyle>;
wrapperStyle?: StyleProp<ViewStyle>;
displayInDefaultIconColor?: boolean;
/** Whether the selected index should be updated when the option is selected even if we have onSelected callback */
shouldUpdateSelectedIndex?: boolean;
subMenuItems?: PopoverMenuItem[];
backButtonText?: string;
avatarSize?: ValueOf<typeof CONST.AVATAR_SIZE>;
Expand Down Expand Up @@ -145,18 +143,9 @@ type ButtonWithDropdownMenuProps<TValueType> = {
/** Icon for main button */
icon?: IconAsset;

/** Whether the popover content should be scrollable */
shouldPopoverUseScrollView?: boolean;

/** Container style to be applied to the popover of the dropdown menu */
containerStyles?: StyleProp<ViewStyle>;

/** Whether to use modal padding style for the popover menu */
shouldUseModalPaddingStyle?: boolean;

/** Whether to use short form for the button */
shouldUseShortForm?: boolean;

/** Whether to display the option icon when only one option is available */
shouldUseOptionIcon?: boolean;
};
Expand Down
70 changes: 10 additions & 60 deletions src/components/KYCWall/BaseKYCWall.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@ import React, {useCallback, useEffect, useRef, useState} from 'react';
import {Dimensions} from 'react-native';
import type {EmitterSubscription, GestureResponderEvent, View} from 'react-native';
import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
import {openPersonalBankAccountSetupView} from '@libs/actions/BankAccounts';
import {completePaymentOnboarding, savePreferredPaymentMethod} from '@libs/actions/IOU';
import {moveIOUReportToPolicy, moveIOUReportToPolicyAndInviteSubmitter} from '@libs/actions/Report';
import {completePaymentOnboarding} from '@libs/actions/IOU';
import getClickedTargetLocation from '@libs/getClickedTargetLocation';
import Log from '@libs/Log';
import Navigation from '@libs/Navigation/Navigation';
import {hasExpensifyPaymentMethod} from '@libs/PaymentUtils';
import {getBankAccountRoute, getPolicyExpenseChat, isExpenseReport as isExpenseReportReportUtils, isIOUReport} from '@libs/ReportUtils';
import {getBankAccountRoute, isExpenseReport as isExpenseReportReportUtils, isIOUReport} from '@libs/ReportUtils';
import {kycWallRef} from '@userActions/PaymentMethods';
import {createWorkspaceFromIOUPayment} from '@userActions/Policy/Policy';
import {setKYCWallSource} from '@userActions/Wallet';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {BankAccountList, Policy} from '@src/types/onyx';
import type {BankAccountList} from '@src/types/onyx';
import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
import {getEmptyObject} from '@src/types/utils/EmptyObject';
import viewRef from '@src/types/utils/viewRef';
Expand Down Expand Up @@ -56,8 +54,6 @@ function KYCWall({
const [reimbursementAccount] = useOnyx(ONYXKEYS.REIMBURSEMENT_ACCOUNT, {canBeMissing: true});
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${chatReportID}`, {canBeMissing: true});

const {formatPhoneNumber} = useLocalize();

const anchorRef = useRef<HTMLDivElement | View>(null);
const transferBalanceButtonRef = useRef<HTMLDivElement | View | null>(null);

Expand All @@ -68,8 +64,6 @@ function KYCWall({
anchorPositionHorizontal: 0,
});

const [lastPaymentMethod] = useOnyx(ONYXKEYS.NVP_LAST_PAYMENT_METHOD, {canBeMissing: true});

const getAnchorPosition = useCallback(
(domRect: DomRect): AnchorPosition => {
if (anchorAlignment.vertical === CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP) {
Expand Down Expand Up @@ -109,55 +103,31 @@ function KYCWall({
}, [getAnchorPosition]);

const selectPaymentMethod = useCallback(
(paymentMethod?: PaymentMethod, policy?: Policy) => {
if (paymentMethod) {
onSelectPaymentMethod(paymentMethod);
}
(paymentMethod: PaymentMethod) => {
onSelectPaymentMethod(paymentMethod);

if (paymentMethod === CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT) {
openPersonalBankAccountSetupView({shouldSetUpUSBankAccount: isIOUReport(iouReport)});
} else if (paymentMethod === CONST.PAYMENT_METHODS.DEBIT_CARD) {
Navigation.navigate(addDebitCardRoute ?? ROUTES.HOME);
} else if (paymentMethod === CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT || policy) {
} else if (paymentMethod === CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT) {
if (iouReport && isIOUReport(iouReport)) {
if (policy) {
const policyExpenseChatReportID = getPolicyExpenseChat(iouReport.ownerAccountID, policy.id)?.reportID;
if (!policyExpenseChatReportID) {
const {policyExpenseChatReportID: newPolicyExpenseChatReportID} = moveIOUReportToPolicyAndInviteSubmitter(iouReport.reportID, policy.id, formatPhoneNumber) ?? {};
savePreferredPaymentMethod(iouReport.policyID, policy.id, CONST.LAST_PAYMENT_METHOD.IOU, lastPaymentMethod?.[policy.id]);
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(newPolicyExpenseChatReportID));
} else {
moveIOUReportToPolicy(iouReport.reportID, policy.id, true);
savePreferredPaymentMethod(iouReport.policyID, policy.id, CONST.LAST_PAYMENT_METHOD.IOU, lastPaymentMethod?.[policy.id]);
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(policyExpenseChatReportID));
}

if (policy?.achAccount) {
return;
}
// Navigate to the bank account set up flow for this specific policy
Navigation.navigate(ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute(policy.id));
return;
}

const {policyID, workspaceChatReportID, reportPreviewReportActionID, adminsChatReportID} = createWorkspaceFromIOUPayment(iouReport) ?? {};
if (policyID && iouReport?.policyID) {
savePreferredPaymentMethod(iouReport.policyID, policyID, CONST.LAST_PAYMENT_METHOD.IOU, lastPaymentMethod?.[iouReport?.policyID]);
}
completePaymentOnboarding(CONST.PAYMENT_SELECTED.BBA, adminsChatReportID, policyID);
if (workspaceChatReportID) {
Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(workspaceChatReportID, reportPreviewReportActionID));
}

// Navigate to the bank account set up flow for this specific policy
Navigation.navigate(ROUTES.BANK_ACCOUNT_WITH_STEP_TO_OPEN.getRoute(policyID));

return;
}
const bankAccountRoute = addBankAccountRoute ?? getBankAccountRoute(chatReport);
Navigation.navigate(bankAccountRoute);
}
},
[addBankAccountRoute, addDebitCardRoute, chatReport, iouReport, onSelectPaymentMethod, formatPhoneNumber, lastPaymentMethod],
[addBankAccountRoute, addDebitCardRoute, chatReport, iouReport, onSelectPaymentMethod],
);

/**
Expand All @@ -167,7 +137,7 @@ function KYCWall({
*
*/
const continueAction = useCallback(
(event?: GestureResponderEvent | KeyboardEvent, iouPaymentType?: PaymentMethodType, paymentMethod?: PaymentMethod, policy?: Policy) => {
(event?: GestureResponderEvent | KeyboardEvent, iouPaymentType?: PaymentMethodType) => {
const currentSource = walletTerms?.source ?? source;

/**
Expand Down Expand Up @@ -201,19 +171,6 @@ function KYCWall({
return;
}

// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
if (paymentMethod || policy) {
setShouldShowAddPaymentMenu(false);
selectPaymentMethod(paymentMethod, policy);
return;
}

if (iouPaymentType && isExpenseReport) {
setShouldShowAddPaymentMenu(false);
selectPaymentMethod(CONST.PAYMENT_METHODS.BUSINESS_BANK_ACCOUNT);
return;
}

const clickedElementLocation = getClickedTargetLocation(targetElement as HTMLDivElement);
const position = getAnchorPosition(clickedElementLocation);

Expand All @@ -226,20 +183,13 @@ function KYCWall({
// Ask the user to upgrade to a gold wallet as this means they have not yet gone through our Know Your Customer (KYC) checks
const hasActivatedWallet = userWallet?.tierName && [CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM].some((name) => name === userWallet.tierName);

if (!hasActivatedWallet && !policy) {
if (!hasActivatedWallet) {
Log.info('[KYC Wallet] User does not have active wallet');

Navigation.navigate(enablePaymentsRoute);

return;
}

// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
if (policy || (paymentMethod && (!hasActivatedWallet || paymentMethod !== CONST.PAYMENT_METHODS.PERSONAL_BANK_ACCOUNT))) {
setShouldShowAddPaymentMenu(false);
selectPaymentMethod(paymentMethod, policy);
return;
}
}

Log.info('[KYC Wallet] User has valid payment method and passed KYC checks or did not need them');
Expand Down
5 changes: 1 addition & 4 deletions src/components/KYCWall/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import type {OnyxEntry} from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import type CONST from '@src/CONST';
import type {Route} from '@src/ROUTES';
import type {Policy, Report} from '@src/types/onyx';
import type {Report} from '@src/types/onyx';
import type {PaymentMethodType} from '@src/types/onyx/OriginalMessage';
import type AnchorAlignment from '@src/types/utils/AnchorAlignment';

Expand Down Expand Up @@ -63,9 +63,6 @@ type KYCWallProps = {

/** Children to build the KYC */
children: (continueAction: (event: GestureResponderEvent | KeyboardEvent | undefined, method?: PaymentMethodType) => void, anchorRef: RefObject<View | null>) => void;

/** The policy used for payment */
policy?: Policy;
};

export type {AnchorPosition, KYCWallProps, PaymentMethod, DomRect, PaymentMethodType, Source};
Loading
Loading