Um erro ocorreu enquanto processava o modelo.
The following has evaluated to null or missing:
==> qstringmap["ecdma-lc"] [in template "10154#10192#19541382" at line 45, column 15]
----
Tip: It's the final [] step that caused this error, not those before it.
----
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: #assign lc = qstringmap["ecdma-lc"]?f... [in template "10154#10192#19541382" at line 45, column 1]
----
1<#--
2public product selector version of rewards calc only has google anyltics(ga()) on rewards calculate button. elan version has all ga() calls.
3-->
4<#-- ecdma-lc=01133 ecdma-lc=04851(Diffrent card art for consumer and business) ecdma-lc=17329(Business cards only) -->
5<#assign utilServ = (serviceLocator.findService("com.elan.crc.utilites.service.CRCRemoteServiceService"))! />
6
7
8<#--<#assign url = request.attributes.CURRENT_URL > -->
9<#assign url = themeDisplay.getURLCurrent() >
10
11<#assign qstringmap = httpUtil.getParameterMap(httpUtil.getQueryString(url))>
12
13<#-- What enviroment we are in QA UAT PROD -->
14<#assign host = request["scheme"] + "://" + themeDisplay.getServerName()>
15<#-- Enviroment used for dynamic Learn More and No Annual Fee links href="${environment}/11t3/${productURL}?ecdma-lc=${lc}${ecidExt}" -->
16<#-- Defaults to enviroment for Prod -->
17<#assign environment = "https://creditcardlearnmore.com">
18<#assign oadURL_TC = 'https://online1.elancard.com/oad/terms.controller' >
19<#if host?contains("uat")>
20 <#assign oadURL_TC = 'https://uat-online1.elancard.com/oad/terms.controller' >
21</#if>
22
23<#if host?contains("admin.") && !host?contains("uat-admin.")>
24 <#assign environment = "http://admin.creditcardlearnmore.com">
25<#elseif host?contains("admin-lr7crc.uat.")>
26 <#assign environment = host + "/web/creditcardlearnmore">
27<#elseif host?contains("lr7crc.uat.")>
28 <#assign environment = host + "/web/creditcardlearnmore">
29<#elseif host?contains("admin-lr7crc.herodigital")>
30 <#assign environment = host + "/web/creditcardlearnmore">
31<#elseif host?contains("admin-lr7crc.qa")>
32 <#assign environment = host + "/web/creditcardlearnmore">
33</#if>
34
35<#-- ecid has something to do with tracking. Used for the Learn More links -->
36<#if qstringmap["ecid"]?has_content>
37 <#assign ecidExt="&ecid="+qstringmap["ecid"]?first>
38 <#assign campaignId = qstringmap["ecid"]?first >
39<#else>
40 <#assign ecidExt="">
41 <#assign campaignId = "" >
42</#if>
43
44<#-- retrieves location code(lc) from query params and sets prefix -->
45<#assign lc = qstringmap["ecdma-lc"]?first>
46<#assign prefix = "00000" >
47<#assign lcWithPrefix = prefix + lc >
48<#assign withPrefixLength = lcWithPrefix?length >
49<#assign startHere = withPrefixLength - 5>
50<#assign lc = lcWithPrefix?substring(startHere)>
51
52<#-- using lc gets partner name, pbu, and subbu -->
53<#assign clientProfileService = serviceLocator.findService('com.elan.crc.user.service.CrcClientProfileLocalService') >
54<#assign clientProfileList = clientProfileService.findByLocationCode(lc)>
55<#if clientProfileList?first?has_content>
56 <#assign clientProfile = clientProfileList?first>
57 <#assign partnerName = clientProfile.getMarketingNameLong()>
58 <#assign pbu = clientProfile.getPbu()>
59 <#assign subbu = clientProfile.getSUBBRANDBUNBR()>
60 <#-- logoFileName path -->
61 <#assign logoFileName = clientProfile.getLogoBFormat1()?replace(".", "-")?replace("-([^-]*)$", ".$1", "r")?lower_case>
62
63 <#-- gets cards for finical institution(fi) -->
64 <#assign fiCardsData = (utilServ.makeCall('crcTier3GetPbuData','0&'+ pbu +'&'+subbu))!>
65</#if>
66
67
68<#assign cdnCardArtUrl = (propsUtil.get('rackspace.cdn.cardart.url'))!>
69<#-- Prod cdnLogoUrl-->
70<#assign cdnLogoUrl = (propsUtil.get('rackspace.cdn.web.url'))!>
71<#assign panoUrl = getterUtil.getString(propsUtil.get('pano.url'), 'https://www.mycardapply.com')>
72
73 <#assign crcRewardsCalculatorLocalService = serviceLocator.findService('com.elan.crc.quicklink.service.CrcRewardsCalculatorLocalService') >
74 <#assign rewardsList =
75 crcRewardsCalculatorLocalService.getCrcRewardsCalculators(-1,-1)>
76
77
78<#-- BUILD REWARDS LOOKUP MAP (offerType → reward) -->
79
80<#assign rewardsByOfferType = {}>
81
82<#if rewardsList?has_content>
83 <#list rewardsList as reward>
84 <#assign rewardsByOfferType =
85 rewardsByOfferType + {
86 reward.getOfferType()?string : reward
87 }
88 >
89 </#list>
90</#if>
91
92<#-- WEB CONTENT LOOKUP (offerType → child fields) -->
93<#-- Parent: Numberh6rv (offerType) -->
94
95<#assign wcByOfferType = {}>
96
97<#if Numberh6rv.getSiblings()?has_content>
98 <#list Numberh6rv.getSiblings() as wcItem>
99
100 <#assign offerTypeKey = wcItem.getData()?string />
101
102 <#assign textTitle = "" />
103 <#if wcItem.Text13zu?? && wcItem.Text13zu.getData()?has_content>
104 <#assign textTitle = wcItem.Text13zu.getData() />
105 </#if>
106
107 <#assign childTextHtml = "" />
108 <#if wcItem.HTMLbl7t?? && wcItem.HTMLbl7t.getData()?has_content>
109 <#assign childTextHtml = wcItem.HTMLbl7t.getData() />
110 </#if>
111
112 <#assign childText = "" />
113 <#if wcItem.annualFeeText?? && wcItem.annualFeeText.getData()?has_content>
114 <#assign childText = wcItem.annualFeeText.getData() />
115 </#if>
116
117 <#assign wcByOfferType = wcByOfferType + {
118 offerTypeKey : {
119 "text" : textTitle,
120 "textHtml" : childTextHtml,
121 "childText" : childText
122 }
123 }>
124
125
126 </#list>
127</#if>
128
129<#-- COMBINED LIST -->
130
131<#assign combinedList = []>
132<#if fiCardsData?has_content>
133 <#list fiCardsData as fib>
134 <#assign offerKey = fib.offerType?string />
135 <#assign offerId = fib.offerId?string />
136 <#assign reward = rewardsByOfferType[offerKey]! />
137 <#assign wcData = wcByOfferType[offerKey]! />
138 <#-- Include only when reward exists -->
139 <#if reward?has_content>
140 <#assign combinedList = combinedList + [{
141 "offerType" : offerKey,
142 "offerId" : offerId,
143 "card" : fib,
144 "reward" : reward,
145 "wc" : wcData
146 }]>
147 </#if>
148
149 </#list>
150</#if>
151
152<#-- STEP 3: OPTIONAL SORT (BY CARD ORDER) -->
153<#--
154<#if combinedList?has_content>
155 <#assign combinedList = combinedList?sort_by("card.cardOrder")>
156</#if>
157-->
158
159<div class="container re_header">
160 <!-- Logo Section -->
161 <div class="row mybenifit_header">
162 <div class="header-bar">
163 <div class="header-left">
164 <#if (backArrow.getData())?? && backArrow.getData() != "">
165 <img class="d-none" alt="${backArrow.getAttribute("alt")}" data-fileentryid="${backArrow.getAttribute("fileEntryId")}" src="${backArrow.getData()}" />
166 </#if>
167 <img
168 class="re_cdn_logo" src="${cdnLogoUrl!''}/${logoFileName!''}"
169 alt="elan-logo" loading="eager"/>
170 </div>
171
172 <!-- Right section -->
173 <div class="header-right d-none card_reset_btn" id="resettext"onclick="setCardType('ALL', this)">
174 <#if (resetIcon.getData())?? && resetIcon.getData() != "">
175 <img alt="${resetIcon.getAttribute("alt")}" data-fileentryid="${resetIcon.getAttribute("fileEntryId")}" src="${resetIcon.getData()}" />
176 </#if>
177 <div class="reset-text">Reset</div>
178 </div>
179 </div>
180
181 <h1 class="re_cdn_titl" id="title1">
182 <#if (title.getData())??>
183 ${title.getData()}
184 </#if>
185 </h1>
186 <p class="re_cdn_sub_titl" id="des1">
187 <#if (description.getData())??>
188 ${description.getData()}
189 </#if></p>
190 <h1 class="re_cdn_titl" id="title2">
191 <#if (consumerCardTitle.getData())??>
192 ${consumerCardTitle.getData()}
193 </#if></h1>
194 <p class="re_cdn_sub_titl" id="des2">
195 <#if (consumerCardDes.getData())??>
196 ${consumerCardDes.getData()}
197 </#if></p>
198 <h1 class="re_cdn_titl" id="title3">
199 <#if (consumerCategoryTitle.getData())??>
200 ${consumerCategoryTitle.getData()}
201 </#if></h1>
202 <p class="re_cdn_sub_titl" id="des3">
203 <#if (consumerEveryDayDes.getData())??>
204 ${consumerEveryDayDes.getData()}
205 </#if></p>
206 <p class="re_cdn_sub_titl" id="des4">
207 <#if (consumerTravelDes.getData())??>
208 ${consumerTravelDes.getData()}
209 </#if></p>
210 </div>
211 <!-- Cards Section -->
212
213 <div class="row re_card_sec mt-4" id="reCardSec">
214
215 <div class="re_card" id="re_card_cosumer" onclick="setCardType('CONSUMER', this)">
216 <img class="re_card_icon" src="${consumerCardImage.getData()}" />
217 <h2 class="re_card_title">Consumer Credit Cards</h2>
218 </div>
219
220 <div class="re_card" id="re_card_consumer_business" onclick="setCardType('BUSINESS', this)">
221 <img class="re_card_icon" src="${businessCardImage.getData()}" />
222 <h2 class="re_card_title">Business Credit Cards</h2>
223 </div>
224 <div class="plus-symbol d-none" id="plussymbol">
225 +
226 </div>
227 <div class="re_card d-none" id="re_card_everyday" onclick="setCardType('EVERYDAY', this)">
228 <#if (consumerEveryDayImg.getData())?? && consumerEveryDayImg.getData() != "">
229 <img class="re_card_icon" alt="${consumerEveryDayImg.getAttribute("alt")}" data-fileentryid="${consumerEveryDayImg.getAttribute("fileEntryId")}" src="${consumerEveryDayImg.getData()}" />
230 </#if>
231 <h2 class="re_card_title">Everyday Spend</h2>
232 </div>
233
234 <div class="re_card d-none" id="re_card_travel" onclick="setCardType('TRAVEL', this)">
235 <#if (consumerTravelImg.getData())?? && consumerTravelImg.getData() != "">
236 <img class="re_card_icon" alt="${consumerTravelImg.getAttribute("alt")}" data-fileentryid="${consumerTravelImg.getAttribute("fileEntryId")}" src="${consumerTravelImg.getData()}" />
237 </#if>
238 <h2 class="re_card_title">Travel</h2>
239 </div>
240
241 </div>
242
243
244</div>
245
246<div class="car_sec">
247 <div class="section-header">
248 <div class="section-title" id="cardCount">
249 All Cards (${combinedList?has_content?then(combinedList?size, 0)} Cards)
250 </div>
251 </div>
252
253 <section class="carousel-section" role="region" aria-label="Cards carousel">
254
255 <!-- ADD rcarousel-inner class -->
256 <div class="card-list rcarousel-inner" id="carouselInner"></div>
257 </section>
258</div>
259
260<div class="frame_sec d-none" id="framesec">
261 <div class="section-aerrow">
262 <div class="carousel-indicator">
263 <button class="indicator-arrow" id="iframePrev"
264 onclick="changeIframe(-1)" aria-label="Previous calculator">
265 ←
266 </button>
267
268 <div class="indicator-count" id="indicatorCount"></div>
269
270 <button class="indicator-arrow" id="iframeNext"
271 onclick="changeIframe(1)" aria-label="Next calculator">
272 →
273 </button>
274
275 </div>
276
277 </div>
278
279 <div class="iframe-wrapper d-none" id="iframeWrapper"></div>
280
281
282
283 <div class="section-footer">
284 <div class="section-footer-title" id="section-footer-title" onclick="scrollToTop()">
285 ↑ Back to top
286 </div>
287 </div>
288</div>
289
290<style>
291.indicator-arrow:disabled {
292 opacity: 0.4;
293 cursor: not-allowed;
294 pointer-events: none;
295}
296
297.indicator-count {
298 min-width: 60px;
299 text-align: center;
300 font-family: Arial, sans-serif;
301 font-size: 14px;
302 font-weight: 700;
303 color: #ffffff; /* arrow bar is black */
304}
305.iframe-wrapper {
306 width: 100%;
307 height: 100%;
308 padding: 0 8px;
309 background: #ffffff;
310
311 display: inline-flex;
312 justify-content: center;
313 align-items: center;
314 gap: 8px;
315 box-sizing: border-box;
316}
317
318.iframe-content {
319 flex: 1 1 0;
320 width: 100%;
321 max-width: 736px;
322 height: 558.9px;
323
324 border: 0;
325}
326
327/* ===== HEADER WRAPPER ===== */
328.mybenifit_header{
329 width: 700px;
330 margin: auto;
331}
332
333.header-bar {
334 display: flex;
335 flex-direction: row;
336 justify-content: space-between;
337 align-items: center;
338 max-width: 700px;
339 width: 100%;
340 height: auto;
341 min-height: 40px;
342 position: relative;
343}
344
345/* ===== LEFT SECTION ===== */
346.header-left {
347 width: 300px;
348 display: flex;
349 align-items: center;
350 gap: 16px;
351}
352/* ===== RIGHT SECTION ===== */
353.header-right {
354 display: flex;
355 align-items: center;
356 justify-content: center;
357 gap: 8px;
358}
359
360
361/* Reset text */
362.card_reset_btn{
363 cursor: pointer;
364}
365.reset-text {
366 color: var(--Core-Black, #000000);
367 font-family: Arial, sans-serif;
368 font-size: 14px;
369 font-weight: 700;
370 text-align: center;
371}
372
373.re_header {
374 max-width: 752px;
375 width: 100%;
376 background: #E6E6E6;
377 padding: 24px;
378 box-sizing: border-box;
379}
380.re_car_sec{
381 height: 62px;
382 background: #000000;
383 border-top: 1px solid #D7D7D7;
384 box-sizing: border-box;
385}
386
387.re_cdn_logo {
388 width: 162px;
389 height: 62px;
390}
391/*.re_cdn_logo.consumer-logo {
392 width: 104px;
393 height: 40px;
394}*/
395.reset-link {
396 margin-left: auto; /* pushes to right corner */
397 cursor: pointer;
398 font-weight: 700;
399 margin-right:50px;
400}
401
402.re_cdn_titl{
403 font: 400 34px/52px Arial, sans-serif;
404 color: #000;
405}
406
407.re_cdn_sub_titl {
408 max-width: 702px;
409 width: 100%;
410 font-family: Arial, sans-serif;
411 font-weight: 400;
412 font-size: 14px;
413 line-height: 22px;
414 letter-spacing: 0;
415 color: #000000;
416}
417
418
419.re_card_sec{
420 display: flex;
421 justify-content: center;
422 align-items: center;
423 gap: 16px;
424 height: 100px;
425}
426
427.re_card {
428 box-sizing: border-box;
429 display: flex;
430 flex-direction: column;
431 align-items: center;
432 width: 100%;
433 max-width: 200px;
434 height: 100px;
435 padding: 12px;
436 background: #FFFFFF;
437 border: 1px solid #969798;
438 cursor: pointer;
439}
440
441.plus-symbol {
442 color: var(--Core-Elan-Dark-Blue, #084BB7);
443 text-align: center;
444 font-family: Arial, sans-serif;
445 font-size: 20px;
446 font-weight: 700;
447 line-height: normal;
448}
449
450.re_card.active {
451 background: var(--Core-Elan-Dark-Blue, #084BB7);
452
453}
454.re_card.active .re_card_title {
455 color: #ffffff; /* or whatever color you want */
456}
457.re_card_sec.consumer-active {
458 gap: 8px;
459}
460.re_card.active .re_card_icon {
461 filter: brightness(0) invert(1);
462}
463
464.re_card_icon{
465 width: 32px;
466 height: 32px;
467 position: relative;
468 top: 2.08px;
469}
470.re_card_title{
471 width: 85px;
472 height: 32px;
473 font-family: Arial, sans-serif;
474 font-weight: 700;
475 font-size: 14px !important;
476 line-height: 1 !important;
477 text-align: center;
478 color: #084BB7;
479}
480
481</style>
482
483<style>
484.car_sec{
485 max-width: 754px;
486 width: 100%;
487 /* min-height: 705px; */
488 box-sizing: border-box;
489}
490.section-header {
491 box-sizing: border-box;
492 width: 100%;
493 max-width: 754px;
494 height: 62px;
495 background: #000000;
496 border: 1px solid #D7D7D7;
497 display: flex;
498 align-items: center;
499 padding: 0 16px;
500 justify-content: center;
501}
502
503.section-title {
504 font-family: Arial, sans-serif;
505 font-weight: 700;
506 font-size: 18px;
507 line-height: 22px;
508 color: #FFFFFF;
509}
510.section-footer{
511 box-sizing: border-box;
512 width: 100%;
513 max-width: 754px;
514 height: 62px;
515 background: var(--Core-Dark-Gray, #969798);
516 border: 1px solid #D7D7D7;
517 display: flex;
518 align-items: center;
519 padding: 0 16px;
520}
521.carousel-section {
522 position: relative;
523 overflow: hidden;
524 max-width: 750px;
525 width: 100%;
526 /* min-height: 643px; */
527 display: flex;
528 flex-direction: column;
529 gap: 16px;
530 padding: 24px 0;
531 background: var(--Core-White, #FFFFFF);
532 box-sizing: border-box;
533}
534
535.card-list {
536 display: flex !important;
537 flex-wrap: wrap !important;
538 justify-content: center;
539 gap: 16px;
540 transform: none !important;
541 transition: none !important;
542}
543
544/*.rcard {
545 flex: 0 0 calc(33.333% - 16px);
546 max-width: calc(33.333% - 16px);
547 display: flex;
548 justify-content: center;
549}*/
550
551
552.cal-card {
553 max-width: 210px;
554 width: 100%;
555 border: 1px solid #FFFFFF;
556 box-sizing: border-box;
557 position: relative;
558 font-family: Arial, sans-serif;
559}
560
561/* ===== IMAGE ===== */
562.cal-card-image {
563 width: 100%;
564 display: flex;
565 justify-content: center;
566 position: absolute;
567 z-index: 2;
568}
569
570.cal-card-image img {
571 width: 171.875px;
572 height: 110px;
573 object-fit: contain;
574}
575
576
577/* ===== BODY ===== */
578
579.cal-card-body {
580 margin-top: 101px;
581 width: 100%;
582 background: #CECACA;
583 border-radius: 12px;
584 box-sizing: border-box;
585 padding: 16px;
586 color:#00000;
587}
588
589
590/* ===== TITLE ===== */
591.cal-card-title {
592 height: 44px;
593 font-family: Arial, sans-serif;
594 font-weight: 700;
595 font-size: 18px;
596 line-height: 21.6px;
597 letter-spacing: 0;
598 text-align: center;
599 display: flex;
600 align-items: center;
601 justify-content: center;
602}
603
604
605/* ===== DIVIDER ===== */
606
607.cal-divider, .cal-card-divider {
608 width: 162px;
609 margin: 16px auto;
610 border-bottom: 1px solid #000000;
611}
612
613/* ===== DETAILS ===== */
614 .cal-card-details {
615 width: 162px;
616 height: 75px;
617 display: flex;
618 flex-direction: column;
619 gap: 12px;
620}
621
622/* Frame */
623.cal-card-detail-row {
624 width: 100%;
625 min-height: 44px;
626 display: flex;
627 gap: 8px;
628 box-sizing: border-box;
629}
630
631.multiplier {
632 min-width: 21px;
633 font-family: Arial, sans-serif;
634 font-weight: 700;
635 font-size: 14px;
636 line-height: 22px;
637 white-space: nowrap;
638}
639.description {
640 font-family: Arial, sans-serif;
641 font-weight: 400;
642 font-size: 14px;
643 line-height: 22px;
644 text-align: center;
645}
646
647/* ===== FEE ===== */
648.cal-fee {
649 font-family: Arial, sans-serif;
650 font-weight: 400;
651 font-size: 14px;
652 line-height: 22px;
653 text-decoration: underline;
654 text-align: center;
655 color : #000 !important;
656}
657
658
659/* ===== ACTIONS ===== */
660.cal-actions {
661 display: flex;
662 justify-content: center;
663 margin-top: auto;
664}
665
666/* ===== BUTTON ===== */
667.cal-btn-primary {
668 color:var(--Core-Elan-Dark-Blue, #084BB7) !important;
669 width: 150px;
670 height: 44px;
671 color: #000;
672 cursor: pointer;
673 display: flex;
674 align-items: center;
675 justify-content: center;
676 border: 2px solid var(--Core-Elan-Dark-Blue, #084BB7) !important;
677 background: var(--Core-White, #FFF) !important;
678}
679
680.cal-btn-text {
681 text-shadow: none !important;
682 font-family: Arial, sans-serif;
683 font-size: 14px;
684 font-style: normal;
685 font-weight: 700;
686 line-height: 22.5px;
687 text-transform: capitalize;
688}
689.frame_sec{
690 max-width: 754px;
691 width: 100%;
692 box-sizing: border-box;
693}
694
695.frame-section-header {
696 box-sizing: border-box;
697 width: 100%;
698 max-width: 754px;
699 height: 62px;
700 background: #000000;
701 border: 1px solid #D7D7D7;
702 display: flex;
703 align-items: center;
704 justify-content: center;
705}
706
707.frame-title {
708 font-family: Arial, sans-serif;
709 font-weight: 700;
710 font-size: 18px;
711 line-height: 22px;
712 color: #FFFFFF;
713}
714.section-footer-title {
715 color: var(--Core-Black, #000000);
716 text-align: center;
717 font-family: Arial, sans-serif;
718 font-size: 18px;
719 font-style: normal;
720 font-weight: 700;
721 line-height: 22px;
722 max-width: 737.203px;
723 flex-shrink: 0;
724 margin: auto;
725 cursor: pointer;
726}
727
728/* Arrows */
729.section-aerrow {
730 box-sizing: border-box;
731 width: 100%;
732 max-width: 754px;
733 height: 62px;
734 background: #000000;
735 border: 1px solid #D7D7D7;
736 display: flex;
737 padding: 0 16px;
738 align-items: center;
739 justify-content: center;
740}
741.carousel-arrow {
742 position: absolute;
743 top: 50%;
744 transform: translateY(-50%);
745 background: #ffffff;
746 border: 1px solid #ccc;
747 width: 36px;
748 height: 36px;
749 border-radius: 50%;
750 cursor: pointer;
751 font-size: 22px;
752 line-height: 34px;
753 text-align: center;
754 z-index: 5;
755}
756
757.carousel-arrow.left {
758 left: 10px;
759}
760
761.carousel-arrow.right {
762 right: 10px;
763}
764
765.carousel-arrow:hover {
766 background: #084BB7;
767 color: #fff;
768}
769.carousel-indicator {
770 display: flex;
771 align-items: center;
772 gap: 14px;
773}
774
775.indicator-arrow {
776 border: none;
777 font-size: 22px;
778 cursor: pointer;
779 background: #000 !important;
780 color: #fff;
781}
782
783.indicator-arrow:hover {
784 color: #084BB7;
785 color: #fff;
786}
787
788.indicator-dots {
789 display: flex;
790 gap: 8px;
791}
792
793.indicator-dot {
794 width: 10px;
795 height: 10px;
796 border-radius: 50%;
797 background: #d0d0d0;
798 cursor: pointer;
799}
800
801.indicator-dot.active {
802 background: #084BB7;
803}
804
805.rcard.is-focused {
806 outline: none;
807 box-shadow: none;
808 border: none;
809}
810
811.rcard.is-focused .cal-card-body {
812 color:#fff;
813 background:var(--Core-Elan-Dark-Blue, #084BB7)
814}
815.rcard.is-focused .cal-fee {
816 color:#fff !important;
817}
818.rcard.is-focused .cal-divider, .rcard.is-focused .cal-card-divider {
819 border-bottom: 1px solid var(--Core-Elan-Dark-Blue, #fff)
820}
821
822
823/* This Style is for */
824
825.re_header,
826.car_sec,
827.section-header,
828.carousel-section,
829.frame_sec,
830.section-aerrow,
831.section-footer {
832 max-width: 100% !important;
833 width: 100% !important;
834}
835
836.header-bar {
837 max-width: 100% !important;
838}
839
840.container {
841 max-width: 100% !important;
842}
843
844
845
846
847
848</style>
849
850<script>
851const cardsData = [
852 <#if combinedList?has_content>
853 <#list combinedList as item>
854 {
855 offerType: "${item.offerType}",
856 offerId: "${item.offerId}",
857 title: "${item.reward.getCardName()?js_string!''}",
858 groupName:
859 "${item.reward.getGroupName()?upper_case?contains('BUSINESS')?then('BUSINESS','CONSUMER')}",
860 category:
861 "${item.reward.getCategory()?upper_case?contains('EVERYDAY')?then('EVERYDAY','TRAVEL')}",
862 imageUrl: "${cdnCardArtUrl}/${item.card.filename}.png",
863 wcTextHtml: "${item.wc?has_content?then(item.wc.textHtml?js_string,'')}",
864 wcChildText: "${item.wc?has_content?then(item.wc.childText?js_string,'')}"
865 }<#if item_has_next>,</#if>
866 </#list>
867 </#if>
868];
869
870
871/* =========================================================
872 INIT
873========================================================= */
874
875document.addEventListener('DOMContentLoaded', () => {
876 applyInitialCardMixUI();
877 renderCarousel();
878 autoSelectFirstCard();
879 updateIframeCounter();
880 isInitialLoad = false;
881});
882
883
884function setCardType(type, el) {
885
886 if (
887 (type === 'CONSUMER' || type === 'BUSINESS') &&
888 el.classList.contains('disabled')
889 ) {
890 return;
891 }
892
893 if (type === 'ALL') {
894 resetUIToDefault();
895 return;
896 }
897
898 // Consumer / Business
899 if (type === 'CONSUMER' || type === 'BUSINESS') {
900 activeCardType = type;
901 activeCategory = 'ALL';
902 }
903
904 // Category only under Consumer
905 if (
906 (type === 'EVERYDAY' || type === 'TRAVEL') &&
907 activeCardType === 'CONSUMER'
908 ) {
909 activeCategory = type;
910 }
911
912 // Active UI
913 // Remove active only when switching main types
914 if (type === 'CONSUMER' || type === 'BUSINESS') {
915 document.querySelectorAll('.re_card')
916 .forEach(card => card.classList.remove('active'));
917 }
918
919 // Always activate clicked card
920 el.classList.add('active');
921
922 // Keep CONSUMER active when selecting sub-categories
923 if (type === 'EVERYDAY' || type === 'TRAVEL') {
924 const consumerCard = document.getElementById('re_card_cosumer');
925 if (consumerCard) {
926 consumerCard.classList.add('active');
927 }
928 }
929
930
931 // Disable logic
932 if (type === 'CONSUMER') {
933 handleConsumerSubCard();
934 el.classList.add('disabled');
935 }
936
937 if (type === 'BUSINESS') {
938 document.getElementById('re_card_everyday')?.classList.remove('active');
939 document.getElementById('re_card_travel')?.classList.remove('active');
940 el.classList.add('disabled');
941 }
942
943 if (type === 'EVERYDAY') handleEveryDayCard();
944 if (type === 'TRAVEL') handleTravelCard();
945
946 currentIframeIndex = 0;
947 currentPage = 0;
948 renderCarousel();
949 autoSelectFirstCard();
950 updateIframeCounter();
951
952}
953
954
955function handleConsumerSubCard() {
956 $("#re_card_consumer_business").hide();
957 $("#re_card_everyday,#re_card_travel,#plussymbol").removeClass("d-none");
958
959 $("#title2,#des2").removeClass("d-none");
960 $("#title1,#des1").addClass("d-none");
961 const cardContainer = document.querySelector('.re_card_sec');
962 cardContainer?.classList.add('consumer-active');
963 $("#resettext").removeClass("d-none");
964 document.querySelector('.re_cdn_logo')?.classList.add('consumer-logo');
965
966}
967function handleEveryDayCard() {
968 document.getElementById('re_card_travel')?.classList.remove('active');
969 $("#resettext").removeClass("d-none");
970 $("#title3,#des3").removeClass("d-none");
971 $("#title2,#des2,#des4").addClass("d-none");
972}
973function handleTravelCard() {
974 document.getElementById('re_card_everyday')?.classList.remove('active');
975 $("#resettext").removeClass("d-none");
976 $("#title3,#des4").removeClass("d-none");
977 $("#title2,#des2,#des3").addClass("d-none");
978}
979
980
981function applyInitialCardMixUI() {
982
983 const groupSet = new Set(cardsData.map(card => card.groupName));
984 $("#reCardSec").removeClass("d-none");
985 // First hide everything (safe – already hidden, no flicker)
986 $("#title1,#title2,#title3,#des1,#des2,#des3,#des4,#framesec,#resettext")
987 .addClass("d-none");
988
989 // BOTH Consumer + Business
990 if (groupSet.size > 1) {
991 $("#title1,#des1").removeClass("d-none");
992 }
993
994 // ONLY Consumer
995 else if (groupSet.has('CONSUMER')) {
996 activeCardType = 'CONSUMER';
997 activeCategory = 'ALL';
998 $("#title2,#des2").removeClass("d-none");
999 $("#re_card_everyday,#re_card_travel").removeClass("d-none");
1000 $("#re_card_cosumer,#re_card_consumer_business").addClass("d-none");
1001 }
1002
1003 // ONLY Business
1004 else if (groupSet.has('BUSINESS')) {
1005 $("#title1,#des1").removeClass("d-none");
1006 $("#reCardSec").addClass("d-none");
1007 }
1008}
1009
1010
1011
1012function resetUIToDefault() {
1013
1014 // Reset filter logic
1015 activeCardType = 'ALL';
1016 activeCategory = 'ALL';
1017
1018 // Reset card buttons
1019 document.querySelectorAll('.re_card').forEach(card => {
1020 card.classList.remove('active');
1021 card.classList.remove('disabled');
1022 });
1023
1024 // Restore card button visibility
1025 $("#re_card_consumer_business").show();
1026 $("#re_card_everyday,#re_card_travel,#plussymbol").addClass("d-none");
1027 document.querySelector('.re_card_sec')?.classList.remove('consumer-active');
1028 document.querySelector('.re_cdn_logo')?.classList.remove('consumer-logo');
1029
1030 document.querySelectorAll('.rcard')
1031 .forEach(card => card.classList.remove('is-focused'));
1032
1033
1034 currentIframeIndex = 0;
1035 // Apply data-based hiding (ONLY what is needed)
1036 applyInitialCardMixUI();
1037
1038 // Reset carousel state
1039 currentPage = 0;
1040
1041
1042 // Re-render
1043 renderCarousel();
1044 autoSelectFirstCard();
1045}
1046
1047
1048
1049/* =========================================================
1050 GLOBAL STATE
1051========================================================= */
1052const PAGE_SIZE = 3;
1053let activeCardType = 'ALL';
1054let activeCategory = 'ALL';
1055let currentPage = 0;
1056let isInitialLoad = true;
1057let currentIframeIndex = 0;
1058let allowAutoScroll = true;
1059const panoUrl = "${panoUrl}";
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069/* =========================================================
1070 FILTER + COUNT
1071========================================================= */
1072
1073function updateCardCount(count, type) {
1074 const el = document.getElementById('cardCount');
1075 if (!el) return;
1076
1077 let label = 'All Cards';
1078 if (type === 'CONSUMER') label = 'Consumer Cards';
1079 if (type === 'BUSINESS') label = 'Business Cards';
1080
1081 // reeMarker-safe
1082 el.textContent = `${r"${label}"} (${r"${count}"} Cards)`;
1083}
1084
1085
1086
1087function getFilteredCards() {
1088 return cardsData.filter(card => {
1089
1090 // Filter by Consumer / Business
1091 if (activeCardType !== 'ALL' && card.groupName !== activeCardType) {
1092 return false;
1093 }
1094
1095 // Category filter ONLY when Consumer is selected
1096 if (activeCardType === 'CONSUMER' && activeCategory !== 'ALL') {
1097 return card.category === activeCategory;
1098 }
1099
1100 // Business ignores category
1101 return true;
1102 });
1103}
1104
1105
1106/* =========================================================
1107 CAROUSEL RENDER
1108========================================================= */
1109function renderCarousel() {
1110 const container = document.getElementById('carouselInner');
1111 if (!container) return;
1112
1113 const filteredCards = getFilteredCards();
1114
1115
1116
1117 if (!filteredCards.length) {
1118 container.innerHTML = '<p style="padding:20px">No cards available</p>';
1119 updateCardCount(0, activeCardType);
1120 return;
1121 }
1122
1123
1124 updateCardCount(filteredCards.length, activeCardType);
1125
1126 const start = currentPage * PAGE_SIZE;
1127 const end = start + PAGE_SIZE;
1128 const pageCards = filteredCards.slice(start, end);
1129
1130 container.innerHTML = pageCards.map(card => `
1131 <div class="rcard"
1132 tabindex="0"
1133 data-offer-type="${r"${card.offerType}"}"
1134 onclick="showCalculator(
1135 panoUrl + '/calculators/${r"${card.offerType}"}',
1136 '${r"${card.title}"}'
1137 )">
1138
1139 <div class="cal-card">
1140 <div class="cal-card-image">
1141 <img src="${r"${card.imageUrl}"}" alt="Card Image">
1142 </div>
1143
1144 <div class="cal-card-body">
1145 <h3 class="cal-card-title">${r"${card.title}"}</h3>
1146 <div class="cal-divider"></div>
1147
1148 <div class="cal-card-details">
1149 <a class="cal-fee"
1150 href="${oadURL_TC}?step=display&offerId=${r"${card.offerId}"}&locationCode=${lc}"
1151 target="_blank"
1152 onclick="event.stopPropagation();">
1153 ${r"${card.wcChildText}"}
1154 </a>
1155 </div>
1156 </div>
1157 </div>
1158 </div>
1159 `).join('');
1160
1161
1162}
1163
1164/* =========================================================
1165 FILTER BUTTON HANDLER
1166========================================================= */
1167
1168
1169
1170
1171/* =========================================================
1172 CAROUSEL CORE
1173========================================================= */
1174function getCards() {
1175 return document.querySelectorAll('.rcard');
1176}
1177
1178
1179
1180
1181function showCalculator(url, title) {
1182 console.log("[CAL URL]",url);
1183 const filteredCards = getFilteredCards();
1184
1185 const index = filteredCards.findIndex(
1186 card => url.includes(card.offerType)
1187 );
1188
1189 if (index !== -1) {
1190 currentIframeIndex = index;
1191 highlightCard(filteredCards[index].offerType);
1192 }
1193
1194 const wrapper = document.getElementById('iframeWrapper');
1195 const titleEl = document.getElementById('frametitle');
1196
1197 if (titleEl) {
1198 titleEl.textContent = title + ' Rewards Calculator';
1199 }
1200
1201 wrapper.innerHTML = '';
1202
1203 const iframe = document.createElement('iframe');
1204 iframe.src = url;
1205 iframe.className = 'iframe-content';
1206 iframe.loading = 'lazy';
1207
1208 wrapper.appendChild(iframe);
1209
1210 $("#framesec,#iframeWrapper").removeClass("d-none");
1211
1212 // scroll only when allowed
1213 if (allowAutoScroll) {
1214 wrapper.scrollIntoView({ behavior: 'smooth' });
1215 }
1216
1217 updateIframeCounter();
1218}
1219
1220
1221function scrollToTop() {
1222 $('html, body').animate({ scrollTop: 0 }, 'slow');
1223}
1224
1225
1226function changeIframe(direction) {
1227 const filteredCards = getFilteredCards();
1228 const total = filteredCards.length;
1229 if (!total) return;
1230
1231 const nextIndex = currentIframeIndex + direction;
1232
1233 // stop at bounds
1234 if (nextIndex < 0 || nextIndex >= total) return;
1235
1236 currentIframeIndex = nextIndex;
1237
1238 // derive page from index
1239 const requiredPage = Math.floor(currentIframeIndex / PAGE_SIZE);
1240
1241 // switch page ONLY if needed
1242 if (requiredPage !== currentPage) {
1243 currentPage = requiredPage;
1244
1245 // prevent auto-select + scroll during re-render
1246 allowAutoScroll = false;
1247 renderCarousel();
1248 allowAutoScroll = true;
1249 }
1250
1251 const card = filteredCards[currentIframeIndex];
1252
1253 // highlight selected card
1254 highlightCard(card.offerType);
1255
1256 // load iframe (user action → scroll allowed)
1257 const url = panoUrl+'/calculators/' + card.offerType;
1258
1259 showCalculator(url, card.title);
1260
1261 updateIframeCounter();
1262}
1263
1264
1265
1266
1267
1268function updateIframeCounter() {
1269 const counterEl = document.getElementById('indicatorCount');
1270 const prevBtn = document.getElementById('iframePrev');
1271 const nextBtn = document.getElementById('iframeNext');
1272
1273 if (!counterEl || !prevBtn || !nextBtn) return;
1274
1275 const filteredCards = getFilteredCards();
1276 const total = filteredCards.length;
1277
1278 if (!total) {
1279 counterEl.textContent = '';
1280 prevBtn.disabled = true;
1281 nextBtn.disabled = true;
1282 return;
1283 }
1284
1285 // ARD-BASED COUNT (this is what you want)
1286 counterEl.textContent =
1287 (currentIframeIndex + 1) + ' of ' + total;
1288
1289 // isable arrows at first / last card
1290 prevBtn.disabled = currentIframeIndex === 0;
1291 nextBtn.disabled = currentIframeIndex === total - 1;
1292}
1293
1294
1295
1296function highlightCard(offerType) {
1297 document.querySelectorAll('.rcard').forEach(card => {
1298 if (card.dataset.offerType === offerType) {
1299 card.classList.add('is-focused');
1300 } else {
1301 card.classList.remove('is-focused');
1302 }
1303 });
1304}
1305
1306function autoSelectFirstCard() {
1307 const filteredCards = getFilteredCards();
1308 if (!filteredCards.length) return;
1309
1310 const firstCard = filteredCards[0];
1311
1312 currentIframeIndex = 0;
1313
1314 // disable scroll for auto select
1315 allowAutoScroll = false;
1316
1317 highlightCard(firstCard.offerType);
1318
1319 const url = panoUrl+'/calculators/' + firstCard.offerType;
1320
1321 showCalculator(url, firstCard.title);
1322
1323 // re-enable scroll for user actions
1324 allowAutoScroll = true;
1325}
1326
1327</script>