diff --git a/src/App.tsx b/src/App.tsx index 7cef56629c77e..1bf42a54d2a5a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,7 +19,6 @@ import InitialURLContextProvider from './components/InitialURLContextProvider'; import {InputBlurContextProvider} from './components/InputBlurContext'; import KeyboardProvider from './components/KeyboardProvider'; import {LocaleContextProvider} from './components/LocaleContextProvider'; -import {ModalProvider} from './components/Modal/Global'; import NavigationBar from './components/NavigationBar'; import OnyxListItemProvider from './components/OnyxListItemProvider'; import PopoverContextProvider from './components/PopoverProvider'; @@ -116,7 +115,6 @@ function App() { InputBlurContextProvider, FullScreenBlockingViewContextProvider, FullScreenLoaderContextProvider, - ModalProvider, SidePanelContextProvider, ]} > diff --git a/src/components/ConfirmModal.tsx b/src/components/ConfirmModal.tsx index 2ac8d1a398af3..bd6db12b03d85 100755 --- a/src/components/ConfirmModal.tsx +++ b/src/components/ConfirmModal.tsx @@ -214,4 +214,3 @@ function ConfirmModal({ ConfirmModal.displayName = 'ConfirmModal'; export default ConfirmModal; -export type {ConfirmModalProps}; diff --git a/src/components/Modal/Global/ConfirmModalWrapper.tsx b/src/components/Modal/Global/ConfirmModalWrapper.tsx deleted file mode 100644 index 0897cb9cbfafb..0000000000000 --- a/src/components/Modal/Global/ConfirmModalWrapper.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React, {useCallback} from 'react'; -import type {ConfirmModalProps} from '@components/ConfirmModal'; -import ConfirmModal from '@components/ConfirmModal'; -import type {ModalProps} from './ModalContext'; - -type ConfirmModalWrapperProps = ModalProps & Omit; - -// This wrapper bridges the ConfirmModal API with the global modal system, providing handlers for the onConfirm and onCancel callbacks to ConfirmModal. -// TODOS after migrating all ConfirmModal instances to use showConfirmModal: -// - handle closeModal inside ConfirmModal -// - remove ConfirmModalWrapper - -function ConfirmModalWrapper({ - closeModal, - title = '', - prompt = '', - confirmText = '', - cancelText = '', - success = true, - danger = false, - shouldDisableConfirmButtonWhenOffline = false, - shouldShowCancelButton = true, - shouldSetModalVisibility = true, - shouldShowDismissIcon = false, - shouldCenterContent = false, - shouldStackButtons = true, - shouldReverseStackedButtons = false, - isConfirmLoading = false, -}: ConfirmModalWrapperProps) { - const handleConfirm = useCallback(() => { - closeModal({action: 'CONFIRM'}); - }, [closeModal]); - - const handleCancel = useCallback(() => { - closeModal({action: 'CLOSE'}); - }, [closeModal]); - - return ( - - ); -} - -ConfirmModalWrapper.displayName = 'ConfirmModalWrapper'; - -export default ConfirmModalWrapper; diff --git a/src/components/Modal/Global/ModalContext.tsx b/src/components/Modal/Global/ModalContext.tsx deleted file mode 100644 index 93f4b63d0c117..0000000000000 --- a/src/components/Modal/Global/ModalContext.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import noop from 'lodash/noop'; -import React, {useCallback, useContext, useMemo, useState} from 'react'; -import Log from '@libs/Log'; -import CONST from '@src/CONST'; - -type ModalAction = 'CONFIRM' | 'CLOSE'; - -type ModalStateChangePayload = {action: A}; - -type ModalProps = { - closeModal: (param?: ModalStateChangePayload) => void; -}; - -type ModalContextType = { - showModal

(options: {component: React.FunctionComponent

; props?: Omit; id?: string; isCloseable?: boolean}): Promise; - closeModal(data?: ModalStateChangePayload): void; -}; - -const ModalContext = React.createContext({ - showModal: () => Promise.resolve({action: 'CLOSE'}), - closeModal: noop, -}); - -const useModal = () => useContext(ModalContext); - -let modalID = 1; - -type ModalInfo = { - id: string; - component: React.FunctionComponent; - props?: Record; - promiseWithResolvers: ReturnType>; - isCloseable: boolean; -}; - -function PromiseModalProvider({children}: {children: React.ReactNode}) { - const [modalStack, setModalStack] = useState<{modals: ModalInfo[]}>({modals: []}); - - const showModal = useCallback(({component, props, id, isCloseable = true}) => { - // This is a promise that will resolve when the modal is closed - let closeModalPromise: Promise | null = null; - - setModalStack((prevState) => { - // Check current state for existing modal - const existingModal = id ? prevState.modals.find((modal: ModalInfo) => modal.id === id) : undefined; - if (existingModal) { - // There is already a modal with this ID. Return the existing promise and don't modify state. - closeModalPromise = existingModal.promiseWithResolvers.promise; - return prevState; // No state change needed - } - - // Create a new promise with resolvers to be resolved when the modal is closed - const promiseWithResolvers = Promise.withResolvers(); - closeModalPromise = promiseWithResolvers.promise; - - return { - ...prevState, - modals: [...prevState.modals, {component: component as React.FunctionComponent, props, promiseWithResolvers, isCloseable, id: id ?? String(modalID++)}], - }; - }); - - // At this point, closeModalPromise should always be assigned - if (!closeModalPromise) { - Log.alert(`${CONST.ERROR.ENSURE_BUG_BOT} Failed to create modal promise. This should never happen.`); - throw new Error('Failed to create modal promise'); - } - - return closeModalPromise; - }, []); - - const closeModal = useCallback((data = {action: 'CLOSE'}) => { - setModalStack((prevState) => { - const lastModal = prevState.modals.at(-1); - lastModal?.promiseWithResolvers.resolve(data); - return { - ...prevState, - modals: prevState.modals.slice(0, -1), - }; - }); - }, []); - - const contextValue = useMemo(() => ({showModal, closeModal}), [closeModal, showModal]); - const modalToRender = modalStack.modals.length > 0 ? modalStack.modals.at(modalStack.modals.length - 1) : null; - const ModalComponent = modalToRender?.component; - - return ( - - {children} - {!!ModalComponent && ( - - )} - - ); -} - -export type {ModalProps}; -export {PromiseModalProvider, useModal}; diff --git a/src/components/Modal/Global/index.ts b/src/components/Modal/Global/index.ts deleted file mode 100644 index f2c3ac87c3203..0000000000000 --- a/src/components/Modal/Global/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export {PromiseModalProvider, useModal} from './ModalContext'; -export {default as useModalHook} from './useModalHook'; -export {default as ConfirmModalWrapper} from './ConfirmModalWrapper'; -export type {ModalProps} from './ModalContext'; - -export {PromiseModalProvider as ModalProvider} from './ModalContext'; -export {default as usePromiseModal} from './useModalHook'; diff --git a/src/components/Modal/Global/useModalHook.tsx b/src/components/Modal/Global/useModalHook.tsx deleted file mode 100644 index b6d5b3737d281..0000000000000 --- a/src/components/Modal/Global/useModalHook.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import ConfirmModalWrapper from './ConfirmModalWrapper'; -import {useModal} from './ModalContext'; -import type {ModalProps} from './ModalContext'; - -type ConfirmModalOptions = Omit, keyof ModalProps>; - -const useConfirmModal = () => { - const context = useModal(); - - const showConfirmModal = (options: ConfirmModalOptions) => { - return context.showModal({ - component: ConfirmModalWrapper, - props: options, - }); - }; - - return { - ...context, - showConfirmModal, - }; -}; - -export default useConfirmModal; diff --git a/src/components/MoneyReportHeader.tsx b/src/components/MoneyReportHeader.tsx index e617b1906a166..3a5190a486fc2 100644 --- a/src/components/MoneyReportHeader.tsx +++ b/src/components/MoneyReportHeader.tsx @@ -108,6 +108,7 @@ import BrokenConnectionDescription from './BrokenConnectionDescription'; import Button from './Button'; import ButtonWithDropdownMenu from './ButtonWithDropdownMenu'; import type {DropdownOption} from './ButtonWithDropdownMenu/types'; +import ConfirmModal from './ConfirmModal'; import DecisionModal from './DecisionModal'; import {DelegateNoAccessContext} from './DelegateNoAccessModalProvider'; import Header from './Header'; @@ -118,7 +119,6 @@ import KYCWall from './KYCWall'; import type {PaymentMethod} from './KYCWall/types'; import LoadingBar from './LoadingBar'; import Modal from './Modal'; -import useConfirmModal from './Modal/Global/useModalHook'; import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar'; import MoneyReportHeaderStatusBarSkeleton from './MoneyReportHeaderStatusBarSkeleton'; import type {MoneyRequestHeaderStatusBarProps} from './MoneyRequestHeaderStatusBar'; @@ -141,6 +141,7 @@ type MoneyReportHeaderProps = { reportActions: OnyxTypes.ReportAction[]; /** The reportID of the transaction thread report associated with this current report, if any */ + // eslint-disable-next-line react/no-unused-prop-types transactionThreadReportID: string | undefined; /** whether we are loading report data in openReport command */ @@ -241,9 +242,13 @@ function MoneyReportHeader({ }, [isExported, reportActions]); const [downloadErrorModalVisible, setDownloadErrorModalVisible] = useState(false); + const [isCancelPaymentModalVisible, setIsCancelPaymentModalVisible] = useState(false); + const [isDeleteExpenseModalVisible, setIsDeleteExpenseModalVisible] = useState(false); + const [isDeleteReportModalVisible, setIsDeleteReportModalVisible] = useState(false); + const [isUnapproveModalVisible, setIsUnapproveModalVisible] = useState(false); + const [isReopenWarningModalVisible, setIsReopenWarningModalVisible] = useState(false); const [isPDFModalVisible, setIsPDFModalVisible] = useState(false); - - const {showConfirmModal} = useConfirmModal(); + const [isExportWithTemplateModalVisible, setIsExportWithTemplateModalVisible] = useState(false); const [exportModalStatus, setExportModalStatus] = useState(null); @@ -303,27 +308,13 @@ function MoneyReportHeader({ const {selectedTransactionIDs, clearSelectedTransactions, currentSearchQueryJSON, currentSearchKey} = useSearchContext(); - const showExportProgressModal = useCallback(() => { - return showConfirmModal({ - title: translate('export.exportInProgress'), - prompt: translate('export.conciergeWillSend'), - confirmText: translate('common.buttonConfirm'), - shouldShowCancelButton: false, - }); - }, [showConfirmModal, translate]); - const beginExportWithTemplate = useCallback( (templateName: string, templateType: string, transactionIDList: string[], policyID?: string) => { if (!moneyRequestReport) { return; } - showExportProgressModal().then((result) => { - if (result.action !== 'CONFIRM') { - return; - } - clearSelectedTransactions(undefined, true); - }); + setIsExportWithTemplateModalVisible(true); queueExportSearchWithTemplate({ templateName, templateType, @@ -333,7 +324,7 @@ function MoneyReportHeader({ policyID, }); }, - [moneyRequestReport, showExportProgressModal, clearSelectedTransactions], + [moneyRequestReport], ); const handleGoBackAfterDeleteExpenses = useCallback(() => { @@ -348,7 +339,12 @@ function MoneyReportHeader({ Navigation.goBack(route.params?.backTo); }, [route]); - const {options: originalSelectedTransactionsOptions, handleDeleteTransactions} = useSelectedTransactionsActions({ + const { + options: selectedTransactionsOptions, + handleDeleteTransactions, + isDeleteModalVisible: hookDeleteModalVisible, + hideDeleteModal, + } = useSelectedTransactionsActions({ report: moneyRequestReport, reportActions, allTransactionsLength: transactions.length, @@ -358,6 +354,8 @@ function MoneyReportHeader({ beginExportWithTemplate: (templateName, templateType, transactionIDList, policyID) => beginExportWithTemplate(templateName, templateType, transactionIDList, policyID), }); + const shouldShowSelectedTransactionsButton = !!selectedTransactionsOptions.length && !transactionThreadReportID; + const canIOUBePaid = useMemo(() => getCanIOUBePaid(), [getCanIOUBePaid]); const onlyShowPayElsewhere = useMemo(() => !canIOUBePaid && getCanIOUBePaid(true), [canIOUBePaid, getCanIOUBePaid]); @@ -892,28 +890,6 @@ function MoneyReportHeader({ return getSecondaryExportReportActions(moneyRequestReport, policy, reportActions, integrationsExportTemplates ?? [], customInAppTemplates ?? []); }, [moneyRequestReport, policy, reportActions, integrationsExportTemplates, customInAppTemplates]); - const connectedIntegrationName = connectedIntegration ? translate('workspace.accounting.connectionName', {connectionName: connectedIntegration}) : ''; - - const unapproveWarningText = useMemo( - () => ( - - {translate('iou.headsUp')}{' '} - {translate('iou.unapproveWithIntegrationWarning', {accountingIntegration: connectedIntegrationName})} - - ), - [connectedIntegrationName, styles.noWrap, styles.textStrong, translate], - ); - - const reopenExportedReportWarningText = useMemo( - () => ( - - {translate('iou.headsUp')} - {translate('iou.reopenExportedReportConfirmation', {connectionName: integrationNameFromExportMessage ?? ''})} - - ), - [integrationNameFromExportMessage, styles.noWrap, styles.textStrong, translate], - ); - const secondaryActionsImplementation: Record< ValueOf, DropdownOption> & Pick @@ -973,18 +949,7 @@ function MoneyReportHeader({ } if (isExported) { - showConfirmModal({ - title: translate('iou.unapproveReport'), - prompt: unapproveWarningText, - confirmText: translate('iou.unapproveReport'), - cancelText: translate('common.cancel'), - danger: true, - }).then((result) => { - if (result.action !== 'CONFIRM') { - return; - } - unapproveExpenseReport(moneyRequestReport); - }); + setIsUnapproveModalVisible(true); return; } @@ -996,18 +961,7 @@ function MoneyReportHeader({ icon: Expensicons.Clear, value: CONST.REPORT.SECONDARY_ACTIONS.CANCEL_PAYMENT, onSelected: () => { - showConfirmModal({ - title: translate('iou.cancelPayment'), - prompt: translate('iou.cancelPaymentConfirmation'), - confirmText: translate('iou.cancelPayment'), - cancelText: translate('common.dismiss'), - danger: true, - }).then((result) => { - if (result.action !== 'CONFIRM' || !chatReport) { - return; - } - cancelPayment(moneyRequestReport, chatReport); - }); + setIsCancelPaymentModalVisible(true); }, }, [CONST.REPORT.SECONDARY_ACTIONS.HOLD]: { @@ -1095,47 +1049,9 @@ function MoneyReportHeader({ value: CONST.REPORT.SECONDARY_ACTIONS.DELETE, onSelected: () => { if (Object.keys(transactions).length === 1) { - showConfirmModal({ - title: translate('iou.deleteExpense', {count: 1}), - prompt: translate('iou.deleteConfirmation', {count: 1}), - confirmText: translate('common.delete'), - cancelText: translate('common.cancel'), - danger: true, - }).then((result) => { - if (result.action !== 'CONFIRM') { - return; - } - let goBackRoute: Route | undefined; - if (transactionThreadReportID) { - if (!requestParentReportAction || !transaction?.transactionID) { - throw new Error('Missing data!'); - } - InteractionManager.runAfterInteractions(() => - deleteMoneyRequest(transaction?.transactionID, requestParentReportAction, duplicateTransactions, duplicateTransactionViolations), - ); - goBackRoute = getNavigationUrlOnMoneyRequestDelete(transaction.transactionID, requestParentReportAction, false); - } - - if (goBackRoute) { - Navigation.setNavigationActionToMicrotaskQueue(() => navigateOnDeleteExpense(goBackRoute)); - } - }); + setIsDeleteExpenseModalVisible(true); } else { - showConfirmModal({ - title: translate('iou.deleteExpense', {count: Object.keys(transactions).length}), - prompt: translate('iou.deleteConfirmation', {count: Object.keys(transactions).length}), - confirmText: translate('common.delete'), - cancelText: translate('common.cancel'), - danger: true, - }).then((result) => { - if (result.action !== 'CONFIRM') { - return; - } - const reportID = moneyRequestReport?.reportID; - if (reportID) { - deleteAppReport(reportID); - } - }); + setIsDeleteReportModalVisible(true); } }, }, @@ -1153,18 +1069,7 @@ function MoneyReportHeader({ value: CONST.REPORT.SECONDARY_ACTIONS.REOPEN, onSelected: () => { if (isExported) { - showConfirmModal({ - title: translate('iou.reopenReport'), - prompt: reopenExportedReportWarningText, - confirmText: translate('iou.reopenReport'), - cancelText: translate('common.cancel'), - danger: true, - }).then((result) => { - if (result.action !== 'CONFIRM') { - return; - } - reopenReport(moneyRequestReport); - }); + setIsReopenWarningModalVisible(true); return; } reopenReport(moneyRequestReport); @@ -1199,64 +1104,6 @@ function MoneyReportHeader({ const applicableSecondaryActions = secondaryActions .map((action) => secondaryActionsImplementation[action]) .filter((action) => action?.shouldShow !== false && action?.value !== primaryAction); - - const showDeleteModal = useCallback(() => { - showConfirmModal({ - title: translate('iou.deleteExpense', {count: selectedTransactionIDs.length}), - prompt: translate('iou.deleteConfirmation', {count: selectedTransactionIDs.length}), - confirmText: translate('common.delete'), - cancelText: translate('common.cancel'), - danger: true, - }).then((result) => { - if (result.action !== 'CONFIRM') { - return; - } - if (transactions.filter((trans) => trans.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length === selectedTransactionIDs.length) { - handleGoBackAfterDeleteExpenses(); - } - handleDeleteTransactions(); - }); - }, [showConfirmModal, translate, selectedTransactionIDs.length, transactions, handleDeleteTransactions, handleGoBackAfterDeleteExpenses]); - - const showExportModal = useCallback(() => { - if (!connectedIntegration) { - return; - } - showConfirmModal({ - title: translate('workspace.exportAgainModal.title'), - prompt: translate('workspace.exportAgainModal.description', { - connectionName: connectedIntegration ?? connectedIntegrationFallback, - reportName: moneyRequestReport?.reportName ?? '', - }), - confirmText: translate('workspace.exportAgainModal.confirmText'), - cancelText: translate('workspace.exportAgainModal.cancelText'), - }).then((result) => { - if (result.action !== 'CONFIRM') { - return; - } - confirmExport(); - }); - }, [showConfirmModal, translate, connectedIntegration, connectedIntegrationFallback, moneyRequestReport?.reportName, confirmExport]); - - useEffect(() => { - if (!exportModalStatus) { - return; - } - showExportModal(); - }, [exportModalStatus, showExportModal]); - - const selectedTransactionsOptions = useMemo(() => { - return originalSelectedTransactionsOptions.map((option) => { - if (option.text === translate('common.delete')) { - return { - ...option, - onSelected: showDeleteModal, - }; - } - return option; - }); - }, [originalSelectedTransactionsOptions, translate, showDeleteModal]); - useEffect(() => { if (!transactionThreadReportID) { return; @@ -1269,7 +1116,16 @@ function MoneyReportHeader({ const shouldShowBackButton = shouldDisplayBackButton || shouldUseNarrowLayout; - const shouldShowSelectedTransactionsButton = !!selectedTransactionsOptions.length && !transactionThreadReportID; + const connectedIntegrationName = connectedIntegration ? translate('workspace.accounting.connectionName', {connectionName: connectedIntegration}) : ''; + const unapproveWarningText = useMemo( + () => ( + + {translate('iou.headsUp')}{' '} + {translate('iou.unapproveWithIntegrationWarning', {accountingIntegration: connectedIntegrationName})} + + ), + [connectedIntegrationName, styles.noWrap, styles.textStrong, translate], + ); const isMobileSelectionModeEnabled = useMobileSelectionMode(); @@ -1290,6 +1146,12 @@ function MoneyReportHeader({ ); } + const reopenExportedReportWarningText = ( + + {translate('iou.headsUp')} + {translate('iou.reopenExportedReportConfirmation', {connectionName: integrationNameFromExportMessage ?? ''})} + + ); const onPaymentSelect = (event: KYCFlowEvent, iouPaymentType: PaymentMethodType, triggerKYCFlow: TriggerKYCFlow) => selectPaymentType(event, iouPaymentType, triggerKYCFlow, policy, confirmPayment, isUserValidated, confirmApproval, moneyRequestReport); @@ -1433,6 +1295,124 @@ function MoneyReportHeader({ isVisible={downloadErrorModalVisible} onClose={() => setDownloadErrorModalVisible(false)} /> + { + if (!chatReport) { + return; + } + cancelPayment(moneyRequestReport, chatReport); + setIsCancelPaymentModalVisible(false); + }} + onCancel={() => setIsCancelPaymentModalVisible(false)} + prompt={translate('iou.cancelPaymentConfirmation')} + confirmText={translate('iou.cancelPayment')} + cancelText={translate('common.dismiss')} + danger + shouldEnableNewFocusManagement + /> + { + let goBackRoute: Route | undefined; + setIsDeleteExpenseModalVisible(false); + if (transactionThreadReportID) { + if (!requestParentReportAction || !transaction?.transactionID) { + throw new Error('Missing data!'); + } + // it's deleting transaction but not the report which leads to bug (that is actually also on staging) + // Money request should be deleted when interactions are done, to not show the not found page before navigating to goBackRoute + InteractionManager.runAfterInteractions(() => + deleteMoneyRequest(transaction?.transactionID, requestParentReportAction, duplicateTransactions, duplicateTransactionViolations), + ); + goBackRoute = getNavigationUrlOnMoneyRequestDelete(transaction.transactionID, requestParentReportAction, false); + } + + if (goBackRoute) { + Navigation.setNavigationActionToMicrotaskQueue(() => navigateOnDeleteExpense(goBackRoute)); + } + }} + onCancel={() => setIsDeleteExpenseModalVisible(false)} + prompt={translate('iou.deleteConfirmation', {count: 1})} + confirmText={translate('common.delete')} + cancelText={translate('common.cancel')} + danger + shouldEnableNewFocusManagement + /> + { + if (transactions.filter((trans) => trans.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length === selectedTransactionIDs.length) { + handleGoBackAfterDeleteExpenses(); + } + handleDeleteTransactions(); + }} + onCancel={hideDeleteModal} + prompt={translate('iou.deleteConfirmation', {count: selectedTransactionIDs.length})} + confirmText={translate('common.delete')} + cancelText={translate('common.cancel')} + danger + shouldEnableNewFocusManagement + /> + { + setIsDeleteReportModalVisible(false); + + Navigation.goBack(); + InteractionManager.runAfterInteractions(() => { + deleteAppReport(moneyRequestReport?.reportID); + }); + }} + onCancel={() => setIsDeleteReportModalVisible(false)} + prompt={translate('iou.deleteReportConfirmation')} + confirmText={translate('common.delete')} + cancelText={translate('common.cancel')} + danger + shouldEnableNewFocusManagement + /> + {!!connectedIntegration && ( + setExportModalStatus(null)} + prompt={translate('workspace.exportAgainModal.description', {connectionName: connectedIntegration, reportName: moneyRequestReport?.reportName ?? ''})} + confirmText={translate('workspace.exportAgainModal.confirmText')} + cancelText={translate('workspace.exportAgainModal.cancelText')} + isVisible={!!exportModalStatus} + /> + )} + { + setIsUnapproveModalVisible(false); + unapproveExpenseReport(moneyRequestReport); + }} + cancelText={translate('common.cancel')} + onCancel={() => setIsUnapproveModalVisible(false)} + prompt={unapproveWarningText} + /> + { + setIsReopenWarningModalVisible(false); + reopenReport(moneyRequestReport); + }} + cancelText={translate('common.cancel')} + onCancel={() => setIsReopenWarningModalVisible(false)} + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + prompt={reopenExportedReportWarningText} + /> + { + setIsExportWithTemplateModalVisible(false); + clearSelectedTransactions(undefined, true); + }} + onCancel={() => setIsExportWithTemplateModalVisible(false)} + isVisible={isExportWithTemplateModalVisible} + title={translate('export.exportInProgress')} + prompt={translate('export.conciergeWillSend')} + confirmText={translate('common.buttonConfirm')} + shouldShowCancelButton={false} + /> ); }