'use strict'; /* admin → shop section: items + purchases + award coins */ (function () { 'use strict'; let inited = false; let _shopItems = []; let _shopEditId = null; let _shopSaving = false; let _shopSearchTimer = null; let _coinsAwarding = false; async function load() { try { const [stats, items] = await Promise.all([ LS.adminShopStats(), LS.adminShopGetItems() ]); const topName = stats.topItems?.[0]?.name || '—'; document.getElementById('shop-stats-grid').innerHTML = `
${stats.activeItems}/${stats.totalItems}
Товаров
${stats.totalPurchases}
Покупок
${stats.totalCoinsInCirculation}
Монет в обороте
${esc(topName)}
Топ товар
`; _shopItems = items; renderShopItems(); if (window.lucide) lucide.createIcons(); } catch(e) { document.getElementById('shop-stats-grid').innerHTML = `
Ошибка: ${esc(e.message)}
`; } } function renderShopItems() { const body = document.getElementById('shop-items-body'); if (!_shopItems.length) { body.innerHTML = 'Нет товаров'; return; } const typeLabels = { frame:'Рамка', title:'Титул', theme:'Тема', effect:'Эффект' }; body.innerHTML = _shopItems.map(it => ` ${it.id} ${esc(it.name)} ${typeLabels[it.type] || esc(it.type)} ${it.price} ${it.sold_count || 0} `).join(''); if (window.lucide) lucide.createIcons(); } function shopAdminCreateItem() { _shopEditId = null; document.getElementById('shop-form-title').textContent = 'Добавить товар'; document.getElementById('shop-f-name').value = ''; document.getElementById('shop-f-type').value = 'frame'; document.getElementById('shop-f-price').value = '100'; document.getElementById('shop-f-desc').value = ''; document.getElementById('shop-f-icon').value = ''; document.getElementById('shop-f-data').value = ''; document.getElementById('shop-f-active').checked = true; document.getElementById('shop-item-form').style.display = ''; } function shopAdminEditItem(id) { const it = _shopItems.find(i => i.id === id); if (!it) return; _shopEditId = id; document.getElementById('shop-form-title').textContent = 'Редактировать товар #' + id; document.getElementById('shop-f-name').value = it.name || ''; document.getElementById('shop-f-type').value = it.type || 'frame'; document.getElementById('shop-f-price').value = it.price ?? 100; document.getElementById('shop-f-desc').value = it.description || ''; document.getElementById('shop-f-icon').value = it.icon || ''; document.getElementById('shop-f-data').value = it.data ? (typeof it.data === 'string' ? it.data : JSON.stringify(it.data)) : ''; document.getElementById('shop-f-active').checked = !!it.is_active; document.getElementById('shop-item-form').style.display = ''; } function shopAdminCancelForm() { document.getElementById('shop-item-form').style.display = 'none'; _shopEditId = null; } async function shopAdminSaveItem() { if (_shopSaving) return; _shopSaving = true; const data = { name: document.getElementById('shop-f-name').value.trim(), type: document.getElementById('shop-f-type').value, price: parseInt(document.getElementById('shop-f-price').value) || 0, description: document.getElementById('shop-f-desc').value.trim(), icon: document.getElementById('shop-f-icon').value.trim(), data: document.getElementById('shop-f-data').value.trim() || null, is_active: document.getElementById('shop-f-active').checked ? 1 : 0 }; if (!data.name) { LS.toast('Введите название', 'error'); _shopSaving = false; return; } try { if (_shopEditId) { await LS.adminShopUpdateItem(_shopEditId, data); LS.toast('Товар обновлён', 'success'); } else { await LS.adminShopCreateItem(data); LS.toast('Товар создан', 'success'); } shopAdminCancelForm(); inited = false; await load(); inited = true; } catch(e) { LS.toast('Ошибка: ' + e.message, 'error'); } finally { _shopSaving = false; } } async function shopAdminDeleteItem(id) { if (!await LS.confirm('Все покупки этого товара будут удалены.', { title: 'Удалить товар?', confirmText: 'Удалить', danger: true })) return; try { await LS.adminShopDeleteItem(id); LS.toast('Товар удалён', 'success'); inited = false; await load(); inited = true; } catch(e) { LS.toast('Ошибка: ' + e.message, 'error'); } } async function shopAdminToggleActive(id, active) { try { await LS.adminShopUpdateItem(id, { is_active: active ? 1 : 0 }); LS.toast(active ? 'Товар активирован' : 'Товар деактивирован', 'success'); } catch(e) { LS.toast('Ошибка: ' + e.message, 'error'); } } async function shopSearchUser(q) { clearTimeout(_shopSearchTimer); const box = document.getElementById('shop-award-results'); if (q.length < 2) { box.classList.remove('open'); return; } _shopSearchTimer = setTimeout(async () => { try { const r = await LS.adminGetUsers({ q, limit: 8 }); const label = u => u.name || u.email; box.innerHTML = (r.users || []).map(u => `
${esc(label(u))}${esc(u.role)}
`).join('') || '
Не найдено
'; box.classList.add('open'); } catch(e) { box.classList.remove('open'); } }, 300); } function shopPickUser(el) { document.getElementById('shop-award-uid').value = el.dataset.uid; document.getElementById('shop-award-user').value = el.dataset.name || ''; document.getElementById('shop-award-results').classList.remove('open'); } async function shopAdminAwardCoins() { if (_coinsAwarding) return; const userId = parseInt(document.getElementById('shop-award-uid').value); const amount = parseInt(document.getElementById('shop-award-amount').value); const reason = document.getElementById('shop-award-reason').value.trim(); if (!userId) { LS.toast('Выберите пользователя', 'error'); return; } if (!amount || amount <= 0) { LS.toast('Введите количество монет', 'error'); return; } _coinsAwarding = true; try { const r = await LS.adminShopAwardCoins({ userId, amount, reason }); LS.toast(`Начислено ${amount} монет. Баланс: ${r.coins}`, 'success'); document.getElementById('shop-award-uid').value = ''; document.getElementById('shop-award-user').value = ''; document.getElementById('shop-award-reason').value = ''; } catch(e) { LS.toast('Ошибка: ' + e.message, 'error'); } finally { _coinsAwarding = false; } } // Expose onclick handlers window.shopAdminCreateItem = shopAdminCreateItem; window.shopAdminEditItem = shopAdminEditItem; window.shopAdminCancelForm = shopAdminCancelForm; window.shopAdminSaveItem = shopAdminSaveItem; window.shopAdminDeleteItem = shopAdminDeleteItem; window.shopAdminToggleActive = shopAdminToggleActive; window.shopSearchUser = shopSearchUser; window.shopPickUser = shopPickUser; window.shopAdminAwardCoins = shopAdminAwardCoins; window.AdminSections = window.AdminSections || {}; window.AdminSections.shop = { init: async () => { if (inited) return; inited = true; await load(); }, reload: load, }; })();