refactor: extract purchase/renewal flow to separate page

Move ~1900 lines of purchase/renewal logic from Subscription.tsx into
a new SubscriptionPurchase.tsx page at /subscription/purchase.

- Create SubscriptionPurchase.tsx with tariffs grid, classic mode wizard,
  switch preview modal, and promo handling
- Create PurchaseCTAButton.tsx with animated gradient border, state-aware
  colors and context-aware text
- Create subscriptionHelpers.ts with shared utilities
- Add CopyIcon to shared icons module
- Register /subscription/purchase route with lazy loading
- Update SubscriptionCardExpired and PromoOffersSection navigators
- Add CTA translation keys to ru.json and en.json
- Remove all scrollToExtend references
This commit is contained in:
Fringg
2026-02-27 06:47:30 +03:00
parent f4d7a2cc8d
commit 126f9ab9b9
10 changed files with 2091 additions and 1942 deletions

View File

@@ -0,0 +1,42 @@
import { AxiosError } from 'axios';
import i18n from '../i18n';
export type PurchaseStep = 'period' | 'traffic' | 'servers' | 'devices' | 'confirm';
export const getErrorMessage = (error: unknown): string => {
if (error instanceof AxiosError) {
const detail = error.response?.data?.detail;
if (typeof detail === 'string') return detail;
if (typeof detail === 'object' && detail?.message) return detail.message;
}
if (error instanceof Error) return error.message;
return i18n.t('common.error');
};
export const getInsufficientBalanceError = (
error: unknown,
): { required: number; balance: number; missingAmount?: number } | null => {
if (error instanceof AxiosError) {
const detail = error.response?.data?.detail;
if (
typeof detail === 'object' &&
(detail?.code === 'insufficient_balance' || detail?.code === 'insufficient_funds')
) {
return {
required: detail.required || detail.total_price || 0,
balance: detail.balance || 0,
missingAmount: detail.missing_amount || detail.missingAmount || 0,
};
}
}
return null;
};
export const getFlagEmoji = (countryCode: string): string => {
if (!countryCode || countryCode.length !== 2) return '';
const codePoints = countryCode
.toUpperCase()
.split('')
.map((char) => 127397 + char.charCodeAt(0));
return String.fromCodePoint(...codePoints);
};