let products = [];
let cart = [];
let currentPage = 1;
let itemsPerPage = 0;
let filteredProducts = [];
// Load Products
async function loadProducts() {
const response = await fetch('/muestras/get-inventory.php');
const csvText = await response.text();
products = Papa.parse(csvText, { header: true, dynamicTyping: true }).data;
filteredProducts = products;
createFilters();
calculateItemsPerPage();
displayPage(1);
filterProducts();
}
// Calculate Items per Page
function calculateItemsPerPage() {
const containerWidth = document.getElementById('productContainer').offsetWidth;
const productWidth = 210; // Product width + margin
itemsPerPage = Math.floor(containerWidth / productWidth) * 50; // Fixed 10 rows
}
// Display Products on Page
function displayPage(page) {
const container = document.getElementById('productContainer');
container.innerHTML = '';
const start = (page - 1) * itemsPerPage;
const slice = filteredProducts.slice(start, start + itemsPerPage);
if (slice.length === 0) {
container.innerHTML = '
No results found.
';
return;
}
slice.forEach(product => {
const productDiv = document.createElement('div');
productDiv.className = 'product';
productDiv.innerHTML = `
${product['Brand']}
${product['Paint Name']}
Price: ${product['Price']} HNL
Agregar al carrito
`;
container.appendChild(productDiv);
});
document.getElementById('prevPageButton').disabled = page === 1;
document.getElementById('nextPageButton').disabled = start + itemsPerPage >= filteredProducts.length;
currentPage = page;
}
// Pagination
// Next and Previous Page Controls with Scroll to Top
function nextPage() {
if (currentPage * itemsPerPage < filteredProducts.length) {
displayPage(currentPage + 1);
scrollToTop(); // Scroll back to the top
}
}
function prevPage() {
if (currentPage > 1) {
displayPage(currentPage - 1);
scrollToTop(); // Scroll back to the top
}
}
// Helper function to scroll back to the top
function scrollToTop() {
window.scrollTo({
top: 0, // Scroll to the very top of the page
behavior: 'smooth' // Smooth scrolling
});
}
// Quantity Controls
function incrementQuantity(code) { updateQuantity(code, 1); }
function decrementQuantity(code) { updateQuantity(code, -1); }
function updateQuantity(code, change) {
const input = document.getElementById(`qty-${code}`);
input.value = Math.max(1, parseInt(input.value) + change);
}
// Cart Management
function addToCart(code) {
const button = event.currentTarget; // Get the button that triggered the event
button.classList.add('loading'); // Add loading class
code = String(code); // Ensure the code is always treated as a string
const product = products.find(p => String(p['Paint Code']) === code);
const quantity = parseInt(document.getElementById(`qty-${code}`).value);
const existing = cart.find(item => String(item['Paint Code']) === code);
setTimeout(() => {
if (existing) existing.quantity += quantity;
else cart.push({ ...product, quantity });
updateCart();
button.classList.remove('loading'); // Remove loading spinner
}, 1000); // Simulate loading for 1 second
}
// Update Cart
function updateCart() {
const cartItems = document.getElementById('cartItems');
const cartTotal = document.getElementById('cartTotal');
const discountDiv = document.getElementById('discountDiv')
const itemCountDiv1 = document.getElementById('itemCountDiv1');
const itemCountDiv2 = document.getElementById('itemCountDiv2');
const checkoutButton = document.querySelector('#checkoutForm button[type="submit"]');
cartItems.innerHTML = '';
let total = 0;
let itemCount = 0;
cart.forEach(item => {
total += item['Price'] * item.quantity;
itemCount += item.quantity;
const li = document.createElement('li');
li.innerHTML = `
${item['Paint Code']} ${item['Paint Name']}
${item['Brand']}
${item.quantity}
`;
cartItems.appendChild(li);
});
// Apply discount based on the number of items
let discount = 0;
if (itemCount >= 3 && itemCount <= 7) {
discount = total * 0.10; // 10% discount
} else if (itemCount >= 8) {
discount = total * 0.25; // 25% discount
}
const finalTotal = total - discount;
// Update the cart total display
cartTotal.textContent = `${finalTotal.toFixed(2)} HNL`;
discountDiv.textContent = `${discount.toFixed(2)} HNL`;
// Update the cart total display with a prefix and bold text
cartTotal.innerHTML = `Total: ${finalTotal.toFixed(2)} HNL`;
// Update the discount display with a prefix and bold text
discountDiv.innerHTML = `Descuento Aplicado: ${discount.toFixed(2)} HNL`;
// Hide or show cart total and discount divs based on their values
cartTotal.style.display = finalTotal === 0 ? 'none' : 'block';
discountDiv.style.display = discount === 0 ? 'none' : 'block';
//Update both item count displays
itemCountDiv1.textContent = itemCount;
itemCountDiv2.textContent = itemCount;
saveCartToCookies();
// Disable the "Pagar" button if the cart is empty
checkoutButton.disabled = itemCount === 0;
return itemCount; // Return the item count for further use if needed
}
function removeFromCart(paintCode) {
// Ensure type consistency by converting both to strings
cart = cart.filter(item => String(item['Paint Code']) !== String(paintCode));
updateCart();
}
function incrementCart(paintCode) {
const cartItem = cart.find(item => String(item['Paint Code']) === String(paintCode));
if (cartItem) {
cartItem.quantity++;
updateCart();
}
}
function decrementCart(paintCode) {
const cartItem = cart.find(item => String(item['Paint Code']) === String(paintCode));
if (cartItem && cartItem.quantity > 1) {
cartItem.quantity--;
updateCart();
}
}
document.addEventListener('DOMContentLoaded', function() {
emailjs.init("ZXdPTp8fqeo6m6_xu"); // Your Public Key
});
function decodeScriptUrl(data) {
const binaryString = atob(data);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return new TextDecoder('utf-8').decode(bytes);
}
// Checkout and PDF Invoice
async function handleCheckout(event) {
event.preventDefault();
const form = this;
const formData = new FormData(form);
const cartData = JSON.stringify(cart);
const itemCountDiv2 = document.getElementById('itemCountDiv2').textContent;
const cartTotalElement = document.getElementById('cartTotal');
const discountDivElement = document.getElementById('discountDiv');
const cartTotal = cartTotalElement ? cartTotalElement.textContent : '0 HNL';
const discountDiv = discountDivElement ? discountDivElement.textContent : '0 HNL';
console.log("Cart Total: ", cartTotal);
console.log("Discount: ", discountDiv);
formData.append('cart', cartData);
formData.append('itemCount', itemCountDiv2);
// ✅ Generate Order ID once and store it in the DOM
const orderID = generateOrderID();
document.getElementById('orderIDField').value = orderID;
// Generate invoice, clear cart, and reset form
generateInvoice();
generateOrder();
cart = [];
updateCart();
event.target.reset();
toggleCart();
Toastify({ text: "¡Gracias por su compra!", duration: 5000, gravity: "top", position: "center" }).showToast();
const paymentProofFile2 = formData.get('paymentProof');
// Convert payment proof to Base64
const base64Fileproof = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result.split(',')[1]);
reader.onerror = reject;
reader.readAsDataURL(paymentProofFile2);
});
// console.log(base64Fileproof);
// Send Email using Google Apps Script
const emailParams = {
order_id: orderID,
from_name: formData.get('name'),
email: formData.get('email'),
phone: formData.get('phone'),
department: formData.get('department'),
city: formData.get('city'),
address: formData.get('address'),
reference: formData.get('reference') || 'No reference provided',
cart: cartData,
Count: itemCountDiv2,
total_price: cartTotal,
discount: discountDiv,
payment_proof: base64Fileproof
};
try {
const response = await fetch("https://script.google.com/macros/s/AKfycby28gTSktoFwDIGppVeEg6EWiMvbxQyEUaCSGedzJ0lbAob9tmEmmSbBzQUtAX092uNVA/exec", {
method: 'POST',
mode: 'no-cors',
body: JSON.stringify(emailParams),
headers: {
'Content-Type': 'application/json'
}
});
console.log("Email sent successfully via Google Apps Script!");
} catch (error) {
console.error("Failed to send email via Apps Script:", error);
}
// Dropbox Upload for Payment Proof
const paymentProofFile = formData.get('paymentProof');
const reader = new FileReader();
reader.onload = async function (event) {
const base64File = event.target.result.split(',')[1];
// Ensure the token is refreshed before uploading
await refreshDropboxToken();
const dropboxUploadUrl = 'https://content.dropboxapi.com/2/files/upload';
const accessToken = DROPBOX_CONFIG.accessToken;
const fileName = `${formData.get('name') || 'Unknown'}_payment_proof.png`;
const parentFolder = '/ColorDemoOrders/pendingorders/';
const orderFolder = `${orderID}`;
const folderPath = `${parentFolder}${orderFolder}/${fileName}`;
const response = await fetch(dropboxUploadUrl, {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/octet-stream',
'Dropbox-API-Arg': JSON.stringify({
path: folderPath,
mode: 'add',
autorename: true,
mute: false
})
},
body: Uint8Array.from(atob(base64File), c => c.charCodeAt(0))
});
const result = await response.json();
if (response.ok) {
console.log("File uploaded successfully to Dropbox!");
console.log("Uploaded to:", result.path_display);
appendOrderToCSV(orderID, formData, cartTotal, discountDiv, itemCountDiv2);
} else {
alert("Error uploading to Dropbox!");
console.error(result);
}
};
reader.readAsDataURL(paymentProofFile);
}
// Function to generate unique Order ID
function generateOrderID() {
const now = new Date();
return `CD-${now.getFullYear()}${(now.getMonth() + 1)}${now.getDate()}-${now.getTime()}`;
}
// Save sales to Dropbox as CSV
async function appendOrderToCSV(orderID, formData, cartTotal, discountDiv, itemCountDiv2) {
await refreshDropboxToken();
const dropboxUploadUrl = 'https://content.dropboxapi.com/2/files/upload';
const accessToken = DROPBOX_CONFIG.accessToken;
const fileName = `/ColorDemoOrders/orders/order_${orderID}.csv`;
const csvHeader = 'Order ID,Name,Email,Phone,Department,City,Address,Total Price,Discount,Item Count,Cart Items\n';
// Wrap address in double quotes
const address = formData.get('address').replace(/"/g, '""'); // Escape existing quotes
const quotedAddress = `"${address}"`; // Wrap address in double quotes
// Convert cart items to readable format
const formattedCartItems = cart.map(item => {
const itemName = item['Paint Name'];
const itemCode = item['Paint Code'] || 'N/A';
const itemQuantity = item.quantity;
const itemPrice = item['Price'];
const itemTotal = itemQuantity * itemPrice;
return `${itemName} (${itemCode}) x${itemQuantity} - ${itemTotal} HNL`;
}).join('; '); // Join items with a semicolon separator
// Create CSV row
const csvLine = `${orderID},${formData.get('name')},${formData.get('email')},${formData.get('phone')},${formData.get('department')},${formData.get('city')},${quotedAddress},${cartTotal},${discountDiv},${itemCountDiv2},"${formattedCartItems}"\n`;
const csvContent = csvHeader + csvLine;
try {
console.log("Uploading CSV to Dropbox...");
const response = await fetch(dropboxUploadUrl, {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/octet-stream',
'Dropbox-API-Arg': JSON.stringify({
path: fileName,
mode: 'overwrite',
autorename: false,
mute: false
})
},
body: csvContent
});
const result = await response.json();
if (result.error) {
console.error("Error uploading CSV:", result.error);
console.log("Failed to upload CSV to Dropbox.");
} else {
console.log("CSV uploaded successfully to Dropbox:", result.path_display);
}
} catch (error) {
console.error("Failed to upload CSV to Dropbox:", error);
console.log("Error uploading order CSV.");
}
}
// Generate Invoice PDF and Upload to Dropbox
function generateInvoice() {
const { jsPDF } = window.jspdf;
const pdf = new jsPDF();
const orderID = document.getElementById('orderIDField').value;
const clientName = document.querySelector('input[name="name"]').value || 'Cliente Desconocido';
const clientEmail = document.querySelector('input[name="email"]').value || 'No Email';
const clientPhone = document.querySelector('input[name="phone"]').value || 'No Phone';
const clientrtn = document.querySelector('input[name="rtn"]').value
const currentDate = new Date().toLocaleDateString();
const currentTime = new Date().toLocaleTimeString();
const itemCount = document.getElementById('itemCountDiv1').textContent;
const cartTotal = document.getElementById('cartTotal').textContent;
const discount = document.getElementById('discountDiv').textContent || '0 HNL';
// Add Image to Header (if available)
if (paperImageBase64) {
pdf.addImage(paperImageBase64, 'PNG', 12, 15, 30, 30); // (x, y, width, height)
}
// HEADER (No space between consecutive lines)
let yHeader = 20;
pdf.setFontSize(18);
pdf.text("Color Demo", 105, yHeader, { align: "center" });
pdf.setFontSize(14);
pdf.text("Factura de Venta", 105, yHeader + 7, { align: "center" });
pdf.setFontSize(12);
yHeader += 13; // Slightly larger space after the title
pdf.text("Dirección: Residencial Santa Cruz,", 105, yHeader, { align: "center" });
pdf.text("II Etapa, Bloque 10, Casa 25", 105, yHeader + 5, { align: "center" });
pdf.text("Tel. Pendiente", 105, yHeader + 10, { align: "center" });
pdf.text("email: colordemo89@gmail.com", 105, yHeader + 15, { align: "center" }); // +5 for tight spacing
pdf.text("RTN: 08011989128389", 105, yHeader + 20, { align: "center" }); // Combine label and value
pdf.text("C.A.I.: F4EB28-BFD5C0-7C4693-E00235-F6DED6-86", 105, yHeader + 25, { align: "center" });
// Space below the header block
yHeader += 40;
// ORDER DETAILS
pdf.text(`Orden: ${orderID}`, 15, yHeader);
pdf.text(`Fecha: ${currentDate}`, 160, yHeader);
pdf.text(`Hora: ${currentTime}`, 162, yHeader + 5);
// === CLIENT INFO (Tighter grouping) ===
let yClient = yHeader + 15;
pdf.setFontSize(14);
pdf.text("Información del Cliente", 15, yClient);
// Calculate the text width and position the underline
const textWidth = pdf.getTextWidth("Información del Cliente:");
const underlineY = yClient + 1; // Slightly below the text
pdf.line(15, underlineY, 15 + textWidth, underlineY); // (x1, y1, x2, y2)
pdf.setFontSize(12);
yClient += 8; // Small gap after section title
pdf.text(`Nombre: ${clientName}`, 15, yClient);
pdf.text(`Correo: ${clientEmail}`, 15, yClient + 5); // Tight spacing
pdf.text(`RTN: ${clientrtn}`, 15, yClient + 10); // Tight spacing
pdf.text(`Teléfono: ${clientPhone}`, 15, yClient + 15); // Tight spacing
// === TABLE HEADER ===
let yTable = yClient + 30;
pdf.setFontSize(14);
pdf.text("Resumen del Pedido", 15, yTable - 3);
// Calculate the text width and position the underline
const textWidth2 = pdf.getTextWidth("Resumen del Pedido");
const underlineY2 = yTable - 2; // Slightly below the text
pdf.line(15, underlineY2, 15 + textWidth2, underlineY2); // (x1, y1, x2, y2)
pdf.setFontSize(12);
pdf.setFillColor(240, 240, 240);
pdf.rect(15, yTable, 180, 10, 'F');
pdf.text("Código", 18, yTable + 7);
pdf.text("Color", 42, yTable + 7);
pdf.text("Marca", 90, yTable + 7);
pdf.text("Cantidad", 143, yTable + 7, { align: "right" });
pdf.text("P. Unitario", 170, yTable + 7, { align: "right" });
pdf.text("Total", 192, yTable + 7, { align: "right" });
yTable += 15;
// === CART ITEMS ===
const pageHeight = pdf.internal.pageSize.height;
const marginBottom = 30;
cart.forEach(item => {
const paintCode = item['Paint Code'] || 'N/A';
if (yTable + 10 > pageHeight - marginBottom) {
pdf.addPage();
yTable = 30;
pdf.setFillColor(240, 240, 240);
pdf.rect(15, yTable, 180, 10, 'F');
pdf.text("Código", 18, yTable + 7);
pdf.text("Color", 42, yTable + 7);
pdf.text("Marca", 90, yTable + 7);
pdf.text("Cantidad", 143, yTable + 7, { align: "right" });
pdf.text("P. Unitario", 170, yTable + 7, { align: "right" });
pdf.text("Total", 192, yTable + 7, { align: "right" });
yTable += 15;
}
pdf.text(`${paintCode}`, 18, yTable);
pdf.text(`${item['Paint Name']}`, 42, yTable);
pdf.text(`${item['Brand']}`, 90, yTable);
pdf.text(`x${item.quantity}`, 143, yTable, { align: "right" });
pdf.text(`${item['Price']} HNL`, 170, yTable, { align: "right" });
pdf.text(`${item['Price'] * item.quantity} HNL`, 192, yTable, { align: "right" });
yTable += 10;
});
// === FOOTER ===
yTable += 10;
pdf.line(15, yTable, 195, yTable);
yTable += 10;
const rightMargin = 195;
const discountWidth = pdf.getTextWidth(`${discount}`);
const totalWidth = pdf.getTextWidth(cartTotal);
pdf.setFontSize(12);
pdf.text(`${discount}`, rightMargin - discountWidth, yTable);
pdf.setFont("helvetica", "bold");
pdf.text(cartTotal, rightMargin - totalWidth, yTable + 6);
pdf.setTextColor(255, 0, 0);
pdf.setFontSize(14);
pdf.text("PAGADO", rightMargin - totalWidth, yTable + 13);
pdf.setTextColor(0, 0, 0);
pdf.setFont("helvetica", "normal");
pdf.text(`Cantidad Total: ${itemCount}`, 15, yTable + 6);
// === THANK YOU MESSAGE ===
yTable += 18;
pdf.setFontSize(11);
pdf.setTextColor(100);
pdf.text("¡Gracias por su compra!", 105, yTable, { align: "center" });
// SAVE PDF LOCALLY
const pdfFileName = `${orderID}_recibo.pdf`;
const pdfBlob = pdf.output("blob");
// UPLOAD PDF TO DROPBOX
uploadInvoiceToDropbox(pdfBlob, pdfFileName, orderID);
// Create a URL from the blob
const pdfURL = URL.createObjectURL(pdfBlob);
}
// Generate Order PDF and Upload to Dropbox
function generateOrder() {
const { jsPDF } = window.jspdf;
const pdf = new jsPDF();
const orderID = document.getElementById('orderIDField').value;
const clientName = document.querySelector('input[name="name"]').value || 'Cliente Desconocido';
const clientEmail = document.querySelector('input[name="email"]').value || 'No Email';
const clientPhone = document.querySelector('input[name="phone"]').value || 'No Phone';
const clientrtn = document.querySelector('input[name="rtn"]').value
const currentDate = new Date().toLocaleDateString();
const currentTime = new Date().toLocaleTimeString();
const itemCount = document.getElementById('itemCountDiv1').textContent;
const cartTotal = document.getElementById('cartTotal').textContent;
const discount = document.getElementById('discountDiv').textContent || '0 HNL';
// Add Image to Header (if available)
if (paperImageBase64) {
pdf.addImage(paperImageBase64, 'PNG', 12, 15, 30, 30); // (x, y, width, height)
}
// HEADER (No space between consecutive lines)
let yHeader = 20;
pdf.setFontSize(18);
pdf.text("Color Demo", 105, yHeader, { align: "center" });
pdf.setFontSize(14);
pdf.text("Orden de Compra", 105, yHeader + 7, { align: "center" });
pdf.setFontSize(12);
yHeader += 13; // Slightly larger space after the title
pdf.text("Cel.: Pendiente", 105, yHeader, { align: "center" });
pdf.text("email: colordemo89@gmail.com", 105, yHeader + 5, { align: "center" }); // +5 for tight spacing
// Space below the header block
yHeader += 30;
// ORDER DETAILS
pdf.text(`Orden: ${orderID}`, 15, yHeader);
pdf.text(`Fecha: ${currentDate}`, 160, yHeader);
pdf.text(`Hora: ${currentTime}`, 162, yHeader + 5);
// === CLIENT INFO (Tighter grouping) ===
let yClient = yHeader + 15;
pdf.setFontSize(14);
pdf.text("Información del Cliente", 15, yClient);
// Calculate the text width and position the underline
const textWidth = pdf.getTextWidth("Información del Cliente:");
const underlineY = yClient + 1; // Slightly below the text
pdf.line(15, underlineY, 15 + textWidth, underlineY); // (x1, y1, x2, y2)
pdf.setFontSize(12);
yClient += 8; // Small gap after section title
pdf.text(`Nombre: ${clientName}`, 15, yClient);
pdf.text(`Correo: ${clientEmail}`, 15, yClient + 5); // Tight spacing
pdf.text(`RTN: ${clientrtn}`, 15, yClient + 10); // Tight spacing
pdf.text(`Teléfono: ${clientPhone}`, 15, yClient + 15); // Tight spacing
// === TABLE HEADER ===
let yTable = yClient + 30;
pdf.setFontSize(14);
pdf.text("Resumen del Pedido", 15, yTable - 3);
// Calculate the text width and position the underline
const textWidth2 = pdf.getTextWidth("Resumen del Pedido");
const underlineY2 = yTable - 2; // Slightly below the text
pdf.line(15, underlineY2, 15 + textWidth2, underlineY2); // (x1, y1, x2, y2)
pdf.setFontSize(12);
pdf.setFillColor(240, 240, 240);
pdf.rect(15, yTable, 180, 10, 'F');
pdf.text("Código", 18, yTable + 7);
pdf.text("Color", 42, yTable + 7);
pdf.text("Marca", 90, yTable + 7);
pdf.text("Cantidad", 143, yTable + 7, { align: "right" });
pdf.text("P. Unitario", 170, yTable + 7, { align: "right" });
pdf.text("Total", 192, yTable + 7, { align: "right" });
yTable += 15;
// === CART ITEMS ===
const pageHeight = pdf.internal.pageSize.height;
const marginBottom = 30;
cart.forEach(item => {
const paintCode = item['Paint Code'] || 'N/A';
if (yTable + 10 > pageHeight - marginBottom) {
pdf.addPage();
yTable = 30;
pdf.setFillColor(240, 240, 240);
pdf.rect(15, yTable, 180, 10, 'F');
pdf.text("Código", 18, yTable + 7);
pdf.text("Color", 42, yTable + 7);
pdf.text("Marca", 90, yTable + 7);
pdf.text("Cantidad", 143, yTable + 7, { align: "right" });
pdf.text("P. Unitario", 170, yTable + 7, { align: "right" });
pdf.text("Total", 192, yTable + 7, { align: "right" });
yTable += 15;
}
pdf.text(`${paintCode}`, 18, yTable);
pdf.text(`${item['Paint Name']}`, 42, yTable);
pdf.text(`${item['Brand']}`, 90, yTable);
pdf.text(`x${item.quantity}`, 143, yTable, { align: "right" });
pdf.text(`${item['Price']} HNL`, 170, yTable, { align: "right" });
pdf.text(`${item['Price'] * item.quantity} HNL`, 192, yTable, { align: "right" });
yTable += 10;
});
// === FOOTER ===
yTable += 10;
pdf.line(15, yTable, 195, yTable);
yTable += 10;
const rightMargin = 195;
const discountWidth = pdf.getTextWidth(`${discount}`);
const totalWidth = pdf.getTextWidth(cartTotal);
pdf.setFontSize(12);
pdf.text(`${discount}`, rightMargin - discountWidth, yTable);
pdf.setFont("helvetica", "bold");
pdf.text(cartTotal, rightMargin - totalWidth, yTable + 6);
pdf.setTextColor(255, 0, 0);
pdf.setFontSize(14);
pdf.text("VERIFICANDO PAGO", rightMargin -50, yTable + 13);
pdf.setTextColor(0, 0, 0);
pdf.setFont("helvetica", "normal");
pdf.text(`Cantidad Total: ${itemCount}`, 15, yTable + 6);
// === THANK YOU MESSAGE ===
yTable += 18;
pdf.setFontSize(11);
pdf.setTextColor(100);
pdf.text("¡Gracias! Estamos procesando su orden.", 105, yTable, { align: "center" });
// SAVE PDF LOCALLY
const pdfFileName = `${orderID}_orden.pdf`;
const pdfBlob = pdf.output("blob");
// UPLOAD PDF TO DROPBOX
uploadInvoiceToDropbox(pdfBlob, pdfFileName, orderID);
Toastify({ text: "Su orden se está procesando...", duration: 5000, gravity: "middle", position: "center" }).showToast();
// Create a URL from the blob
const pdfURL = URL.createObjectURL(pdfBlob);
// Open the PDF in a new window/tab
window.open(pdfURL, '_blank');
// Optional: Revoke the object URL after some time to free memory
setTimeout(() => URL.revokeObjectURL(pdfURL), 10000);
}
async function bankaccount(event) {
event.preventDefault();
// Find the form associated with the clicked button
const form = document.getElementById('checkoutForm'); // Use a specific ID for the form
if (!form) {
console.error("Form element not found.");
return;
}
const formData = new FormData(form);
// Validate inputs
const from_name = formData.get('name')?.trim();
const email = formData.get('email')?.trim();
const phone = formData.get('phone')?.trim();
if (!from_name || !email || !phone) {
Toastify({ text: "Favor llenar los campos de Nombre, correo y teléfono.", duration: 3000, gravity: "middle", position: "center" }).showToast();
} else {
Toastify({ text: "Su solicitud fue enviada. Favor revisar su correo en bandeja de entrada o spam (correo no deseado). ¡Gracias!", duration: 5000, gravity: "middle", position: "center" }).showToast();
}
const emailParams = {
from_name: from_name,
email: email,
phone: phone,
};
try {
const response = await fetch("https://script.google.com/macros/s/AKfycbzPqIWRPykp3ycPAoTNpyj3W7Hv_4Fwv3cy-9TWivdEMtmKFGA2S1WNZ7TVmrrG1SZaFA/exec", {
method: 'POST',
mode: 'no-cors',
body: JSON.stringify(emailParams),
// Uncomment if needed
// headers: {
// 'Content-Type': 'application/json'
// }
});
console.log("Email sent successfully via Google Apps Script!");
} catch (error) {
console.error("Failed to send email via Apps Script:", error);
}
}
// Logo on PDF
// Load image as Base64 and generate PDF
let paperImageBase64 = 'data:image/jpeg;base64,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';
// Convert image to Base64
function loadImage() {
const img = new Image();
img.src = 'images/paper.png';
img.crossOrigin = 'Anonymous'; // Prevent CORS issues if served remotely
img.onload = function () {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
paperImageBase64 = canvas.toDataURL('image/png');
liveGenerateInvoice(); // Generate PDF after loading image
};
}
// Event Listeners
window.onload = () => loadProducts();
window.addEventListener('resize', () => {
calculateItemsPerPage();
displayPage(currentPage);
});
window.onload = () => {
console.log("Triggering CSV test upload...");
appendOrderToCSV('CD-TEST-123', new FormData(), '1500 HNL', '200 HNL', '3');
};
document.getElementById('checkoutForm').addEventListener('submit', handleCheckout);
document.getElementById('checkoutForm').addEventListener('accounts', bankaccount);
function toggleCart() {
const cartSidebar = document.getElementById('cartSidebar');
if (cartSidebar.classList.contains('open')) {
cartSidebar.classList.remove('open');
} else {
cartSidebar.classList.add('open');
}
}
// Filter products based on user input
function filterProducts() {
const query = document.getElementById('searchInput').value.toLowerCase();
filteredProducts = products.filter(product =>
String(product['Paint Name'] || '').toLowerCase().includes(query) ||
String(product['Brand'] || '').toLowerCase().includes(query) ||
String(product['Paint Code'] || '').toLowerCase().includes(query) ||
String(product['Combinaciones'] || '').toLowerCase().includes(query) ||
String(product['Disenador'] || '').toLowerCase().includes(query)
);
currentPage = 1; // Reset to the first page
displayPage(currentPage); // Show filtered results
}
// Make precio disappear
document.addEventListener('DOMContentLoaded', () => {
const ribbon = document.querySelector('.precio');
let lastScrollPosition = 0;
window.addEventListener('scroll', () => {
const currentScrollPosition = window.scrollY;
if (currentScrollPosition > lastScrollPosition) {
// Scrolling down
ribbon.classList.add('hidden');
} else {
// Scrolling up
ribbon.classList.remove('hidden');
}
lastScrollPosition = currentScrollPosition;
});
});
// Calculate products top position
window.addEventListener('load', () => {
const precioHeight = document.querySelector('.precio').offsetHeight;
document.querySelector('.products').style.marginTop = `${75 + precioHeight + 20}px`;
});
window.addEventListener('load', adjustMargins);
window.addEventListener('resize', adjustMargins);
function adjustMargins() {
const headerHeight = document.querySelector('header').offsetHeight;
const calculatedMargin = headerHeight + 20 + 'px'; // Header height + additional spacing
document.querySelector('.search-container').style.marginTop = calculatedMargin;
document.querySelector('.products-wrapper').style.marginTop = calculatedMargin;
}
function updateItemCount(count) {
const itemCountDiv1 = document.getElementById('itemCountDiv1');
const itemCountDiv2 = document.getElementById('itemCountDiv2');
// Update both elements with the same content
itemCountDiv1.innerHTML = count;
itemCountDiv2.innerHTML = count;
}
// Set a cookie with name, value, and expiration (in days)
function setCookie(name, value, days) {
const date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
document.cookie = `${name}=${encodeURIComponent(value)};expires=${date.toUTCString()};path=/`;
}
// Get a cookie by name
function getCookie(name) {
const cookies = document.cookie.split('; ');
for (let cookie of cookies) {
const [key, value] = cookie.split('=');
if (key === name) return decodeURIComponent(value);
}
return null;
}
function saveCartToCookies() {
const cartString = JSON.stringify(cart);
setCookie('cart', cartString, 7); // Cookie expires in 7 days
}
function loadCartFromCookies() {
const cartString = getCookie('cart');
if (cartString) {
cart = JSON.parse(cartString);
updateCart();
}
}
function acceptCookies() {
setCookie('cookieConsent', 'true', 365); // Consent valid for 1 year
document.getElementById('cookieConsent').classList.add('hidden');
}
function checkCookieConsent() {
const consent = getCookie('cookieConsent');
if (!consent) {
document.getElementById('cookieConsent').classList.remove('hidden');
}
}
// Create filters
function createFilters() {
const familySet = new Set(products.map(p => p.Family).filter(Boolean));
const typeSet = new Set(products.map(p => p.Type).filter(Boolean));
const brandSet = new Set(products.map(p => p.Brand).filter(Boolean)); // Extract unique values for Brand
const filterContainer = document.createElement('div');
filterContainer.id = 'filterMenu';
filterContainer.style.display = 'none'; // Hidden by default
filterContainer.style.position = 'absolute';
filterContainer.style.background = 'white';
filterContainer.style.border = '1px solid #ccc';
filterContainer.style.padding = '10px';
filterContainer.style.zIndex = '1000';
const familyFilter = createFilterSection('Family', [...familySet]);
const typeFilter = createFilterSection('Type', [...typeSet]);
const brandFilter = createFilterSection('Brand', [...brandSet]); // Add filter section for Brand
filterContainer.appendChild(familyFilter);
filterContainer.appendChild(typeFilter);
filterContainer.appendChild(brandFilter); // Append Brand filter
document.body.appendChild(filterContainer);
const searchInput = document.getElementById('searchInput');
const adjustFilterPosition = () => {
const rect = searchInput.getBoundingClientRect();
filterContainer.style.top = `${rect.bottom + window.scrollY}px`;
filterContainer.style.left = `${rect.left + window.scrollX}px`;
filterContainer.style.width = `${rect.width}px`; // Match the search box width
};
searchInput.addEventListener('focus', () => {
adjustFilterPosition();
filterContainer.style.display = 'block';
});
window.addEventListener('resize', adjustFilterPosition); // Adjust on window resize
window.addEventListener('scroll', adjustFilterPosition); // Adjust on page scroll
document.addEventListener('click', (event) => {
if (!filterContainer.contains(event.target) && event.target.id !== 'searchInput') {
filterContainer.style.display = 'none';
}
});
}
function createFilterSection(title, options) {
const section = document.createElement('div');
section.style.marginBottom = '10px';
const label = document.createElement('strong');
label.textContent = `${title}:`;
section.appendChild(label);
options.forEach(option => {
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.value = option;
checkbox.addEventListener('change', applyFilters);
const span = document.createElement('span');
span.textContent = ` ${option}`;
const wrapper = document.createElement('div');
wrapper.appendChild(checkbox);
wrapper.appendChild(span);
section.appendChild(wrapper);
});
return section;
}
function applyFilters() {
const selectedFamilies = Array.from(document.querySelectorAll('#filterMenu [type="checkbox"][value]'))
.filter(checkbox => checkbox.checked && checkbox.parentElement.parentElement.querySelector('strong').textContent.includes('Family'))
.map(checkbox => checkbox.value);
const selectedTypes = Array.from(document.querySelectorAll('#filterMenu [type="checkbox"][value]'))
.filter(checkbox => checkbox.checked && checkbox.parentElement.parentElement.querySelector('strong').textContent.includes('Type'))
.map(checkbox => checkbox.value);
const selectedBrands = Array.from(document.querySelectorAll('#filterMenu [type="checkbox"][value]'))
.filter(checkbox => checkbox.checked && checkbox.parentElement.parentElement.querySelector('strong').textContent.includes('Brand'))
.map(checkbox => checkbox.value);
filteredProducts = products.filter(product =>
(selectedFamilies.length === 0 || selectedFamilies.includes(product.Family)) &&
(selectedTypes.length === 0 || selectedTypes.includes(product.Type)) &&
(selectedBrands.length === 0 || selectedBrands.includes(product.Brand))
);
currentPage = 1;
displayPage(currentPage);
}
async function refreshDropboxToken() {
const dropboxTokenUrl = "https://api.dropboxapi.com/oauth2/token";
const credentials = `${DROPBOX_CONFIG.clientId}:${DROPBOX_CONFIG.clientSecret}`;
const encodedCredentials = btoa(credentials);
const requestOptions = {
method: 'POST',
headers: {
'Authorization': `Basic ${encodedCredentials}`,
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: "refresh_token",
refresh_token: DROPBOX_CONFIG.refreshToken
})
};
const response = await fetch(dropboxTokenUrl, requestOptions);
const data = await response.json();
if (data.access_token) {
DROPBOX_CONFIG.accessToken = data.access_token;
console.log("New Dropbox Access Token Acquired!");
} else {
console.error("Failed to refresh Dropbox token:", data);
console.log("Failed to refresh Dropbox token. Check console for details.");
}
}
// Upload Invoice
async function uploadInvoiceToDropbox(pdfBlob, fileName, orderID) {
await refreshDropboxToken(); // Ensure token is refreshed
const accessToken = DROPBOX_CONFIG.accessToken;
// Paths for both folders
const folderPath1 = `/ColorDemoOrders/pendingorders/${orderID}/${fileName}`;
const folderPath2 = `/ColorDemoOrders/history/${fileName}`; // New history folder
// Upload to primary folder
const response1 = await fetch('https://content.dropboxapi.com/2/files/upload', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/octet-stream',
'Dropbox-API-Arg': JSON.stringify({
path: folderPath1,
mode: 'add',
autorename: true,
mute: false
})
},
body: pdfBlob
});
const result1 = await response1.json();
if (result1.error) {
console.error("Error uploading PDF invoice to main Dropbox folder:", result1.error);
console.log("Failed to upload PDF to Dropbox.");
} else {
console.log("PDF invoice uploaded successfully to main folder:", result1.path_display);
}
// Upload to history folder
const response2 = await fetch('https://content.dropboxapi.com/2/files/upload', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/octet-stream',
'Dropbox-API-Arg': JSON.stringify({
path: folderPath2,
mode: 'add',
autorename: true,
mute: false
})
},
body: pdfBlob
});
const result2 = await response2.json();
if (result2.error) {
console.error("Error uploading PDF invoice to history Dropbox folder:", result2.error);
console.log("Failed to upload PDF to history folder.");
} else {
console.log("PDF invoice uploaded successfully to history folder:", result2.path_display);
}
}
// Upload Order
async function uploadOrderToDropbox(pdfBlob, fileName, orderID) {
await refreshDropboxToken(); // Ensure token is refreshed
const accessToken = DROPBOX_CONFIG.accessToken;
// Paths for both folders
const folderPath1 = `/ColorDemoOrders/pendingorders/${orderID}/${fileName}`;
const folderPath2 = `/ColorDemoOrders/history/${fileName}`; // New history folder
// Upload to primary folder
const response1 = await fetch('https://content.dropboxapi.com/2/files/upload', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/octet-stream',
'Dropbox-API-Arg': JSON.stringify({
path: folderPath1,
mode: 'add',
autorename: true,
mute: false
})
},
body: pdfBlob
});
const result1 = await response1.json();
if (result1.error) {
console.error("Error uploading PDF invoice to main Dropbox folder:", result1.error);
console.log("Failed to upload PDF to Dropbox.");
} else {
console.log("PDF invoice uploaded successfully to main folder:", result1.path_display);
}
// Upload to history folder
const response2 = await fetch('https://content.dropboxapi.com/2/files/upload', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/octet-stream',
'Dropbox-API-Arg': JSON.stringify({
path: folderPath2,
mode: 'add',
autorename: true,
mute: false
})
},
body: pdfBlob
});
const result2 = await response2.json();
if (result2.error) {
console.error("Error uploading PDF invoice to history Dropbox folder:", result2.error);
console.log("Failed to upload PDF to history folder.");
} else {
console.log("PDF invoice uploaded successfully to history folder:", result2.path_display);
}
}
// Helper function to convert blob to base64
function blobToBase64(blob) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result.split(",")[1]); // Get only the Base64 part
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
// Reset Cart
function clearCart() {
cart = []; // Empty the cart array
updateCart(); // Update the cart display
Toastify({ text: "El carrito ha sido vaciado.", duration: 3000, gravity: "top", position: "center" }).showToast();
}
window.onload = function() {
// Extract the query parameter from the URL
const urlParams = new URLSearchParams(window.location.search);
const keyword = urlParams.get('filter'); // Get the 'filter' parameter
if (keyword) {
// Set the search input value to the keyword
document.getElementById('searchInput').value = keyword;
// Optionally, set the keyword as the placeholder
document.getElementById('searchInput').setAttribute("placeholder", keyword);
// Call the filter function to filter products based on the keyword
filterProducts(); // This will use the value from the search input to filter
}
// Ensure products are loaded after page load (if needed)
loadProducts(); // Call loadProducts to load all products if no filter is applied
checkCookieConsent();
loadCartFromCookies();
// history.replaceState(null, '', '/muestras');
};
// Open Quick View Modal
function openQuickView(element) {
const modal = document.getElementById("quick-view-modal");
const modalSwatch = document.getElementById("modal-swatch"); // Target the new swatch div
const modalName = document.getElementById("modal-name");
const modalId = document.getElementById("modal-id");
const modalbrand = document.getElementById("modal-brand");
const modalfamily = document.getElementById("modal-family");
const modalDescription = document.getElementById("modal-description");
// Get the data from the clicked swatch
const hexColor = element.style.background; // Extract the swatch color
modalSwatch.style.background = hexColor; // Apply it to the modal
modalName.textContent = element.dataset.name;
modalId.textContent = "Código: " + element.dataset.id;
modalbrand.textContent = "Marca: " + element.dataset.brand;
modalfamily.textContent = "Familia: " + element.dataset.family;
modalDescription.textContent = "Descripción: " + element.dataset.desc;
// Show modal
modal.style.display = "flex";
}
// Close Modal
document.querySelector(".close").addEventListener("click", function () {
document.getElementById("quick-view-modal").style.display = "none";
});
// Close Quick View Modal and Cart Sidebar when clicking outside
window.addEventListener("click", function (event) {
const modal = document.getElementById("quick-view-modal");
const cartsideb = document.getElementById("cartSidebar");
// Close Quick View Modal
if (event.target === modal) {
modal.style.display = "none";
}
// Prevent closing the cart when clicking inside it or on control buttons
if (
!cartsideb.contains(event.target) &&
!event.target.closest(".cart-button") && // Prevent closing when clicking cart button
!event.target.closest(".quantity") && // Prevent closing when clicking quantity buttons
!event.target.closest(".remove-btn") && // Prevent closing when clicking remove button
!event.target.closest(".quantity-btn") // Prevent closing when clicking + or -
) {
cartsideb.classList.remove("open");
}
});
// Manual Checkout
document.addEventListener("DOMContentLoaded", function () {
const manualCheckoutCheckbox = document.querySelector("input[name='manualcheckout']");
const pagarButton = document.getElementById("pagarButton");
const whatsappButton = document.getElementById("whatsappButton");
const checkoutForm = document.getElementById("checkoutForm");
const cartItems = document.getElementById("cartItems");
const cartTotal = document.getElementById("cartTotal");
const requiredFields = [...checkoutForm.querySelectorAll("input[required], textarea[required]")];
const paymentProofInput = document.querySelector("input[name='paymentProof']");
const paymentProofSection = document.querySelector("h3[name='PmntPr']"); // Select using name attribute
// Function to reset the cart
function resetCart() {
cartItems.innerHTML = ""; // Clear cart items
cartTotal.innerText = "Total: 0.00 HNL"; // Reset total price
checkConditions(); // Recheck conditions to disable buttons
}
// Function to toggle payment proof requirement
function togglePaymentProof() {
if (manualCheckoutCheckbox.checked) {
paymentProofInput.required = false;
paymentProofInput.disabled = true;
paymentProofInput.style.display = "none";
if (paymentProofSection) {
paymentProofSection.style.display = "none"; // Hide the entire section
}
} else {
paymentProofInput.required = true;
paymentProofInput.disabled = false;
paymentProofInput.style.display = "block";
if (paymentProofSection) {
paymentProofSection.style.display = "block"; // Show the entire section
}
}
}
// Function to check if all required conditions are met
function checkConditions() {
const isManualCheckout = manualCheckoutCheckbox.checked;
const isCartEmpty = cartItems.children.length === 0;
// Check required fields and payment proof if not in manual checkout mode
const requiredInputs = requiredFields.filter(field => field !== paymentProofInput);
const allFieldsFilled = requiredInputs.every(field => field.value.trim() !== "");
// If manual checkout is OFF, payment proof is required
const isPaymentProofValid = isManualCheckout || paymentProofInput.files.length > 0;
console.log("Cart Empty:", isCartEmpty, "| All Fields Filled:", allFieldsFilled, "| Manual Checkout:", isManualCheckout, "| Payment Proof Valid:", isPaymentProofValid);
// Enable or disable both buttons
pagarButton.disabled = isCartEmpty || !allFieldsFilled || !isPaymentProofValid;
whatsappButton.disabled = isCartEmpty || !allFieldsFilled;
if (isManualCheckout) {
pagarButton.style.display = "none";
whatsappButton.style.display = "inline-block";
} else {
pagarButton.style.display = "inline-block";
whatsappButton.style.display = "none";
}
// Force-enable the WhatsApp button if conditions are met
if (!whatsappButton.disabled) {
whatsappButton.removeAttribute("disabled");
}
}
// Initialize button state and payment proof on page load
checkConditions();
togglePaymentProof();
// Listen for checkbox changes to switch buttons and payment proof state
manualCheckoutCheckbox.addEventListener("change", function () {
togglePaymentProof();
checkConditions();
});
// Listen for changes in required form fields
requiredFields.forEach(field => {
field.addEventListener("input", checkConditions);
});
// Listen for changes in payment proof upload
paymentProofInput.addEventListener("change", checkConditions);
// Monitor cart changes dynamically
const observer = new MutationObserver(checkConditions);
observer.observe(cartItems, { childList: true });
// Handle WhatsApp button click
whatsappButton.addEventListener("click", async function (event) {
event.preventDefault();
const isCartEmpty = cartItems.children.length === 0;
const requiredInputs = requiredFields.filter(field => field !== paymentProofInput);
const allFieldsFilled = requiredInputs.every(field => field.value.trim() !== "");
if (isCartEmpty) {
Toastify({ text: "Su carrito está vacío. Agregue productos antes de solicitar ayuda.", duration: 3000, gravity: "middle", position: "center" }).showToast();
return;
}
if (!allFieldsFilled) {
Toastify({ text: "Por favor, complete todos los campos requeridos.", duration: 3000, gravity: "middle", position: "center" }).showToast();
return;
}
const formData = new FormData(checkoutForm);
const apiKey = "7215694"; // Your CallMeBot API Key
// Get the subscription preference
const wantsNewsletter = formData.get("subscribe") ? "Sí" : "No";
// Gather order details
// Extract cart items with quantities
let cartDetails = cart.map(item => {
const itemName = item["Paint Name"] || "Producto Desconocido";
const itemCode = item["Paint Code"] || "N/A";
const quantity = item.quantity || 1;
return `📌 ${itemName} (${itemCode}) - x ${quantity}`;
}).join("\n");
// Get discount value
const discountElement = document.getElementById("discountDiv");
const discount = discountElement ? discountElement.innerText : "0 HNL";
// Gather base order details
const baseOrderDetails = `
👤 Nombre: ${formData.get("name")}\n
📧 Email: ${formData.get("email")}\n
📞 Teléfono: ${formData.get("phone")}\n
📍 Dirección: ${formData.get("address")}\n
🏙️ Ciudad: ${formData.get("city")}, ${formData.get("department")}\n`;
// Complete order text
const fullOrderText = `¡Hola! Favor procesar mi pedido. 📦\n\n${baseOrderDetails}\n🛍️ Pedido:\n${cartDetails}\n💰 ${document.getElementById("cartTotal").innerText}\n🎉 ${discount}\n📩 Recibir noticias y ofertas: ${wantsNewsletter}\n📝 Favor indicar el método de pago.`;
// **Encode the message for the WhatsApp URL**
const encodedMessage = encodeURIComponent(fullOrderText);
// **Detect device type & screen width**
const isMobileOrTablet = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
const isNarrowScreen = window.innerWidth <= 768; // Mobile screens
// **Use WhatsApp Web for Desktop & WhatsApp App for Mobile**
const phoneNumber = "50431811871"; // Your WhatsApp Number (without +)
const whatsappMobileURL = `whatsapp://send?phone=${phoneNumber}&text=${encodedMessage}`;
const whatsappWebURL = `https://web.whatsapp.com/send?phone=${phoneNumber}&text=${encodedMessage}`;
function openWhatsApp() {
// **Decide if it should open in the same tab or new tab**
let openInNewTab = !isNarrowScreen; // Open in new tab for tablets & desktops
// **Pre-open a tab only if it's a wide screen**
let newTab = openInNewTab ? window.open("", "_blank") : null;
// Show message before opening WhatsApp
Toastify({
text: "Redirigiendo a WhatsApp. Color Demo nunca te pedirá tu nombre de usuario ni tus contraseñas...",
duration: 2000,
gravity: "middle",
position: "center"
}).showToast();
setTimeout(() => {
if (!openInNewTab) {
// **Mobile: Force immediate navigation to WhatsApp (no confirmation)**
setTimeout(() => { window.location.href = whatsappMobileURL; }, 100);
} else {
newTab.location.href = whatsappWebURL;
}
// **Reset form after opening WhatsApp**
checkoutForm.reset();
manualCheckoutCheckbox.checked = false;
checkConditions();
togglePaymentProof();
cart = []; // Empty the cart array
updateCart(); // Update the cart display
toggleCart();
}, 2000);
}
// **Trigger WhatsApp Opening**
openWhatsApp();
});
});