Add Orders and Order Status repositories with pagination and management features
- Implemented OrdersRepository for handling order data with pagination, filtering, and sorting capabilities. - Added methods for retrieving order status options, quick stats, and detailed order information. - Created OrderStatusRepository for managing order status groups and statuses, including CRUD operations and sorting. - Introduced a bootstrap file for test environment setup and autoloading.
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
<?php $rows = is_array($integrations ?? null) ? $integrations : []; ?>
|
||||
|
||||
<section class="card">
|
||||
<h1><?= $e($t('marketplace.title')) ?></h1>
|
||||
<p class="muted"><?= $e($t('marketplace.description')) ?></p>
|
||||
</section>
|
||||
|
||||
<section class="card mt-16">
|
||||
<h2 class="section-title"><?= $e($t('marketplace.integrations_title')) ?></h2>
|
||||
|
||||
<?php if (!empty($errorMessage)): ?>
|
||||
<div class="alert alert--danger mt-12" role="alert"><?= $e((string) $errorMessage) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($rows === []): ?>
|
||||
<p class="muted mt-12"><?= $e($t('marketplace.empty_integrations')) ?></p>
|
||||
<?php else: ?>
|
||||
<div class="table-wrap mt-12">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th><?= $e($t('marketplace.fields.integration')) ?></th>
|
||||
<th><?= $e($t('marketplace.fields.linked_offers_count')) ?></th>
|
||||
<th><?= $e($t('marketplace.fields.actions')) ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $row): ?>
|
||||
<?php $integrationId = (int) ($row['id'] ?? 0); ?>
|
||||
<tr>
|
||||
<td><?= $e((string) $integrationId) ?></td>
|
||||
<td><?= $e((string) ($row['name'] ?? '')) ?></td>
|
||||
<td><?= $e((string) ((int) ($row['linked_offers_count'] ?? 0))) ?></td>
|
||||
<td>
|
||||
<a class="btn btn--secondary" href="/marketplace/<?= $e((string) $integrationId) ?>">
|
||||
<?= $e($t('marketplace.actions.open_offers')) ?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,406 @@
|
||||
<?php $integrationData = is_array($integration ?? null) ? $integration : []; ?>
|
||||
<?php $rows = is_array($offers ?? null) ? $offers : []; ?>
|
||||
<?php $integrationId = (int) ($integrationData['id'] ?? 0); ?>
|
||||
<?php $filters = is_array($filters ?? null) ? $filters : []; ?>
|
||||
<?php $channelOptions = is_array($channelOptions ?? null) ? $channelOptions : []; ?>
|
||||
<?php $pagination = is_array($pagination ?? null) ? $pagination : []; ?>
|
||||
<?php
|
||||
$currentSort = (string) ($filters['sort'] ?? 'updated_at');
|
||||
$currentDir = strtoupper((string) ($filters['sort_dir'] ?? 'DESC')) === 'ASC' ? 'ASC' : 'DESC';
|
||||
$page = max(1, (int) ($pagination['page'] ?? 1));
|
||||
$totalPages = max(1, (int) ($pagination['total_pages'] ?? 1));
|
||||
$total = max(0, (int) ($pagination['total'] ?? count($rows)));
|
||||
$perPage = max(1, (int) ($pagination['per_page'] ?? 20));
|
||||
$buildUrl = static function (array $params = []) use ($integrationId, $filters): string {
|
||||
$merged = array_merge($filters, $params);
|
||||
foreach ($merged as $key => $value) {
|
||||
if ($value === '' || $value === null) {
|
||||
unset($merged[$key]);
|
||||
}
|
||||
}
|
||||
$query = http_build_query($merged);
|
||||
$base = '/marketplace/' . $integrationId;
|
||||
return $query !== '' ? ($base . '?' . $query) : $base;
|
||||
};
|
||||
?>
|
||||
|
||||
<section class="card">
|
||||
<h1><?= $e($t('marketplace.offers_title', ['name' => (string) ($integrationData['name'] ?? '')])) ?></h1>
|
||||
<p class="muted"><?= $e($t('marketplace.offers_description')) ?></p>
|
||||
</section>
|
||||
|
||||
<section class="card mt-16">
|
||||
<a class="btn btn--secondary" href="/marketplace"><?= $e($t('marketplace.actions.back_to_marketplace')) ?></a>
|
||||
|
||||
<?php if (!empty($errorMessage)): ?>
|
||||
<div class="alert alert--danger mt-12" role="alert"><?= $e((string) $errorMessage) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($successMessage)): ?>
|
||||
<div class="alert alert--success mt-12" role="status"><?= $e((string) $successMessage) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="get" action="/marketplace/<?= $e((string) $integrationId) ?>" class="table-list-filters mt-12">
|
||||
<label class="form-field">
|
||||
<span class="field-label"><?= $e($t('products.filters.search')) ?></span>
|
||||
<input class="form-control" type="text" name="search" value="<?= $e((string) ($filters['search'] ?? '')) ?>" placeholder="Oferta, SKU, EAN, external ID">
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span class="field-label"><?= $e($t('marketplace.fields.channel')) ?></span>
|
||||
<select class="form-control" name="channel">
|
||||
<option value=""><?= $e($t('products.filters.any')) ?></option>
|
||||
<?php foreach ($channelOptions as $channelName): ?>
|
||||
<option value="<?= $e((string) $channelName) ?>"<?= (string) ($filters['channel'] ?? '') === (string) $channelName ? ' selected' : '' ?>>
|
||||
<?= $e((string) $channelName) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
<label class="form-field">
|
||||
<span class="field-label"><?= $e($t('products.filters.per_page')) ?></span>
|
||||
<select class="form-control" name="per_page">
|
||||
<?php foreach ([10, 20, 50, 100] as $opt): ?>
|
||||
<option value="<?= $e((string) $opt) ?>"<?= $perPage === $opt ? ' selected' : '' ?>><?= $e((string) $opt) ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</label>
|
||||
<input type="hidden" name="sort" value="<?= $e((string) ($filters['sort'] ?? 'updated_at')) ?>">
|
||||
<input type="hidden" name="sort_dir" value="<?= $e((string) ($filters['sort_dir'] ?? 'DESC')) ?>">
|
||||
<input type="hidden" name="page" value="1">
|
||||
<div class="filters-actions">
|
||||
<button class="btn btn--primary" type="submit"><?= $e($t('products.actions.filter')) ?></button>
|
||||
<a class="btn btn--secondary" href="/marketplace/<?= $e((string) $integrationId) ?>"><?= $e($t('products.actions.reset')) ?></a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="muted mt-12"><?= $e($t('products.pagination.summary', ['total' => (string) $total])) ?></p>
|
||||
|
||||
<?php if ($rows === []): ?>
|
||||
<p class="muted mt-12"><?= $e($t('marketplace.empty_offers')) ?></p>
|
||||
<?php else: ?>
|
||||
<div class="table-wrap mt-12">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<a href="<?= $e($buildUrl(['sort' => 'offer_name', 'sort_dir' => ($currentSort === 'offer_name' && $currentDir === 'ASC') ? 'DESC' : 'ASC', 'page' => 1])) ?>" class="table-sort-link">
|
||||
<?= $e($t('marketplace.fields.offer_name')) ?><?= $currentSort === 'offer_name' ? ($currentDir === 'ASC' ? ' ↑' : ' ↓') : '' ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a href="<?= $e($buildUrl(['sort' => 'external_product_id', 'sort_dir' => ($currentSort === 'external_product_id' && $currentDir === 'ASC') ? 'DESC' : 'ASC', 'page' => 1])) ?>" class="table-sort-link">
|
||||
<?= $e($t('marketplace.fields.external_product_id')) ?><?= $currentSort === 'external_product_id' ? ($currentDir === 'ASC' ? ' ↑' : ' ↓') : '' ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a href="<?= $e($buildUrl(['sort' => 'external_variant_id', 'sort_dir' => ($currentSort === 'external_variant_id' && $currentDir === 'ASC') ? 'DESC' : 'ASC', 'page' => 1])) ?>" class="table-sort-link">
|
||||
<?= $e($t('marketplace.fields.external_variant_id')) ?><?= $currentSort === 'external_variant_id' ? ($currentDir === 'ASC' ? ' ↑' : ' ↓') : '' ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a href="<?= $e($buildUrl(['sort' => 'external_offer_id', 'sort_dir' => ($currentSort === 'external_offer_id' && $currentDir === 'ASC') ? 'DESC' : 'ASC', 'page' => 1])) ?>" class="table-sort-link">
|
||||
<?= $e($t('marketplace.fields.external_offer_id')) ?><?= $currentSort === 'external_offer_id' ? ($currentDir === 'ASC' ? ' ↑' : ' ↓') : '' ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a href="<?= $e($buildUrl(['sort' => 'channel_name', 'sort_dir' => ($currentSort === 'channel_name' && $currentDir === 'ASC') ? 'DESC' : 'ASC', 'page' => 1])) ?>" class="table-sort-link">
|
||||
<?= $e($t('marketplace.fields.channel')) ?><?= $currentSort === 'channel_name' ? ($currentDir === 'ASC' ? ' ↑' : ' ↓') : '' ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a href="<?= $e($buildUrl(['sort' => 'product_name', 'sort_dir' => ($currentSort === 'product_name' && $currentDir === 'ASC') ? 'DESC' : 'ASC', 'page' => 1])) ?>" class="table-sort-link">
|
||||
<?= $e($t('marketplace.fields.product')) ?><?= $currentSort === 'product_name' ? ($currentDir === 'ASC' ? ' ↑' : ' ↓') : '' ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a href="<?= $e($buildUrl(['sort' => 'product_sku', 'sort_dir' => ($currentSort === 'product_sku' && $currentDir === 'ASC') ? 'DESC' : 'ASC', 'page' => 1])) ?>" class="table-sort-link">
|
||||
SKU<?= $currentSort === 'product_sku' ? ($currentDir === 'ASC' ? ' ↑' : ' ↓') : '' ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a href="<?= $e($buildUrl(['sort' => 'product_ean', 'sort_dir' => ($currentSort === 'product_ean' && $currentDir === 'ASC') ? 'DESC' : 'ASC', 'page' => 1])) ?>" class="table-sort-link">
|
||||
EAN<?= $currentSort === 'product_ean' ? ($currentDir === 'ASC' ? ' ↑' : ' ↓') : '' ?>
|
||||
</a>
|
||||
</th>
|
||||
<th>
|
||||
<a href="<?= $e($buildUrl(['sort' => 'updated_at', 'sort_dir' => ($currentSort === 'updated_at' && $currentDir === 'ASC') ? 'DESC' : 'ASC', 'page' => 1])) ?>" class="table-sort-link">
|
||||
<?= $e($t('marketplace.fields.updated_at')) ?><?= $currentSort === 'updated_at' ? ($currentDir === 'ASC' ? ' ↑' : ' ↓') : '' ?>
|
||||
</a>
|
||||
</th>
|
||||
<th><?= $e($t('marketplace.fields.actions')) ?></th>
|
||||
<th>Kategorie</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($rows as $row): ?>
|
||||
<?php $productId = (int) ($row['product_id'] ?? 0); ?>
|
||||
<?php $externalProductId = (int) ($row['external_product_id'] ?? 0); ?>
|
||||
<tr>
|
||||
<td><?= $e(trim((string) ($row['offer_name'] ?? '')) !== '' ? (string) ($row['offer_name'] ?? '') : '-') ?></td>
|
||||
<td><?= $e((string) ($row['external_product_id'] ?? '')) ?></td>
|
||||
<td><?= $e((string) ($row['external_variant_id'] ?? '')) ?></td>
|
||||
<td><?= $e((string) ($row['external_offer_id'] ?? '')) ?></td>
|
||||
<td><?= $e((string) ($row['channel_name'] ?? '')) ?></td>
|
||||
<td>
|
||||
<a href="/products/<?= $e((string) $productId) ?>">
|
||||
<?= $e((string) ($row['product_name'] ?? '')) ?>
|
||||
</a>
|
||||
</td>
|
||||
<td><?= $e((string) ($row['product_sku'] ?? '')) ?></td>
|
||||
<td><?= $e((string) ($row['product_ean'] ?? '')) ?></td>
|
||||
<td><?= $e((string) ($row['updated_at'] ?? '')) ?></td>
|
||||
<td>
|
||||
<?php if ($externalProductId > 0): ?>
|
||||
<a
|
||||
class="btn btn--secondary btn--sm"
|
||||
href="/marketplace/<?= $e((string) $integrationId) ?>/product/<?= $e((string) $externalProductId) ?>/edit"
|
||||
><?= $e($t('marketplace.actions.edit_offer')) ?></a>
|
||||
<?php else: ?>
|
||||
<span class="muted">-</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn--secondary btn--sm js-assign-categories"
|
||||
data-integration-id="<?= $e((string) $integrationId) ?>"
|
||||
data-product-id="<?= $e((string) ($row['external_product_id'] ?? '')) ?>"
|
||||
>Przypisz kategorie</button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="table-list__footer mt-12">
|
||||
<div class="pagination">
|
||||
<?php $startPage = max(1, $page - 2); ?>
|
||||
<?php $endPage = min($totalPages, $page + 2); ?>
|
||||
|
||||
<a class="pagination__item<?= $page <= 1 ? ' is-disabled' : '' ?>" href="<?= $e($buildUrl(['page' => 1])) ?>">«</a>
|
||||
<a class="pagination__item<?= $page <= 1 ? ' is-disabled' : '' ?>" href="<?= $e($buildUrl(['page' => max(1, $page - 1)])) ?>">‹</a>
|
||||
|
||||
<?php for ($i = $startPage; $i <= $endPage; $i++): ?>
|
||||
<a class="pagination__item<?= $i === $page ? ' is-active' : '' ?>" href="<?= $e($buildUrl(['page' => $i])) ?>">
|
||||
<?= $e((string) $i) ?>
|
||||
</a>
|
||||
<?php endfor; ?>
|
||||
|
||||
<a class="pagination__item<?= $page >= $totalPages ? ' is-disabled' : '' ?>" href="<?= $e($buildUrl(['page' => min($totalPages, $page + 1)])) ?>">›</a>
|
||||
<a class="pagination__item<?= $page >= $totalPages ? ' is-disabled' : '' ?>" href="<?= $e($buildUrl(['page' => $totalPages])) ?>">»</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<!-- Modal: przypisywanie kategorii shopPRO -->
|
||||
<div id="cat-modal-backdrop" class="jq-alert-modal-backdrop" style="display:none" aria-hidden="true">
|
||||
<div class="jq-alert-modal" role="dialog" aria-modal="true" aria-labelledby="cat-modal-title" style="max-width:520px;width:100%">
|
||||
<div class="jq-alert-modal__header">
|
||||
<h3 id="cat-modal-title">Przypisz kategorie</h3>
|
||||
</div>
|
||||
<div class="jq-alert-modal__body" style="max-height:420px;overflow-y:auto">
|
||||
<div id="cat-modal-loading">Ładowanie kategorii...</div>
|
||||
<div id="cat-modal-error" class="alert alert--danger" style="display:none"></div>
|
||||
<div id="cat-modal-tree" style="display:none"></div>
|
||||
</div>
|
||||
<div class="jq-alert-modal__footer">
|
||||
<button type="button" class="btn btn--secondary" id="cat-modal-cancel">Anuluj</button>
|
||||
<button type="button" class="btn btn--primary" id="cat-modal-save" style="display:none">Zapisz</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var CSRF = <?= json_encode($csrfToken ?? '') ?>;
|
||||
var backdrop = document.getElementById('cat-modal-backdrop');
|
||||
var treeEl = document.getElementById('cat-modal-tree');
|
||||
var loadingEl = document.getElementById('cat-modal-loading');
|
||||
var errorEl = document.getElementById('cat-modal-error');
|
||||
var saveBtn = document.getElementById('cat-modal-save');
|
||||
var cancelBtn = document.getElementById('cat-modal-cancel');
|
||||
|
||||
var state = { integrationId: 0, productId: 0, cachedCategories: null, cachedIntegrationId: 0 };
|
||||
|
||||
// Open modal on button click
|
||||
document.addEventListener('click', function (e) {
|
||||
var btn = e.target.closest('.js-assign-categories');
|
||||
if (!btn) return;
|
||||
state.integrationId = parseInt(btn.dataset.integrationId, 10) || 0;
|
||||
state.productId = parseInt(btn.dataset.productId, 10) || 0;
|
||||
if (state.integrationId <= 0 || state.productId <= 0) return;
|
||||
openModal();
|
||||
loadData();
|
||||
});
|
||||
|
||||
function openModal() {
|
||||
backdrop.style.display = '';
|
||||
backdrop.getBoundingClientRect(); // force reflow so CSS transition fires
|
||||
backdrop.setAttribute('aria-hidden', 'false');
|
||||
backdrop.classList.add('is-visible');
|
||||
loadingEl.style.display = '';
|
||||
treeEl.style.display = 'none';
|
||||
errorEl.style.display = 'none';
|
||||
saveBtn.style.display = 'none';
|
||||
treeEl.innerHTML = '';
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
backdrop.classList.remove('is-visible');
|
||||
backdrop.style.display = 'none';
|
||||
backdrop.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
|
||||
cancelBtn.addEventListener('click', closeModal);
|
||||
backdrop.addEventListener('click', function (e) { if (e.target === backdrop) closeModal(); });
|
||||
document.addEventListener('keydown', function (e) {
|
||||
if (e.key === 'Escape' && backdrop.style.display !== 'none') closeModal();
|
||||
});
|
||||
|
||||
// Load categories + current product categories in parallel
|
||||
function loadData() {
|
||||
var iid = state.integrationId;
|
||||
var pid = state.productId;
|
||||
|
||||
var categoriesPromise;
|
||||
if (state.cachedIntegrationId === iid && state.cachedCategories !== null) {
|
||||
categoriesPromise = Promise.resolve(state.cachedCategories);
|
||||
} else {
|
||||
categoriesPromise = fetch('/marketplace/' + iid + '/categories', {
|
||||
headers: { 'Accept': 'application/json' }
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (d) {
|
||||
if (!d.ok) throw new Error(d.message || 'Błąd pobierania kategorii');
|
||||
state.cachedCategories = d.categories;
|
||||
state.cachedIntegrationId = iid;
|
||||
return d.categories;
|
||||
});
|
||||
}
|
||||
|
||||
var currentPromise = fetch('/marketplace/' + iid + '/product/' + pid + '/categories', {
|
||||
headers: { 'Accept': 'application/json' }
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (d) {
|
||||
if (!d.ok) throw new Error(d.message || 'Błąd pobierania kategorii produktu');
|
||||
return d.current_category_ids || [];
|
||||
});
|
||||
|
||||
Promise.all([categoriesPromise, currentPromise])
|
||||
.then(function (res) { renderTree(res[0], res[1]); })
|
||||
.catch(function (err) { showError(err.message || 'Nieznany błąd'); });
|
||||
}
|
||||
|
||||
// Build tree from flat list
|
||||
function buildTree(flat) {
|
||||
var map = {}, roots = [];
|
||||
flat.forEach(function (c) { map[c.id] = { id: c.id, parent_id: c.parent_id, title: c.title, children: [] }; });
|
||||
flat.forEach(function (c) {
|
||||
if (c.parent_id && map[c.parent_id]) {
|
||||
map[c.parent_id].children.push(map[c.id]);
|
||||
} else {
|
||||
roots.push(map[c.id]);
|
||||
}
|
||||
});
|
||||
return roots;
|
||||
}
|
||||
|
||||
function renderNode(node, checked) {
|
||||
var li = document.createElement('li');
|
||||
li.style.cssText = 'list-style:none;padding:0';
|
||||
|
||||
var row = document.createElement('div');
|
||||
row.style.cssText = 'display:flex;align-items:center;gap:6px;padding:3px 0';
|
||||
|
||||
if (node.children.length > 0) {
|
||||
var toggle = document.createElement('button');
|
||||
toggle.type = 'button';
|
||||
toggle.textContent = '▶';
|
||||
toggle.style.cssText = 'background:none;border:none;cursor:pointer;font-size:10px;padding:0 2px;color:#666';
|
||||
toggle.addEventListener('click', function () {
|
||||
var sub = li.querySelector('ul');
|
||||
if (sub) { sub.hidden = !sub.hidden; toggle.textContent = sub.hidden ? '▶' : '▼'; }
|
||||
});
|
||||
row.appendChild(toggle);
|
||||
} else {
|
||||
var sp = document.createElement('span');
|
||||
sp.style.display = 'inline-block'; sp.style.width = '16px';
|
||||
row.appendChild(sp);
|
||||
}
|
||||
|
||||
var label = document.createElement('label');
|
||||
label.style.cssText = 'display:flex;align-items:center;gap:5px;cursor:pointer';
|
||||
var cb = document.createElement('input');
|
||||
cb.type = 'checkbox'; cb.value = String(node.id);
|
||||
cb.checked = checked.indexOf(node.id) !== -1;
|
||||
label.appendChild(cb);
|
||||
label.appendChild(document.createTextNode(node.title));
|
||||
row.appendChild(label);
|
||||
li.appendChild(row);
|
||||
|
||||
if (node.children.length > 0) {
|
||||
var ul = document.createElement('ul');
|
||||
ul.style.cssText = 'padding-left:20px;margin:0';
|
||||
node.children.forEach(function (ch) { ul.appendChild(renderNode(ch, checked)); });
|
||||
li.appendChild(ul);
|
||||
}
|
||||
return li;
|
||||
}
|
||||
|
||||
function renderTree(flat, checked) {
|
||||
treeEl.innerHTML = '';
|
||||
var roots = buildTree(flat);
|
||||
var ul = document.createElement('ul');
|
||||
ul.style.cssText = 'padding:0;margin:0';
|
||||
if (roots.length === 0) {
|
||||
treeEl.textContent = 'Brak dostępnych kategorii.';
|
||||
} else {
|
||||
roots.forEach(function (r) { ul.appendChild(renderNode(r, checked)); });
|
||||
treeEl.appendChild(ul);
|
||||
}
|
||||
loadingEl.style.display = 'none';
|
||||
treeEl.style.display = '';
|
||||
saveBtn.style.display = '';
|
||||
}
|
||||
|
||||
function showError(msg) {
|
||||
loadingEl.style.display = 'none';
|
||||
errorEl.textContent = msg;
|
||||
errorEl.style.display = '';
|
||||
}
|
||||
|
||||
// Save
|
||||
saveBtn.addEventListener('click', function () {
|
||||
var cbs = treeEl.querySelectorAll('input[type=checkbox]:checked');
|
||||
var ids = [];
|
||||
cbs.forEach(function (cb) { var id = parseInt(cb.value, 10); if (id > 0) ids.push(id); });
|
||||
|
||||
saveBtn.disabled = true;
|
||||
saveBtn.textContent = 'Zapisuję...';
|
||||
|
||||
fetch('/marketplace/' + state.integrationId + '/product/' + state.productId + '/categories', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },
|
||||
body: JSON.stringify({ _token: CSRF, category_ids: ids })
|
||||
})
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (d) {
|
||||
saveBtn.disabled = false; saveBtn.textContent = 'Zapisz';
|
||||
if (d.ok) {
|
||||
closeModal();
|
||||
if (window.OrderProAlerts) window.OrderProAlerts.show({ type: 'success', message: 'Kategorie zapisane.', timeout: 3000 });
|
||||
} else {
|
||||
if (window.OrderProAlerts) window.OrderProAlerts.show({ type: 'danger', message: d.message || 'Błąd zapisu.', timeout: 5000 });
|
||||
}
|
||||
})
|
||||
.catch(function (err) {
|
||||
saveBtn.disabled = false; saveBtn.textContent = 'Zapisz';
|
||||
if (window.OrderProAlerts) window.OrderProAlerts.show({ type: 'danger', message: 'Błąd sieci: ' + err.message, timeout: 5000 });
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
Reference in New Issue
Block a user