From bdfc74534ab726c1a4cfd3424225b899298d9644 Mon Sep 17 00:00:00 2001 From: PEDZEO Date: Mon, 19 Jan 2026 23:44:02 +0300 Subject: [PATCH] Refactor PeriodTariffModal to remove server traffic limits and add custom days and traffic options for flexible tariffs --- src/pages/AdminTariffs.tsx | 241 +++++++++++++++++++++++-------------- 1 file changed, 148 insertions(+), 93 deletions(-) diff --git a/src/pages/AdminTariffs.tsx b/src/pages/AdminTariffs.tsx index 7c7d514..eb7a2ee 100644 --- a/src/pages/AdminTariffs.tsx +++ b/src/pages/AdminTariffs.tsx @@ -9,8 +9,7 @@ import { TariffCreateRequest, TariffUpdateRequest, PeriodPrice, - ServerInfo, - ServerTrafficLimit + ServerInfo } from '../api/tariffs' // Icons @@ -146,9 +145,6 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri tariff?.period_prices?.length ? tariff.period_prices : [] ) const [selectedSquads, setSelectedSquads] = useState(tariff?.allowed_squads || []) - const [serverTrafficLimits, setServerTrafficLimits] = useState>( - tariff?.server_traffic_limits || {} - ) // Докупка трафика const [trafficTopupEnabled, setTrafficTopupEnabled] = useState(tariff?.traffic_topup_enabled || false) const [maxTopupTrafficGb, setMaxTopupTrafficGb] = useState(tariff?.max_topup_traffic_gb || 0) @@ -159,6 +155,18 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri // Режим сброса трафика const [trafficResetMode, setTrafficResetMode] = useState(tariff?.traffic_reset_mode || null) + // Плавающий тариф - произвольное количество дней + const [customDaysEnabled, setCustomDaysEnabled] = useState(tariff?.custom_days_enabled || false) + const [pricePerDayKopeks, setPricePerDayKopeks] = useState(tariff?.price_per_day_kopeks || 0) + const [minDays, setMinDays] = useState(tariff?.min_days || 1) + const [maxDays, setMaxDays] = useState(tariff?.max_days || 365) + + // Плавающий тариф - произвольный трафик + const [customTrafficEnabled, setCustomTrafficEnabled] = useState(tariff?.custom_traffic_enabled || false) + const [trafficPricePerGbKopeks, setTrafficPricePerGbKopeks] = useState(tariff?.traffic_price_per_gb_kopeks || 0) + const [minTrafficGb, setMinTrafficGb] = useState(tariff?.min_traffic_gb || 1) + const [maxTrafficGb, setMaxTrafficGb] = useState(tariff?.max_traffic_gb || 1000) + // Новый период для добавления const [newPeriodDays, setNewPeriodDays] = useState(30) const [newPeriodPrice, setNewPeriodPrice] = useState(300) @@ -166,13 +174,6 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri const [activeTab, setActiveTab] = useState<'basic' | 'periods' | 'servers' | 'extra'>('basic') const handleSubmit = () => { - const filteredLimits: Record = {} - for (const uuid of selectedSquads) { - if (serverTrafficLimits[uuid] && serverTrafficLimits[uuid].traffic_limit_gb > 0) { - filteredLimits[uuid] = serverTrafficLimits[uuid] - } - } - const data: TariffCreateRequest | TariffUpdateRequest = { name, description: description || undefined, @@ -183,24 +184,25 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri tier_level: tierLevel, period_prices: periodPrices.filter(p => p.price_kopeks > 0), allowed_squads: selectedSquads, - server_traffic_limits: Object.keys(filteredLimits).length > 0 ? filteredLimits : {}, traffic_topup_enabled: trafficTopupEnabled, traffic_topup_packages: trafficTopupPackages, max_topup_traffic_gb: maxTopupTrafficGb, is_daily: false, daily_price_kopeks: 0, traffic_reset_mode: trafficResetMode, + // Плавающий тариф + custom_days_enabled: customDaysEnabled, + price_per_day_kopeks: pricePerDayKopeks, + min_days: minDays, + max_days: maxDays, + custom_traffic_enabled: customTrafficEnabled, + traffic_price_per_gb_kopeks: trafficPricePerGbKopeks, + min_traffic_gb: minTrafficGb, + max_traffic_gb: maxTrafficGb, } onSave(data) } - const updateServerTrafficLimit = (uuid: string, limitGb: number) => { - setServerTrafficLimits(prev => ({ - ...prev, - [uuid]: { traffic_limit_gb: limitGb } - })) - } - const toggleServer = (uuid: string) => { setSelectedSquads(prev => prev.includes(uuid) @@ -430,27 +432,24 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri {activeTab === 'servers' && (

- Выберите серверы, доступные на этом тарифе. Можно задать индивидуальный лимит трафика для каждого. + Выберите серверы, доступные на этом тарифе.

{servers.length === 0 ? (

Нет доступных серверов

) : ( servers.map(server => { const isSelected = selectedSquads.includes(server.squad_uuid) - const serverLimit = serverTrafficLimits[server.squad_uuid]?.traffic_limit_gb || 0 return (
toggleServer(server.squad_uuid)} + className={`p-3 rounded-lg transition-colors cursor-pointer ${ isSelected ? 'bg-accent-500/20 border border-accent-500/50' : 'bg-dark-700 hover:bg-dark-600 border border-transparent' }`} > -
toggleServer(server.squad_uuid)} - className="flex items-center gap-3 cursor-pointer" - > +
{server.country_code} )}
- {isSelected && ( -
- Лимит трафика: - e.stopPropagation()} - onChange={e => { - e.stopPropagation() - updateServerTrafficLimit(server.squad_uuid, Math.max(0, parseInt(e.target.value) || 0)) - }} - className="w-20 px-2 py-1 bg-dark-600 border border-dark-500 rounded text-sm text-dark-100 focus:outline-none focus:border-accent-500" - min={0} - placeholder="0" - /> - ГБ - {serverLimit === 0 && ( - (использовать общий) - )} -
- )}
) }) @@ -585,6 +563,124 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri )}
+ {/* Плавающий тариф - произвольное количество дней */} +
+
+
+

Произвольное количество дней

+

Пользователь сам выбирает срок подписки

+
+ +
+ {customDaysEnabled && ( +
+
+ Цена за день: + setPricePerDayKopeks(Math.max(0, parseFloat(e.target.value) || 0) * 100)} + className="w-24 px-3 py-2 bg-dark-600 border border-dark-500 rounded-lg text-dark-100 focus:outline-none focus:border-accent-500" + min={0} + step={0.1} + /> + +
+
+ Мин. дней: + setMinDays(Math.max(1, parseInt(e.target.value) || 1))} + className="w-24 px-3 py-2 bg-dark-600 border border-dark-500 rounded-lg text-dark-100 focus:outline-none focus:border-accent-500" + min={1} + /> +
+
+ Макс. дней: + setMaxDays(Math.max(1, parseInt(e.target.value) || 1))} + className="w-24 px-3 py-2 bg-dark-600 border border-dark-500 rounded-lg text-dark-100 focus:outline-none focus:border-accent-500" + min={1} + /> +
+
+ )} +
+ + {/* Плавающий тариф - произвольный трафик */} +
+
+
+

Произвольный объём трафика

+

Пользователь сам выбирает объём трафика при покупке

+
+ +
+ {customTrafficEnabled && ( +
+
+ Цена за 1 ГБ: + setTrafficPricePerGbKopeks(Math.max(0, parseFloat(e.target.value) || 0) * 100)} + className="w-24 px-3 py-2 bg-dark-600 border border-dark-500 rounded-lg text-dark-100 focus:outline-none focus:border-accent-500" + min={0} + step={0.1} + /> + +
+
+ Мин. ГБ: + setMinTrafficGb(Math.max(1, parseInt(e.target.value) || 1))} + className="w-24 px-3 py-2 bg-dark-600 border border-dark-500 rounded-lg text-dark-100 focus:outline-none focus:border-accent-500" + min={1} + /> +
+
+ Макс. ГБ: + setMaxTrafficGb(Math.max(1, parseInt(e.target.value) || 1))} + className="w-24 px-3 py-2 bg-dark-600 border border-dark-500 rounded-lg text-dark-100 focus:outline-none focus:border-accent-500" + min={1} + /> +
+
+ )} +
+ {/* Режим сброса трафика */}

Режим сброса трафика

@@ -636,7 +732,7 @@ function PeriodTariffModal({ tariff, servers, onSave, onClose, isLoading }: Peri