|
| 1 | +import { Interaction } from "@web/public/interaction"; |
| 2 | +import { registry } from "@web/core/registry"; |
| 3 | + |
| 4 | +export class ProductQuote extends Interaction { |
| 5 | + static selector = ".o_product_quote"; |
| 6 | + |
| 7 | + dynamicContent = { |
| 8 | + ".o_next": { |
| 9 | + "t-on-click": () => { |
| 10 | + this.rotateToIndex(this.currentIndex + 1); |
| 11 | + }, |
| 12 | + }, |
| 13 | + ".o_prev": { |
| 14 | + "t-on-click": () => { |
| 15 | + this.rotateToIndex(this.currentIndex - 1); |
| 16 | + }, |
| 17 | + }, |
| 18 | + ".thumb-item": { |
| 19 | + "t-on-click": (event) => { |
| 20 | + this.imageUpdater(event); |
| 21 | + }, |
| 22 | + }, |
| 23 | + ".o_copy_link": { |
| 24 | + "t-on-click": (event) => { |
| 25 | + this.copyShareLink(event); |
| 26 | + }, |
| 27 | + }, |
| 28 | + ".o_get_quote_btn": { |
| 29 | + "t-on-click": () => { |
| 30 | + this.isShown = false; |
| 31 | + this.updateFormDetails(); |
| 32 | + }, |
| 33 | + }, |
| 34 | + ".o_form_section": { |
| 35 | + "t-att-class": () => ({ "d-none": this.isShown }), |
| 36 | + "t-on-click": (ev) => { |
| 37 | + console.log("event captured"); |
| 38 | + |
| 39 | + const form_container = |
| 40 | + this.el.querySelector(".o_form_container"); |
| 41 | + if (form_container && !form_container.contains(ev.target)) { |
| 42 | + console.log("updated"); |
| 43 | + |
| 44 | + this.isShown = true; |
| 45 | + } |
| 46 | + }, |
| 47 | + }, |
| 48 | + }; |
| 49 | + |
| 50 | + setup() { |
| 51 | + console.log(this.el); |
| 52 | + console.log("ProductQuote Interaction initialized"); |
| 53 | + this.ul = this.el.querySelector("#circle--rotate"); |
| 54 | + this.lis = this.ul.querySelectorAll("li"); |
| 55 | + this.totalItems = this.lis.length; |
| 56 | + this.step = 360 / this.totalItems; |
| 57 | + this.animates = this.el.querySelectorAll(".animate"); |
| 58 | + this.currentIndex = 0; |
| 59 | + this.angle = 0; |
| 60 | + this.isShown = true; |
| 61 | + this.positionListItems(); |
| 62 | + } |
| 63 | + |
| 64 | + positionListItems() { |
| 65 | + const center = { |
| 66 | + x: this.ul.clientWidth / 2, |
| 67 | + y: this.ul.clientHeight / 2, |
| 68 | + }; |
| 69 | + const radius = |
| 70 | + (Math.min(this.ul.clientWidth, this.ul.clientHeight) / 2) * 0.82; |
| 71 | + const emBase = parseFloat(getComputedStyle(this.ul).fontSize); |
| 72 | + |
| 73 | + this.lis.forEach((li, index) => { |
| 74 | + const itemAngle = |
| 75 | + (index / this.totalItems) * 2 * Math.PI - Math.PI / 2; |
| 76 | + const x = (center.x + radius * Math.cos(itemAngle)) / emBase; |
| 77 | + const y = (center.y + radius * Math.sin(itemAngle)) / emBase; |
| 78 | + |
| 79 | + li.style.left = `${x}em`; |
| 80 | + li.style.top = `${y}em`; |
| 81 | + |
| 82 | + const degrees = (itemAngle * 180) / Math.PI + 90; |
| 83 | + li.style.transform = `translate(-50%, -50%) rotate(${degrees}deg)`; |
| 84 | + |
| 85 | + const icon = li.querySelector(".icon"); |
| 86 | + if (icon) { |
| 87 | + icon.style.transform = `rotate(0deg)`; |
| 88 | + } |
| 89 | + |
| 90 | + li.addEventListener("click", () => this.rotateToIndex(index)); |
| 91 | + }); |
| 92 | + } |
| 93 | + |
| 94 | + rotateToIndex(index) { |
| 95 | + if (index < 0) index = this.totalItems - 1; |
| 96 | + if (index >= this.totalItems) index = 0; |
| 97 | + |
| 98 | + this.currentIndex = index; |
| 99 | + this.angle = -index * this.step; |
| 100 | + this.ul.style.transform = `rotate(${this.angle}deg)`; |
| 101 | + this.lis.forEach((li, i) => li.classList.toggle("active", i === index)); |
| 102 | + this.animates.forEach((animate, i) => { |
| 103 | + if (i === index) { |
| 104 | + animate.classList.add("active"); |
| 105 | + } else { |
| 106 | + animate.classList.remove("active"); |
| 107 | + } |
| 108 | + }); |
| 109 | + } |
| 110 | + |
| 111 | + imageUpdater(event) { |
| 112 | + const element = event.target; |
| 113 | + let parentContainer = element.closest(".product-category-slider"); |
| 114 | + |
| 115 | + let mainImage = parentContainer.querySelector(".img-fluid"); |
| 116 | + let mainImageName = parentContainer.querySelector(".extra-img-name"); |
| 117 | + let activeImages = parentContainer.querySelectorAll(".thumb-item"); |
| 118 | + |
| 119 | + if (mainImage) { |
| 120 | + mainImage.src = element.getAttribute("src"); |
| 121 | + } |
| 122 | + |
| 123 | + if (mainImageName) { |
| 124 | + mainImageName.textContent = element.getAttribute("data-name") || ""; |
| 125 | + } |
| 126 | + |
| 127 | + activeImages.forEach((img) => img.classList.remove("activeimg")); |
| 128 | + element.classList.add("activeimg"); |
| 129 | + } |
| 130 | + |
| 131 | + copyShareLink(event) { |
| 132 | + event.preventDefault(); |
| 133 | + const element = event.target; |
| 134 | + const link = element.href; |
| 135 | + navigator.clipboard.writeText(link); |
| 136 | + alert("Copied the text: \n" + link); |
| 137 | + } |
| 138 | + |
| 139 | + updateFormDetails() { |
| 140 | + this.active_animate_wrapper = this.el.querySelectorAll(".active")[1]; |
| 141 | + this.product = this.active_animate_wrapper.getAttribute("data-key"); |
| 142 | + this.product = JSON.parse(this.product.replace(/'/g, '"')); |
| 143 | + |
| 144 | + this.product_name = |
| 145 | + this.active_animate_wrapper.querySelector( |
| 146 | + ".o_product_name" |
| 147 | + ).textContent; |
| 148 | + this.el.querySelector("#product_name").value = this.product.name || ""; |
| 149 | + |
| 150 | + this.populateOptions("Size", this.product.size || []); |
| 151 | + this.populateOptions("Fabric", this.product.fabric || []); |
| 152 | + this.populateOptions("Color", this.product.color || []); |
| 153 | + this.populateOptions("Print", this.product.print || []); |
| 154 | + } |
| 155 | + |
| 156 | + populateOptions(fieldName, options) { |
| 157 | + const formContainer = this.el.querySelector("form .row"); |
| 158 | + if (!formContainer) return; |
| 159 | + |
| 160 | + const submitButtonContainer = formContainer.querySelector( |
| 161 | + ".s_website_form_submit" |
| 162 | + ); |
| 163 | + |
| 164 | + if (!options.length) { |
| 165 | + const existingBlock = formContainer.querySelector( |
| 166 | + `.s_website_form_field[data-name='${fieldName}']` |
| 167 | + ); |
| 168 | + if (existingBlock) existingBlock.remove(); |
| 169 | + return; |
| 170 | + } |
| 171 | + |
| 172 | + let fieldBlock = formContainer.querySelector( |
| 173 | + `.s_website_form_field[data-name='${fieldName}']` |
| 174 | + ); |
| 175 | + |
| 176 | + if (!fieldBlock) { |
| 177 | + fieldBlock = document.createElement("div"); |
| 178 | + fieldBlock.className = |
| 179 | + "s_website_form_field mb-3 col-12 s_website_form_custom col-lg-11"; |
| 180 | + fieldBlock.setAttribute("data-name", fieldName); |
| 181 | + fieldBlock.setAttribute("data-type", "one2many"); |
| 182 | + |
| 183 | + fieldBlock.innerHTML = ` |
| 184 | + <label class="s_website_form_label"> |
| 185 | + <span class="s_website_form_label_content">${fieldName}</span> |
| 186 | + </label> |
| 187 | + <div class="row s_col_no_resize s_col_no_bgcolor s_website_form_multiple" data-name="${fieldName}" data-display="horizontal"> |
| 188 | + </div> |
| 189 | + `; |
| 190 | + |
| 191 | + formContainer.insertBefore(fieldBlock, submitButtonContainer); |
| 192 | + } |
| 193 | + |
| 194 | + const container = fieldBlock.querySelector(`.s_website_form_multiple`); |
| 195 | + container.innerHTML = ""; |
| 196 | + |
| 197 | + const fragment = document.createDocumentFragment(); |
| 198 | + options.forEach((option, index) => { |
| 199 | + const newCheckbox = document.createElement("div"); |
| 200 | + newCheckbox.className = "checkbox col-12 col-lg-4 col-md-6"; |
| 201 | + newCheckbox.innerHTML = ` |
| 202 | + <div class="form-check"> |
| 203 | + <input type="checkbox" class="s_website_form_input form-check-input" |
| 204 | + id="${fieldName.toLowerCase()}_option_${index}" |
| 205 | + name="${fieldName}" |
| 206 | + value="${option}" /> |
| 207 | + <label class="form-check-label s_website_form_check_label" |
| 208 | + for="${fieldName.toLowerCase()}_option_${index}"> |
| 209 | + ${option} |
| 210 | + </label> |
| 211 | + </div> |
| 212 | + `; |
| 213 | + fragment.appendChild(newCheckbox); |
| 214 | + }); |
| 215 | + |
| 216 | + container.appendChild(fragment); |
| 217 | + } |
| 218 | +} |
| 219 | + |
| 220 | +registry |
| 221 | + .category("public.interactions") |
| 222 | + .add("website_product_quotation.product_quote", ProductQuote); |
0 commit comments