/** @odoo-module **/ // Sales rep portal - new service call form interactions. // Uses Odoo 19 public Interaction class per project frontend rules // (NOT IIFE / DOMContentLoaded). Uses only safe DOM construction // (textContent + createElement) - no innerHTML, no XSS risk. import { Interaction } from "@web/public/interaction"; import { registry } from "@web/core/registry"; import { rpc } from "@web/core/network/rpc"; export class SalesRepRepairIntake extends Interaction { static selector = ".o_fusion_repairs_portal"; dynamicContent = { "#partner_search": { "t-on-input": this._onPartnerSearchInput, }, }; setup() { this._partnerSearchTimer = null; } _onPartnerSearchInput(ev) { const query = (ev.target.value || "").trim(); if (this._partnerSearchTimer) { clearTimeout(this._partnerSearchTimer); } if (query.length < 3) { this._renderMatches([]); return; } this._partnerSearchTimer = setTimeout(async () => { try { const result = await rpc("/my/repair/lookup_partner", { query }); this._renderMatches(result.matches || []); } catch (e) { this._renderMatches([]); } }, 250); } _renderMatches(matches) { const list = document.getElementById("partner_matches"); if (!list) { return; } while (list.firstChild) { list.removeChild(list.firstChild); } for (const m of matches) { list.appendChild(this._buildMatchItem(m)); } } _buildMatchItem(m) { const item = document.createElement("button"); item.type = "button"; item.className = "list-group-item list-group-item-action text-start"; const nameStrong = document.createElement("strong"); nameStrong.textContent = m.name || ""; item.appendChild(nameStrong); if (m.phone) { const phone = document.createElement("span"); phone.className = "text-muted ms-2"; phone.textContent = m.phone; item.appendChild(phone); } if (m.repair_count) { const badge = document.createElement("span"); badge.className = "badge bg-secondary ms-2"; badge.textContent = `${m.repair_count} repair(s)`; item.appendChild(badge); } if (m.street) { const addr = document.createElement("div"); addr.className = "small text-muted"; addr.textContent = [m.street, m.city].filter(Boolean).join(", "); item.appendChild(addr); } item.addEventListener("click", () => this._selectPartner(m)); return item; } _selectPartner(m) { document.getElementById("partner_id_input").value = m.id; document.getElementById("partner_selected_name").textContent = m.name + (m.phone ? ` (${m.phone})` : ""); document .getElementById("partner_selected") .classList.remove("d-none"); const list = document.getElementById("partner_matches"); while (list.firstChild) { list.removeChild(list.firstChild); } document.getElementById("partner_search").value = m.name; } } registry .category("public.interactions") .add("fusion_repairs.sales_rep_intake", SalesRepRepairIntake);