/* ===== Администрирование пяти модулей Лиги ===== */
const LA_MODULES={
'league-rating':{title:'Рейтинг и баллы',subtitle:'Баланс, уровни и неизменяемый журнал операций.',icon:'trophy'},
'league-infrastructure':{title:'Инфраструктура',subtitle:'Трассы, слоты, бронирования и ремонтная мастерская.',icon:'pin'},
'league-discounts':{title:'Скидки и привилегии',subtitle:'Партнёры, промокоды и предложения магазина Лиги.',icon:'star'},
'league-pilots':{title:'Карточки пилотов',subtitle:'Профили, полёты, оборудование и достижения.',icon:'award'},
'league-support':{title:'Техническая поддержка',subtitle:'Telegram, быстрые решения и обращения участников.',icon:'wrench'},
};
const LA_LABELS={pending:'Ожидает',confirmed:'Подтверждено',cancelled:'Отменено',completed:'Завершено',no_show:'Неявка',new:'Новое',diagnostics:'Диагностика',approval:'Согласование',repairing:'В ремонте',ready:'Готово',issued:'Выдано',accepted:'Принято',working:'В работе',waiting_user:'Ожидает пользователя',workshop:'В мастерской',resolved:'Решено',closed:'Закрыто'};
async function laFetch(payload){
const url=payload?'api/league.php':`api/league.php?mode=admin&_=${Date.now()}`;
const res=await fetch(url,{credentials:'same-origin',cache:'no-store',...(payload?{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)}:{})});
const d=await res.json().catch(()=>({ok:false,error:'Пустой ответ'}));if(!res.ok||d.ok===false)throw new Error(d.error||`HTTP ${res.status}`);return d;
}
function laHeadStats(module,data){
if(!data)return [];
if(module==='league-rating')return [
{icon:'users',value:data.users?.length||0,label:'участников'},
{icon:'history',value:data.transactions?.length||0,label:'операций'},
{icon:'award',value:data.levels?.length||0,label:'уровней'},
];
if(module==='league-infrastructure')return [
{icon:'flag',value:(data.tracks||[]).filter(x=>Number(x.active)).length,label:'активных трасс'},
{icon:'calendar',value:(data.bookings||[]).filter(x=>['pending','confirmed'].includes(x.status)).length,label:'активных броней'},
{icon:'wrench',value:(data.repairs||[]).filter(x=>!['issued','cancelled'].includes(x.status)).length,label:'заявок в работе'},
];
if(module==='league-discounts')return [
{icon:'users',value:(data.partners||[]).filter(x=>Number(x.active)).length,label:'партнёров'},
{icon:'star',value:(data.offers||[]).filter(x=>Number(x.active)).length,label:'предложений'},
{icon:'checkCircle',value:(data.offers||[]).reduce((sum,x)=>sum+Number(x.usageCount||0),0),label:'использований'},
];
if(module==='league-pilots')return [
{icon:'award',value:data.profiles?.length||0,label:'карточек'},
{icon:'drone',value:data.flights?.length||0,label:'полётов'},
{icon:'trophy',value:data.achievements?.length||0,label:'достижений'},
];
return [
{icon:'mail',value:(data.tickets||[]).filter(x=>!['resolved','closed'].includes(x.status)).length,label:'открытых обращений'},
{icon:'zap',value:(data.tickets||[]).filter(x=>x.priority==='urgent'&&!['resolved','closed'].includes(x.status)).length,label:'срочных'},
{icon:'doc',value:(data.articles||[]).filter(x=>Number(x.active)).length,label:'решений'},
];
}
function LAHead({module,onReload,busy,data}){
const m=LA_MODULES[module],stats=laHeadStats(module,data);
return
Лига Дронов · Control Center
{m.title}
{m.subtitle}
{stats.length>0&&
{stats.map((item,index)=>
{item.value}{item.label}
)}
};
}
function LASection({title,subtitle='',actions,children}){return
{title}
{subtitle&&
{subtitle}
}
{actions}
{children};}
function LAStatusSelect({value,options,onChange,busy}){return ;}
function LAEmpty(){return
Записей пока нет.
;}
function LAFormModal({title,fields,draft,setDraft,onSave,onClose,busy}){
async function file(field,file){if(!file)return;try{const path=await uploadAdminFile(file);setDraft({...draft,[field.key]:field.array?[path]:path});}catch(e){alert(e.message);}}
return
e.stopPropagation()}>
{title}
{fields.map(f=>
{f.type==='textarea'?
)}
;
}
function AdminLeague({module}){
const [data,setData]=useState(null),[loading,setLoading]=useState(true),[message,setMessage]=useState(''),[busy,setBusy]=useState(false),[modal,setModal]=useState(null);
async function load(clearMessage=true){setLoading(true);if(clearMessage)setMessage('');try{setData((await laFetch()).data);return true;}catch(e){setMessage(e.message);return false;}finally{setLoading(false);}}
useEffect(()=>{load();},[module]);
async function action(payload,ok='Изменения сохранены.'){setBusy(true);setMessage('');try{await laFetch(payload);setModal(null);const reloaded=await load(false);if(reloaded)setMessage(ok);return reloaded;}catch(e){setMessage(e.message);return false;}finally{setBusy(false);}}
if(loading&&!data)return
;
}
function LARating({data,action,busy,modal,setModal}){
const [points,setPoints]=useState({userId:'',points:'',reason:'',activityType:'manual'}),[filter,setFilter]=useState(''),[formError,setFormError]=useState('');
const members=data.users.filter(u=>u.role==='user');
const rows=data.transactions.filter(x=>!filter||String(x.userName||'').toLowerCase().includes(filter.toLowerCase()));
async function savePoints(){
if(!points.userId){setFormError('Выберите пилота из списка участников Лиги.');return;}
if(!Number(points.points)){setFormError('Укажите количество баллов — положительное для начисления или отрицательное для списания.');return;}
if(!String(points.reason||'').trim()){setFormError('Заполните поле «Обязательное основание». Без комментария баллы не начисляются.');return;}
setFormError('');
const saved=await action({action:'points',...points},'Баллы начислены, журнал и баланс обновлены.');
if(saved)setPoints({userId:points.userId,points:'',reason:'',activityType:'manual'});
}
function csv(){const body=[['Дата','Пилот','Баллы','Баланс','Основание','Администратор'],...rows.map(x=>[x.created_at,x.userName,x.points,x.balance_after,x.reason,x.actor_name])].map(r=>r.map(v=>`"${String(v??'').replaceAll('"','""')}"`).join(';')).join('\n');const a=document.createElement('a');a.href=URL.createObjectURL(new Blob(['\ufeff'+body],{type:'text/csv'}));a.download='league-rating.csv';a.click();URL.revokeObjectURL(a.href);}
return <>