mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 13:35:42 +09:00
feat(premium): native Nordic prices and subscribing during grace (#3274)
This commit is contained in:
1 parent
0ef1cd14c3
commit
7a4aa42d4b
84 files changed
+7720
-4589
No files matched your search
@@ -62,6 +62,7 @@ export const PlutoniumContent = observer(({defaultGiftMode = false}: PlutoniumCo
|
||||
const [isGiftMode, setIsGiftMode] = useState(defaultGiftMode);
|
||||
const giftSectionRef = useRef<HTMLDivElement | null>(null);
|
||||
const perksSectionRef = useRef<HTMLDivElement | null>(null);
|
||||
const pricingSectionRef = useRef<HTMLDivElement | null>(null);
|
||||
const countryCode = GeoIP.countryCode;
|
||||
const guilds = Guilds.getGuilds();
|
||||
const visionaryGuild = useMemo(() => {
|
||||
@@ -94,12 +95,9 @@ export const PlutoniumContent = observer(({defaultGiftMode = false}: PlutoniumCo
|
||||
handleCancelPendingSubscriptionChange,
|
||||
} = useSubscriptionActions(countryCode);
|
||||
const {loadingRejoinCommunity, handleCommunityButtonClick} = useCommunityActions(visionaryGuild);
|
||||
const {loadingCheckout, handleSelectPlan} = useCheckoutActions(
|
||||
priceIds,
|
||||
countryCode,
|
||||
subscriptionStatus.isGiftSubscription,
|
||||
mobileLayoutState.enabled,
|
||||
);
|
||||
const {loadingCheckout, handleSelectPlan} = useCheckoutActions(priceIds, countryCode, mobileLayoutState.enabled, {
|
||||
hasGiftTime: subscriptionStatus.isGiftSubscription,
|
||||
});
|
||||
useEffect(() => {
|
||||
if (!currentUser?.id) return;
|
||||
void PremiumCommands.refreshPremiumState(countryCode ?? undefined);
|
||||
@@ -114,6 +112,7 @@ export const PlutoniumContent = observer(({defaultGiftMode = false}: PlutoniumCo
|
||||
const billingUnavailable =
|
||||
!shouldShowPremiumFeatures() ||
|
||||
(!arePremiumPurchasesAvailable() && !(hasBillingRelationship && canServiceStripeSubscriptions()));
|
||||
const canSubscribe = purchasesAvailable && subscriptionStatus.canStartSubscription;
|
||||
const purchaseDisabledTooltip = !isClaimed
|
||||
? i18n._(CLAIM_ACCOUNT_TO_PURCHASE_PREMIUM_DESCRIPTOR, {premiumProductFullName: getPremiumProductFullName()})
|
||||
: i18n._(VERIFY_EMAIL_TO_PURCHASE_PREMIUM_DESCRIPTOR, {premiumProductFullName: getPremiumProductFullName()});
|
||||
@@ -127,6 +126,9 @@ export const PlutoniumContent = observer(({defaultGiftMode = false}: PlutoniumCo
|
||||
const scrollToPerks = useCallback(() => {
|
||||
perksSectionRef.current?.scrollIntoView({behavior: 'auto', block: 'start'});
|
||||
}, []);
|
||||
const scrollToPricing = useCallback(() => {
|
||||
pricingSectionRef.current?.scrollIntoView({behavior: 'auto', block: 'start'});
|
||||
}, []);
|
||||
const navigateToRedeemGift = useCallback(() => {
|
||||
ComponentBus.dispatch('USER_SETTINGS_TAB_SELECT', {tab: 'gift_inventory'});
|
||||
}, []);
|
||||
@@ -227,6 +229,8 @@ export const PlutoniumContent = observer(({defaultGiftMode = false}: PlutoniumCo
|
||||
isVisionary={subscriptionStatus.isVisionary}
|
||||
perksDisabled={subscriptionStatus.perksDisabled}
|
||||
isGiftSubscription={subscriptionStatus.isGiftSubscription}
|
||||
isGiftGrace={subscriptionStatus.isGiftGrace}
|
||||
canSubscribe={canSubscribe}
|
||||
storeSubscription={subscriptionStatus.storeSubscription}
|
||||
premiumUntil={subscriptionStatus.actualPremiumUntil}
|
||||
billingCycle={subscriptionStatus.billingCycle}
|
||||
@@ -256,6 +260,7 @@ export const PlutoniumContent = observer(({defaultGiftMode = false}: PlutoniumCo
|
||||
loadingRejoinCommunity={loadingRejoinCommunity}
|
||||
scrollToPerks={scrollToPerks}
|
||||
navigateToRedeemGift={navigateToRedeemGift}
|
||||
handleStartSubscription={scrollToPricing}
|
||||
handleOpenCustomerPortal={handleOpenCustomerPortal}
|
||||
handleReactivateSubscription={handleReactivateSubscription}
|
||||
handleCancelSubscription={handleCancelSubscriptionConfirmed}
|
||||
@@ -312,21 +317,23 @@ export const PlutoniumContent = observer(({defaultGiftMode = false}: PlutoniumCo
|
||||
</Button>
|
||||
</section>
|
||||
)
|
||||
) : !subscriptionStatus.shouldShowPremiumCard ? (
|
||||
<PricingSection
|
||||
isGiftMode={isGiftMode && giftPurchasesAvailable}
|
||||
giftPurchasesAvailable={giftPurchasesAvailable}
|
||||
setIsGiftMode={setIsGiftMode}
|
||||
monthlyPrice={monthlyPrice}
|
||||
yearlyPrice={yearlyPrice}
|
||||
giftMonthlyPrice={giftMonthlyPrice}
|
||||
giftYearlyPrice={giftYearlyPrice}
|
||||
loadingCheckout={loadingCheckout}
|
||||
handleSelectPlan={handleSelectPlanGuarded}
|
||||
purchaseDisabled={purchaseDisabled}
|
||||
purchaseDisabledTooltip={purchaseDisabledTooltip}
|
||||
data-flx="app.plutonium-content.pricing-section"
|
||||
/>
|
||||
) : canSubscribe ? (
|
||||
<div ref={pricingSectionRef} data-flx="app.plutonium-content.pricing-anchor">
|
||||
<PricingSection
|
||||
isGiftMode={isGiftMode && giftPurchasesAvailable}
|
||||
giftPurchasesAvailable={giftPurchasesAvailable}
|
||||
setIsGiftMode={setIsGiftMode}
|
||||
monthlyPrice={monthlyPrice}
|
||||
yearlyPrice={yearlyPrice}
|
||||
giftMonthlyPrice={giftMonthlyPrice}
|
||||
giftYearlyPrice={giftYearlyPrice}
|
||||
loadingCheckout={loadingCheckout}
|
||||
handleSelectPlan={handleSelectPlanGuarded}
|
||||
purchaseDisabled={purchaseDisabled}
|
||||
purchaseDisabledTooltip={purchaseDisabledTooltip}
|
||||
data-flx="app.plutonium-content.pricing-section"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
giftPurchasesAvailable && (
|
||||
<GiftSection
|
||||
@@ -355,7 +362,7 @@ export const PlutoniumContent = observer(({defaultGiftMode = false}: PlutoniumCo
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
{!subscriptionStatus.isPremium && purchasesAvailable && (
|
||||
{canSubscribe && (
|
||||
<BottomCTASection
|
||||
isGiftMode={isGiftMode && giftPurchasesAvailable}
|
||||
monthlyPrice={monthlyPrice}
|
||||
|
||||
+110
-41
@@ -75,6 +75,8 @@ interface SubscriptionCardProps {
|
||||
isVisionary: boolean;
|
||||
perksDisabled: boolean;
|
||||
isGiftSubscription: boolean;
|
||||
isGiftGrace: boolean;
|
||||
canSubscribe: boolean;
|
||||
storeSubscription: PremiumStoreSubscriptionState | null;
|
||||
premiumUntil: Date | null;
|
||||
billingCycle: string | null;
|
||||
@@ -104,6 +106,7 @@ interface SubscriptionCardProps {
|
||||
loadingRejoinCommunity: boolean;
|
||||
scrollToPerks: () => void;
|
||||
navigateToRedeemGift: () => void;
|
||||
handleStartSubscription: () => void;
|
||||
handleOpenCustomerPortal: () => void;
|
||||
handleReactivateSubscription: () => void;
|
||||
handleCancelSubscription: () => void;
|
||||
@@ -144,6 +147,8 @@ export const SubscriptionCard: React.FC<SubscriptionCardProps> = observer(
|
||||
isVisionary,
|
||||
perksDisabled,
|
||||
isGiftSubscription,
|
||||
isGiftGrace,
|
||||
canSubscribe,
|
||||
storeSubscription,
|
||||
premiumUntil,
|
||||
billingCycle,
|
||||
@@ -173,6 +178,7 @@ export const SubscriptionCard: React.FC<SubscriptionCardProps> = observer(
|
||||
loadingRejoinCommunity,
|
||||
scrollToPerks,
|
||||
navigateToRedeemGift,
|
||||
handleStartSubscription,
|
||||
handleOpenCustomerPortal,
|
||||
handleReactivateSubscription,
|
||||
handleCancelSubscription,
|
||||
@@ -497,6 +503,22 @@ export const SubscriptionCard: React.FC<SubscriptionCardProps> = observer(
|
||||
</Trans>
|
||||
);
|
||||
})()
|
||||
) : isGiftGrace ? (
|
||||
(() => {
|
||||
const graceDate = graceEndDate ? getFormattedLongDate(graceEndDate, locale) : undefined;
|
||||
return (
|
||||
<Trans comment="Plutonium subscription card text shown in the short grace period after gifted premium time ends. {graceDate} is a date already formatted and localized by code; never write a date into the translation.">
|
||||
Your gift time ended but{' '}
|
||||
<PerksButton
|
||||
onClick={scrollToPerks}
|
||||
data-flx="app.plutonium.subscription-card.perks-button.scroll-to-perks--11"
|
||||
/>{' '}
|
||||
stay active until{' '}
|
||||
<strong data-flx="app.plutonium.subscription-card.strong--19">{graceDate}</strong>. Subscribe
|
||||
before then to keep them.
|
||||
</Trans>
|
||||
);
|
||||
})()
|
||||
) : isInGracePeriod ? (
|
||||
(() => {
|
||||
const graceDate = graceEndDate ? getFormattedLongDate(graceEndDate, locale) : undefined;
|
||||
@@ -773,55 +795,102 @@ export const SubscriptionCard: React.FC<SubscriptionCardProps> = observer(
|
||||
>
|
||||
{i18n._(MANAGE_SUBSCRIPTION_DESCRIPTOR)}
|
||||
</Button>
|
||||
) : isGiftSubscription || billingUnavailable ? (
|
||||
wrapIfDisabled(
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={navigateToRedeemGift}
|
||||
small
|
||||
className={styles.actionButton}
|
||||
disabled={purchaseDisabled}
|
||||
data-flx="app.plutonium.subscription-card.action-button.navigate-to-redeem-gift"
|
||||
>
|
||||
<Trans comment="Billing button for entering a premium gift code.">Redeem gift code</Trans>
|
||||
</Button>,
|
||||
'redeem-gift',
|
||||
purchaseDisabled,
|
||||
)
|
||||
) : (
|
||||
) : isGiftSubscription || isGiftGrace || billingUnavailable ? (
|
||||
<>
|
||||
{hasEverPurchased &&
|
||||
{canSubscribe &&
|
||||
!billingUnavailable &&
|
||||
wrapIfDisabled(
|
||||
<Button
|
||||
variant={isFullyExpired || isInGracePeriod || premiumWillCancel ? 'primary' : 'secondary'}
|
||||
onClick={shouldUseReactivateQuickAction ? handleReactivateSubscription : handleOpenCustomerPortal}
|
||||
submitting={shouldUseReactivateQuickAction ? loadingReactivate : loadingPortal}
|
||||
variant="primary"
|
||||
onClick={handleStartSubscription}
|
||||
small
|
||||
className={styles.actionButton}
|
||||
disabled={purchaseDisabled && shouldUseReactivateQuickAction}
|
||||
data-flx="app.plutonium.subscription-card.action-button.reactivate-subscription"
|
||||
disabled={purchaseDisabled}
|
||||
data-flx="app.plutonium.subscription-card.action-button.start-subscription"
|
||||
>
|
||||
{isFullyExpired ? (
|
||||
<Trans comment="Billing button for starting a new subscription after premium expired.">
|
||||
Resubscribe
|
||||
</Trans>
|
||||
) : isInGracePeriod ? (
|
||||
<Trans comment="Billing button for restarting a subscription during the grace period.">
|
||||
Resubscribe
|
||||
</Trans>
|
||||
) : premiumWillCancel ? (
|
||||
<Trans comment="Billing button that cancels a scheduled subscription cancellation.">
|
||||
Reactivate
|
||||
</Trans>
|
||||
) : isVisionary ? (
|
||||
<Trans comment="Billing button that opens the external customer portal.">Customer portal</Trans>
|
||||
) : (
|
||||
i18n._(MANAGE_SUBSCRIPTION_DESCRIPTOR)
|
||||
)}
|
||||
<Trans comment="Billing button that starts a recurring subscription for someone on gifted premium time.">
|
||||
Subscribe
|
||||
</Trans>
|
||||
</Button>,
|
||||
'manage-reactivate',
|
||||
purchaseDisabled && shouldUseReactivateQuickAction,
|
||||
'start-subscription',
|
||||
purchaseDisabled,
|
||||
)}
|
||||
{wrapIfDisabled(
|
||||
<Button
|
||||
variant={canSubscribe && !billingUnavailable ? 'secondary' : 'primary'}
|
||||
onClick={navigateToRedeemGift}
|
||||
small
|
||||
className={styles.actionButton}
|
||||
disabled={purchaseDisabled}
|
||||
data-flx="app.plutonium.subscription-card.action-button.navigate-to-redeem-gift"
|
||||
>
|
||||
<Trans comment="Billing button for entering a premium gift code.">Redeem gift code</Trans>
|
||||
</Button>,
|
||||
'redeem-gift',
|
||||
purchaseDisabled,
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{(isFullyExpired || isInGracePeriod) && canSubscribe
|
||||
? wrapIfDisabled(
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleStartSubscription}
|
||||
small
|
||||
className={styles.actionButton}
|
||||
disabled={purchaseDisabled}
|
||||
data-flx="app.plutonium.subscription-card.action-button.resubscribe"
|
||||
>
|
||||
{hasEverPurchased ? (
|
||||
<Trans comment="Billing button for starting a new subscription after premium ended.">
|
||||
Resubscribe
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans comment="Billing button that starts a recurring subscription for someone on gifted premium time.">
|
||||
Subscribe
|
||||
</Trans>
|
||||
)}
|
||||
</Button>,
|
||||
'resubscribe',
|
||||
purchaseDisabled,
|
||||
)
|
||||
: hasEverPurchased &&
|
||||
wrapIfDisabled(
|
||||
<Button
|
||||
variant={isFullyExpired || isInGracePeriod || premiumWillCancel ? 'primary' : 'secondary'}
|
||||
onClick={
|
||||
shouldUseReactivateQuickAction ? handleReactivateSubscription : handleOpenCustomerPortal
|
||||
}
|
||||
submitting={shouldUseReactivateQuickAction ? loadingReactivate : loadingPortal}
|
||||
small
|
||||
className={styles.actionButton}
|
||||
disabled={purchaseDisabled && shouldUseReactivateQuickAction}
|
||||
data-flx="app.plutonium.subscription-card.action-button.reactivate-subscription"
|
||||
>
|
||||
{isFullyExpired ? (
|
||||
<Trans comment="Billing button for starting a new subscription after premium expired.">
|
||||
Resubscribe
|
||||
</Trans>
|
||||
) : isInGracePeriod ? (
|
||||
<Trans comment="Billing button for restarting a subscription during the grace period.">
|
||||
Resubscribe
|
||||
</Trans>
|
||||
) : premiumWillCancel ? (
|
||||
<Trans comment="Billing button that cancels a scheduled subscription cancellation.">
|
||||
Reactivate
|
||||
</Trans>
|
||||
) : isVisionary ? (
|
||||
<Trans comment="Billing button that opens the external customer portal.">
|
||||
Customer portal
|
||||
</Trans>
|
||||
) : (
|
||||
i18n._(MANAGE_SUBSCRIPTION_DESCRIPTOR)
|
||||
)}
|
||||
</Button>,
|
||||
'manage-reactivate',
|
||||
purchaseDisabled && shouldUseReactivateQuickAction,
|
||||
)}
|
||||
{isVisionary && (
|
||||
<Button
|
||||
variant="secondary"
|
||||
|
||||
+53
-31
@@ -132,11 +132,19 @@ const CHECKOUT_START_FAILED_BODY_DESCRIPTOR = msg({
|
||||
message: 'Something went wrong while starting checkout. Please try again in a moment.',
|
||||
comment: 'Body of the generic fallback error modal shown when creating a checkout session fails unexpectedly.',
|
||||
});
|
||||
const GIFT_SUBSCRIPTION_BLOCKS_RECURRING_TOAST_DESCRIPTOR = msg({
|
||||
message:
|
||||
"You're currently on a gift subscription. It won't renew. You can redeem more gift codes to extend it. Recurring subscriptions can be started after your gift time ends.",
|
||||
const GIFT_TIME_KEPT_TITLE_DESCRIPTOR = msg({
|
||||
message: 'Your gift time is kept',
|
||||
comment:
|
||||
'Error modal body shown when a gift-subscription user tries to start a recurring subscription. Explains the extension/redemption path.',
|
||||
'Title of the confirmation shown before checkout when a user with gifted premium time starts a recurring subscription.',
|
||||
});
|
||||
const GIFT_TIME_KEPT_BODY_DESCRIPTOR = msg({
|
||||
message: "You'll be charged now. Your remaining gift time is added after your paid period, so none of it is lost.",
|
||||
comment:
|
||||
'Body of the confirmation shown before checkout when a user with gifted premium time starts a recurring subscription. The subscription is charged immediately and the unused gift time is appended after the paid period.',
|
||||
});
|
||||
const CONTINUE_TO_CHECKOUT_DESCRIPTOR = msg({
|
||||
message: 'Continue to checkout',
|
||||
comment: 'Button in the gift time confirmation that proceeds to subscription checkout.',
|
||||
});
|
||||
const PRICING_NOT_LOADED_TOAST_DESCRIPTOR = msg({
|
||||
message: 'Pricing is still loading.',
|
||||
@@ -208,8 +216,8 @@ function alternativePaymentMethodForCurrency(
|
||||
export const useCheckoutActions = (
|
||||
priceIds: PriceIds | null,
|
||||
countryCode: string | null,
|
||||
isGiftSubscription: boolean,
|
||||
mobileEnabled: boolean,
|
||||
{hasGiftTime = false}: {hasGiftTime?: boolean} = {},
|
||||
) => {
|
||||
const {i18n} = useLingui();
|
||||
const [loadingCheckout, setLoadingCheckout] = useState(false);
|
||||
@@ -398,7 +406,7 @@ export const useCheckoutActions = (
|
||||
const handleSelectPlan = useCallback(
|
||||
async (plan: Plan) => {
|
||||
if (loadingCheckout) return;
|
||||
logger.info('Plan selected', {plan, isGiftSubscription});
|
||||
logger.info('Plan selected', {plan, hasGiftTime});
|
||||
const showCheckoutPlanErrorModal = (message: string, flxKey: string) => {
|
||||
ModalCommands.push(
|
||||
modal(() => (
|
||||
@@ -410,13 +418,6 @@ export const useCheckoutActions = (
|
||||
)),
|
||||
);
|
||||
};
|
||||
if (isGiftSubscription && (plan === 'monthly' || plan === 'yearly')) {
|
||||
showCheckoutPlanErrorModal(
|
||||
i18n._(GIFT_SUBSCRIPTION_BLOCKS_RECURRING_TOAST_DESCRIPTOR),
|
||||
'app.plutonium.use-checkout-actions.gift-subscription-blocked.generic-error-modal',
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!priceIds) {
|
||||
logger.error('Price IDs not loaded yet');
|
||||
showCheckoutPlanErrorModal(
|
||||
@@ -498,34 +499,55 @@ export const useCheckoutActions = (
|
||||
setLoadingCheckout(false);
|
||||
}
|
||||
};
|
||||
const altPaymentMethod = alternativePaymentMethodForCurrency(priceIds.currency, isGift, plan);
|
||||
if (altPaymentMethod && MANDATORY_LOCAL_PAYMENT_CURRENCIES.has(priceIds.currency ?? '')) {
|
||||
await startCheckout({paymentMethod: altPaymentMethod});
|
||||
return;
|
||||
}
|
||||
if (altPaymentMethod) {
|
||||
const altPrompt = getAlternativePaymentMethodPrompt(priceIds.currency, altPaymentMethod);
|
||||
const proceedToCheckout = async ({afterConfirm = false}: {afterConfirm?: boolean} = {}) => {
|
||||
const altPaymentMethod = alternativePaymentMethodForCurrency(priceIds.currency, isGift, plan);
|
||||
if (altPaymentMethod && MANDATORY_LOCAL_PAYMENT_CURRENCIES.has(priceIds.currency ?? '')) {
|
||||
await startCheckout({skipMobilePrompt: afterConfirm, paymentMethod: altPaymentMethod});
|
||||
return;
|
||||
}
|
||||
if (altPaymentMethod) {
|
||||
const altPrompt = getAlternativePaymentMethodPrompt(priceIds.currency, altPaymentMethod);
|
||||
ModalCommands.push(
|
||||
modal(() => (
|
||||
<ConfirmModal
|
||||
title={i18n._(CHOOSE_PAYMENT_METHOD_MODAL_TITLE_DESCRIPTOR)}
|
||||
description={altPrompt.description}
|
||||
primaryText={altPrompt.primaryText}
|
||||
primaryVariant="primary"
|
||||
secondaryText={i18n._(USE_CARD_BUTTON_DESCRIPTOR)}
|
||||
onPrimary={() => {
|
||||
void startCheckout({skipMobilePrompt: true, paymentMethod: altPaymentMethod});
|
||||
}}
|
||||
onSecondary={() => {
|
||||
void startCheckout({skipMobilePrompt: true});
|
||||
}}
|
||||
data-flx="app.plutonium.use-checkout-actions.handle-select-plan.confirm-modal--2"
|
||||
/>
|
||||
)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
await startCheckout({skipMobilePrompt: afterConfirm});
|
||||
};
|
||||
if (hasGiftTime && !isGift) {
|
||||
ModalCommands.push(
|
||||
modal(() => (
|
||||
<ConfirmModal
|
||||
title={i18n._(CHOOSE_PAYMENT_METHOD_MODAL_TITLE_DESCRIPTOR)}
|
||||
description={altPrompt.description}
|
||||
primaryText={altPrompt.primaryText}
|
||||
title={i18n._(GIFT_TIME_KEPT_TITLE_DESCRIPTOR)}
|
||||
description={i18n._(GIFT_TIME_KEPT_BODY_DESCRIPTOR)}
|
||||
primaryText={i18n._(CONTINUE_TO_CHECKOUT_DESCRIPTOR)}
|
||||
primaryVariant="primary"
|
||||
secondaryText={i18n._(USE_CARD_BUTTON_DESCRIPTOR)}
|
||||
secondaryText={i18n._(CANCEL_DESCRIPTOR)}
|
||||
onPrimary={() => {
|
||||
void startCheckout({skipMobilePrompt: true, paymentMethod: altPaymentMethod});
|
||||
void proceedToCheckout({afterConfirm: true});
|
||||
}}
|
||||
onSecondary={() => {
|
||||
void startCheckout({skipMobilePrompt: true});
|
||||
}}
|
||||
data-flx="app.plutonium.use-checkout-actions.handle-select-plan.confirm-modal--2"
|
||||
data-flx="app.plutonium.use-checkout-actions.handle-select-plan.gift-time-confirm-modal"
|
||||
/>
|
||||
)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
await startCheckout();
|
||||
await proceedToCheckout();
|
||||
},
|
||||
[
|
||||
handleCheckoutError,
|
||||
@@ -533,7 +555,7 @@ export const useCheckoutActions = (
|
||||
priceIds,
|
||||
countryCode,
|
||||
getAlternativePaymentMethodPrompt,
|
||||
isGiftSubscription,
|
||||
hasGiftTime,
|
||||
mobileEnabled,
|
||||
i18n,
|
||||
],
|
||||
|
||||
+17
-1
@@ -2,6 +2,7 @@
|
||||
|
||||
import DeveloperOptions from '@app/features/devtools/state/DeveloperOptions';
|
||||
import {getPremiumGraceEndDate} from '@app/features/premium/utils/PremiumGrace';
|
||||
import {classifyPremiumSubscription} from '@app/features/premium/utils/PremiumSubscriptionClassification';
|
||||
import {getStoreOwnedSubscription} from '@app/features/premium/utils/PremiumUtils';
|
||||
import type {User} from '@app/features/user/models/User';
|
||||
import {UserPremiumTypes} from '@fluxer/constants/src/UserConstants';
|
||||
@@ -27,6 +28,8 @@ export interface SubscriptionStatusInfo {
|
||||
billingCycle: string | null;
|
||||
actualPremiumUntil: Date | null;
|
||||
isGiftSubscription: boolean;
|
||||
isGiftGrace: boolean;
|
||||
canStartSubscription: boolean;
|
||||
storeSubscription: PremiumStoreSubscriptionState | null;
|
||||
gracePeriodInfo: GracePeriodInfo;
|
||||
shouldShowPremiumCard: boolean;
|
||||
@@ -91,7 +94,6 @@ export const useSubscriptionStatus = (
|
||||
: storeSubscription
|
||||
? storeSubscription.billing_cycle
|
||||
: (actual?.premium_billing_cycle ?? currentUser?.premiumBillingCycle ?? null);
|
||||
const isGiftSubscription = Boolean(!billingCycle && hasPaidPremium && !isVisionary && premiumUntil);
|
||||
const isStoreGrace = storeSubscription?.state === 'grace' && premiumGraceEndsAt != null;
|
||||
const gracePeriodInfo = useMemo((): GracePeriodInfo => {
|
||||
if (isVisionary) {
|
||||
@@ -125,6 +127,18 @@ export const useSubscriptionStatus = (
|
||||
return {isInGracePeriod, isExpired, graceEndDate, showExpiredState, isPaymentRecovery};
|
||||
}, [premiumUntil, premiumGraceEndsAt, isVisionary, billingCycle, isStoreGrace]);
|
||||
const {isInGracePeriod, isExpired: isFullyExpired, showExpiredState} = gracePeriodInfo;
|
||||
const {isGiftSubscription, isGiftGrace, canStartSubscription} = classifyPremiumSubscription({
|
||||
hasPaidPremium,
|
||||
isVisionary,
|
||||
hasStoreSubscription: storeSubscription != null,
|
||||
billingCycle,
|
||||
premiumUntil,
|
||||
isInGracePeriod,
|
||||
isFullyExpired,
|
||||
billingKnown: !useScenarioOverride && premiumState != null,
|
||||
storeOwnershipKnown: useScenarioOverride || premiumState != null,
|
||||
billingSubscription: useScenarioOverride ? null : (premiumState?.billing.subscription ?? null),
|
||||
});
|
||||
const isPremium = useDeveloperOverride
|
||||
? hasPaidPremium && !isFullyExpired && !perksDisabled
|
||||
: (effective?.is_premium ?? currentUser?.isPremium() ?? false);
|
||||
@@ -163,6 +177,8 @@ export const useSubscriptionStatus = (
|
||||
billingCycle,
|
||||
actualPremiumUntil: premiumUntil,
|
||||
isGiftSubscription,
|
||||
isGiftGrace,
|
||||
canStartSubscription,
|
||||
storeSubscription,
|
||||
gracePeriodInfo,
|
||||
shouldShowPremiumCard,
|
||||
|
||||
Reference in new issue
Block a user