diff --git a/src/languages/en.ts b/src/languages/en.ts index 78932053ee2f..0aa886dd2df6 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -3530,6 +3530,13 @@ export default { changeCurrency: 'Change payment currency', cardNotFound: 'No payment card added', retryPaymentButton: 'Retry payment', + requestRefund: 'Request refund', + requestRefundModal: { + phrase1: 'Getting a refund is easy, just downgrade your account before your next billing date and you’ll receive a refund.', + phrase2: + 'Heads up: Downgrading your account means your workspace(s) will be deleted. This action can’t be undone, but you can always create a new workspace if you change your mind.', + confirm: 'Delete workspace(s) and downgrade', + }, viewPaymentHistory: 'View payment history', }, yourPlan: { diff --git a/src/languages/es.ts b/src/languages/es.ts index fe67b48a5b70..b1d78ca7ad5b 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -4032,6 +4032,13 @@ export default { changeCurrency: 'Cambiar moneda de pago', cardNotFound: 'No se ha añadido ninguna tarjeta de pago', retryPaymentButton: 'Reintentar el pago', + requestRefund: 'Solicitar reembolso', + requestRefundModal: { + phrase1: 'Obtener un reembolso es fácil, simplemente baja tu cuenta de categoría antes de la próxima fecha de facturación y recibirás un reembolso.', + phrase2: + 'Atención: Bajar tu cuenta de categoría significa que tu(s) espacio(s) de trabajo será(n) eliminado(s). Esta acción no se puede deshacer, pero siempre puedes crear un nuevo espacio de trabajo si cambias de opinión.', + confirm: 'Eliminar y degradar', + }, viewPaymentHistory: 'Ver historial de pagos', }, yourPlan: { diff --git a/src/libs/API/types.ts b/src/libs/API/types.ts index 1d6456f3df47..c448fc9aa1f4 100644 --- a/src/libs/API/types.ts +++ b/src/libs/API/types.ts @@ -229,6 +229,7 @@ const WRITE_COMMANDS = { UPDATE_SUBSCRIPTION_AUTO_RENEW: 'UpdateSubscriptionAutoRenew', UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY: 'UpdateSubscriptionAddNewUsersAutomatically', UPDATE_SUBSCRIPTION_SIZE: 'UpdateSubscriptionSize', + REQUEST_REFUND: 'User_RefundPurchase', UPDATE_NETSUITE_SUBSIDIARY: 'UpdateNetSuiteSubsidiary', UPDATE_NETSUITE_EXPORTER: 'UpdateNetSuiteExporter', UPDATE_NETSUITE_EXPORT_DATE: 'UpdateNetSuiteExportDate', @@ -475,6 +476,7 @@ type WriteCommandParameters = { [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_AUTO_RENEW]: Parameters.UpdateSubscriptionAutoRenewParams; [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_ADD_NEW_USERS_AUTOMATICALLY]: Parameters.UpdateSubscriptionAddNewUsersAutomaticallyParams; [WRITE_COMMANDS.UPDATE_SUBSCRIPTION_SIZE]: Parameters.UpdateSubscriptionSizeParams; + [WRITE_COMMANDS.REQUEST_REFUND]: null; [WRITE_COMMANDS.CONNECT_POLICY_TO_SAGE_INTACCT]: Parameters.ConnectPolicyToSageIntacctParams; // Netsuite parameters diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index fbeed3cd72e9..7acc79485f0c 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -1022,6 +1022,10 @@ function dismissTrackTrainingModal() { }); } +function requestRefund() { + API.write(WRITE_COMMANDS.REQUEST_REFUND, null); +} + export { clearFocusModeNotification, closeAccount, @@ -1053,4 +1057,5 @@ export { clearCustomStatus, updateDraftCustomStatus, clearDraftCustomStatus, + requestRefund, }; diff --git a/src/pages/settings/Subscription/CardSection/CardSection.tsx b/src/pages/settings/Subscription/CardSection/CardSection.tsx index 006baf3a4c0f..4bafb3c1d56f 100644 --- a/src/pages/settings/Subscription/CardSection/CardSection.tsx +++ b/src/pages/settings/Subscription/CardSection/CardSection.tsx @@ -1,14 +1,17 @@ -import React, {useMemo} from 'react'; +import React, {useCallback, useMemo, useState} from 'react'; import {View} from 'react-native'; import {useOnyx} from 'react-native-onyx'; +import ConfirmModal from '@components/ConfirmModal'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import MenuItem from '@components/MenuItem'; import Section from '@components/Section'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import useSubscriptionPlan from '@hooks/useSubscriptionPlan'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as User from '@libs/actions/User'; import DateUtils from '@libs/DateUtils'; import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; @@ -22,17 +25,26 @@ import CardSectionDataEmpty from './CardSectionDataEmpty'; import CardSectionUtils from './utils'; function CardSection() { + const [isRequestRefundModalVisible, setIsRequestRefundModalVisible] = useState(false); const {translate, preferredLocale} = useLocalize(); const styles = useThemeStyles(); const theme = useTheme(); const [account] = useOnyx(ONYXKEYS.ACCOUNT); const [privateSubscription] = useOnyx(ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION); const [fundList] = useOnyx(ONYXKEYS.FUND_LIST); + const subscriptionPlan = useSubscriptionPlan(); + const [network] = useOnyx(ONYXKEYS.NETWORK); const defaultCard = useMemo(() => Object.values(fundList ?? {}).find((card) => card.accountData?.additionalData?.isBillingCard), [fundList]); const cardMonth = useMemo(() => DateUtils.getMonthNames(preferredLocale)[(defaultCard?.accountData?.cardMonth ?? 1) - 1], [defaultCard?.accountData?.cardMonth, preferredLocale]); + const requestRefund = useCallback(() => { + User.requestRefund(); + setIsRequestRefundModalVisible(false); + Navigation.resetToHome(); + }, []); + const billingStatus = CardSectionUtils.getBillingStatus(translate, defaultCard?.accountData?.cardNumber ?? ''); const nextPaymentDate = !isEmptyObject(privateSubscription) ? CardSectionUtils.getNextBillingDate() : undefined; @@ -55,17 +67,17 @@ function CardSection() { } return ( -
- - {!isEmptyObject(defaultCard?.accountData) && ( - <> + <> +
+ + {!isEmptyObject(defaultCard?.accountData) && ( + - - - )} + )} + + {isEmptyObject(defaultCard?.accountData) && } - - {!!account?.hasPurchases && ( - Navigation.navigate(ROUTES.SEARCH.getRoute(CONST.SEARCH.TAB.ALL))} - hoverAndPressStyle={styles.hoveredComponentBG} + {!!account?.hasPurchases && ( + Navigation.navigate(ROUTES.SEARCH.getRoute(CONST.SEARCH.TAB.ALL))} + hoverAndPressStyle={styles.hoveredComponentBG} + /> + )} + {!!(subscriptionPlan && account?.isEligibleForRefund) && ( + setIsRequestRefundModalVisible(true)} + /> + )} +
+ + {account?.isEligibleForRefund && ( + setIsRequestRefundModalVisible(false)} + prompt={ + <> + {translate('subscription.cardSection.requestRefundModal.phrase1')} + {translate('subscription.cardSection.requestRefundModal.phrase2')} + + } + confirmText={translate('subscription.cardSection.requestRefundModal.confirm')} + cancelText={translate('common.cancel')} + danger /> )} -
+ ); } diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts index 2a0efaaf84ff..9149221bc64f 100644 --- a/src/types/onyx/Account.ts +++ b/src/types/onyx/Account.ts @@ -80,6 +80,9 @@ type Account = { /** Indicates whether the user can downgrade current subscription plan */ canDowngrade?: boolean; + /** Indicates whether the user can downgrade current subscription plan */ + isEligibleForRefund?: boolean; + /** Indicates whether the user has at least one previous purchase */ hasPurchases?: boolean; };