import { useState, useEffect } from 'react';
import { useNavigate, useSearchParams } from 'react-router';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import {
campaignsApi,
CampaignCreateRequest,
CampaignBonusType,
ServerSquadInfo,
TariffListItem,
} from '../api/campaigns';
import { partnerApi } from '../api/partners';
import { AdminBackButton } from '../components/admin';
import { createNumberInputHandler, toNumber } from '../utils/inputHelpers';
import Twemoji from 'react-twemoji';
// Icons
const CampaignIcon = () => (
);
const CheckIcon = () => (
);
const RefreshIcon = () => (
);
// Bonus type config
const bonusTypeConfig: Record<
CampaignBonusType,
{ labelKey: string; color: string; bgColor: string; borderColor: string }
> = {
balance: {
labelKey: 'admin.campaigns.bonusType.balance',
color: 'text-success-400',
bgColor: 'bg-success-500/10',
borderColor: 'border-success-500/30',
},
subscription: {
labelKey: 'admin.campaigns.bonusType.subscription',
color: 'text-accent-400',
bgColor: 'bg-accent-500/10',
borderColor: 'border-accent-500/30',
},
tariff: {
labelKey: 'admin.campaigns.bonusType.tariff',
color: 'text-accent-400',
bgColor: 'bg-accent-500/10',
borderColor: 'border-accent-500/30',
},
none: {
labelKey: 'admin.campaigns.bonusType.none',
color: 'text-dark-400',
bgColor: 'bg-dark-500/10',
borderColor: 'border-dark-500/30',
},
};
// Server selector component
function ServerSelector({
servers,
selected,
onToggle,
}: {
servers: ServerSquadInfo[];
selected: string[];
onToggle: (uuid: string) => void;
}) {
const { t } = useTranslation();
if (servers.length === 0) return null;
return (
{servers.map((server) => (
))}
);
}
// Tariff selector component
function TariffSelector({
tariffs,
value,
onChange,
}: {
tariffs: TariffListItem[];
value: number | null;
onChange: (id: number | null) => void;
}) {
const { t } = useTranslation();
return (
);
}
function slugify(text: string): string {
return text
.toLowerCase()
.replace(/[^a-z0-9]+/gi, '_')
.replace(/^_|_$/g, '')
.slice(0, 30);
}
export default function AdminCampaignCreate() {
const { t } = useTranslation();
const navigate = useNavigate();
const queryClient = useQueryClient();
const [searchParams] = useSearchParams();
const partnerId = searchParams.get('partnerId');
// Fetch partner info if creating for a partner
const { data: partner } = useQuery({
queryKey: ['admin-partner-detail', partnerId],
queryFn: () => partnerApi.getPartnerDetail(Number(partnerId)),
enabled: !!partnerId,
});
// Form state
const [name, setName] = useState('');
const [startParameter, setStartParameter] = useState('');
const [bonusType, setBonusType] = useState('balance');
const [isActive, setIsActive] = useState(true);
// Auto-fill from partner
const [autoFilled, setAutoFilled] = useState(false);
useEffect(() => {
if (partner && !autoFilled) {
const partnerName = partner.first_name || partner.username || '';
if (!name && partnerName) setName(partnerName);
if (!startParameter && partnerName) setStartParameter(`partner_${slugify(partnerName)}`);
setAutoFilled(true);
}
}, [partner, autoFilled, name, startParameter]);
// Balance bonus
const [balanceBonusRubles, setBalanceBonusRubles] = useState(0);
// Subscription bonus
const [subscriptionDays, setSubscriptionDays] = useState(7);
const [subscriptionTraffic, setSubscriptionTraffic] = useState(10);
const [subscriptionDevices, setSubscriptionDevices] = useState(1);
const [selectedSquads, setSelectedSquads] = useState([]);
// Tariff bonus
const [tariffId, setTariffId] = useState(null);
const [tariffDays, setTariffDays] = useState(30);
// Fetch servers
const { data: servers = [] } = useQuery({
queryKey: ['admin-campaigns-servers'],
queryFn: () => campaignsApi.getAvailableServers(),
});
// Fetch tariffs
const { data: tariffs = [] } = useQuery({
queryKey: ['admin-campaigns-tariffs'],
queryFn: () => campaignsApi.getAvailableTariffs(),
});
// Create mutation
const createMutation = useMutation({
mutationFn: campaignsApi.createCampaign,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin-campaigns'] });
queryClient.invalidateQueries({ queryKey: ['admin-campaigns-overview'] });
if (partnerId) {
queryClient.invalidateQueries({ queryKey: ['admin-partner-detail', partnerId] });
navigate(`/admin/partners/${partnerId}`);
} else {
navigate('/admin/campaigns');
}
},
});
const toggleServer = (uuid: string) => {
setSelectedSquads((prev) =>
prev.includes(uuid) ? prev.filter((s) => s !== uuid) : [...prev, uuid],
);
};
const handleSubmit = () => {
const data: CampaignCreateRequest = {
name,
start_parameter: startParameter,
bonus_type: bonusType,
is_active: isActive,
};
if (bonusType === 'balance') {
data.balance_bonus_kopeks = Math.round(toNumber(balanceBonusRubles) * 100);
} else if (bonusType === 'subscription') {
data.subscription_duration_days = toNumber(subscriptionDays, 7);
data.subscription_traffic_gb = toNumber(subscriptionTraffic, 10);
data.subscription_device_limit = toNumber(subscriptionDevices, 1);
data.subscription_squads = selectedSquads;
} else if (bonusType === 'tariff') {
data.tariff_id = tariffId || undefined;
data.tariff_duration_days = toNumber(tariffDays, 30);
}
if (partnerId) {
data.partner_user_id = Number(partnerId);
}
createMutation.mutate(data);
};
const isNameValid = name.trim().length > 0;
const isStartParamValid =
startParameter.trim().length > 0 && /^[a-zA-Z0-9_-]+$/.test(startParameter);
const isValid = isNameValid && isStartParamValid;
return (
{/* Header */}
{t('admin.campaigns.modal.createTitle')}
{t('admin.campaigns.subtitle')}
{/* Partner info banner */}
{partnerId && partner && (
{t('admin.campaigns.form.partnerAutoAssign', {
name: partner.first_name || partner.username || `#${partnerId}`,
})}
)}
{/* Basic Info */}
{/* Name */}
setName(e.target.value)}
className={`input ${name.length > 0 && !isNameValid ? 'border-error-500/50' : ''}`}
placeholder={t('admin.campaigns.form.namePlaceholder')}
maxLength={255}
/>
{name.length > 0 && !isNameValid && (
{t('admin.campaigns.validation.nameRequired')}
)}
{/* Start Parameter */}
{/* Active toggle */}
{t('admin.campaigns.form.active')}
{/* Bonus Type */}
{t('admin.campaigns.form.bonusType')}
{(Object.keys(bonusTypeConfig) as CampaignBonusType[]).map((type) => (
))}
{/* Bonus Settings */}
{bonusType === 'balance' && (
)}
{bonusType === 'subscription' && (
{t('admin.campaigns.form.trialSubscription')}
)}
{bonusType === 'tariff' && (
)}
{bonusType === 'none' && (
{t('admin.campaigns.form.noBonusDescription')}
)}
{/* Footer */}
);
}