diff --git a/src/components/AccountSwitcher.tsx b/src/components/AccountSwitcher.tsx
index 6a08eace0fe1..fc192585fc53 100644
--- a/src/components/AccountSwitcher.tsx
+++ b/src/components/AccountSwitcher.tsx
@@ -35,7 +35,7 @@ import {View} from 'react-native';
import type {PopoverMenuItem} from './PopoverMenu';
import Avatar from './Avatar';
-import Button from './Button';
+import Button from './ButtonComposed';
import {ModalActions} from './Modal/Global/ModalContext';
import PopoverMenu from './PopoverMenu';
import {useProductTrainingContext} from './ProductTrainingContext';
@@ -308,14 +308,14 @@ function AccountSwitcher({isScreenFocused}: AccountSwitcherProps) {
{/* View wrapper forwards the hover events Tooltip injects; Button doesn't pass them to its underlying pressable, so the tooltip wouldn't show without it */}
+ >
+ {translate('delegate.switch')}
+
+
)}
diff --git a/src/components/AddExistingExpenseFooter.tsx b/src/components/AddExistingExpenseFooter.tsx
index d4ff7530ebb2..10a7297f23d0 100644
--- a/src/components/AddExistingExpenseFooter.tsx
+++ b/src/components/AddExistingExpenseFooter.tsx
@@ -25,7 +25,7 @@ import type {OnyxEntry} from 'react-native-onyx';
import {isTrackIntentUserSelector} from '@selectors/Onboarding';
import React from 'react';
-import Button from './Button';
+import Button from './ButtonComposed';
import FormHelpMessage from './FormHelpMessage';
import {usePersonalDetails, useSession} from './OnyxListItemProvider';
@@ -132,14 +132,14 @@ function AddExistingExpenseFooter({selectedIds, report, reportToConfirm, policy,
/>
)}
+ >
+
+ {translate('iou.addExistingExpenseConfirm')}
+
>
);
}
diff --git a/src/components/AgentPromotionalBanner.tsx b/src/components/AgentPromotionalBanner.tsx
index 2ae5763cc878..ed245074ae25 100644
--- a/src/components/AgentPromotionalBanner.tsx
+++ b/src/components/AgentPromotionalBanner.tsx
@@ -5,13 +5,15 @@ import useThemeStyles from '@hooks/useThemeStyles';
import BillingBanner from '@pages/settings/Subscription/CardSection/BillingBanner/BillingBanner';
+import CONST from '@src/CONST';
+
import type {StyleProp, ViewStyle} from 'react-native';
import React, {useMemo} from 'react';
import {View} from 'react-native';
import Badge from './Badge';
-import Button from './Button';
+import Button from './ButtonComposed';
import Text from './Text';
type AgentPromotionalBannerProps = {
@@ -75,23 +77,23 @@ function AgentPromotionalBanner({title, subtitle, onDismiss, dismissSentryLabel,
return (
+ >
+ {ctaText ?? ''}
+
);
}
return (
+ >
+ {ctaText ?? ''}
+
);
}, [hasCta, shouldUseNarrowLayout, isInLandscapeMode, ctaText, onCtaPress, ctaSentryLabel, styles]);
diff --git a/src/components/AnonymousReportFooter.tsx b/src/components/AnonymousReportFooter.tsx
index 5c94592e2185..2e728753722a 100644
--- a/src/components/AnonymousReportFooter.tsx
+++ b/src/components/AnonymousReportFooter.tsx
@@ -9,13 +9,14 @@ import variables from '@styles/variables';
import {signOutAndRedirectToSignIn} from '@userActions/Session';
+import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import React from 'react';
import {View} from 'react-native';
import AvatarWithDisplayName from './AvatarWithDisplayName';
-import Button from './Button';
+import Button from './ButtonComposed';
import ExpensifyWordmark from './ExpensifyWordmark';
import Text from './Text';
@@ -51,12 +52,13 @@ function AnonymousReportFooter({reportID}: AnonymousReportFooterProps) {
diff --git a/src/components/ApprovalWorkflowSection.tsx b/src/components/ApprovalWorkflowSection.tsx
index 858eb8efa254..b7e7e01886ec 100644
--- a/src/components/ApprovalWorkflowSection.tsx
+++ b/src/components/ApprovalWorkflowSection.tsx
@@ -15,7 +15,7 @@ import {Str} from 'expensify-common';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import Icon from './Icon';
import MenuItem from './MenuItem';
import OfflineWithFeedback from './OfflineWithFeedback';
@@ -202,13 +202,14 @@ function ApprovalWorkflowSection({
{!isDisabled && (
+ >
+
+ {translate('workflowsPage.editWorkflowAction')}
+
)}
diff --git a/src/components/AvatarPageFooter.tsx b/src/components/AvatarPageFooter.tsx
index dc9931785ea0..1fad12b392b3 100644
--- a/src/components/AvatarPageFooter.tsx
+++ b/src/components/AvatarPageFooter.tsx
@@ -1,11 +1,12 @@
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
import type {TranslationPaths} from '@src/languages/types';
import React from 'react';
-import Button from './Button';
+import Button from './ButtonComposed';
import DotIndicatorMessage from './DotIndicatorMessage';
import FixedFooter from './FixedFooter';
@@ -40,13 +41,14 @@ function AvatarPageFooter({validationError, phraseParam = {}, isDirty, onSave}:
/>
)}
+ >
+
+ {translate('common.save')}
+
);
}
diff --git a/src/components/BankAccountVerificationView.tsx b/src/components/BankAccountVerificationView.tsx
index a3bd2ed18393..f1f9c1532701 100644
--- a/src/components/BankAccountVerificationView.tsx
+++ b/src/components/BankAccountVerificationView.tsx
@@ -17,7 +17,7 @@ import type {ValueOf} from 'type-fest';
import React from 'react';
import BlockingView from './BlockingViews/BlockingView';
-import Button from './Button';
+import Button from './ButtonComposed';
import LottieAnimations from './LottieAnimations';
type BankAccountVerificationViewProps = {
@@ -66,13 +66,14 @@ function BankAccountVerificationView({verificationState, children, onVerifiedBut
iconWidth={variables.cardPreviewHeight}
/>
>
);
case CONST.EXPENSIFY_CARD.VERIFICATION_STATE.VERIFIED:
@@ -98,13 +99,14 @@ function BankAccountVerificationView({verificationState, children, onVerifiedBut
/>
)}
+ >
+
+ {verifiedButtonText ?? translate('workspace.expensifyCard.gotIt')}
+
>
);
default:
diff --git a/src/components/Banner.tsx b/src/components/Banner.tsx
index 1398577a6202..756ea38bb372 100644
--- a/src/components/Banner.tsx
+++ b/src/components/Banner.tsx
@@ -14,7 +14,7 @@ import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
import React, {memo} from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import Hoverable from './Hoverable';
import Icon from './Icon';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
@@ -130,11 +130,12 @@ function Banner({
{children ??
(shouldShowButton && (
+ >
+ {translate('common.chatNow')}
+
))}
{shouldShowCloseButton && !!onClose && (
diff --git a/src/components/BaseWidgetItem.tsx b/src/components/BaseWidgetItem.tsx
index c99d5384df82..c6157034ec43 100644
--- a/src/components/BaseWidgetItem.tsx
+++ b/src/components/BaseWidgetItem.tsx
@@ -2,6 +2,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
+import type {ButtonVariant} from '@styles/utils/types';
import variables from '@styles/variables';
import CONST from '@src/CONST';
@@ -10,9 +11,7 @@ import type IconAsset from '@src/types/utils/IconAsset';
import React from 'react';
import {View} from 'react-native';
-import type {ButtonProps} from './Button';
-
-import Button from './Button';
+import Button from './ButtonComposed';
import Icon from './Icon';
import {PressableWithoutFeedback} from './Pressable';
import Text from './Text';
@@ -41,11 +40,11 @@ type BaseWidgetItemProps = {
/** Optional: fill color for the icon (defaults to white) */
iconFill?: string;
- /** Additional props to pass to the Button component for styling control */
- buttonProps?: Partial;
+ /** The visual variant of the CTA button */
+ buttonVariant?: ButtonVariant;
};
-function BaseWidgetItem({icon, iconBackgroundColor, title, subtitle, ctaText, onCtaPress, iconFill, buttonProps}: BaseWidgetItemProps) {
+function BaseWidgetItem({icon, iconBackgroundColor, title, subtitle, ctaText, onCtaPress, iconFill, buttonVariant}: BaseWidgetItemProps) {
const styles = useThemeStyles();
const theme = useTheme();
const {shouldUseNarrowLayout} = useResponsiveLayout();
@@ -72,14 +71,13 @@ function BaseWidgetItem({icon, iconBackgroundColor, title, subtitle, ctaText, on
{title}
+ variant={buttonVariant}
+ >
+ {ctaText}
+
)}
diff --git a/src/components/BigNumberPad.tsx b/src/components/BigNumberPad.tsx
index 25f053bf90e2..b3090bdba096 100644
--- a/src/components/BigNumberPad.tsx
+++ b/src/components/BigNumberPad.tsx
@@ -5,10 +5,14 @@ import useThemeStyles from '@hooks/useThemeStyles';
import ControlSelection from '@libs/ControlSelection';
+import CONST from '@src/CONST';
+
+import type {ValueOf} from 'type-fest';
+
import React, {useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
type BigNumberPadProps = {
/** Callback to inform parent modal with key pressed */
@@ -62,6 +66,15 @@ function BigNumberPad({numberPressed, longPressHandlerStateChanged = () => {}, i
setTimer(newTimer);
};
+ let numberPadButtonSize: ValueOf;
+ if (isInLandscapeMode) {
+ numberPadButtonSize = CONST.BUTTON_SIZE.SMALL;
+ } else if (isExtraSmallScreenHeight) {
+ numberPadButtonSize = CONST.BUTTON_SIZE.MEDIUM;
+ } else {
+ numberPadButtonSize = CONST.BUTTON_SIZE.LARGE;
+ }
+
return (
{}, i
return (
);
})}
diff --git a/src/components/BiometricsTestToolRow.tsx b/src/components/BiometricsTestToolRow.tsx
index 62be4fa0e5d3..dfe43b214994 100644
--- a/src/components/BiometricsTestToolRow.tsx
+++ b/src/components/BiometricsTestToolRow.tsx
@@ -12,7 +12,7 @@ import ROUTES from '@src/ROUTES';
import React, {useState} from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import {useMultifactorAuthentication} from './MultifactorAuthentication/Context';
import TestToolRow from './TestToolRow';
@@ -36,9 +36,8 @@ function BiometricsTestToolRow() {
{isCurrentDeviceRegistered && !!localCredentialID && (
)}
diff --git a/src/components/BookCallButton.tsx b/src/components/BookCallButton.tsx
index cabf167e1647..a5026e99224a 100644
--- a/src/components/BookCallButton.tsx
+++ b/src/components/BookCallButton.tsx
@@ -1,7 +1,6 @@
import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset';
import useLocalize from '@hooks/useLocalize';
import useOnyx from '@hooks/useOnyx';
-import useThemeStyles from '@hooks/useThemeStyles';
import {openExternalLink} from '@libs/actions/Link';
import {callFunctionIfActionIsAllowed} from '@libs/actions/Session';
@@ -12,12 +11,8 @@ import type {PersonalDetailsList} from '@src/types/onyx';
import type {StyleProp, ViewStyle} from 'react-native';
-import React from 'react';
-import {View} from 'react-native';
-
import Avatar from './Avatar';
-import Button from './Button';
-import Text from './Text';
+import Button from './ButtonComposed';
type BookCallButtonProps = {
/** The calendar link to open when the button is pressed */
@@ -35,7 +30,6 @@ type BookCallButtonProps = {
function BookCallButton({calendarLink, avatarAccountID, isNested = false, style}: BookCallButtonProps) {
const {translate} = useLocalize();
- const styles = useThemeStyles();
const icons = useMemoizedLazyExpensifyIcons(['Phone']);
const [avatarDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {
selector: (personalDetails: PersonalDetailsList | undefined) => (avatarAccountID ? personalDetails?.[avatarAccountID] : undefined),
@@ -52,32 +46,28 @@ function BookCallButton({calendarLink, avatarAccountID, isNested = false, style}
sentryLabel: CONST.SENTRY_LABEL.ACCOUNT_MANAGER_BOOK_CALL.BUTTON,
accessibilityLabel: label,
isNested,
- medium: true as const,
style,
};
if (!avatarAccountID) {
return (
-
+
);
}
return (
);
}
diff --git a/src/components/BookTravelButton.tsx b/src/components/BookTravelButton.tsx
index 75f6e01ded7b..ec2b66fc6a83 100644
--- a/src/components/BookTravelButton.tsx
+++ b/src/components/BookTravelButton.tsx
@@ -31,7 +31,7 @@ import {emailSelector} from '@selectors/Session';
import {Str} from 'expensify-common';
import React, {useEffect, useRef, useState} from 'react';
-import Button from './Button';
+import Button from './ButtonComposed';
import DotIndicatorMessage from './DotIndicatorMessage';
import RenderHTML from './RenderHTML';
@@ -226,15 +226,16 @@ function BookTravelButton({
/>
)}
+ >
+ {text}
+
{shouldRenderErrorMessageBelowButton && !!errorMessage && (
);
diff --git a/src/components/ColumnsSettingsList.tsx b/src/components/ColumnsSettingsList.tsx
index 88b54acb0abd..934a38f50af9 100644
--- a/src/components/ColumnsSettingsList.tsx
+++ b/src/components/ColumnsSettingsList.tsx
@@ -6,13 +6,15 @@ import useThemeStyles from '@hooks/useThemeStyles';
import {getSearchColumnTranslationKey} from '@libs/SearchUIUtils';
+import CONST from '@src/CONST';
+
import React, {useRef, useState} from 'react';
import {View} from 'react-native';
import type {SearchCustomColumnIds} from './Search/types';
import type {ListItem} from './SelectionList/types';
-import Button from './Button';
+import Button from './ButtonComposed';
import DraggableList from './DraggableList';
import HeaderWithBackButton from './HeaderWithBackButton';
import Icon from './Icon';
@@ -297,12 +299,13 @@ function ColumnsSettingsList({allColumns, defaultSelectedColumns, currentColumns
+ >
+
+ {translate('common.save')}
+
);
diff --git a/src/components/ConfirmContent.tsx b/src/components/ConfirmContent.tsx
index ab466ddcf33a..12112bae8c8e 100644
--- a/src/components/ConfirmContent.tsx
+++ b/src/components/ConfirmContent.tsx
@@ -5,6 +5,7 @@ import useNetwork from '@hooks/useNetwork';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
+import type {ButtonVariant} from '@styles/utils/types';
import variables from '@styles/variables';
import CONST from '@src/CONST';
@@ -17,7 +18,7 @@ import React from 'react';
import {View} from 'react-native';
import ActivityIndicator from './ActivityIndicator';
-import Button from './Button';
+import Button from './ButtonComposed';
import Header from './Header';
import Icon from './Icon';
import ImageSVG from './ImageSVG';
@@ -175,6 +176,13 @@ function ConfirmContent({
const isCentered = shouldCenterContent;
+ let confirmButtonVariant: ButtonVariant | undefined;
+ if (danger) {
+ confirmButtonVariant = CONST.BUTTON_VARIANT.DANGER;
+ } else if ((shouldUseSuccessStyleForConfirm || (shouldShowCancelButton && !danger)) && success) {
+ confirmButtonVariant = CONST.BUTTON_VARIANT.SUCCESS;
+ }
+
const promptContent = typeof prompt === 'string' ? {prompt} : prompt;
// Rendered outside the (optionally scrollable) prompt so it stays fixed above the prompt.
let subtitleContent: ReactNode = subtitle;
@@ -244,30 +252,31 @@ function ConfirmContent({
+ size={CONST.BUTTON_SIZE.LARGE}
+ >
+ {cancelText || translate('common.no')}
+
)}
+ >
+
+ {confirmText || translate('common.yes')}
+
{shouldShowCancelButton && !shouldReverseStackedButtons && (
+ size={CONST.BUTTON_SIZE.LARGE}
+ >
+ {cancelText || translate('common.no')}
+
)}
>
) : (
@@ -276,20 +285,20 @@ function ConfirmContent({
+ >
+ {cancelText || translate('common.no')}
+
)}
+ >
+
+ {confirmText || translate('common.yes')}
+
)}
diff --git a/src/components/ConfirmationPage.tsx b/src/components/ConfirmationPage.tsx
index c8e77a6a58ae..36c3d8478809 100644
--- a/src/components/ConfirmationPage.tsx
+++ b/src/components/ConfirmationPage.tsx
@@ -4,6 +4,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import Accessibility from '@libs/Accessibility';
import isIllustrationLottieAnimation from '@libs/isIllustrationLottieAnimation';
+import CONST from '@src/CONST';
import type IconAsset from '@src/types/utils/IconAsset';
import type {StyleProp, TextStyle, ViewStyle} from 'react-native';
@@ -13,7 +14,7 @@ import {StyleSheet, View} from 'react-native';
import type DotLottieAnimation from './LottieAnimations/types';
-import Button from './Button';
+import Button from './ButtonComposed';
import FixedFooter from './FixedFooter';
import ImageSVG from './ImageSVG';
import Lottie from './Lottie';
@@ -153,23 +154,25 @@ function ConfirmationPage({
{shouldShowSecondaryButton && (
+ >
+ {secondaryButtonText}
+
)}
{shouldShowButton && (
+ >
+
+ {buttonText}
+
)}
)}
diff --git a/src/components/ConnectionStatusMessage.tsx b/src/components/ConnectionStatusMessage.tsx
index acd4d1e82e2e..b01f696282f1 100644
--- a/src/components/ConnectionStatusMessage.tsx
+++ b/src/components/ConnectionStatusMessage.tsx
@@ -3,12 +3,14 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
+
import type {ComponentProps} from 'react';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import Icon from './Icon';
import RenderHTML from './RenderHTML';
@@ -69,13 +71,14 @@ function ConnectionStatusMessage({
const actionButton = shouldShowActionButton ? (
+ >
+ {actionText}
+
) : null;
return (
diff --git a/src/components/DecisionModal.tsx b/src/components/DecisionModal.tsx
index dc19968d01bb..4aa7123a6228 100644
--- a/src/components/DecisionModal.tsx
+++ b/src/components/DecisionModal.tsx
@@ -1,11 +1,13 @@
import useThemeStyles from '@hooks/useThemeStyles';
+import type {ButtonVariant} from '@styles/utils/types';
+
import CONST from '@src/CONST';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import Header from './Header';
import Modal from './Modal';
import RenderHTML from './RenderHTML';
@@ -77,6 +79,20 @@ function DecisionModal({
}: DecisionModalProps) {
const styles = useThemeStyles();
+ let firstOptionVariant: ButtonVariant | undefined;
+ if (isFirstOptionDanger) {
+ firstOptionVariant = CONST.BUTTON_VARIANT.DANGER;
+ } else if (isFirstOptionSuccess) {
+ firstOptionVariant = CONST.BUTTON_VARIANT.SUCCESS;
+ }
+
+ let secondOptionVariant: ButtonVariant | undefined;
+ if (isSecondOptionDanger) {
+ secondOptionVariant = CONST.BUTTON_VARIANT.DANGER;
+ } else if (isSecondOptionSuccess) {
+ secondOptionVariant = CONST.BUTTON_VARIANT.SUCCESS;
+ }
+
return (
{!!firstOptionText && (
+ size={CONST.BUTTON_SIZE.LARGE}
+ >
+
+ {firstOptionText}
+
)}
+ variant={secondOptionVariant}
+ size={CONST.BUTTON_SIZE.LARGE}
+ >
+ {secondOptionText}
+
);
diff --git a/src/components/DotIndicatorMessage.tsx b/src/components/DotIndicatorMessage.tsx
index 13d0dfee7152..8d0e8174c74e 100644
--- a/src/components/DotIndicatorMessage.tsx
+++ b/src/components/DotIndicatorMessage.tsx
@@ -20,7 +20,7 @@ import {Str} from 'expensify-common';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import Icon from './Icon';
import RenderHTML from './RenderHTML';
import Text from './Text';
@@ -140,18 +140,20 @@ function DotIndicatorMessage({messages = {}, style, type, textStyles, dismissErr
const buttonsRow = (
+ >
+ {translate('iou.deleteExpense', {count: 1})}
+
);
if (!isStackedLayout) {
diff --git a/src/components/ExportDownloadStatusModal.tsx b/src/components/ExportDownloadStatusModal.tsx
index 086291969a4a..bc1774d65edb 100644
--- a/src/components/ExportDownloadStatusModal.tsx
+++ b/src/components/ExportDownloadStatusModal.tsx
@@ -22,7 +22,7 @@ import React, {useEffect} from 'react';
import {View} from 'react-native';
import ActivityIndicator from './ActivityIndicator';
-import Button from './Button';
+import Button from './ButtonComposed';
import Modal from './Modal';
import RenderHTML from './RenderHTML';
import Text from './Text';
@@ -120,10 +120,11 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E
{translate('exportDownload.preparingBody')}
+ >
+ {translate('exportDownload.sendFromConcierge')}
+
>
);
}
@@ -134,16 +135,18 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E
{translate('exportDownload.conciergeTitle')}
{translate('exportDownload.conciergeBody')}
+ >
+ {translate('exportDownload.goToConcierge')}
+
+ >
+ {translate('exportDownload.dismiss')}
+
>
);
}
@@ -154,10 +157,11 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E
{translate('exportDownload.noReceiptsTitle')}
{translate('exportDownload.noReceiptsBody')}
+ >
+ {translate('exportDownload.close')}
+
>
);
}
@@ -194,11 +198,12 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E
{translate('exportDownload.readyTitle')}
{renderPartialBody()}
+ >
+ {translate('exportDownload.downloadFile')}
+
>
);
}
@@ -219,10 +224,11 @@ function ExportDownloadStatusModal({exportID, isVisible, onClose, failedBody}: E
{translate('exportDownload.failedTitle')}
{!!resolvedFailedBody && {resolvedFailedBody}}
+ >
+ {translate('exportDownload.close')}
+
>
);
}
diff --git a/src/components/FeatureList.tsx b/src/components/FeatureList.tsx
index eb746f55b9d1..81f6276a9ffe 100644
--- a/src/components/FeatureList.tsx
+++ b/src/components/FeatureList.tsx
@@ -15,7 +15,7 @@ import {View} from 'react-native';
import type DotLottieAnimation from './LottieAnimations/types';
-import Button from './Button';
+import Button from './ButtonComposed';
import MenuItem from './MenuItem';
import Section from './Section';
@@ -136,17 +136,18 @@ function FeatureList({
{!!ctaText && (
+ >
+ {ctaText}
+
)}
{!!footer && footer}
diff --git a/src/components/FormAlertWithSubmitButton.tsx b/src/components/FormAlertWithSubmitButton.tsx
index ba8c98b7a9e4..de4fa2b67e17 100644
--- a/src/components/FormAlertWithSubmitButton.tsx
+++ b/src/components/FormAlertWithSubmitButton.tsx
@@ -12,7 +12,7 @@ import type {StyleProp, ViewStyle} from 'react-native';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import FormAlertWrapper from './FormAlertWrapper';
type FormAlertWithSubmitButtonProps = WithSentryLabel & {
@@ -153,35 +153,32 @@ function FormAlertWithSubmitButton({
{shouldRenderFooterAboveSubmit && footerContent}
{isOffline && !enabledWhenOffline ? (
) : (
)}
{!shouldRenderFooterAboveSubmit && footerContent}
diff --git a/src/components/FrozenCardHeader.tsx b/src/components/FrozenCardHeader.tsx
index 3af6a6e83dca..b54a917c1444 100644
--- a/src/components/FrozenCardHeader.tsx
+++ b/src/components/FrozenCardHeader.tsx
@@ -21,7 +21,7 @@ import type {StyleProp, ViewStyle} from 'react-native';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import Text from './Text';
import TextLink from './TextLink';
@@ -104,14 +104,14 @@ function FrozenCardHeader({cardPreview, children, style, onUnfreezePress, onAskT
+ >
+
+ {translate(canUnfreezeCard ? 'cardPage.unfreezeCard' : 'cardPage.askToUnfreeze')}
+
{shouldUseEqualButtonWidths
? actionButtons.map((button, index) => (
diff --git a/src/components/FullscreenLoadingIndicator.tsx b/src/components/FullscreenLoadingIndicator.tsx
index c3dfcdb425dd..96c01ce13efc 100644
--- a/src/components/FullscreenLoadingIndicator.tsx
+++ b/src/components/FullscreenLoadingIndicator.tsx
@@ -12,7 +12,7 @@ import React, {useEffect, useState} from 'react';
import {StyleSheet, View} from 'react-native';
import ActivityIndicator from './ActivityIndicator';
-import Button from './Button';
+import Button from './ButtonComposed';
import Text from './Text';
type FullScreenLoadingIndicatorIconSize = ActivityIndicatorProps['size'];
@@ -69,10 +69,9 @@ function FullScreenLoadingIndicator({
{translate('common.thisIsTakingLongerThanExpected')}
-
)}
diff --git a/src/components/GrowlNotification/GrowlNotificationContent.tsx b/src/components/GrowlNotification/GrowlNotificationContent.tsx
index 6e8ff02473f5..0c3d79223f25 100644
--- a/src/components/GrowlNotification/GrowlNotificationContent.tsx
+++ b/src/components/GrowlNotification/GrowlNotificationContent.tsx
@@ -1,4 +1,4 @@
-import Button from '@components/Button';
+import Button from '@components/ButtonComposed';
import Icon from '@components/Icon';
import * as Pressables from '@components/Pressable';
import Text from '@components/Text';
@@ -155,8 +155,6 @@ function GrowlNotificationContent({bodyText, type, duration, action, nonce, onDi
{!!action && (
{
@@ -168,10 +166,10 @@ function GrowlNotificationContent({bodyText, type, duration, action, nonce, onDi
action.onPress();
}}
innerStyles={styles.bgTransparent}
- textStyles={styles.growlNotificationActionText}
- shouldUseDefaultHover={false}
hoverStyles={styles.growlNotificationActionHovered}
- />
+ >
+ {action.label}
+
)}
diff --git a/src/components/HRSyncResultsModal.tsx b/src/components/HRSyncResultsModal.tsx
index 0b35211aea87..9a74c22ecb90 100644
--- a/src/components/HRSyncResultsModal.tsx
+++ b/src/components/HRSyncResultsModal.tsx
@@ -15,7 +15,7 @@ import {View} from 'react-native';
import type {ModalProps} from './Modal/Global/ModalContext';
-import Button from './Button';
+import Button from './ButtonComposed';
import FixedFooter from './FixedFooter';
import HeaderWithBackButton from './HeaderWithBackButton';
import Icon from './Icon';
@@ -118,11 +118,12 @@ function HRSyncResultsModal({result, policyID, closeModal}: HRSyncResultsModalPr
+ >
+ {translate('common.buttonConfirm')}
+
diff --git a/src/components/ImportSpreadsheet.tsx b/src/components/ImportSpreadsheet.tsx
index 089ea336771f..6ebf85634d41 100644
--- a/src/components/ImportSpreadsheet.tsx
+++ b/src/components/ImportSpreadsheet.tsx
@@ -23,7 +23,7 @@ import React, {useRef, useState} from 'react';
import {PanResponder, PixelRatio, Platform, View} from 'react-native';
import RNFetchBlob from 'react-native-blob-util';
-import Button from './Button';
+import Button from './ButtonComposed';
import DragAndDropConsumer from './DragAndDrop/Consumer';
import DragAndDropProvider from './DragAndDrop/Provider';
import FilePicker from './FilePicker';
@@ -206,8 +206,7 @@ function ImportSpreadsheet({backTo, goTo, shouldForceReplaceNavigation = false,
{({openPicker}) => (
+ >
+ {translate('common.chooseFile')}
+
)}
>
diff --git a/src/components/ImportSpreadsheetColumns.tsx b/src/components/ImportSpreadsheetColumns.tsx
index 9237a335cd6d..527609ce11a7 100644
--- a/src/components/ImportSpreadsheetColumns.tsx
+++ b/src/components/ImportSpreadsheetColumns.tsx
@@ -5,6 +5,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import {setContainsHeader} from '@libs/actions/ImportSpreadsheet';
+import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {Errors} from '@src/types/onyx/OnyxCommon';
@@ -13,7 +14,7 @@ import {View} from 'react-native';
import type {ColumnRole} from './ImportColumn';
-import Button from './Button';
+import Button from './ButtonComposed';
import FixedFooter from './FixedFooter';
import ImportColumn from './ImportColumn';
import OfflineWithFeedback from './OfflineWithFeedback';
@@ -125,14 +126,15 @@ function ImportSpreadsheetColumns({
errorRowStyles={styles.mv2}
>
+ >
+
+ {translate('common.import')}
+
>
diff --git a/src/components/ImportedStateIndicator.tsx b/src/components/ImportedStateIndicator.tsx
index f7dd1ebe62f3..c760cf328734 100644
--- a/src/components/ImportedStateIndicator.tsx
+++ b/src/components/ImportedStateIndicator.tsx
@@ -4,12 +4,13 @@ import useThemeStyles from '@hooks/useThemeStyles';
import {clearOnyxAndResetApp} from '@libs/actions/App';
+import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
function ImportedStateIndicator() {
const styles = useThemeStyles();
@@ -23,14 +24,13 @@ function ImportedStateIndicator() {
return (
clearOnyxAndResetApp(true)}
- textStyles={[styles.fontWeightNormal]}
- />
+ >
+ {translate('initialSettingsPage.troubleshoot.usingImportedState')}
+
);
}
diff --git a/src/components/MoneyRequestHeaderPrimaryAction.tsx b/src/components/MoneyRequestHeaderPrimaryAction.tsx
index 5e9c11b2f95d..6fd53e3f00d9 100644
--- a/src/components/MoneyRequestHeaderPrimaryAction.tsx
+++ b/src/components/MoneyRequestHeaderPrimaryAction.tsx
@@ -34,7 +34,7 @@ import {personalDetailsLoginSelector} from '@selectors/PersonalDetails';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import {useDelegateNoAccessActions, useDelegateNoAccessState} from './DelegateNoAccessModalProvider';
import {useWideRHPState} from './WideRHPContextProvider';
@@ -92,8 +92,7 @@ function MoneyRequestHeaderPrimaryAction({reportID}: MoneyRequestHeaderPrimaryAc
if (primaryAction === CONST.REPORT.TRANSACTION_PRIMARY_ACTIONS.REMOVE_HOLD) {
return (
{
if (isDelegateAccessRestricted) {
showDelegateNoAccessModal();
@@ -110,45 +109,48 @@ function MoneyRequestHeaderPrimaryAction({reportID}: MoneyRequestHeaderPrimaryAc
delegateAccountID,
);
}}
- />
+ >
+ {translate('iou.unhold')}
+
);
}
if (primaryAction === CONST.REPORT.TRANSACTION_PRIMARY_ACTIONS.MARK_AS_RESOLVED) {
return (
{
if (!transaction?.transactionID) {
return;
}
markRejectViolationAsResolved(transaction.transactionID, isOffline, rawTransactionViolations, reportID);
}}
- />
+ >
+ {translate('iou.reject.markAsResolved')}
+
);
}
if (primaryAction === CONST.REPORT.TRANSACTION_PRIMARY_ACTIONS.REVIEW_DUPLICATES) {
return (
{
if (!reportID) {
return;
}
Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.TRANSACTION_DUPLICATE_REVIEW.getRoute(reportID)));
}}
- />
+ >
+ {translate('iou.reviewDuplicates')}
+
);
}
if (primaryAction === CONST.REPORT.TRANSACTION_PRIMARY_ACTIONS.KEEP_THIS_ONE) {
return (
{
if (!reportID) {
return;
@@ -173,19 +175,22 @@ function MoneyRequestHeaderPrimaryAction({reportID}: MoneyRequestHeaderPrimaryAc
),
);
}}
- />
+ >
+ {translate('violations.keepThisOne')}
+
);
}
if (primaryAction === CONST.REPORT.TRANSACTION_PRIMARY_ACTIONS.MARK_AS_CASH) {
return (
{
markAsCashAction(transaction?.transactionID, reportID, transactionViolations);
}}
- />
+ >
+ {translate('iou.markAsCash')}
+
);
}
diff --git a/src/components/NumberWithSymbolForm.tsx b/src/components/NumberWithSymbolForm.tsx
index 3cb5f36a0bf8..a49678cc577f 100644
--- a/src/components/NumberWithSymbolForm.tsx
+++ b/src/components/NumberWithSymbolForm.tsx
@@ -34,7 +34,7 @@ import type {BaseTextInputRef} from './TextInput/BaseTextInput/types';
import type {TextInputWithSymbolProps} from './TextInputWithSymbol/types';
import BigNumberPad from './BigNumberPad';
-import Button from './Button';
+import Button from './ButtonComposed';
import FormHelpMessage from './FormHelpMessage';
import ScrollView from './ScrollView';
import TextInput from './TextInput';
@@ -500,28 +500,34 @@ function NumberWithSymbolForm({
{shouldShowFlipButton && allowNegativeInput && canUseTouchScreen && (
e.preventDefault()}
- iconWrapperStyles={styles.justifyContentCenter}
- text={translate('iou.flip')}
+ contentContainerStyle={styles.justifyContentCenter}
accessibilityLabel={translate('iou.flip')}
isDisabled={disabled}
- />
+ >
+
+ {translate('iou.flip')}
+
)}
{shouldShowCurrencyButton && !!currencyOrUnitButtonText && (
+ >
+
+ {currencyOrUnitButtonText}
+
)}
);
@@ -645,27 +651,33 @@ function NumberWithSymbolForm({
{isSymbolPressable && (
+ >
+
+ {currency}
+
)}
{allowFlippingAmount && (
+ >
+
+ {translate('iou.flip')}
+
)}
{!!errorText && (
@@ -725,15 +737,18 @@ function NumberWithSymbolForm({
{textInputComponent}
{isSymbolPressable && !!currency && !canUseTouchScreen && (
+ >
+
+ {currency}
+
)}
{!!errorText && (
{isSymbolPressable && canUseTouchScreen && (
+ >
+
+ {currency}
+
)}
{allowFlippingAmount && canUseTouchScreen && (
+ >
+
+ {translate('iou.flip')}
+
)}
diff --git a/src/components/OnboardingMergingAccountBlockedView.tsx b/src/components/OnboardingMergingAccountBlockedView.tsx
index 6715b797d7b3..fa6f6c76a273 100644
--- a/src/components/OnboardingMergingAccountBlockedView.tsx
+++ b/src/components/OnboardingMergingAccountBlockedView.tsx
@@ -9,13 +9,14 @@ import variables from '@styles/variables';
import {setOnboardingErrorMessage} from '@userActions/Welcome';
+import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import React from 'react';
import BlockingView from './BlockingViews/BlockingView';
-import Button from './Button';
+import Button from './ButtonComposed';
type OnboardingMergingAccountBlockedViewProps = {
// Work email to display in the subtitle
@@ -50,10 +51,9 @@ function OnboardingMergingAccountBlockedView({workEmail, isVsb}: OnboardingMergi
subtitleStyle={[styles.colorMuted]}
/>
{
setOnboardingErrorMessage(null);
if (isVsb) {
@@ -62,7 +62,9 @@ function OnboardingMergingAccountBlockedView({workEmail, isVsb}: OnboardingMergi
}
Navigation.navigate(ROUTES.ONBOARDING_PURPOSE.getRoute());
}}
- />
+ >
+ {translate('common.buttonConfirm')}
+
>
);
}
diff --git a/src/components/PDFDownloadModal.tsx b/src/components/PDFDownloadModal.tsx
index ad04a2c55a94..6a01390f1f1e 100644
--- a/src/components/PDFDownloadModal.tsx
+++ b/src/components/PDFDownloadModal.tsx
@@ -10,7 +10,7 @@ import React, {useEffect, useRef} from 'react';
import {View} from 'react-native';
import ActivityIndicator from './ActivityIndicator';
-import Button from './Button';
+import Button from './ButtonComposed';
import Header from './Header';
import Icon from './Icon';
import Modal from './Modal';
@@ -115,7 +115,7 @@ function PDFDownloadModal({
{
if (!hasFinishedPDFDownload) {
onClose();
@@ -127,8 +127,9 @@ function PDFDownloadModal({
onClose();
}
}}
- text={hasFinishedPDFDownload ? translate('common.download') : translate('common.cancel')}
- />
+ >
+ {hasFinishedPDFDownload ? translate('common.download') : translate('common.cancel')}
+
+ >
+
+ {translate('proactiveAppReview.positiveButton')}
+
+ >
+ {translate('proactiveAppReview.negativeButton')}
+
);
diff --git a/src/components/PromotedActionsBar.tsx b/src/components/PromotedActionsBar.tsx
index 6338efeeca6c..8c8a852348c4 100644
--- a/src/components/PromotedActionsBar.tsx
+++ b/src/components/PromotedActionsBar.tsx
@@ -24,7 +24,7 @@ import {View} from 'react-native';
import type {ThreeDotsMenuItem} from './HeaderWithBackButton/types';
-import Button from './Button';
+import Button from './ButtonComposed';
type PromotedAction = {
key: string;
@@ -144,12 +144,13 @@ function PromotedActionsBar({promotedActions, containerStyle}: PromotedActionsBa
style={[styles.flex1, styles.mw50]}
key={key}
>
-
+
+
+ {translate(translationKey)}
+
))}
diff --git a/src/components/RequireTwoFactorAuthenticationModal.tsx b/src/components/RequireTwoFactorAuthenticationModal.tsx
index a64391856e06..d1d512209f59 100644
--- a/src/components/RequireTwoFactorAuthenticationModal.tsx
+++ b/src/components/RequireTwoFactorAuthenticationModal.tsx
@@ -11,7 +11,7 @@ import CONST from '@src/CONST';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import ImageSVG from './ImageSVG';
import Lottie from './Lottie';
import LottieAnimations from './LottieAnimations';
@@ -79,12 +79,13 @@ function RequireTwoFactorAuthenticationModal({onCancel = () => {}, description,
{description}
+ >
+
+ {translate('twoFactorAuth.enableTwoFactorAuth')}
+
diff --git a/src/components/SubscriptionPlanDowngradeBlocked.tsx b/src/components/SubscriptionPlanDowngradeBlocked.tsx
index f257db7dc109..87424b5f1ed7 100644
--- a/src/components/SubscriptionPlanDowngradeBlocked.tsx
+++ b/src/components/SubscriptionPlanDowngradeBlocked.tsx
@@ -3,6 +3,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import {isSubscriptionTypeOfInvoicing} from '@libs/SubscriptionUtils';
+import CONST from '@src/CONST';
import type {PrivateSubscription} from '@src/types/onyx';
import type {OnyxEntry} from 'react-native-onyx';
@@ -10,7 +11,7 @@ import type {OnyxEntry} from 'react-native-onyx';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import FixedFooter from './FixedFooter';
import Text from './Text';
@@ -38,11 +39,12 @@ function SubscriptionPlanDowngradeBlocked({privateSubscription, formattedSubscri
)}
+ >
+ {translate('common.close')}
+
);
diff --git a/src/components/TaskHeaderActionButton.tsx b/src/components/TaskHeaderActionButton.tsx
index 79d0dcf785d1..0d06c5b27a4e 100644
--- a/src/components/TaskHeaderActionButton.tsx
+++ b/src/components/TaskHeaderActionButton.tsx
@@ -21,7 +21,7 @@ import {delegateEmailSelector} from '@selectors/Account';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
type TaskHeaderActionButtonProps = {
/** The report currently being looked at */
@@ -46,9 +46,8 @@ function TaskHeaderActionButton({report}: TaskHeaderActionButtonProps) {
return (
{
// If we're already navigating to these task editing pages, early return not to mark as completed, otherwise we would have not found page.
if (isActiveTaskEditRoute(report.reportID)) {
@@ -62,7 +61,9 @@ function TaskHeaderActionButton({report}: TaskHeaderActionButtonProps) {
})}
style={styles.flex1}
sentryLabel={CONST.SENTRY_LABEL.TASK.HEADER_ACTION_BUTTON}
- />
+ >
+ {translate(isCompletedTaskReport(report) ? 'task.markAsIncomplete' : 'task.markAsComplete')}
+
);
}
diff --git a/src/components/TestToolMenu.tsx b/src/components/TestToolMenu.tsx
index 0d3b5f31beff..7152b6f0ee5a 100644
--- a/src/components/TestToolMenu.tsx
+++ b/src/components/TestToolMenu.tsx
@@ -12,13 +12,14 @@ import {expireSessionWithDelay, invalidateAuthToken, invalidateCredentials} from
import {setIsDebugModeEnabled, setShouldShowBranchNameInTitle, setShouldUseStagingServer} from '@userActions/User';
import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import React from 'react';
import {Platform} from 'react-native';
import BiometricsTestToolRow from './BiometricsTestToolRow';
-import Button from './Button';
+import Button from './ButtonComposed';
import SoftKillTestToolRow from './SoftKillTestToolRow';
import Switch from './Switch';
import TestCrash from './TestCrash';
@@ -77,37 +78,41 @@ function TestToolMenu() {
{/* Instantly invalidates a user's local authToken. Useful for testing flows related to reauthentication. */}
invalidateAuthToken()}
- />
+ >
+ {translate('initialSettingsPage.troubleshoot.invalidate')}
+
{/* Clears stored auto-generated credentials, corrupts the local authToken and fires a request so reauth fails and the user is signed out. Useful for manually testing sign out logic. */}
invalidateCredentials()}
- />
+ >
+ {translate('initialSettingsPage.troubleshoot.destroy')}
+
{/* Sends an expired session to the FE and invalidates the session by the same time in the BE. Action is delayed for 15s */}
expireSessionWithDelay()}
- />
+ >
+ {translate('initialSettingsPage.troubleshoot.invalidateWithDelay')}
+
{/* Clears the useSidebarOrderedReports cache to re-compute from latest onyx values */}
+ >
+ {translate('initialSettingsPage.troubleshoot.clearleftHandNavCache')}
+
{/* Allows testing and revoking biometric multifactor authentication */}
diff --git a/src/components/TrialPaymentReminderModal.tsx b/src/components/TrialPaymentReminderModal.tsx
index 3e6d5bceb06d..6bc935035088 100644
--- a/src/components/TrialPaymentReminderModal.tsx
+++ b/src/components/TrialPaymentReminderModal.tsx
@@ -9,7 +9,7 @@ import CONST from '@src/CONST';
import React from 'react';
import {View} from 'react-native';
-import Button from './Button';
+import Button from './ButtonComposed';
import ImageSVG from './ImageSVG';
import Modal from './Modal';
import Text from './Text';
@@ -78,19 +78,21 @@ function TrialPaymentReminderModal({isVisible, variant, daysRemaining, countdown
{translate('trialPaymentReminder.subtitle')}
+ >
+
+ {translate('trialPaymentReminder.addPaymentCardButton')}
+
+ >
+ {translate('trialPaymentReminder.closeButton')}
+
);
diff --git a/src/components/UploadFile.tsx b/src/components/UploadFile.tsx
index a908810a773e..7f833d4c309e 100644
--- a/src/components/UploadFile.tsx
+++ b/src/components/UploadFile.tsx
@@ -15,7 +15,7 @@ import React from 'react';
import {View} from 'react-native';
import AttachmentPicker from './AttachmentPicker';
-import Button from './Button';
+import Button from './ButtonComposed';
import DotIndicatorMessage from './DotIndicatorMessage';
import Icon from './Icon';
import {PressableWithFeedback} from './Pressable';
@@ -129,15 +129,15 @@ function UploadFile({
>
{({openPicker}) => (
{
openPicker({
onPicked: handleFileUpload,
});
}}
- />
+ >
+ {buttonText}
+
)}
{uploadedFiles.map((file) => (
diff --git a/src/pages/home/ForYouSection/index.tsx b/src/pages/home/ForYouSection/index.tsx
index d5c79257a972..cf5d38c51cbe 100644
--- a/src/pages/home/ForYouSection/index.tsx
+++ b/src/pages/home/ForYouSection/index.tsx
@@ -103,7 +103,7 @@ function ForYouSection() {
iconFill: colors.tangerine500,
translationKey: 'homePage.forYouSection.reviewExpenses' as const,
handler: reviewExpenses,
- buttonProps: {danger: true} as const,
+ buttonVariant: CONST.BUTTON_VARIANT.DANGER,
},
{
key: 'submit',
@@ -162,7 +162,7 @@ function ForYouSection() {
const renderTodoItems = () => (
- {todoItems.map(({key, count, icon, iconBackgroundColor, iconFill, translationKey, handler, buttonProps}) => (
+ {todoItems.map(({key, count, icon, iconBackgroundColor, iconFill, translationKey, handler, buttonVariant}) => (
))}
diff --git a/src/pages/home/TimeSensitiveSection/items/ActivateCard.tsx b/src/pages/home/TimeSensitiveSection/items/ActivateCard.tsx
index f2dd8bd13e68..46c7375a0e94 100644
--- a/src/pages/home/TimeSensitiveSection/items/ActivateCard.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/ActivateCard.tsx
@@ -7,6 +7,7 @@ import useTheme from '@hooks/useTheme';
import Navigation from '@libs/Navigation/Navigation';
+import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import type {Card} from '@src/types/onyx';
@@ -29,7 +30,7 @@ function ActivateCard({card}: ActivateCardProps) {
subtitle={translate('homePage.timeSensitiveSection.activateCard.subtitle')}
ctaText={translate('homePage.timeSensitiveSection.activateCard.cta')}
onCtaPress={() => Navigation.navigate(ROUTES.SETTINGS_WALLET_CARD_ACTIVATE.getRoute(String(card.cardID)))}
- buttonProps={{success: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.SUCCESS}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/AddBankAccount.tsx b/src/pages/home/TimeSensitiveSection/items/AddBankAccount.tsx
index 0db3dc0226bf..28f6557d550f 100644
--- a/src/pages/home/TimeSensitiveSection/items/AddBankAccount.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/AddBankAccount.tsx
@@ -11,6 +11,7 @@ import {openPersonalBankAccountSetupView} from '@libs/actions/BankAccounts';
import colors from '@styles/theme/colors';
+import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import {isUserValidatedSelector} from '@selectors/Account';
@@ -30,7 +31,7 @@ function AddBankAccount() {
subtitle={translate('common.wallet')}
ctaText={translate('common.add')}
onCtaPress={() => openPersonalBankAccountSetupView({isUserValidated})}
- buttonProps={{success: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.SUCCESS}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/AddPaymentCard/index.tsx b/src/pages/home/TimeSensitiveSection/items/AddPaymentCard/index.tsx
index c937a11cb9de..d286f2e2e2a3 100644
--- a/src/pages/home/TimeSensitiveSection/items/AddPaymentCard/index.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/AddPaymentCard/index.tsx
@@ -6,6 +6,8 @@ import useTheme from '@hooks/useTheme';
import navigateToSubscriptionPayment from '@pages/home/common/navigateToSubscriptionPayment';
+import CONST from '@src/CONST';
+
import React from 'react';
function AddPaymentCard() {
@@ -22,7 +24,7 @@ function AddPaymentCard() {
subtitle={translate('homePage.timeSensitiveSection.addPaymentCard.subtitle')}
ctaText={translate('homePage.timeSensitiveSection.addPaymentCard.cta')}
onCtaPress={navigateToSubscriptionPayment}
- buttonProps={{success: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.SUCCESS}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/AddShippingAddress.tsx b/src/pages/home/TimeSensitiveSection/items/AddShippingAddress.tsx
index bbd8df424739..d65b6cbdea3e 100644
--- a/src/pages/home/TimeSensitiveSection/items/AddShippingAddress.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/AddShippingAddress.tsx
@@ -7,6 +7,7 @@ import useTheme from '@hooks/useTheme';
import Navigation from '@libs/Navigation/Navigation';
+import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import type {Card} from '@src/types/onyx';
@@ -29,7 +30,7 @@ function AddShippingAddress({card}: AddShippingAddressProps) {
subtitle={translate('homePage.timeSensitiveSection.addShippingAddress.subtitle')}
ctaText={translate('homePage.timeSensitiveSection.addShippingAddress.cta')}
onCtaPress={() => Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAIN_CARD.getRoute(String(card.cardID)))}
- buttonProps={{success: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.SUCCESS}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/AddVirtualCardPersonalDetails.tsx b/src/pages/home/TimeSensitiveSection/items/AddVirtualCardPersonalDetails.tsx
index 60b4ed6c744c..7386d73ef761 100644
--- a/src/pages/home/TimeSensitiveSection/items/AddVirtualCardPersonalDetails.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/AddVirtualCardPersonalDetails.tsx
@@ -8,6 +8,7 @@ import useTheme from '@hooks/useTheme';
import createDynamicRoute from '@libs/Navigation/helpers/dynamicRoutesUtils/createDynamicRoute';
import Navigation from '@libs/Navigation/Navigation';
+import CONST from '@src/CONST';
import {DYNAMIC_ROUTES} from '@src/ROUTES';
import type {Card} from '@src/types/onyx';
@@ -30,7 +31,7 @@ function AddVirtualCardPersonalDetails({card}: AddVirtualCardPersonalDetailsProp
subtitle={translate('homePage.timeSensitiveSection.addVirtualCardPersonalDetails.subtitle')}
ctaText={translate('homePage.timeSensitiveSection.addVirtualCardPersonalDetails.cta')}
onCtaPress={() => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.MISSING_PERSONAL_DETAILS.getRoute(String(card.cardID))))}
- buttonProps={{success: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.SUCCESS}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/EnterSignerInfo.tsx b/src/pages/home/TimeSensitiveSection/items/EnterSignerInfo.tsx
index 90d3cfa25d5f..28a49c92e27c 100644
--- a/src/pages/home/TimeSensitiveSection/items/EnterSignerInfo.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/EnterSignerInfo.tsx
@@ -7,6 +7,7 @@ import Navigation from '@libs/Navigation/Navigation';
import colors from '@styles/theme/colors';
+import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import React from 'react';
@@ -39,7 +40,7 @@ function EnterSignerInfo({policyID, bankAccountID, bankAccountLastFour}: EnterSi
subtitle={translate('homePage.timeSensitiveSection.enterSignerInfo.subtitle', {bankAccountLastFour})}
ctaText={translate('homePage.forYouSection.begin')}
onCtaPress={handleCtaPress}
- buttonProps={{success: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.SUCCESS}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/FixCompanyCardConnection.tsx b/src/pages/home/TimeSensitiveSection/items/FixCompanyCardConnection.tsx
index 4b4cda187a3e..281160bad0dc 100644
--- a/src/pages/home/TimeSensitiveSection/items/FixCompanyCardConnection.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/FixCompanyCardConnection.tsx
@@ -113,7 +113,7 @@ function FixCompanyCardConnection({card, policyID, policyName}: FixCompanyCardCo
}
Navigation.navigate(ROUTES.WORKSPACE_COMPANY_CARDS.getRoute(policyID));
}}
- buttonProps={{danger: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.DANGER}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/FixFailedBilling.tsx b/src/pages/home/TimeSensitiveSection/items/FixFailedBilling.tsx
index 4d9bd24e84d2..00695bb38b09 100644
--- a/src/pages/home/TimeSensitiveSection/items/FixFailedBilling.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/FixFailedBilling.tsx
@@ -7,6 +7,8 @@ import navigateToSubscriptionPayment from '@pages/home/common/navigateToSubscrip
import colors from '@styles/theme/colors';
+import CONST from '@src/CONST';
+
import React from 'react';
function FixFailedBilling() {
@@ -22,7 +24,7 @@ function FixFailedBilling() {
subtitle={translate('homePage.timeSensitiveSection.fixFailedBilling.subtitle')}
ctaText={translate('homePage.timeSensitiveSection.ctaFix')}
onCtaPress={navigateToSubscriptionPayment}
- buttonProps={{danger: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.DANGER}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/FixPersonalCardConnection.tsx b/src/pages/home/TimeSensitiveSection/items/FixPersonalCardConnection.tsx
index a16a7c809615..d6e3380efb1c 100644
--- a/src/pages/home/TimeSensitiveSection/items/FixPersonalCardConnection.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/FixPersonalCardConnection.tsx
@@ -7,6 +7,7 @@ import Navigation from '@libs/Navigation/Navigation';
import colors from '@styles/theme/colors';
+import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
import type {Card} from '@src/types/onyx';
@@ -30,7 +31,7 @@ function FixPersonalCardConnection({card}: FixPersonalCardConnectionProps) {
subtitle={translate('homePage.timeSensitiveSection.fixPersonalCardConnection.subtitle')}
ctaText={translate('homePage.timeSensitiveSection.ctaFix')}
onCtaPress={() => Navigation.navigate(ROUTES.SETTINGS_WALLET_PERSONAL_CARD_DETAILS.getRoute(String(card.cardID)))}
- buttonProps={{danger: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.DANGER}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/FixPolicyConnection.tsx b/src/pages/home/TimeSensitiveSection/items/FixPolicyConnection.tsx
index 758a2af4c0b0..4fc9a9e269f1 100644
--- a/src/pages/home/TimeSensitiveSection/items/FixPolicyConnection.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/FixPolicyConnection.tsx
@@ -47,7 +47,7 @@ function FixPolicyConnection({connectionName, policyID, policyName, integrationN
subtitle={subtitle}
ctaText={translate('homePage.timeSensitiveSection.ctaFix')}
onCtaPress={() => Navigation.navigate(fixRoute)}
- buttonProps={{danger: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.DANGER}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/ReviewCardFraud.tsx b/src/pages/home/TimeSensitiveSection/items/ReviewCardFraud.tsx
index 5813a23be4bd..0425be510099 100644
--- a/src/pages/home/TimeSensitiveSection/items/ReviewCardFraud.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/ReviewCardFraud.tsx
@@ -59,7 +59,7 @@ function ReviewCardFraud({possibleFraud}: ReviewCardFraudProps) {
subtitle={translate('homePage.timeSensitiveSection.reviewCardFraud.subtitle')}
ctaText={translate('homePage.timeSensitiveSection.reviewCardFraud.cta')}
onCtaPress={handleReviewPress}
- buttonProps={{danger: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.DANGER}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/UnlockBankAccount.tsx b/src/pages/home/TimeSensitiveSection/items/UnlockBankAccount.tsx
index 1f57963a01a2..4856ec92c0bc 100644
--- a/src/pages/home/TimeSensitiveSection/items/UnlockBankAccount.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/UnlockBankAccount.tsx
@@ -11,6 +11,7 @@ import {navigateToConciergeChat} from '@libs/actions/Report';
import colors from '@styles/theme/colors';
+import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import {hasSeenTourSelector} from '@selectors/Onboarding';
@@ -54,7 +55,7 @@ function UnlockBankAccount({bankAccountID, policyName}: UnlockBankAccountProps)
subtitle={subtitle}
ctaText={translate('homePage.timeSensitiveSection.ctaFix')}
onCtaPress={handleCtaPress}
- buttonProps={{danger: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.DANGER}
/>
);
}
diff --git a/src/pages/home/TimeSensitiveSection/items/ValidateAccount.tsx b/src/pages/home/TimeSensitiveSection/items/ValidateAccount.tsx
index a72a40a158be..167ca7f06a33 100644
--- a/src/pages/home/TimeSensitiveSection/items/ValidateAccount.tsx
+++ b/src/pages/home/TimeSensitiveSection/items/ValidateAccount.tsx
@@ -8,6 +8,7 @@ import Navigation from '@libs/Navigation/Navigation';
import colors from '@styles/theme/colors';
+import CONST from '@src/CONST';
import {DYNAMIC_ROUTES} from '@src/ROUTES';
import React from 'react';
@@ -25,7 +26,7 @@ function ValidateAccount() {
subtitle={translate('homePage.timeSensitiveSection.validateAccount.subtitle')}
ctaText={translate('homePage.timeSensitiveSection.validateAccount.cta')}
onCtaPress={() => Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.VERIFY_ACCOUNT.path))}
- buttonProps={{success: true}}
+ buttonVariant={CONST.BUTTON_VARIANT.SUCCESS}
/>
);
}
diff --git a/src/pages/settings/Wallet/PaymentMethodListItem.tsx b/src/pages/settings/Wallet/PaymentMethodListItem.tsx
index c747de3bcc4b..e639aa52b928 100644
--- a/src/pages/settings/Wallet/PaymentMethodListItem.tsx
+++ b/src/pages/settings/Wallet/PaymentMethodListItem.tsx
@@ -1,5 +1,5 @@
import Badge from '@components/Badge';
-import Button from '@components/Button';
+import Button from '@components/ButtonComposed';
import ConnectionStatusBadge from '@components/ConnectionStatusBadge';
import ConnectionStatusMessage from '@components/ConnectionStatusMessage';
import Hoverable from '@components/Hoverable';
@@ -329,11 +329,12 @@ function PaymentMethodListItem({item, shouldShowDefaultBadge, threeDotsMenuItems
{translate('walletPage.addVirtualCardPersonalDetails.subtitle')}
Navigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.MISSING_PERSONAL_DETAILS.getRoute(String(item.cardID))))}
- />
+ >
+ {translate('walletPage.addVirtualCardPersonalDetails.cta')}
+
)}
{isChaseAccountConnectedViaPlaid && (
diff --git a/src/pages/signin/ChooseSSOOrValidateCode.tsx b/src/pages/signin/ChooseSSOOrValidateCode.tsx
index 09f28c29ccaf..330c739cd972 100644
--- a/src/pages/signin/ChooseSSOOrValidateCode.tsx
+++ b/src/pages/signin/ChooseSSOOrValidateCode.tsx
@@ -1,4 +1,4 @@
-import Button from '@components/Button';
+import Button from '@components/ButtonComposed';
import FormHelpMessage from '@components/FormHelpMessage';
import Text from '@components/Text';
@@ -54,16 +54,17 @@ function ChooseSSOOrValidateCode({setIsUsingValidateCode}: ChooseSSOOrValidateCo
{translate('samlSignIn.welcomeSAMLEnabled')}
{
Navigation.navigate(ROUTES.SAML_SIGN_IN);
}}
sentryLabel={CONST.SENTRY_LABEL.SIGN_IN.SSO}
- />
+ >
+ {translate('samlSignIn.useSingleSignOn')}
+
@@ -74,15 +75,16 @@ function ChooseSSOOrValidateCode({setIsUsingValidateCode}: ChooseSSOOrValidateCo
{
resendValidateCode({reasonCode: COMMON_CONST.VALIDATE_CODE_REASONS.SIGN_IN}, credentials?.login);
setIsUsingValidateCode(true);
}}
sentryLabel={CONST.SENTRY_LABEL.SIGN_IN.VALIDATE_CODE}
- />
+ >
+ {translate('samlSignIn.useSecurityCode')}
+
{!!account && !isEmptyObject(account.errors) && }
clearSignInData()} />
diff --git a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx
index e2f750504502..1e6f423a0f77 100644
--- a/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx
+++ b/src/pages/workspace/members/WorkspaceMemberDetailsPage.tsx
@@ -353,11 +353,12 @@ function WorkspaceMemberDetailsPage({personalDetails, policy, route}: WorkspaceM
{isSelectedMemberOwner && isCurrentUserAdmin && !isCurrentUserOwner ? (
shouldRenderTransferOwnerButton(fundList) && (
+ >
+
+ {translate('workspace.people.transferOwner')}
+
)
) : (
void;
+ children?: React.ReactNode;
[key: string]: unknown;
};
const mockButtonSpy = jest.fn();
-jest.mock('@components/Button', () => {
+jest.mock('@components/ButtonComposed', () => {
const ReactLib = jest.requireActual('react');
+ const MockButton = (props: ButtonProps) => {
+ mockButtonSpy(props);
+ return ReactLib.createElement('mock-button', props);
+ };
return {
__esModule: true,
- default: (props: ButtonProps) => {
- mockButtonSpy(props);
- return ReactLib.createElement('mock-button', props);
- },
+ default: Object.assign(MockButton, {
+ Text: () => null,
+ Icon: () => null,
+ KeyboardShortcut: () => null,
+ }),
};
});
@@ -65,12 +71,9 @@ describe('ConfirmContent', () => {
mockButtonSpy.mockClear();
});
- function getConfirmButtonProps(shouldStackButtons: boolean): ButtonProps | undefined {
+ function getConfirmButtonProps(onConfirm: () => void): ButtonProps | undefined {
const calls = mockButtonSpy.mock.calls;
- if (shouldStackButtons) {
- return calls.find((call) => call[0].pressOnEnter)?.[0];
- }
- return calls.find((call) => call[0].pressOnEnter)?.[0];
+ return calls.find((call) => call[0].onPress === onConfirm)?.[0];
}
const testCases = [
@@ -84,15 +87,26 @@ describe('ConfirmContent', () => {
{shouldShowCancelButton: true, danger: true, success: true, expectedSuccess: false},
];
+ function expectedVariant(danger: boolean, expectedSuccess: boolean): string | undefined {
+ if (danger) {
+ return CONST.BUTTON_VARIANT.DANGER;
+ }
+ if (expectedSuccess) {
+ return CONST.BUTTON_VARIANT.SUCCESS;
+ }
+ return undefined;
+ }
+
describe('stacked buttons (shouldStackButtons=true)', () => {
it.each(testCases)(
- 'confirm button success=$expectedSuccess when shouldShowCancelButton=$shouldShowCancelButton, danger=$danger, success=$success',
+ 'confirm button variant=$expectedSuccess when shouldShowCancelButton=$shouldShowCancelButton, danger=$danger, success=$success',
({shouldShowCancelButton, danger, success, expectedSuccess}) => {
mockButtonSpy.mockClear();
+ const onConfirm = jest.fn();
render(
{
/>,
);
- const confirmProps = getConfirmButtonProps(true);
- expect(confirmProps?.success).toBe(expectedSuccess);
- expect(confirmProps?.danger).toBe(danger);
+ const confirmProps = getConfirmButtonProps(onConfirm);
+ expect(confirmProps?.variant).toBe(expectedVariant(danger, expectedSuccess));
},
);
});
describe('side-by-side buttons (shouldStackButtons=false)', () => {
it.each(testCases)(
- 'confirm button success=$expectedSuccess when shouldShowCancelButton=$shouldShowCancelButton, danger=$danger, success=$success',
+ 'confirm button variant=$expectedSuccess when shouldShowCancelButton=$shouldShowCancelButton, danger=$danger, success=$success',
({shouldShowCancelButton, danger, success, expectedSuccess}) => {
mockButtonSpy.mockClear();
+ const onConfirm = jest.fn();
render(
{
/>,
);
- const confirmProps = getConfirmButtonProps(false);
- expect(confirmProps?.success).toBe(expectedSuccess);
- expect(confirmProps?.danger).toBe(danger);
+ const confirmProps = getConfirmButtonProps(onConfirm);
+ expect(confirmProps?.variant).toBe(expectedVariant(danger, expectedSuccess));
},
);
});