Files
bedolaga-cabinet/src/api/tariffs.ts
c0mrade 0d024aec58 fix(i18n): spell the brand "Remnawave" instead of camelCase "RemnaWave"
Replace the user-facing 'RemnaWave' spelling with 'Remnawave' across all locale values (en/ru/zh/fa, 67 strings), t() display fallbacks, and code comments. Translation keys (refreshRemnaWave, ...) and code identifiers (RemnaWaveService, setRemnaWaveUuid, ...) are left untouched.
2026-06-01 13:31:12 +03:00

275 lines
7.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import apiClient from './client';
// Types
export interface PeriodPrice {
days: number;
price_kopeks: number;
price_rubles?: number;
}
export interface ServerTrafficLimit {
traffic_limit_gb: number;
}
export interface ServerInfo {
id: number;
squad_uuid: string;
display_name: string;
country_code: string | null;
is_selected: boolean;
traffic_limit_gb?: number | null;
}
export interface PromoGroupInfo {
id: number;
name: string;
is_selected: boolean;
}
export interface TariffListItem {
id: number;
name: string;
description: string | null;
is_active: boolean;
is_trial_available: boolean;
show_in_gift: boolean;
is_daily: boolean;
daily_price_kopeks: number;
traffic_limit_gb: number;
device_limit: number;
tier_level: number;
display_order: number;
servers_count: number;
subscriptions_count: number;
created_at: string;
}
export interface TariffListResponse {
tariffs: TariffListItem[];
total: number;
}
export interface TariffDetail {
id: number;
name: string;
description: string | null;
is_active: boolean;
is_trial_available: boolean;
show_in_gift: boolean;
traffic_limit_gb: number;
device_limit: number;
device_price_kopeks: number | null;
max_device_limit: number | null;
tier_level: number;
display_order: number;
period_prices: PeriodPrice[];
allowed_squads: string[];
server_traffic_limits: Record<string, ServerTrafficLimit>;
servers: ServerInfo[];
promo_groups: PromoGroupInfo[];
subscriptions_count: number;
// Произвольное количество дней
custom_days_enabled: boolean;
price_per_day_kopeks: number;
min_days: number;
max_days: number;
// Произвольный трафик при покупке
custom_traffic_enabled: boolean;
traffic_price_per_gb_kopeks: number;
min_traffic_gb: number;
max_traffic_gb: number;
// Докупка трафика
traffic_topup_enabled: boolean;
traffic_topup_packages: Record<string, number>;
max_topup_traffic_gb: number;
// Дневной тариф
is_daily: boolean;
daily_price_kopeks: number;
// Режим сброса трафика
traffic_reset_mode: string | null; // 'DAY', 'WEEK', 'MONTH', 'MONTH_ROLLING', 'NO_RESET', null = глобальная настройка
// Внешний сквад Remnawave
external_squad_uuid: string | null;
created_at: string;
updated_at: string | null;
}
export interface TariffCreateRequest {
name: string;
description?: string;
is_active?: boolean;
show_in_gift?: boolean;
traffic_limit_gb?: number;
device_limit?: number;
device_price_kopeks?: number;
max_device_limit?: number;
tier_level?: number;
period_prices?: PeriodPrice[];
allowed_squads?: string[];
server_traffic_limits?: Record<string, ServerTrafficLimit>;
promo_group_ids?: number[];
// Произвольное количество дней
custom_days_enabled?: boolean;
price_per_day_kopeks?: number;
min_days?: number;
max_days?: number;
// Произвольный трафик при покупке
custom_traffic_enabled?: boolean;
traffic_price_per_gb_kopeks?: number;
min_traffic_gb?: number;
max_traffic_gb?: number;
// Докупка трафика
traffic_topup_enabled?: boolean;
traffic_topup_packages?: Record<string, number>;
max_topup_traffic_gb?: number;
// Дневной тариф
is_daily?: boolean;
daily_price_kopeks?: number;
// Режим сброса трафика
traffic_reset_mode?: string | null;
// Внешний сквад Remnawave
external_squad_uuid?: string | null;
}
export interface ExternalSquadInfo {
uuid: string;
name: string;
members_count: number;
}
export interface TariffUpdateRequest {
name?: string;
description?: string;
is_active?: boolean;
show_in_gift?: boolean;
traffic_limit_gb?: number;
device_limit?: number;
device_price_kopeks?: number;
max_device_limit?: number;
tier_level?: number;
display_order?: number;
period_prices?: PeriodPrice[];
allowed_squads?: string[];
server_traffic_limits?: Record<string, ServerTrafficLimit>;
promo_group_ids?: number[];
// Произвольное количество дней
custom_days_enabled?: boolean;
price_per_day_kopeks?: number;
min_days?: number;
max_days?: number;
// Произвольный трафик при покупке
custom_traffic_enabled?: boolean;
traffic_price_per_gb_kopeks?: number;
min_traffic_gb?: number;
max_traffic_gb?: number;
// Докупка трафика
traffic_topup_enabled?: boolean;
traffic_topup_packages?: Record<string, number>;
max_topup_traffic_gb?: number;
// Дневной тариф
is_daily?: boolean;
daily_price_kopeks?: number;
// Режим сброса трафика
traffic_reset_mode?: string | null;
// Внешний сквад Remnawave
external_squad_uuid?: string | null;
}
export interface TariffToggleResponse {
id: number;
is_active: boolean;
message: string;
}
export interface TariffTrialResponse {
id: number;
is_trial_available: boolean;
message: string;
}
export interface TariffStats {
id: number;
name: string;
subscriptions_count: number;
active_subscriptions: number;
trial_subscriptions: number;
revenue_kopeks: number;
revenue_rubles: number;
}
export const tariffsApi = {
// Get all tariffs
getTariffs: async (includeInactive = true): Promise<TariffListResponse> => {
const response = await apiClient.get('/cabinet/admin/tariffs', {
params: { include_inactive: includeInactive },
});
return response.data;
},
// Get single tariff
getTariff: async (tariffId: number): Promise<TariffDetail> => {
const response = await apiClient.get(`/cabinet/admin/tariffs/${tariffId}`);
return response.data;
},
// Create new tariff
createTariff: async (data: TariffCreateRequest): Promise<TariffDetail> => {
const response = await apiClient.post('/cabinet/admin/tariffs', data);
return response.data;
},
// Update tariff
updateTariff: async (tariffId: number, data: TariffUpdateRequest): Promise<TariffDetail> => {
const response = await apiClient.put(`/cabinet/admin/tariffs/${tariffId}`, data);
return response.data;
},
// Delete tariff
deleteTariff: async (
tariffId: number,
): Promise<{ message: string; affected_subscriptions: number }> => {
const response = await apiClient.delete(`/cabinet/admin/tariffs/${tariffId}`);
return response.data;
},
// Toggle tariff active status
toggleTariff: async (tariffId: number): Promise<TariffToggleResponse> => {
const response = await apiClient.post(`/cabinet/admin/tariffs/${tariffId}/toggle`);
return response.data;
},
// Toggle trial status
toggleTrial: async (tariffId: number): Promise<TariffTrialResponse> => {
const response = await apiClient.post(`/cabinet/admin/tariffs/${tariffId}/trial`);
return response.data;
},
// Get tariff stats
getTariffStats: async (tariffId: number): Promise<TariffStats> => {
const response = await apiClient.get(`/cabinet/admin/tariffs/${tariffId}/stats`);
return response.data;
},
// Update tariff display order
updateOrder: async (tariffIds: number[]): Promise<void> => {
await apiClient.put('/cabinet/admin/tariffs/order', { tariff_ids: tariffIds });
},
// Get available servers for selection
getAvailableServers: async (): Promise<ServerInfo[]> => {
const response = await apiClient.get('/cabinet/admin/tariffs/available-servers');
return response.data;
},
// Get available promo groups for selection
getAvailablePromoGroups: async (): Promise<{ id: number; name: string }[]> => {
const response = await apiClient.get('/cabinet/admin/payment-methods/promo-groups');
return response.data;
},
// Get available external squads from Remnawave
getAvailableExternalSquads: async (): Promise<ExternalSquadInfo[]> => {
const response = await apiClient.get('/cabinet/admin/tariffs/available-external-squads');
return response.data;
},
};