feat(lava): автопродление Lava на странице подписки

Парная фронтовая часть к эндпоинтам /cabinet/subscription/lava-recurrent
(бот: 0dea2182). Блок — сиблинг Platega-блока с той же семантикой состояний
(off/pending/active/past_due), поллинг раз в 8с пока привязка PENDING.

Отличие от Platega в подписи: у Lava период задан продуктом в кабинете
провайдера и приезжает числом дней, поэтому канонические значения (30/90/365
и т.д.) показываются словами, а произвольные — как «раз в N дн.».

utils/lavaRecurring.ts: строгое распознавание 403 'Lava recurrent disabled'
(другие 403-guard'ы прятать нельзя), деградация неизвестного статуса в off.
Локали ru/en/zh/fa (+25 строк каждая, плейсхолдеры сверены). 7 тестов утилиты.
This commit is contained in:
Fringg
2026-07-29 16:34:43 +03:00
parent 62aaa5d7c9
commit 2dce539da2
9 changed files with 474 additions and 0 deletions

View File

@@ -13,6 +13,7 @@ import type {
PurchasePreview,
AppConfig,
SbpRecurringInfo,
LavaRecurringInfo,
} from '../types';
/** Helper: build query params with optional subscription_id */
@@ -394,6 +395,34 @@ export const subscriptionApi = {
return response.data;
},
// ── Recurring (Lava) ──────────────────────────────────────────────────
getLavaRecurring: async (subscriptionId?: number): Promise<LavaRecurringInfo> => {
const response = await apiClient.get<LavaRecurringInfo>(
'/cabinet/subscription/lava-recurrent',
withSubId(subscriptionId),
);
return response.data;
},
enableLavaRecurring: async (
subscriptionId?: number,
): Promise<{ status: string; redirect_url: string | null }> => {
const response = await apiClient.post(
'/cabinet/subscription/lava-recurrent/enable',
...bodyWithSubId({}, subscriptionId),
);
return response.data;
},
cancelLavaRecurring: async (subscriptionId?: number): Promise<{ status: string }> => {
const response = await apiClient.post(
'/cabinet/subscription/lava-recurrent/cancel',
...bodyWithSubId({}, subscriptionId),
);
return response.data;
},
// ── Trial ───────────────────────────────────────────────────────────
getTrialInfo: async (): Promise<TrialInfo> => {