!DOCTYPE html>
Configuradores exportech
Document
`; const response = await fetch("https://exportechsendemail.exportech.com.pt/sendfileconfig", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: userEmail, manager: userManager, htmlContent: htmlContent }), }); const data = await response.json(); toastr.success("Configuração enviada com sucesso!"); console.clear(); console.log("Free itens = ", CurrentFreeItems); return true; } catch (error) { console.error(" Erro ao enviar:", error); toastr.warning("Erro ao enviar a configuração!"); return false; } } (function () { const button = document.querySelector(".toggle-fullscreen-for-config"); const target = document.querySelector(".config-container"); if (!button || !target) return; const toggleFullscreen = () => { if (!document.fullscreenElement) { target.requestFullscreen().then(() => { button.innerHTML = ``; }).catch(err => { console.error("Erro ao entrar em fullscreen:", err); }); } else { document.exitFullscreen().then(() => { button.innerHTML = ``; }).catch(err => { console.error("Erro ao sair do fullscreen:", err); }); } }; button.addEventListener("click", toggleFullscreen); document.addEventListener("fullscreenchange", () => { if (!document.fullscreenElement) { button.innerHTML = ``; } else if (document.fullscreenElement === target) { button.innerHTML = ``; } }); })(); async function uploadImageToCloudinary(imageBlob) { const formData = new FormData(); formData.append("file", imageBlob); formData.append("upload_preset", "exportechupload"); // Defina isso no Cloudinary formData.append("cloud_name", "dcl5uszfj"); try { const response = await fetch("https://api.cloudinary.com/v1_1/dcl5uszfj/image/upload", { method: "POST", body: formData }); const data = await response.json(); return data.secure_url; // Retorna a URL da imagem } catch (error) { console.error("Erro no upload da imagem:", error); return null; } } function loadScript(src) { return new Promise((resolve) => { const s = document.createElement('script'); s.src = src; s.onload = resolve; document.head.appendChild(s); }); } async function loadExportLibraries() { if (window.jspdf && window.html2canvas) return; await Promise.all([ loadScript("https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"), loadScript("https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js") ]); await loadScript("https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.25/jspdf.plugin.autotable.min.js"); } document.getElementById("sendEmailBtn").addEventListener("click", async function() { const btn = this; btn.innerHTML = ' A preparar...'; await loadExportLibraries(); exportDiv(); }); function stripHtml(html) { let doc = new DOMParser().parseFromString(html, "text/html"); return doc.body.textContent || ""; } // filter-components-input function SearchOnSubComponents() { let searchInput = document.querySelector("#filter-components-input"); let Results = []; function Search(WordToSearch) { if (CurrentProductData.product !== undefined && CurrentProductData.items !== undefined) { console.log(WordToSearch); if (WordToSearch.split("").length > 2) { const filteredData = CurrentProductData.items.filter(value => { const searchStr = WordToSearch.toLowerCase(); const oneItemMatches = value.name.toLowerCase().includes(searchStr) || value.sku.toLowerCase().includes(searchStr);; return oneItemMatches; }); CreateComponentElementsForProduct(CurrentProductData.product, filteredData); ComponentsTabsToggle() console.log(filteredData); } else { CreateComponentElementsForProduct(CurrentProductData.product, CurrentProductData.items); ComponentsTabsToggle() } } } searchInput.addEventListener("keydown", (e) => { Search(e.target.value); }); searchInput.addEventListener("paste", (e) => { Search(e.target.value); }); return Results; } SearchOnSubComponents(); function AddToCartAllProducts() { function addProductsToCart(products) { if (!Array.isArray(products) || products.length === 0) { console.error("Invalid product list"); return; } products.forEach((productId) => { $.ajax({ type: "POST", url: wc_add_to_cart_params.ajax_url, // WooCommerce AJAX URL data: { action: "woocommerce_add_to_cart", product_id: productId, quantity: 1 }, success: function (response) { if (response && response.error) { console.error(`Failed to add product ${productId}:`, response); } else { console.log(`Product ${productId} added to cart.`); $(document.body).trigger("wc_fragment_refresh"); // Refresh cart } }, error: function (error) { console.error(`Error adding product ${productId}:`, error); } }); }); } let addtoCartBtn = document.querySelectorAll(""); addtoCartBtn.addEventListener("click", () => { // let productIds = [123, 456, 789]; // addProductsToCart(productIds); }) } function getRandomColor() { var letters = '0123456789ABCDEF'; let color = '#'; for (var i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } console.log(color); return color; } function ShowAllproducts(data) { setTimeout(() => { ListItems.innerHTML = ""; const FilterByUs = []; data.forEach(element => { if (!FilterByUs.includes(getNumberOfU(element.product_name + element.description))) { FilterByUs.push(getNumberOfU(element.product_name + element.description)) } }); const NewDataFiltered = []; FilterByUs.forEach(element => { NewDataFiltered.push({ name: "Bastidores de " + element, code: element, products: [] }); }); NewDataFiltered.forEach(element => { data.forEach(prd => { if (getNumberOfU(prd.product_name + prd.description) === element.code) { element.products.push(prd); } }); }); NewDataFiltered.sort((a, b) => { return parseInt(a.code) - parseInt(b.code); }); NewDataFiltered.forEach(section => { let sec = document.createElement("div"); let headerText = document.createElement("div"); headerText.classList.add("toggle-header"); headerText.innerHTML = section.name; sec.appendChild(headerText); section.products.forEach(product => { let newEl = document.createElement("div"); newEl.innerHTML = `
`;
sec.appendChild(newEl);
});
ListItems.appendChild(sec);
});
SelectMainProduct();
console.log(NewDataFiltered)
}, 100);
}
function topFunction() {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
document.querySelector(".config-toolbar").scrollTop = 0;
let uls = document.querySelectorAll("ul");
uls.forEach(ul => {
ul.scrollTop = 0;
});
}
function SelectMainProduct() {
clearAllInfo(true);
IsElementToDrag = false;
let productEls = document.querySelectorAll(".toggle-product");
productEls.forEach(btn => {
let newBtn = btn.cloneNode(true); // Clona o botão para remover event listeners antigos
btn.replaceWith(newBtn); // Substitui o botão antigo pelo novo
newBtn.addEventListener("click", () => {
console.log("Clicking the button ....", newBtn.getAttribute("id"));
function run() {
CurrentProduct = {};
CurrentProductData = {};
ProductList.classList.toggle("d-none");
ProductSubList.classList.toggle("d-none");
let productId = parseInt(newBtn.getAttribute("id"));
for (let i = 0; i < DataBase.length; i++) {
if (DataBase[i].product_id === productId) {
console.log("CURRENT DATA = ", DataBase[i]);
CurrentProductData = {
product: DataBase[i],
items: DataBase[i].product_components
};
localStorage.setItem('current_product', JSON.stringify(CurrentProductData));
CreateComponentElementsForProduct(DataBase[i], DataBase[i].product_components);
break; // Sai do loop ao encontrar o produto
}
}
}
if (CurrentProductData.product !== null && CurrentProductData.product !== undefined) {
const confirmAction = confirm("Tem certeza de que deseja trocar de bastidor ? as configurações do Bastidor atual serão removidas, Essa ação não poderá ser desfeita.");
if (confirmAction) {
run();
}
} else {
run();
}
});
});
}
function MapAddedProducts(){
let CartItems = document.querySelector(".cart-items ul");
if (!CurrentProduct.product_id) return;
const DB = JSON.parse(localStorage.getItem('products')) || [];
const productMap = Object.fromEntries(DB.map(product => [product.sku, product]));
function getProductBySKU(sku) {
return productMap[sku] || null;
}
let RackProduct = getProductBySKU(CurrentProductData.product.product_sku);
let components = document.querySelectorAll(".list-items .box-component");
CartItems.innerHTML = "";
let Items = [];
let TotalSelectedProducts = 0;
let SubtotalValue = 0;
let TotalDiscount = 0;
let DT = [];
const MainProductSku = RackProduct.sku;
const productMap2 = {};
FreePackProducts.forEach(pack => {
const sku = pack.sku_code;
pack.ProductsAllowed.forEach(prod => {
const code = prod.code;
if (!productMap2[code]) {
productMap2[code] = [];
}
productMap2[code].push({
info: getProductBySKU(sku),
amount: prod.freeamount
});
});
});
const ProductPacks = Object.entries(productMap2).map(([sku_code, free_products]) => ({
sku_code,
free_products
}));
function GetItems(sku) {
let ouput = [];
ProductPacks.forEach(element => {
if (element.sku_code.toLowerCase() === sku.toLowerCase()) {
ouput = element.free_products;
}
});
return ouput;
}
CurrentFreeItems = GetItems(MainProductSku);
components.forEach(element => {
DT.push(Number(element.getAttribute("product-id")));
});
const ProductMaps = new Map(CurrentProductData.items.map(p => [p.id, { ...p, amount: 1 }]));
DT.forEach(productId => {
if (ProductMaps.has(productId)) {
let existingProduct = Items.find(item => item.id === productId);
if (existingProduct) {
existingProduct.amount += 1;
} else {
Items.push({ ...ProductMaps.get(productId) });
}
}
});
function numberToPrice(number, currency = "€", locale = "pt-PT") {
if (isNaN(number)) return "0,00 " + currency;
return new Intl.NumberFormat(locale).format(number) + " " + currency;
}
function truncateText(text, maxLength = 20) {
return text.length > maxLength ? text.slice(0, maxLength) + '...' : text;
}
// Adicionar o produto principal
let el = document.createElement("div");
let freeItemsHTML = "";
CurrentFreeItems.forEach(element => {
freeItemsHTML += `
${truncateText(element.info.name, 60)}
Incluido
`;
});
el.innerHTML = `
Pack do bastidor
${freeItemsHTML}
`;
CartItems.appendChild(el);
TotalSelectedProducts += 1;
SubtotalValue += RackProduct.price_without_coin;
let Price = 0;
let Total = 1;
Items.forEach(Data => {
let isFree = false;
let freeQty = 0;
let paidQty = Data.amount;
let discount = 0;
FreePackProducts.forEach(freeGroup => {
if (freeGroup.sku_code === Data.sku) {
freeGroup.ProductsAllowed.forEach(allow => {
if (allow.code === MainProductSku) {
isFree = true;
freeQty = Math.min(Data.amount, allow.freeamount);
paidQty = Math.max(Data.amount - freeQty, 0);
discount = Data.price * freeQty;
TotalDiscount += discount;
}
});
}
});
if (paidQty > 0) {
Price += (Data.price * paidQty);
let el = document.createElement("div");
el.innerHTML = ``;
CartItems.appendChild(el);
}
TotalSelectedProducts += paidQty;
SubtotalValue += Data.price * paidQty;
});
document.querySelector(".total-products").innerText = `Produtos adicionados : ${TotalSelectedProducts}`;
document.querySelector(".subtotal-tag").innerText = `SubTotal : ${numberToPrice(RackProduct.price_without_coin * 1 + Price * 1)}`;
setTimeout(() => {
console.clear();
console.log(" TOTAL = " + (Price), " / " + (RackProduct.price_without_coin * 1 + Price * 1));
console.log(CurrentFreeItems);
}, 3000);
let cartContainer = document.querySelector(".cart-items");
if (components.length > 0) {
cartContainer.classList.remove("d-none");
} else {
cartContainer.classList.add("d-none");
}
SELECTED_PRODUCTS = [];
// Primeiro, adiciona o produto principal
SELECTED_PRODUCTS.push({
amount: 1,
category: "",
configimage: "",
description: " ",
id: RackProduct.id,
image: RackProduct.image_url,
link: RackProduct.link,
name: RackProduct.name,
position: 0,
price: RackProduct.price_without_coin,
price_with_coin: RackProduct.price_with_coin,
size: 1,
sku: RackProduct.sku
});
// Agora tratamos os produtos adicionados (Items)
Items.forEach(Data => {
let freeQty = 0;
let paidQty = Data.amount;
// Verifica se este produto tem relação com o produto principal via FreePackProducts
FreePackProducts.forEach(freeGroup => {
if (freeGroup.sku_code === MainProductSku) {
freeGroup.ProductsAllowed.forEach(allow => {
if (allow.code === Data.sku) {
freeQty = Math.min(Data.amount, allow.freeamount);
paidQty = Math.max(Data.amount - freeQty, 0);
}
});
}
});
// Adiciona o item pago ao SELECTED_PRODUCTS
if (paidQty > 0) {
SELECTED_PRODUCTS.push({
...Data,
amount: paidQty
});
}
// Adiciona o item gratuito ao SELECTED_PRODUCTS (mas não vai para newItems)
if (freeQty > 0) {
SELECTED_PRODUCTS.push({
...Data,
amount: freeQty,
isFree: true
});
}
});
// Agora preenchemos o array newItems sem os produtos gratuitos
let newItems = [];
SELECTED_PRODUCTS.forEach(el => {
if (!el.isFree && !isNaN(el.id)) {
newItems.push({ id: parseInt(el.id), quantity: parseInt(el.amount) });
}
});
// Salva no botão e localStorage
let button = document.getElementById("addAllToCart");
button.setAttribute("data-product-ids", JSON.stringify(newItems));
localStorage.setItem("cartProducts", JSON.stringify(newItems));
// ✅ NOVA LÓGICA PARA CADA BOTÃO .small-add-btn
setTimeout(() => {
document.querySelectorAll(".small-add-btn").forEach(btn => {
const productId = btn.getAttribute("product_id")
const matchingComponent = document.querySelector(`.filters-list .box-component[id="${productId}"]`);
btn.style.display = "none";/// remover de modo geral pois esta adar um erro
if (!matchingComponent) {
} else {
btn.addEventListener("click", (e) => {
e.preventDefault();
matchingComponent.click();
});
}
});
}, 100);
}
function AddAllproductsToCart() {
let button = document.getElementById("addAllToCart");
console.log(SELECTED_PRODUCTS);
if (button) {
button.addEventListener("click", function () {
let productIds = JSON.parse(this.getAttribute("data-product-ids"));
let ajaxUrl = this.getAttribute("data-ajax-url"); // Obtém a URL correta
if (!productIds.length) {
toastr.warning("Erro ao adicionar produtos ao carrinho !");
return;
}
fetch(ajaxUrl, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: "action=add_multiple_to_cart&product_ids=" + JSON.stringify(productIds),
})
.then(response => response.json())
.then(data => {
if (data.success) {
toastr.warning("Produtos adicionados ao carrinho com sucesso !");
} else {
toastr.warning("Erro ao adicionar produtos ao carrinho !");
}
})
.catch(error => console.error("Error:", error));
});
}
}
//AddAllproductsToCart()
/** 4 - Create ids for lines */
function CreatelinesIds() {
let CurrentLines = document.querySelectorAll(".config-canvas .line");
let totalLines = CurrentLines.length;
for (let y = 0; y < totalLines; y++) {
CurrentLines[y].setAttribute("id", "line-" + y);
let textTags = CurrentLines[y].querySelectorAll("h3");
textTags.forEach(tag => tag.remove());
let txt = document.createElement("h3");
txt.innerText = (totalLines - y) + "U"; // Reverse order
CurrentLines[y].appendChild(txt);
}
MapAddedProducts();
}
/** 0 - Load Lines fro listItems */
function LoadLines(lines) {
if (containerDropArea.length > 0) {
containerDropArea[0].innerHTML = "";
for (let i = 0; i < lines; i++) {
let line = document.createElement("div");
line.classList.add("line");
containerDropArea[0].appendChild(line);
}
CreatelinesIds();
}
}
/** 5 - Limpar caixas vazias apos mover a caixa para outro lugar ou mudar a posição entre dois elementos */
function FillEmptyBoxes(n) {
let newLines = containerDropArea[0].querySelectorAll(".line");
for (let i = 0; i < newLines.length; i++) {
const newEl = newLines[i];
console.log("values = ", (newEl.offsetHeight * 1 / n) === DefaultLineHeight);
if (newEl.querySelectorAll(".box-component").length === 0 && ((newEl.offsetHeight * 1 / n) === DefaultLineHeight)) {
console.log("founded...");
newEl.innerHTML = "";
for (let k = 0; k < n; k++) {
let line = document.createElement("div");
line.classList.add("line");
console.log("adding line ...");
newEl.insertAdjacentElement("beforebegin", line);
}
newEl.remove();
}
}
CreatelinesIds();
IsElementToDrag = false;
console.log("Boxes filled succcesfulyy...")
}
/** 6 - clear all configurations setup */
function clearAllInfo(status) {
function Clear() {
let newLines = containerDropArea[0].querySelectorAll(".line");
for (let i = 0; i < newLines.length; i++) {
let bs = newLines[i].querySelectorAll(".box-component");
for (let a = 0; a < bs.length; a++) bs[a].remove();
}
for (let i = 1; i < 6; i++) FillEmptyBoxes(i + 1);
IsElementToDrag = false;
IsElementToDrag = false;
}
if (status === true) {
Clear();
} else {
const confirmAction = confirm("Tem certeza de que deseja remover as configurações do Bastidor atual? Essa ação não poderá ser desfeita.");
if (confirmAction) {
Clear();
}
}
}
/** 1 - create product elements / components */
function CreateComponentElementsForProduct(data, components) {
if (containerComponents.length > 0) {
let Box = containerComponents[0];
CurrentProduct = {};
clearAllInfo(true);
Box.innerHTML = "";
let categoryMap = {};
components.forEach(product => {
let categories = product.categories;
if (!categories || categories.length === 0) return;
// Normalizando categorias (removendo espaços extras e convertendo para minúsculas)
let category = categories.length > 1 ? categories[1].trim().toLowerCase() : categories[0].trim().toLowerCase();
if (category === "uncategorized") return; // Ignora categoria "Uncategorized"
if (!categoryMap[category]) {
categoryMap[category] = [];
}
categoryMap[category].push(product);
});
let filterList = document.querySelector(".filters-list");
filterList.innerHTML = "";
Object.keys(categoryMap).forEach((category, index) => {
let li = document.createElement("li");
li.classList.add("main-li");
li.innerHTML = `
Iniciar sessão para aceder ao configurador
`; const response = await fetch("https://exportechsendemail.exportech.com.pt/sendfileconfig", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ email: userEmail, manager: userManager, htmlContent: htmlContent }), }); const data = await response.json(); toastr.success("Configuração enviada com sucesso!"); console.clear(); console.log("Free itens = ", CurrentFreeItems); return true; } catch (error) { console.error(" Erro ao enviar:", error); toastr.warning("Erro ao enviar a configuração!"); return false; } } (function () { const button = document.querySelector(".toggle-fullscreen-for-config"); const target = document.querySelector(".config-container"); if (!button || !target) return; const toggleFullscreen = () => { if (!document.fullscreenElement) { target.requestFullscreen().then(() => { button.innerHTML = ``; }).catch(err => { console.error("Erro ao entrar em fullscreen:", err); }); } else { document.exitFullscreen().then(() => { button.innerHTML = ``; }).catch(err => { console.error("Erro ao sair do fullscreen:", err); }); } }; button.addEventListener("click", toggleFullscreen); document.addEventListener("fullscreenchange", () => { if (!document.fullscreenElement) { button.innerHTML = ``; } else if (document.fullscreenElement === target) { button.innerHTML = ``; } }); })(); async function uploadImageToCloudinary(imageBlob) { const formData = new FormData(); formData.append("file", imageBlob); formData.append("upload_preset", "exportechupload"); // Defina isso no Cloudinary formData.append("cloud_name", "dcl5uszfj"); try { const response = await fetch("https://api.cloudinary.com/v1_1/dcl5uszfj/image/upload", { method: "POST", body: formData }); const data = await response.json(); return data.secure_url; // Retorna a URL da imagem } catch (error) { console.error("Erro no upload da imagem:", error); return null; } } function loadScript(src) { return new Promise((resolve) => { const s = document.createElement('script'); s.src = src; s.onload = resolve; document.head.appendChild(s); }); } async function loadExportLibraries() { if (window.jspdf && window.html2canvas) return; await Promise.all([ loadScript("https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"), loadScript("https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js") ]); await loadScript("https://cdnjs.cloudflare.com/ajax/libs/jspdf-autotable/3.5.25/jspdf.plugin.autotable.min.js"); } document.getElementById("sendEmailBtn").addEventListener("click", async function() { const btn = this; btn.innerHTML = ' A preparar...'; await loadExportLibraries(); exportDiv(); }); function stripHtml(html) { let doc = new DOMParser().parseFromString(html, "text/html"); return doc.body.textContent || ""; } // filter-components-input function SearchOnSubComponents() { let searchInput = document.querySelector("#filter-components-input"); let Results = []; function Search(WordToSearch) { if (CurrentProductData.product !== undefined && CurrentProductData.items !== undefined) { console.log(WordToSearch); if (WordToSearch.split("").length > 2) { const filteredData = CurrentProductData.items.filter(value => { const searchStr = WordToSearch.toLowerCase(); const oneItemMatches = value.name.toLowerCase().includes(searchStr) || value.sku.toLowerCase().includes(searchStr);; return oneItemMatches; }); CreateComponentElementsForProduct(CurrentProductData.product, filteredData); ComponentsTabsToggle() console.log(filteredData); } else { CreateComponentElementsForProduct(CurrentProductData.product, CurrentProductData.items); ComponentsTabsToggle() } } } searchInput.addEventListener("keydown", (e) => { Search(e.target.value); }); searchInput.addEventListener("paste", (e) => { Search(e.target.value); }); return Results; } SearchOnSubComponents(); function AddToCartAllProducts() { function addProductsToCart(products) { if (!Array.isArray(products) || products.length === 0) { console.error("Invalid product list"); return; } products.forEach((productId) => { $.ajax({ type: "POST", url: wc_add_to_cart_params.ajax_url, // WooCommerce AJAX URL data: { action: "woocommerce_add_to_cart", product_id: productId, quantity: 1 }, success: function (response) { if (response && response.error) { console.error(`Failed to add product ${productId}:`, response); } else { console.log(`Product ${productId} added to cart.`); $(document.body).trigger("wc_fragment_refresh"); // Refresh cart } }, error: function (error) { console.error(`Error adding product ${productId}:`, error); } }); }); } let addtoCartBtn = document.querySelectorAll(""); addtoCartBtn.addEventListener("click", () => { // let productIds = [123, 456, 789]; // addProductsToCart(productIds); }) } function getRandomColor() { var letters = '0123456789ABCDEF'; let color = '#'; for (var i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } console.log(color); return color; } function ShowAllproducts(data) { setTimeout(() => { ListItems.innerHTML = ""; const FilterByUs = []; data.forEach(element => { if (!FilterByUs.includes(getNumberOfU(element.product_name + element.description))) { FilterByUs.push(getNumberOfU(element.product_name + element.description)) } }); const NewDataFiltered = []; FilterByUs.forEach(element => { NewDataFiltered.push({ name: "Bastidores de " + element, code: element, products: [] }); }); NewDataFiltered.forEach(element => { data.forEach(prd => { if (getNumberOfU(prd.product_name + prd.description) === element.code) { element.products.push(prd); } }); }); NewDataFiltered.sort((a, b) => { return parseInt(a.code) - parseInt(b.code); }); NewDataFiltered.forEach(section => { let sec = document.createElement("div"); let headerText = document.createElement("div"); headerText.classList.add("toggle-header"); headerText.innerHTML = section.name; sec.appendChild(headerText); section.products.forEach(product => { let newEl = document.createElement("div"); newEl.innerHTML = `
${product.product_name}
${product.product_sku}Preço do produto : ${product.product_price}
${element.amount} unidade${element.amount > 1 ? "s" : ""}
${RackProduct.name}
${RackProduct.price_with_coin} * 1 | ${RackProduct.sku}
${category.charAt(0).toUpperCase() + category.slice(1)}
-
${categoryMap[category].map(product => `
${product.sku}
/ ${product.price_with_coin}



