// ====== ROUTING ====== const routes = ["usuario", "tecnico", "admin"]; const navBtns = document.querySelectorAll("[data-route]");function showRoute(route){ routes.forEach(r=>{ const el = document.getElementById(`view-${r}`); if(!el) return; el.hidden = (r !== route); }); navBtns.forEach(b=>{ b.classList.toggle("active", b.dataset.route === route); }); } navBtns.forEach(b=> b.addEventListener("click", ()=> showRoute(b.dataset.route))); showRoute("usuario");// ====== MOCK DATA ====== const techs = [ { id:"t1", name:"Daniel R.", score:4.8, jobs:312, eta: "12–18 min", priceFrom: 95000, tags:["Verificado","Garantía"], status:"Disponible" }, { id:"t2", name:"María P.", score:4.7, jobs:221, eta: "18–25 min", priceFrom: 105000, tags:["Refrigeración","Verificado"], status:"Disponible" }, { id:"t3", name:"Carlos S.", score:4.6, jobs:408, eta: "25–35 min", priceFrom: 85000, tags:["Electrodomésticos"], status:"En servicio" } ];const states = [ {title:"Solicitud creada", desc:"Tu solicitud fue registrada."}, {title:"Buscando técnicos", desc:"Buscando disponibilidad cerca de ti…"}, {title:"Técnico asignado", desc:"Se asignó un técnico verificado."}, {title:"En camino", desc:"El técnico va hacia tu ubicación."}, {title:"En diagnóstico", desc:"Revisión inicial y confirmación del presupuesto."}, {title:"Reparación", desc:"Trabajo en progreso."}, {title:"Finalizado", desc:"Servicio completado. Puedes pagar y calificar."}, ];let currentState = 0; let selectedTech = null; let userAvailability = true;// ====== UTIL ====== function moneyCOP(n){ return new Intl.NumberFormat("es-CO").format(n); } function setText(id, txt){ const el = document.getElementById(id); if(el) el.textContent = txt; }// ====== TIMELINE ====== function renderTimeline(){ const wrap = document.getElementById("timeline"); wrap.innerHTML = ""; states.forEach((s, idx)=>{ const row = document.createElement("div"); row.className = "step " + (idx < currentState ? "done" : idx === currentState ? "active" : ""); row.innerHTML = `
${idx+1}. ${s.title}
${s.desc}
`; wrap.appendChild(row); }); } renderTimeline();// ====== USER FLOW ====== const techlist = document.getElementById("techlist"); const matchingHint = document.getElementById("matching-hint");function renderTechList(){ techlist.innerHTML = ""; techs.forEach(t=>{ const card = document.createElement("div"); card.className = "techcard"; const badgeClass = t.status === "Disponible" ? "green" : "amber"; card.innerHTML = `
${t.name} ${t.status}
★ ${t.score} • ${t.jobs} servicios • ETA ${t.eta}
Desde $ ${moneyCOP(t.priceFrom)} COP
${t.tags.map(x=>`${x}`).join(" ")}
`; techlist.appendChild(card); });techlist.querySelectorAll("[data-pick]").forEach(btn=>{ btn.addEventListener("click", ()=>{ const id = btn.dataset.pick; selectedTech = techs.find(x=>x.id === id); matchingHint.textContent = `Técnico seleccionado: ${selectedTech.name}. Ya puedes avanzar el estado o abrir chat.`; // Salta a "Técnico asignado" currentState = Math.max(currentState, 2); renderTimeline(); setText("chatSub", `Hablando con ${selectedTech.name} (demo)`); pushChat(`Hola, soy ${selectedTech.name}. Voy en camino apenas confirmes.`, false); }); }); }document.getElementById("btn-buscar").addEventListener("click", ()=>{ matchingHint.textContent = "Buscando… (simulado)"; currentState = Math.max(currentState, 1); renderTimeline(); setTimeout(()=>{ renderTechList(); matchingHint.textContent = "Selecciona un técnico para asignar el servicio."; }, 450); });document.getElementById("btn-estado").addEventListener("click", ()=>{ if(currentState < states.length - 1) currentState++; renderTimeline(); });document.getElementById("btn-reset").addEventListener("click", ()=>{ currentState = 0; selectedTech = null; techlist.innerHTML = ""; matchingHint.textContent = "Haz clic en “Buscar técnicos disponibles”."; renderTimeline(); setRating(0); resetChat(); });document.getElementById("btn-demo-flujo").addEventListener("click", async ()=>{ // Demo automático de 10–15s para presentación document.getElementById("btn-reset").click(); document.getElementById("btn-buscar").click(); await sleep(650); // elige el primero disponible const firstPick = techlist.querySelector("[data-pick]"); if(firstPick) firstPick.click(); await sleep(500); // avanza estados a "En camino" currentState = 3; renderTimeline(); await sleep(700); currentState = 4; renderTimeline(); await sleep(700); currentState = 5; renderTimeline(); await sleep(700); currentState = 6; renderTimeline(); });function sleep(ms){ return new Promise(r=>setTimeout(r,ms)); }// ====== CHAT ====== const chatModal = document.getElementById("chatModal"); const chatBody = document.getElementById("chatBody"); const chatInput = document.getElementById("chatInput");function resetChat(){ chatBody.innerHTML = ""; setText("chatSub", selectedTech ? `Hablando con ${selectedTech.name} (demo)` : "Conectando…"); } function pushChat(text, me){ const b = document.createElement("div"); b.className = "bubble " + (me ? "me" : ""); b.textContent = text; chatBody.appendChild(b); chatBody.scrollTop = chatBody.scrollHeight; } document.getElementById("btn-chat").addEventListener("click", ()=>{ resetChat(); if(!selectedTech){ pushChat("Selecciona un técnico para iniciar conversación.", false); } else { pushChat("¿Podrías confirmar si el equipo presenta algún olor a quemado o solo no enciende?", false); } chatModal.showModal(); }); document.getElementById("btn-close-chat").addEventListener("click", ()=> chatModal.close()); document.getElementById("btn-send-chat").addEventListener("click", ()=>{ const v = chatInput.value.trim(); if(!v) return; pushChat(v, true); chatInput.value = ""; // auto-respuesta demo setTimeout(()=>{ pushChat("Perfecto. Al llegar hago diagnóstico y te confirmo repuesto/tiempo. Gracias.", false); }, 500); }); chatInput.addEventListener("keydown", (e)=>{ if(e.key === "Enter") document.getElementById("btn-send-chat").click(); });// ====== PAGO ====== const payModal = document.getElementById("payModal"); let payMethod = null;document.getElementById("btn-pagar").addEventListener("click", ()=>{ document.getElementById("payHint").textContent = "Elige un método."; payMethod = null; payModal.showModal(); }); document.getElementById("btn-close-pay").addEventListener("click", ()=> payModal.close());document.querySelectorAll(".payopt").forEach(b=>{ b.addEventListener("click", ()=>{ payMethod = b.dataset.pay; document.getElementById("payHint").textContent = `Método seleccionado: ${payMethod.toUpperCase()} (demo).`; }); }); document.getElementById("btn-confirm-pay").addEventListener("click", ()=>{ if(!payMethod){ document.getElementById("payHint").textContent = "Selecciona un método antes de confirmar."; return; } payModal.close(); // fuerza a finalizado si no lo está currentState = Math.max(currentState, 6); renderTimeline(); pushChat("Pago confirmado (demo). ¿Me calificarías con 5 estrellas si quedaste satisfecho?", false); });// ====== RATING ====== let rating = 0; function setRating(n){ rating = n; document.querySelectorAll(".star").forEach(s=>{ s.classList.toggle("on", Number(s.dataset.star) <= rating); }); setText("ratingtext", rating ? `Calificación: ${rating}/5` : "Aún no calificado"); } document.querySelectorAll(".star").forEach(s=>{ s.addEventListener("click", ()=> setRating(Number(s.dataset.star))); });// ====== TECNICO VIEW ====== let techOnline = true; let incomingId = 0; let activeService = null; let techStateIdx = 0;const dispoBtn = document.getElementById("btn-toggle-dispo"); dispoBtn.addEventListener("click", ()=>{ techOnline = !techOnline; dispoBtn.textContent = techOnline ? "Disponible" : "No disponible"; dispoBtn.classList.toggle("primary", techOnline); dispoBtn.classList.toggle("danger", !techOnline); });function renderRequests(){ const wrap = document.getElementById("requests"); wrap.innerHTML = ""; if(!techOnline){ wrap.innerHTML = `
Estás offline. Activa “Disponible” para recibir solicitudes.
`; return; } // si no hay requests if(!window._requests || window._requests.length === 0){ wrap.innerHTML = `
Sin solicitudes por ahora.
`; return; } window._requests.forEach(req=>{ const el = document.createElement("div"); el.className = "req"; el.innerHTML = `
${req.title}
${req.zone} • ${req.problem} • ${req.urgency}
Pago estimado: $ ${moneyCOP(req.total)} COP
`; wrap.appendChild(el); });wrap.querySelectorAll("[data-accept]").forEach(b=>{ b.addEventListener("click", ()=>{ const id = b.dataset.accept; const req = window._requests.find(x=>x.id===id); activeService = req; techStateIdx = 0; window._requests = window._requests.filter(x=>x.id!==id); renderRequests(); renderActiveService(); }); }); wrap.querySelectorAll("[data-decline]").forEach(b=>{ b.addEventListener("click", ()=>{ const id = b.dataset.decline; window._requests = window._requests.filter(x=>x.id!==id); renderRequests(); }); }); }function renderActiveService(){ const wrap = document.getElementById("servicecard"); const hint = document.getElementById("active-hint"); if(!activeService){ hint.textContent = "Acepta una solicitud para ver detalles."; wrap.innerHTML = ""; return; } hint.textContent = `Servicio activo: ${activeService.title}`; const localStates = ["Asignado", "En camino", "Diagnóstico", "Reparación", "Finalizado"]; wrap.innerHTML = `
Cliente${activeService.customer}
Zona${activeService.zone}
Problema${activeService.problem}
Estado${localStates[techStateIdx]}
Total estimado$ ${moneyCOP(activeService.total)} COP
`; }document.getElementById("btn-simular-solicitud").addEventListener("click", ()=>{ if(!techOnline) return; window._requests = window._requests || []; incomingId++; const category = document.getElementById("u-categoria")?.value || "lavadora"; const catName = category === "nevera" ? "Nevera" : category === "electrodomestico" ? "Electrodoméstico" : "Lavadora"; const req = { id: `r${incomingId}`, title: `${catName} • Servicio a domicilio`, zone: "Bogotá, Chapinero", problem: document.getElementById("u-problema")?.value || "No enciende", urgency: document.getElementById("u-urgencia")?.value || "Lo antes posible", customer: "Cliente demo", total: 165000 }; window._requests.unshift(req); renderRequests(); });document.getElementById("btn-tec-estado").addEventListener("click", ()=>{ if(!activeService) return; techStateIdx = Math.min(techStateIdx + 1, 4); renderActiveService(); });document.getElementById("btn-tec-evidencia").addEventListener("click", ()=>{ if(!activeService) return; alert("Evidencia añadida (demo): Foto/nota guardada en el mockup."); });document.getElementById("btn-tec-cerrar").addEventListener("click", ()=>{ if(!activeService) return; techStateIdx = 4; renderActiveService(); alert("Servicio cerrado (demo)."); });renderRequests(); renderActiveService();// ====== ADMIN LOGIN ====== const adminLoginCard = document.getElementById("admin-login-card"); const adminPanelCard = document.getElementById("admin-panel-card");document.getElementById("btn-admin-login").addEventListener("click", ()=>{ const user = document.getElementById("a-user").value.trim(); const pass = document.getElementById("a-pass").value.trim(); if(user === "admin" && pass === "12345"){ adminLoginCard.hidden = true; adminPanelCard.hidden = false; }else{ document.getElementById("admin-login-hint").textContent = "Credenciales incorrectas (demo)."; } });document.getElementById("btn-admin-logout").addEventListener("click", ()=>{ adminPanelCard.hidden = true; adminLoginCard.hidden = false; document.getElementById("admin-login-hint").textContent = "Credenciales demo."; });
screen tagSupport