'use strict'; /* admin → shop section: items + purchases */ (function () { 'use strict'; let inited = false; let _shopItems = []; let _filterType = ''; let _search = ''; const TYPE_LABELS = { frame:'Рамка', title:'Титул', theme:'Тема', effect:'Эффект', background:'Фон' }; const TYPE_ICONS = { frame:'square', title:'award', background:'image', effect:'sparkles', theme:'palette' }; const typeCls = t => ['frame','title','background','effect'].includes(t) ? 't-' + t : 't-other'; const typeIcon = t => TYPE_ICONS[t] || 'tag'; async function load() { try { const [stats, items] = await Promise.all([ LS.adminShopStats(), LS.adminShopGetItems() ]); const topName = stats.topItems?.[0]?.name || '—'; const stat = (cls, icon, ic, val, label, sm) => `
${val} ${label}
`; document.getElementById('shop-stats-grid').innerHTML = stat('var(--violet)', 'shopping-bag', 'rgba(155,93,229,0.12)', `${stats.activeItems}/${stats.totalItems}`, 'товаров активно') + stat('var(--cyan)', 'receipt', 'rgba(6,214,224,0.12)', stats.totalPurchases, 'покупок') + stat('var(--green)', 'coins', 'rgba(6,214,100,0.12)', stats.totalCoinsInCirculation, 'монет в обороте') + stat('#d98a17', 'star', 'rgba(255,179,71,0.16)', esc(topName), 'топ-товар', true); _shopItems = items; renderShopItems(); if (window.lucide) lucide.createIcons(); } catch(e) { document.getElementById('shop-stats-grid').innerHTML = `
Ошибка: ${esc(e.message)}
`; } } function shopApplyFilters() { _filterType = document.getElementById('shop-filter-type')?.value || ''; _search = (document.getElementById('shop-search')?.value || '').trim().toLowerCase(); renderShopItems(); } function renderShopItems() { const body = document.getElementById('shop-items-body'); const countEl = document.getElementById('shop-count'); const filtered = _shopItems.filter(it => (!_filterType || it.type === _filterType) && (!_search || (it.name || '').toLowerCase().includes(_search)) ); if (countEl) countEl.textContent = filtered.length === _shopItems.length ? `${_shopItems.length} товаров` : `${filtered.length} из ${_shopItems.length}`; if (!_shopItems.length) { body.innerHTML = 'Нет товаров'; return; } if (!filtered.length) { body.innerHTML = 'Ничего не найдено'; return; } body.innerHTML = filtered.map(it => `
${esc(it.name)} ${it.description ? esc(it.description) : '#' + it.id}
${TYPE_LABELS[it.type] || esc(it.type)} ${it.price} ${it.sold_count || 0} `).join(''); if (window.lucide) lucide.createIcons(); } const TYPE_OPTIONS = [ { v: 'frame', l: 'Рамка' }, { v: 'title', l: 'Титул' }, { v: 'background', l: 'Фон' }, { v: 'effect', l: 'Эффект' }, ]; /* Open the add/edit item modal. item = null → create, object → edit. */ function openItemModal(item) { const isEdit = !!item; const dataStr = item && item.data ? (typeof item.data === 'string' ? item.data : JSON.stringify(item.data)) : ''; const body = document.createElement('div'); body.innerHTML = `
`; const $ = sel => body.querySelector(sel); $('#shop-f-name').value = item?.name || ''; $('#shop-f-type').value = item?.type || 'frame'; $('#shop-f-price').value = item?.price ?? 100; $('#shop-f-desc').value = item?.description || ''; $('#shop-f-icon').value = item?.icon || ''; $('#shop-f-data').value = dataStr; $('#shop-f-active').checked = item ? !!item.is_active : true; let saving = false; const m = LS.modal({ title: isEdit ? ('Редактировать товар #' + item.id) : 'Добавить товар', content: body, size: 'md', actions: [ { label: 'Отмена', onClick: () => m.close() }, { label: 'Сохранить', primary: true, id: 'shop-save-btn', onClick: async () => { if (saving) return; const payload = { name: $('#shop-f-name').value.trim(), type: $('#shop-f-type').value, price: parseInt($('#shop-f-price').value, 10) || 0, description: $('#shop-f-desc').value.trim(), icon: $('#shop-f-icon').value.trim(), data: $('#shop-f-data').value.trim() || null, is_active: $('#shop-f-active').checked ? 1 : 0, }; if (!payload.name) { m.setError('Введите название'); return; } if (payload.data) { try { JSON.parse(payload.data); } catch { m.setError('Поле «Данные» — некорректный JSON'); return; } } saving = true; const btn = document.getElementById('shop-save-btn'); if (btn) { btn.disabled = true; btn.textContent = 'Сохранение…'; } try { if (isEdit) { await LS.adminShopUpdateItem(item.id, payload); LS.toast('Товар обновлён', 'success'); } else { await LS.adminShopCreateItem(payload); LS.toast('Товар создан', 'success'); } m.close(); inited = false; await load(); inited = true; } catch(e) { m.setError('Ошибка: ' + e.message); saving = false; if (btn) { btn.disabled = false; btn.textContent = 'Сохранить'; } } } }, ], }); setTimeout(() => $('#shop-f-name')?.focus(), 80); } function shopAdminCreateItem() { openItemModal(null); } function shopAdminEditItem(id) { const it = _shopItems.find(i => i.id === id); if (it) openItemModal(it); } 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'); } } // Expose onclick handlers window.shopAdminCreateItem = shopAdminCreateItem; window.shopAdminEditItem = shopAdminEditItem; window.shopAdminDeleteItem = shopAdminDeleteItem; window.shopAdminToggleActive = shopAdminToggleActive; window.shopApplyFilters = shopApplyFilters; window.AdminSections = window.AdminSections || {}; window.AdminSections.shop = { init: async () => { if (inited) return; inited = true; await load(); }, reload: load, }; })();