Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
26 changes: 11 additions & 15 deletions src/libs/SubscriptionUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
};

let currentUserAccountID = -1;
Onyx.connect({

Check warning on line 52 in src/libs/SubscriptionUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.SESSION,
callback: (value) => {
currentUserAccountID = value?.accountID ?? CONST.DEFAULT_NUMBER_ID;
Expand All @@ -57,25 +57,25 @@
});

let amountOwed: OnyxEntry<number>;
Onyx.connect({

Check warning on line 60 in src/libs/SubscriptionUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED,
callback: (value) => (amountOwed = value),
});

let billingStatus: OnyxEntry<BillingStatus>;
Onyx.connect({

Check warning on line 66 in src/libs/SubscriptionUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.NVP_PRIVATE_BILLING_STATUS,
callback: (value) => (billingStatus = value),
});

let ownerBillingGraceEndPeriod: OnyxEntry<number>;
Onyx.connect({

Check warning on line 72 in src/libs/SubscriptionUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END,
callback: (value) => (ownerBillingGraceEndPeriod = value),
});

let fundList: OnyxEntry<FundList>;
Onyx.connect({

Check warning on line 78 in src/libs/SubscriptionUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.FUND_LIST,
callback: (value) => {
if (!value) {
Expand All @@ -86,21 +86,15 @@
},
});

let lastDayFreeTrial: OnyxEntry<string>;
Onyx.connect({
key: ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL,
callback: (value) => (lastDayFreeTrial = value),
});

let userBillingGraceEndPeriodCollection: OnyxCollection<BillingGraceEndPeriod>;
Onyx.connect({

Check warning on line 90 in src/libs/SubscriptionUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END,
callback: (value) => (userBillingGraceEndPeriodCollection = value),
waitForCollectionCallback: true,
});

let allPolicies: OnyxCollection<Policy>;
Onyx.connect({

Check warning on line 97 in src/libs/SubscriptionUtils.ts

View workflow job for this annotation

GitHub Actions / Changed files ESLint check

Onyx.connect() is deprecated. Use useOnyx() hook instead and pass the data as parameters to a pure function
key: ONYXKEYS.COLLECTION.POLICY,
callback: (value) => (allPolicies = value),
waitForCollectionCallback: true,
Expand Down Expand Up @@ -169,12 +163,12 @@
return billingStatus?.declineReason === 'insufficient_funds' && getAmountOwed() !== 0;
}

function shouldShowPreTrialBillingBanner(introSelected: OnyxEntry<IntroSelected>, firstDayFreeTrial: string | undefined): boolean {
function shouldShowPreTrialBillingBanner(introSelected: OnyxEntry<IntroSelected>, firstDayFreeTrial: string | undefined, lastDayFreeTrial: string | undefined): boolean {
// We don't want to show the Pre Trial banner if the user was a Test Drive Receiver that created their workspace
// with the promo code.
const wasUserTestDriveReceiver = introSelected?.previousChoices?.some((choice) => choice === CONST.ONBOARDING_CHOICES.TEST_DRIVE_RECEIVER);

return !isUserOnFreeTrial(firstDayFreeTrial) && !hasUserFreeTrialEnded() && !wasUserTestDriveReceiver;
return !isUserOnFreeTrial(firstDayFreeTrial, lastDayFreeTrial) && !hasUserFreeTrialEnded(lastDayFreeTrial) && !wasUserTestDriveReceiver;
}
/**
* @returns The card to be used for subscription billing.
Expand Down Expand Up @@ -212,13 +206,14 @@
hasTeam2025Pricing: boolean,
subscriptionPlan: ValueOf<typeof CONST.POLICY.TYPE> | null,
firstDayFreeTrial: string | undefined,
lastDayFreeTrial: string | undefined,
userBillingFundID: number | undefined,
): boolean {
if (!getOwnedPaidPolicies(allPolicies, currentUserAccountID)?.length) {
return false;
}

if (!isUserOnFreeTrial(firstDayFreeTrial)) {
if (!isUserOnFreeTrial(firstDayFreeTrial, lastDayFreeTrial)) {
return false;
}

Expand Down Expand Up @@ -416,7 +411,7 @@
/**
* Calculates the remaining number of days of the workspace owner's free trial before it ends.
*/
function calculateRemainingFreeTrialDays(): number {
function calculateRemainingFreeTrialDays(lastDayFreeTrial: string | undefined): number {
if (!lastDayFreeTrial) {
return 0;
}
Expand All @@ -438,17 +433,18 @@
policies: OnyxCollection<Policy> | null,
introSelected: OnyxEntry<IntroSelected>,
firstDayFreeTrial: string | undefined,
lastDayFreeTrial: string | undefined,
): string | undefined {
const ownedPaidPolicies = getOwnedPaidPolicies(policies, currentUserAccountID);
if (isEmptyObject(ownedPaidPolicies)) {
return undefined;
}

if (shouldShowPreTrialBillingBanner(introSelected, firstDayFreeTrial)) {
if (shouldShowPreTrialBillingBanner(introSelected, firstDayFreeTrial, lastDayFreeTrial)) {
return translate('subscription.billingBanner.preTrial.title');
}
if (isUserOnFreeTrial(firstDayFreeTrial)) {
return translate('subscription.billingBanner.trialStarted.title', {numOfDays: calculateRemainingFreeTrialDays()});
if (isUserOnFreeTrial(firstDayFreeTrial, lastDayFreeTrial)) {
return translate('subscription.billingBanner.trialStarted.title', {numOfDays: calculateRemainingFreeTrialDays(lastDayFreeTrial)});
}

return undefined;
Expand All @@ -457,7 +453,7 @@
/**
* Whether the workspace's owner is on its free trial period.
*/
function isUserOnFreeTrial(firstDayFreeTrial: string | undefined): boolean {
function isUserOnFreeTrial(firstDayFreeTrial: string | undefined, lastDayFreeTrial: string | undefined): boolean {
if (!firstDayFreeTrial || !lastDayFreeTrial) {
return false;
}
Expand All @@ -474,7 +470,7 @@
/**
* Whether the workspace owner's free trial period has ended.
*/
function hasUserFreeTrialEnded(): boolean {
function hasUserFreeTrialEnded(lastDayFreeTrial: string | undefined): boolean {
if (!lastDayFreeTrial) {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/home/HeaderView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ 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, userBillingFundID) && !isReportArchived,
() => shouldShowDiscountBanner(hasTeam2025Pricing, subscriptionPlan, firstDayFreeTrial, lastDayFreeTrial, userBillingFundID) && !isReportArchived,
// eslint-disable-next-line react-compiler/react-compiler
// eslint-disable-next-line react-hooks/exhaustive-deps
[firstDayFreeTrial, lastDayFreeTrial, hasTeam2025Pricing, reportNameValuePairs, subscriptionPlan, userBillingFundID],
Expand Down
6 changes: 4 additions & 2 deletions src/pages/settings/InitialSettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,14 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr
const isScreenFocused = useIsSidebarRouteActive(NAVIGATORS.SETTINGS_SPLIT_NAVIGATOR, shouldUseNarrowLayout);
const hasActivatedWallet = ([CONST.WALLET.TIER_NAME.GOLD, CONST.WALLET.TIER_NAME.PLATINUM] as string[]).includes(userWallet?.tierName ?? '');
const [firstDayFreeTrial] = useOnyx(ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL, {canBeMissing: true});
const [lastDayFreeTrial] = useOnyx(ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL, {canBeMissing: true});
const privateSubscription = usePrivateSubscription();
const subscriptionPlan = useSubscriptionPlan();
const previousUserPersonalDetails = usePrevious(currentUserPersonalDetails);

const shouldLogout = useRef(false);

const freeTrialText = getFreeTrialText(translate, policies, introSelected, firstDayFreeTrial);
const freeTrialText = getFreeTrialText(translate, policies, introSelected, firstDayFreeTrial, lastDayFreeTrial);

const shouldDisplayLHB = !shouldUseNarrowLayout;

Expand Down Expand Up @@ -227,9 +228,10 @@ function InitialSettingsPage({currentUserPersonalDetails}: InitialSettingsPagePr
styles.badgeSuccess,
privateSubscription?.errors,
stripeCustomerId,
freeTrialText,
retryBillingSuccessful,
billingDisputePending,
retryBillingFailed,
freeTrialText,
]);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import BillingBanner from './BillingBanner';
function TrialStartedBillingBanner() {
const {translate} = useLocalize();
const [userBillingFundID] = useOnyx(ONYXKEYS.NVP_BILLING_FUND_ID, {canBeMissing: true});

const [lastDayFreeTrial] = useOnyx(ONYXKEYS.NVP_LAST_DAY_FREE_TRIAL, {canBeMissing: true});
const subtitle = !doesUserHavePaymentCardAdded(userBillingFundID) ? translate('subscription.billingBanner.trialStarted.subtitle') : '';

return (
<BillingBanner
title={translate('subscription.billingBanner.trialStarted.title', {numOfDays: calculateRemainingFreeTrialDays()})}
title={translate('subscription.billingBanner.trialStarted.title', {numOfDays: calculateRemainingFreeTrialDays(lastDayFreeTrial)})}
subtitle={subtitle}
icon={Illustrations.TreasureChest}
/>
Expand Down
9 changes: 5 additions & 4 deletions src/pages/settings/Subscription/CardSection/CardSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ function CardSection() {
[purchaseList],
);
const [firstDayFreeTrial] = useOnyx(ONYXKEYS.NVP_FIRST_DAY_FREE_TRIAL, {canBeMissing: true});
const [lastDayFreeTrial] = useOnyx(ONYXKEYS.NVP_LAST_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(() => {
Expand Down Expand Up @@ -142,13 +143,13 @@ function CardSection() {
};

let BillingBanner: React.ReactNode | undefined;
if (shouldShowDiscountBanner(hasTeam2025Pricing, subscriptionPlan, firstDayFreeTrial, userBillingFundID)) {
if (shouldShowDiscountBanner(hasTeam2025Pricing, subscriptionPlan, firstDayFreeTrial, lastDayFreeTrial, userBillingFundID)) {
BillingBanner = <EarlyDiscountBanner isSubscriptionPage />;
} else if (shouldShowPreTrialBillingBanner(introSelected, firstDayFreeTrial)) {
} else if (shouldShowPreTrialBillingBanner(introSelected, firstDayFreeTrial, lastDayFreeTrial)) {
BillingBanner = <PreTrialBillingBanner />;
} else if (isUserOnFreeTrial(firstDayFreeTrial)) {
} else if (isUserOnFreeTrial(firstDayFreeTrial, lastDayFreeTrial)) {
BillingBanner = <TrialStartedBillingBanner />;
} else if (hasUserFreeTrialEnded()) {
} else if (hasUserFreeTrialEnded(lastDayFreeTrial)) {
BillingBanner = <TrialEndedBillingBanner />;
}
if (billingStatus) {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/settings/Subscription/FreeTrial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function FreeTrial({badgeStyles, pressable = false, addSpacing = false, success
if (!privateSubscription && !isOffline) {
return;
}
setFreeTrialText(getFreeTrialText(translate, policies, introSelected, firstDayFreeTrial));
setFreeTrialText(getFreeTrialText(translate, policies, introSelected, firstDayFreeTrial, lastDayFreeTrial));
}, [isOffline, privateSubscription, translate, policies, firstDayFreeTrial, lastDayFreeTrial, introSelected]);

if (!freeTrialText) {
Expand Down
Loading
Loading