Files
backPRO/templates/topics/index.php

293 lines
14 KiB
PHP

<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2>Tematy: <?= htmlspecialchars($site['name']) ?></h2>
<a href="/sites" class="text-muted small">&larr; Powrót do stron</a>
</div>
</div>
<div class="row g-4">
<div class="col-md-8">
<div class="card">
<div class="card-body p-0">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>Temat</th>
<th>Kategoria</th>
<th>Kat. WP</th>
<th>Artykuły</th>
<th>Status</th>
<th>Akcje</th>
</tr>
</thead>
<tbody>
<?php if (empty($topics)): ?>
<tr><td colspan="6" class="text-center text-muted py-4">Brak tematów. Dodaj tematy z biblioteki lub utwórz własny.</td></tr>
<?php else: ?>
<?php
// Group topics by parent category
$grouped = [];
foreach ($topics as $topic) {
$group = $topic['global_category_name']
?? ($topic['global_topic_name'] && !$topic['global_category_name'] ? $topic['global_topic_name'] : null)
?? '__custom__';
$grouped[$group][] = $topic;
}
?>
<?php foreach ($grouped as $groupName => $groupTopics): ?>
<tr class="table-light">
<td colspan="6" class="py-1 px-3">
<strong class="small text-uppercase text-muted">
<?= $groupName === '__custom__' ? 'Własne tematy' : htmlspecialchars($groupName) ?>
</strong>
<span class="badge bg-secondary ms-1"><?= count($groupTopics) ?></span>
</td>
</tr>
<?php foreach ($groupTopics as $topic): ?>
<tr>
<td class="ps-4"><strong><?= htmlspecialchars($topic['name']) ?></strong></td>
<td class="small text-muted">
<?php if ($topic['global_category_name']): ?>
<?= htmlspecialchars($topic['global_category_name']) ?>
<?php elseif ($topic['global_topic_name']): ?>
<?= htmlspecialchars($topic['global_topic_name']) ?>
<?php else: ?>
<em>własny</em>
<?php endif; ?>
</td>
<td><?= $topic['wp_category_id'] ?: '-' ?></td>
<td><span class="badge bg-primary"><?= $topic['article_count'] ?></span></td>
<td>
<?php if ($topic['is_active']): ?>
<span class="badge bg-success">Aktywny</span>
<?php else: ?>
<span class="badge bg-secondary">Nieaktywny</span>
<?php endif; ?>
</td>
<td>
<div class="btn-group btn-group-sm">
<button class="btn btn-outline-primary btn-edit-topic"
data-id="<?= $topic['id'] ?>"
data-name="<?= htmlspecialchars($topic['name']) ?>"
data-description="<?= htmlspecialchars($topic['description'] ?? '') ?>"
data-wp-category="<?= $topic['wp_category_id'] ?>"
data-global-topic="<?= $topic['global_topic_id'] ?>"
data-active="<?= $topic['is_active'] ?>">
<i class="bi bi-pencil"></i>
</button>
<button class="btn btn-outline-danger btn-delete-topic" data-id="<?= $topic['id'] ?>" data-name="<?= htmlspecialchars($topic['name']) ?>">
<i class="bi bi-trash"></i>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5 class="mb-0" id="topicFormTitle">Dodaj temat</h5>
</div>
<div class="card-body">
<form method="post" action="/sites/<?= $site['id'] ?>/topics" id="topicForm">
<?php
$assignedGlobalIdSet = [];
foreach (($assignedGlobalIds ?? []) as $gid) {
$assignedGlobalIdSet[(int) $gid] = true;
}
$assignedNameSet = [];
foreach (($assignedTopicNames ?? []) as $tname) {
$assignedNameSet[mb_strtolower(trim((string) $tname))] = true;
}
?>
<div class="mb-3">
<label class="form-label">Wybierz z biblioteki</label>
<select class="form-select" id="topic_global_id" name="global_topic_id" onchange="fillFromLibrary(this)">
<option value="">-- własny temat --</option>
<?php foreach ($globalTopics as $cat): ?>
<optgroup label="<?= htmlspecialchars($cat['name']) ?>">
<?php foreach ($cat['children'] as $child): ?>
<?php
$childId = (int) $child['id'];
$childNameKey = mb_strtolower(trim((string) ($child['name'] ?? '')));
$alreadyAssigned = isset($assignedGlobalIdSet[$childId]) || isset($assignedNameSet[$childNameKey]);
?>
<?php if ($alreadyAssigned) continue; ?>
<option value="<?= $child['id'] ?>"
data-name="<?= htmlspecialchars($child['name']) ?>"
data-desc="<?= htmlspecialchars($child['description'] ?? '') ?>">
<?= htmlspecialchars($child['name']) ?>
</option>
<?php endforeach; ?>
</optgroup>
<?php endforeach; ?>
</select>
<div class="form-text">Wybierz temat z <a href="/global-topics">biblioteki</a> lub wpisz własny poniżej</div>
</div>
<div class="mb-3">
<label for="topic_name" class="form-label">Nazwa tematu</label>
<input type="text" class="form-control" id="topic_name" name="name" required placeholder="np. Ogrodnictwo">
</div>
<div class="mb-3">
<label for="topic_description" class="form-label">Opis / wytyczne dla AI</label>
<textarea class="form-control" id="topic_description" name="description" rows="3" placeholder="Opisz czego powinny dotyczyć artykuły..."></textarea>
<div class="form-text">Wskazówki dla AI, jak pisać artykuły z tego tematu</div>
</div>
<div class="mb-3">
<label for="topic_wp_category" class="form-label">ID kategorii WordPress</label>
<input type="number" class="form-control" id="topic_wp_category" name="wp_category_id" placeholder="np. 5">
<div class="form-text">
<a href="/sites/<?= $site['id'] ?>/categories">Sprawdź kategorie na stronie</a>
</div>
</div>
<div class="mb-3">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="topic_is_active" name="is_active" value="1" checked>
<label class="form-check-label" for="topic_is_active">Aktywny</label>
</div>
</div>
<button type="submit" class="btn btn-primary w-100" id="topicFormSubmit">Dodaj temat</button>
</form>
</div>
</div>
</div>
</div>
<script>
var siteId = <?= (int) $site['id'] ?>;
function fillFromLibrary(select) {
var opt = select.options[select.selectedIndex];
if (opt.value) {
document.getElementById('topic_name').value = opt.dataset.name || '';
document.getElementById('topic_description').value = opt.dataset.desc || '';
}
}
document.querySelectorAll('.btn-delete-topic').forEach(function (btn) {
btn.addEventListener('click', async function () {
var id = this.dataset.id;
var name = this.dataset.name;
var ok = await backproConfirm('Na pewno usunac temat "' + name + '"?', {
title: 'Usuwanie tematu',
confirmText: 'Usun',
cancelText: 'Anuluj',
confirmClass: 'btn-danger'
});
if (!ok) return;
var row = this.closest('tr');
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
fetch('/topics/' + id + '/delete', {
method: 'POST',
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(function (r) { return r.json(); })
.then(function (data) {
if (data.success) {
row.style.transition = 'opacity .3s';
row.style.opacity = '0';
setTimeout(function () {
row.remove();
var tbody = document.querySelector('table tbody');
if (tbody && !tbody.querySelector('tr')) {
tbody.innerHTML = '<tr><td colspan="6" class="text-center text-muted py-4">Brak tematow. Dodaj tematy z biblioteki lub utworz wlasny.</td></tr>';
}
}, 300);
backproNotify('Temat zostal usuniety.', 'success', { delay: 2500 });
} else {
backproNotify(data.message || 'Blad usuwania', 'danger');
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-trash"></i>';
}
})
.catch(function () {
backproNotify('Blad polaczenia', 'danger');
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-trash"></i>';
});
});
});
(function () {
var params = new URLSearchParams(window.location.search);
if (params.get('topic_added') !== '1') {
return;
}
// Prevent repeated prompt on refresh.
params.delete('topic_added');
var nextQuery = params.toString();
var nextUrl = window.location.pathname + (nextQuery ? ('?' + nextQuery) : '');
window.history.replaceState({}, '', nextUrl);
setTimeout(async function () {
function notify(message, type) {
if (typeof window.backproNotify === 'function') {
window.backproNotify(message, type || 'info');
return;
}
window.alert(message);
}
var ok = false;
if (typeof window.backproConfirm === 'function') {
ok = await window.backproConfirm(
'Temat został dodany. Czy chcesz od razu zsynchronizować kategorie w WordPressie na podstawie tematów?',
{
title: 'Synchronizacja kategorii',
confirmText: 'Tak, synchronizuj',
cancelText: 'Nie teraz',
confirmClass: 'btn-success'
}
);
} else {
ok = window.confirm('Temat został dodany. Czy chcesz od razu zsynchronizować kategorie w WordPressie?');
}
if (!ok) {
return;
}
fetch('/sites/' + siteId + '/categories/from-topics', {
method: 'POST',
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then(function (r) { return r.json(); })
.then(function (data) {
if (data && data.success) {
var hasErrors = Array.isArray(data.errors) && data.errors.length > 0;
if (hasErrors) {
notify(data.message || 'Synchronizacja zakończona częściowo (z błędami).', 'warning');
} else {
notify(data.message || 'Kategorie zostały zsynchronizowane.', 'success');
}
setTimeout(function () { window.location.reload(); }, 1800);
return;
}
notify((data && data.message) ? data.message : 'Nie udało się zsynchronizować kategorii.', 'danger');
})
.catch(function () {
notify('Błąd połączenia podczas synchronizacji kategorii.', 'danger');
});
}, 120);
})();
</script>