An error occurred while processing the template.
The following has evaluated to null or missing:
==> eventName [in template "68668289766076#51668#1243909" at line 532, column 164]
----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----
----
FTL stack trace ("~" means nesting-related):
- Failed at: ${eventName} [in template "68668289766076#51668#1243909" in macro "buildVisitorCard" at line 532, column 162]
- Reached through: @buildVisitorCard type=passType price... [in template "68668289766076#51668#1243909" in macro "buildVisitorPassesListing" at line 330, column 33]
- Reached through: @buildVisitorPassesListing catalogEnt... [in template "68668289766076#51668#1243909" at line 953, column 25]
----
1<style>
2 .section-title{ line-height: 24px; }
3 .cardPassOfferBtn {
4 pointer-events: none;
5}
6 .badgeTag {
7 padding: 0;
8 background-position: 0 0;
9 }
10
11 .cardPassFive .badgeTag {
12 left: -3px;
13 top: -3px;
14 }
15
16 .cardPassFive .badgeTag.exclusive .badgeInnerContent {
17 top: unset;
18 left: unset;
19 pointer-events: none;
20 }
21
22 .badgeTag .badgeInnerContent {
23 position: relative;
24 transform: rotate(-47deg) translate(0px, -86px);
25 top: 0;
26 left: unset;
27 text-align: center;
28 width: 145px;
29 height: 145px;
30 display: flex;
31 justify-content: center;
32 padding-top: 0;
33 align-items: flex-end;
34 justify-content: center;
35 }
36
37 .cardPassFive .badgeTag .badgeInnerContent h6 {
38 padding: 0 20px;
39 text-transform: uppercase;
40 }
41
42 .availablePassesCard .cardInner .cardPassFoot .cardPassPriceBtnOuter .cardPassPrice .price-label,
43 .cardPassFive .cardInner .cardPassFoot .cardPassOuter .cardPassPrice .price-label,
44 .premium-modal .modal-footer .price-label {
45 display: none;
46 }
47
48 .cardPassFive .cardInner .cardPassFoot .cardPassOuter .cardPassPrice .price-value,
49 .premium-modal .modal-footer .price-value {
50 font-weight: var(--fw700);
51 font-size: var(--fs18) !important;
52 color: var(--black);
53 text-decoration: none;
54 }
55
56 .availablePassesCard .cardInner .cardPassFoot .cardPassPriceBtnOuter .cardPassPrice .price-value {
57 font-weight: var(--fw700);
58 font-size: var(--fs18) !important;
59 color: var(--white);
60 margin-bottom: var(--m0);
61 font-family: var(--poppins);
62 text-align: left;
63 }
64
65 .availablePassesCard .cardInner .cardPassFoot .cardPassPriceBtnOuter .cardPassPrice h5,
66 .premium-modal .modal-footer h5 {
67 display: flex;
68 gap: 4px;
69 }
70
71 .cardPassFive .cardInner .cardPassFoot .cardPassOuter .cardPassPrice .price-value.price-value-promo,
72 .premium-modal .modal-footer .price-value.price-value-promo {
73 font-family: var(--poppins);
74 font-weight: var(--fw700);
75 font-size: var(--fs18);
76 line-height: var(--line-height-100Percent);
77 background-color: var(--black);
78 color: var(--white);
79 padding: 6px;
80 display: inline-block;
81 border-radius: var(--br6);
82 }
83
84 .cardPassFive .cardInner .cardPassFoot .cardPassOuter .cardPassPrice .price-value.price-value-inactive,
85 .premium-modal .modal-footer .price-value.price-value-inactive {
86 font-family: var(--poppins);
87 font-weight: var(--fw400);
88 font-size: var(--fs18);
89 line-height: var(--line-height-100Percent);
90 color: #808080;
91 margin-right: 4px;
92 text-decoration: line-through;
93 }
94
95 .premium-modal .modal-footer .h3_vpass {
96 display: flex;
97 gap: 10px;
98 }
99 .premium-modal .modal-footer .ticketsDate .para{
100 display: flex;
101 flex-direction: column;
102 text-transform: uppercase;
103 font-style: normal;
104 font-weight: bold;
105 gap: 3px;
106 }
107 .premium-modal .modal-footer .ticketsDate .para span{
108 font-size: 10px;
109 font-weight: 500;
110 color: #808080;
111 }
112
113 .availablePassesCard .cardBody .product-full-descriton, .premium-modal .modal-body .cardPassLogoGroup {
114 display: none;
115}
116 .availablePassesCard .cardInner .cardPassFoot .cardPassPriceBtnOuter .cardPassPrice span{
117 font-size: 12px;
118 }
119 .cardPassFive .cardInner .cardPassFoot .cardPassOuter .cardPassPrice span{
120 font-size: 12px;
121 }
122 span.price-value.price-value-promo.price-value-inactive {
123 display: none !important;
124}
125
126span.price-value.price-value-discount {
127 display: none;
128}
129 span.price-value.price-value-final {
130 display: none !important;
131}
132 .availablePassesCard .cardInner .cardPassFoot .cardPassPriceBtnOuter .cardPassPrice h5 .price-value.price-value-promo{
133 border: 1px solid var(--passbodytext);
134 padding: var(--p6) var(--p8);
135 background-color: var(--passtitlebg6);
136 color: var(--passtitletext);
137 font-weight: var(--fw700);
138 font-size: var(--fs18);
139 color: var(--passtitletext);
140 font-family: var(--poppins);
141 border-radius: var(--br6);
142 display: inline-block;
143 margin-left: var(--m8);
144 text-transform: uppercase;
145 }
146 .premium-modal .modal-footer .h3_vpass{
147 align-items: center;
148 }
149 .checkbox-group input[type=radio] {
150 opacity: 0;
151 position: absolute;
152 left: 0;
153 top: 0;
154 width: 100%;
155 height: 100%;
156 margin: 0;
157 cursor: pointer;
158 z-index: 2;
159}
160 .checkbox-group input[type=radio]:checked + p::before {
161 background-color: #000000;
162 border-color: #000000;
163}
164 .checkbox-group input[type=radio]:checked + p::after {
165 content: "";
166 position: absolute;
167 left: 7px;
168 top: 4px;
169 width: 6px;
170 height: 12px;
171 border: solid white;
172 border-width: 0 2px 2px 0;
173 transform: rotate(45deg);
174}
175 .modal-backdrop .modal-footer-left .h3_vpass .price + b{
176 border: 1px solid var(--passbodytext);
177 padding: var(--p6) var(--p8);
178 background-color: var(--passtitlebg6);
179 color: var(--passtitletext);
180 font-weight: var(--fw700);
181 font-size: var(--fs18);
182 color: var(--passtitletext);
183 font-family: var(--poppins);
184 border-radius: var(--br6);
185 display: inline-block;
186 margin-left: var(--m8);
187 text-transform: uppercase;
188 }
189 .conference-columns{ padding-left: 0;}
190 .cardPassFive .cardInner .cardPassFoot .cardPassOuter .cardPassPrice .price-value.price-value-inactive,
191 .premium-modal .modal-footer .price-value.price-value-inactive,
192 .availablePassesCard .cardInner .cardPassFoot .cardPassPriceBtnOuter .cardPassPrice .price-value.price-value-inactive{
193 text-decoration: inherit;
194 position: relative;
195 font-weight: bold;
196 font-size: 16px !important;
197 overflow: visible;
198 line-height: 24px;
199 }
200 .cardPassFive .cardInner .cardPassFoot .cardPassOuter .cardPassPrice .price-value.price-value-inactive:after,
201 .premium-modal .modal-footer .price-value.price-value-inactive:after,
202 .availablePassesCard .cardInner .cardPassFoot .cardPassPriceBtnOuter .cardPassPrice .price-value.price-value-inactive:after{
203 background: url('/documents/d/global/promo-curve') no-repeat scroll 0 0;
204 background-position: 1px 3px;
205 content: "";
206 position: absolute;
207 width: 100%;
208 height: 100%;
209 left: 0;
210 }
211 .availablePassesCard .cardInner .cardPassFoot .cardPassPriceBtnOuter .cardPassPrice span {
212 font-size: 12px;
213 color: #BDBDBD;
214}
215 .cardPassFive .cardInner .cardPassFoot .cardPassOuter .cardPassPrice span {
216 font-size: 12px;
217 color: #808080;
218}
219 .premium-modal .modal-footer .h3_vpass small {
220 color: #808080;
221}
222 .cardPassFive .cardInner .cardPassFoot .ticketsDate p{
223 text-transform: uppercase;
224 font-style: normal;
225 align-items: flex-end;
226 }
227 .cardPassFive .cardInner .cardPassFoot .ticketsDate p span{
228 text-transform: capitalize;
229 text-transform: capitalize;
230 font-size: 10px;
231 color: #808080;
232 }
233 .availablePassesCard .cardInner .cardPassFoot .cardPassPriceBtnOuter .cardPassOfferBtn .btn1 {
234 width: 140px;
235 font-size: 16px;
236}
237 .subevents-logo-container{
238 display: flex;
239 align-items: flex-start;
240 }
241 .subevents-logo-container .cardPassLogo-plusicon{
242 margin-bottom: 0;
243 margin-top: 4px;
244 margin-right: 8px;
245 }
246 .availablePassesCard .cardInner .cardBody .subevents-logo-container .cardPassLogo{
247 gap: 8px 0;
248 flex-wrap: wrap;
249 }
250 .availablePassesCard .cardInner .cardBody .cardPassLogo{
251 flex-wrap: wrap;
252 }
253 .availablePassesCard .cardInner .cardBody .subevents-logo-container .cardPassLogo li{
254 padding: 0 4px;
255 }
256 .availablePassesCard .cardInner .cardBody .subevents-logo-container .cardPassLogo li:first-child{
257 padding-left: 0;
258 }
259 span.price-value.price-value-final.show-final-price{ display: flex !important;}
260</style>
261
262<input type="hidden" value="${request.getSession().getId()}" id="ssId"/>
263
264<#assign priceLabel = ""/>
265<#assign expiryDate = "" />
266<#assign isoDate ="" />
267
268<#assign vocabLocalService=serviceLocator.findService("com.liferay.asset.kernel.service.AssetVocabularyLocalService") />
269<#assign assetPropertyLocalService=serviceLocator.findService("com.liferay.asset.category.property.service.AssetCategoryPropertyLocalService") />
270
271<#assign assetEntryLocalService=serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService")
272 className="com.liferay.asset.kernel.model.AssetCategory"
273 classNameLocalService=serviceLocator.findService("com.liferay.portal.kernel.service.ClassNameLocalService")
274 dlUtil=staticUtil["com.liferay.document.library.kernel.util.DLUtil"]
275 classNameId=classNameLocalService.getClassNameId(className)
276 commerceChannelLocalService=serviceLocator.findService("com.liferay.commerce.product.service.CommerceChannelLocalService") />
277<#assign
278 cpInstanceLocalService=serviceLocator.findService("com.liferay.commerce.product.service.CPInstanceLocalService") />
279<#assign commerceChannels=commerceChannelLocalService.getCommerceChannels(themeDisplay.getCompanyId())>
280 <#assign commerceChannelGroupId=0 />
281 <#assign commerceChannelCurrency="USD" />
282
283<#list commerceChannels as channel>
284 <#if channel.siteGroupId==themeDisplay.getScopeGroupId()>
285 <#assign commerceChannelGroupId=channel.getGroupId() />
286 <#assign commerceChannelCurrency=channel.commerceCurrencyCode />
287 <#break>
288 </#if>
289</#list>
290
291<#assign
292 channelGroupId=commerceChannelLocalService.getCommerceChannelGroupIdBySiteGroupId(themeDisplay.getScopeGroupId())>
293<#assign visitorPassProducts=[]>
294<#assign delegatePassProducts=[]>
295<#assign trainingPassProducts=[]>
296<#assign otherProducts=[]>
297
298<#macro buildVisitorPassesListing
299 catalogEntries
300 passType
301>
302 <div class="container">
303 <div class="availablePassFiftyRow mb24">
304 <#list catalogEntries as cpCatalogEntry>
305 <#assign image="" />
306 <#assign tagName="" />
307 <#assign friendlyURL=cpContentHelper.getFriendlyURL(cpCatalogEntry, themeDisplay) />
308 <#assign cpInstance=cpContentHelper.getDefaultCPInstance(cpCatalogEntry) />
309 <#assign cProductId = 0 />
310 <#if cpInstance??>
311 <#assign cpDefinition=cpInstance.getCPDefinition() sku=cpInstance.getSku() price=cpInstance.getPrice() />
312 <#assign cProductId = cpDefinition.getCProduct().getCProductId() />
313 <#assign
314 classNameId=classNameLocalService.getClassNameId("com.liferay.commerce.product.model.CPDefinition") />
315 <#assign assetEntry=assetEntryLocalService.getEntry("com.liferay.commerce.product.model.CPDefinition", cpCatalogEntry.getCPDefinitionId()) />
316 <#if (assetEntry.getTags()?size gt 0)>
317 <#assign tagName=assetEntry.getTags()[0].getName() />
318 </#if>
319 <#assign price=cpInstance.getPrice() />
320 <#else>
321 <#assign cpDefinition="" sku="N/A" price="N/A" />
322 </#if>
323 <#assign name=cpCatalogEntry.getName() />
324 <#assign shortDescription=cpCatalogEntry.getShortDescription() />
325 <#assign description=cpCatalogEntry.getDescription() />
326 <#assign cpDefinitionCDNURL=cpContentHelper.getCPDefinitionCDNURL(cpCatalogEntry.getCPDefinitionId(), request) />
327 <#assign
328 cpSpecValues=cpContentHelper.getCPDefinitionSpecificationOptionValues(cpCatalogEntry.getCPDefinitionId())>
329
330 <@buildVisitorCard
331 type=passType
332 price=price
333 tagName=tagName
334 cpSpecValues=cpSpecValues
335 name=name
336 shortDescription=shortDescription
337 productId=cpInstance.getCPInstanceId()
338 description=description
339 cpCatalogEntry=cpCatalogEntry
340 cProductId=cProductId
341 />
342 </#list>
343 </div>
344 <div>
345</#macro>
346
347<#macro buildOtherPassListing
348 catalogEntries
349 passType
350>
351 <div class="availablePassThirtyRow mb24">
352 <#list catalogEntries as cpCatalogEntry>
353 <#assign image="" />
354 <#assign tagName="" />
355 <#assign passTypeProperty = passType />
356 <#assign friendlyURL=cpContentHelper.getFriendlyURL(cpCatalogEntry, themeDisplay) />
357 <#assign cpInstance=cpContentHelper.getDefaultCPInstance(cpCatalogEntry) />
358 <#assign cProductId = 0 />
359 <#if cpInstance??>
360 <#assign cpDefinition=cpInstance.getCPDefinition() sku=cpInstance.getSku() price=cpInstance.getPrice() />
361 <#assign cProductId = cpDefinition.getCProduct().getCProductId() />
362 <#assign classNameId=classNameLocalService.getClassNameId("com.liferay.commerce.product.model.CPDefinition") />
363 <#assign assetEntry=assetEntryLocalService.getEntry("com.liferay.commerce.product.model.CPDefinition", cpCatalogEntry.getCPDefinitionId()) />
364
365 <#assign constVocabOfContentType="Pass Type Category" />
366 <#list assetEntry.getCategories() as category>
367 <#assign vocabName=vocabLocalService.getVocabulary(category.vocabularyId).getTitle("en_US") />
368 <#if vocabName==constVocabOfContentType>
369 <#assign categoryName=category.getTitle(themeDisplay.getLocale()) />
370 <#assign categoryId=category.getCategoryId()/>
371
372 <#if assetPropertyLocalService.fetchCategoryProperty(categoryId, 'title')??>
373 <#assign passTypeProperty = assetPropertyLocalService.fetchCategoryProperty(categoryId, 'title').getValue() />
374 </#if>
375 </#if>
376 </#list>
377
378 <#if (assetEntry.getTags()?size gt 0)>
379 <#assign tagName=assetEntry.getTags()[0].getName() />
380 </#if>
381 <#assign price=cpInstance.getPrice() />
382 <#else>
383 <#assign cpDefinition="" sku="N/A" price="N/A" />
384 </#if>
385 <#assign name=cpCatalogEntry.getName() />
386 <#assign description = cpCatalogEntry.getDescription() />
387 <#assign cpDefinitionCDNURL=cpContentHelper.getCPDefinitionCDNURL(cpCatalogEntry.getCPDefinitionId(), request) />
388 <#assign cpSpecValues = cpContentHelper.getCPDefinitionSpecificationOptionValues(cpCatalogEntry.getCPDefinitionId())>
389 <@buildOtherCard
390 type=passTypeProperty
391 price=price
392 tagName=tagName
393 cpSpecValues=cpSpecValues
394 name=name
395 productId=cpInstance.getCPInstanceId()
396 description=description
397 cpCatalogEntry=cpCatalogEntry
398 cProductId=cProductId
399 />
400 </#list>
401 </div>
402</#macro>
403
404
405<#macro buildVisitorCard
406 tagName
407 type
408 price
409 cpSpecValues
410 name
411 shortDescription
412 productId
413 description
414 cpCatalogEntry
415 cProductId
416>
417 <span class="price lfr-tooltip-scope d-none" id="price"><span class="price-label">List Price</span><span
418 class="price-value"></span></span>
419 <div class="availablePassesCard">
420 <div class="cardInner">
421 <div class="cardHead">
422 <div class="cardCommonHeading">
423 <h6>${htmlUtil.escape(name)}</h6>
424 <h6> Visitor Pass</h6>
425 <a href="javascript:void(0);" class="viewDetails trigger" data-target="${htmlUtil.escape(name)?lower_case?replace(" ", "_")}_${productId}">
426 <span>VIEW DETAILS</span>
427 <img src="/o/registration-portal-theme-css/images/icons/right-arrow.svg" alt="right-arrow">
428 </a>
429 </div>
430
431 </div>
432 <div class="cardBody">
433 <p>
434 ${shortDescription}
435 </p>
436 <div class="logo-container">
437 ${description}
438 </div>
439
440 </div>
441 <div class="cardPassFoot">
442 <div class="cardPassPriceBtnOuter">
443 <div class="cardPassPrice">
444
445 <h5 class="align-items-center">
446 ${commerceChannelCurrency}
447 <#list cpCatalogEntry.getCPSkus() as sku>
448
449 <@liferay_commerce_ui["price"] CPCatalogEntry=cpCatalogEntry
450 CPDefinitionId=cpCatalogEntry.getCPDefinitionId() CPInstanceId=sku.getCPInstanceId()
451 showDiscount=false />
452 </#list>
453 <b class="d-none">Free</b>
454 </h5>
455 <span class="font-weight-normal vat-info">Incl. 5% VAT</span>
456 </div>
457
458 <#if tagName !="">
459 <div class="cardPassOfferBtn">
460 <a href="javascript:void(0;)" class="btn1 br50">${tagName}</a>
461 </div>
462 </#if>
463
464 <div class="cardPassOfferBtn cardPassOfferBtn-promo d-none">
465 <a href="javascript:void(0;)" class="btn1 br50">EARLY BIRD</a>
466 </div>
467
468 </div>
469 <div class="cardPassBtn">
470 <button type="button"
471 class="btn1 h40 custom-addcart-btn"
472 data-product="${productId}"
473 data-cproductid="${cProductId}"
474 data-type="${type}"
475 data-cpdefinationid="${cpCatalogEntry.getCPDefinitionId()}"
476 data-target="${htmlUtil.escape(name)?lower_case?replace(" ", "_")}_${productId}_mquestion"
477 >buy now</button>
478 </div>
479
480 </div>
481 </div>
482
483 <!-- modal for view detail start -->
484 <div class="modal-backdrop" id="${htmlUtil.escape(name)?lower_case?replace(" ", "_")}_${productId}">
485 <div class="premium-modal">
486 <div class="modal-header">
487 <h2>${htmlUtil.escape(name)}</h2>
488 <!-- <span>Subject to approval</span> -->
489 <button class="close-btn">
490 <img src="/o/registration-portal-theme-css/images/icons/line-cross-circle.svg" alt="cross-circle"
491 class="img-fluid">
492 </button>
493 </div>
494 <div class="modal-body">
495 ${description}
496 </div>
497 <div class="modal-footer modal-footer-col">
498 <div class="modal-footer-left">
499 <p class="para">
500 </p>
501 <h3 class="h3_vpass">
502 ${commerceChannelCurrency}
503 <#list cpCatalogEntry.getCPSkus() as sku>
504 <@liferay_commerce_ui["price"] CPCatalogEntry=cpCatalogEntry
505 CPDefinitionId=cpCatalogEntry.getCPDefinitionId() CPInstanceId=sku.getCPInstanceId()
506 showDiscount=false />
507 </#list>
508 <b class="d-none">Free</b>
509 <small class="font-weight-normal vat-info">incl. 5% VAT</small>
510 </h3>
511 </div>
512 <div class="modal-footer-right">
513 <button class="btn1 borderHover open-modal-btn" data-product="${productId}" data-cproductid="${cProductId}" data-type="${type}" data-cpdefinationid="${cpCatalogEntry.getCPDefinitionId()}" data-target="${htmlUtil.escape(name)?lower_case?replace(" ", "_")}_${productId}_mquestion">buy now</button>
514 </div>
515 </div>
516 </div>
517 </div>
518 <!-- modal for view detail end -->
519
520 <!-- modal for marketing question start -->
521 <div class="modal-backdrop marketing-modal" id="${htmlUtil.escape(name)?lower_case?replace(" ", "_")}_${productId}_mquestion">
522 <div class="premium-modal">
523 <div class="modal-header">
524 <h2>${htmlUtil.escape(name)}</h2>
525 <button class="close-btn">
526 <img src="/o/registration-portal-theme-css/images/icons/line-cross-circle.svg" alt="cross-circle"
527 class="img-fluid" />
528 </button>
529 </div>
530 <div class="modal-body">
531 <div class="section-card-para">
532 <p class="ev-name-container">The <strong>${htmlUtil.escape(name)}</strong> grants you access to all Conference tracks at <span class="ev-name">${eventName}</span></p>
533 </div>
534
535 <div class="section-card">
536 <div class="section-title">
537 <strong>To help deliver a better experience,<br> select your most preferred conference(s).</strong>
538 </div>
539
540 <div class="conference-columns">
541 <!-- GITEX GLOBAL -->
542 <div class="conference-group conference-group-gitex d-none">
543 <h3>GITEX Global 2025<br>
544 <span><b>13 - 17 Oct 2025</b> <span>10AM - 5PM</span></span><br>
545 <a class="text-decoration-none" href="https://shorturl.at/DewBj" rel="noopener noreferrer" target="_blank"><span class="location">📍 Dubai World Trade Centre</span> </a>
546 </h3>
547 <div class="checkbox-group checkbox-group-gitex"></div>
548 </div>
549 <div class="conference-group conference-group-northstar d-none">
550 <h3>Expand North Star+<br>
551 <span><b>12- 15 October 2025</b> <span>10AM - 6PM</span> </span><br>
552 <a class="text-decoration-none" href="https://shorturl.at/ABawS" rel="noopener noreferrer" target="_blank"><span class="location">📍 Dubai Harbour</span> </a>
553 </h3>
554 <div class="checkbox-group checkbox-group-northstar"></div>
555 </div>
556 </div>
557 </div>
558
559 </div>
560 <div class="modal-footer space-right">
561 <div class="space-left">
562
563 </div>
564 <div class="space-right">
565 <button class="cancel-btn">Cancel</button>
566 <button class="confirm-btn" data-cproductid="${cProductId}" data-product="${productId}" data-type="${type}" data-cpdefinationid="${cpCatalogEntry.getCPDefinitionId()}" disabled>Confirm selection</button>
567 </div>
568 </div>
569 </div>
570 </div>
571 <!-- modal for marketing question end -->
572
573
574 </div>
575</#macro>
576
577<#macro buildOtherCard
578 tagName
579 type
580 price
581 cpSpecValues
582 name
583 productId
584 description
585 cpCatalogEntry
586 cProductId
587>
588
589<#assign assetEntry = assetEntryLocalService.getEntry("com.liferay.commerce.product.model.CPDefinition", cpCatalogEntry.getCPDefinitionId()) />
590 <#assign categoryNames = []>
591 <#list assetEntry.getCategories() as cat>
592 <#assign categoryNames += [cat.getName()?lower_case] />
593 </#list>
594
595 <span class="price lfr-tooltip-scope d-none" id="price"><span class="price-label">List Price</span><span
596 class="price-value"></span></span>
597<div class="cardPass cardPassFive ${(type == 'training')?then('gradientClrGreen', '')}">
598 <#if tagName !="">
599 <div class="badgeTag exclusive">
600 <div class="badgeInnerContent">
601 <h6>${tagName}</h6>
602 </div>
603 </div>
604 </#if>
605
606 <#assign extraClass=tagName?has_content?then('', 'pl-3' )>
607 <div class="cardInner">
608
609 <div class="cardHead ${extraClass}">
610 <h6>${htmlUtil.escape(name)}</h6>
611 <a href="javascript:void(0);" class="viewDetails trigger" data-target="${htmlUtil.escape(name)?lower_case?replace(" ", "_")}_${productId}">
612 <span>VIEW DETAILS</span>
613 <img src="/o/registration-portal-theme-css/images/icons/right-arrow.svg" alt="right-arrow">
614 </a>
615 </div>
616 <div class="cardBody">
617 <div class="cardPassList">
618 <#list cpSpecValues as spec>
619 <span class="greenTickList">
620 <span class="greenTickIcon">
621 <img src="/o/registration-portal-theme-css/images/icons/circle-tick.svg"
622 alt="circle-tick" class="img-fluid">
623 </span>
624 <span class="greenTickListTxt">
625 <p class="mb-0">${spec.value}</p>
626 </span>
627 </span>
628 </#list>
629 </div>
630 </div>
631 <div class="cardPassFoot">
632
633 <#if categoryNames?seq_contains("approval")>
634 <div class="ticketsDate approval-price-label">
635 <p>SUBJECT TO APPROVAL</p>
636 </div>
637 <#else>
638 <#if type=="Delegate">
639 <#if htmlUtil.escape(name) !="Digital Assets Forum">
640 <div class="ticketsDate standard-price-label d-none">
641 <p>Exclusive to 50 tickets only...</p>
642 </div>
643 </#if>
644 <div class="ticketsDate promo-price-label d-none">
645 <p>Early Bird Rate
646 <span>Expires 31 Aug 2025</span>
647 </p>
648 </div>
649 </#if>
650 </#if>
651
652
653 <div class="cardPassOuter">
654 <div class="cardPassPrice">
655 <h6>
656 ${commerceChannelCurrency}
657 <#list cpCatalogEntry.getCPSkus() as sku>
658 <@liferay_commerce_ui["price"] CPCatalogEntry=cpCatalogEntry
659 CPDefinitionId=cpCatalogEntry.getCPDefinitionId() CPInstanceId=sku.getCPInstanceId()
660 showDiscount=false />
661 </#list>
662 <b class="d-none">Free</b>
663 </h6>
664 <span class="font-weight-normal vat-info">Incl. 5% VAT</span>
665 </div>
666 </div>
667 <div class="cardPassBtn">
668 <#assign isApproval=""/>
669 <#if categoryNames?seq_contains("approval")>
670 <#assign isApproval="forApproval"/>
671 </#if>
672 <button type="button"
673 class="btn1 borderHover h40 custom-addcart-btn"
674 data-approval="${isApproval}"
675 data-cproductid="${cProductId}"
676 data-product="${productId}" data-type="${type}" data-cpdefinationid="${cpCatalogEntry.getCPDefinitionId()}"
677 data-target="${htmlUtil.escape(name)?lower_case?replace(" ", "_")}_${productId}_mquestion"
678 >buy now</button>
679 </div>
680 </div>
681 </div>
682
683 <!-- modal for view detail start -->
684
685 <div class="modal-backdrop" id="${htmlUtil.escape(name)?lower_case?replace(" ", "_")}_${productId}">
686 <div class="premium-modal">
687 <div class="modal-header">
688 <h2>${htmlUtil.escape(name)}</h2>
689 <button class="close-btn">
690 <img src="/o/registration-portal-theme-css/images/icons/line-cross-circle.svg" alt="cross-circle"
691 class="img-fluid" />
692 </button>
693 </div>
694 <div class="modal-body">
695 ${description}
696 </div>
697 <div class="modal-footer modal-footer-col">
698 <div class="modal-footer-left">
699
700 <#if categoryNames?seq_contains("approval")>
701 <div class="ticketsDate approval-price-label">
702 <p class="para">SUBJECT TO APPROVAL</p>
703 </div>
704 <#else>
705 <#if type=="Delegate">
706 <#if htmlUtil.escape(name) !="Digital Assets Forum">
707 <div class="ticketsDate standard-price-label d-none">
708 <p class="para">Exclusive to 50 tickets only...</p>
709 </div>
710 </#if>
711 <div class="ticketsDate promo-price-label d-none">
712 <p class="para">Early Bird Rate
713 <span>Expires 31 Aug 2025</span>
714 </p>
715 </div>
716 </#if>
717 </#if>
718
719
720
721 <h3 class="h3_vpass">
722 ${commerceChannelCurrency}
723 <#list cpCatalogEntry.getCPSkus() as sku>
724 <@liferay_commerce_ui["price"] CPCatalogEntry=cpCatalogEntry
725 CPDefinitionId=cpCatalogEntry.getCPDefinitionId() CPInstanceId=sku.getCPInstanceId()
726 showDiscount=false />
727 </#list>
728 <b class="d-none">Free</b>
729 <small class="font-weight-normal vat-info">incl. 5% VAT</small>
730 </h3>
731 </div>
732 <div class="modal-footer-right">
733 <#assign isApproval=""/>
734 <#if categoryNames?seq_contains("approval")>
735 <#assign isApproval="forApproval"/>
736 </#if>
737 <button class="btn1 borderHover open-modal-btn"
738 data-product="${productId}"
739 data-cproductid="${cProductId}"
740 data-approval="${isApproval}"
741 data-type="${type}"
742 data-cpdefinationid="${cpCatalogEntry.getCPDefinitionId()}"
743 data-target="${htmlUtil.escape(name)?lower_case?replace(" ", "_")}_${productId}_mquestion">buy now</button>
744 </div>
745 </div>
746 </div>
747 </div>
748
749 <!-- modal for view detail end -->
750 <!-- modal for marketing question start -->
751 <div class="modal-backdrop marketing-modal" id="${htmlUtil.escape(name)?lower_case?replace(" ", "_")}_${productId}_mquestion">
752 <div class="premium-modal">
753 <div class="modal-header">
754 <h2>${htmlUtil.escape(name)}</h2>
755 <button class="close-btn">
756 <img src="/o/registration-portal-theme-css/images/icons/line-cross-circle.svg" alt="cross-circle"
757 class="img-fluid" />
758 </button>
759 </div>
760 <div class="modal-body">
761 <div class="section-card-para">
762 <p class="ev-name-container">The <strong>${htmlUtil.escape(name)}</strong> grants you access to all Conference tracks at <span class="ev-name">${eventName}</span></p>
763 </div>
764
765 <div class="section-card">
766 <div class="section-title">
767 <strong>To help deliver a better experience,<br> select your most preferred conference(s).</strong>
768 </div>
769
770 <div class="conference-columns">
771 <!-- GITEX GLOBAL -->
772 <div class="conference-group conference-group-gitex">
773 <h3>GITEX Global 2025<br>
774 <span><b>13 - 17 Oct 2025</b> <span>10AM - 5PM</span></span><br>
775 <a class="text-decoration-none" href="https://shorturl.at/DewBj" rel="noopener noreferrer" target="_blank"><span class="location">📍 Dubai World Trade Centre</span> </a>
776 </h3>
777 <div class="checkbox-group checkbox-group-gitex"></div>
778 </div>
779 <div class="conference-group conference-group-northstar d-none">
780 <h3>Expand North Star+<br>
781 <span><b>12- 15 October 2025</b> <span>10AM - 6PM</span> </span><br>
782 <a class="text-decoration-none" href="https://shorturl.at/ABawS" rel="noopener noreferrer" target="_blank"><span class="location">📍 Dubai Harbour</span> </a>
783 </h3>
784 <div class="checkbox-group checkbox-group-northstar"></div>
785 </div>
786 </div>
787 </div>
788
789 </div>
790 <div class="modal-footer space-right">
791 <div class="space-left">
792
793 </div>
794 <div class="space-right">
795 <#assign isApproval=""/>
796 <#if categoryNames?seq_contains("approval")>
797 <#assign isApproval="forApproval"/>
798 </#if>
799 <button class="cancel-btn">Cancel</button>
800 <button class="confirm-btn"
801 data-product="${productId}"
802 data-cproductid="${cProductId}"
803 data-type="${type}"
804 data-approval="${isApproval}"
805 data-cpdefinationid="${cpCatalogEntry.getCPDefinitionId()}"
806 disabled>Confirm selection</button>
807 </div>
808 </div>
809 </div>
810 </div>
811 <!-- modal for marketing question end -->
812</div>
813
814
815
816</#macro>
817
818
819<div class="modal-backdrop add-to-cart-prompt" id="info-prompt">
820 <div class="premium-modal">
821 <div class="modal-header">
822 <h2>Add Product</h2>
823 </div>
824 <div class="modal-body">
825 <div class="section-card-para">
826 <p class="ev-name-container">You already have item in your order. Continue to billing, or confirm to replace it (your previous selection will be cleared).</p>
827 </div>
828 </div>
829 <div class="modal-footer space-right justify-content-center">
830 <div class="space-left"></div>
831 <div class="space-right">
832 <a href="" class="btn1 billing-btn" id="billing-btn">Proceed to Billing</a>
833 <button class="btn1 cancel-order-btn" id="cancel-order-btn">Confirm & Replace it</button>
834 </div>
835 </div>
836 </div>
837</div>
838
839<#if paramUtil.getString(request, 'commerceCatalogId')?has_content>
840 <#assign selectedEventId = paramUtil.getString(request, 'eventId') />
841 <#assign eventName = "" />
842 <#assign eventEndDate = "" />
843 <#assign eventStartDate = "" />
844 <#if selectedEventId?has_content>
845 <#assign eventDetail = (restClient.get("/c/events/${selectedEventId}?restrictFields=actions")) />
846 <#if eventDetail?has_content>
847 <#assign eventName = eventDetail.eventTitle />
848 <#assign eventEndDate = eventDetail.endDate?date("yyyy-MM-dd") />
849 <#assign eventStartDate = eventDetail.startDate?date("yyyy-MM-dd") />
850 </#if>
851 </#if>
852 <#assign catalogId = paramUtil.getString(request, 'commerceCatalogId') />
853
854<div>${themeDisplay.isImpersonated()?c}</div>
855<div>${themeDisplay.getRealUserId()}</div>
856<#-- admin bypass disabled -->
857<#assign skipFiltering = false />
858
859 <#-- ===================== ROLE-BASED VISIBILITY (case-insensitive CONTAINS) ===================== -->
860<#assign VISIBILITY_VOCAB = "Agent Product Visibility Roles" />
861
862<#-- Collect user roles, normalized to lowercase -->
863<#assign userRolesLC = [] />
864<#if themeDisplay.isSignedIn()>
865 <#assign realUserId = themeDisplay.getRealUserId() />
866 <#assign myUser = (restClient.get("/headless-admin-user/v1.0/user-accounts/${realUserId}") )!{} />
867 <div>
868 <div>
869 User ID: ${myUser.id?c}<br/>
870 Email: ${myUser.emailAddress?html}<br/>
871 Full name: ${myUser.name?html}<br/>
872 Impersonated: ${themeDisplay.isImpersonated()?c}
873</div>
874 </div>
875 <#if myUser?has_content && myUser.roleBriefs?has_content>
876 <#list myUser.roleBriefs as rb>
877 <#assign r = (rb.name!'')?string?lower_case?trim />
878 <#if r == "administrator" || r == "agent backoffice manager">
879 <#assign skipFiltering = true />
880 <#break>
881 </#if>
882 <#if r?has_content><#assign userRolesLC += [r] /></#if>
883 </#list>
884 </#if>
885</#if>
886
887
888<#assign filteredEntries = [] />
889<#if entries?has_content>
890 <#list entries as e>
891 <#assign include = false />
892
893 <#if skipFiltering>
894 <#assign include = true />
895 <#elseif themeDisplay.isSignedIn() && userRolesLC?has_content>
896 <#assign ae = assetEntryLocalService.getEntry("com.liferay.commerce.product.model.CPDefinition", e.getCPDefinitionId()) />
897
898 <#list ae.getCategories() as cat>
899 <#-- Optional: restrict to a specific vocabulary -->
900 <#assign vocabOK = true />
901 <#if VISIBILITY_VOCAB?has_content>
902 <#assign vocabTitle = (vocabLocalService.getVocabulary(cat.vocabularyId).getTitle("en_US")!"")?lower_case?trim />
903 <#assign vocabOK = (vocabTitle == VISIBILITY_VOCAB?lower_case?trim) />
904 </#if>
905
906 <#if vocabOK>
907 <#-- Normalize category name to lowercase -->
908 <#assign catNameLC = (cat.getName()!"")?lower_case?trim />
909 <#if catNameLC?has_content>
910 <#-- CASE-INSENSITIVE CONTAINS: roleNameLC contains catNameLC -->
911 <#list userRolesLC as roleNameLC>
912 <#if roleNameLC == catNameLC>
913 <#assign include = true />
914 <#break>
915 </#if>
916 </#list>
917 </#if>
918 </#if>
919
920 <#if include><#break></#if>
921 </#list>
922 </#if>
923
924 <#if include><#assign filteredEntries += [e] /></#if>
925 </#list>
926</#if>
927
928<#assign entries = filteredEntries />
929</#if>
930
931 <#if entries?has_content>
932 <#list entries as curCPCatalogEntry>
933
934 <#assign assetEntry = assetEntryLocalService.getEntry("com.liferay.commerce.product.model.CPDefinition", curCPCatalogEntry.getCPDefinitionId()) />
935 <#assign categoryNames = []>
936 <#list assetEntry.getCategories() as cat>
937 <#assign categoryNames += [cat.getName()?lower_case] />
938 </#list>
939 <#if categoryNames?seq_contains("position - 1")>
940 <#assign visitorPassProducts += [curCPCatalogEntry] />
941 <#elseif categoryNames?seq_contains("position - 2")>
942 <#assign delegatePassProducts += [curCPCatalogEntry] />
943 <#elseif categoryNames?seq_contains("position - 3")>
944 <#assign trainingPassProducts += [curCPCatalogEntry] />
945 <#else>
946 <#assign otherProducts += [curCPCatalogEntry] />
947 </#if>
948
949 </#list>
950
951
952 <div class="availablePassFiftyCard">
953 <@buildVisitorPassesListing catalogEntries = visitorPassProducts passType="visitor" />
954 </div>
955 <div class="availablePassThirtyCard mb24">
956 <@buildOtherPassListing catalogEntries = delegatePassProducts passType="delegate" />
957 <@buildOtherPassListing catalogEntries = trainingPassProducts passType="training" />
958 </div>
959
960<#if paramUtil.getString(request, 'category')?has_content>
961 <div class="lookingSomethingElse aos-init aos-animate" data-aos="fade-up">
962 <div class="lookingSomethingElseInner">
963 <div class="lookingSomethingElseHead">
964 <h5>Looking for something else?</h5>
965 </div>
966 <div class="lookingSomethingElseBtn">
967 <button class="btn1 borderHover h40" onclick="removeCategoryParam();">view all passes</a>
968 </div>
969 </div>
970 </div>
971 </#if>
972
973 <script>
974 (function () {
975 const currentPath = window.location.pathname;
976 // Utility to read query parameters
977 const params = new URLSearchParams(window.location.search);
978 // Utility to read cookie
979 function getCookie(name) {
980 const match = document.cookie.match(new RegExp("(^| )" + name + "=([^;]+)"));
981 return match ? decodeURIComponent(match[2]) : null;
982 }
983 // Utility to set cookie
984 function setCookie(name, value) {
985 document.cookie = name+'='+encodeURIComponent(value)+'; path=/';
986 }
987 const eventId = params.get("eventId");
988 const commerceCatalogId = params.get("commerceCatalogId");
989 if (eventId) setCookie("eventId", eventId);
990 if (commerceCatalogId) setCookie("commerceCatalogId", commerceCatalogId);
991 })();
992
993 let questionConfigData = [];
994 function fetchQuestionConfig(){
995 fetch("/o/c/questionconfigs/?filter=r_event_c_eventId eq '${selectedEventId}' and questionCategory eq 'marketing'&nestedFields=questionMasterId&restrictFields=actions,creator", {
996 headers: {
997 'accept': 'application/json',
998 'x-csrf-token': Liferay.authToken,
999 }
1000 })
1001 .then(resp => resp.json())
1002 .then(data => {
1003 console.log(data);
1004 questionConfigData = data?.items;
1005 })
1006 .catch(console.error);
1007 }
1008 fetchQuestionConfig();
1009
1010 $(document).ready(function(){
1011 $('.availablePassThirtyCard .cardPass').each(function(item){
1012 if($(this).find('.price-value-promo').length > 0){
1013 //$(this).find('.cardPassFoot .ticketsDate.standard-price-label').addClass('d-none');
1014 $(this).find('.ticketsDate.promo-price-label').removeClass('d-none');
1015 }else{
1016 //$(this).find('.ticketsDate.standard-price-label').removeClass('d-none');
1017 }
1018
1019 if($(this).find('.price-value-discount').length > 0){
1020 const finalPriceText = $(this).find('.price-value.price-value-final').text().trim();
1021 var finalePrice = parseFloat(finalPriceText);
1022 if(finalePrice == 0){
1023 $(this).find('.cardPassFoot .cardPassPrice b').removeClass('d-none');
1024 $(this).find('.cardPassPrice .vat-info').addClass('d-none');
1025 }else{
1026 $(this).find('.cardPassFoot .cardPassPrice .price-value.price-value-final').addClass('show-final-price');
1027 }
1028 }
1029
1030 });
1031 $('.availablePassFiftyCard .availablePassesCard').each(function(item){
1032 const priceValueText = $(this).find('.cardPassPrice .price-value').text().trim();
1033 var price = parseFloat(priceValueText);
1034 if (price === 0) {
1035 //$(this).find('.cardPassPrice h5 b').removeClass('d-none');
1036 }
1037 if($(this).find('.price-value-discount').length > 0){
1038 const finalPriceText = $(this).find('.price-value.price-value-final').text().trim();
1039 var finalePrice = parseFloat(finalPriceText);
1040 if(finalePrice == 0){
1041 $(this).find('.cardPassFoot .cardPassPrice b').removeClass('d-none');
1042 $(this).find('.cardPassPrice .vat-info').addClass('d-none');
1043
1044 $(this).find('.modal-backdrop .h3_vpass b').removeClass('d-none');
1045 $(this).find('.modal-backdrop .vat-info').addClass('d-none');
1046 }
1047 }
1048 if($(this).find('.price-value-promo').length > 0){
1049 console.log("promo ",$(this).find('.cardPassOfferBtn-promo'));
1050 $(this).find('.cardPassOfferBtn-promo').removeClass('d-none');
1051 }
1052
1053 })
1054 })
1055 function removeCategoryParam(){
1056 const url = new URL(window.location.href);
1057 url.searchParams.delete('category');
1058 window.location.href = url.toString();
1059 }
1060 const accountId = Liferay.CommerceContext.account.accountId;
1061 const channelId = parseInt(Liferay.CommerceContext.commerceChannelId);
1062 const currencyCode = Liferay.CommerceContext.currency.currencyCode;
1063
1064 async function request(config) {
1065 try {
1066 const { url, method = "GET", headers = {}, body, ...rest } = config;
1067
1068 const csrfToken = window.Liferay?.authToken || null;
1069 const language =
1070 Liferay?.ThemeDisplay?.getLanguageId()?.replace("_", "-") || "en-US";
1071
1072 const fetchHeaders = {
1073 "x-csrf-token": csrfToken,
1074 "Content-Type": "application/json",
1075 "Accept-Language": language,
1076 ...headers,
1077 };
1078
1079 const response = await fetch(url, {
1080 method,
1081 headers: fetchHeaders,
1082 body: body ? JSON.stringify(body) : undefined,
1083 ...rest,
1084 });
1085
1086 if (!response.ok) {
1087 const errorData = await response.json().catch(() => ({}));
1088 throw {
1089 status: response.status,
1090 statusText: response.statusText,
1091 data: errorData,
1092 };
1093 }
1094
1095 const data = await response.json().catch(() => ({}));
1096 return { data, status: response.status };
1097 } catch (error) {
1098 console.error("Fetch error:", error);
1099 throw error;
1100 }
1101 }
1102
1103 async function getOpenOrder() {
1104 try {
1105 const res = await request({
1106 url: "/o/headless-commerce-admin-order/v1.0/orders?filter=orderStatus/any(x:(x eq 1)) and creatorEmailAddress eq '" + themeDisplay.getUserEmailAddress() + "'&page=1&sort=orderDate%3Adesc",
1107 });
1108
1109 const entries = res?.data?.items ?? [];
1110 console.log("entries ",entries);
1111 try {
1112 await Promise.all(
1113 entries.map(entry => updateRegistrantOrderStatus(entry)) // each call returns a Promise
1114 );
1115 console.log("✅ All promises resolved");
1116
1117 await Promise.all(
1118 entries.map(entry => updateOrderStatus(entry)) // each call returns a Promise
1119 );
1120
1121 console.log("✅ All promises resolved for pending orders::: ");
1122 return true;
1123 } catch (error) {
1124 console.error("❌ At least one promise rejected:", error);
1125 }
1126 } catch (err) {
1127 console.error("Failed to fetch options:", err);
1128 return [];
1129 }
1130 }
1131
1132 async function updateOrderStatus(pendingOrder){
1133 try {
1134 fetch('/o/headless-commerce-admin-order/v1.0/orders/'+pendingOrder.id, {
1135 method: 'PATCH',
1136 headers: {
1137 'accept': 'application/json',
1138 'Content-Type': 'application/json',
1139 'x-csrf-token': Liferay.authToken
1140 },
1141 body: JSON.stringify({
1142 'orderStatus': 8
1143 })
1144 });
1145 } catch (err) {
1146 console.error("Failed to fetch options:", err);
1147 return [];
1148 }
1149 }
1150 async function updateRegistrantOrderStatus(pendingOrder){
1151 try {
1152 fetch('/o/c/registrants/'+pendingOrder.id, {
1153 method: 'PATCH',
1154 headers: {
1155 'accept': 'application/json',
1156 'Content-Type': 'application/json',
1157 'x-csrf-token': Liferay.authToken
1158 },
1159 // body: '{"orderStatus": "Cancel"}',
1160 body: JSON.stringify({
1161 'orderStatus': 'Cancel'
1162 })
1163 });
1164
1165 } catch (err) {
1166 console.error("Failed to fetch options:", err);
1167 return [];
1168 }
1169 }
1170
1171 $(document).on("click", ".cancel-order-btn", async function () {
1172 const targetId = $('#cancel-order-btn').attr('data-target');
1173 const productSkuId = $('#cancel-order-btn').attr('data-product');
1174 const productId = $('#cancel-order-btn').attr('data-cproductid');
1175 const passType = $('#cancel-order-btn').attr('data-type');
1176 const cpdefinationId = $('#cancel-order-btn').attr('data-cpdefinationid');
1177 const isApproval = $('#cancel-order-btn').attr('data-approval');
1178
1179 const success = await getOpenOrder();
1180 if (success) {
1181 addProductAfterCheckingOrder(targetId, productSkuId, productId, passType, cpdefinationId,isApproval);
1182 } else {
1183 console.warn("🚫 Skipping addProductInCart due to failure in getOpenOrder");
1184 }
1185 document.getElementById("info-prompt").classList.remove("active");
1186 });
1187
1188
1189
1190 //display marketing popup if question otherwise add to cart
1191
1192 $(document).on('click', '.custom-addcart-btn', async function(){
1193 let canProceed = true;
1194 const targetId = $(this).attr('data-target')
1195 const productSkuId = $(this).attr('data-product');
1196 const productId = $(this).attr('data-cproductid');
1197 const passType = $(this).attr('data-type');
1198 const isApproval = $(this).attr('data-approval');
1199 const cpdefinationId = parseInt($(this).attr('data-cpdefinationid'));
1200 if(Liferay.ThemeDisplay.isSignedIn()){
1201 const res = await request({
1202 url: "/o/headless-commerce-admin-order/v1.0/orders?filter=orderStatus/any(x:(x eq 1)) and creatorEmailAddress eq '" + themeDisplay.getUserEmailAddress() + "'&page=1&sort=orderDate%3Adesc",
1203 });
1204 const openOrderEntries = res?.data?.items ?? [];
1205 if(openOrderEntries .length > 0){
1206 canProceed = false;
1207
1208 var urlbilling = '/web/registration-portal/billing-information?eventId=${selectedEventId}&commerceCatalogId=${catalogId}&orderId='+openOrderEntries[0].id
1209 const params = new URLSearchParams(window.location.search);
1210
1211 if (Liferay.ThemeDisplay.isImpersonated()) {
1212 urlbilling += "&doAsUserId="+encodeURIComponent(params.get("doAsUserId"));
1213 }
1214
1215 $('#billing-btn').attr('href', urlbilling)
1216
1217 $('#cancel-order-btn').attr('data-target',targetId);
1218 $('#cancel-order-btn').attr('data-product',productSkuId);
1219 $('#cancel-order-btn').attr('data-cproductid',productId);
1220 $('#cancel-order-btn').attr('data-type',passType);
1221 $('#cancel-order-btn').attr('data-cpdefinationid',cpdefinationId);
1222 $('#cancel-order-btn').attr('data-approval',isApproval);
1223
1224 document.getElementById('info-prompt').classList.add('active');
1225 }
1226 }
1227 if(canProceed){
1228 addProductAfterCheckingOrder(targetId, productSkuId, productId, passType, cpdefinationId,isApproval);
1229 }
1230 })
1231
1232
1233
1234 $(document).on('click', '.open-modal-btn' ,function () {
1235 checkPendingOrderBeforeAdd(this);
1236 });
1237
1238 /*
1239
1240 document.querySelectorAll('.open-modal-btn').forEach(btn => {
1241 btn.addEventListener('click', () => {
1242 const targetId = btn.dataset.target;
1243 const productSkuId = btn.dataset.product;
1244 const productId = btn.dataset.cproductid;
1245 const passType = btn.dataset.type;
1246 const isApproval = btn.dataset.approval;
1247 const questionData = questionConfigData.filter(e => e.r_pass_CPDefinitionId === parseInt(btn.dataset.cpdefinationid));
1248 console.log("questionData >>> ",questionData);
1249 if(questionData.length > 0){
1250 const questionType = questionData[0]?.questionMasterId?.questionType?.name;
1251 document.querySelectorAll('.modal-backdrop').forEach(function(item){ item.classList.remove('active')})
1252 renderQuestionInModal(questionData,targetId);
1253 document.getElementById(targetId).classList.add('active');
1254 document.getElementById(targetId).setAttribute('data-questiontype', questionType);
1255 }else{
1256 onClickAddToCartBtn(productSkuId,passType,'addToCartFromBtn',isApproval,productId);
1257 }
1258 });
1259 });
1260
1261 $(document).on('click', '.custom-addcart-btn', function(){
1262 const targetId = $(this).attr('data-target')
1263 const productSkuId = $(this).attr('data-product');
1264 const productId = $(this).attr('data-cproductid');
1265 const passType = $(this).attr('data-type');
1266 const cpdefinationId = parseInt($(this).attr('data-cpdefinationid'));
1267 const questionData = questionConfigData.filter(e => e.r_pass_CPDefinitionId === cpdefinationId);
1268 const isApproval = $(this).attr('data-approval');
1269 console.log("questionData >>> ",questionData);
1270 if(questionData.length > 0){
1271 const questionType = questionData[0]?.questionMasterId?.questionType?.name;
1272 document.querySelectorAll('.modal-backdrop').forEach(function(item){ item.classList.remove('active')})
1273 renderQuestionInModal(questionData,targetId);
1274 document.getElementById(targetId).classList.add('active');
1275 document.getElementById(targetId).setAttribute('data-questiontype', questionType);
1276 }else{
1277 onClickAddToCartBtn(productSkuId,passType,'addToCartFromBtn',isApproval,productId);
1278 }
1279 });
1280
1281 */
1282
1283 async function checkPendingOrderBeforeAdd(thisObj){
1284 let canProceed = true;
1285 const targetId = $(thisObj).attr('data-target')
1286 const productSkuId = $(thisObj).attr('data-product');
1287 const productId = $(thisObj).attr('data-cproductid');
1288 const passType = $(thisObj).attr('data-type');
1289 const cpdefinationId = parseInt($(thisObj).attr('data-cpdefinationid'));
1290 const isApproval = $(this).attr('data-approval');
1291
1292 if(Liferay.ThemeDisplay.isSignedIn()){
1293 const res = await request({
1294 url: "/o/headless-commerce-admin-order/v1.0/orders?filter=orderStatus/any(x:(x eq 1)) and creatorEmailAddress eq '" + themeDisplay.getUserEmailAddress() + "'&page=1&sort=orderDate%3Adesc",
1295 });
1296 const openOrderEntries = res?.data?.items ?? [];
1297 if(openOrderEntries .length > 0){
1298 canProceed = false;
1299
1300 var urlbilling = '/web/registration-portal/billing-information?eventId=${selectedEventId}&commerceCatalogId=${catalogId}&orderId='+openOrderEntries[0].id
1301 const params = new URLSearchParams(window.location.search);
1302 if (Liferay.ThemeDisplay.isImpersonated()) {
1303 urlbilling += "&doAsUserId="+encodeURIComponent(params.get("doAsUserId"));
1304 }
1305
1306 //<p class="ev-name-container">You already have [Item] in your order. Continue to billing, or confirm to replace it (your previous selection will be cleared).</p>
1307 $('#billing-btn').attr('href', urlbilling)
1308
1309 $('#cancel-order-btn').attr('data-target',targetId);
1310 $('#cancel-order-btn').attr('data-product',productSkuId);
1311 $('#cancel-order-btn').attr('data-cproductid',productId);
1312 $('#cancel-order-btn').attr('data-type',passType);
1313 $('#cancel-order-btn').attr('data-cpdefinationid',cpdefinationId);
1314 $('#cancel-order-btn').attr('data-approval',isApproval);
1315
1316 document.getElementById('info-prompt').classList.add('active');
1317 }
1318 }
1319 if(canProceed){
1320 addProductAfterCheckingOrder(targetId, productSkuId, productId, passType, cpdefinationId,isApproval);
1321 }
1322 console.log("coming here to add product:::::");
1323 }
1324
1325 function addProductAfterCheckingOrder(targetId, productSkuId, productId, passType, cpdefinationId,isApproval){
1326 const questionData = questionConfigData.filter(e => e.r_pass_CPDefinitionId === cpdefinationId);
1327 const isImpersonted = Liferay.ThemeDisplay.isImpersonated()
1328 if (questionData.length > 0 && !isImpersonted) {
1329 const questionType = questionData[0]?.questionMasterId?.questionType?.name;
1330 document.querySelectorAll('.modal-backdrop').forEach(function(item) {
1331 item.classList.remove('active')
1332 })
1333 renderQuestionInModal(questionData, targetId);
1334 document.getElementById(targetId).classList.add('active');
1335 document.getElementById(targetId).setAttribute('data-questiontype', questionType);
1336 } else {
1337 onClickAddToCartBtn(productSkuId, passType, 'addToCartFromBtn',isApproval ,productId);
1338 }
1339 }
1340
1341 function onClickAddToCartBtn(productSkuId,pass_Type,addToCartLocation,isApproval,productId) {
1342 if (themeDisplay.isSignedIn()) {
1343 if(Liferay.CommerceContext?.order?.orderId){
1344 addItemsInCart(Liferay.CommerceContext?.order?.orderId, productSkuId,pass_Type,addToCartLocation,isApproval,productId);
1345 }else{
1346 addNewItemInCart(productSkuId,pass_Type,addToCartLocation,isApproval,productId);
1347 }
1348 } else {
1349 addNewItemInCart(productSkuId,pass_Type,addToCartLocation,isApproval,productId);
1350 }
1351 }
1352 function manageRegistrationRedirection(productId ,data){
1353 const params = new URLSearchParams(window.location.search);
1354 var url = "/web/registration-portal/registration?eventId=${selectedEventId}&commerceCatalogId=${catalogId}&entryClassPK=" + productId;
1355 if (params.has("doAsUserId")) {
1356 url += "&doAsUserId="+encodeURIComponent(params.get("doAsUserId"))+"&orderId="+data.id;
1357 }
1358 window.location.href=url;
1359 }
1360
1361 function addGADataToTable(capturedParams,orderData){
1362 console.log("orderData >> ",orderData?.id);
1363 fetch('/o/c/gatrackings/', {
1364 method: 'POST',
1365 headers: {
1366 'accept': 'application/json',
1367 'Content-Type': 'application/json',
1368 'x-csrf-token': Liferay.authToken
1369 },
1370 body: JSON.stringify({
1371 sessionId: document.getElementById('ssId').value,
1372 utmCampaign: capturedParams.utm_campaign,
1373 utmContent: capturedParams.utm_content,
1374 utmMedium: capturedParams.utm_medium,
1375 utmSource: capturedParams.utm_source,
1376 utmTerm: capturedParams.utm_term,
1377 orderId: orderData?.id,
1378 urnNumber: orderData?.cartItems[0].id
1379 })
1380 })
1381 .then(response => {
1382 if (!response.ok) {
1383 // Handle HTTP-level errors
1384 throw new Error('HTTP error! Status:' + response.status);
1385 }
1386 return response.json(); // If API returns JSON
1387 })
1388 .then(data => {
1389 console.log('Success:', data);
1390 })
1391 .catch(error => {
1392 console.error('Fetch error:', error);
1393 });
1394 }
1395
1396 function manageQestionOrOrderAfterAddToCart(data, pass_Type, addToCartLocation, isApproval, productId) {
1397 let price = data?.cartItems[0].price?.finalPrice == 0
1398 ? data?.cartItems[0].price?.finalPrice
1399 : data?.cartItems[0].price?.price;
1400
1401 let promoPrice = data?.cartItems[0].price?.finalPrice == 0
1402 ? data?.cartItems[0].price?.finalPrice
1403 : data?.cartItems[0].price?.promoPrice;
1404
1405 const productData = {
1406 name: data?.cartItems[0].name,
1407 passType: pass_Type,
1408 price: price,
1409 total: data?.cartItems[0].price?.finalPrice,
1410 promoPrice: data?.cartItems[0].price?.promoPrice,
1411 isApproval: isApproval,
1412 productId: productId
1413 };
1414
1415 const params = new URLSearchParams(window.location.search);
1416 let capturedParams = {};
1417 // Capture UTM params
1418 ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"].forEach(param => {
1419 const value = params.get(param);
1420 if (value) {
1421 capturedParams[param] = value;
1422 }
1423 });
1424
1425 // Push event to GTM dataLayer
1426 window.dataLayer = window.dataLayer || [];
1427 window.dataLayer.push({
1428 'event': 'PassSelected',
1429 'eventId': '${selectedEventId}',
1430 'eventName': '${eventName}',
1431 'passName': data?.cartItems[0].name,
1432 'passType': pass_Type,
1433 'passPrice': price,
1434 'pageName': 'Pass Selection'
1435 });
1436
1437 // Store order + productData in cookies
1438 document.cookie = "com.liferay.commerce.model.CommerceOrder#${channelGroupId}=" + data.externalReferenceCode + "; path=/";
1439 document.cookie = "productData=" + encodeURIComponent(JSON.stringify(productData)) + "; path=/";
1440
1441 // Trigger Liferay event
1442 Liferay.fire("current-order-updated", { order: data });
1443
1444 // Add GA data if params exist
1445 if (Object.keys(capturedParams).length > 0) {
1446 addGADataToTable(capturedParams, data);
1447 }
1448
1449 fetch('/o/headless-commerce-delivery-cart/v1.0/cart-items/'+data?.cartItems[0].id, {
1450 method: 'PATCH',
1451 headers: {
1452 'accept': 'application/json',
1453 'Content-Type': 'application/json',
1454 'x-csrf-token': Liferay.authToken
1455 },
1456 body: JSON.stringify({
1457 'quantity': 1
1458 })
1459 })
1460 .then(response => {
1461 if (!response.ok) {
1462 throw new Error(response.status);
1463 }
1464 return response.json(); // adjust if API doesn’t return JSON
1465 })
1466 .then(updateData => {
1467 console.log("event id added in order:::: ", updateData);
1468 if (addToCartLocation === "addToCartFromModal") {
1469 manageQuestionDataOnSave($(document).find('.marketing-modal.active'), data?.cartItems[0].id, productId);
1470 } else {
1471 manageRegistrationRedirection(productId ,data);
1472 }
1473 })
1474 .catch(error => {
1475 console.error("Failed to update eventId:", error);
1476 if (addToCartLocation === "addToCartFromModal") {
1477 manageQuestionDataOnSave($(document).find('.marketing-modal.active'), data?.cartItems[0].id, productId);
1478 } else {
1479 manageRegistrationRedirection(productId , data);
1480 }
1481 })
1482
1483
1484 /*fetch('/o/headless-commerce-admin-order/v1.0/orderItems/'+data?.cartItems[0].id, {
1485 method: 'PATCH',
1486 headers: {
1487 'accept': 'application/json',
1488 'Content-Type': 'application/json',
1489 'x-csrf-token': Liferay.authToken
1490 },
1491 body: JSON.stringify({
1492 'quantity': 1
1493 })
1494 })
1495 .then(response => {
1496 if (!response.ok) {
1497 throw new Error(response.status);
1498 }
1499 return response.json(); // adjust if API doesn’t return JSON
1500 })
1501 .then(updateData => {
1502 console.log("event id added in order:::: ", updateData);
1503 if (addToCartLocation === "addToCartFromModal") {
1504 manageQuestionDataOnSave($(document).find('.marketing-modal.active'), data?.cartItems[0].id, productId);
1505 } else {
1506 manageRegistrationRedirection(productId);
1507 }
1508 })
1509 .catch(error => {
1510 console.error("Failed to update eventId:", error);
1511 if (addToCartLocation === "addToCartFromModal") {
1512 manageQuestionDataOnSave($(document).find('.marketing-modal.active'), data?.cartItems[0].id, productId);
1513 } else {
1514 manageRegistrationRedirection(productId);
1515 }
1516 });*/
1517
1518 /*
1519
1520 let commerceOrderId = 0;
1521 if (Liferay.CommerceContext?.order?.orderId) {
1522 commerceOrderId = Liferay.CommerceContext?.order?.orderId;
1523 } else {
1524 commerceOrderId = data?.id;
1525 }
1526
1527 fetch("https://apimanager-dwtc-prd.lfr.cloud/api/upgradepass/updateEventId?orderId=" + commerceOrderId + "&eventId=${selectedEventId}", {
1528 method: 'GET',
1529 })
1530 .then(response => {
1531 if (!response.ok) {
1532 throw new Error(response.status);
1533 }
1534 return response.json(); // adjust if API doesn’t return JSON
1535 })
1536 .then(updateData => {
1537 console.log("event id added in order:::: ", updateData);
1538 if (addToCartLocation === "addToCartFromModal") {
1539 manageQuestionDataOnSave($(document).find('.marketing-modal.active'), data?.cartItems[0].id, productId);
1540 } else {
1541 manageRegistrationRedirection(productId);
1542 }
1543 })
1544 .catch(error => {
1545 console.error("Failed to update eventId:", error);
1546 if (addToCartLocation === "addToCartFromModal") {
1547 manageQuestionDataOnSave($(document).find('.marketing-modal.active'), data?.cartItems[0].id, productId);
1548 } else {
1549 manageRegistrationRedirection(productId);
1550 }
1551 });*/
1552
1553
1554 // Continue flow without API call
1555 /*if (addToCartLocation === "addToCartFromModal") {
1556 manageQuestionDataOnSave($(document).find('.marketing-modal.active'), data?.cartItems[0].id, productId);
1557 } else {
1558 manageRegistrationRedirection(productId);
1559 }*/
1560 }
1561
1562 function addNewItemInCart(skuId,pass_Type,addToCartLocation,isApproval,productId) {
1563 const eventId= '${selectedEventId}';
1564 const customFieldsValue = Liferay.ThemeDisplay.isImpersonated()? { event_Id: eventId+"", Source: "Backend Agent" }: { event_Id: eventId+"" };
1565 const createCartBody = {
1566 accountId: accountId,
1567 cartItems: [{ options: '[]', quantity: 1, replacedSkuId: 0, skuId: skuId.toString() }],
1568 currencyCode: currencyCode,
1569 customFields: customFieldsValue
1570 };
1571
1572 fetch('/o/headless-commerce-delivery-cart/v1.0/channels/' + channelId + '/carts?nestedFields=cartItems', {
1573 "headers": {
1574 "accept": "application/json",
1575 "accept-language": "en-US",
1576 "content-type": "application/json",
1577 "x-csrf-token": Liferay.authToken
1578 },
1579 "body": JSON.stringify(createCartBody),
1580 "method": "POST",
1581 }).then(response => response.json())
1582 .then(data => {
1583 console.log("fire::: ", data);
1584 manageQestionOrOrderAfterAddToCart(data,pass_Type,addToCartLocation,isApproval,productId);
1585 })
1586 .catch(console.error);
1587 }
1588
1589 function addItemsInCart(cartId, skuId,pass_Type,addToCartLocation,isApproval,productId) {
1590 const eventId= '${selectedEventId}'
1591 fetch('/o/headless-commerce-delivery-cart/v1.0/carts/' + cartId + '?nestedFields=cartItems', {
1592 method: 'GET',
1593 headers: {
1594 accept: 'application/json',
1595 'Content-Type': 'application/json',
1596 'x-csrf-token': Liferay.authToken
1597 }
1598 })
1599 .then(r => r.json())
1600 .then(data => {
1601 const items = [...(data.cartItems || []), { options: '[]', quantity: 1, replacedSkuId: 0, skuId }];
1602 const customFieldsValue = Liferay.ThemeDisplay.isImpersonated()? { event_Id: eventId+"", Source: "Backend Agent" }: { event_Id: eventId+"" };
1603 const createCartBody = {
1604 cartItems: [{ options: '[]', quantity: 1, replacedSkuId: 0, skuId: skuId.toString() }],
1605 customFields: customFieldsValue
1606 };
1607
1608 return fetch('/o/headless-commerce-delivery-cart/v1.0/carts/' + cartId + '?nestedFields=cartItems', {
1609 method: 'PATCH',
1610 headers: {
1611 accept: 'application/json',
1612 'Content-Type': 'application/json',
1613 'x-csrf-token': Liferay.authToken
1614 },
1615 body: JSON.stringify(createCartBody)
1616 });
1617 })
1618 .then(response => response.json())
1619 .then(data => {
1620 console.log("fire::: ", data);
1621 manageQestionOrOrderAfterAddToCart(data,pass_Type,addToCartLocation,isApproval,productId);
1622 })
1623 .catch(console.error);
1624 }
1625
1626 // Open modal
1627 document.querySelectorAll('.trigger').forEach(btn => {
1628 manageModal(btn)
1629 });
1630
1631
1632
1633 function renderQuestionInModal(questionData,targetId){
1634 const questionLabel = questionData[0]?.questionMasterId?.questionLabel;
1635 const questionType = questionData[0]?.questionMasterId?.questionType?.name;
1636 document
1637 .getElementById(targetId)
1638 .querySelector('.section-title').setAttribute('data-questionid', questionData[0]?.id);
1639 document
1640 .getElementById(targetId)
1641 .querySelector('.section-title strong')
1642 .innerHTML = questionLabel;
1643
1644
1645 let updatedQuestionData = questionData || [];
1646 // Find the index of the object whose name starts with "North Star-"
1647 const northStarIndex = updatedQuestionData.findIndex(item => item.questionMasterId?.questionLabel.startsWith('North Star-'));
1648
1649 if (northStarIndex !== -1 && northStarIndex !== 1) {
1650 const [northStarItem] = updatedQuestionData.splice(northStarIndex, 1);
1651 updatedQuestionData.splice(1, 0, northStarItem);
1652 }
1653 console.log(updatedQuestionData);
1654
1655
1656 const gitexContainer = document.getElementById(targetId).querySelector('.checkbox-group-gitex');
1657 gitexContainer.innerHTML = "";
1658 const northStarContainer = document.getElementById(targetId).querySelector('.checkbox-group-northstar');
1659 northStarContainer.innerHTML = "";
1660 if(updatedQuestionData.length > 1){
1661 fetchAnswersforQuestion(updatedQuestionData[0]?.questionMasterId?.id, targetId, questionType, gitexContainer);
1662 fetchAnswersforQuestion(updatedQuestionData[1]?.questionMasterId?.id, targetId, questionType, northStarContainer);
1663 document.getElementById(targetId).querySelector('.conference-group-northstar').classList.remove('d-none');
1664
1665 }else if(updatedQuestionData.length == 1){
1666 //fetchAnswersforQuestion(updatedQuestionData[0]?.questionMasterId?.id, targetId, questionType, gitexContainer);
1667 const questionLabel = updatedQuestionData[0]?.questionMasterId?.questionLabel;
1668 let containerId = gitexContainer;
1669 if(questionLabel.startsWith('North Star-')){
1670 containerId = northStarContainer;
1671 const parts = questionLabel.split("North Star-");
1672 const currentYear = new Date().getFullYear();
1673 document.getElementById(targetId).querySelector('.section-title strong').innerHTML = parts[1];
1674 document.getElementById(targetId).querySelector('.conference-group-northstar').classList.remove('d-none');
1675 document.getElementById(targetId).querySelector('.conference-group-gitex').classList.add('d-none');
1676 document.getElementById(targetId).querySelector('.ev-name-container span').innerHTML = 'Expand North Star '+currentYear;
1677 }
1678 fetchAnswersforQuestion(updatedQuestionData[0]?.questionMasterId?.id, targetId, questionType, containerId);
1679 }
1680 }
1681
1682 function fetchAnswersforQuestion(questionMasterId, targetId, questionType, container){
1683 console.log("questionType ",questionType);
1684 const url = '/o/c/questionmasters/'+questionMasterId+'/question';
1685 Liferay.Util.fetch(url)
1686 .then((res) => res.json())
1687 .then((data) => {
1688 console.log("Questions fetched:", data);
1689 if(data.items.length > 0){
1690 //const container = document.getElementById(targetId).querySelector('.checkbox-group');
1691 container.innerHTML = "";
1692
1693 data.items.sort((a, b) => {
1694 if (a.answerLabel < b.answerLabel) return -1;
1695 if (a.answerLabel > b.answerLabel) return 1;
1696 return 0;
1697 });
1698
1699 data.items.map(item => {
1700 let checkboxTMPL = "";
1701 if(questionType == "SingleSelect"){
1702 checkboxTMPL = '<label> <input type="radio" name="marketingAnswers" value="'+item.id+'" data-label="'+item.answerLabel+'"> <p>'+item.answerLabel+'</p> </label>';
1703 }else if(questionType == "MultiSelect"){
1704 checkboxTMPL = '<label> <input type="checkbox" value="'+item.id+'" data-label="'+item.answerLabel+'"> <p>'+item.answerLabel+'</p> </label>';
1705 }else{
1706 checkboxTMPL = '<label> <input class="form-control" type="text" data-value="'+item.id+'"></label>';
1707 }
1708 container.insertAdjacentHTML('beforeend', checkboxTMPL);
1709 });
1710 }
1711 })
1712 .catch((error) => {
1713 console.error("Error fetching answer:", error);
1714 });
1715 }
1716
1717 function manageModal(btn){
1718 btn.addEventListener('click', () => {
1719 document.querySelectorAll('.modal-backdrop').forEach(function(item){ item.classList.remove('active')})
1720 const targetId = btn.dataset.target;
1721 document.getElementById(targetId).classList.add('active');
1722 });
1723 }
1724
1725
1726 // Modal logic
1727 $('.modal-backdrop').each(function () {
1728 const $modal = $(this);
1729 const $closeBtn = $modal.find('.close-btn');
1730 const $cancelBtn = $modal.find('.cancel-btn');
1731 // Close modal on close/cancel click
1732 $closeBtn.on('click', function () {
1733 $modal.removeClass('active');
1734 });
1735
1736 $cancelBtn.on('click', function () {
1737 $modal.removeClass('active');
1738 });
1739 })
1740
1741 function updateAnswerTransactions(answersArr,productId){
1742 fetch('/o/c/answertransactions/batch', {
1743 method: 'POST',
1744 headers: {
1745 'accept': 'application/json',
1746 'Content-Type': 'application/json',
1747 'x-csrf-token': Liferay.authToken
1748 },
1749 body: JSON.stringify(answersArr)
1750 })
1751 .then(response => response.json())
1752 .then(data => {
1753 console.log("data ",data);
1754 manageRegistrationRedirection(productId);
1755 })
1756 .catch(console.error);
1757 }
1758 function saveDataForQuestionSelection($modal, orderLineId, optionType,productId){
1759 const questionId = $modal.find('.section-title').attr('data-questionid');
1760 const selectedItems = $modal.find('input[type="'+optionType+'"]:checked');
1761 const userId = themeDisplay.getUserId();
1762 let selectedItemsArr = [];
1763 selectedItems.each(function(index, item){
1764 let answerObj = {};
1765 answerObj.answerMasterId = parseInt($(this).attr('value'));
1766 answerObj.answerValue = $(this).attr('data-label');
1767 answerObj.currentUserId = parseInt(userId);
1768 answerObj.orderLineId = orderLineId;
1769 answerObj.questionId = parseInt(questionId);
1770 answerObj.parentAnswerId = 0;
1771 selectedItemsArr.push(answerObj);
1772 });
1773 updateAnswerTransactions(selectedItemsArr,productId);
1774 }
1775
1776 function saveDataOfTextQuestions($modal, orderLineId,productId){
1777 const questionId = $modal.find('.section-title').attr('data-questionid');
1778 const selectedItems = $modal.find('input[type="text"]');
1779 const userId = themeDisplay.getUserId();
1780 let selectedItemsArr = [];
1781 selectedItems.each(function(index, item){
1782 let answerObj = {};
1783 answerObj.answerMasterId = parseInt($(this).attr('value'));
1784 answerObj.answerValue = $(this).val();
1785 answerObj.currentUserId = parseInt(userId);
1786 answerObj.orderLineId = orderLineId;
1787 answerObj.questionId = parseInt(questionId);
1788 answerObj.parentAnswerId = 0;
1789 selectedItemsArr.push(answerObj);
1790 });
1791 updateAnswerTransactions(selectedItemsArr,productId);
1792 }
1793 function manageQuestionDataOnSave($modal, orderItemId,productId){
1794 const questionType = $modal.attr('data-questiontype');
1795 console.log("questionType ",questionType);
1796 console.log("order item id ",orderItemId);
1797 if(questionType == "MultiSelect"){
1798 saveDataForQuestionSelection($modal, orderItemId, 'checkbox',productId);
1799 }else if(questionType == "SingleSelect"){
1800 saveDataForQuestionSelection($modal, orderItemId, 'radio',productId);
1801 }else{
1802 saveDataOfTextQuestions($modal, orderItemId,productId);
1803 }
1804 }
1805
1806 $('.marketing-modal').each(function () {
1807 const $modal = $(this);
1808 const questionType = $modal.attr('data-questiontype');
1809 const $confirmBtn = $modal.find('.confirm-btn');
1810 $confirmBtn.on('click', function (event) {
1811 const productSkuId = $(this).attr('data-product');
1812 const productId = $(this).attr('data-cproductid');
1813 const productType = $(this).attr('data-type');
1814 const isApproval = $(this).attr('data-approval');
1815 console.log("on confirm btn ");
1816 onClickAddToCartBtn(productSkuId, productType, 'addToCartFromModal',isApproval,productId);
1817 });
1818
1819
1820 // Toggle confirm button based on checkbox count
1821 function toggleConfirmButton() {
1822 const checkedCount = $modal.find('input[type="checkbox"]:checked').length;
1823 if (checkedCount >= 1) {
1824 $confirmBtn.addClass('enabled').removeAttr('disabled');
1825 } else {
1826 $confirmBtn.removeClass('enabled').attr('disabled', true);
1827 }
1828 }
1829 function toggleConfirmButtonForRadio(){
1830 const checkedRadioCount = $modal.find('input[type="radio"]:checked').length;
1831 console.log("checkedRadioCount", checkedRadioCount);
1832 if (checkedRadioCount == 1) {
1833 $confirmBtn.addClass('enabled').removeAttr('disabled');
1834 } else {
1835 $confirmBtn.removeClass('enabled').attr('disabled', true);
1836 }
1837 }
1838
1839 function toggleConfirmButtonForText() {
1840 const textInputItem = $modal.find('input[type="text"]');
1841 if (textInputItem.val().length > 0) {
1842 $confirmBtn.addClass('enabled').removeAttr('disabled');
1843 } else {
1844 $confirmBtn.removeClass('enabled').attr('disabled', true);
1845 }
1846 }
1847
1848 // Delegate change event for dynamically added checkboxes
1849 $modal.on('change', 'input[type="checkbox"]', toggleConfirmButton);
1850 $modal.on('change', 'input[type="radio"]', toggleConfirmButtonForRadio);
1851 $modal.on('input', 'input[type="text"]', toggleConfirmButtonForText);
1852
1853 // Initial state
1854 toggleConfirmButton();
1855 });
1856
1857 </script>
1858<#else>
1859 No Result Found
1860</#if>