// ============================================================
// NEW BOSS REGISTRATION — BACKEND ONLY VERSION
// Fuente única de verdad:
// Frontend limpio → nb-registration-worker → Firebase Auth + Firestore
// ============================================================
const REGISTRATION_WORKER_URL = "https://nb-registration-worker.mrmartinezbtc7.workers.dev";
const SUCCESS_LOGIN_URL = "https://newbosslife.com/nb_login.html";
const COMPANY_FALLBACK_TAG = "@NewBoss";
let currentSponsor = {
uid: null,
usernameLower: null,
display: COMPANY_FALLBACK_TAG,
source: "fallback"
};
// ========== ELEMENTOS DOM ==========
const $ = (id) => document.getElementById(id);
// ========== PAÍSES Y WHATSAPP ==========
const countries = [
{ code:"US", name:"Estados Unidos", dial:"+1", flag:"🇺🇸" },
{ code:"MX", name:"México", dial:"+52", flag:"🇲🇽" },
{ code:"CO", name:"Colombia", dial:"+57", flag:"🇨🇴" },
{ code:"VE", name:"Venezuela", dial:"+58", flag:"🇻🇪" },
{ code:"PE", name:"Perú", dial:"+51", flag:"🇵🇪" },
{ code:"CL", name:"Chile", dial:"+56", flag:"🇨🇱" },
{ code:"AR", name:"Argentina", dial:"+54", flag:"🇦🇷" },
{ code:"EC", name:"Ecuador", dial:"+593", flag:"🇪🇨" },
{ code:"DO", name:"República Dominicana", dial:"+1", flag:"🇩🇴" },
{ code:"PR", name:"Puerto Rico", dial:"+1", flag:"🇵🇷" },
{ code:"ES", name:"España", dial:"+34", flag:"🇪🇸" }
];
function onlyDigits(str){
return (str || "").replace(/\D+/g, "");
}
function normalizeUsername(value){
return String(value || "")
.trim()
.toLowerCase()
.normalize("NFD")
.replace(/[\u0300-\u036f]/g, "")
.replace(/\s+/g, "")
.replace(/[^a-z0-9._-]/g, "")
.replace(/^@+/, "");
}
function getParam(name){
const params = new URLSearchParams(window.location.search);
return String(params.get(name) || "").trim();
}
function getSponsorRefFromUrl(){
return (
getParam("ref") ||
getParam("usernameLower") ||
getParam("sponsor") ||
getParam("partnerCode") ||
getParam("code") ||
""
).trim();
}
function populateCountries() {
const select = $("countrySelect");
if (!select) return;
select.innerHTML = "";
countries.forEach(c => {
const opt = document.createElement("option");
opt.value = c.code;
opt.textContent = `${c.flag} ${c.name} (${c.dial})`;
opt.dataset.dial = c.dial;
select.appendChild(opt);
});
}
function guessDefaultCountry() {
const lang = (navigator.language || "").toLowerCase();
if (lang.includes("es-mx")) return "MX";
if (lang.includes("es-co")) return "CO";
if (lang.includes("es-ve")) return "VE";
if (lang.includes("es-pe")) return "PE";
if (lang.includes("es-cl")) return "CL";
if (lang.includes("es-ar")) return "AR";
if (lang.includes("es-ec")) return "EC";
if (lang.includes("es-do")) return "DO";
if (lang.includes("es-pr")) return "PR";
if (lang.includes("es-es")) return "ES";
return "US";
}
function updateE164() {
const select = $("countrySelect");
const selected = select?.options?.[select.selectedIndex];
const dial = selected ? selected.dataset.dial : "+1";
const digits = onlyDigits($("whatsappLocal")?.value || "");
const dialDigits = onlyDigits(dial);
const e164 = (dialDigits && digits) ? (`+${dialDigits}${digits}`) : "";
if ($("whatsappE164")) $("whatsappE164").value = e164;
if ($("e164Preview")) $("e164Preview").textContent = e164 || "—";
}
function setSelectedSide(side = "R"){
const cleanSide = side === "L" ? "L" : "R";
if ($("selectedSide")) $("selectedSide").value = cleanSide;
$("btnSideL")?.classList.remove("active");
$("btnSideR")?.classList.remove("active");
if (cleanSide === "L") {
$("btnSideL")?.classList.add("active");
} else {
$("btnSideR")?.classList.add("active");
}
}
function showMsg(type, text){
const box = $("msg");
if (!box) return;
box.classList.remove("hidden");
box.textContent = text;
box.className = "rounded-xl p-4 text-sm";
if (type === "success") box.classList.add("msg-success");
else if (type === "warning") box.classList.add("msg-warning");
else box.classList.add("msg-error");
}
function clearMsg(){
const box = $("msg");
if (!box) return;
box.classList.add("hidden");
box.textContent = "";
}
function disableButton(disabled){
const btn = $("btnCreate");
if (!btn) return;
btn.disabled = !!disabled;
btn.classList.toggle("opacity-70", !!disabled);
btn.classList.toggle("cursor-not-allowed", !!disabled);
}
function friendlyWorkerError(error){
const msg = String(error?.message || error || "Error");
if (msg.includes("username_taken")) return "Ese username ya está en uso. Elige otro.";
if (msg.includes("email_exists") || msg.includes("EMAIL_EXISTS")) return "Ese correo ya está en uso.";
if (msg.includes("weak_password") || msg.includes("WEAK_PASSWORD")) return "La contraseña es muy débil.";
if (msg.includes("missing_username")) return "Escribe un username válido.";
if (msg.includes("invalid_email")) return "Escribe un correo válido.";
if (msg.includes("missing_password")) return "Escribe una contraseña válida.";
if (msg.includes("sponsor_not_found")) return "No se encontró el sponsor. Verifica el link o código.";
if (msg.includes("binary_parent_slot_taken")) return "Ese espacio binario ya fue ocupado. Elige otro lado o refresca.";
if (msg.includes("registration_code_invalid")) return "El código de registro no es válido.";
if (msg.includes("registration_code_used")) return "Ese código de registro ya fue usado.";
return msg;
}
async function postRegistrationWorker(path, payload = {}){
const res = await fetch(`${REGISTRATION_WORKER_URL}${path}`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-newboss-source": "nb_register_backend_only"
},
body: JSON.stringify(payload)
});
const data = await res.json().catch(() => ({}));
if (!res.ok || data.ok === false) {
const err = new Error(data.message || data.error || `worker_error_${res.status}`);
err.status = res.status;
err.data = data;
throw err;
}
return data;
}
async function resolveSponsor(ref){
const cleanRef = String(ref || "").replace(/^@/, "").trim();
if (!cleanRef) {
currentSponsor = {
uid: null,
usernameLower: null,
display: COMPANY_FALLBACK_TAG,
source: "fallback"
};
if ($("sponsor")) $("sponsor").value = COMPANY_FALLBACK_TAG;
return currentSponsor;
}
try {
const data = await postRegistrationWorker("/register/resolve-sponsor", {
ref: cleanRef
});
if (data?.found && data?.sponsor) {
currentSponsor = {
uid: data.sponsor.sponsorUid || null,
usernameLower: data.sponsor.sponsorUsernameLower || cleanRef,
display: data.sponsor.sponsorDisplay ? `@${String(data.sponsor.sponsorUsernameLower || data.sponsor.sponsorDisplay).replace(/^@/, "")}` : `@${cleanRef}`,
source: data.sponsor.source || "worker"
};
if ($("sponsor")) $("sponsor").value = currentSponsor.display;
return currentSponsor;
}
} catch (err) {
console.warn("[NB REGISTER] sponsor resolve failed:", err?.message || err);
}
currentSponsor = {
uid: null,
usernameLower: null,
display: COMPANY_FALLBACK_TAG,
source: "fallback"
};
if ($("sponsor")) $("sponsor").value = COMPANY_FALLBACK_TAG;
return currentSponsor;
}
async function copyText(text){
try{
await navigator.clipboard.writeText(String(text || ""));
return true;
}catch(e){
try {
const ta = document.createElement("textarea");
ta.value = String(text || "");
ta.style.position = "fixed";
ta.style.left = "-9999px";
document.body.appendChild(ta);
ta.focus();
ta.select();
document.execCommand("copy");
document.body.removeChild(ta);
return true;
} catch {
return false;
}
}
}
function openSuccessOverlay({ usernameLower, email, password, sponsorDisplay, loginUrl }){
if ($("succUsername")) $("succUsername").textContent = "@" + usernameLower;
if ($("succEmail")) $("succEmail").textContent = email;
if ($("succPassword")) $("succPassword").textContent = password;
if ($("succCreatedAt")) $("succCreatedAt").textContent = new Date().toLocaleString();
if ($("succSponsor")) $("succSponsor").textContent = sponsorDisplay || currentSponsor.display || COMPANY_FALLBACK_TAG;
const finalLoginUrl = loginUrl || SUCCESS_LOGIN_URL;
if ($("succLoginLink")) {
$("succLoginLink").href = finalLoginUrl;
$("succLoginLink").textContent = finalLoginUrl;
}
$("successOverlay")?.classList.add("show");
}
function closeSuccessOverlay(){
$("successOverlay")?.classList.remove("show");
}
function resetFormForAnother(){
closeSuccessOverlay();
["inviteCode", "username", "firstName", "lastName", "email", "password", "password2", "whatsappLocal"].forEach((id) => {
if ($(id)) $(id).value = "";
});
updateE164();
clearMsg();
setSelectedSide("R");
window.scrollTo({ top: 0, behavior: "smooth" });
}
function validateForm(payload, password2){
if (!payload.username || payload.username.length < 3) return "Escribe un username válido (mínimo 3 caracteres).";
if (!payload.email || !payload.email.includes("@")) return "Escribe un correo válido.";
if (!payload.whatsapp || payload.whatsapp.length < 8) return "Escribe tu WhatsApp con código de país.";
if (!payload.password || payload.password.length < 6) return "La contraseña debe tener mínimo 6 caracteres.";
if (payload.password !== password2) return "Las contraseñas no coinciden.";
if (!payload.firstName || payload.firstName.length < 2) return "Escribe tu nombre.";
if (!payload.lastName || payload.lastName.length < 2) return "Escribe tu apellido.";
return "";
}
function buildRegistrationPayload(){
const usernameRaw = $("username")?.value || "";
const usernameLower = normalizeUsername(usernameRaw);
const email = String($("email")?.value || "").trim().toLowerCase();
const firstName = String($("firstName")?.value || "").trim();
const lastName = String($("lastName")?.value || "").trim();
const whatsapp = String($("whatsappE164")?.value || "").trim();
const password = String($("password")?.value || "");
const inviteCode = String($("inviteCode")?.value || "").trim();
const placementSide = $("selectedSide")?.value === "L" ? "L" : "R";
const urlRef = getSponsorRefFromUrl();
return {
username: usernameLower,
usernameLower,
email,
password,
firstName,
lastName,
whatsapp,
inviteCode,
registrationCode: inviteCode,
ref: urlRef || currentSponsor.usernameLower || currentSponsor.display || "",
sponsorUid: currentSponsor.uid || "",
sponsorUsernameLower: currentSponsor.usernameLower || "",
placementSide,
requestedSide: placementSide,
accessMode: "FULL",
source: "nb_register_backend_only",
pageUrl: window.location.href,
userAgent: navigator.userAgent || "",
language: navigator.language || ""
};
}
async function createFullAccount(){
clearMsg();
disableButton(true);
try {
const payload = buildRegistrationPayload();
const password2 = String($("password2")?.value || "");
const validationError = validateForm(payload, password2);
if (validationError) {
showMsg("error", validationError);
disableButton(false);
return;
}
showMsg("warning", "Creando cuenta desde Registration Worker...");
const data = await postRegistrationWorker("/register/full", payload);
showMsg("success", "¡Cuenta creada exitosamente!");
openSuccessOverlay({
usernameLower: data.usernameLower || payload.usernameLower,
email: data.email || payload.email,
password: payload.password,
sponsorDisplay: data.sponsor?.sponsorUsernameLower ? `@${data.sponsor.sponsorUsernameLower}` : currentSponsor.display,
loginUrl: data.loginUrl || SUCCESS_LOGIN_URL
});
} catch (err) {
console.error("[NB REGISTER] register/full failed:", err);
showMsg("error", "No se pudo crear la cuenta: " + friendlyWorkerError(err));
} finally {
disableButton(false);
}
}
// ========== EVENTOS ==========
$("btnHasCode")?.addEventListener("click", () => {
window.scrollTo({ top: $("formWrap")?.offsetTop - 24 || 0, behavior: "smooth" });
});
$("btnNoCode")?.addEventListener("click", () => {
window.location.href = "nb_packages_v2.html";
});
$("btnLite")?.addEventListener("click", () => {
window.location.href = "register_lite.html";
});
$("btnHow")?.addEventListener("click", () => {
$("infoBox")?.classList.toggle("hidden");
});
$("btnCloseSuccess")?.addEventListener("click", closeSuccessOverlay);
$("btnGoToLogin")?.addEventListener("click", () => {
window.location.href = SUCCESS_LOGIN_URL;
});
$("btnCreateAnother")?.addEventListener("click", resetFormForAnother);
document.querySelectorAll(".btnCopy").forEach(btn => {
btn.addEventListener("click", async () => {
const id = btn.getAttribute("data-copy");
const el = document.getElementById(id);
const ok = await copyText(el?.textContent || "");
if(ok) alert("✅ Copiado");
else alert("❌ No se pudo copiar");
});
});
$("btnCopyLoginLink")?.addEventListener("click", async () => {
const a = $("succLoginLink");
const ok = await copyText(a?.getAttribute("href") || a?.textContent || "");
if(ok) alert("✅ Link copiado");
else alert("❌ No se pudo copiar");
});
$("btnSideL")?.addEventListener("click", () => setSelectedSide("L"));
$("btnSideR")?.addEventListener("click", () => setSelectedSide("R"));
$("btnCreate")?.addEventListener("click", createFullAccount);
// ========== INIT ==========
populateCountries();
const defaultCountryIndex = countries.findIndex(c => c.code === guessDefaultCountry());
$("countrySelect").selectedIndex = defaultCountryIndex >= 0 ? defaultCountryIndex : 0;
$("countrySelect")?.addEventListener("change", updateE164);
$("whatsappLocal")?.addEventListener("input", (e) => {
const cleaned = onlyDigits(e.target.value);
if (e.target.value !== cleaned) e.target.value = cleaned;
updateE164();
});
updateE164();
const sideFromUrl = String(getParam("placementSide") || getParam("side") || "").toUpperCase();
setSelectedSide(sideFromUrl === "L" ? "L" : "R");
await resolveSponsor(getSponsorRefFromUrl());
}
});