diff --git a/src/libs/SubscriptionUtils.ts b/src/libs/SubscriptionUtils.ts index d7d010f3d15a..9aa2ce4b4a4d 100644 --- a/src/libs/SubscriptionUtils.ts +++ b/src/libs/SubscriptionUtils.ts @@ -107,12 +107,6 @@ Onyx.connect({ callback: (value) => (lastDayFreeTrial = value), }); -let userBillingFundID: OnyxEntry; -Onyx.connect({ - key: ONYXKEYS.NVP_BILLING_FUND_ID, - callback: (value) => (userBillingFundID = value), -}); - let userBillingGraceEndPeriodCollection: OnyxCollection; Onyx.connect({ key: ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END, @@ -229,7 +223,12 @@ function hasCardExpiringSoon(): boolean { return isExpiringThisMonth || isExpiringNextMonth; } -function shouldShowDiscountBanner(hasTeam2025Pricing: boolean, subscriptionPlan: ValueOf | null, firstDayFreeTrial: string | undefined): boolean { +function shouldShowDiscountBanner( + hasTeam2025Pricing: boolean, + subscriptionPlan: ValueOf | null, + firstDayFreeTrial: string | undefined, + userBillingFundID: number | undefined, +): boolean { if (!getOwnedPaidPolicies(allPolicies, currentUserAccountID)?.length) { return false; } @@ -238,7 +237,7 @@ function shouldShowDiscountBanner(hasTeam2025Pricing: boolean, subscriptionPlan: return false; } - if (doesUserHavePaymentCardAdded()) { + if (doesUserHavePaymentCardAdded(userBillingFundID)) { return false; } @@ -490,7 +489,7 @@ function hasUserFreeTrialEnded(): boolean { /** * Whether the user has a payment card added to its account. */ -function doesUserHavePaymentCardAdded(): boolean { +function doesUserHavePaymentCardAdded(userBillingFundID: number | undefined): boolean { return userBillingFundID !== undefined; } diff --git a/src/pages/home/HeaderView.tsx b/src/pages/home/HeaderView.tsx index 7a52fc9273af..526530fcb6d9 100644 --- a/src/pages/home/HeaderView.tsx +++ b/src/pages/home/HeaderView.tsx @@ -109,6 +109,7 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, const [grandParentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(parentReport?.parentReportID)}`, {canBeMissing: true}); const policy = usePolicy(report?.policyID); const [personalDetails] = useOnyx(ONYXKEYS.PERSONAL_DETAILS_LIST, {canBeMissing: true}); + const [userBillingFundID] = useOnyx(ONYXKEYS.NVP_BILLING_FUND_ID, {canBeMissing: true}); const shouldShowLoadingBar = useLoadingBarVisibility(); const [firstDayFreeTrial] = useOnyx(ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL, {canBeMissing: true}); const [lastDayFreeTrial] = useOnyx(ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL, {canBeMissing: true}); @@ -205,10 +206,10 @@ function HeaderView({report, parentReportAction, onNavigationMenuButtonClicked, // If the onboarding report is directly loaded, shouldShowDiscountBanner can return wrong value as it is not // linked to the react lifecycle directly. Wait for trial dates to load, before calculating. const shouldShowDiscount = useMemo( - () => shouldShowDiscountBanner(hasTeam2025Pricing, subscriptionPlan, firstDayFreeTrial) && !isReportArchived, + () => shouldShowDiscountBanner(hasTeam2025Pricing, subscriptionPlan, firstDayFreeTrial, userBillingFundID) && !isReportArchived, // eslint-disable-next-line react-compiler/react-compiler // eslint-disable-next-line react-hooks/exhaustive-deps - [firstDayFreeTrial, lastDayFreeTrial, hasTeam2025Pricing, reportNameValuePairs, subscriptionPlan], + [firstDayFreeTrial, lastDayFreeTrial, hasTeam2025Pricing, reportNameValuePairs, subscriptionPlan, userBillingFundID], ); const shouldShowSubscript = shouldReportShowSubscript(report, isReportArchived); diff --git a/src/pages/settings/Subscription/CardSection/BillingBanner/TrialEndedBillingBanner.tsx b/src/pages/settings/Subscription/CardSection/BillingBanner/TrialEndedBillingBanner.tsx index 67dd37f7a844..afaff9739008 100644 --- a/src/pages/settings/Subscription/CardSection/BillingBanner/TrialEndedBillingBanner.tsx +++ b/src/pages/settings/Subscription/CardSection/BillingBanner/TrialEndedBillingBanner.tsx @@ -1,13 +1,16 @@ import React from 'react'; import * as Illustrations from '@components/Icon/Illustrations'; import useLocalize from '@hooks/useLocalize'; -import * as SubscriptionUtils from '@libs/SubscriptionUtils'; +import useOnyx from '@hooks/useOnyx'; +import {doesUserHavePaymentCardAdded} from '@libs/SubscriptionUtils'; +import ONYXKEYS from '@src/ONYXKEYS'; import BillingBanner from './BillingBanner'; function TrialEndedBillingBanner() { const {translate} = useLocalize(); + const [userBillingFundID] = useOnyx(ONYXKEYS.NVP_BILLING_FUND_ID, {canBeMissing: true}); - if (SubscriptionUtils.doesUserHavePaymentCardAdded()) { + if (doesUserHavePaymentCardAdded(userBillingFundID)) { return null; } diff --git a/src/pages/settings/Subscription/CardSection/BillingBanner/TrialStartedBillingBanner.tsx b/src/pages/settings/Subscription/CardSection/BillingBanner/TrialStartedBillingBanner.tsx index 608a4a861c6a..fe807219c2af 100644 --- a/src/pages/settings/Subscription/CardSection/BillingBanner/TrialStartedBillingBanner.tsx +++ b/src/pages/settings/Subscription/CardSection/BillingBanner/TrialStartedBillingBanner.tsx @@ -1,17 +1,20 @@ import React from 'react'; import * as Illustrations from '@components/Icon/Illustrations'; import useLocalize from '@hooks/useLocalize'; -import * as SubscriptionUtils from '@libs/SubscriptionUtils'; +import useOnyx from '@hooks/useOnyx'; +import {calculateRemainingFreeTrialDays, doesUserHavePaymentCardAdded} from '@libs/SubscriptionUtils'; +import ONYXKEYS from '@src/ONYXKEYS'; import BillingBanner from './BillingBanner'; function TrialStartedBillingBanner() { const {translate} = useLocalize(); + const [userBillingFundID] = useOnyx(ONYXKEYS.NVP_BILLING_FUND_ID, {canBeMissing: true}); - const subtitle = !SubscriptionUtils.doesUserHavePaymentCardAdded() ? translate('subscription.billingBanner.trialStarted.subtitle') : ''; + const subtitle = !doesUserHavePaymentCardAdded(userBillingFundID) ? translate('subscription.billingBanner.trialStarted.subtitle') : ''; return ( diff --git a/src/pages/settings/Subscription/CardSection/CardSection.tsx b/src/pages/settings/Subscription/CardSection/CardSection.tsx index b71357768af1..43ece838d148 100644 --- a/src/pages/settings/Subscription/CardSection/CardSection.tsx +++ b/src/pages/settings/Subscription/CardSection/CardSection.tsx @@ -67,6 +67,7 @@ function CardSection() { ); const [firstDayFreeTrial] = useOnyx(ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL, {canBeMissing: true}); const [billingDisputePending] = useOnyx(ONYXKEYS.NVP_PRIVATE_BILLING_DISPUTE_PENDING, {canBeMissing: true}); + const [userBillingFundID] = useOnyx(ONYXKEYS.NVP_BILLING_FUND_ID, {canBeMissing: true}); const requestRefund = useCallback(() => { requestRefundByUser(); setIsRequestRefundModalVisible(false); @@ -139,7 +140,7 @@ function CardSection() { }; let BillingBanner: React.ReactNode | undefined; - if (shouldShowDiscountBanner(hasTeam2025Pricing, subscriptionPlan, firstDayFreeTrial)) { + if (shouldShowDiscountBanner(hasTeam2025Pricing, subscriptionPlan, firstDayFreeTrial, userBillingFundID)) { BillingBanner = ; } else if (shouldShowPreTrialBillingBanner(introSelected, firstDayFreeTrial)) { BillingBanner = ; diff --git a/tests/unit/SubscriptionUtilsTest.ts b/tests/unit/SubscriptionUtilsTest.ts index b2ce2202d993..d949298611fd 100644 --- a/tests/unit/SubscriptionUtilsTest.ts +++ b/tests/unit/SubscriptionUtilsTest.ts @@ -183,12 +183,12 @@ describe('SubscriptionUtils', () => { }); it('should return false if the Onyx key is not set', () => { - expect(doesUserHavePaymentCardAdded()).toBeFalsy(); + expect(doesUserHavePaymentCardAdded(undefined)).toBeFalsy(); }); it('should return true if the Onyx key is set', async () => { await Onyx.set(ONYXKEYS.NVP_BILLING_FUND_ID, 8010); - expect(doesUserHavePaymentCardAdded()).toBeTruthy(); + expect(doesUserHavePaymentCardAdded(8010)).toBeTruthy(); }); }); @@ -529,7 +529,7 @@ describe('SubscriptionUtils', () => { [ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL]: null, [ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL]: null, }); - expect(shouldShowDiscountBanner(true, 'corporate', undefined)).toBeFalsy(); + expect(shouldShowDiscountBanner(true, 'corporate', undefined, undefined)).toBeFalsy(); }); it(`should return false if user has already added a payment method`, async () => { @@ -542,7 +542,7 @@ describe('SubscriptionUtils', () => { }, [ONYXKEYS.NVP_BILLING_FUND_ID]: 8010, }); - expect(shouldShowDiscountBanner(true, 'corporate', undefined)).toBeFalsy(); + expect(shouldShowDiscountBanner(true, 'corporate', undefined, 8010)).toBeFalsy(); }); it('should return false if the user is on Team plan', async () => { @@ -557,7 +557,7 @@ describe('SubscriptionUtils', () => { [ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL]: firstDayFreeTrial, [ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL]: formatDate(addDays(new Date(), 10), CONST.DATE.FNS_DATE_TIME_FORMAT_STRING), }); - expect(shouldShowDiscountBanner(true, 'team', firstDayFreeTrial)).toBeFalsy(); + expect(shouldShowDiscountBanner(true, 'team', firstDayFreeTrial, undefined)).toBeFalsy(); }); it('should return true if the date is before the free trial end date or within the 8 days from the trial start date', async () => { @@ -572,7 +572,7 @@ describe('SubscriptionUtils', () => { [ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL]: firstDayFreeTrial, [ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL]: formatDate(addDays(new Date(), 10), CONST.DATE.FNS_DATE_TIME_FORMAT_STRING), }); - expect(shouldShowDiscountBanner(true, 'corporate', firstDayFreeTrial)).toBeTruthy(); + expect(shouldShowDiscountBanner(true, 'corporate', firstDayFreeTrial, undefined)).toBeTruthy(); }); it("should return false if user's trial is during the discount period but has no workspaces", async () => { @@ -582,7 +582,7 @@ describe('SubscriptionUtils', () => { [ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL]: firstDayFreeTrial, [ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL]: formatDate(addDays(new Date(), 10), CONST.DATE.FNS_DATE_TIME_FORMAT_STRING), }); - expect(shouldShowDiscountBanner(true, 'corporate', firstDayFreeTrial)).toBeFalsy(); + expect(shouldShowDiscountBanner(true, 'corporate', firstDayFreeTrial, undefined)).toBeFalsy(); }); });