import { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useTranslation } from 'react-i18next';
import {
campaignsApi,
CampaignUpdateRequest,
CampaignBonusType,
ServerSquadInfo,
TariffListItem,
AvailablePartner,
} from '../api/campaigns';
import { AdminBackButton } from '../components/admin';
import { CheckIcon, CampaignIcon } from '../components/icons';
import { createNumberInputHandler, toNumber } from '../utils/inputHelpers';
// 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 (
);
}
// Partner selector component
function PartnerSelector({
partners,
value,
onChange,
}: {
partners: AvailablePartner[];
value: number | null;
onChange: (id: number | null) => void;
}) {
const { t } = useTranslation();
return (
);
}
export default function AdminCampaignEdit() {
const { t } = useTranslation();
const { id } = useParams<{ id: string }>();
const navigate = useNavigate();
const queryClient = useQueryClient();
const campaignId = parseInt(id || '0');
// Fetch campaign
const {
data: campaign,
isLoading,
error,
} = useQuery({
queryKey: ['admin-campaign', campaignId],
queryFn: () => campaignsApi.getCampaign(campaignId),
enabled: campaignId > 0,
});
// 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(),
});
// Fetch partners
const { data: partners = [] } = useQuery({
queryKey: ['admin-campaigns-partners'],
queryFn: () => campaignsApi.getAvailablePartners(),
});
// Form state
const [name, setName] = useState('');
const [startParameter, setStartParameter] = useState('');
const [bonusType, setBonusType] = useState('balance');
const [isActive, setIsActive] = useState(true);
// 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);
// Partner
const [partnerUserId, setPartnerUserId] = useState(null);
const [initialPartnerUserId, setInitialPartnerUserId] = useState(null);
// Initialize form when campaign loads
useEffect(() => {
if (campaign) {
setName(campaign.name || '');
setStartParameter(campaign.start_parameter || '');
setBonusType(campaign.bonus_type || 'balance');
setIsActive(campaign.is_active ?? true);
setBalanceBonusRubles((campaign.balance_bonus_kopeks || 0) / 100);
setSubscriptionDays(campaign.subscription_duration_days || 7);
setSubscriptionTraffic(campaign.subscription_traffic_gb || 10);
setSubscriptionDevices(campaign.subscription_device_limit || 1);
setSelectedSquads(campaign.subscription_squads || []);
setTariffId(campaign.tariff_id || null);
setTariffDays(campaign.tariff_duration_days || 30);
setPartnerUserId(campaign.partner_user_id ?? null);
setInitialPartnerUserId(campaign.partner_user_id ?? null);
}
}, [campaign]);
// Update mutation
const updateMutation = useMutation({
mutationFn: (data: CampaignUpdateRequest) => campaignsApi.updateCampaign(campaignId, data),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['admin-campaigns'] });
queryClient.invalidateQueries({ queryKey: ['admin-campaign', campaignId] });
navigate('/admin/campaigns');
},
});
const toggleServer = (uuid: string) => {
setSelectedSquads((prev) =>
prev.includes(uuid) ? prev.filter((s) => s !== uuid) : [...prev, uuid],
);
};
const handleSubmit = () => {
const data: CampaignUpdateRequest = {
name,
start_parameter: startParameter,
bonus_type: bonusType,
is_active: isActive,
};
// Only send partner_user_id when it was actually changed
if (partnerUserId !== initialPartnerUserId) {
data.partner_user_id = partnerUserId;
}
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);
}
updateMutation.mutate(data);
};
const isNameValid = name.trim().length > 0;
const isStartParamValid =
startParameter.trim().length > 0 && /^[a-zA-Z0-9_-]+$/.test(startParameter);
const isValid = isNameValid && isStartParamValid;
if (isLoading) {
return (
);
}
if (error || !campaign) {
return (
{t('admin.campaigns.modal.editTitle')}
{t('admin.campaigns.loadError')}
);
}
return (
{/* Header */}
{t('admin.campaigns.modal.editTitle')}
{campaign.name}
{/* 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')}
{/* Partner */}
{partners.length > 0 && (
)}
{/* 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 */}
{updateMutation.isError && (
{t('admin.campaigns.updateError')}
)}
);
}