const currentUrl = window.location.href.split('#')[0]; // odcinamy część z hash const patterns = [ /^https:\/\/projectpro\.apilo\.com\/order\/order\/news\/?$/, /^https:\/\/projectpro\.apilo\.com\/order\/order\/in-progress\/?$/, /^https:\/\/projectpro\.apilo\.com\/order\/order\/to-send\/?$/, /^https:\/\/projectpro\.apilo\.com\/order\/order\/completed\/?$/, /^https:\/\/projectpro\.apilo\.com\/order\/order\/status\/?$/, /^https:\/\/projectpro\.apilo\.com\/order\/order\/(news|in-progress|to-send|completed|all)\/?$/, /^https:\/\/projectpro\.apilo\.com\/order\/order\/status\/[^\/?#]+\/?$/ ]; if (patterns.some(pattern => pattern.test(currentUrl))) { console.log('test'); waitForTableAndSetImage(); attachTableReloadListener(); } else { console.log('Nie pasuje do żadnego wzorca URL'); } // --- 2) Czekanie na tabelę i start przetwarzania --- function waitForTableAndSetImage() { const start = Date.now(); const maxWait = 10000; // 10s const intervalId = setInterval(() => { const tbody = document.querySelector('#DataTables_Table_0 tbody'); if (tbody && tbody.querySelector('tr')) { clearInterval(intervalId); setImageToProduct(); } else if (Date.now() - start > maxWait) { clearInterval(intervalId); } }, 120); } // --- 3) Obserwator zmian w tabeli (przeładowanie/paginacja) --- function attachTableReloadListener() { const tbody = document.querySelector('#DataTables_Table_0 tbody'); if (!tbody) return; const observer = new MutationObserver(mutations => { for (const m of mutations) { if (m.type === 'childList') { setImageToProduct(); break; } } }); observer.observe(tbody, { childList: true, subtree: false }); } // --- 4) Główny worker: wstawianie miniatur wg SKU --- const imgCache = new Map(); // SKU -> imgURL const previewState = { largeImg: null, sourceImg: null, onMove: null }; let previewGuardsAttached = false; function hideLargePreview() { if (previewState.onMove) { document.removeEventListener('mousemove', previewState.onMove); } if (previewState.largeImg) { previewState.largeImg.remove(); } previewState.largeImg = null; previewState.sourceImg = null; previewState.onMove = null; } function ensurePreviewGuardListeners() { if (previewGuardsAttached) return; previewGuardsAttached = true; window.addEventListener('blur', hideLargePreview); document.addEventListener('visibilitychange', () => { if (document.hidden) hideLargePreview(); }); document.addEventListener('scroll', hideLargePreview, true); } function setImageToProduct() { hideLargePreview(); const tbody = document.querySelector('#DataTables_Table_0 tbody'); if (!tbody) return; const rows = Array.from(tbody.querySelectorAll('tr')); rows.forEach(tr => { const cells = tr.querySelectorAll('td'); if (cells.length < 4) return; // Kolumna 2 zawiera info z domeną (wklejone w tym samym TD co numer zamówienia itp.) const domain = detectDomainFromCell(cells[1]); if (!domain) return; // Kolumna 4: "Dane produktu" const productsCell = cells[3]; // ============ POPRAWIONY FRAGMENT ============ // Każdy produkt:
...
const productBlocks = productsCell.querySelectorAll('[data-item="all-products"] [data-item="product"]'); productBlocks.forEach(block => { // nie rób drugi raz if (block.dataset.imgInserted === '1') return; // Struktura: [data-item="product"] > .d-flex.mb-2 > [imgHolder DIV] + [dataHolder DIV] const flex = block.querySelector(':scope > .d-flex.mb-2') || block.querySelector('.d-flex.mb-2') || block.firstElementChild; // awaryjnie, gdyby klasy się zmieniły if (!flex) return; const imgHolder = flex.children?.[0]; //
const dataHolder = flex.children?.[1]; //
z nazwą, SKU, EAN, ceną if (!imgHolder || !dataHolder) return; // Jeśli już jest w imgHolder, pomijamy if (imgHolder.querySelector('img')) { block.dataset.imgInserted = '1'; return; } // Znajdź konkretnie DIV z SKU (bez mieszania z innymi liniami) const skuDiv = Array.from(dataHolder.querySelectorAll('div')) .find(d => /SKU\s*:/i.test(d.textContent || '')); const skuMatch = (skuDiv?.textContent || '').match(/SKU\s*:\s*([A-Za-z0-9_-]+)/i); const sku = skuMatch?.[1]?.toUpperCase(); if (!sku) return; const placeImage = (imgUrl) => { if (!imgUrl) return; // czyścimy ikonę i wstawiamy miniaturę imgHolder.innerHTML = ''; const imgEl = makeImg(imgUrl); imgHolder.appendChild(imgEl); setupPreview(imgEl, imgUrl); block.dataset.imgInserted = '1'; }; if (imgCache.has(sku)) { placeImage(imgCache.get(sku)); } else { getProductData(sku, domain) .then(url => { if (url) imgCache.set(sku, url); placeImage(url); }) .catch(() => { }); } }); }); } function detectDomainFromCell(td) { const text = (td.textContent || '').toLowerCase(); if (text.includes('marianek.pl')) return 'marianek.pl'; if (text.includes('pomysloweprezenty.pl')) return 'pomysloweprezenty.pl'; return null; } function makeImg(src) { const img = document.createElement('img'); img.src = src; img.alt = 'product'; img.className = 'img-fluid center-block'; img.style.maxWidth = '48px'; img.style.maxHeight = '48px'; img.style.objectFit = 'contain'; img.style.cursor = 'zoom-in'; return img; } // --- 5) Podgląd dużego obrazka --- function setupPreview(imgElement, src) { ensurePreviewGuardListeners(); const onMove = (ev) => { if (!previewState.largeImg) return; if (!previewState.sourceImg || !previewState.sourceImg.isConnected || !previewState.sourceImg.matches(':hover')) { hideLargePreview(); return; } const pad = 10; previewState.largeImg.style.top = (ev.pageY - previewState.largeImg.height / 2) + 'px'; previewState.largeImg.style.left = (ev.pageX + pad) + 'px'; }; const onOver = (ev) => { hideLargePreview(); const largeImg = document.createElement('img'); largeImg.id = 'largeImagePreview'; largeImg.src = src; largeImg.style.position = 'absolute'; largeImg.style.maxWidth = '400px'; largeImg.style.maxHeight = '400px'; largeImg.style.border = '1px solid #ccc'; largeImg.style.background = '#fff'; largeImg.style.zIndex = '10000'; largeImg.style.pointerEvents = 'none'; document.body.appendChild(largeImg); previewState.largeImg = largeImg; previewState.sourceImg = imgElement; previewState.onMove = onMove; onMove(ev); document.addEventListener('mousemove', onMove); }; const onOut = () => hideLargePreview(); imgElement.addEventListener('mouseenter', onOver); imgElement.addEventListener('mouseout', onOut); imgElement.addEventListener('mouseleave', onOut); } // --- 6) API: pobranie URL obrazka po SKU i domenie --- async function getProductData(sku, domain) { let url = null; if (domain === 'marianek.pl') { url = `https://marianek.pl/api/v1/product.php?sku=${encodeURIComponent(sku)}`; } else if (domain === 'pomysloweprezenty.pl') { url = `https://pomysloweprezenty.pl/api/v1/product.php?sku=${encodeURIComponent(sku)}`; } else { return null; } try { const resp = await fetch(url, { credentials: 'omit' }); if (!resp.ok) { throw new Error(`HTTP error! status: ${resp.status}`); } const data = await resp.json(); // zakładam, że API zwraca { img: "https://..." } return data?.img || null; } catch (err) { console.error('Error fetching product data:', url, err); return null; } } const currentUrl2 = window.location.href; const pattern = /^https:\/\/projectpro\.apilo\.com\/warehouse\/shipment\/new-for-order\/.+/; if (pattern.test(currentUrl2)) { const portletBody = document.querySelector('.kt-portlet__body'); if (portletBody) { const buttonContainer = document.createElement('div'); buttonContainer.className = 'custom-button-container'; buttonContainer.style.display = 'flex'; buttonContainer.style.gap = '10px'; buttonContainer.style.marginBottom = '15px'; portletBody.parentNode.insertBefore(buttonContainer, portletBody); const buttonP2D = createButton('Inpost P2D', '#007bff', 'P2D.inpost', 'RZE14N||RZE14N'); const buttonD2D = createButton('Inpost D2D', '#ff7800', 'D2D.inpostkurier'); const buttonD2P = createButton('Inpost D2P', '#28a745', 'D2P.inpost'); const buttonP2P = createButton('Inpost P2P', '#ffc107', 'P2P.inpost', 'RZE14N||RZE14N'); const buttonD2Dapaczka = createButton('D2D Apaczka', '#ff7800', 'D2D.apaczka'); const buttonD2PApaczka = createButton('D2P Apaczka', '#28a745', 'D2P.apaczka'); const buttonP2Papaczka = createButton('P2P Apaczka', '#ffc107', 'P2P.apaczka'); const buttonOrlen = createButton('Orlen', 'rgb(255, 7, 193)', 'P2P.orlen'); // buttonContainer.appendChild(buttonP2D); buttonContainer.appendChild(buttonD2Dapaczka); buttonContainer.appendChild(buttonD2PApaczka); buttonContainer.appendChild(buttonP2Papaczka); buttonContainer.appendChild(buttonOrlen); // buttonContainer.appendChild(buttonD2D); // buttonContainer.appendChild(buttonD2P); // buttonContainer.appendChild(buttonP2P); } } function createButton(text, backgroundColor, method, dropoffPoint = null) { const button = document.createElement('button'); button.textContent = text; button.style.background = backgroundColor; button.style.display = 'inline-flex'; button.style.width = '200px'; button.style.height = '40px'; button.style.alignItems = 'center'; button.style.justifyContent = 'center'; button.style.color = '#FFF'; button.style.border = 'none'; button.style.cursor = 'pointer'; button.addEventListener('click', () => handleShipment(method, dropoffPoint)); return button; } async function handleShipment(method, dropoffPoint = null) { try { await selectPackageType(method); await setShipmentMethod(method); if (dropoffPoint) { await setDropoffPoint(dropoffPoint); } await setContent(method); await setParcelWeight('1'); await submitShipment(); } catch (error) { console.error('Wystąpił błąd: ', error); } } function retryUntilSuccess(fn, interval = 1000, retries = 10) { return new Promise((resolve, reject) => { const attempt = async () => { try { const result = await fn(); resolve(result); } catch (err) { if (retries === 0) { reject(err); } else { setTimeout(() => { retries--; attempt(); }, interval); } } }; attempt(); }); } function setContent(method) { if (method == 'D2D.apaczka' || method == 'D2P.apaczka' || method == 'P2P.apaczka' || method == 'P2P.orlen') { return retryUntilSuccess(() => { return new Promise((resolve, reject) => { const selectElement = document.getElementById('warehousebundle_shipment_preferences_content'); selectElement.value = 'prezent'; const event = document.createEvent('HTMLEvents'); event.initEvent('change', true, false); selectElement.dispatchEvent(event); resolve(); }); }); } } function selectPackageType(method) { return retryUntilSuccess(() => { return new Promise((resolve, reject) => { if (method == 'P2P.orlen') { //warehousebundle_shipment_carrierAccount const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount'); selectElement.value = 17; const event = document.createEvent('HTMLEvents'); event.initEvent('change', true, false); selectElement.dispatchEvent(event); // settimeout setTimeout(() => { const selectElement2 = document.getElementById('warehousebundle_shipment_method'); selectElement2.value = 50; const event2 = document.createEvent('HTMLEvents'); event2.initEvent('change', true, false); selectElement2.dispatchEvent(event2); // settimeout setTimeout(() => { const selectElement3 = document.getElementById('warehousebundle_shipment_preferences_packageType'); selectElement3.value = 'PACZKA'; const event3 = document.createEvent('HTMLEvents'); event3.initEvent('change', true, false); selectElement3.dispatchEvent(event3); resolve(); }, 1000); }, 1000); } else if (method == 'D2P.apaczka' || method == 'P2P.apaczka') { //warehousebundle_shipment_carrierAccount const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount'); selectElement.value = 17; const event = document.createEvent('HTMLEvents'); event.initEvent('change', true, false); selectElement.dispatchEvent(event); // settimeout setTimeout(() => { const selectElement2 = document.getElementById('warehousebundle_shipment_method'); selectElement2.value = 41; const event2 = document.createEvent('HTMLEvents'); event2.initEvent('change', true, false); selectElement2.dispatchEvent(event2); // settimeout setTimeout(() => { const selectElement3 = document.getElementById('warehousebundle_shipment_preferences_packageType'); selectElement3.value = 'PACZKA'; const event3 = document.createEvent('HTMLEvents'); event3.initEvent('change', true, false); selectElement3.dispatchEvent(event3); resolve(); }, 1000); }, 1000); } else if (method == 'D2D.apaczka') { const selectElement = document.getElementById('warehousebundle_shipment_carrierAccount'); selectElement.value = 17; const event = document.createEvent('HTMLEvents'); event.initEvent('change', true, false); selectElement.dispatchEvent(event); // settimeout setTimeout(() => { const selectElement2 = document.getElementById('warehousebundle_shipment_method'); selectElement2.value = 42; const event2 = document.createEvent('HTMLEvents'); event2.initEvent('change', true, false); selectElement2.dispatchEvent(event2); // settimeout setTimeout(() => { const selectElement3 = document.getElementById('warehousebundle_shipment_preferences_packageType'); selectElement3.value = 'PACZKA'; const event3 = document.createEvent('HTMLEvents'); event3.initEvent('change', true, false); selectElement3.dispatchEvent(event3); resolve(); }, 1000); }, 1000); } else { const selectElement = document.getElementById('warehousebundle_shipment_packageType'); if (selectElement) { selectElement.value = 'package'; const event = document.createEvent('HTMLEvents'); event.initEvent('change', true, false); selectElement.dispatchEvent(event); resolve(); } else { reject('Nie znaleziono elementu packageType'); } } }); }); } function setShipmentMethod(method) { if (method == 'D2D.apaczka' || method == 'D2P.apaczka' || method == 'P2P.apaczka' || method == 'P2P.orlen') { return new Promise((resolve, reject) => { resolve(); }); } return retryUntilSuccess(() => { return new Promise((resolve, reject) => { const methodElement = document.getElementById('warehousebundle_shipment_method'); if (methodElement) { methodElement.value = method; const methodEvent = document.createEvent('HTMLEvents'); methodEvent.initEvent('change', true, false); methodElement.dispatchEvent(methodEvent); resolve(); } else { reject('Nie znaleziono elementu shipment_method'); } }); }); } function setDropoffPoint(dropoffPoint) { return retryUntilSuccess(() => { return new Promise((resolve, reject) => { const dropoffPointElement = document.getElementById('warehousebundle_shipment_preferences_dropoffPoint'); if (dropoffPointElement) { dropoffPointElement.value = dropoffPoint; const dropoffPointEvent = document.createEvent('HTMLEvents'); dropoffPointEvent.initEvent('change', true, false); dropoffPointElement.dispatchEvent(dropoffPointEvent); resolve(); } else { reject('Nie znaleziono elementu dropoffPoint'); } }); }); } function setParcelWeight(weight) { return retryUntilSuccess(() => { return new Promise((resolve, reject) => { const weightElement = document.getElementById('warehousebundle_shipment_shipmentParcels_0_weight'); if (weightElement) { weightElement.value = weight; const weightEvent = document.createEvent('HTMLEvents'); weightEvent.initEvent('change', true, false); weightElement.dispatchEvent(weightEvent); resolve(); } else { reject('Nie znaleziono elementu shipmentParcels_0_weight'); } }); }); } function submitShipment() { return retryUntilSuccess(() => { return new Promise((resolve, reject) => { const submitButton = document.getElementById('warehousebundle_shipment_buttons_submit'); if (submitButton) { submitButton.click(); resolve(); } else { reject('Nie znaleziono przycisku submit'); } }); }); }