Files
orderPRO/resources/views/settings/statuses.php
Jacek Pyziak c489891d15 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.
2026-03-03 01:32:28 +01:00

342 lines
17 KiB
PHP

<?php
$groupsList = is_array($groups ?? null) ? $groups : [];
$statusesList = is_array($statuses ?? null) ? $statuses : [];
$statusesByGroup = [];
foreach ($groupsList as $groupRow) {
$groupId = max(0, (int) ($groupRow['id'] ?? 0));
if ($groupId <= 0) {
continue;
}
$statusesByGroup[$groupId] = [];
}
foreach ($statusesList as $statusRow) {
$groupId = max(0, (int) ($statusRow['group_id'] ?? 0));
if ($groupId <= 0) {
continue;
}
if (!isset($statusesByGroup[$groupId])) {
$statusesByGroup[$groupId] = [];
}
$statusesByGroup[$groupId][] = $statusRow;
}
?>
<section class="card">
<h2 class="section-title"><?= $e($t('settings.statuses.title')) ?></h2>
<p class="muted mt-12"><?= $e($t('settings.statuses.description')) ?></p>
<?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; ?>
</section>
<section class="card mt-16">
<nav class="content-tabs-nav" aria-label="<?= $e($t('settings.statuses.tabs.label')) ?>">
<button type="button" class="content-tab-btn is-active" data-tab-target="statuses-tab">
<?= $e($t('settings.statuses.tabs.statuses')) ?>
</button>
<button type="button" class="content-tab-btn" data-tab-target="groups-tab">
<?= $e($t('settings.statuses.tabs.groups')) ?>
</button>
</nav>
<div class="content-tab-panel is-active" data-tab-panel="statuses-tab">
<h2 class="section-title"><?= $e($t('settings.statuses.statuses.create_title')) ?></h2>
<form class="statuses-form mt-16" action="/settings/statuses/create" method="post">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<label class="form-field">
<span class="field-label"><?= $e($t('settings.statuses.fields.group')) ?></span>
<select name="group_id" class="form-control" required>
<option value=""><?= $e($t('settings.statuses.fields.group_placeholder')) ?></option>
<?php foreach ($groupsList as $group): ?>
<?php $groupId = max(0, (int) ($group['id'] ?? 0)); ?>
<?php if ($groupId <= 0) continue; ?>
<option value="<?= $e((string) $groupId) ?>"><?= $e((string) ($group['name'] ?? ('#' . $groupId))) ?></option>
<?php endforeach; ?>
</select>
</label>
<label class="form-field">
<span class="field-label"><?= $e($t('settings.statuses.fields.name')) ?></span>
<input type="text" name="name" class="form-control" maxlength="120" required>
</label>
<label class="field-inline">
<input type="hidden" name="is_active" value="0">
<input type="checkbox" name="is_active" value="1" checked>
<span><?= $e($t('settings.statuses.fields.is_active')) ?></span>
</label>
<p class="muted statuses-hint"><?= $e($t('settings.statuses.hints.code_auto')) ?></p>
<div class="form-actions">
<button type="submit" class="btn btn--primary"><?= $e($t('settings.statuses.actions.add_status')) ?></button>
</div>
</form>
<h2 class="section-title mt-16"><?= $e($t('settings.statuses.statuses.list_title')) ?></h2>
<?php if ($groupsList === []): ?>
<div class="alert alert--warning mt-12"><?= $e($t('settings.statuses.groups.empty')) ?></div>
<?php endif; ?>
<?php foreach ($groupsList as $group): ?>
<?php
$groupId = max(0, (int) ($group['id'] ?? 0));
if ($groupId <= 0) {
continue;
}
$groupName = (string) ($group['name'] ?? ('#' . $groupId));
$groupColor = (string) ($group['color_hex'] ?? '#64748b');
$groupStatuses = is_array($statusesByGroup[$groupId] ?? null) ? $statusesByGroup[$groupId] : [];
?>
<article class="statuses-group-block mt-16">
<header class="statuses-group-block__head">
<h3 class="statuses-group-block__title">
<span class="statuses-color-dot" style="background: <?= $e($groupColor) ?>;"></span>
<?= $e($groupName) ?>
</h3>
<span class="muted"><?= $e($t('settings.statuses.hints.drag_statuses')) ?> <?= $e($t('settings.statuses.hints.auto_save_order')) ?></span>
</header>
<ul class="statuses-dnd-list js-dnd-list" data-order-scope="statuses-<?= $e((string) $groupId) ?>">
<?php foreach ($groupStatuses as $status): ?>
<?php $statusId = max(0, (int) ($status['id'] ?? 0)); ?>
<?php if ($statusId <= 0) continue; ?>
<li class="statuses-dnd-item" draggable="true" data-id="<?= $e((string) $statusId) ?>">
<div class="statuses-dnd-item__drag" title="<?= $e($t('settings.statuses.hints.drag_handle')) ?>">::</div>
<div class="statuses-dnd-item__content">
<form action="/settings/statuses/update" method="post" class="statuses-inline-form statuses-inline-form--row">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<input type="hidden" name="status_id" value="<?= $e((string) $statusId) ?>">
<input type="text" name="name" class="form-control" maxlength="120" required value="<?= $e((string) ($status['name'] ?? '')) ?>" aria-label="<?= $e($t('settings.statuses.fields.name')) ?>">
<select name="group_id" class="form-control" required aria-label="<?= $e($t('settings.statuses.fields.group')) ?>">
<?php foreach ($groupsList as $groupOption): ?>
<?php $groupOptionId = max(0, (int) ($groupOption['id'] ?? 0)); ?>
<?php if ($groupOptionId <= 0) continue; ?>
<option value="<?= $e((string) $groupOptionId) ?>"<?= $groupOptionId === (int) ($status['group_id'] ?? 0) ? ' selected' : '' ?>>
<?= $e((string) ($groupOption['name'] ?? ('#' . $groupOptionId))) ?>
</option>
<?php endforeach; ?>
</select>
<label class="field-inline statuses-inline-check">
<input type="hidden" name="is_active" value="0">
<input type="checkbox" name="is_active" value="1"<?= ((int) ($status['is_active'] ?? 0)) === 1 ? ' checked' : '' ?>>
<span><?= $e($t('settings.statuses.fields.is_active')) ?></span>
</label>
<div class="statuses-code-readonly">
<span class="statuses-code-label"><?= $e($t('settings.statuses.fields.code')) ?>:</span>
<code><?= $e((string) ($status['code'] ?? '')) ?></code>
</div>
<button type="submit" class="btn btn--secondary"><?= $e($t('settings.statuses.actions.save')) ?></button>
</form>
<form action="/settings/statuses/delete" method="post" class="table-inline-action statuses-inline-delete" data-alert-confirm="<?= $e($t('settings.statuses.confirm.delete_status')) ?>" data-alert-confirm-title="<?= $e($t('settings.statuses.confirm.title')) ?>" data-alert-confirm-yes="<?= $e($t('settings.statuses.confirm.confirm')) ?>" data-alert-confirm-no="<?= $e($t('settings.statuses.confirm.cancel')) ?>">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<input type="hidden" name="status_id" value="<?= $e((string) $statusId) ?>">
<button type="submit" class="btn btn--danger"><?= $e($t('settings.statuses.actions.delete')) ?></button>
</form>
</div>
</li>
<?php endforeach; ?>
</ul>
<?php if ($groupStatuses === []): ?>
<p class="muted mt-12"><?= $e($t('settings.statuses.statuses.empty')) ?></p>
<?php endif; ?>
<?php if ($groupStatuses !== []): ?>
<form action="/settings/statuses/reorder" method="post" class="statuses-reorder-form js-reorder-form mt-12" data-order-scope="statuses-<?= $e((string) $groupId) ?>">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<input type="hidden" name="group_id" value="<?= $e((string) $groupId) ?>">
<div class="js-order-inputs"></div>
</form>
<?php endif; ?>
</article>
<?php endforeach; ?>
</div>
<div class="content-tab-panel" data-tab-panel="groups-tab">
<h2 class="section-title"><?= $e($t('settings.statuses.groups.create_title')) ?></h2>
<form class="statuses-form mt-16" action="/settings/status-groups" method="post">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<label class="form-field">
<span class="field-label"><?= $e($t('settings.statuses.fields.name')) ?></span>
<input type="text" name="name" class="form-control" maxlength="120" required>
</label>
<label class="form-field">
<span class="field-label"><?= $e($t('settings.statuses.fields.color')) ?></span>
<input type="color" name="color_hex" class="form-control statuses-color-input" value="#64748b">
</label>
<label class="field-inline">
<input type="hidden" name="is_active" value="0">
<input type="checkbox" name="is_active" value="1" checked>
<span><?= $e($t('settings.statuses.fields.is_active')) ?></span>
</label>
<p class="muted statuses-hint"><?= $e($t('settings.statuses.hints.code_auto')) ?></p>
<div class="form-actions">
<button type="submit" class="btn btn--primary"><?= $e($t('settings.statuses.actions.add_group')) ?></button>
</div>
</form>
<h2 class="section-title mt-16"><?= $e($t('settings.statuses.groups.list_title')) ?></h2>
<p class="muted mt-12"><?= $e($t('settings.statuses.hints.drag_groups')) ?> <?= $e($t('settings.statuses.hints.auto_save_order')) ?></p>
<ul class="statuses-dnd-list js-dnd-list mt-12" data-order-scope="groups">
<?php foreach ($groupsList as $group): ?>
<?php
$groupId = max(0, (int) ($group['id'] ?? 0));
if ($groupId <= 0) {
continue;
}
?>
<li class="statuses-dnd-item" draggable="true" data-id="<?= $e((string) $groupId) ?>">
<div class="statuses-dnd-item__drag" title="<?= $e($t('settings.statuses.hints.drag_handle')) ?>">::</div>
<div class="statuses-dnd-item__content">
<form action="/settings/status-groups/update" method="post" class="statuses-inline-form statuses-inline-form--row-group">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<input type="hidden" name="group_id" value="<?= $e((string) $groupId) ?>">
<input type="text" name="name" class="form-control" maxlength="120" required value="<?= $e((string) ($group['name'] ?? '')) ?>" aria-label="<?= $e($t('settings.statuses.fields.name')) ?>">
<input type="color" name="color_hex" class="form-control statuses-color-input" value="<?= $e((string) ($group['color_hex'] ?? '#64748b')) ?>" aria-label="<?= $e($t('settings.statuses.fields.color')) ?>">
<label class="field-inline statuses-inline-check">
<input type="hidden" name="is_active" value="0">
<input type="checkbox" name="is_active" value="1"<?= ((int) ($group['is_active'] ?? 0)) === 1 ? ' checked' : '' ?>>
<span><?= $e($t('settings.statuses.fields.is_active')) ?></span>
</label>
<div class="statuses-code-readonly">
<span class="statuses-code-label"><?= $e($t('settings.statuses.fields.code')) ?>:</span>
<code><?= $e((string) ($group['code'] ?? '')) ?></code>
</div>
<button type="submit" class="btn btn--secondary"><?= $e($t('settings.statuses.actions.save')) ?></button>
</form>
<form action="/settings/status-groups/delete" method="post" class="table-inline-action statuses-inline-delete" data-alert-confirm="<?= $e($t('settings.statuses.confirm.delete_group')) ?>" data-alert-confirm-title="<?= $e($t('settings.statuses.confirm.title')) ?>" data-alert-confirm-yes="<?= $e($t('settings.statuses.confirm.confirm')) ?>" data-alert-confirm-no="<?= $e($t('settings.statuses.confirm.cancel')) ?>">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<input type="hidden" name="group_id" value="<?= $e((string) $groupId) ?>">
<button type="submit" class="btn btn--danger"><?= $e($t('settings.statuses.actions.delete')) ?></button>
</form>
</div>
</li>
<?php endforeach; ?>
</ul>
<?php if ($groupsList === []): ?>
<p class="muted mt-12"><?= $e($t('settings.statuses.groups.empty')) ?></p>
<?php endif; ?>
<?php if ($groupsList !== []): ?>
<form action="/settings/status-groups/reorder" method="post" class="statuses-reorder-form js-reorder-form mt-12" data-order-scope="groups">
<input type="hidden" name="_token" value="<?= $e($csrfToken ?? '') ?>">
<div class="js-order-inputs"></div>
</form>
<?php endif; ?>
</div>
</section>
<script>
(function() {
var tabStorageKey = 'settings.statuses.active_tab';
var defaultTab = 'statuses-tab';
function activateTab(target) {
var normalizedTarget = (target === 'groups-tab' || target === 'statuses-tab') ? target : defaultTab;
tabButtons.forEach(function(btn) { btn.classList.remove('is-active'); });
tabPanels.forEach(function(panel) { panel.classList.remove('is-active'); });
var activeButton = document.querySelector('[data-tab-target="' + normalizedTarget + '"]');
var activePanel = document.querySelector('[data-tab-panel="' + normalizedTarget + '"]');
if (activeButton) activeButton.classList.add('is-active');
if (activePanel) activePanel.classList.add('is-active');
}
var tabButtons = document.querySelectorAll('[data-tab-target]');
var tabPanels = document.querySelectorAll('[data-tab-panel]');
try {
activateTab(localStorage.getItem(tabStorageKey) || defaultTab);
} catch (e) {
activateTab(defaultTab);
}
tabButtons.forEach(function(button) {
button.addEventListener('click', function() {
var target = button.getAttribute('data-tab-target');
activateTab(target);
try {
localStorage.setItem(tabStorageKey, target || defaultTab);
} catch (e) {}
});
});
function initDndList(list) {
var dragged = null;
var startIndex = -1;
function submitReorderForScope(scope) {
if (scope === '') return;
var form = document.querySelector('.js-reorder-form[data-order-scope="' + scope + '"]');
if (!form || form.getAttribute('data-submitting') === '1') return;
var sourceList = document.querySelector('.js-dnd-list[data-order-scope="' + scope + '"]');
if (!sourceList) return;
var holder = form.querySelector('.js-order-inputs');
if (!holder) return;
holder.innerHTML = '';
sourceList.querySelectorAll('.statuses-dnd-item').forEach(function(item) {
var id = item.getAttribute('data-id') || '';
if (id === '') return;
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'order[]';
input.value = id;
holder.appendChild(input);
});
form.setAttribute('data-submitting', '1');
form.submit();
}
list.querySelectorAll('.statuses-dnd-item').forEach(function(item) {
item.addEventListener('dragstart', function() {
dragged = item;
startIndex = Array.prototype.indexOf.call(list.children, item);
item.classList.add('is-dragging');
});
item.addEventListener('dragend', function() {
item.classList.remove('is-dragging');
var endIndex = Array.prototype.indexOf.call(list.children, item);
var moved = startIndex >= 0 && endIndex >= 0 && startIndex !== endIndex;
var scope = list.getAttribute('data-order-scope') || '';
dragged = null;
startIndex = -1;
if (moved) {
submitReorderForScope(scope);
}
});
item.addEventListener('dragover', function(event) {
event.preventDefault();
if (!dragged || dragged === item) return;
var rect = item.getBoundingClientRect();
var before = event.clientY < rect.top + rect.height / 2;
list.insertBefore(dragged, before ? item : item.nextSibling);
});
});
}
document.querySelectorAll('.js-dnd-list').forEach(initDndList);
document.addEventListener('submit', function(event) {
var form = event.target;
if (!form || !form.matches || !form.matches('form[data-alert-confirm]')) return;
if (form.getAttribute('data-confirmed') === '1') {
form.removeAttribute('data-confirmed');
return;
}
var message = form.getAttribute('data-alert-confirm') || '';
if (message === '') return;
if (!window.OrderProAlerts || typeof window.OrderProAlerts.confirm !== 'function') return;
event.preventDefault();
window.OrderProAlerts.confirm({
title: form.getAttribute('data-alert-confirm-title') || 'Potwierdzenie',
message: message,
confirmLabel: form.getAttribute('data-alert-confirm-yes') || 'Potwierdz',
cancelLabel: form.getAttribute('data-alert-confirm-no') || 'Anuluj',
danger: true
}).then(function(accepted) {
if (!accepted) return;
form.setAttribute('data-confirmed', '1');
form.submit();
});
});
})();
</script>