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 */}
setStartParameter(e.target.value.replace(/[^a-zA-Z0-9_-]/g, ''))} className={`input font-mono ${startParameter.length > 0 && !isStartParamValid ? 'border-error-500/50' : ''}`} placeholder="instagram_jan2024" maxLength={100} />

{t('admin.campaigns.form.startParameterHint')}

{/* 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' && (

{t('admin.campaigns.form.balanceBonus')}

)} {bonusType === 'subscription' && (

{t('admin.campaigns.form.trialSubscription')}

)} {bonusType === 'tariff' && (

{t('admin.campaigns.form.tariff')}

)} {bonusType === 'none' && (

{t('admin.campaigns.form.noBonusDescription')}

)} {/* Footer */}
); }