/* =========================================================
CONFIGURACIÓN CENTRAL DEL SITIO — PURELABS MÉXICO
-----------------------------------------------------------
Edita SOLO este archivo para actualizar los datos de
contacto/negocio en TODO el sitio (header, footer, botón
flotante de WhatsApp, checkout por WhatsApp, etc.).
Los valores marcado con [ ] son placeholders: reemplázalos
por tus datos reales antes de publicar el sitio.
========================================================= */
const SITE_CONFIG = {
// Identidad
brandName: "Purelabs México",
tagline: "Péptidos de grado investigación, calidad certificada",
// Contacto — reemplaza con tus datos reales
whatsappNumber: "5215655653224", // formato: 52 + 10 dígitos, sin espacios ni signos
whatsappDisplay: "+52 56 5565 3224", // ej. +52 55 0000 0000
email: "atencionaclientes@purelabs.mx",
city: "Monterrey, Nuevo León",
addressLine: "[DIRECCIÓN FISCAL / CENTRO DE OPERACIONES]",
// Datos fiscales — persona moral (para sección de facturación)
razonSocial: "[RAZÓN SOCIAL S.A. DE C.V.]",
rfc: "[RFC DE LA EMPRESA]",
regimenFiscal: "[RÉGIMEN FISCAL]",
// Mensajes de WhatsApp
whatsappGreeting: "Hola, bienvenido a Purelabs México. ¿Podemos ayudarte con información de catálogo, COA o tu pedido?",
// Métodos de pago que se muestran en el sitio (edítalos según lo que actives)
paymentMethods: ["Transferencia SPEI", "Tarjeta de crédito/débito (próximamente vía pasarela)", "Mercado Pago (por integrar)", "USDT / BTC (opcional)"],
};
// ---- Helpers para construir enlaces de WhatsApp ----
function buildWhatsAppLink(message){
const base = "https://wa.me/" + SITE_CONFIG.whatsappNumber;
return message ? base + "?text=" + encodeURIComponent(message) : base;
}
/* =========================================================
PURELABS MÉXICO — Catálogo base (7 SKU estrella)
-----------------------------------------------------------
Todos los precios son PLACEHOLDER en MXN — ajústalos a tu
costo real antes de publicar. Las rutas "img" apuntan a
/img/productos/ — ver img/productos/LEEME.txt para los
nombres y tamaños exactos de imagen que debes subir.
========================================================= */
const PRODUCTS = [
{
id: "bpc-157",
name: "BPC-157",
tag: "Más vendido",
category: "Reparación / Recuperación",
short: "Péptido sintético de investigación estudiado por su rol en modelos de reparación tisular y recuperación.",
purity: "99.2%",
presentations: [
{ label: "5 mg", price: 990 },
{ label: "10 mg", price: 1690 },
],
img: "img/productos/bpc-157.jpg",
},
{
id: "tb-500",
name: "TB-500",
tag: "Popular",
category: "Reparación / Recuperación",
short: "Fragmento sintético de Timosina Beta-4, utilizado en investigación de modelos de regeneración tisular.",
purity: "99.1%",
presentations: [
{ label: "5 mg", price: 1050 },
{ label: "10 mg", price: 1790 },
],
img: "img/productos/tb-500.jpg",
},
{
id: "cjc-1295-ipamorelin",
name: "CJC-1295 / Ipamorelin Blend",
tag: "Combo",
category: "Eje GH / Secretagogos",
short: "Combinación de análogo de GHRH y secretagogo selectivo de GH, ampliamente referenciada en literatura de investigación.",
purity: "99.3%",
presentations: [
{ label: "5 mg blend", price: 1290 },
{ label: "10 mg blend", price: 2190 },
],
img: "img/productos/cjc-1295-ipamorelin.jpg",
},
{
id: "semaglutida",
name: "Semaglutida",
tag: "Alta demanda",
category: "Metabólico",
short: "Análogo de GLP-1 de uso extendido en estudios de investigación metabólica.",
purity: "99.4%",
presentations: [
{ label: "5 mg", price: 1590 },
{ label: "10 mg", price: 2690 },
],
img: "img/productos/semaglutida.jpg",
},
{
id: "tirzepatida",
name: "Tirzepatida",
tag: "Nuevo",
category: "Metabólico",
short: "Agonista dual GIP/GLP-1 empleado en protocolos de investigación metabólica avanzada.",
purity: "99.2%",
presentations: [
{ label: "10 mg", price: 2390 },
{ label: "20 mg", price: 3990 },
],
img: "img/productos/tirzepatida.jpg",
},
{
id: "ghk-cu",
name: "GHK-Cu (Péptido de cobre)",
tag: "Piel / Dérmico",
category: "Estética / Dérmico",
short: "Complejo péptido-cobre estudiado en investigación dérmica y de matriz extracelular.",
purity: "99.0%",
presentations: [
{ label: "50 mg", price: 890 },
{ label: "100 mg", price: 1490 },
],
img: "img/productos/ghk-cu.jpg",
},
{
id: "retatrutide",
name: "Retatrutide",
tag: "Tendencia",
category: "Metabólico",
short: "Triple agonista (GIP/GLP-1/glucagón) de interés creciente en investigación metabólica.",
purity: "99.1%",
presentations: [
{ label: "10 mg", price: 2790 },
{ label: "20 mg", price: 4590 },
],
img: "img/productos/retatrutide.jpg",
},
];
function getProductById(id) {
return PRODUCTS.find(function (p) { return p.id === id; });
}
/* =========================================================
PURELABS MÉXICO — cart.js
Carrito de compras basado en localStorage + checkout vía
WhatsApp. Cuando conectes una pasarela real (Mercado Pago,
Stripe, etc.) sustituye la función checkoutWhatsApp() por
tu integración de pago.
========================================================= */
const CART_KEY = "plmx_cart";
function getCart() {
try {
return JSON.parse(localStorage.getItem(CART_KEY)) || [];
} catch (e) {
return [];
}
}
function saveCart(cart) {
localStorage.setItem(CART_KEY, JSON.stringify(cart));
updateCartBadge();
}
function addToCart(productId, presentationLabel, price, qty) {
const cart = getCart();
const existing = cart.find(function (i) {
if (i.productId !== productId) return false;
return i.presentation === presentationLabel;
});
if (existing) {
existing.qty += qty;
} else {
const product = getProductById(productId);
cart.push({
productId: productId,
name: product ? product.name : productId,
img: product ? product.img : "",
presentation: presentationLabel,
price: price,
qty: qty,
});
}
saveCart(cart);
if (typeof showToast === "function") showToast("Agregado al carrito ✓");
}
function removeFromCart(index) {
const cart = getCart();
cart.splice(index, 1);
saveCart(cart);
if (typeof renderCartPage === "function") renderCartPage();
}
function changeQty(index, delta) {
const cart = getCart();
if (!cart[index]) return;
cart[index].qty = Math.max(1, cart[index].qty + delta);
saveCart(cart);
if (typeof renderCartPage === "function") renderCartPage();
}
function cartTotal() {
return getCart().reduce(function (sum, item) {
return sum + item.price * item.qty;
}, 0);
}
function formatMXN(n) {
return "$" + n.toLocaleString("es-MX") + " MXN";
}
/* ---------- Render de la página carrito.html ---------- */
function renderCartPage() {
const wrap = document.getElementById("cart-wrap");
if (!wrap) return;
const cart = getCart();
if (cart.length === 0) {
wrap.innerHTML =
'
' +
"
Tu carrito está vacío " +
'
Explora el catálogo y agrega péptidos de investigación.
' +
'
Ver catálogo ' +
"
";
return;
}
let rows = "";
cart.forEach(function (item, idx) {
rows +=
"" +
'' +
'
' +
'
🧪
' +
"
" + item.name + " " + item.presentation + "
" +
"
" +
"" + formatMXN(item.price) + " " +
'' +
'− ' +
' ' +
'+ ' +
"
" +
"" + formatMXN(item.price * item.qty) + " " +
'Eliminar ' +
" ";
});
const total = cartTotal();
wrap.innerHTML =
'' +
'
Producto Precio Cantidad Subtotal ' +
rows +
"
" +
'
' +
'
Subtotal ' + formatMXN(total) + "
" +
'
Envío Se cotiza por WhatsApp
' +
'
Total estimado ' + formatMXN(total) + "
" +
'
Enviar pedido por WhatsApp ' +
'
Al enviar tu pedido, un asesor confirmará disponibilidad, forma de pago (SPEI, tarjeta o cripto) y tiempos de envío.
' +
"
";
// Actualiza contenedores de grid a una sola columna en móvil
const gridEl = wrap.querySelector(".grid");
if (window.innerWidth < 800) {
if (gridEl) gridEl.style.gridTemplateColumns = "1fr";
}
}
function checkoutWhatsApp() {
const cart = getCart();
if (cart.length === 0) return;
let msg = "Hola, quiero hacer un pedido en " + (typeof SITE_CONFIG !== "undefined" ? SITE_CONFIG.brandName : "Purelabs México") + ":\n\n";
cart.forEach(function (item) {
msg += "• " + item.name + " (" + item.presentation + ") x" + item.qty + " — " + formatMXN(item.price * item.qty) + "\n";
});
msg += "\nTotal estimado: " + formatMXN(cartTotal());
msg += "\n\nQuedo atento para confirmar disponibilidad, forma de pago y envío.";
window.open(buildWhatsAppLink(msg), "_blank");
}
document.addEventListener("DOMContentLoaded", function () {
if (document.getElementById("cart-wrap")) renderCartPage();
});
/* =========================================================
PURELABS MÉXICO — main.js
Lógica compartida en todas las páginas: nav móvil, FAQ,
age-gate, inyección de datos de contacto, toast, WhatsApp.
========================================================= */
document.addEventListener("DOMContentLoaded", function () {
injectContactData();
setupNavToggle();
setupFaqAccordion();
setupAgeGate();
setupWhatsAppFloat();
updateCartBadge();
});
/* ---------- Inyecta datos de SITE_CONFIG en el DOM ---------- */
function injectContactData() {
if (typeof SITE_CONFIG === "undefined") return;
document.querySelectorAll("[data-cfg]").forEach(function (el) {
const key = el.getAttribute("data-cfg");
if (SITE_CONFIG[key] !== undefined) el.textContent = SITE_CONFIG[key];
});
document.querySelectorAll("[data-cfg-href]").forEach(function (el) {
const key = el.getAttribute("data-cfg-href");
if (key === "whatsapp") el.setAttribute("href", buildWhatsAppLink());
else if (key === "email") el.setAttribute("href", "mailto:" + SITE_CONFIG.email);
});
document.querySelectorAll("[data-cfg-brand]").forEach(function (el) {
el.textContent = SITE_CONFIG.brandName;
});
}
/* ---------- Nav móvil ---------- */
function setupNavToggle() {
const toggle = document.querySelector(".nav-toggle");
const nav = document.querySelector(".main-nav");
if (!toggle || !nav) return;
toggle.addEventListener("click", function () {
nav.classList.toggle("open");
toggle.textContent = nav.classList.contains("open") ? "✕" : "☰";
});
nav.querySelectorAll("a").forEach(function (a) {
a.addEventListener("click", function () {
nav.classList.remove("open");
toggle.textContent = "☰";
});
});
}
/* ---------- Acordeón de FAQ ---------- */
function setupFaqAccordion() {
document.querySelectorAll(".faq-item").forEach(function (item) {
const q = item.querySelector(".faq-q");
if (!q) return;
q.addEventListener("click", function () {
const wasOpen = item.classList.contains("open");
item.parentElement.querySelectorAll(".faq-item").forEach(function (i) {
i.classList.remove("open");
});
if (!wasOpen) item.classList.add("open");
});
});
}
/* ---------- Age gate / aviso de uso exclusivo de investigación ---------- */
function setupAgeGate() {
const overlay = document.getElementById("age-gate");
if (!overlay) return;
const KEY = "plmx_age_confirmed_at";
const last = localStorage.getItem(KEY);
const DAY = 24 * 60 * 60 * 1000;
if (last) {
if (Date.now() - Number(last) < DAY) {
overlay.classList.add("hidden");
return;
}
}
overlay.classList.remove("hidden");
document.body.style.overflow = "hidden";
const enterBtn = document.getElementById("age-gate-enter");
const exitBtn = document.getElementById("age-gate-exit");
if (enterBtn) {
enterBtn.addEventListener("click", function () {
localStorage.setItem(KEY, String(Date.now()));
overlay.classList.add("hidden");
document.body.style.overflow = "";
});
}
if (exitBtn) {
exitBtn.addEventListener("click", function () {
window.location.href = "https://www.google.com";
});
}
}
/* ---------- Botón flotante de WhatsApp ---------- */
function setupWhatsAppFloat() {
const btn = document.querySelector(".wa-float");
if (!btn || typeof SITE_CONFIG === "undefined") return;
btn.setAttribute("href", buildWhatsAppLink(SITE_CONFIG.whatsappGreeting));
btn.setAttribute("target", "_blank");
btn.setAttribute("rel", "noopener");
}
/* ---------- Toast genérico ---------- */
function showToast(message) {
let toast = document.getElementById("toast");
if (!toast) {
toast = document.createElement("div");
toast.id = "toast";
document.body.appendChild(toast);
}
toast.textContent = message;
toast.classList.add("show");
clearTimeout(window.__toastTimer);
window.__toastTimer = setTimeout(function () {
toast.classList.remove("show");
}, 2600);
}
/* ---------- Badge del carrito (definido a fondo en cart.js) ---------- */
function updateCartBadge() {
const el = document.querySelector(".cart-count");
if (!el || typeof getCart !== "function") return;
const cart = getCart();
const count = cart.reduce(function (sum, item) { return sum + item.qty; }, 0);
el.textContent = count;
el.style.display = count > 0 ? "flex" : "none";
}
/* =========================================================
PURELABS MÉXICO — catalog.js
Renderiza la cuadrícula de productos en index.html (destacados)
y catalogo.html (catálogo completo con filtros por categoría).
========================================================= */
function productCardHTML(p) {
const minPrice = Math.min.apply(null, p.presentations.map(function (x) { return x.price; }));
return (
'' +
'' +
'
' + p.tag + " " +
'
' +
'
🧪 Imagen de producto ' + p.name + "
" +
"
" +
'' +
"
" + p.name + " " +
'
Pureza ' + p.purity + " " + p.category + " COA incluido
" +
"
" + p.short + "
" +
'
' +
'
' + formatMXN(minPrice) + 'desde / por presentación
' +
'
Ver producto ' +
"
"
);
}
function renderProductGrid(targetId, limit) {
const el = document.getElementById(targetId);
if (!el) return;
const list = limit ? PRODUCTS.slice(0, limit) : PRODUCTS;
el.innerHTML = list.map(productCardHTML).join("");
}
function renderCatalogWithFilters() {
const grid = document.getElementById("catalog-grid");
if (!grid) return;
const categories = ["Todos"].concat(
PRODUCTS.reduce(function (acc, p) {
if (acc.indexOf(p.category) === -1) acc.push(p.category);
return acc;
}, [])
);
const chipRow = document.getElementById("catalog-filters");
if (chipRow) {
chipRow.innerHTML = categories
.map(function (c, i) {
return '' + c + " ";
})
.join("");
chipRow.querySelectorAll(".chip").forEach(function (chip) {
chip.addEventListener("click", function () {
chipRow.querySelectorAll(".chip").forEach(function (c) { c.classList.remove("active"); });
chip.classList.add("active");
const cat = chip.getAttribute("data-cat");
const filtered = cat === "Todos" ? PRODUCTS : PRODUCTS.filter(function (p) { return p.category === cat; });
grid.innerHTML = filtered.map(productCardHTML).join("");
});
});
}
grid.innerHTML = PRODUCTS.map(productCardHTML).join("");
}
document.addEventListener("DOMContentLoaded", function () {
renderProductGrid("featured-grid", 4);
renderCatalogWithFilters();
});
/* =========================================================
PURELABS MÉXICO — product-detail.js
Rellena la página de producto individual (producto-*.html)
a partir de PRODUCTS (products.js), usando el atributo
data-product-id del .
========================================================= */
let __selectedPresIndex = 0;
function renderProductDetail() {
const root = document.getElementById("pd-root");
if (!root) return;
const id = document.body.getAttribute("data-product-id");
const p = getProductById(id);
if (!p) {
root.innerHTML = "Producto no encontrado.
";
return;
}
document.title = p.name + " — " + (typeof SITE_CONFIG !== "undefined" ? SITE_CONFIG.brandName : "Purelabs México");
const crumbEl = document.getElementById("pd-crumb-name");
if (crumbEl) crumbEl.textContent = p.name;
root.innerHTML =
'' +
'
' +
'
' +
'
🧪 Imagen principal ' + p.name + 'Coloca ' + p.img + ' — 1000x1000px sugerido
' +
"
" +
'
' +
[1, 2, 3].map(function (n) {
return '
' +
'
🧪
';
}).join("") +
"
" +
'' +
'
Pureza ' + p.purity + ' ' + p.category + ' HPLC verificado
' +
'
' + p.name + " " +
"
" + p.short + "
" +
'
' + formatMXN(p.presentations[0].price) + "
" +
'
' +
"
Presentación " +
'
' +
p.presentations
.map(function (pres, i) {
return '' + pres.label + " ";
})
.join("") +
"
" +
'
" +
'
" +
'
📄 Certificado de análisis (COA) por lote disponible bajo solicitud, indicando el número de lote de tu pedido.
' +
"
";
// Tabs (Descripción / Uso en investigación / Envío y almacenamiento)
const tabsWrap = document.getElementById("pd-tabs");
if (tabsWrap) {
tabsWrap.innerHTML =
'' +
'Descripción ' +
'Uso en investigación ' +
'Envío y almacenamiento ' +
"
" +
'' + p.short + ' Producto de grado investigación, sintetizado y analizado bajo control de calidad, con verificación de pureza mediante HPLC en cada lote. La ficha técnica completa y el COA correspondiente se comparten junto con el pedido cuando están disponibles.
' +
'Este producto se comercializa exclusivamente para fines de investigación científica y de laboratorio . No está destinado para consumo humano, uso médico, veterinario, diagnóstico o tratamiento. El manejo debe realizarse únicamente por personal calificado dentro de entornos adecuados de investigación, siguiendo los protocolos y normativas aplicables.
' +
'Se envía liofilizado en polvo, estable a temperatura ambiente durante el traslado. Empaque sellado y protegido para conservar la integridad del producto. Una vez recibido, se recomienda almacenar según la ficha técnica específica (generalmente refrigerado y protegido de la luz tras la reconstitución).
';
tabsWrap.querySelectorAll(".pd-tab-nav button").forEach(function (btn) {
btn.addEventListener("click", function () {
tabsWrap.querySelectorAll(".pd-tab-nav button").forEach(function (b) { b.classList.remove("active"); });
tabsWrap.querySelectorAll(".pd-tab-panel").forEach(function (pnl) { pnl.classList.remove("active"); });
btn.classList.add("active");
tabsWrap.querySelector('[data-panel="' + btn.getAttribute("data-tab") + '"]').classList.add("active");
});
});
}
// Interactividad de presentación / cantidad / carrito
__selectedPresIndex = 0;
const presRow = document.getElementById("pd-pres-row");
const priceEl = document.getElementById("pd-price");
const qtyEl = document.getElementById("pd-qty");
presRow.querySelectorAll(".pres-btn").forEach(function (btn) {
btn.addEventListener("click", function () {
presRow.querySelectorAll(".pres-btn").forEach(function (b) { b.classList.remove("active"); });
btn.classList.add("active");
__selectedPresIndex = Number(btn.getAttribute("data-idx"));
priceEl.textContent = formatMXN(p.presentations[__selectedPresIndex].price);
});
});
document.getElementById("pd-qty-minus").addEventListener("click", function () {
qtyEl.value = Math.max(1, Number(qtyEl.value) - 1);
});
document.getElementById("pd-qty-plus").addEventListener("click", function () {
qtyEl.value = Number(qtyEl.value) + 1;
});
document.getElementById("pd-add-cart").addEventListener("click", function () {
const pres = p.presentations[__selectedPresIndex];
addToCart(p.id, pres.label, pres.price, Number(qtyEl.value));
});
const waBtn = document.getElementById("pd-wa-btn");
if (waBtn) {
if (typeof buildWhatsAppLink === "function") {
waBtn.setAttribute("href", buildWhatsAppLink("Hola, tengo una pregunta sobre " + p.name + "."));
}
}
// Productos relacionados
const relatedGrid = document.getElementById("related-grid");
if (relatedGrid) {
const related = PRODUCTS.filter(function (x) { return x.id !== p.id; }).slice(0, 3);
relatedGrid.innerHTML = related.map(productCardHTML).join("");
}
}
document.addEventListener("DOMContentLoaded", renderProductDetail);
/* =========================================================
PURELABS MÉXICO — calculadora.js
Calculadora de reconstitución para fines de documentación
de investigación. NO constituye indicación de dosis, uso
humano ni consejo médico — ver aviso en calculadora.html.
========================================================= */
function calcReconstitucion() {
const mg = parseFloat(document.getElementById("calc-mg").value);
const water = parseFloat(document.getElementById("calc-water").value);
const doseMcg = parseFloat(document.getElementById("calc-dose").value);
const resultBox = document.getElementById("calc-result");
if (!mg || !water || !doseMcg || mg <= 0 || water <= 0 || doseMcg <= 0) {
resultBox.classList.add("hidden");
return;
}
const concentrationMcgPerMl = (mg * 1000) / water; // mcg/mL
const volumePerDoseMl = doseMcg / concentrationMcgPerMl; // mL
const unitsOnSyringe100 = volumePerDoseMl * 100; // jeringa de insulina de 100 UI = 1 mL
const dosesPerVial = (mg * 1000) / doseMcg;
document.getElementById("calc-concentration").textContent = concentrationMcgPerMl.toFixed(1) + " mcg/mL";
document.getElementById("calc-volume").textContent = volumePerDoseMl.toFixed(3) + " mL";
document.getElementById("calc-units").textContent = unitsOnSyringe100.toFixed(1) + " UI (jeringa 100 UI)";
document.getElementById("calc-doses").textContent = Math.floor(dosesPerVial) + " dosis por vial";
resultBox.classList.remove("hidden");
}
document.addEventListener("DOMContentLoaded", function () {
const form = document.getElementById("calc-form");
if (!form) return;
form.querySelectorAll("input").forEach(function (input) {
input.addEventListener("input", calcReconstitucion);
});
});