diff --git a/src/pages/Subscription.tsx b/src/pages/Subscription.tsx index 402de39..e5b1891 100644 --- a/src/pages/Subscription.tsx +++ b/src/pages/Subscription.tsx @@ -312,6 +312,28 @@ export default function Subscription() { queryClient.invalidateQueries({ queryKey: ['purchase-options'] }); setSwitchTariffId(null); }, + onError: (error: unknown) => { + // Handle subscription_expired error - redirect to purchase flow + if (error instanceof AxiosError) { + const detail = error.response?.data?.detail; + if ( + typeof detail === 'object' && + detail?.error_code === 'subscription_expired' && + detail?.use_purchase_flow === true + ) { + // Find the tariff user was trying to switch to and open purchase form + const targetTariff = tariffs.find((t) => t.id === switchTariffId); + if (targetTariff) { + setSwitchTariffId(null); + setSelectedTariff(targetTariff); + setSelectedTariffPeriod(targetTariff.periods[0] || null); + setShowTariffPurchase(true); + // Refetch purchase-options to get updated expired status + queryClient.invalidateQueries({ queryKey: ['purchase-options'] }); + } + } + } + }, }); // Tariff purchase mutation @@ -1955,6 +1977,40 @@ export default function Subscription() { )} + {/* Expired subscription notice - prompt to purchase new tariff */} + {isTariffsMode && + purchaseOptions && + 'subscription_is_expired' in purchaseOptions && + purchaseOptions.subscription_is_expired && ( +
+
+
+ + + +
+
+
+ {t('subscription.expired.title')} +
+
+ {t('subscription.expired.selectTariff')} +
+
+
+
+ )} + {/* Legacy subscription notice - if user has subscription without tariff */} {subscription && !subscription.is_trial && !subscription.tariff_id && (
@@ -2066,6 +2122,27 @@ export default function Subscription() { t('subscription.switchTariff.switch') )} + + {/* Show error (except subscription_expired which redirects to purchase) */} + {switchTariffMutation.isError && + (() => { + const detail = + switchTariffMutation.error instanceof AxiosError + ? switchTariffMutation.error.response?.data?.detail + : null; + // Skip displaying if it's subscription_expired (handled by redirect) + if ( + typeof detail === 'object' && + detail?.error_code === 'subscription_expired' + ) { + return null; + } + return ( +
+ {getErrorMessage(switchTariffMutation.error)} +
+ ); + })()} ); })() @@ -2125,11 +2202,20 @@ export default function Subscription() { .map((tariff) => { const isCurrentTariff = tariff.is_current || tariff.id === subscription?.tariff_id; + // Check if subscription is expired from purchaseOptions + const isSubscriptionExpired = + isTariffsMode && + purchaseOptions && + 'subscription_is_expired' in purchaseOptions && + purchaseOptions.subscription_is_expired === true; + // canSwitch only if subscription is active (not expired, not trial) const canSwitch = subscription && subscription.tariff_id && !isCurrentTariff && - !subscription.is_trial; + !subscription.is_trial && + !isSubscriptionExpired && + subscription.is_active; // Если есть подписка БЕЗ tariff_id (классическая) - разрешить выбрать тариф const isLegacySubscription = subscription && !subscription.is_trial && !subscription.tariff_id;