Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Payment card / Subscription] Integrate failed billing scenarios banner with backend data #44072

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4394366
implement subscription utils, add banner show logic
pasyukevich Jun 14, 2024
2c22d47
fix locale type
pasyukevich Jun 14, 2024
99bb6ea
Merge branch 'main' into feature/billing-banner-logic-api-integration
JKobrynski Jun 18, 2024
d511850
fix runtime errors
JKobrynski Jun 19, 2024
54bf99e
add missing cases
JKobrynski Jun 19, 2024
1e397fa
Merge branch 'main' into feature/billing-banner-logic-api-integration
JKobrynski Jun 20, 2024
b420547
lint the code
JKobrynski Jun 20, 2024
c46f6b0
remove unnecessary condition
JKobrynski Jun 20, 2024
9c7bf73
fix typecheck errors
JKobrynski Jun 20, 2024
1494877
update and fix the error cases, show the right icons, handle errors
JKobrynski Jun 21, 2024
29c408d
Merge branch 'main' into feature/billing-banner-logic-api-integration
JKobrynski Jun 21, 2024
d31b7e5
remove redundant BillingBanner component
JKobrynski Jun 21, 2024
73e3a9c
remove unnecessary edge case
JKobrynski Jun 21, 2024
6d2cb30
remove unnecessary space in translation
JKobrynski Jun 21, 2024
0a6905c
remove leftovers, apply suggested changes
JKobrynski Jun 21, 2024
70b30d4
remove unnecessary empty line
JKobrynski Jun 21, 2024
1e0a8aa
Merge branch 'main' into feature/billing-banner-logic-api-integration
JKobrynski Jun 24, 2024
db92789
apply changes based on feedback from Fabio
JKobrynski Jun 24, 2024
e6fbf2b
apply suggested changes
JKobrynski Jun 25, 2024
f453e74
add unit tests for getSubscriptionStatus method
JKobrynski Jun 26, 2024
77ac09c
refactor billing banner translations
JKobrynski Jun 26, 2024
f83bd34
Merge branch 'main' into feature/billing-banner-logic-api-integration
JKobrynski Jun 26, 2024
003d0ec
bring back SUBSCRIPTION_RETRY_BILLING_STATUS logic
JKobrynski Jun 26, 2024
054ebbc
Merge branch 'main' into feature/billing-banner-logic-api-integration
JKobrynski Jun 27, 2024
0900cb2
apply suggested changes
JKobrynski Jun 27, 2024
6688534
Merge branch 'main' into feature/billing-banner-logic-api-integration
JKobrynski Jun 27, 2024
74bd4de
fix code linting
JKobrynski Jun 27, 2024
d14c688
add description to hasAmountOwed util
JKobrynski Jun 27, 2024
7f218f0
apply suggested changes
JKobrynski Jun 28, 2024
08d5f8d
replace jest.clearAllMocks with jest.restoreAllMocks in CardsSectionU…
JKobrynski Jul 1, 2024
a2633b7
Merge branch 'main' into feature/billing-banner-logic-api-integration
JKobrynski Jul 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions src/ONYXKEYS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,15 @@ const ONYXKEYS = {
/** Store the state of the subscription */
NVP_PRIVATE_SUBSCRIPTION: 'nvp_private_subscription',

/** Store the stripe id status */
NVP_PRIVATE_STRIPE_CUSTOMER_ID: 'nvp_private_stripeCustomerID',

/** Store the billing dispute status */
NVP_PRIVATE_BILLING_DISPUTE_PENDING: 'nvp_private_billingDisputePending',

/** Store the billing status */
NVP_PRIVATE_BILLING_STATUS: 'nvp_private_billingStatus',

/** Store preferred skintone for emoji */
PREFERRED_EMOJI_SKIN_TONE: 'nvp_expensify_preferredEmojiSkinTone',

Expand All @@ -187,7 +196,7 @@ const ONYXKEYS = {
NVP_BILLING_FUND_ID: 'nvp_expensify_billingFundID',

/** The amount owed by the workspace’s owner. */
NVP_PRIVATE_AMOUNT_OWNED: 'nvp_private_amountOwed',
NVP_PRIVATE_AMOUNT_OWED: 'nvp_private_amountOwed',

/** The end date (epoch timestamp) of the workspace owner’s grace period after the free trial ends. */
NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END: 'nvp_private_billingGracePeriodEnd',
Expand Down Expand Up @@ -350,6 +359,12 @@ const ONYXKEYS = {
/** Holds the checks used while transferring the ownership of the workspace */
POLICY_OWNERSHIP_CHANGE_CHECKS: 'policyOwnershipChangeChecks',

/** Indicates whether ClearOutstandingBalance failed */
SUBSCRIPTION_RETRY_BILLING_STATUS_FAILED: 'subscriptionRetryBillingStatusFailed',

/** Indicates whether ClearOutstandingBalance was successful */
SUBSCRIPTION_RETRY_BILLING_STATUS_SUCCESSFUL: 'subscriptionRetryBillingStatusSuccessful',
JKobrynski marked this conversation as resolved.
Show resolved Hide resolved

/** Stores info during review duplicates flow */
REVIEW_DUPLICATES: 'reviewDuplicates',

Expand Down Expand Up @@ -702,6 +717,9 @@ type OnyxValuesMapping = {
[ONYXKEYS.NVP_DISMISSED_REFERRAL_BANNERS]: OnyxTypes.DismissedReferralBanners;
[ONYXKEYS.NVP_HAS_SEEN_TRACK_TRAINING]: boolean;
[ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION]: OnyxTypes.PrivateSubscription;
[ONYXKEYS.NVP_PRIVATE_STRIPE_CUSTOMER_ID]: OnyxTypes.StripeCustomerID;
[ONYXKEYS.NVP_PRIVATE_BILLING_DISPUTE_PENDING]: number;
[ONYXKEYS.NVP_PRIVATE_BILLING_STATUS]: OnyxTypes.BillingStatus;
[ONYXKEYS.USER_WALLET]: OnyxTypes.UserWallet;
[ONYXKEYS.WALLET_ONFIDO]: OnyxTypes.WalletOnfido;
[ONYXKEYS.WALLET_ADDITIONAL_DETAILS]: OnyxTypes.WalletAdditionalDetails;
Expand Down Expand Up @@ -750,13 +768,15 @@ type OnyxValuesMapping = {
[ONYXKEYS.CACHED_PDF_PATHS]: Record<string, string>;
[ONYXKEYS.POLICY_OWNERSHIP_CHANGE_CHECKS]: Record<string, OnyxTypes.PolicyOwnershipChangeChecks>;
[ONYXKEYS.NVP_QUICK_ACTION_GLOBAL_CREATE]: OnyxTypes.QuickAction;
[ONYXKEYS.SUBSCRIPTION_RETRY_BILLING_STATUS_FAILED]: boolean;
[ONYXKEYS.SUBSCRIPTION_RETRY_BILLING_STATUS_SUCCESSFUL]: boolean;
[ONYXKEYS.NVP_TRAVEL_SETTINGS]: OnyxTypes.TravelSettings;
[ONYXKEYS.REVIEW_DUPLICATES]: OnyxTypes.ReviewDuplicates;
[ONYXKEYS.ISSUE_NEW_EXPENSIFY_CARD]: OnyxTypes.IssueNewCard;
[ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL]: string;
[ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL]: string;
[ONYXKEYS.NVP_BILLING_FUND_ID]: number;
[ONYXKEYS.NVP_PRIVATE_AMOUNT_OWNED]: number;
[ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED]: number;
[ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END]: number;
};

Expand Down
4 changes: 3 additions & 1 deletion src/components/Indicator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {withOnyx} from 'react-native-onyx';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as PolicyUtils from '@libs/PolicyUtils';
import * as SubscriptionUtils from '@libs/SubscriptionUtils';
import * as UserUtils from '@libs/UserUtils';
import * as PaymentMethods from '@userActions/PaymentMethods';
import ONYXKEYS from '@src/ONYXKEYS';
Expand Down Expand Up @@ -54,13 +55,14 @@ function Indicator({reimbursementAccount, policies, bankAccountList, fundList, u
() => Object.values(cleanPolicies).some(PolicyUtils.hasPolicyError),
() => Object.values(cleanPolicies).some(PolicyUtils.hasCustomUnitsError),
() => Object.values(cleanPolicies).some(PolicyUtils.hasEmployeeListError),
() => SubscriptionUtils.hasSubscriptionRedDotError(),
() => Object.keys(reimbursementAccount?.errors ?? {}).length > 0,
() => !!loginList && UserUtils.hasLoginListError(loginList),

// Wallet term errors that are not caused by an IOU (we show the red brick indicator for those in the LHN instead)
() => Object.keys(walletTerms?.errors ?? {}).length > 0 && !walletTerms?.chatReportID,
];
const infoCheckingMethods: CheckingMethod[] = [() => !!loginList && UserUtils.hasLoginListInfo(loginList)];
const infoCheckingMethods: CheckingMethod[] = [() => !!loginList && UserUtils.hasLoginListInfo(loginList), () => SubscriptionUtils.hasSubscriptionGreenDotInfo()];
const shouldShowErrorIndicator = errorCheckingMethods.some((errorCheckingMethod) => errorCheckingMethod());
const shouldShowInfoIndicator = !shouldShowErrorIndicator && infoCheckingMethods.some((infoCheckingMethod) => infoCheckingMethod());

Expand Down
49 changes: 49 additions & 0 deletions src/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3335,6 +3335,55 @@ export default {
subscription: {
mobileReducedFunctionalityMessage: 'You can’t make changes to your subscription in the mobile app.',
billingBanner: {
policyOwnerAmountOwed: {
title: 'Your payment info is outdated',
subtitle: ({date}) => `Update your payment card by ${date} to continue using all of your favorite features.`,
},
policyOwnerAmountOwedOverdue: {
title: 'Your payment info is outdated',
subtitle: 'Please update your payment information.',
},
policyOwnerUnderInvoicing: {
title: 'Your payment info is outdated',
subtitle: ({date}) => `Your payment is past due. Please pay your invoice by ${date} to avoid service interruption.`,
},
policyOwnerUnderInvoicingOverdue: {
title: 'Your payment info is outdated',
subtitle: 'Your payment is past due. Please pay your invoice.',
},
billingDisputePending: {
title: 'Your card couldn’t be charged',
subtitle: ({amountOwed, cardEnding}) =>
`You disputed the ${amountOwed} charge on the card ending in ${cardEnding}. Your account will be locked until the dispute is resolved with your bank.`,
},
cardAuthenticationRequired: {
title: 'Your card couldn’t be charged',
subtitle: ({cardEnding}) =>
`Your payment card hasn’t been fully authenticated. Please complete the authentication process to activate your payment card ending in ${cardEnding}.`,
},
insufficientFunds: {
title: 'Your card couldn’t be charged',
subtitle: ({amountOwed}) =>
`Your payment card was declined due to insufficient funds. Please retry or add a new payment card to clear your ${amountOwed} outstanding balance.`,
},
cardExpired: {
title: 'Your card couldn’t be charged',
subtitle: ({amountOwed}) => `Your payment card expired. Please add a new payment card to clear your ${amountOwed} outstanding balance.`,
},
cardExpireSoon: {
title: 'Your card is expiring soon',
subtitle: 'Your payment card will expire at the end of this month. Click the three-dot menu below to update it and continue using all your favorite features.',
blimpich marked this conversation as resolved.
Show resolved Hide resolved
},
retryBillingSuccess: {
title: 'Success!',
subtitle: 'Your card has been billed successfully.',
},
retryBillingError: {
title: 'Your card couldn’t be charged',
subtitle: 'Before retrying, please call your bank directly to authorize Expensify charges and remove any holds. Otherwise, try adding a different payment card.',
},
cardOnDispute: ({amountOwed, cardEnding}) =>
`You disputed the ${amountOwed} charge on the card ending in ${cardEnding}. Your account will be locked until the dispute is resolved with your bank.`,
preTrial: {
title: 'Start a free trial',
subtitle: 'To get started, ',
Expand Down
51 changes: 51 additions & 0 deletions src/languages/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3835,6 +3835,57 @@ export default {
subscription: {
mobileReducedFunctionalityMessage: 'No puedes hacer cambios en tu suscripción en la aplicación móvil.',
billingBanner: {
policyOwnerAmountOwed: {
title: 'Tu información de pago está desactualizada',
subtitle: ({date}) => `Actualiza tu tarjeta de pago antes del ${date} para continuar utilizando todas tus herramientas favoritas`,
},
policyOwnerAmountOwedOverdue: {
title: 'Tu información de pago está desactualizada',
subtitle: 'Por favor, actualiza tu información de pago.',
},
policyOwnerUnderInvoicing: {
title: 'Tu información de pago está desactualizada',
subtitle: ({date}) => `Tu pago está vencido. Por favor, paga tu factura antes del ${date} para evitar la interrupción del servicio.`,
},
policyOwnerUnderInvoicingOverdue: {
title: 'Tu información de pago está desactualizada',
subtitle: 'Tu pago está vencido. Por favor, paga tu factura.',
},
billingDisputePending: {
title: 'No se ha podido realizar el cobro a tu tarjeta',
subtitle: ({amountOwed, cardEnding}) =>
`Has impugnado el cargo ${amountOwed} en la tarjeta terminada en ${cardEnding}. Tu cuenta estará bloqueada hasta que se resuelva la disputa con tu banco.`,
},
cardAuthenticationRequired: {
title: 'No se ha podido realizar el cobro a tu tarjeta',
subtitle: ({cardEnding}) =>
`Tu tarjeta de pago no ha sido autenticada completamente. Por favor, completa el proceso de autenticación para activar tu tarjeta de pago que termina en ${cardEnding}.`,
},
insufficientFunds: {
title: 'No se ha podido realizar el cobro a tu tarjeta',
subtitle: ({amountOwed}) =>
`Tu tarjeta de pago fue rechazada por falta de fondos. Vuelve a intentarlo o añade una nueva tarjeta de pago para liquidar tu saldo pendiente de ${amountOwed}.`,
},
cardExpired: {
title: 'No se ha podido realizar el cobro a tu tarjeta',
subtitle: ({amountOwed}) => `Tu tarjeta de pago ha expirado. Por favor, añade una nueva tarjeta de pago para liquidar tu saldo pendiente de ${amountOwed}.`,
},
cardExpireSoon: {
title: 'Tu tarjeta caducará pronto',
subtitle:
'Tu tarjeta de pago caducará a finales de este mes. Haz clic en el menú de tres puntos que aparece a continuación para actualizarla y continuar utilizando todas tus herramientas favoritas.',
},
retryBillingSuccess: {
title: 'Éxito!',
subtitle: 'Tu tarjeta fue facturada correctamente.',
},
retryBillingError: {
title: 'No se ha podido realizar el cobro a tu tarjeta',
subtitle:
'Antes de volver a intentarlo, llama directamente a tu banco para que autorice los cargos de Expensify y elimine las retenciones. De lo contrario, añade una tarjeta de pago diferente.',
},
cardOnDispute: ({amountOwed, cardEnding}) =>
`Has impugnado el cargo ${amountOwed} en la tarjeta terminada en ${cardEnding}. Tu cuenta estará bloqueada hasta que se resuelva la disputa con tu banco.`,
preTrial: {
title: 'Iniciar una prueba gratuita',
subtitle: 'Para empezar, ',
Expand Down
Loading
Loading