From 5a63f88153bae75a0d4e5a00178a6309cee6b87f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Sat, 26 Jun 2021 22:31:34 +0200 Subject: [PATCH] WIP Migrate product detail page --- package-lock.json | 86 ++- package.json | 10 +- .../Classes/Controller/AjaxDateController.php | 16 +- .../Controller/AjaxTableController.php | 14 +- .../Classes/Controller/ProductController.php | 23 +- .../Classes/Service/DateService.php | 29 +- .../Configuration/TypoScript/setup.typoscript | 2 +- .../Resources/Private/Assets/js/_app.js | 68 +- .../Assets/js/components/EventPriceTable.vue | 2 +- .../Private/Assets/js/components/OsmMap.vue | 90 --- .../Assets/js/components/SearchResultItem.vue | 2 +- .../Assets/js/components/ajax-content.js | 10 +- .../Private/Assets/js/components/appconfig.js | 2 +- .../Private/Assets/js/components/collapse.js | 20 +- .../Private/Assets/js/components/fbpixel.js | 3 +- .../Private/Assets/js/components/osm-map.js | 52 ++ .../Assets/js/components/product-detail.js | 85 +++ .../Private/Assets/js/components/sticky.js | 7 +- .../Assets/js/components/watchlist-toggle.js | 7 +- .../Resources/Private/Partials/Faq.html | 2 +- .../Private/Partials/Hotel/TeaserWide.html | 2 +- .../Partials/Product/SearchresultItem.html | 2 +- .../Private/Partials/Product/TeaserWide.html | 2 +- .../Resources/Private/Partials/Topnav.html | 2 +- .../Private/Templates/AjaxDate/Dates.html | 173 +++++ .../Templates/AjaxTable/Pricetable.html | 146 ++++ .../Templates/FluidStyledContent/Gmap.html | 6 +- .../Private/Templates/Hotel/Detail.html | 8 +- .../Private/Templates/Hotel/DetailEvent.html | 3 +- .../Private/Templates/Map/General.html | 4 +- .../Private/Templates/Product/Detail.html | 679 ++++++++++++------ .../Private/Templates/Product/Detail_Vue.html | 305 ++++++++ .../Private/Templates/Region/Detail.html | 2 +- .../Private/Templates/Reseller/Copypaste.html | 10 +- .../Private/Templates/Search/Searchbar.html | 2 +- .../Private/Templates/Search/Searchbox.html | 2 + .../Templates/Search/Searchresult.html | 2 +- 37 files changed, 1410 insertions(+), 470 deletions(-) delete mode 100644 public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/OsmMap.vue create mode 100644 public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/osm-map.js create mode 100644 public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/product-detail.js create mode 100644 public/typo3conf/ext/ep_theme/Resources/Private/Templates/AjaxDate/Dates.html create mode 100644 public/typo3conf/ext/ep_theme/Resources/Private/Templates/AjaxTable/Pricetable.html create mode 100644 public/typo3conf/ext/ep_theme/Resources/Private/Templates/Product/Detail_Vue.html diff --git a/package-lock.json b/package-lock.json index b44b1316..28a68bf7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -395,9 +395,9 @@ } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.5.tgz", - "integrity": "sha512-tbD/CG3l43FIXxmu4a7RBe4zH7MLJ+S/lFowPFO7HetS2hyOZ/0nnnznegDuzFzfkyQYTxqdTH/hKmuBngaDAA==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.14.7.tgz", + "integrity": "sha512-RK8Wj7lXLY3bqei69/cc25gwS5puEc3dknoFPFbqfy3XxYQBQFvu4ioWpafMBAB+L9NyptQK4nMOa5Xz16og8Q==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5", @@ -487,16 +487,24 @@ } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.5.tgz", - "integrity": "sha512-VzMyY6PWNPPT3pxc5hi9LloKNr4SSrVCg7Yr6aZpW4Ym07r7KqSU/QXYwjXLVxqwSv0t/XSXkFoKBPUkZ8vb2A==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.14.7.tgz", + "integrity": "sha512-082hsZz+sVabfmDWo1Oct1u1AgbKbUAyVgmX4otIc7bdsRgHBXwTwb3DpDmD4Eyyx6DNiuz5UAATT655k+kL5g==", "dev": true, "requires": { - "@babel/compat-data": "^7.14.5", + "@babel/compat-data": "^7.14.7", "@babel/helper-compilation-targets": "^7.14.5", "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-transform-parameters": "^7.14.5" + }, + "dependencies": { + "@babel/compat-data": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz", + "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==", + "dev": true + } } }, "@babel/plugin-proposal-optional-catch-binding": { @@ -741,9 +749,9 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.5.tgz", - "integrity": "sha512-wU9tYisEbRMxqDezKUqC9GleLycCRoUsai9ddlsq54r8QRLaeEhc+d+9DqCG+kV9W2GgQjTZESPTpn5bAFMDww==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", + "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" @@ -862,9 +870,9 @@ } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.5.tgz", - "integrity": "sha512-+Xe5+6MWFo311U8SchgeX5c1+lJM+eZDBZgD+tvXu9VVQPXwwVzeManMMjYX6xw2HczngfOSZjoFYKwdeB/Jvw==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.7.tgz", + "integrity": "sha512-DTNOTaS7TkW97xsDMrp7nycUVh6sn/eq22VaxWfEdzuEbRsiaOU0pqU7DlyUGHVsbQbSghvjKRpEl+nUCKGQSg==", "dev": true, "requires": { "@babel/helper-create-regexp-features-plugin": "^7.14.5" @@ -991,17 +999,17 @@ } }, "@babel/preset-env": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.5.tgz", - "integrity": "sha512-ci6TsS0bjrdPpWGnQ+m4f+JSSzDKlckqKIJJt9UZ/+g7Zz9k0N8lYU8IeLg/01o2h8LyNZDMLGgRLDTxpudLsA==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.14.7.tgz", + "integrity": "sha512-itOGqCKLsSUl0Y+1nSfhbuuOlTs0MJk2Iv7iSH+XT/mR8U1zRLO7NjWlYXB47yhK4J/7j+HYty/EhFZDYKa/VA==", "dev": true, "requires": { - "@babel/compat-data": "^7.14.5", + "@babel/compat-data": "^7.14.7", "@babel/helper-compilation-targets": "^7.14.5", "@babel/helper-plugin-utils": "^7.14.5", "@babel/helper-validator-option": "^7.14.5", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.14.5", - "@babel/plugin-proposal-async-generator-functions": "^7.14.5", + "@babel/plugin-proposal-async-generator-functions": "^7.14.7", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-class-static-block": "^7.14.5", "@babel/plugin-proposal-dynamic-import": "^7.14.5", @@ -1010,7 +1018,7 @@ "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", "@babel/plugin-proposal-numeric-separator": "^7.14.5", - "@babel/plugin-proposal-object-rest-spread": "^7.14.5", + "@babel/plugin-proposal-object-rest-spread": "^7.14.7", "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", "@babel/plugin-proposal-optional-chaining": "^7.14.5", "@babel/plugin-proposal-private-methods": "^7.14.5", @@ -1036,7 +1044,7 @@ "@babel/plugin-transform-block-scoping": "^7.14.5", "@babel/plugin-transform-classes": "^7.14.5", "@babel/plugin-transform-computed-properties": "^7.14.5", - "@babel/plugin-transform-destructuring": "^7.14.5", + "@babel/plugin-transform-destructuring": "^7.14.7", "@babel/plugin-transform-dotall-regex": "^7.14.5", "@babel/plugin-transform-duplicate-keys": "^7.14.5", "@babel/plugin-transform-exponentiation-operator": "^7.14.5", @@ -1048,7 +1056,7 @@ "@babel/plugin-transform-modules-commonjs": "^7.14.5", "@babel/plugin-transform-modules-systemjs": "^7.14.5", "@babel/plugin-transform-modules-umd": "^7.14.5", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.7", "@babel/plugin-transform-new-target": "^7.14.5", "@babel/plugin-transform-object-super": "^7.14.5", "@babel/plugin-transform-parameters": "^7.14.5", @@ -1056,7 +1064,7 @@ "@babel/plugin-transform-regenerator": "^7.14.5", "@babel/plugin-transform-reserved-words": "^7.14.5", "@babel/plugin-transform-shorthand-properties": "^7.14.5", - "@babel/plugin-transform-spread": "^7.14.5", + "@babel/plugin-transform-spread": "^7.14.6", "@babel/plugin-transform-sticky-regex": "^7.14.5", "@babel/plugin-transform-template-literals": "^7.14.5", "@babel/plugin-transform-typeof-symbol": "^7.14.5", @@ -1067,8 +1075,16 @@ "babel-plugin-polyfill-corejs2": "^0.2.2", "babel-plugin-polyfill-corejs3": "^0.2.2", "babel-plugin-polyfill-regenerator": "^0.2.2", - "core-js-compat": "^3.14.0", + "core-js-compat": "^3.15.0", "semver": "^6.3.0" + }, + "dependencies": { + "@babel/compat-data": { + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.14.7.tgz", + "integrity": "sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==", + "dev": true + } } }, "@babel/preset-modules": { @@ -1797,9 +1813,9 @@ "dev": true }, "alpinejs": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.1.1.tgz", - "integrity": "sha512-svEX82laPua+oqbYlUgX1H7Q+R0GD0V7fOnjZocPBqABmpQGkofPtPV9dGFkgZy7G6q60KFSzkiSwKMw33EFYw==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.2.1.tgz", + "integrity": "sha512-MYYGUmVHNWN27TvgAtUCYXZlfsXoVCrLQT3a0Ak6CQKqf1TCHfQKxmhzJWscW5kPcLlOK2aYmWbV2H+XyfN2FQ==", "requires": { "@vue/reactivity": "^3.0.2" } @@ -2707,15 +2723,15 @@ "integrity": "sha512-v8JWLJcI7Zs9NWrs8hiVldVtm3EBF70TJI231vxn6YToBGj0c9dvdnYwltydkAnrbBMOM/qX1xLFrnTfm5wTag==" }, "core-js": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.15.0.tgz", - "integrity": "sha512-GUbtPllXMYRzIgHNZ4dTYTcUemls2cni83Q4Q/TrFONHfhcg9oEGOtaGHfb0cpzec60P96UKPvMkjX1jET8rUw==", + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.15.2.tgz", + "integrity": "sha512-tKs41J7NJVuaya8DxIOCnl8QuPHx5/ZVbFo1oKgVl1qHFBBrDctzQGtuLjPpRdNTWmKPH6oEvgN/MUID+l485Q==", "dev": true }, "core-js-compat": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.15.0.tgz", - "integrity": "sha512-8X6lWsG+s7IfOKzV93a7fRYfWRZobOfjw5V5rrq43Vh/W+V6qYxl7Akalsvgab4PFT/4L/pjQbdBUEM36NXKrw==", + "version": "3.15.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.15.1.tgz", + "integrity": "sha512-xGhzYMX6y7oEGQGAJmP2TmtBLvR4nZmRGEcFa3ubHOq5YEp51gGN9AovVa0AoujGZIq+Wm6dISiYyGNfdflYww==", "dev": true, "requires": { "browserslist": "^4.16.6", @@ -7922,9 +7938,9 @@ } }, "vue-router": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.1.tgz", - "integrity": "sha512-RRQNLT8Mzr8z7eL4p7BtKvRaTSGdCbTy2+Mm5HTJvLGYSSeG9gDzNasJPP/yOYKLy+/cLG/ftrqq5fvkFwBJEw==" + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.2.tgz", + "integrity": "sha512-807gn82hTnjCYGrnF3eNmIw/dk7/GE4B5h69BlyCK9KHASwSloD1Sjcn06zg9fVG4fYH2DrsNBZkpLtb25WtaQ==" }, "vue-scrollto": { "version": "2.20.0", diff --git a/package.json b/package.json index 7da423f5..5bdd65db 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@splidejs/splide": "^2.4.21", - "alpinejs": "^3.1.1", + "alpinejs": "^3.2.1", "axios": "^0.21.1", "axios-auth-refresh": "^1.0.7", "bootstrap-sass": "^3.4.1", @@ -29,19 +29,19 @@ "slick-carousel": "^1.8.1", "sticky-js": "^1.3.0", "vue": "^2.6.14", - "vue-router": "^3.5.1", + "vue-router": "^3.5.2", "vue-scrollto": "^2.20.0", "vue-session": "^1.0.0", "vuex": "^3.6.2" }, "devDependencies": { - "@babel/plugin-proposal-object-rest-spread": "^7.14.5", + "@babel/plugin-proposal-object-rest-spread": "^7.14.7", "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/preset-env": "^7.14.5", + "@babel/preset-env": "^7.14.7", "@symfony/webpack-encore": "^1.5.0", "@tailwindcss/custom-forms": "^0.2.1", "autoprefixer": "^9.4.6", - "core-js": "^3.15.0", + "core-js": "^3.15.2", "file-loader": "^6.2.0", "node-sass": "^4.14.1", "postcss": "^8.3.5", diff --git a/public/typo3conf/ext/ep_products/Classes/Controller/AjaxDateController.php b/public/typo3conf/ext/ep_products/Classes/Controller/AjaxDateController.php index c10e0df0..db0b0d60 100644 --- a/public/typo3conf/ext/ep_products/Classes/Controller/AjaxDateController.php +++ b/public/typo3conf/ext/ep_products/Classes/Controller/AjaxDateController.php @@ -115,15 +115,6 @@ class AjaxDateController extends ActionController */ public function datesAction(Product $product, Hotel $hotel = null, $paCode = null, $dateFrom = null, $dateTo = null) { - if ($hotel === null) { - return json_encode([ - 'dates' => [], - 'bookable' => false, - 'altProductLink' => null, - 'altLabel' => null, - ]); - } - $forcedConceptUids = GeneralUtility::trimExplode(',', $this->settings['forcedConceptUids'], true); $filterSettings = $this->filterService->getDefaultFilterSettings( $forcedConceptUids, @@ -157,12 +148,17 @@ class AjaxDateController extends ActionController 'template' => $this->settings['bpnBookingUrlTemplateCode'], 'paCode' => $paCode, ]); + $hasSurchargeOrDiscount = $this->dateService->checkSurcharcheOrDiscount($datesTable); + return json_encode([ 'dates' => $datesTable, 'bookable' => $product->getBookable(), + 'hotelName' => $hotel->getName(), 'altProductLink' => $altProductLink, 'altLabel' => $altLabel, - ]); + 'hasSurcharge' => $hasSurchargeOrDiscount['surcharge'], + 'hasDiscount' => $hasSurchargeOrDiscount['discount'], + ], JSON_THROW_ON_ERROR); } } diff --git a/public/typo3conf/ext/ep_products/Classes/Controller/AjaxTableController.php b/public/typo3conf/ext/ep_products/Classes/Controller/AjaxTableController.php index e841dcc9..d32e7308 100644 --- a/public/typo3conf/ext/ep_products/Classes/Controller/AjaxTableController.php +++ b/public/typo3conf/ext/ep_products/Classes/Controller/AjaxTableController.php @@ -111,12 +111,16 @@ class AjaxTableController extends ActionController 'template' => $this->settings['bpnBookingUrlTemplateCode'], 'paCode' => $paCode, ]); + + $dateStart = $date ? $date->getDateStart()->format('d.m.Y') : ''; + $dateEnd = $date ? $date->getDateEnd()->format('d.m.Y') : ''; + $dateRange = sprintf('%s - %s', $dateStart, $dateEnd); + return json_encode([ - 'dateStart' => $date ? $date->getDateStart()->format('Y-m-d') : '', - 'dateEnd' => $date ? $date->getDateEnd()->format('Y-m-d') : '', - 'servicesIncluded' => $date ? $date->getServicesIncluded() : '', - 'priceTable' => $priceTable, - ]); + 'dateRange' => $dateRange, + 'servicesIncluded' => $date ? $date->getServicesIncluded() : [], + 'prices' => $priceTable, + ], JSON_THROW_ON_ERROR); } /** diff --git a/public/typo3conf/ext/ep_products/Classes/Controller/ProductController.php b/public/typo3conf/ext/ep_products/Classes/Controller/ProductController.php index 4d0efdfc..4e8de1a1 100644 --- a/public/typo3conf/ext/ep_products/Classes/Controller/ProductController.php +++ b/public/typo3conf/ext/ep_products/Classes/Controller/ProductController.php @@ -159,6 +159,26 @@ class ProductController extends ActionController $backlinkUrl = GeneralUtility::_GET('ref'); $backLinkLabel = strpos($backlinkUrl, 'suche') !== -1 ? 'zurück zum Suchergebnis' : 'zurück'; + // Generate dates uri + $datesArguments = [ + 'dateFrom' => $dateFrom, + 'dateTo' => $dateTo, + 'product' => $product, + 'hotel' => $hotel + ]; + $datesUri = $this->uriBuilder + ->reset() + ->setCreateAbsoluteUri(true) + ->setTargetPageType(1702) + ->setTargetPageUid(855) + ->uriFor( + 'dates', + $datesArguments, + 'AjaxDate', + 'EpProducts', + 'ajax' + ); + $this->view->assignMultiple([ 'hotel' => $hotel, 'product' => $product, @@ -168,7 +188,8 @@ class ProductController extends ActionController 'dateFrom' => $dateFrom, 'dateTo' => $dateTo, 'referringUrl' => $backlinkUrl, - 'backlinkLabel' => $backLinkLabel + 'backlinkLabel' => $backLinkLabel, + 'datesUri' => $datesUri, ]); } diff --git a/public/typo3conf/ext/ep_products/Classes/Service/DateService.php b/public/typo3conf/ext/ep_products/Classes/Service/DateService.php index fe64ba45..dabe960a 100644 --- a/public/typo3conf/ext/ep_products/Classes/Service/DateService.php +++ b/public/typo3conf/ext/ep_products/Classes/Service/DateService.php @@ -158,7 +158,7 @@ class DateService implements SingletonInterface $filterSettings ); - return $this->preprocessDateTable([ + return $this->preprocessDatesTable([ 'dateTableData' => $dateTableData, 'template' => $template, 'paCode' => $paCode, @@ -322,6 +322,7 @@ class DateService implements SingletonInterface 'roomBusProId' => $row['roomBusProId'], 'bookingUrl' => $bookingUrl, 'isHideBookingButton' => $isHideBookingButton, + 'showBookingButton' => !$isHideBookingButton, ]; } @@ -332,7 +333,7 @@ class DateService implements SingletonInterface * @param array $options * @return array */ - public function preprocessDateTable(array $options) + public function preprocessDatesTable(array $options) { $resolver = new OptionsResolver(); $resolver->setDefined(['paCode', 'isDayTrip', 'isHideBookingButton', 'nonBookableDateUids']); @@ -370,8 +371,8 @@ class DateService implements SingletonInterface 'dateEnd' => $dateEnd->format('d.m.y'), 'dateMinPrice' => $row['dateMinPrice'], 'datePseudoPrice' => $row['datePseudoPrice'], - 'dateBusPrice' => $row['dateBusPrice'], - 'dateDiscount' => $row['dateDiscount'], + 'dateBusPrice' => $row['dateBusPrice'] ?? 0, + 'dateDiscount' => $row['dateDiscount'] ?? 0, 'dateNights' => $row['dateNights'], 'dateBusIncluded' => (bool) $row['dateBusIncluded'], 'dateSkipassIncluded' => (bool) $row['dateSkipassIncluded'], @@ -379,8 +380,10 @@ class DateService implements SingletonInterface 'dateServicesGeneral' => unserialize($row['dateServicesGeneral'], ['allowed_classes' => false]), 'season' => $row['season'], 'available' => $row['available'], + 'unavailable' => $row['available'] === 0, 'bookingUrl' => $bookingUrl, 'isHideBookingButton' => $isHideBookingButton, + 'showBookingButton' => !$isHideBookingButton, ]; } @@ -486,4 +489,22 @@ class DateService implements SingletonInterface return $priceTable; } + public function checkSurcharcheOrDiscount(array $datesTableData) + { + $data = [ + 'surcharge' => false, + 'discount' => false, + ]; + + foreach ($datesTableData as $row) { + if ($row['dateBusPrice'] && $row['dateBusPrice'] > 0) { + $data['surcharge'] = true; + } + if ($row['dateDiscount'] && $row['dateDiscount'] < 0) { + $data['discount'] = true; + } + } + + return $data; + } } diff --git a/public/typo3conf/ext/ep_theme/Configuration/TypoScript/setup.typoscript b/public/typo3conf/ext/ep_theme/Configuration/TypoScript/setup.typoscript index 6d737da2..1eb3eb8c 100644 --- a/public/typo3conf/ext/ep_theme/Configuration/TypoScript/setup.typoscript +++ b/public/typo3conf/ext/ep_theme/Configuration/TypoScript/setup.typoscript @@ -119,7 +119,7 @@ lib.stdheader.3.headerClass > @import "EXT:ep_theme/Configuration/TypoScript/Page/Export.typoscript" config { - compressJs = 1 + compressJs = 0 compressCss = 1 typolinkCheckRootline = 1 typolinkEnableLinksAcrossDomains = 1 diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_app.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_app.js index f6ae4cf0..52a09284 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_app.js +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_app.js @@ -22,11 +22,13 @@ import collapse from './components/collapse' import fbpixel from './components/fbpixel' import ajaxContent from './components/ajax-content' import faq from './components/faq' +import osmMap from './components/osm-map' +import productDetail from './components/product-detail' // Executed on document ready document.addEventListener('DOMContentLoaded', () => { const appConfig = parseAppConfig() - const storedWatchlist = JSON.parse(sessionStorage.getItem('myep-watchlist')) + const storedWatchlist = JSON.parse(sessionStorage.getItem('myep-watchlist')) || [] appendPaCode(appConfig) initSliders() Alpine.store('appconfig', appConfig) @@ -34,7 +36,7 @@ document.addEventListener('DOMContentLoaded', () => { searchBox: false, mobileNav: false, }) - Alpine.store('watchlist', storedWatchlist ? storedWatchlist : []) + Alpine.store('watchlist', storedWatchlist) Alpine.data('scrollTop', scrollTop) Alpine.data('sticky', sticky) Alpine.data('watchlistToggle', watchlistToggle) @@ -43,6 +45,8 @@ document.addEventListener('DOMContentLoaded', () => { Alpine.data('fbpixel', fbpixel) Alpine.data('ajaxContent', ajaxContent) Alpine.data('faq', faq) + Alpine.data('osmMap', osmMap) + Alpine.data('productDetail', productDetail) Alpine.start() Glightbox({ @@ -62,7 +66,6 @@ import 'dayjs/locale/de' global.$ = global.jQuery = $; -require('bootstrap-sass/assets/javascripts/bootstrap/alert') require('bootstrap-sass/assets/javascripts/bootstrap/dropdown') require('bootstrap-sass/assets/javascripts/bootstrap/modal') require('bootstrap-sass/assets/javascripts/bootstrap/transition') @@ -70,7 +73,7 @@ require('bootstrap-sass/assets/javascripts/bootstrap/transition') // Import components import SearchBar from './components/SearchBar.vue' import SearchBox from './components/SearchBox.vue' -import ProductDetail from './components/ProductDetail.vue' +//import ProductDetail from './components/ProductDetail.vue' import Calendar from './components/Calendar.vue' import EventPricetable from './components/EventPriceTable.vue' import ContactForm from './components/ContactForm.vue' @@ -83,33 +86,32 @@ Vue.filter('date', (value) => { }); // Store -import store from './store'; +// import store from './store'; -//Initialize vue app -new Vue({ - el: '#app', - store, - components: { - SearchBar, - SearchBox, - SearchResult: () => import('./components/SearchResult.vue'), - ProductDetail, - OsmMap: () => import('./components/OsmMap.vue'), - Calendar, - EventPricetable, - ContactForm, - Watchlist, - HotelList, - MyEp: () => import('./myep/App.vue'), - GroupsPriceCalculator: () => import('./components/GroupsPriceCalculator.vue'), - }, - data () { - return { - maxWindowWidth: 991, - mobileMode: false, - } - }, - created () { - this.$store.dispatch('init'); - }, -}); +// Initialize vue app +// new Vue({ +// el: '#app', +// store, +// components: { +// SearchBar, +// //SearchBox, +// //SearchResult: () => import('./components/SearchResult.vue'), +// //ProductDetail, +// //Calendar, +// //EventPricetable, +// //ContactForm, +// //Watchlist, +// //HotelList, +// //MyEp: () => import('./myep/App.vue'), +// //GroupsPriceCalculator: () => import('./components/GroupsPriceCalculator.vue'), +// }, +// data () { +// return { +// maxWindowWidth: 991, +// mobileMode: false, +// } +// }, +// created () { +// this.$store.dispatch('init'); +// }, +// }); diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/EventPriceTable.vue b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/EventPriceTable.vue index 9d7c515b..e9db7228 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/EventPriceTable.vue +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/EventPriceTable.vue @@ -16,7 +16,7 @@
-
+
Loading diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/OsmMap.vue b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/OsmMap.vue deleted file mode 100644 index 82b49a10..00000000 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/OsmMap.vue +++ /dev/null @@ -1,90 +0,0 @@ - - - - diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/SearchResultItem.vue b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/SearchResultItem.vue index 1c447a60..013750db 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/SearchResultItem.vue +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/SearchResultItem.vue @@ -61,7 +61,7 @@
- + diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/ajax-content.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/ajax-content.js index 9d000a2f..aeca8ff0 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/ajax-content.js +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/ajax-content.js @@ -1,18 +1,20 @@ import axios from 'axios' import { debounce } from './throttle-debounce' -export default () => ({ - uri: '', +export default uri => ({ + uri, loaded: false, loading: false, init() { - this.uri = this.$el.dataset.uri window.addEventListener('scroll', debounce(() => { this.load() }, 250)) }, load() { - if (true === this.loaded || false === this.inViewport()) { + if (true === this.loaded) { + return + } + if (false === this.inViewport()) { return } this.loading = true diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/appconfig.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/appconfig.js index dcb80567..050d4187 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/appconfig.js +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/appconfig.js @@ -1,5 +1,5 @@ export default () => { - const configElement = document.getElementById('appconfig'); + const configElement = document.getElementById('appconfig') if (null === configElement) { return {} } diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/collapse.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/collapse.js index c2b743a2..c00faa46 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/collapse.js +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/collapse.js @@ -1,25 +1,21 @@ import { debounce } from './throttle-debounce' -export default () => ({ - collapsed: false, +export default (isCollapsed = true, until = null, from = null) => ({ + collapsed: isCollapsed, + collapsedUntil: until, + collapsedFrom: from, init() { - const initialState = this.$el.dataset.collapsed - if (initialState !== undefined) { - this.collapsed = true - } this.checkBreakpoints() window.addEventListener('resize', debounce(() => { this.checkBreakpoints() }, 250)) }, checkBreakpoints() { - const until = this.$el.dataset.collapseUntil - if (until !== undefined) { - this.collapsed = window.innerWidth < parseInt(until) + if (null !== this.collapsedUntil) { + this.collapsed = window.innerWidth < parseInt(this.collapsedUntil) } - const from = this.$el.dataset.collapseFrom - if (from !== undefined) { - this.collapsed = window.innerWidth > parseInt(from) + if (null !== this.collapsedFrom) { + this.collapsed = window.innerWidth > parseInt(this.collapsedFrom) } }, trigger: { diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/fbpixel.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/fbpixel.js index e57bcfd7..b987a75c 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/fbpixel.js +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/fbpixel.js @@ -1,6 +1,5 @@ -export default () => ({ +export default props => ({ init() { - const props = JSON.parse(this.$el.dataset.fbpixelProps) fbq('track', 'ViewContent', props) } }) diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/osm-map.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/osm-map.js new file mode 100644 index 00000000..e3615476 --- /dev/null +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/osm-map.js @@ -0,0 +1,52 @@ +import L from 'leaflet'; + +export default () => ({ + init() { + this.lat = this.$el.dataset.lat + this.lng = this.$el.dataset.lng + this.zoom = this.$el.dataset.zoom || 12 + this.externalLink = this.$el.dataset.link + this.markers = this.$el.dataset.markers ? JSON.parse(this.$el.dataset.markers) : [] + this.map = L.map(this.$el, { + scrollWheelZoom: false + }); + this.map.setZoom(this.zoom); + if (this.lat && this.lng) { + const position = L.latLng(this.lat, this.lng); + const marker = L.marker(position); + if (this.externalLink) { + marker.on('click', () => { + window.open(this.externalLink, '_blank') + }); + } else { + marker.on('click', () => { + window.open('https://www.google.com/maps/search/?api=1&zoom=15&query=' + this.lat + ',' + this.lng, '_blank') + }); + } + marker.addTo(this.map); + this.map.setView(position); + } else if (this.markers.length) { + const bounds = L.latLngBounds(); + for (let item of this.markers) { + const position = L.latLng(item.lat, item.lng); + const marker = L.marker(position); + if (item.externalLink) { + marker.on('click', () => { + window.open(item.externalLink, '_blank'); + }); + } else { + const popupContent = '
' + item.name + '
' + item.teaser + + '
zu den Details
'; + marker.bindPopup(popupContent); + } + marker.addTo(this.map); + bounds.extend(position); + } + this.map.fitBounds(bounds); + } + L.tileLayer('https://{s}.tile.openstreetmap.de/tiles/osmde/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: '© OpenStreetMap' + }).addTo(this.map); + } +}) diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/product-detail.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/product-detail.js new file mode 100644 index 00000000..836dc7f4 --- /dev/null +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/product-detail.js @@ -0,0 +1,85 @@ +import axios from 'axios' + +export default uris => ({ + uris, + show: 'dates', + tableMode: 'dates', + datesRows: [], + pricesRows: [], + servicesIncluded: [], + dateRange: '', + available: false, + singleDate: false, + bookable: true, + hasSurcharge: false, + hasDiscount: false, + altLabel: null, + altProductLink: null, + loading: false, + addBus: false, + discountBus: false, + showAll: false, + init() { + this.loadDates() + }, + loadDates() { + this.loading = true + axios({ + url: this.uris.dates, + }).then(response => { + const json = response.data + if (json.dates.length === 1) { + this.singleDate = true + const dateUid = json.dates[0].dateUid + this.loadPrices(dateUid) + } else { + this.singleDate = false + this.datesRows = json.dates + this.bookable = json.bookable + this.altLabel = json.altLabel + this.altProductLink = json.altProductLink + this.hasSurcharge = json.hasSurcharge + this.hasDiscount = json.hasDiscount + this.available = json.dates.length > 0 + this.tableMode = 'dates' + } + }).catch(() => { + }).finally(() => { + this.loading = false + }) + }, + loadPrices(dateUid) { + this.loading = true + const data = new FormData() + data.set('tx_epproducts_ajax[date]', dateUid) + data.set('tx_epproducts_ajax[paCode]', this.$store.appconfig.paCode) + axios({ + url: this.uris.pricetable, + method: 'POST', + data + }).then(response => { + const json = response.data + this.pricesRows = json.prices + this.servicesIncluded = json.servicesIncluded + this.dateRange = json.dateRange + this.tableMode = 'prices' + }).catch(() => { + }).finally(() => { + this.loading = false + }) + }, + calculatePrice(minPrice, busPrice, discount) { + if (this.addBus) { + return minPrice + busPrice + } else if (this.discountBus) { + return minPrice + discount + } + return minPrice + }, + showBusIcon(busPrice, busIncluded) { + return ( + busPrice && this.addBus || + busIncluded && !this.discountBus + ) + }, +}) diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/sticky.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/sticky.js index 64a72aa4..1bca5cc4 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/sticky.js +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/sticky.js @@ -1,12 +1,9 @@ import { debounce } from './throttle-debounce' -export default () => ({ +export default offset => ({ + offset, sticky: false, - offset: 0, init() { - if (this.$el.dataset.offset) { - this.offset = this.$el.dataset.offset - } window.addEventListener('scroll', debounce(() => { this.sticky = window.scrollY > this.offset }, 250)) diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/watchlist-toggle.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/watchlist-toggle.js index 067ea5df..7d0e71e0 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/watchlist-toggle.js +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/watchlist-toggle.js @@ -1,5 +1,5 @@ -export default () => ({ - uid: null, +export default uid => ({ + uid, trigger: { ['@click.prevent']() { const watchlistIndex = this.$store.watchlist.indexOf(this.uid) @@ -11,9 +11,6 @@ export default () => ({ sessionStorage.setItem('myep-watchlist', JSON.stringify(this.$store.watchlist)) } }, - init() { - this.uid = this.$el.dataset.uid - }, onList() { return -1 !== this.$store.watchlist.indexOf(this.uid) }, diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Faq.html b/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Faq.html index 2ed36fd0..2db8ef2e 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Faq.html +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Faq.html @@ -12,7 +12,7 @@
-
+
{faq.question} diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Hotel/TeaserWide.html b/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Hotel/TeaserWide.html index a4795602..3a7523b9 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Hotel/TeaserWide.html +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Hotel/TeaserWide.html @@ -117,7 +117,7 @@
- + diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Product/SearchresultItem.html b/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Product/SearchresultItem.html index b313ec9f..bf0789dd 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Product/SearchresultItem.html +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Product/SearchresultItem.html @@ -115,7 +115,7 @@
- + diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Product/TeaserWide.html b/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Product/TeaserWide.html index 990bc0a1..8e4d46fc 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Product/TeaserWide.html +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Product/TeaserWide.html @@ -92,7 +92,7 @@
- + diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Topnav.html b/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Topnav.html index 5934ba3f..870d6ca2 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Topnav.html +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Partials/Topnav.html @@ -9,7 +9,7 @@ Bereich wechseln