templates/bundles/BoldrShopBundle/shop.html.twig line 163

Open in your IDE?
  1. {% set assets = assets|default(boldr_cms_get_assets()) %}
  2. {% do assets.addJsFile(asset('assets/js/shop.js')) %}
  3. {% set cart = boldr_shop_get_cart() %}
  4. {% set isShop = true %}
  5. {% extends 'base.html.twig' %}
  6. {% block head %}
  7. {{ parent() }}
  8. <script>
  9. let currentCurrency = {{ boldr_shop_get_currency()|json_encode|raw }};
  10. const ALLERGEN_IMAGE_URL = '{{ asset('/assets/images/allergens/' ~ app.request.locale ~ '/ALLERGEN.png') }}';
  11. </script>
  12. {% endblock %}
  13. {% block header_wrapper_content %}
  14. {{ parent() }}
  15. <div class="subheader-filter-search">
  16. <div class="subheader-filter-search-controls">
  17. <div class="subheader-filter">
  18. {# Filter op #}
  19. <a href="#" class="subheader-filter-button boldr-button boldr-button-outline-light">
  20. <i class="icon-filter"></i>
  21. <span class="boldr-button-text">{{ 'filter_by'|trans({}, 'HelensBakery') }}</span>
  22. <i class="icon-chevron-down"></i>
  23. <span class="subheader-filter-button-count"></span>
  24. </a>
  25. <div class="subheader-filter-dropdown hide-past-scroll">
  26. <div class="form-label-control">
  27. <input id="subheader-filter-choice-beef" type="checkbox" data-property="beef" />
  28. <label for="subheader-filter-choice-beef"><i class="icon-rundvlees"></i> {{ '100percent_beef'|trans({}, 'HelensBakery') }}</label>
  29. </div>
  30. <div class="form-label-control">
  31. <input id="subheader-filter-choice-vegan" type="checkbox" data-property="vegan" />
  32. <label for="subheader-filter-choice-vegan"><i class="icon-vegan"></i> {{ 'vegan'|trans({}, 'HelensBakery') }}</label>
  33. </div>
  34. <div class="form-label-control">
  35. <input id="subheader-filter-choice-vegetarian" type="checkbox" data-property="vegetarian" />
  36. <label for="subheader-filter-choice-vegetarian"><i class="icon-vegetarian"></i> {{ 'vegetarian'|trans({}, 'HelensBakery') }}</label>
  37. </div>
  38. {# <div class="form-label-control">
  39. <input id="subheader-filter-choice-fish" type="checkbox" data-property="fish" />
  40. <label for="subheader-filter-choice-fish"><i class="icon-vis"></i> Vis</label>
  41. </div> #}
  42. <div class="form-label-control">
  43. <input id="subheader-filter-choice-homemade" type="checkbox" data-property="homemade" />
  44. <label for="subheader-filter-choice-homemade"><i class="icon-homemade"></i></label>
  45. </div>
  46. </div>
  47. </div>
  48. {# Zoeken #}
  49. <input type="search" class="subheader-search-input" placeholder="{{ 'search'|trans({}, 'HelensBakery') }}" />
  50. </div>
  51. {#
  52. <div class="subheader-shop-switcher">
  53. <a href="#" class="subheader-shop-switcher-button boldr-button boldr-button-outline-light">
  54. <span class="boldr-button-text">Locatie: {{ cart.shop.name }}</span>
  55. <i class="icon-chevron-down"></i>
  56. </a>
  57. <div class="subheader-shop-switcher-dropdown">
  58. {% for shop in boldr_multishop_get_shops() %}
  59. <a data-id="{{ shop.id }}">{{ shop.name }}</a>
  60. {% endfor %}
  61. </div>
  62. </div>
  63. #}
  64. </div>
  65. <div class="subheader-categories">
  66. {# Categories #}
  67. {% for category in categories %}
  68. {% set categoryCatalogProducts = catalogProducts|filter(catalogProduct => category in catalogProduct.product.categories) %}
  69. {% if categoryCatalogProducts|length > 0 %}
  70. <a href="#" data-id="{{ category.id }}">
  71. {{ category.name }}
  72. </a>
  73. {% endif %}
  74. {% endfor %}
  75. </div>
  76. {% endblock %}
  77. {% block overlays %}
  78. <div class="overlay" id="overlay-add-product">
  79. <a href="#" class="overlay-close">
  80. <i class="icon-plus"></i>
  81. </a>
  82. <div class="overlay-content overlay-add-product">
  83. {% if not cart.canItemsBeModified %}
  84. <div style="padding: 20px">
  85. <p>
  86. {{ 'cant_add_while_paying'|trans({}, 'HelensBakery') }}
  87. </p>
  88. <div class="order-window-cart-next-states">
  89. {% for nextState in cart.nextStates %}
  90. <a href="{{ nextState.url }}" class="order-window-cart-next-state boldr-button boldr-button-highlight">
  91. {{ nextState.buttonText }}
  92. </a>
  93. {% endfor %}
  94. </div>
  95. </div>
  96. {% endif %}
  97. <div class="overlay-add-product-content" {{ not cart.canItemsBeModified ? 'style="display: none"' }}>
  98. <div class="overlay-add-product-info">
  99. <div class="overlay-add-product-info-header">
  100. <a class="overlay-add-product-info-header-close-mobile">
  101. <i class="icon-arrow-left"></i>
  102. </a>
  103. {# Heading image #}
  104. <img class="overlay-add-product-info-header-image" />
  105. <div class="overlay-add-product-info-header-allergens">
  106. <div class="overlay-add-product-info-header-allergens-title">{{ 'allergen_information'|trans({}, 'HelensBakery') }}:</div>
  107. <div class="overlay-add-product-info-header-allergens-list">
  108. {% for allergen in ['celery', 'egg', 'fish', 'gluten', 'lupine', 'milk', 'mollusks', 'mustard', 'nuts', 'peanut', 'sesame', 'shellfish', 'soy', 'sulfites'] %}
  109. <img src="{{ asset('/assets/images/allergens/' ~ app.request.locale ~ '/' ~ allergen ~ '.png') }}" class="overlay-add-product-info-header-allergen" data-name="{{ allergen }}">
  110. {% endfor %}
  111. </div>
  112. </div>
  113. </div>
  114. <div class="overlay-add-product-info-content">
  115. {# Product details #}
  116. <span class="overlay-add-product-info-name"></span>
  117. <span class="overlay-add-product-info-details"></span>
  118. {# Options #}
  119. <div class="overlay-add-product-info-options"></div>
  120. </div>
  121. </div>
  122. <div class="overlay-add-product-extra">
  123. <span class="overlay-add-product-extra-heading">{{ 'shop.add_extras'|trans }}</span>
  124. {% for category in categories|filter(category => category.hbVisibleInExtras) %}
  125. {% set categoryCatalogProducts = catalogProducts|filter(catalogProduct => category in catalogProduct.product.categories) %}
  126. {% if categoryCatalogProducts|length > 0 %}
  127. <div class="overlay-add-product-extra-category">
  128. <span class="overlay-add-product-extra-category-selection-count">
  129. 0
  130. </span>
  131. <div class="overlay-add-product-extra-category-heading">
  132. <span class="overlay-add-product-extra-category-name">
  133. {{ category.name }}
  134. </span>
  135. <a href="#" class="overlay-add-product-extra-category-toggle">
  136. <i class="icon-plus"></i>
  137. <i class="icon-minus"></i>
  138. </a>
  139. </div>
  140. <div class="overlay-add-product-extra-category-products-wrapper">
  141. <div class="overlay-add-product-extra-category-products">
  142. {% for catalogProduct in categoryCatalogProducts|sort((a, b) => a.product.name <=> b.product.name) %}
  143. <div class="overlay-add-product-extra-product" data-product-variant-id="{{ catalogProduct.variants[0].productVariant.id }}"
  144. data-product-id="{{ catalogProduct.product.id }}"
  145. data-price="{{ catalogProduct.variants[0].totalPrice }}">
  146. <div class="overlay-add-product-extra-product-info">
  147. <span class="overlay-add-product-extra-product-name">
  148. {{ catalogProduct.product.name }}
  149. </span>
  150. <span class="overlay-add-product-extra-product-price">
  151. + {{ boldr_shop_format_currency(catalogProduct.variants[0].totalPrice, catalogProduct.variants[0].currency.isoCode) }}
  152. </span>
  153. </div>
  154. <div class="overlay-add-product-extra-product-image-and-controls">
  155. {% if catalogProduct.product.primaryImage is not null %}
  156. <img src="{{ catalogProduct.product.primaryImage.attachment.Sizes.small }}" class="overlay-add-product-extra-product-image" />
  157. {% endif %}
  158. <div class="overlay-add-product-extra-product-controls">
  159. <a href="#" class="overlay-add-product-extra-product-minus">
  160. <i class="icon-minus"></i>
  161. </a>
  162. <span class="overlay-add-product-extra-product-quantity">0</span>
  163. <a href="#" class="overlay-add-product-extra-product-plus">
  164. <i class="icon-plus"></i>
  165. </a>
  166. </div>
  167. </div>
  168. </div>
  169. {% endfor %}
  170. <div class="overlay-add-product-extra-product-spacer"></div>
  171. <div class="overlay-add-product-extra-product-spacer"></div>
  172. <div class="overlay-add-product-extra-product-spacer"></div>
  173. </div>
  174. </div>
  175. </div>
  176. {% endif %}
  177. {% endfor %}
  178. </div>
  179. </div>
  180. <div class="overlay-add-product-add" {{ not cart.canItemsBeModified ? 'style="display: none"' }}>
  181. <div class="overlay-add-product-add-prices">
  182. <span class="overlay-add-product-add-price">
  183. &euro;3.20
  184. </span>
  185. <span class="overlay-add-product-add-additional-price">
  186. </span>
  187. </div>
  188. <a href="#" class="boldr-button boldr-button-medium boldr-button-highlight overlay-add-product-add-button">
  189. <span class="text-mobile">{{ 'add'|trans({}, 'HelensBakery') }}</span>
  190. <span class="text-desktop">{{ 'add_to_cart'|trans({}, 'HelensBakery') }}</span>
  191. </a>
  192. </div>
  193. </div>
  194. </div>
  195. {% endblock %}
  196. {% block body %}
  197. {# Products #}
  198. <div class="order-window {{ cart.items|length > 0 ? 'order-window-cart-visible' }}">
  199. <div class="product-list-wrapper">
  200. <div class="product-list">
  201. {% for category in categories %}
  202. {% set categoryCatalogProducts = catalogProducts|filter(catalogProduct => category in catalogProduct.product.categories) %}
  203. {% if categoryCatalogProducts|length > 0 %}
  204. <div class="product-list-category" data-id="{{ category.id }}" data-show-extras="{{ category.hbShowExtras ? 'true' : 'false' }}">
  205. <div class="product-list-category-header">
  206. {{ category.name }}
  207. </div>
  208. <div class="product-list-category-products">
  209. {% for catalogProduct in categoryCatalogProducts|sort((a, b) => a.product.name|split('.')[0] <=> b.product.name|split('.')[0]) %}
  210. {% set variant = catalogProduct.variants[0] %}
  211. <div class="product-list-product" data-product-variant-id="{{ variant.productVariant.id }}"
  212. data-price="{{ variant.totalPrice }}"
  213. data-new="{{ catalogProduct.product.new ? 'true' : 'false' }}"
  214. data-homemade="{{ catalogProduct.product.homemade ? 'true' : 'false' }}"
  215. data-vegan="{{ catalogProduct.product.vegan ? 'true' : 'false' }}"
  216. data-vegetarian="{{ catalogProduct.product.vegetarian ? 'true' : 'false' }}"
  217. data-fish="{{ catalogProduct.product.fish ? 'true' : 'false' }}"
  218. data-beef="{{ catalogProduct.product.beef ? 'true' : 'false' }}"
  219. data-image-large="{{ catalogProduct.product.primaryImage is not null ? catalogProduct.product.primaryImage.attachment.sizes.large }}"
  220. data-allergen-gluten="{{ variant.productVariant.allergens.gluten ? 'true' : 'false' }}"
  221. data-allergen-egg="{{ variant.productVariant.allergens.egg ? 'true' : 'false' }}"
  222. data-allergen-fish="{{ variant.productVariant.allergens.fish ? 'true' : 'false' }}"
  223. data-allergen-peanut="{{ variant.productVariant.allergens.peanut ? 'true' : 'false' }}"
  224. data-allergen-nuts="{{ variant.productVariant.allergens.nuts ? 'true' : 'false' }}"
  225. data-allergen-soy="{{ variant.productVariant.allergens.soy ? 'true' : 'false' }}"
  226. data-allergen-milk="{{ variant.productVariant.allergens.milk ? 'true' : 'false' }}"
  227. data-allergen-shellfish="{{ variant.productVariant.allergens.shellfish ? 'true' : 'false' }}"
  228. data-allergen-mollusks="{{ variant.productVariant.allergens.mollusks ? 'true' : 'false' }}"
  229. data-allergen-celery="{{ variant.productVariant.allergens.celery ? 'true' : 'false' }}"
  230. data-allergen-mustard="{{ variant.productVariant.allergens.mustard ? 'true' : 'false' }}"
  231. data-allergen-sesame="{{ variant.productVariant.allergens.sesame ? 'true' : 'false' }}"
  232. data-allergen-sulfites="{{ variant.productVariant.allergens.sulfites ? 'true' : 'false' }}"
  233. data-allergen-lupine="{{ variant.productVariant.allergens.lupine ? 'true' : 'false' }}"
  234. >
  235. {% if catalogProduct.product.primaryImage %}
  236. <div class="product-list-product-header">
  237. <img src="{{ catalogProduct.product.primaryImage.attachment.sizes.medium }}" style="object-fit: {{ catalogProduct.product.primaryImage.cover ? 'cover' : 'contain' }}; object-position: {{ catalogProduct.product.primaryImage.positionX ~ ' ' ~ catalogProduct.product.primaryImage.positionY }}" class="product-list-product-image" />
  238. {% if catalogProduct.product.new %}
  239. <span class="badge-new">{{ 'new'|trans({}, 'HelensBakery') }}</span>
  240. {% endif %}
  241. <div class="product-list-product-variants">
  242. {% if catalogProduct.product.homemade %}
  243. <i class="icon-homemade" title="Homemade"></i>
  244. {% endif %}
  245. {% if catalogProduct.product.vegan %}
  246. <i class="icon-vegan" title="{{ 'vegan'|trans({}, 'HelensBakery') }}"></i>
  247. {% endif %}
  248. {% if catalogProduct.product.vegetarian %}
  249. <i class="icon-vegetarian" title="{{ 'vegetarian'|trans({}, 'HelensBakery') }}"></i>
  250. {% endif %}
  251. {% if catalogProduct.product.fish %}
  252. <i class="icon-vis" title="Vis"></i>
  253. {% endif %}
  254. {% if catalogProduct.product.beef %}
  255. <i class="icon-rundvlees" title="{{ '100percent_beef'|trans({}, 'HelensBakery') }}"></i>
  256. {% endif %}
  257. </div>
  258. </div>
  259. {% endif %}
  260. <div class="product-list-product-info">
  261. <span class="product-list-product-name">
  262. {{ catalogProduct.product.name }}
  263. {% if not variant.inStock %}
  264. {{ 'sold_out'|trans({}, 'HelensBakery') }}
  265. {% endif %}
  266. </span>
  267. <span class="product-list-product-details">
  268. {{ catalogProduct.product.description|default(catalogProduct.product.ingredients|map(ingredient => ingredient.name)|join(', '))|striptags|raw }}
  269. </span>
  270. <span class="product-list-product-price">
  271. {{ boldr_shop_format_currency(variant.totalPrice, variant.currency.isoCode) }}
  272. </span>
  273. </div>
  274. <a class="product-list-product-add" href="#">
  275. <i class="icon-plus"></i>
  276. </a>
  277. </div>
  278. {% endfor %}
  279. <div class="product-list-product-spacer"></div>
  280. <div class="product-list-product-spacer"></div>
  281. <div class="product-list-product-spacer"></div>
  282. </div>
  283. </div>
  284. {% endif %}
  285. {% endfor %}
  286. <div class="product-list-refine-search">
  287. <span>{{ 'search_no_products'|trans({}, 'HelensBakery') }}</span>
  288. <a href="#" class="product-list-refine-search-clear boldr-button boldr-button-filled">{{ 'show_all_products'|trans({}, 'HelensBakery') }}</a>
  289. </div>
  290. </div>
  291. </div>
  292. <div class="order-window-cart-wrapper">
  293. <div class="order-window-cart">
  294. <div class="order-window-cart-body">
  295. <div class="order-window-cart-title">
  296. <span>{{ 'my_order'|trans({}, 'HelensBakery') }}</span>
  297. <i class="order-window-cart-title-close icon-chevron-down"></i>
  298. </div>
  299. <div class="order-window-cart-products">
  300. <div class="order-window-cart-mobile-empty">
  301. <span class="order-window-cart-mobile-empty-text">{{ 'no_products_in_cart'|trans({}, 'HelensBakery') }}</span>
  302. <a id="order-window-cart-mobile-empty-close" class="boldr-button boldr-button-filled">
  303. {{ 'add_product'|trans({}, 'HelensBakery') }}
  304. </a>
  305. </div>
  306. {% for orderItem in cart.items %}
  307. <div class="order-window-cart-product" data-order-item-id="{{ orderItem.id }}" data-quantity="{{ orderItem.quantity }}">
  308. <span class="order-window-cart-product-quantity">{{ orderItem.quantity }}x</span>
  309. <div class="order-window-cart-product-info">
  310. <div class="order-window-cart-product-name-price">
  311. <span class="order-window-cart-product-name">{{ orderItem.productVariant.name }}</span>
  312. <span class="order-window-cart-product-price">
  313. {{ boldr_shop_format_currency(orderItem.price.totalPriceExcludingModifiers, cart.currency.isoCode) }}
  314. </span>
  315. </div>
  316. <div class="order-window-cart-product-modifiers">
  317. {% for modifier in orderItem.price.modifiers %}
  318. <div class="order-window-cart-product-modifier">
  319. <span class="order-window-cart-product-modifier-name">
  320. {{ modifier.quantity > 1 ? modifier.quantity ~ 'x' }} {{ modifier.name }}
  321. </span>
  322. <span class="order-window-cart-product-modifier-amount">
  323. {{ modifier.amount < 0 ? '-' : '+' }} {{ boldr_shop_format_currency(modifier.amount|abs, cart.currency.isoCode) }}
  324. </span>
  325. </div>
  326. {% endfor %}
  327. </div>
  328. <div class="order-window-cart-product-option-values">
  329. {% for optionValue in orderItem.optionValues %}
  330. <div class="order-window-cart-product-option-value">
  331. {% if optionValue.name %}
  332. {{ optionValue.name }}:
  333. {% endif %}
  334. {{ optionValue.text }}
  335. </div>
  336. {% endfor %}
  337. </div>
  338. {% set allergens = ['celery', 'egg', 'fish', 'gluten', 'lupine', 'milk', 'mollusks', 'mustard', 'nuts', 'peanut', 'sesame', 'shellfish', 'soy', 'sulfites'] %}
  339. {% set hasAllergens = allergens|reduce((c, v) => c or attribute(orderItem.productVariant.allergens, v), false) %}
  340. {% if hasAllergens %}
  341. <div class="order-window-cart-product-allergens">
  342. <span class="order-window-cart-product-allergens-label">{{ 'allergen_information'|trans({}, 'HelensBakery') }}:</span>
  343. {% for allergen in allergens %}
  344. {% if attribute(orderItem.productVariant.allergens, allergen) %}
  345. <img src="{{ asset('/assets/images/allergens/' ~ app.request.locale ~ '/' ~ allergen ~ '.png') }}" class="order-window-cart-product-allergen" data-name="{{ allergen }}">
  346. {% endif %}
  347. {% endfor %}
  348. </div>
  349. {% endif %}
  350. {% if cart.canItemsBeModified %}
  351. <div class="order-window-cart-product-quantity-buttons">
  352. <a href="#" class="order-window-cart-product-quantity-remove">
  353. <i class="icon-minus"></i>
  354. </a>
  355. <a href="#" class="order-window-cart-product-quantity-add">
  356. <i class="icon-plus"></i>
  357. </a>
  358. </div>
  359. {% endif %}
  360. </div>
  361. </div>
  362. {% endfor %}
  363. </div>
  364. <div class="order-window-cart-subtotal-modifiers" {{ cart.total == cart.subtotal ? 'style="display: none"' }}>
  365. <div class="order-window-cart-subtotal">
  366. <span class="order-window-cart-subtotal-text">{{ 'sub_total'|trans({}, 'HelensBakery') }}</span>
  367. <span id="order-window-cart-subtotal-amount" class="order-window-cart-subtotal-amount">{{ boldr_shop_format_currency(cart.subtotal, cart.currency.isoCode) }}</span>
  368. </div>
  369. <div class="order-window-cart-modifiers">
  370. {% for modifier in cart.price.modifiers %}
  371. <div class="order-window-cart-subtotal">
  372. <span class="order-window-cart-subtotal-text">{{ modifier.name }}</span>
  373. <span class="order-window-cart-subtotal-amount">{{ (modifier.amount < 0 ? '- ' : '') ~ boldr_shop_format_currency(modifier.amount|abs, cart.currency.isoCode) }}</span>
  374. </div>
  375. {% endfor %}
  376. </div>
  377. </div>
  378. </div>
  379. <div class="order-window-cart-footer">
  380. <div class="order-window-cart-subtotal">
  381. <span class="order-window-cart-subtotal-text">{{ 'total'|trans({}, 'HelensBakery') }}</span>
  382. <span id="order-window-cart-total-amount" class="order-window-cart-subtotal-amount">{{ boldr_shop_format_currency(cart.total, cart.currency.isoCode) }}</span>
  383. </div>
  384. {% if not cart.canItemsBeModified %}
  385. <p>
  386. {{ 'cant_add_while_paying'|trans({}, 'HelensBakery') }}
  387. </p>
  388. {% endif %}
  389. <div class="order-window-cart-next-states">
  390. {% for nextState in cart.nextStates %}
  391. <a href="{{ nextState.url }}" class="order-window-cart-next-state boldr-button boldr-button-highlight">
  392. {{ nextState.buttonText }}
  393. </a>
  394. {% endfor %}
  395. </div>
  396. </div>
  397. </div>
  398. </div>
  399. </div>
  400. {% endblock %}