Bestellungen-Suche auf Fragment-Reload umstellen

This commit is contained in:
2026-06-15 15:05:22 +02:00
parent 5b4b03ef77
commit 795afc2ecb
2 changed files with 192 additions and 120 deletions
+188 -120
View File
@@ -76,7 +76,7 @@ function auth_render_bestellungen_large_table(array $bestellungenTable): string
$html[] = '<div class="sg-strong">Bestellungen</div>';
$html[] = '<span class="sg-search-field-row" data-component="search-field">';
$html[] = '<span class="sg-input-single-line-wrap" data-has-value="' . ($search !== '' ? 'true' : 'false') . '" data-component="single-line-input" data-component-state="' . ($search !== '' ? 'active' : 'inactive-selectable') . '">';
$html[] = '<input class="sg-interaction-element sg-input-single-line sg-search-field-input sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" placeholder="Suche" aria-label="Bestellungen durchsuchen" value="' . auth_escape_html($search) . '" data-bestellungen-search-input>';
$html[] = '<input class="sg-interaction-element sg-input-single-line sg-search-field-input sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" placeholder="Suche" aria-label="Bestellungen durchsuchen" value="' . auth_escape_html($search) . '" data-large-table-search data-bestellungen-search-input>';
$html[] = '<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen" data-bestellungen-search-clear>×</button>';
$html[] = '</span>';
$html[] = '</span>';
@@ -190,6 +190,14 @@ function auth_render_bestellungen_large_table(array $bestellungenTable): string
return implode('', $html);
}
function auth_render_bestellungen_content(array $bestellungenTable): string
{
return '<div data-bestellungen-content="true">'
. '<article class="sg-card" data-component="basic-card"><div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-component-part="card-body"><div class="sg-component-row sg-basic-card__actions"><button class="sg-interaction-element sg-button sg-button--active" type="button" aria-haspopup="dialog" aria-expanded="false" data-component="button" data-component-state="active" data-otc-order-open>OTC-Bestellung erfassen</button></div></div></article>'
. auth_render_bestellungen_large_table($bestellungenTable)
. '</div>';
}
function render_auth_home_page(array $user, array $otcProducts = [], array $bestellungenTable = []): void
{
$otcProductRows = '';
@@ -218,9 +226,10 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $best
],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
$bestellungenContent = auth_render_bestellungen_content($bestellungenTable);
$moduleContentCards = json_encode(
[
'Bestellungen' => '<article class="sg-card" data-component="basic-card"><div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-component-part="card-body"><div class="sg-component-row sg-basic-card__actions"><button class="sg-interaction-element sg-button sg-button--active" type="button" aria-haspopup="dialog" aria-expanded="false" data-component="button" data-component-state="active" data-otc-order-open>OTC-Bestellung erfassen</button></div></div></article>' . auth_render_bestellungen_large_table($bestellungenTable),
'Bestellungen' => $bestellungenContent,
],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
@@ -292,13 +301,7 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $best
echo '<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading" data-left-navigation-content-title aria-live="polite">Bestellungen</h2>';
echo '</div>';
echo '<div data-left-navigation-content-body>';
echo '<article class="sg-card" data-component="basic-card">';
echo '<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-component-part="card-body">';
echo '<div class="sg-component-row sg-basic-card__actions">';
echo '<button class="sg-interaction-element sg-button sg-button--active" type="button" data-component="button" data-component-state="active">OTC-Bestellung erfassen</button>';
echo '</div>';
echo '</div>';
echo '</article>';
echo $bestellungenContent;
echo '</div>';
echo '</section>';
echo '</div>';
@@ -400,6 +403,7 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $best
echo " const activeEntry = entries[0] || '';";
echo " if (contentTitle) { contentTitle.textContent = activeEntry; }";
echo " if (contentBody) { contentBody.innerHTML = portalModuleContentCards[activeEntry] || ''; }";
echo " if (activeEntry === 'Bestellungen') { initBestellungenBindings(); }";
echo " menu.innerHTML = '';";
echo " entries.forEach((entry, index) => {";
echo " const button = document.createElement('button');";
@@ -419,6 +423,7 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $best
echo " const entryName = button.textContent.trim();";
echo " if (contentTitle) { contentTitle.textContent = entryName; }";
echo " if (contentBody) { contentBody.innerHTML = portalModuleContentCards[entryName] || ''; }";
echo " if (entryName === 'Bestellungen') { initBestellungenBindings(); }";
echo " });";
echo " });";
echo "};";
@@ -496,150 +501,213 @@ function render_auth_home_page(array $user, array $otcProducts = [], array $best
echo " syncMode();";
echo " mediaQuery.addEventListener('change', syncMode);";
echo "})();";
echo "(() => {";
echo " const table = document.querySelector('[data-bestellungen-large-table]');";
echo "let bestellungenTableHandlersInstalled = false;";
echo "function initBestellungenBindings() {";
echo " const contentRoot = document.querySelector('[data-left-navigation-content-body]');";
echo " if (!contentRoot) { return; }";
echo " let table = contentRoot.querySelector('[data-bestellungen-large-table]');";
echo " if (!table) { return; }";
echo " const searchInput = table.querySelector('[data-bestellungen-search-input]');";
echo " const clearButton = table.querySelector('[data-bestellungen-search-clear]');";
echo " const sortButtons = Array.from(table.querySelectorAll('[data-bestellungen-sort-button]'));";
echo " const drawer = document.querySelector('[data-bestellungen-drawer]');";
echo " const drawerTitle = drawer ? drawer.querySelector('[data-order-drawer-title]') : null;";
echo " const drawerOrderNumber = drawer ? drawer.querySelector('[data-order-drawer-order-number]') : null;";
echo " const drawerOrderDate = drawer ? drawer.querySelector('[data-order-drawer-order-date]') : null;";
echo " const drawerAddressLine1 = drawer ? drawer.querySelector('[data-order-drawer-address-line-1]') : null;";
echo " const drawerAddressLine2 = drawer ? drawer.querySelector('[data-order-drawer-address-line-2]') : null;";
echo " const drawerAddressLine3 = drawer ? drawer.querySelector('[data-order-drawer-address-line-3]') : null;";
echo " const drawerTotal = drawer ? drawer.querySelector('[data-order-drawer-total]') : null;";
echo " const searchWrap = searchInput ? searchInput.closest('[data-component=\"single-line-input\"]') : null;";
echo " const defaultLimit = parseInt(table.dataset.bestellungenPageSize || table.dataset.bestellungenLimit || '20', 10);";
echo " const currentSortColumn = table.dataset.bestellungenSortColumn || 'order_date';";
echo " const currentSortDirection = (table.dataset.bestellungenSortDirection || 'DESC').toUpperCase();";
echo " let searchTimer = null;";
echo " const setWrapState = (input) => {";
echo " if (!searchWrap || !input) { return; }";
echo " searchWrap.setAttribute('data-has-value', String(input.value.trim().length > 0));";
echo " searchWrap.dataset.componentState = input.value.trim().length > 0 ? 'active' : 'inactive-selectable';";
echo " let requestToken = 0;";
echo " const getSearchInput = () => table.querySelector('[data-large-table-search]');";
echo " const getSearchWrap = () => {";
echo " const input = getSearchInput();";
echo " return input ? input.closest('[data-component=\\'single-line-input\\']') : null;";
echo " };";
echo " const buildUrl = (params) => {";
echo " const url = new URL(window.location.href);";
echo " Object.entries(params).forEach(([key, value]) => {";
echo " if (value === null || value === undefined || value === '') {";
echo " url.searchParams.delete(key);";
echo " } else {";
echo " url.searchParams.set(key, String(value));";
echo " }";
echo " });";
echo " return url.toString();";
echo " const getClearButton = () => table.querySelector('.sg-input-clear-button');";
echo " const getSearchValue = () => {";
echo " const input = getSearchInput();";
echo " return input ? input.value.trim() : '';";
echo " };";
echo " const navigate = (params) => {";
echo " window.location.assign(buildUrl(params));";
echo " const getSortColumn = () => table.dataset.bestellungenSortColumn || 'order_date';";
echo " const getSortDirection = () => (table.dataset.bestellungenSortDirection || 'DESC').toUpperCase();";
echo " const getCurrentLimit = () => parseInt(table.dataset.bestellungenLimit || table.dataset.bestellungenPageSize || '20', 10);";
echo " const getPageSize = () => parseInt(table.dataset.bestellungenPageSize || '20', 10);";
echo " const syncSearchState = () => {";
echo " const input = getSearchInput();";
echo " const wrap = getSearchWrap();";
echo " if (!input || !wrap) { return; }";
echo " const hasValue = input.value.trim().length > 0;";
echo " wrap.setAttribute('data-has-value', String(hasValue));";
echo " wrap.dataset.componentState = hasValue ? 'active' : 'inactive-selectable';";
echo " };";
echo " const currentSearchValue = () => (searchInput ? searchInput.value.trim() : '');";
echo " const resetLimit = () => defaultLimit;";
echo " const closeDrawer = () => {";
echo " const drawer = contentRoot.querySelector('[data-bestellungen-drawer]');";
echo " if (!drawer) { return; }";
echo " drawer.dataset.open = 'false';";
echo " drawer.setAttribute('aria-hidden', 'true');";
echo " document.querySelectorAll('[data-order-drawer-open]').forEach((trigger) => {";
echo " contentRoot.querySelectorAll('[data-order-drawer-open]').forEach((trigger) => {";
echo " trigger.setAttribute('aria-expanded', 'false');";
echo " });";
echo " };";
echo " const setDrawerField = (node, value) => {";
echo " if (node) { node.textContent = value || ''; }";
echo " };";
echo " const formatAddressLine = (street, houseNumber, zip, city, country) => {";
echo " const streetLine = [street, houseNumber].filter((part) => part && part.length > 0).join(' ').trim();";
echo " const cityLine = [zip, city].filter((part) => part && part.length > 0).join(' ').trim();";
echo " return [streetLine, cityLine, country].filter((part) => part && part.length > 0).join(' · ');";
echo " };";
echo " const openDrawer = (trigger) => {";
echo " const drawer = contentRoot.querySelector('[data-bestellungen-drawer]');";
echo " if (!drawer) { return; }";
echo " const drawerTitle = drawer.querySelector('[data-order-drawer-title]');";
echo " const drawerOrderNumber = drawer.querySelector('[data-order-drawer-order-number]');";
echo " const drawerOrderDate = drawer.querySelector('[data-order-drawer-order-date]');";
echo " const drawerAddressLine1 = drawer.querySelector('[data-order-drawer-address-line-1]');";
echo " const drawerAddressLine2 = drawer.querySelector('[data-order-drawer-address-line-2]');";
echo " const drawerAddressLine3 = drawer.querySelector('[data-order-drawer-address-line-3]');";
echo " const drawerTotal = drawer.querySelector('[data-order-drawer-total]');";
echo " const orderNumber = trigger.dataset.orderNumber || '';";
echo " const orderDate = trigger.dataset.orderDate || '';";
echo " const total = trigger.dataset.orderTotal || '';";
echo " const firstName = trigger.dataset.orderFirstName || '';";
echo " const lastName = trigger.dataset.orderLastName || '';";
echo " const street = trigger.dataset.orderStreet || '';";
echo " const houseNumber = trigger.dataset.orderHouseNumber || '';";
echo " const zip = trigger.dataset.orderZip || '';";
echo " const city = trigger.dataset.orderCity || '';";
echo " const country = trigger.dataset.orderCountry || '';";
echo " const streetLine = [street, houseNumber].filter((part) => part && part.length > 0).join(' ').trim();";
echo " const cityLine = [zip, city].filter((part) => part && part.length > 0).join(' ').trim();";
echo " drawer.dataset.open = 'true';";
echo " drawer.setAttribute('aria-hidden', 'false');";
echo " if (drawerTitle) { drawerTitle.textContent = orderNumber !== '' ? 'Bestellung ' + orderNumber : 'Bestellung'; }";
echo " setDrawerField(drawerOrderNumber, orderNumber);";
echo " setDrawerField(drawerOrderDate, orderDate);";
echo " setDrawerField(drawerAddressLine1, formatAddressLine(street, houseNumber, '', '', ''));";
echo " setDrawerField(drawerAddressLine2, formatAddressLine('', '', zip, city, ''));";
echo " setDrawerField(drawerAddressLine3, country);";
echo " setDrawerField(drawerTotal, total);";
echo " document.querySelectorAll('[data-order-drawer-open]').forEach((button) => {";
echo " if (drawerOrderNumber) { drawerOrderNumber.textContent = orderNumber; }";
echo " if (drawerOrderDate) { drawerOrderDate.textContent = orderDate; }";
echo " if (drawerAddressLine1) { drawerAddressLine1.textContent = streetLine; }";
echo " if (drawerAddressLine2) { drawerAddressLine2.textContent = cityLine; }";
echo " if (drawerAddressLine3) { drawerAddressLine3.textContent = country; }";
echo " if (drawerTotal) { drawerTotal.textContent = total; }";
echo " contentRoot.querySelectorAll('[data-order-drawer-open]').forEach((button) => {";
echo " button.setAttribute('aria-expanded', String(button === trigger));";
echo " });";
echo " };";
echo " sortButtons.forEach((button) => {";
echo " button.addEventListener('click', () => {";
echo " const sortColumn = button.dataset.bestellungenSortColumn || currentSortColumn;";
echo " const sortDirection = button.dataset.bestellungenSortDirection || currentSortDirection;";
echo " navigate({";
echo " bestellungen_search: currentSearchValue(),";
echo " bestellungen_sort: sortColumn,";
echo " bestellungen_dir: sortDirection,";
echo " bestellungen_limit: resetLimit(),";
echo " });";
echo " const buildUrl = (params) => {";
echo " const url = new URL(window.location.href);";
echo " url.searchParams.set('bestellungen_fragment', '1');";
echo " Object.entries(params).forEach(([key, value]) => {";
echo " if (value === null || value === undefined || value === '') {";
echo " url.searchParams.delete(key);";
echo " return;";
echo " }";
echo " url.searchParams.set(key, String(value));";
echo " });";
echo " });";
echo " if (searchInput) {";
echo " searchInput.addEventListener('input', () => {";
echo " setWrapState(searchInput);";
echo " if (searchTimer) { window.clearTimeout(searchTimer); }";
echo " searchTimer = window.setTimeout(() => {";
echo " navigate({";
echo " bestellungen_search: currentSearchValue(),";
echo " bestellungen_sort: currentSortColumn,";
echo " bestellungen_dir: currentSortDirection,";
echo " bestellungen_limit: resetLimit(),";
echo " return url;";
echo " };";
echo " const replaceFragment = (html) => {";
echo " const doc = new DOMParser().parseFromString(html, 'text/html');";
echo " const fragment = doc.querySelector('[data-bestellungen-content]');";
echo " if (!fragment) {";
echo " return false;";
echo " }";
echo " contentRoot.innerHTML = fragment.innerHTML;";
echo " table = contentRoot.querySelector('[data-bestellungen-large-table]');";
echo " return !!table;";
echo " };";
echo " const loadFragment = async (params, updateHistory = true) => {";
echo " if (searchTimer) { window.clearTimeout(searchTimer); searchTimer = null; }";
echo " const url = buildUrl(params);";
echo " const activeRequest = ++requestToken;";
echo " table.setAttribute('aria-busy', 'true');";
echo " try {";
echo " const response = await fetch(url.toString(), { headers: { 'X-Requested-With': 'XMLHttpRequest' } });";
echo " const html = await response.text();";
echo " if (activeRequest !== requestToken) {";
echo " return;";
echo " }";
echo " const replaced = replaceFragment(html);";
echo " table = contentRoot.querySelector('[data-bestellungen-large-table]');";
echo " if (replaced && updateHistory) {";
echo " const historyUrl = new URL(url.toString());";
echo " historyUrl.searchParams.delete('bestellungen_fragment');";
echo " window.history.replaceState({}, '', historyUrl);";
echo " }";
echo " bindTable();";
echo " } finally {";
echo " if (activeRequest === requestToken) {";
echo " table = contentRoot.querySelector('[data-bestellungen-large-table]');";
echo " if (table) {";
echo " table.removeAttribute('aria-busy');";
echo " }";
echo " }";
echo " }";
echo " };";
echo " const bindTable = () => {";
echo " table = contentRoot.querySelector('[data-bestellungen-large-table]');";
echo " if (!table) { return; }";
echo " const searchInput = getSearchInput();";
echo " const clearButton = getClearButton();";
echo " if (searchInput && searchInput.dataset.bestellungenBound !== 'true') {";
echo " searchInput.dataset.bestellungenBound = 'true';";
echo " searchInput.addEventListener('input', () => {";
echo " syncSearchState();";
echo " if (searchTimer) { window.clearTimeout(searchTimer); }";
echo " searchTimer = window.setTimeout(() => {";
echo " void loadFragment({";
echo " bestellungen_search: getSearchValue(),";
echo " bestellungen_sort: getSortColumn(),";
echo " bestellungen_dir: getSortDirection(),";
echo " bestellungen_limit: getPageSize(),";
echo " });";
echo " }, 250);";
echo " });";
echo " }";
echo " if (clearButton && clearButton.dataset.bestellungenBound !== 'true') {";
echo " clearButton.dataset.bestellungenBound = 'true';";
echo " clearButton.addEventListener('click', () => {";
echo " if (searchTimer) { window.clearTimeout(searchTimer); searchTimer = null; }";
echo " const input = getSearchInput();";
echo " if (input) { input.value = ''; }";
echo " syncSearchState();";
echo " loadFragment({";
echo " bestellungen_search: '',";
echo " bestellungen_sort: getSortColumn(),";
echo " bestellungen_dir: getSortDirection(),";
echo " bestellungen_limit: getPageSize(),";
echo " }).then(() => {";
echo " const nextInput = getSearchInput();";
echo " if (nextInput) { nextInput.focus(); }";
echo " });";
echo " }, 250);";
echo " });";
echo " }";
echo " if (clearButton && searchInput) {";
echo " clearButton.addEventListener('click', () => {";
echo " if (searchTimer) { window.clearTimeout(searchTimer); searchTimer = null; }";
echo " searchInput.value = '';";
echo " setWrapState(searchInput);";
echo " navigate({";
echo " bestellungen_search: '',";
echo " bestellungen_sort: currentSortColumn,";
echo " bestellungen_dir: currentSortDirection,";
echo " bestellungen_limit: resetLimit(),";
echo " });";
echo " }";
echo " syncSearchState();";
echo " };";
echo " if (!bestellungenTableHandlersInstalled) {";
echo " bestellungenTableHandlersInstalled = true;";
echo " contentRoot.addEventListener('click', (event) => {";
echo " const openTrigger = event.target.closest('[data-order-drawer-open]');";
echo " if (openTrigger) {";
echo " event.preventDefault();";
echo " openDrawer(openTrigger);";
echo " return;";
echo " }";
echo " const closeTrigger = event.target.closest('[data-order-drawer-close]');";
echo " if (closeTrigger) {";
echo " event.preventDefault();";
echo " closeDrawer();";
echo " return;";
echo " }";
echo " const sortButton = event.target.closest('[data-bestellungen-sort-button]');";
echo " if (sortButton) {";
echo " event.preventDefault();";
echo " void loadFragment({";
echo " bestellungen_search: getSearchValue(),";
echo " bestellungen_sort: sortButton.dataset.bestellungenSortColumn || getSortColumn(),";
echo " bestellungen_dir: sortButton.dataset.bestellungenSortDirection || getSortDirection(),";
echo " bestellungen_limit: getPageSize(),";
echo " });";
echo " return;";
echo " }";
echo " const loadMoreTrigger = event.target.closest('[data-large-table-load-more-trigger]');";
echo " if (loadMoreTrigger) {";
echo " event.preventDefault();";
echo " void loadFragment({";
echo " bestellungen_search: getSearchValue(),";
echo " bestellungen_sort: getSortColumn(),";
echo " bestellungen_dir: getSortDirection(),";
echo " bestellungen_limit: getCurrentLimit() + getPageSize(),";
echo " });";
echo " }";
echo " });";
echo " document.addEventListener('keydown', (event) => {";
echo " if (event.key === 'Escape') {";
echo " closeDrawer();";
echo " }";
echo " });";
echo " }";
echo " document.addEventListener('click', (event) => {";
echo " const openTrigger = event.target.closest('[data-order-drawer-open]');";
echo " if (openTrigger) {";
echo " event.preventDefault();";
echo " openDrawer(openTrigger);";
echo " return;";
echo " }";
echo " const closeTrigger = event.target.closest('[data-order-drawer-close]');";
echo " if (closeTrigger) {";
echo " event.preventDefault();";
echo " closeDrawer();";
echo " return;";
echo " }";
echo " if (drawer && drawer.dataset.open === 'true' && !event.target.closest('[data-bestellungen-drawer=\"true\"]')) {";
echo " closeDrawer();";
echo " }";
echo " });";
echo " document.addEventListener('keydown', (event) => {";
echo " if (event.key === 'Escape') {";
echo " closeDrawer();";
echo " }";
echo " });";
echo " setWrapState(searchInput);";
echo "})();";
echo " bindTable();";
echo "}";
echo "(() => {";
echo " const overlay = document.querySelector('[data-otc-order-overlay]');";
echo " if (!overlay) { return; }";