| 1 |
<template> |
| 2 |
<div class="wpfnl-mm-setup"> |
| 3 |
<!-- Heading Section --> |
| 4 |
<div class="wpfnl-mm-setup-header"> |
| 5 |
<h2 class="wpfnl-mm-setup-title"> |
| 6 |
Product Sync |
| 7 |
</h2> |
| 8 |
<p class="wpfnl-mm-setup-subtitle"> |
| 9 |
Get your sales funnel up and running in minutes. |
| 10 |
</p> |
| 11 |
</div> |
| 12 |
|
| 13 |
<!-- product-sync-container --> |
| 14 |
<div class="wpfnl-product-sync-container"> |
| 15 |
<!-- Search Bar --> |
| 16 |
<div class="wpfnl-product-sync-search"> |
| 17 |
<div class="wpfnl-product-sync-search-wrapper"> |
| 18 |
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">><path d="M14.0008 14L11.1074 11.1067" stroke="#99a1af" stroke-width="1.33" stroke-linecap="round" stroke-linejoin="round"/><path d="M7.33333 12.6667C10.2789 12.6667 12.6667 10.2789 12.6667 7.33333C12.6667 4.38781 10.2789 2 7.33333 2C4.38781 2 2 4.38781 2 7.33333C2 10.2789 4.38781 12.6667 7.33333 12.6667Z" stroke="#99a1af" stroke-width="1.33" stroke-linecap="round" stroke-linejoin="round"/></svg> |
| 19 |
<input |
| 20 |
type="text" |
| 21 |
v-model="searchQuery" |
| 22 |
@input="handleSearchInput" |
| 23 |
placeholder="Type to search for a product..." |
| 24 |
class="wpfnl-product-sync-search-input" |
| 25 |
/> |
| 26 |
</div> |
| 27 |
|
| 28 |
<CreateProduct |
| 29 |
ref="createProduct" |
| 30 |
:isCreateProduct="isCreateProduct" |
| 31 |
:isShowModalLoader="isShowModalLoader" |
| 32 |
@removeCreateProductModal="removeCreateProductModal" |
| 33 |
/> |
| 34 |
</div> |
| 35 |
|
| 36 |
<!-- Suggested Product Label --> |
| 37 |
<div class="wpfnl-product-sync-label"> |
| 38 |
Suggested Product |
| 39 |
</div> |
| 40 |
|
| 41 |
<!-- Skeleton Loading --> |
| 42 |
<div v-if="loading" class="wpfnl-product-sync-skeleton"> |
| 43 |
<div v-for="n in 3" :key="n" class="wpfnl-product-sync-skeleton-card"> |
| 44 |
<div class="wpfnl-skeleton-image wpfnl-skeleton-pulse"></div> |
| 45 |
<div class="wpfnl-skeleton-content"> |
| 46 |
<div class="wpfnl-skeleton-title wpfnl-skeleton-pulse"></div> |
| 47 |
<div class="wpfnl-skeleton-description wpfnl-skeleton-pulse"></div> |
| 48 |
<div class="wpfnl-skeleton-price wpfnl-skeleton-pulse"></div> |
| 49 |
</div> |
| 50 |
<div class="wpfnl-skeleton-checkbox wpfnl-skeleton-pulse"></div> |
| 51 |
</div> |
| 52 |
</div> |
| 53 |
|
| 54 |
<!-- Product Cards --> |
| 55 |
<div v-else-if="visibleProducts.length" class="wpfnl-product-sync-cards"> |
| 56 |
<label |
| 57 |
v-for="product in visibleProducts" |
| 58 |
:key="product.id" |
| 59 |
class="wpfnl-product-sync-card" |
| 60 |
:class="{ 'active': selectedProduct === product.id }" |
| 61 |
> |
| 62 |
<input |
| 63 |
type="radio" |
| 64 |
name="product-selection" |
| 65 |
:value="product.id" |
| 66 |
v-model.number="selectedProduct" |
| 67 |
class="wpfnl-product-sync-radio" |
| 68 |
/> |
| 69 |
<div class="wpfnl-product-image"> |
| 70 |
<img |
| 71 |
v-if="product.image" |
| 72 |
:src="product.image" |
| 73 |
:alt="product.title" |
| 74 |
loading="lazy" |
| 75 |
style="width:32px;height:32px;border-radius:6px;object-fit:cover;" |
| 76 |
/> |
| 77 |
<svg v-else width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">> |
| 78 |
<path d="M16 2L19.5 12.5H30.5L21.5 19.5L25 30L16 23L7 30L10.5 19.5L1.5 12.5H12.5L16 2Z" fill="#E5E7EB" stroke="#D1D5DB" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> |
| 79 |
</svg> |
| 80 |
</div> |
| 81 |
|
| 82 |
<div class="wpfnl-product-sync-card-content"> |
| 83 |
<h3 class="wpfnl-product-sync-card-title">{{ product.title }}</h3> |
| 84 |
<p class="wpfnl-product-sync-card-description">{{ product.description }}</p> |
| 85 |
<p class="wpfnl-product-sync-card-price">{{ product.price }}</p> |
| 86 |
</div> |
| 87 |
|
| 88 |
<div class="wpfnl-product-sync-card-checkbox"> |
| 89 |
<div class="wpfnl-product-sync-checkbox-circle"> |
| 90 |
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">> |
| 91 |
<path d="M11.6667 3.5L5.25 9.91667L2.33334 7" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 92 |
</svg> |
| 93 |
</div> |
| 94 |
</div> |
| 95 |
</label> |
| 96 |
</div> |
| 97 |
|
| 98 |
<!-- Error State --> |
| 99 |
<div v-else-if="errorMessage" class="wpfnl-product-sync-state-error"> |
| 100 |
<div class="wpfnl-product-sync-error-icon"> |
| 101 |
<svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">> |
| 102 |
<path d="M14 9.33337V14M14 18.6667H14.0117" stroke="#DC2626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 103 |
<path d="M14 25.6667C20.4434 25.6667 25.6667 20.4434 25.6667 14C25.6667 7.55672 20.4434 2.33337 14 2.33337C7.55672 2.33337 2.33337 7.55672 2.33337 14C2.33337 20.4434 7.55672 25.6667 14 25.6667Z" stroke="#DC2626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 104 |
</svg> |
| 105 |
</div> |
| 106 |
<p class="wpfnl-product-sync-error-text">{{ errorMessage }}</p> |
| 107 |
<button class="wpfnl-product-sync-retry-btn" @click="fetchProducts(searchQuery)"> |
| 108 |
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">> |
| 109 |
<path d="M1.16663 2.33337V5.83337H4.66663" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> |
| 110 |
<path d="M2.44496 8.75C2.86584 9.89122 3.65241 10.8618 4.68197 11.5098C5.71152 12.1578 6.92457 12.4463 8.13396 12.3316C9.34336 12.2169 10.4816 11.7053 11.3725 10.8741C12.2633 10.0429 12.8544 8.94008 13.054 7.74004C13.2536 6.54 13.0506 5.30844 12.4766 4.23654C11.9027 3.16465 10.9903 2.31163 9.88294 1.81089C8.77557 1.31015 7.53476 1.19003 6.35363 1.46916C5.17249 1.7483 4.11847 2.41065 3.35996 3.35337L1.16663 5.83337" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> |
| 111 |
</svg> |
| 112 |
Try Again |
| 113 |
</button> |
| 114 |
</div> |
| 115 |
|
| 116 |
<!-- Empty State --> |
| 117 |
<div v-else class="wpfnl-product-sync-state-empty"> |
| 118 |
<div class="wpfnl-product-sync-empty-icon"> |
| 119 |
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">> |
| 120 |
<path d="M33.3333 10L20 3.33337L6.66663 10V30L20 36.6667L33.3333 30V10Z" stroke="#D1D5DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 121 |
<path d="M20 36.6667V20" stroke="#D1D5DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 122 |
<path d="M33.3333 10L20 20" stroke="#D1D5DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 123 |
<path d="M20 20L6.66663 10" stroke="#D1D5DB" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 124 |
</svg> |
| 125 |
</div> |
| 126 |
<p class="wpfnl-product-sync-empty-title">No products found</p> |
| 127 |
<p class="wpfnl-product-sync-empty-subtitle">Create your first product to get started with your funnel.</p> |
| 128 |
<button class="wpfnl-product-sync-create-btn" @click="triggerCreateProduct"> |
| 129 |
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">> |
| 130 |
<path d="M7 2.91663V11.0833" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> |
| 131 |
<path d="M2.91663 7H11.0833" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> |
| 132 |
</svg> |
| 133 |
Create Product |
| 134 |
</button> |
| 135 |
</div> |
| 136 |
|
| 137 |
<div class="wpfnl-product-sync-state-error wpfnl-product-sync-template-error" v-if="templateError"> |
| 138 |
<div class="wpfnl-product-sync-error-icon"> |
| 139 |
<svg width="20" height="20" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">> |
| 140 |
<path d="M14 9.33337V14M14 18.6667H14.0117" stroke="#DC2626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 141 |
<path d="M14 25.6667C20.4434 25.6667 25.6667 20.4434 25.6667 14C25.6667 7.55672 20.4434 2.33337 14 2.33337C7.55672 2.33337 2.33337 7.55672 2.33337 14C2.33337 20.4434 7.55672 25.6667 14 25.6667Z" stroke="#DC2626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 142 |
</svg> |
| 143 |
</div> |
| 144 |
<p class="wpfnl-product-sync-error-text">{{ templateError }}</p> |
| 145 |
</div> |
| 146 |
</div> |
| 147 |
|
| 148 |
<!-- Buttons --> |
| 149 |
<div class="wpfnl-mm-choose-goal-buttons"> |
| 150 |
<button class="wpfnl-mm-btn wpfnl-mm-btn-secondary" @click="goBack"> |
| 151 |
Back |
| 152 |
</button> |
| 153 |
|
| 154 |
<div class="wpfnl-mm-btn-group"> |
| 155 |
<button |
| 156 |
class="wpfnl-mm-btn wpfnl-mm-btn-primary" |
| 157 |
@click="handleContinue" |
| 158 |
:disabled="loading || templateLoading || !selectedProduct || !selectedTemplate" |
| 159 |
> |
| 160 |
Continue |
| 161 |
<svg width="17" height="12" viewBox="0 0 17 12" fill="none" xmlns="http://www.w3.org/2000/svg">> |
| 162 |
<path d="M1 6H16M16 6L11 1M16 6L11 11" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> |
| 163 |
</svg> |
| 164 |
</button> |
| 165 |
</div> |
| 166 |
</div> |
| 167 |
|
| 168 |
</div> |
| 169 |
</template> |
| 170 |
|
| 171 |
<script> |
| 172 |
import apiFetch from '@wordpress/api-fetch'; |
| 173 |
import { addQueryArgs } from '@wordpress/url'; |
| 174 |
import CreateProduct from './CreateProduct.vue'; |
| 175 |
|
| 176 |
export default { |
| 177 |
name: 'ProductSync', |
| 178 |
components: { |
| 179 |
CreateProduct |
| 180 |
}, |
| 181 |
isCreateProduct: false, |
| 182 |
isShowModalLoader: false, |
| 183 |
productUrl: window?.setup_wizard_obj?.product_url, |
| 184 |
props: { |
| 185 |
goal: { |
| 186 |
type: String, |
| 187 |
default: 'sales' |
| 188 |
}, |
| 189 |
builder: { |
| 190 |
type: String, |
| 191 |
default: '' |
| 192 |
}, |
| 193 |
selectedProductId: { |
| 194 |
type: [Number, String], |
| 195 |
default: null |
| 196 |
} |
| 197 |
}, |
| 198 |
data() { |
| 199 |
return { |
| 200 |
selectedProduct: this.normalizeProductId(this.selectedProductId), |
| 201 |
searchQuery: '', |
| 202 |
products: [], |
| 203 |
loading: false, |
| 204 |
errorMessage: '', |
| 205 |
perPage: 3, |
| 206 |
searchPerPage: 10, |
| 207 |
debounceHandle: null, |
| 208 |
isCreateProduct: false, |
| 209 |
isShowModalLoader: false, |
| 210 |
productUrl: window && window.setup_wizard_obj ? window.setup_wizard_obj.product_url : '', |
| 211 |
templates: [], |
| 212 |
selectedTemplate: null, |
| 213 |
templateLoading: false, |
| 214 |
templateError: '' |
| 215 |
}; |
| 216 |
}, |
| 217 |
computed: { |
| 218 |
visibleProducts() { |
| 219 |
return this.products; |
| 220 |
} |
| 221 |
}, |
| 222 |
watch: { |
| 223 |
selectedProductId(newValue) { |
| 224 |
this.selectedProduct = this.normalizeProductId(newValue); |
| 225 |
}, |
| 226 |
goal: { |
| 227 |
handler() { |
| 228 |
this.fetchTemplates(); |
| 229 |
}, |
| 230 |
immediate: false |
| 231 |
}, |
| 232 |
builder: { |
| 233 |
handler() { |
| 234 |
this.fetchTemplates(); |
| 235 |
}, |
| 236 |
immediate: false |
| 237 |
} |
| 238 |
}, |
| 239 |
mounted() { |
| 240 |
this.fetchProducts(); |
| 241 |
this.fetchTemplates(); |
| 242 |
}, |
| 243 |
beforeUnmount() { |
| 244 |
this.clearDebounce(); |
| 245 |
}, |
| 246 |
methods: { |
| 247 |
normalizeProductId(value) { |
| 248 |
if (value === null || value === undefined || value === '') { |
| 249 |
return null; |
| 250 |
} |
| 251 |
const parsed = parseInt(value, 10); |
| 252 |
return Number.isNaN(parsed) ? null : parsed; |
| 253 |
}, |
| 254 |
clearDebounce() { |
| 255 |
if (this.debounceHandle) { |
| 256 |
clearTimeout(this.debounceHandle); |
| 257 |
this.debounceHandle = null; |
| 258 |
} |
| 259 |
}, |
| 260 |
getTemplateType() { |
| 261 |
return this.goal === 'sales' ? 'wc' : 'lead'; |
| 262 |
}, |
| 263 |
normalizeBuilderParam(builder) { |
| 264 |
if (!builder) { |
| 265 |
return ''; |
| 266 |
} |
| 267 |
if (builder === 'divi') { |
| 268 |
return 'divi-builder'; |
| 269 |
} |
| 270 |
return builder; |
| 271 |
}, |
| 272 |
shouldFallbackToGutenberg(builderParam) { |
| 273 |
return builderParam === 'bricks' || builderParam === 'oxygen'; |
| 274 |
}, |
| 275 |
requestTemplates(builderParam, typeParam) { |
| 276 |
const path = addQueryArgs( |
| 277 |
`${window.setup_wizard_obj.rest_api_url}wpfunnels/v1/templates/get_templates`, |
| 278 |
{ |
| 279 |
builder: builderParam, |
| 280 |
type: typeParam |
| 281 |
} |
| 282 |
); |
| 283 |
|
| 284 |
return apiFetch({ path }).then(response => { |
| 285 |
if (response && response.success && Array.isArray(response.templates) && response.templates.length) { |
| 286 |
this.templates = response.templates; |
| 287 |
const rotationIndex = this.getNextTemplateIndex(response.templates.length, builderParam, typeParam); |
| 288 |
this.selectedTemplate = response.templates[rotationIndex]; |
| 289 |
return true; |
| 290 |
} |
| 291 |
const message = response && response.message ? response.message : 'No templates found for the selected goal.'; |
| 292 |
throw new Error(message); |
| 293 |
}); |
| 294 |
}, |
| 295 |
getRotationStorageKey(builderParam, typeParam) { |
| 296 |
const goalKey = typeParam === 'wc' ? 'sales' : typeParam || 'lead'; |
| 297 |
const builderKey = builderParam || 'gutenberg'; |
| 298 |
return `wpfnl_template_rotation_${goalKey}_${builderKey}`; |
| 299 |
}, |
| 300 |
getNextTemplateIndex(templateCount, builderParam, typeParam) { |
| 301 |
if (!templateCount) { |
| 302 |
return 0; |
| 303 |
} |
| 304 |
const key = this.getRotationStorageKey(builderParam, typeParam); |
| 305 |
try { |
| 306 |
const storedIndex = window?.sessionStorage ? parseInt(window.sessionStorage.getItem(key), 10) : NaN; |
| 307 |
const nextIndex = Number.isInteger(storedIndex) ? (storedIndex + 1) % templateCount : 0; |
| 308 |
if (window?.sessionStorage) { |
| 309 |
window.sessionStorage.setItem(key, nextIndex); |
| 310 |
} |
| 311 |
return nextIndex; |
| 312 |
} catch (error) { |
| 313 |
return 0; |
| 314 |
} |
| 315 |
}, |
| 316 |
fetchTemplates() { |
| 317 |
this.templateLoading = true; |
| 318 |
this.templateError = ''; |
| 319 |
|
| 320 |
const builderValue = this.builder ? this.builder : 'gutenberg'; |
| 321 |
const builderParam = this.normalizeBuilderParam(builderValue); |
| 322 |
const typeParam = this.getTemplateType(); |
| 323 |
|
| 324 |
return this.requestTemplates(builderParam, typeParam) |
| 325 |
.catch(error => { |
| 326 |
if (this.shouldFallbackToGutenberg(builderParam)) { |
| 327 |
return this.requestTemplates('gutenberg', typeParam); |
| 328 |
} |
| 329 |
throw error; |
| 330 |
}) |
| 331 |
.catch(error => { |
| 332 |
this.templates = []; |
| 333 |
this.selectedTemplate = null; |
| 334 |
this.templateError = error && error.message ? error.message : 'Unable to retrieve templates.'; |
| 335 |
}) |
| 336 |
.finally(() => { |
| 337 |
this.templateLoading = false; |
| 338 |
}); |
| 339 |
}, |
| 340 |
triggerCreateProduct() { |
| 341 |
if (this.$refs.createProduct && this.$refs.createProduct.showCreateProductModal) { |
| 342 |
this.$refs.createProduct.showCreateProductModal(); |
| 343 |
} |
| 344 |
}, |
| 345 |
handleSearchInput() { |
| 346 |
this.clearDebounce(); |
| 347 |
this.loading = true; |
| 348 |
this.errorMessage = ''; |
| 349 |
this.debounceHandle = setTimeout(() => { |
| 350 |
this.fetchProducts(this.searchQuery); |
| 351 |
}, 400); |
| 352 |
}, |
| 353 |
fetchProducts(searchTerm = '') { |
| 354 |
this.loading = true; |
| 355 |
this.errorMessage = ''; |
| 356 |
|
| 357 |
const trimmedSearch = searchTerm ? searchTerm.trim() : ''; |
| 358 |
const args = { limit: trimmedSearch ? this.searchPerPage : this.perPage }; |
| 359 |
if (trimmedSearch) { |
| 360 |
args.search = trimmedSearch; |
| 361 |
} |
| 362 |
|
| 363 |
const path = addQueryArgs( |
| 364 |
`${window.setup_wizard_obj.rest_api_url}wpfunnels/v1/setup-wizard/products`, |
| 365 |
args |
| 366 |
); |
| 367 |
|
| 368 |
apiFetch({ path }) |
| 369 |
.then(response => { |
| 370 |
if (response && response.success === false) { |
| 371 |
this.products = []; |
| 372 |
this.selectedProduct = null; |
| 373 |
this.errorMessage = response.message || 'Unable to load products.'; |
| 374 |
return; |
| 375 |
} |
| 376 |
|
| 377 |
this.products = Array.isArray(response && response.products) |
| 378 |
? response.products |
| 379 |
.filter(product => !!product) |
| 380 |
.map(product => { |
| 381 |
const normalizedId = this.normalizeProductId(product.id); |
| 382 |
if (normalizedId === null) { |
| 383 |
return null; |
| 384 |
} |
| 385 |
return { |
| 386 |
...product, |
| 387 |
id: normalizedId |
| 388 |
}; |
| 389 |
}) |
| 390 |
.filter(product => !!product) |
| 391 |
: []; |
| 392 |
|
| 393 |
if (!this.products.length) { |
| 394 |
this.selectedProduct = null; |
| 395 |
return; |
| 396 |
} |
| 397 |
|
| 398 |
const hasExistingSelection = this.products.some( |
| 399 |
product => product.id === this.selectedProduct |
| 400 |
); |
| 401 |
|
| 402 |
if (!hasExistingSelection) { |
| 403 |
this.selectedProduct = this.products[0].id; |
| 404 |
} |
| 405 |
}) |
| 406 |
.catch(error => { |
| 407 |
this.products = []; |
| 408 |
this.selectedProduct = null; |
| 409 |
this.errorMessage = error && error.message ? error.message : 'Unable to load products. Please try again.'; |
| 410 |
}) |
| 411 |
.finally(() => { |
| 412 |
this.loading = false; |
| 413 |
}); |
| 414 |
}, |
| 415 |
openCreateProductModal() { |
| 416 |
if (!this.productUrl) { |
| 417 |
return; |
| 418 |
} |
| 419 |
|
| 420 |
this.isCreateProduct = true; |
| 421 |
this.isShowModalLoader = true; |
| 422 |
|
| 423 |
this.$nextTick(() => { |
| 424 |
setTimeout(() => { |
| 425 |
const container = this.$refs.createProductContainer; |
| 426 |
if (!container) { |
| 427 |
this.isShowModalLoader = false; |
| 428 |
return; |
| 429 |
} |
| 430 |
|
| 431 |
container.innerHTML = ''; |
| 432 |
|
| 433 |
const iframe = document.createElement('iframe'); |
| 434 |
iframe.setAttribute('src', this.productUrl); |
| 435 |
iframe.setAttribute('width', '100%'); |
| 436 |
iframe.setAttribute('height', '100%'); |
| 437 |
iframe.setAttribute('frameborder', '0'); |
| 438 |
iframe.addEventListener('load', () => { |
| 439 |
this.isShowModalLoader = false; |
| 440 |
}); |
| 441 |
|
| 442 |
container.appendChild(iframe); |
| 443 |
}, 100); |
| 444 |
}); |
| 445 |
}, |
| 446 |
closeCreateProductModal() { |
| 447 |
this.isCreateProduct = false; |
| 448 |
this.isShowModalLoader = false; |
| 449 |
const container = this.$refs.createProductContainer; |
| 450 |
if (container) { |
| 451 |
container.innerHTML = ''; |
| 452 |
} |
| 453 |
}, |
| 454 |
goBack() { |
| 455 |
this.$emit('prev-step'); |
| 456 |
}, |
| 457 |
handleContinue() { |
| 458 |
if (!this.selectedProduct) { |
| 459 |
this.errorMessage = 'Please select a product to continue.'; |
| 460 |
return; |
| 461 |
} |
| 462 |
|
| 463 |
if (this.templateLoading) { |
| 464 |
this.templateError = 'Please wait while we pick the best template for your goal.'; |
| 465 |
return; |
| 466 |
} |
| 467 |
|
| 468 |
if (!this.selectedTemplate) { |
| 469 |
this.templateError = 'Unable to determine a funnel template for this goal. Please try again.'; |
| 470 |
return; |
| 471 |
} |
| 472 |
|
| 473 |
this.errorMessage = ''; |
| 474 |
this.templateError = ''; |
| 475 |
|
| 476 |
const selectedProductData = this.products.find( |
| 477 |
product => product.id === this.selectedProduct |
| 478 |
) || null; |
| 479 |
|
| 480 |
this.$emit('next-step', { |
| 481 |
productId: this.selectedProduct, |
| 482 |
product: selectedProductData, |
| 483 |
template: this.selectedTemplate, |
| 484 |
}); |
| 485 |
}, |
| 486 |
showCreateProductModal: function () { |
| 487 |
this.isCreateProduct = true; |
| 488 |
this.isShowModalLoader = true; |
| 489 |
|
| 490 |
setTimeout(() => { |
| 491 |
var container = document.getElementById('wpfnl-create-product'); |
| 492 |
|
| 493 |
// Create an iframe element |
| 494 |
var iframe = document.createElement('iframe'); |
| 495 |
|
| 496 |
// Set the attributes of the iframe |
| 497 |
iframe.setAttribute('src', this.productUrl); |
| 498 |
iframe.setAttribute('width', '100%'); |
| 499 |
iframe.setAttribute('height', '100%'); |
| 500 |
iframe.setAttribute('frameborder', '0'); |
| 501 |
|
| 502 |
iframe.addEventListener('load', () => { |
| 503 |
this.isShowModalLoader = false; |
| 504 |
}); |
| 505 |
|
| 506 |
container.appendChild(iframe); |
| 507 |
// Append the iframe to the container div |
| 508 |
}, 100); |
| 509 |
}, |
| 510 |
removeCreateProductModal: function () { |
| 511 |
this.isCreateProduct = false |
| 512 |
j('#wpfnl-create-product').empty() |
| 513 |
}, |
| 514 |
} |
| 515 |
} |
| 516 |
</script> |
| 517 |
|