feat: add show_in_gift toggle UI for tariffs in admin panel

Add pill toggle in tariff create/edit form and purple gift badge
in tariff list. Includes i18n for ru, en, zh, fa locales.
This commit is contained in:
Fringg
2026-03-12 04:16:04 +03:00
parent 01e811bdfc
commit 5a5a987893
7 changed files with 61 additions and 0 deletions

View File

@@ -32,6 +32,7 @@ export interface TariffListItem {
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;
@@ -54,6 +55,7 @@ export interface TariffDetail {
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;
@@ -95,6 +97,7 @@ 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;
@@ -137,6 +140,7 @@ 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;

View File

@@ -2044,6 +2044,9 @@
"statusTitle": "Tariff Status",
"isActiveLabel": "Active",
"isActiveHint": "Inactive tariffs are not shown to users",
"showInGiftLabel": "Show in gifts",
"showInGiftHint": "Tariff will be available for purchase in the gifts section",
"giftBadge": "Gift",
"isTrialLabel": "Trial tariff",
"isTrialHint": "Available for free trial period",
"validation": {

View File

@@ -1705,6 +1705,9 @@
"statusTitle": "وضعیت تعرفه",
"isActiveLabel": "فعال",
"isActiveHint": "تعرفه‌های غیرفعال به کاربران نمایش داده نمی‌شوند",
"showInGiftLabel": "نمایش در هدایا",
"showInGiftHint": "تعرفه برای خرید در بخش هدایا در دسترس خواهد بود",
"giftBadge": "هدیه",
"isTrialLabel": "تعرفه آزمایشی",
"isTrialHint": "برای دوره آزمایشی رایگان در دسترس است",
"validation": {

View File

@@ -2558,6 +2558,9 @@
"statusTitle": "Статус тарифа",
"isActiveLabel": "Активен",
"isActiveHint": "Неактивные тарифы не отображаются пользователям",
"showInGiftLabel": "Видимость в подарках",
"showInGiftHint": "Тариф будет доступен для покупки в разделе подарков",
"giftBadge": "Подарок",
"isTrialLabel": "Триальный тариф",
"isTrialHint": "Доступен для бесплатного пробного периода",
"validation": {

View File

@@ -1742,6 +1742,9 @@
"statusTitle": "套餐状态",
"isActiveLabel": "已激活",
"isActiveHint": "未激活的套餐不会显示给用户",
"showInGiftLabel": "在礼物中显示",
"showInGiftHint": "套餐将在礼物区域中可供购买",
"giftBadge": "礼物",
"isTrialLabel": "试用套餐",
"isTrialHint": "可用于免费试用期",
"validation": {

View File

@@ -125,6 +125,9 @@ export default function AdminTariffCreate() {
// Traffic reset mode
const [trafficResetMode, setTrafficResetMode] = useState<string | null>(null);
// Gift visibility
const [showInGift, setShowInGift] = useState(true);
// New period for adding
const [newPeriodDays, setNewPeriodDays] = useState<number | ''>(30);
const [newPeriodPrice, setNewPeriodPrice] = useState<number | ''>(300);
@@ -182,6 +185,7 @@ export default function AdminTariffCreate() {
setMaxTopupTrafficGb(data.max_topup_traffic_gb || 0);
setTrafficTopupPackages(data.traffic_topup_packages || {});
setTrafficResetMode(data.traffic_reset_mode || null);
setShowInGift(data.show_in_gift ?? true);
return data;
}, []),
});
@@ -212,6 +216,7 @@ export default function AdminTariffCreate() {
name,
description: description || undefined,
is_active: isActive,
show_in_gift: showInGift,
traffic_limit_gb: toNumber(trafficLimitGb, 100),
device_limit: toNumber(deviceLimit, 1),
device_price_kopeks:
@@ -1113,6 +1118,28 @@ export default function AdminTariffCreate() {
/>
</button>
</div>
{/* Show in gift toggle */}
<div className="flex items-center justify-between rounded-lg bg-dark-800 p-3">
<div>
<span className="text-sm font-medium text-dark-200">
{t('admin.tariffs.showInGiftLabel')}
</span>
<p className="text-xs text-dark-500">{t('admin.tariffs.showInGiftHint')}</p>
</div>
<button
type="button"
onClick={() => setShowInGift(!showInGift)}
className={`relative h-6 w-11 rounded-full transition-colors ${
showInGift ? 'bg-accent-500' : 'bg-dark-600'
}`}
>
<span
className={`absolute top-1 h-4 w-4 rounded-full bg-white transition-transform ${
showInGift ? 'left-6' : 'left-1'
}`}
/>
</button>
</div>
</div>
</div>
)}

View File

@@ -173,6 +173,24 @@ function SortableTariffCard({
{t('admin.tariffs.trial')}
</span>
)}
{tariff.show_in_gift && (
<span className="inline-flex items-center gap-1 rounded bg-purple-500/20 px-2 py-0.5 text-xs text-purple-400">
<svg
className="h-3 w-3"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M21 11.25v8.25a1.5 1.5 0 01-1.5 1.5H5.25a1.5 1.5 0 01-1.5-1.5v-8.25M12 4.875A2.625 2.625 0 109.375 7.5H12m0-2.625V7.5m0-2.625A2.625 2.625 0 1114.625 7.5H12m0 0V21m-8.625-9.75h18c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125h-18c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z"
/>
</svg>
{t('admin.tariffs.giftBadge')}
</span>
)}
{!tariff.is_active && (
<span className="rounded bg-dark-600 px-2 py-0.5 text-xs text-dark-400">
{t('admin.tariffs.inactive')}