fix: show error state instead of blank page on purchase-options failure

When the purchase-options API call failed (e.g. for email-registered
users), the page rendered only the header with no content. Now shows
an error message with retry button. Also adds a fallback for when
the API returns no available tariffs or periods.
This commit is contained in:
Fringg
2026-03-22 04:45:19 +03:00
parent ac1550ce10
commit 9d519fb5ec

View File

@@ -45,7 +45,12 @@ export default function SubscriptionPurchase() {
const subscription = subscriptionResponse?.subscription ?? null;
// Purchase options
const { data: purchaseOptions, isLoading: optionsLoading } = useQuery({
const {
data: purchaseOptions,
isLoading: optionsLoading,
isError: optionsError,
refetch: refetchOptions,
} = useQuery({
queryKey: ['purchase-options'],
queryFn: subscriptionApi.getPurchaseOptions,
staleTime: 0,
@@ -362,6 +367,58 @@ export default function SubscriptionPurchase() {
);
}
if (optionsError || (!purchaseOptions && !optionsLoading)) {
return (
<div className="space-y-6">
<div className="flex items-center gap-3">
<button
onClick={() => navigate('/subscription')}
aria-label="Back"
className="flex h-9 w-9 items-center justify-center rounded-xl transition-colors"
style={{
background: g.innerBg,
border: `1px solid ${g.innerBorder}`,
}}
>
<svg
width="18"
height="18"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
className="text-dark-50/60"
>
<path d="M19 12H5M12 19l-7-7 7-7" />
</svg>
</button>
<h1 className="text-2xl font-bold text-dark-50 sm:text-3xl">
{t('subscription.extend')}
</h1>
</div>
<div
className="rounded-3xl p-6 text-center"
style={{
background: g.cardBg,
border: `1px solid ${g.cardBorder}`,
}}
>
<p className="mb-4 text-dark-300">
{t('subscription.loadError', 'Не удалось загрузить варианты подписки')}
</p>
<button
onClick={() => refetchOptions()}
className="rounded-xl bg-accent-500 px-6 py-2 text-sm font-medium text-white transition-colors hover:bg-accent-600"
>
{t('common.retry')}
</button>
</div>
</div>
);
}
return (
<div className="space-y-6">
{/* Header with back link */}
@@ -1936,6 +1993,30 @@ export default function SubscriptionPurchase() {
)}
</div>
)}
{/* No options available fallback */}
{purchaseOptions &&
!optionsLoading &&
!(isTariffsMode && tariffs.length > 0) &&
!(classicOptions && classicOptions.periods.length > 0) && (
<div
className="rounded-3xl p-6 text-center"
style={{
background: g.cardBg,
border: `1px solid ${g.cardBorder}`,
}}
>
<p className="mb-4 text-dark-300">
{t('subscription.noOptionsAvailable', 'Нет доступных вариантов подписки')}
</p>
<button
onClick={() => refetchOptions()}
className="rounded-xl bg-accent-500 px-6 py-2 text-sm font-medium text-white transition-colors hover:bg-accent-600"
>
{t('common.retry')}
</button>
</div>
)}
</div>
);
}