Files
orderPRO/resources/views/components/table-list.php

474 lines
19 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
$config = is_array($tableList ?? null) ? $tableList : [];
$basePath = (string) ($config['base_path'] ?? '');
$query = is_array($config['query'] ?? null) ? $config['query'] : [];
$filters = is_array($config['filters'] ?? null) ? $config['filters'] : [];
$columns = is_array($config['columns'] ?? null) ? $config['columns'] : [];
$rows = is_array($config['rows'] ?? null) ? $config['rows'] : [];
$pagination = is_array($config['pagination'] ?? null) ? $config['pagination'] : [];
$perPageOptions = is_array($config['per_page_options'] ?? null) ? $config['per_page_options'] : [20, 50, 100];
$createUrl = (string) ($config['create_url'] ?? '');
$createLabel = (string) ($config['create_label'] ?? '');
$headerActions = is_array($config['header_actions'] ?? null) ? $config['header_actions'] : [];
$emptyMessage = (string) ($config['empty_message'] ?? 'Brak rekordow.');
$showActions = (bool) ($config['show_actions'] ?? true);
$actionsLabel = (string) ($config['actions_label'] ?? 'Akcje');
$listKey = (string) ($config['list_key'] ?? md5($basePath !== '' ? $basePath : 'table-list'));
$currentSort = (string) ($query['sort'] ?? 'id');
$currentDir = strtoupper((string) ($query['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'] ?? 0));
$perPage = max(1, (int) ($pagination['per_page'] ?? 20));
$activeFiltersCount = 0;
foreach ($filters as $filter) {
if ((string) ($filter['value'] ?? '') !== '') {
$activeFiltersCount++;
}
}
$hasActiveFilters = $activeFiltersCount > 0;
$buildUrl = static function (array $params = []) use ($basePath, $query): string {
$merged = array_merge($query, $params);
foreach ($merged as $key => $value) {
if ($value === '' || $value === null) {
unset($merged[$key]);
}
}
$qs = http_build_query($merged);
if ($qs === '') {
return $basePath;
}
return $basePath . '?' . $qs;
};
?>
<section class="card table-list" data-table-list-id="<?= $e($listKey) ?>" data-table-list-base="<?= $e($basePath) ?>">
<div class="table-list__header">
<div class="table-list__left">
<?php if ($createUrl !== '' && $createLabel !== ''): ?>
<a href="<?= $e($createUrl) ?>" class="btn btn--primary">
<?= $e($createLabel) ?>
</a>
<?php endif; ?>
<?php foreach ($headerActions as $action): ?>
<?php
$actionType = (string) ($action['type'] ?? 'link');
$actionLabel = (string) ($action['label'] ?? '');
$actionClass = (string) ($action['class'] ?? 'btn btn--secondary');
$actionAttrs = is_array($action['attrs'] ?? null) ? $action['attrs'] : [];
if ($actionLabel === '') {
continue;
}
?>
<?php if ($actionType === 'button'): ?>
<button type="button" class="<?= $e($actionClass) ?>"
<?php foreach ($actionAttrs as $attrKey => $attrValue): ?>
<?= $e((string) $attrKey) ?>="<?= $e((string) $attrValue) ?>"
<?php endforeach; ?>
><?= $e($actionLabel) ?></button>
<?php else: ?>
<a href="<?= $e((string) ($action['url'] ?? '#')) ?>" class="<?= $e($actionClass) ?>"
<?php foreach ($actionAttrs as $attrKey => $attrValue): ?>
<?= $e((string) $attrKey) ?>="<?= $e((string) $attrValue) ?>"
<?php endforeach; ?>
><?= $e($actionLabel) ?></a>
<?php endif; ?>
<?php endforeach; ?>
</div>
<div class="table-list-header-actions">
<span class="muted">Wynikow: <?= $e((string) $total) ?></span>
<?php if (!empty($filters)): ?>
<button type="button" class="btn btn--secondary js-filter-toggle-btn<?= $hasActiveFilters ? ' is-active' : '' ?>" title="Filtry">
Filtry
<?php if ($hasActiveFilters): ?>
<span class="table-filter-badge"><?= $e((string) $activeFiltersCount) ?></span>
<?php endif; ?>
</button>
<?php endif; ?>
<div class="table-col-toggle-wrapper">
<button type="button" class="btn btn--secondary js-col-toggle-btn" title="Widocznosc kolumn">Kolumny</button>
<div class="table-col-toggle-dropdown js-col-toggle-dropdown">
<div class="table-col-toggle-header">Widocznosc kolumn</div>
<?php foreach ($columns as $index => $column): ?>
<?php $colKey = (string) ($column['key'] ?? ('col_' . $index)); ?>
<label class="table-col-toggle-item">
<span class="table-col-switch">
<input type="checkbox" class="js-col-toggle-checkbox" data-col-key="<?= $e($colKey) ?>" checked>
<span class="table-col-switch-slider"></span>
</span>
<?= $e((string) ($column['label'] ?? $colKey)) ?>
</label>
<?php endforeach; ?>
<div class="table-col-toggle-footer">
<button type="button" class="btn btn--secondary js-col-toggle-reset">Pokaz wszystkie</button>
</div>
</div>
</div>
</div>
</div>
<?php if (!empty($filters)): ?>
<div class="table-filters-wrapper js-table-filters-wrapper<?= $hasActiveFilters ? ' is-open' : '' ?>">
<form method="get" action="<?= $e($basePath) ?>" class="table-list-filters js-table-filters-form">
<?php foreach ($filters as $filter): ?>
<?php
$filterKey = (string) ($filter['key'] ?? '');
$filterType = (string) ($filter['type'] ?? 'text');
$filterLabel = (string) ($filter['label'] ?? $filterKey);
$filterValue = (string) ($filter['value'] ?? '');
$inputId = 'filter_' . preg_replace('/[^a-zA-Z0-9_]+/', '_', $filterKey) . '_' . $listKey;
?>
<label class="form-field">
<span class="field-label"><?= $e($filterLabel) ?></span>
<?php if ($filterType === 'select'): ?>
<select class="form-control" id="<?= $e($inputId) ?>" name="<?= $e($filterKey) ?>">
<?php foreach ((array) ($filter['options'] ?? []) as $value => $label): ?>
<option value="<?= $e((string) $value) ?>"<?= (string) $value === $filterValue ? ' selected' : '' ?>>
<?= $e((string) $label) ?>
</option>
<?php endforeach; ?>
</select>
<?php elseif ($filterType === 'date'): ?>
<input class="form-control" id="<?= $e($inputId) ?>" type="date" name="<?= $e($filterKey) ?>" value="<?= $e($filterValue) ?>">
<?php else: ?>
<input class="form-control" id="<?= $e($inputId) ?>" type="text" name="<?= $e($filterKey) ?>" value="<?= $e($filterValue) ?>">
<?php endif; ?>
</label>
<?php endforeach; ?>
<?php foreach ($query as $key => $value): ?>
<?php if (!in_array((string) $key, array_map(static fn (array $filter): string => (string) ($filter['key'] ?? ''), $filters), true) && (string) $key !== 'page'): ?>
<input type="hidden" name="<?= $e((string) $key) ?>" value="<?= $e((string) $value) ?>">
<?php endif; ?>
<?php endforeach; ?>
<div class="filters-actions">
<button type="submit" class="btn btn--primary">Szukaj</button>
<a href="<?= $e($basePath) ?>" class="btn btn--secondary js-table-filters-clear">Wyczysc</a>
</div>
</form>
</div>
<?php endif; ?>
<div class="table-wrap">
<table class="table table-list-table">
<thead>
<tr>
<?php foreach ($columns as $index => $column): ?>
<?php
$colKey = (string) ($column['key'] ?? ('col_' . $index));
$label = (string) ($column['label'] ?? $colKey);
$sortable = (bool) ($column['sortable'] ?? false);
$sortKey = (string) ($column['sort_key'] ?? $colKey);
$isCurrent = $sortable && $currentSort === $sortKey;
$nextDir = $isCurrent && $currentDir === 'ASC' ? 'DESC' : 'ASC';
$headerClass = trim((string) ($column['class'] ?? ''));
?>
<th class="<?= $e($headerClass) ?>" data-col-key="<?= $e($colKey) ?>">
<?php if ($sortable): ?>
<a href="<?= $e($buildUrl(['sort' => $sortKey, 'sort_dir' => $nextDir, 'page' => 1])) ?>" class="table-sort-link">
<?= $e($label) ?>
<?php if ($isCurrent): ?>
<span class="table-sort-icon"><?= $e($currentDir === 'ASC' ? '↑' : '↓') ?></span>
<?php else: ?>
<span class="table-sort-icon is-muted">↕</span>
<?php endif; ?>
</a>
<?php else: ?>
<?= $e($label) ?>
<?php endif; ?>
</th>
<?php endforeach; ?>
<?php if ($showActions): ?>
<th><?= $e($actionsLabel) ?></th>
<?php endif; ?>
</tr>
</thead>
<tbody>
<?php if (empty($rows)): ?>
<tr>
<td colspan="<?= $e((string) (count($columns) + ($showActions ? 1 : 0))) ?>" class="muted">
<?= $e($emptyMessage) ?>
</td>
</tr>
<?php else: ?>
<?php foreach ($rows as $row): ?>
<tr>
<?php foreach ($columns as $index => $column): ?>
<?php
$colKey = (string) ($column['key'] ?? ('col_' . $index));
$raw = (bool) ($column['raw'] ?? false);
$cellClass = trim((string) ($column['class'] ?? ''));
$value = $row[$colKey] ?? '';
?>
<td class="<?= $e($cellClass) ?>" data-col-key="<?= $e($colKey) ?>">
<?php if ($raw): ?>
<?= (string) $value ?>
<?php else: ?>
<?= $e((string) $value) ?>
<?php endif; ?>
</td>
<?php endforeach; ?>
<?php if ($showActions): ?>
<td>
<?php foreach ((array) ($row['_actions'] ?? []) as $action): ?>
<?php
$actionMethod = strtolower((string) ($action['method'] ?? 'get'));
$actionUrl = (string) ($action['url'] ?? '#');
$actionClass = (string) ($action['class'] ?? 'btn btn--secondary');
$actionLabel = (string) ($action['label'] ?? 'Akcja');
$actionConfirm = trim((string) ($action['confirm'] ?? ''));
$actionConfirmTitle = trim((string) ($action['confirm_title'] ?? 'Potwierdzenie'));
$actionConfirmYes = trim((string) ($action['confirm_yes'] ?? 'Potwierdz'));
$actionConfirmNo = trim((string) ($action['confirm_no'] ?? 'Anuluj'));
$actionParams = is_array($action['params'] ?? null) ? $action['params'] : [];
?>
<?php if ($actionMethod === 'post'): ?>
<form
action="<?= $e($actionUrl) ?>"
method="post"
class="table-inline-action"
<?php if ($actionConfirm !== ''): ?>
data-alert-confirm="<?= $e($actionConfirm) ?>"
data-alert-confirm-title="<?= $e($actionConfirmTitle) ?>"
data-alert-confirm-yes="<?= $e($actionConfirmYes) ?>"
data-alert-confirm-no="<?= $e($actionConfirmNo) ?>"
<?php endif; ?>
>
<input type="hidden" name="_token" value="<?= $e((string) ($csrfToken ?? '')) ?>">
<?php foreach ($actionParams as $paramKey => $paramValue): ?>
<input type="hidden" name="<?= $e((string) $paramKey) ?>" value="<?= $e((string) $paramValue) ?>">
<?php endforeach; ?>
<button type="submit" class="<?= $e($actionClass) ?>"><?= $e($actionLabel) ?></button>
</form>
<?php else: ?>
<a href="<?= $e($actionUrl) ?>" class="<?= $e($actionClass) ?>">
<?= $e($actionLabel) ?>
</a>
<?php endif; ?>
<?php endforeach; ?>
</td>
<?php endif; ?>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
<div class="table-list__footer">
<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>
<form method="get" action="<?= $e($basePath) ?>" class="table-list-per-page-form js-per-page-form">
<?php foreach ($query as $key => $value): ?>
<?php if ((string) $key !== 'per_page' && (string) $key !== 'page'): ?>
<input type="hidden" name="<?= $e((string) $key) ?>" value="<?= $e((string) $value) ?>">
<?php endif; ?>
<?php endforeach; ?>
<input type="hidden" name="page" value="1">
<span>Wyswietlaj</span>
<select class="form-control js-per-page-select" name="per_page">
<?php foreach ($perPageOptions as $opt): ?>
<option value="<?= $e((string) $opt) ?>"<?= (int) $opt === $perPage ? ' selected' : '' ?>><?= $e((string) $opt) ?></option>
<?php endforeach; ?>
</select>
<span>rekordow</span>
</form>
</div>
</section>
<script>
(function() {
var root = document.querySelector('[data-table-list-id="<?= $e($listKey) ?>"]');
if (!root) return;
var basePath = root.getAttribute('data-table-list-base') || '';
var storagePrefix = 'tableList_' + (basePath || 'default') + '_<?= $e($listKey) ?>';
var filterKey = storagePrefix + '_filters_open';
var colsKey = storagePrefix + '_hidden_cols';
var queryKey = storagePrefix + '_query';
var clearKey = storagePrefix + '_cleared';
function readJson(key, fallback) {
try {
var val = localStorage.getItem(key);
if (!val) return fallback;
return JSON.parse(val);
} catch (e) {
return fallback;
}
}
function writeJson(key, val) {
try {
localStorage.setItem(key, JSON.stringify(val));
} catch (e) {}
}
var filterWrapper = root.querySelector('.js-table-filters-wrapper');
var filterBtn = root.querySelector('.js-filter-toggle-btn');
if (filterWrapper && filterBtn) {
var savedOpen = localStorage.getItem(filterKey) === '1';
if (savedOpen && !filterWrapper.classList.contains('is-open')) {
filterWrapper.classList.add('is-open');
filterBtn.classList.add('is-active');
}
filterBtn.addEventListener('click', function() {
var isOpen = filterWrapper.classList.toggle('is-open');
filterBtn.classList.toggle('is-active', isOpen);
try { localStorage.setItem(filterKey, isOpen ? '1' : '0'); } catch (e) {}
});
}
var dropdownBtn = root.querySelector('.js-col-toggle-btn');
var dropdown = root.querySelector('.js-col-toggle-dropdown');
if (dropdownBtn && dropdown) {
dropdownBtn.addEventListener('click', function(ev) {
ev.stopPropagation();
dropdown.classList.toggle('is-open');
});
dropdown.addEventListener('click', function(ev) { ev.stopPropagation(); });
document.addEventListener('click', function() { dropdown.classList.remove('is-open'); });
}
function applyHiddenCols(hiddenCols) {
var allCells = root.querySelectorAll('th[data-col-key], td[data-col-key]');
allCells.forEach(function(cell) {
var key = cell.getAttribute('data-col-key');
cell.classList.toggle('table-col-hidden', hiddenCols.indexOf(key) !== -1);
});
var checkboxes = root.querySelectorAll('.js-col-toggle-checkbox');
checkboxes.forEach(function(cb) {
var key = cb.getAttribute('data-col-key');
cb.checked = hiddenCols.indexOf(key) === -1;
});
}
var hiddenCols = readJson(colsKey, []);
if (!Array.isArray(hiddenCols)) hiddenCols = [];
applyHiddenCols(hiddenCols);
root.querySelectorAll('.js-col-toggle-checkbox').forEach(function(cb) {
cb.addEventListener('change', function() {
var key = cb.getAttribute('data-col-key');
hiddenCols = readJson(colsKey, []);
if (!Array.isArray(hiddenCols)) hiddenCols = [];
if (cb.checked) {
hiddenCols = hiddenCols.filter(function(v) { return v !== key; });
} else if (hiddenCols.indexOf(key) === -1) {
hiddenCols.push(key);
}
writeJson(colsKey, hiddenCols);
applyHiddenCols(hiddenCols);
});
});
var resetBtn = root.querySelector('.js-col-toggle-reset');
if (resetBtn) {
resetBtn.addEventListener('click', function() {
hiddenCols = [];
writeJson(colsKey, hiddenCols);
applyHiddenCols(hiddenCols);
});
}
root.querySelectorAll('.js-per-page-select').forEach(function(select) {
select.addEventListener('change', function() {
var form = select.closest('form');
if (form) form.submit();
});
});
var clearBtn = root.querySelector('.js-table-filters-clear');
if (clearBtn) {
clearBtn.addEventListener('click', function() {
try {
localStorage.removeItem(queryKey);
sessionStorage.setItem(clearKey, '1');
} catch (e) {}
});
}
root.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;
event.preventDefault();
var title = form.getAttribute('data-alert-confirm-title') || 'Potwierdzenie';
var confirmYes = form.getAttribute('data-alert-confirm-yes') || 'Potwierdz';
var confirmNo = form.getAttribute('data-alert-confirm-no') || 'Anuluj';
if (window.OrderProAlerts && typeof window.OrderProAlerts.confirm === 'function') {
window.OrderProAlerts.confirm({
title: title,
message: message,
confirmLabel: confirmYes,
cancelLabel: confirmNo,
danger: true
}).then(function(accepted) {
if (!accepted) return;
form.setAttribute('data-confirmed', '1');
form.submit();
});
return;
}
if (window.confirm(message)) {
form.setAttribute('data-confirmed', '1');
form.submit();
}
});
try {
var query = window.location.search ? window.location.search.substring(1) : '';
var justCleared = sessionStorage.getItem(clearKey) === '1';
sessionStorage.removeItem(clearKey);
if (query) {
localStorage.setItem(queryKey, query);
} else if (!justCleared) {
var saved = localStorage.getItem(queryKey);
if (saved) window.location.replace(basePath + '?' + saved);
}
} catch (e) {}
})();
</script>