Hitesh Methani
About Us
Applications
Fehler bei der Verarbeitung der Vorlage.
The following has evaluated to null or missing:
==> publisherCatalogId  [in template "3192443#3192485#29283146" at line 202, column 182]

----
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 requestUrl = "/headless-comme...  [in template "3192443#3192485#29283146" at line 202, column 1]
----
1<style type="text/css"> 
2.product-card { 
3	border: solid 1px #E2E2E4; 
4	border-radius: 10px; 
5	box-sizing: border-box; 
6	max-height:340px; 
7	max-width: 430px; 
8	min-width: 430px; 
9	position: relative; 
10	transition: all 0.3s cubic-bezier(.25,.8,.25,1); 
11	cursor:point; 
12
13.product-card:hover{	border: solid 1px #89a7e0!important;} 
14 
15.product-card-paragraph { 
16	-webkit-box-orient: vertical; 
17	-webkit-line-clamp: 3; 
18	display: -webkit-box; 
19	font-size: 14px; 
20	font-size: 14px; 
21	font-weight: 400; 
22	height: 60px; 
23	letter-spacing: 0%; 
24	line-height: 20px; 
25	overflow: hidden; 
26	text-overflow: ellipsis; 
27	width: 340px; 
28
29 
30.product-tag { 
31	background-color: #E6EBF5; 
32	box-sizing: border-box; 
33	color: #2E5AAC; 
34	font-family: Source Sans 3; 
35	font-size: 13px; 
36	font-weight: 400; 
37	letter-spacing: 0%; 
38	line-height: 16px; 
39	max-height: 24px; 
40	transition: all 0.3s cubic-bezier(.25, .8, .25, 1); 
41	vertical-align: middle; 
42
43	.image-container .app-search-image { 
44		object-fit: contain; 
45	width:56px; 
46		height:56px; 
47
48	.app-search-image{ 
49		width:56px; 
50		height:56px; 
51		fit-content:contain; 
52	  -webkit-user-drag: none; 
53  user-drag: none; 
54
55 
56.price { 
57	font-family: Source Sans 3; 
58	font-size: 16px; 
59	font-weight: 600; 
60	letter-spacing: 0%; 
61	line-height: 24px; 
62	vertical-align: middle; 
63
64 
65.apps-container { 
66	padding: 5px; 
67	gap: 24px; 
68 
69
70 
71.tags-container { 
72	gap: 8px; 
73
74 
75.app-type-badge { 
76	border-bottom-left-radius: 10px; 
77	border-bottom-right-radius: 10px; 
78	border-top-left-radius: 2px; 
79	border-top-right-radius: 2px; 
80	display: inline-block; 
81	height: 20; 
82	padding-left: 10px; 
83	padding-right: 10px; 
84	position: absolute; 
85	right: 32px; 
86	top: -6px; 
87	width: 80; 
88
89 
90.object-action { 
91	background-color: #D1ECFA; 
92	color: #166E9E; 
93
94	 
95	.no-type { 
96	background: #cccccc; 
97	color: #ffffff; 
98  transition: all 0.3s cubic-bezier(.25,.8,.25,1) 
99
100	 
101.theme { 
102	background: #FBE0FF; 
103	color: #720086; 
104  transition: all 0.3s cubic-bezier(.25,.8,.25,1) 
105
106	 
107.site-initializer {	 
108	background: #D1EEDC; 
109	color: #0E7835; 
110  transition: all 0.3s cubic-bezier(.25,.8,.25,1) 
111
112	 
113.payment-methods { 
114	background: #D2E6FF; 
115	color: #2868FF; 
116  transition: all 0.3s cubic-bezier(.25,.8,.25,1) 
117
118	 
119.batch { 
120	background: #FFE6C6; 
121	color:  #9D4C00; 
122  transition: all 0.3s cubic-bezier(.25,.8,.25,1) 
123
124	.fragments { 
125	background: #DCD7E9; 
126	color: #503690; 
127  transition: all 0.3s cubic-bezier(.25,.8,.25,1) 
128
129	 
130.workflow-action { 
131	background: #DCD7E9; 
132	color: #503690; 
133  transition: all 0.3s cubic-bezier(.25,.8,.25,1) 
134
135 
136.checkout { 
137	background: #DAF4C7; 
138	color: 	#4E7135; 
139  transition: all 0.3s cubic-bezier(.25,.8,.25,1) 
140}	 
141	.other { 
142	background: #DAF4C7; 
143	color: 	#4E7135; 
144  transition: all 0.3s cubic-bezier(.25,.8,.25,1) 
145
146 
147.pagination-bar { 
148    align-items: center; 
149    display: flex; 
150    justify-content: space-between; 
151    margin-top: 2rem; 
152    width: 100%; 
153
154.pagination-items-per-page .dropdown-toggle, .pagination-results { 
155    color: #6b6c7e; 
156
157</style> 
158 
159<#-- Bloco de inicialização de variáveis --> 
160<#assign commerceContext=renderRequest.getAttribute("COMMERCE_CONTEXT") /> 
161<#assign url=themeDisplay.getURLCurrent()?string> 
162<#assign basePageURL = url?keep_before("?")> 
163<#assign queryString = ""> 
164<#assign idx = url?index_of("?")> 
165<#if idx != -1> 
166  <#assign queryString = url?substring(idx + 1)> 
167</#if> 
168 
169<#-- Valores padrão para paginação --> 
170<#assign delta = 8> 
171<#assign start = 1> 
172	 
173<#-- Leitura dos parâmetros da URL --> 
174<#if queryString?has_content> 
175  <#assign params = queryString?split("&")> 
176  <#list params as param> 
177    <#assign keyValue = param?split("=")> 
178    <#if keyValue?size == 2> 
179      <#if keyValue[0] == "delta"> 
180        <#assign delta = keyValue[1]?number> 
181      </#if> 
182      <#if keyValue[0] == "start"> 
183        <#assign start = keyValue[1]?number> 
184      </#if> 
185    </#if> 
186  </#list> 
187</#if> 
188				 
189<#assign baseURL="https://marketplace.liferay.com" /> 
190			 
191				 
192<#assign channelId=commerceContext.getCommerceChannelId() /> 
193<#assign urlParts=url?split("/")> 
194<#assign lastSegment=urlParts[urlParts?size - 1]?split(" \\?")[0]> 
195<#assign publisherDetails=restClient.get("/c/publisherdetailses/" + lastSegment ) /> 
196	 
197<#if publisherDetails.catalogId?has_content> 
198	<#assign publisherCatalogId=publisherDetails.catalogId /> 
199</#if> 
200 
201<#-- Construção da URL da API com os parâmetros de paginação --> 
202<#assign requestUrl = "/headless-commerce-delivery-catalog/v1.0/channels/" + channelId + "/products?accountId=-1&nestedFields=categories,productSpecifications&filter=catalogId eq "+publisherCatalogId> 
203<#assign requestUrl = requestUrl + "&pageSize=" + delta> 
204<#assign requestUrl = requestUrl + "&page=" + start> 
205 
206<#assign catalogApps=restClient.get(requestUrl) /> 
207 
208<#-- Verificação principal: só renderiza se houver conteúdo --> 
209<#if catalogApps?has_content && catalogApps.items?has_content> 
210	<#assign products = catalogApps.items /> 
211 
212	<div class="d-flex flex-wrap apps-container flex-row mb-5" > 
213		<#list products as productEntry> 
214			<#if productEntry?has_content> 
215 
216				<#assign 
217					accountEntryId=commerceContext.getAccountEntry().getAccountEntryId() 
218					portalURL=portalUtil.getLayoutURL(themeDisplay) 
219					productId=productEntry.id 
220					productName=productEntry.name 
221					remainingCategoriesText=[] 
222					productImage=cpContentHelper.getDefaultImageFileURL(accountEntryId, productEntry.id) 
223					catalogName=productEntry.catalogName  
224					appFriendlyURLName=productEntry.slug 
225				/> 
226					<#if productEntry.categories?has_content> 
227						<#assign 
228							productCategories=productEntry.categories?filter(productCategory -> productCategory.vocabulary?replace(" ", "-") == "marketplace-app-category")![] 
229							categoriesListSize = productCategories?size-1 
230							productTypes=productEntry.categories?filter(productCategory -> productCategory.vocabulary?replace(" ", "-") == "marketplace-category")![] 
231						/> 
232							 
233					</#if> 
234						<#if productTypes[0]?has_content> 
235							<#assign productType=productTypes[0]/> 
236						<#else> 
237							<#assign productType=""/> 
238						</#if> 
239				 
240						<#if productEntry.productSpecifications?has_content> 
241							<#assign productSpecifications=productEntry.productSpecifications![] /> 
242						</#if> 
243						<#if productEntry.description?has_content> 
244							<#assign productDescription=stringUtil.shorten(htmlUtil.stripHtml(productEntry.description!""), 150, "..." ) /> 
245						<#else> 
246							<#assign productDescription="" /> 
247						</#if> 
248						<a class="product-card p-5 bg-white border-radius-medium d-flex flex-column mb-0 text-dark text-decoration-none" href="${baseURL}/p/${appFriendlyURLName}"> 
249							<div class="align-items-center card-image-title-container d-flex"> 
250								<div class="image-container mr-2 rounded"> 
251									<img alt="${productName}" class="app-search-image" src="${productImage}" width="56" height="56" /> 
252								</div> 
253								<div> 
254									<span class="d-flex justify-content-end"> 
255										<div> 
256										<#if productType?has_content > 
257 
258											<#if productType.name == 'Other'>	 
259												<div class="app-type-badge"></div> 
260												<#else> 
261														<div class="app-type-badge no-type font-weight-bold 
262												<#if productType.name == 'Theme'> theme</#if> 
263												<#if productType.name == 'Object action'> object-action</#if> 
264												<#if productType.name == 'Site Initializer'> site-initializer</#if> 
265												<#if productType.name == 'Payment methods'> payment-methods</#if> 
266												<#if productType.name == 'Workflow action'>	workflow-action</#if> 
267												<#if productType.name == 'Batch'>	batch</#if> 
268												<#if productType.name == 'Checkout'>	checkout</#if> 
269												<#if productType.name == 'Fragments'>	fragments</#if>				 
270											"> 
271												${productType.name} 
272											</div> 
273											</#if> 
274										 
275											</#if> 
276											 
277										</div> 
278									</span> 
279									<div class="font-weight-bold"> 
280										${productName} 
281									</div> 
282							 
283									<#if productSpecifications?has_content> 
284										<#assign productDeveloperName=productSpecifications?filter(item -> item.specificationKey == "developer-name") /> 
285										<#list productDeveloperName as developerNameItem> 
286											<#if developerNameItem.value?has_content> 
287												<#assign developerName=developerNameItem.value /> 
288											<#else> 
289												<#assign developerName="" /> 
290											</#if> 
291											<div class="mt-1 text-black-50"> 
292												${developerName} 
293											</div> 
294										</#list> 
295									</#if> 
296								</div> 
297							</div> 
298							<div class="d-flex flex-column font-size-paragraph-small h-100 justify-content-between"> 
299								<div class="font-weight-normal my-6 text-break"> 
300									${productDescription} 
301								</div> 
302								<div class="d-flex flex-column"> 
303									<#if productSpecifications?has_content> 
304										<#assign productPriceModels=productSpecifications?filter(item -> item.specificationKey == "price-model") /> 
305										<#list productPriceModels as productPriceModel> 
306											<#if productPriceModel.value?has_content> 
307												<#assign priceModel=productPriceModel.value /> 
308											<#else> 
309												<#assign priceModel="" /> 
310											</#if> 
311											<div class="font-weight-semi-bold my-4 text-capitalize"> 
312												${priceModel} 
313											</div> 
314										</#list> 
315									</#if> 
316									<#if productCategories?has_content> 
317										<#assign 
318											principalCategory=productCategories[0] 
319											remainingCategories=productCategories?filter(category -> category.name != principalCategory.name) 
320										/> 
321										<#list remainingCategories as category> 
322											<#assign remainingCategoriesText=remainingCategoriesText + [category.name] /> 
323										</#list> 
324									</#if> 
325									<#if principalCategory?has_content> 
326										<div> 
327											<span class="product-tag px-2 py-1 rounded mr-3" title="${principalCategory.name}"> 
328												${principalCategory.name} 
329											</span> 
330											<#if categoriesListSize?has_content && remainingCategoriesText?has_content> 
331												<span class="product-tag px-2 py-1 rounded" title="${remainingCategoriesText?join('\n')}"> 
332													+ ${categoriesListSize} 
333												</span> 
334											</#if> 
335										</div> 
336									</#if> 
337								</div> 
338							</div> 
339						</a> 
340					</#if> 
341				</#list> 
342	</div> 
343 
344	<#-- Pagination --> 
345 
346	<#assign currentPage = catalogApps.page /> 
347	<#assign pageSize = catalogApps.pageSize /> 
348	<#assign totalCount = catalogApps.totalCount /> 
349	<#assign totalPages = (totalCount / pageSize)?ceiling /> 
350	 
351	 
352 
353		<div class="pagination-bar"> 
354			<div class="dropdown pagination-items-per-page"> 
355				<a aria-expanded="false" aria-haspopup="true" class="dropdown-toggle" data-toggle="dropdown" href="javascript:;" role="button"> 
356					${pageSize} entries 
357					<@clay["icon"] symbol="caret-bottom" /> 
358				</a> 
359				<ul class="dropdown-menu dropdown-menu-top"> 
360					<#list [8, 16, 24, 48] as deltaOption> 
361						<li><a class="dropdown-item" href="${basePageURL}?delta=${deltaOption}&start=1">${deltaOption}</a></li> 
362					</#list> 
363				</ul> 
364			</div> 
365			 
366			 
367			<#assign startItem = (currentPage - 1) * pageSize + 1 /> 
368		 
369			<#assign endItem = [(currentPage * pageSize), totalCount]?min /> 
370			<div class="pagination-results">Showing ${startItem} to ${endItem} of ${totalCount} entries.</div> 
371 
372			<ul class="pagination"> 
373			 
374				<li class="page-item<#if currentPage == 1> disabled</#if>"> 
375					<a class="page-link" href="<#if currentPage gt 1>${basePageURL}?delta=${pageSize}&start=${currentPage - 1}<#else>javascript:;</#if>" role="button"> 
376						<@clay["icon"] symbol="angle-left" /> 
377						<span class="sr-only">Back</span> 
378					</a> 
379				</li> 
380				 
381				 
382				<#assign ellipsisPrinted = false /> 
383				<#list 1..totalPages as pageNumber> 
384					<#assign showPage = false /> 
385					 
386					<#if (pageNumber == 1) ||  
387						 (pageNumber == totalPages) ||  
388						 (pageNumber >= currentPage - 2 && pageNumber <= currentPage + 2)> 
389						<#assign showPage = true /> 
390					</#if> 
391					 
392					<#if showPage> 
393						<li class="page-item<#if pageNumber == currentPage> active</#if>"> 
394							<a class="page-link" href="${basePageURL}?delta=${pageSize}&start=${pageNumber}">${pageNumber}</a> 
395						</li> 
396						<#assign ellipsisPrinted = false /> 
397					<#else> 
398						<#if !ellipsisPrinted> 
399							<li class="page-item disabled"> 
400								<a class="page-link" href="javascript:;" tabindex="-1">...</a> 
401							</li> 
402							<#assign ellipsisPrinted = true /> 
403						</#if> 
404					</#if> 
405				</#list> 
406				 
407		 
408				<li class="page-item<#if currentPage == totalPages> disabled</#if>"> 
409					<a class="page-link" href="<#if currentPage lt totalPages>${basePageURL}?delta=${pageSize}&start=${currentPage + 1}<#else>javascript:;</#if>" role="button"> 
410						<@clay["icon"] symbol="angle-right" /> 
411						<span class="sr-only">Next</span> 
412					</a> 
413				</li> 
414			</ul> 
415		</div> 
416 
417 
418 
419<#else> 
420	<div class="alert alert-info">No apps found for this publisher.</div> 
421</#if> 
422				 
423	 
424<script> 
425document.addEventListener("DOMContentLoaded", function () { 
426    const paginationBar = document.querySelector('.pagination-bar'); 
427 
428    if (!paginationBar) { 
429        return; 
430
431 
432    function closePaginationDropdown() { 
433        const openMenu = paginationBar.querySelector('.dropdown-menu.show'); 
434         
435        if (openMenu) { 
436            openMenu.classList.remove('show'); 
437             
438            const dropdown = openMenu.closest('.dropdown'); 
439            if (dropdown) { 
440                const toggle = dropdown.querySelector('.dropdown-toggle'); 
441                if (toggle) { 
442                    toggle.setAttribute('aria-expanded', 'false'); 
443
444
445
446
447 
448    document.addEventListener('click', function (event) { 
449         
450        const toggle = event.target.closest('.pagination-items-per-page .dropdown-toggle'); 
451 
452        if (toggle) { 
453            event.preventDefault(); 
454 
455            const menu = toggle.closest('.dropdown').querySelector('.dropdown-menu'); 
456             
457            if (menu) { 
458                const isCurrentlyShown = menu.classList.contains('show'); 
459 
460                closePaginationDropdown(); 
461 
462                if (!isCurrentlyShown) { 
463                    menu.classList.add('show'); 
464                    toggle.setAttribute('aria-expanded', 'true'); 
465
466
467            return;  
468
469 
470        if (!event.target.closest('.pagination-items-per-page')) { 
471            closePaginationDropdown(); 
472
473    }); 
474}); 
475</script>