Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
229c675e4d | ||
|
|
22072b4a25 | ||
|
|
d809d747b7 | ||
|
|
9fc490fabf | ||
|
|
5396ab941b | ||
|
|
e8154ebba1 | ||
|
|
7342db4afa |
No files matched your search
@@ -6,7 +6,7 @@ GET https://ep-reisen.ddev.site/api/product
|
||||
|
||||
### GET hotel data for myep
|
||||
GET https://ep-reisen.ddev.site/api/hotel
|
||||
?hotel=SSTGR
|
||||
?hotel=DPWGRP
|
||||
&key=abcabc123
|
||||
|
||||
###
|
||||
Generated
+6
-6
@@ -4647,16 +4647,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-grapheme",
|
||||
"version": "v1.38.1",
|
||||
"version": "v1.41.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
|
||||
"reference": "e9247d281d694a5120554d9afaf54e070e88a603"
|
||||
"reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/e9247d281d694a5120554d9afaf54e070e88a603",
|
||||
"reference": "e9247d281d694a5120554d9afaf54e070e88a603",
|
||||
"url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/bb899c1db0aa8127dc3afe8cda4a67eb24915f8d",
|
||||
"reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4705,7 +4705,7 @@
|
||||
"shim"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.38.1"
|
||||
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.41.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -4725,7 +4725,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-05-26T05:58:03+00:00"
|
||||
"time": "2026-07-28T08:25:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-intl-icu",
|
||||
|
||||
Generated
+196
-223
@@ -131,14 +131,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/generator": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz",
|
||||
"integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==",
|
||||
"version": "7.29.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz",
|
||||
"integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/parser": "^7.29.7",
|
||||
"@babel/types": "^7.29.7",
|
||||
"@babel/parser": "^7.29.8",
|
||||
"@babel/types": "^7.29.8",
|
||||
"@jridgewell/gen-mapping": "^0.3.12",
|
||||
"@jridgewell/trace-mapping": "^0.3.28",
|
||||
"jsesc": "^3.0.2"
|
||||
@@ -421,12 +421,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
|
||||
"integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
|
||||
"version": "7.29.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz",
|
||||
"integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.29.7"
|
||||
"@babel/types": "^7.29.8"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
@@ -1067,16 +1067,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-modules-systemjs": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz",
|
||||
"integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==",
|
||||
"version": "7.29.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.8.tgz",
|
||||
"integrity": "sha512-6iSnEK0zlkLKU4heofK/AdmRD4e2SHVpJMtrwnTCzhnaM98ria4rTrOXBBi45BTTYnJtO8txnPsX4fChYXkmeA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-module-transforms": "^7.29.7",
|
||||
"@babel/helper-plugin-utils": "^7.29.7",
|
||||
"@babel/helper-validator-identifier": "^7.29.7",
|
||||
"@babel/traverse": "^7.29.7"
|
||||
"@babel/traverse": "^7.29.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -1305,9 +1305,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-regenerator": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz",
|
||||
"integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==",
|
||||
"version": "7.29.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.8.tgz",
|
||||
"integrity": "sha512-0UpIXPtdDtMXfnV2OJAVMLpj3H/92vmkA6lpSRakmycJvj3VUy6Xs1dM8tXRugupykr5WB+LpiVl0J8LMVg2mg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1370,9 +1370,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-spread": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz",
|
||||
"integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==",
|
||||
"version": "7.29.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.8.tgz",
|
||||
"integrity": "sha512-4S9ksMGVWUshvgK0mKfvZky7leuG5/uoFVwMpAomJ8bMoDJiNHRVmc1EglwW/CmGVSqqWpEbXm9FmbRit22qoA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1618,18 +1618,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz",
|
||||
"integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==",
|
||||
"version": "7.29.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz",
|
||||
"integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.29.7",
|
||||
"@babel/generator": "^7.29.7",
|
||||
"@babel/generator": "^7.29.8",
|
||||
"@babel/helper-globals": "^7.29.7",
|
||||
"@babel/parser": "^7.29.7",
|
||||
"@babel/parser": "^7.29.8",
|
||||
"@babel/template": "^7.29.7",
|
||||
"@babel/types": "^7.29.7",
|
||||
"@babel/types": "^7.29.8",
|
||||
"debug": "^4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1637,9 +1637,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.29.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
|
||||
"integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
|
||||
"version": "7.29.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz",
|
||||
"integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.29.7",
|
||||
@@ -1906,9 +1906,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz",
|
||||
"integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.6.0.tgz",
|
||||
"integrity": "sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
@@ -1917,7 +1917,7 @@
|
||||
"detect-libc": "^2.0.3",
|
||||
"is-glob": "^4.0.3",
|
||||
"node-addon-api": "^7.0.0",
|
||||
"picomatch": "^4.0.3"
|
||||
"picomatch": "^4.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
@@ -1927,25 +1927,24 @@
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@parcel/watcher-android-arm64": "2.5.6",
|
||||
"@parcel/watcher-darwin-arm64": "2.5.6",
|
||||
"@parcel/watcher-darwin-x64": "2.5.6",
|
||||
"@parcel/watcher-freebsd-x64": "2.5.6",
|
||||
"@parcel/watcher-linux-arm-glibc": "2.5.6",
|
||||
"@parcel/watcher-linux-arm-musl": "2.5.6",
|
||||
"@parcel/watcher-linux-arm64-glibc": "2.5.6",
|
||||
"@parcel/watcher-linux-arm64-musl": "2.5.6",
|
||||
"@parcel/watcher-linux-x64-glibc": "2.5.6",
|
||||
"@parcel/watcher-linux-x64-musl": "2.5.6",
|
||||
"@parcel/watcher-win32-arm64": "2.5.6",
|
||||
"@parcel/watcher-win32-ia32": "2.5.6",
|
||||
"@parcel/watcher-win32-x64": "2.5.6"
|
||||
"@parcel/watcher-android-arm64": "2.6.0",
|
||||
"@parcel/watcher-darwin-arm64": "2.6.0",
|
||||
"@parcel/watcher-darwin-x64": "2.6.0",
|
||||
"@parcel/watcher-freebsd-x64": "2.6.0",
|
||||
"@parcel/watcher-linux-arm-glibc": "2.6.0",
|
||||
"@parcel/watcher-linux-arm-musl": "2.6.0",
|
||||
"@parcel/watcher-linux-arm64-glibc": "2.6.0",
|
||||
"@parcel/watcher-linux-arm64-musl": "2.6.0",
|
||||
"@parcel/watcher-linux-x64-glibc": "2.6.0",
|
||||
"@parcel/watcher-linux-x64-musl": "2.6.0",
|
||||
"@parcel/watcher-win32-arm64": "2.6.0",
|
||||
"@parcel/watcher-win32-x64": "2.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-android-arm64": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz",
|
||||
"integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.6.0.tgz",
|
||||
"integrity": "sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1964,9 +1963,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-darwin-arm64": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz",
|
||||
"integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.6.0.tgz",
|
||||
"integrity": "sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1985,9 +1984,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-darwin-x64": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz",
|
||||
"integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.6.0.tgz",
|
||||
"integrity": "sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2006,9 +2005,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-freebsd-x64": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz",
|
||||
"integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.6.0.tgz",
|
||||
"integrity": "sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2027,9 +2026,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm-glibc": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz",
|
||||
"integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.6.0.tgz",
|
||||
"integrity": "sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2048,9 +2047,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm-musl": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz",
|
||||
"integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.6.0.tgz",
|
||||
"integrity": "sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -2069,9 +2068,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm64-glibc": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz",
|
||||
"integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.6.0.tgz",
|
||||
"integrity": "sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2090,9 +2089,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-arm64-musl": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz",
|
||||
"integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.6.0.tgz",
|
||||
"integrity": "sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2111,9 +2110,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-x64-glibc": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz",
|
||||
"integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.6.0.tgz",
|
||||
"integrity": "sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2132,9 +2131,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-linux-x64-musl": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz",
|
||||
"integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.6.0.tgz",
|
||||
"integrity": "sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2153,9 +2152,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-win32-arm64": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz",
|
||||
"integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.6.0.tgz",
|
||||
"integrity": "sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -2173,31 +2172,10 @@
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-win32-ia32": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz",
|
||||
"integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/@parcel/watcher-win32-x64": {
|
||||
"version": "2.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz",
|
||||
"integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.6.0.tgz",
|
||||
"integrity": "sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -2395,9 +2373,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/express-serve-static-core": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.2.tgz",
|
||||
"integrity": "sha512-d3KvEXBSo/lOAMc2u6fkyDHBvetBHeqD7wm/AcXfLpSOQwlmG9D/aQ0SFswVjv05p7ullQS7Mjohj6/VdbZuTg==",
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.3.tgz",
|
||||
"integrity": "sha512-dPfW8NFiOF4wOHc7+N/QSxlY9cfSsenewGbAz8C8U/MULPd/YZ27LvJUIlzaXie7e6Ove9YunJGgC9tbHD2cKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2470,9 +2448,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "26.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.1.tgz",
|
||||
"integrity": "sha512-nxAkRSVkN1Y0JC1W8ky/fTfkGsMmcrRsbx+3XoZE+rMOX71kLYTV7fLXpqud1GpbpP5TuffXFqfX7fH2GgZREw==",
|
||||
"version": "26.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.1.2.tgz",
|
||||
"integrity": "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2895,9 +2873,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.17.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.17.0.tgz",
|
||||
"integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==",
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz",
|
||||
"integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -2907,19 +2885,6 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-import-phases": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
|
||||
"integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"acorn": "^8.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/adjust-sourcemap-loader": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz",
|
||||
@@ -3156,9 +3121,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/autoprefixer": {
|
||||
"version": "10.5.2",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.2.tgz",
|
||||
"integrity": "sha512-rD5t5DwOjJdmSORcTq64j8MawTC+tbQ+HHqjR4NDumamy/ambn1UJrlKL+KdwujWxMkFjPM3pPHOEA9tl4767Q==",
|
||||
"version": "10.5.4",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.4.tgz",
|
||||
"integrity": "sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3176,8 +3141,8 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.28.4",
|
||||
"caniuse-lite": "^1.0.30001799",
|
||||
"browserslist": "^4.28.6",
|
||||
"caniuse-lite": "^1.0.30001806",
|
||||
"fraction.js": "^5.3.4",
|
||||
"picocolors": "^1.1.1",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
@@ -3193,13 +3158,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.18.1.tgz",
|
||||
"integrity": "sha512-3nTvFlvpn9Zu/RkHUqtc7/+al4UpRW5az71ap5zccp6e8RAYEzhMTecX8Dz1wWDYrPpUoB1HAQEGEAEvUr7S9g==",
|
||||
"version": "1.19.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz",
|
||||
"integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.16.0",
|
||||
"form-data": "^4.0.5",
|
||||
"form-data": "^4.0.6",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"proxy-from-env": "^2.1.0"
|
||||
}
|
||||
@@ -3274,9 +3239,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/baseline-browser-mapping": {
|
||||
"version": "2.10.42",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.42.tgz",
|
||||
"integrity": "sha512-c/jurFrDLyui7o1J86yLkRu4LMsTYcBohveus7/I2Hzdn9KIP2bdJPTue/lR1KH46enoPbD77GKeSYNdyPoD3Q==",
|
||||
"version": "2.11.12",
|
||||
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz",
|
||||
"integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
@@ -3366,9 +3331,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bonjour-service": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.2.tgz",
|
||||
"integrity": "sha512-lMskhnsW70yWHr4PhPeh2rvaIkLSaDpp+nmtbXBZaNKTXwxL73QOkW6HhbzqTImXjevn9TreGT4GACGBCGP9nQ==",
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.4.tgz",
|
||||
"integrity": "sha512-jCZcVv7eoc4QesRscwEZtSROBen+6LpKAmBIsQYQrsAeVHLyMXWX/t6eIV5KiRZYNUBl8eVqImEEMQ8L5+c/Kw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3384,9 +3349,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "1.1.16",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz",
|
||||
"integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==",
|
||||
"version": "1.1.18",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
|
||||
"integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3408,9 +3373,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.28.5",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.5.tgz",
|
||||
"integrity": "sha512-Cu2E6QejHWzuDMTkuwgpABFgDfZrXLQq5V13YOACZx4mFAG4IwGTbTfHPMr4WtxlHoXSM8FIuRwYYCz5XiabaQ==",
|
||||
"version": "4.28.7",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz",
|
||||
"integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3428,10 +3393,10 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.10.42",
|
||||
"caniuse-lite": "^1.0.30001800",
|
||||
"electron-to-chromium": "^1.5.387",
|
||||
"node-releases": "^2.0.50",
|
||||
"baseline-browser-mapping": "^2.10.44",
|
||||
"caniuse-lite": "^1.0.30001806",
|
||||
"electron-to-chromium": "^1.5.393",
|
||||
"node-releases": "^2.0.51",
|
||||
"update-browserslist-db": "^1.2.3"
|
||||
},
|
||||
"bin": {
|
||||
@@ -3535,9 +3500,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001803",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001803.tgz",
|
||||
"integrity": "sha512-g/uHREV2ZpK9qMalCsWaxmA6ol+DX8GYhuf3T40RKoP+oL7vhRJh8LNt73PCjpnR6l14FzfPrB5Yux4PKm2meg==",
|
||||
"version": "1.0.30001806",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz",
|
||||
"integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -3836,25 +3801,31 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.49.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz",
|
||||
"integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==",
|
||||
"version": "3.50.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.50.0.tgz",
|
||||
"integrity": "sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/core-js-compat": {
|
||||
"version": "3.49.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz",
|
||||
"integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==",
|
||||
"version": "3.50.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.50.0.tgz",
|
||||
"integrity": "sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserslist": "^4.28.1"
|
||||
"browserslist": "^4.28.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.4.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
@@ -4461,9 +4432,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.389",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.389.tgz",
|
||||
"integrity": "sha512-cEto7aeOqBfU1D+c5py5pE+ooscKE75JifxLBdFUZsqAxRS6y7kebtxAZvICszSl05gPjYHDTjY+lXpyGvpJbg==",
|
||||
"version": "1.5.401",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.401.tgz",
|
||||
"integrity": "sha512-H6ViHN68nGYlChEvlIU67fn8O2/tpbWQPwck98yaJmh+08LSvHiydzDQ6oXNccLU3kNRVIRS9A4mA7CG+i6fLQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@@ -4495,9 +4466,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.24.2",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.2.tgz",
|
||||
"integrity": "sha512-rpsZEGT1jFuve6QlpyRp9ckQ+kN61hvF9BzCPyMdaKTm8UJce96KBn3sorXOFXlzjPrs3Vc4T1NsSroZ3PxlFw==",
|
||||
"version": "5.24.5",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz",
|
||||
"integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -4570,9 +4541,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.0.tgz",
|
||||
"integrity": "sha512-KLdwQm2NvGLDkQDCGvmiQrhkd0JbMzXthwQAUgWjQuQdBLFa3eiBP5arXZyA+f8x+x7OXgud6bq2rxjGtHV2tw==",
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz",
|
||||
"integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -4866,9 +4837,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fast-uri": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz",
|
||||
"integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==",
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz",
|
||||
"integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
@@ -5705,9 +5676,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz",
|
||||
"integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==",
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.5.0.tgz",
|
||||
"integrity": "sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -6075,20 +6046,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/loader-runner": {
|
||||
"version": "4.3.2",
|
||||
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz",
|
||||
"integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6.11.5"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/webpack"
|
||||
}
|
||||
},
|
||||
"node_modules/loader-utils": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
|
||||
@@ -6597,9 +6554,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.15",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.15.tgz",
|
||||
"integrity": "sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==",
|
||||
"version": "3.3.17",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.17.tgz",
|
||||
"integrity": "sha512-xQLf0A3HOMlgHq0n247/LRuAOYmB7dXJ/DvAxGvsSBij45XtBSmQycu+F8ODbHwns/XyFZagyL1+J0Offw1E0g==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -6650,9 +6607,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.51",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz",
|
||||
"integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==",
|
||||
"version": "2.0.52",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.52.tgz",
|
||||
"integrity": "sha512-MRlTqhAfoMx/4mhEbPo3Hi02g9LJZaJkka69V6h67Cb1gjrAG0jsTE4CZX1eptNx+VCAwJmfpnDIF4P0Nh1A7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -7136,9 +7093,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.16",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.16.tgz",
|
||||
"integrity": "sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==",
|
||||
"version": "8.5.25",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz",
|
||||
"integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -7155,7 +7112,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.12",
|
||||
"nanoid": "^3.3.16",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
@@ -8296,9 +8253,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.101.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz",
|
||||
"integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==",
|
||||
"version": "1.102.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.102.0.tgz",
|
||||
"integrity": "sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -8363,9 +8320,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz",
|
||||
"integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==",
|
||||
"version": "1.6.1",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz",
|
||||
"integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
@@ -8611,9 +8568,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz",
|
||||
"integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==",
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz",
|
||||
"integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -8978,9 +8935,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/svgo": {
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.2.tgz",
|
||||
"integrity": "sha512-TyzE4NVGLUFy+H/Uy4N6c3G0HEeprsVfge6Lmq+0FdQQ/zqoVYB62IsBZORsiL+o96s6ff/V6/3UQo/C0cgCAA==",
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.3.tgz",
|
||||
"integrity": "sha512-5EZD0pafXX6PphdwOGCiVLDSaV1xyuQao2blHajHLsPxr07q4mmEjdtXEWgG07ae2mIz8Ex2CDXNCTiXhy3Khw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -9179,6 +9136,24 @@
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss/node_modules/yaml": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz",
|
||||
"integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/eemeli"
|
||||
}
|
||||
},
|
||||
"node_modules/tapable": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz",
|
||||
@@ -9194,9 +9169,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.49.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.49.0.tgz",
|
||||
"integrity": "sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==",
|
||||
"version": "5.49.2",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.49.2.tgz",
|
||||
"integrity": "sha512-rGbJiKeQ4WDe3EXlDAIaQcwftVfv2Q8o1awFNfvXolJYKkb1AuZY1RTOmqx4LJXZENbWZA7eIsYGHuEzHsi1nQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
@@ -9773,9 +9748,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.108.4",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.108.4.tgz",
|
||||
"integrity": "sha512-yur8LyJoeiWh47dErD+Ok7vlbmDsJ3UbbRPAoxbGJ54WpE2y5yVo5G/inUzujnYgw3tPmBRdn+G7PoxXaYC33w==",
|
||||
"version": "5.109.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.109.2.tgz",
|
||||
"integrity": "sha512-U9/cvLzxObKNEZ9+TtdqrHM5/9z3lgl2c+c4BzbqGxFQvQvBAq87yql5A8pQ+rrMbS496MZJeF5enVBndIy2hw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -9785,22 +9760,20 @@
|
||||
"@webassemblyjs/wasm-edit": "^1.14.1",
|
||||
"@webassemblyjs/wasm-parser": "^1.14.1",
|
||||
"acorn": "^8.16.0",
|
||||
"acorn-import-phases": "^1.0.3",
|
||||
"browserslist": "^4.28.1",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.22.2",
|
||||
"enhanced-resolve": "^5.24.4",
|
||||
"es-module-lexer": "^2.1.0",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"graceful-fs": "^4.2.11",
|
||||
"loader-runner": "^4.3.2",
|
||||
"mime-db": "^1.54.0",
|
||||
"minimizer-webpack-plugin": "^5.6.1",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^4.3.3",
|
||||
"tapable": "^2.3.0",
|
||||
"watchpack": "^2.5.2",
|
||||
"webpack-sources": "^3.5.0"
|
||||
"webpack-sources": "^3.5.1"
|
||||
},
|
||||
"bin": {
|
||||
"webpack": "bin/webpack.js"
|
||||
@@ -10299,9 +10272,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.21.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz",
|
||||
"integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==",
|
||||
"version": "8.21.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz",
|
||||
"integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
|
||||
@@ -27,8 +27,10 @@ namespace EP\EpProducts\Controller;
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use EP\EpProducts\BpnConnect\ApiClient;
|
||||
use EP\EpProducts\BpnConnect\ApiClient as BpnConnectClient;
|
||||
use EP\EpProducts\MyEP\ApiClient as MyEpClient;
|
||||
use EP\EpProducts\Domain\Model\Hotel;
|
||||
use EP\EpProducts\MyEP\ApiException;
|
||||
use EP\EpProducts\Utility\DateUtility;
|
||||
use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
@@ -37,26 +39,152 @@ class AjaxCalendarController extends ActionController
|
||||
{
|
||||
private const CACHE_TTL = 3600;
|
||||
|
||||
/**
|
||||
* @var ApiClient
|
||||
*/
|
||||
protected $apiClient;
|
||||
protected BpnConnectClient $bpnConnectClient;
|
||||
protected MyEpClient $myEpClient;
|
||||
protected FrontendInterface $cache;
|
||||
|
||||
/**
|
||||
* @var FrontendInterface
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @param ApiClient $apiClient
|
||||
* @param FrontendInterface $cache
|
||||
*/
|
||||
public function __construct(ApiClient $apiClient, FrontendInterface $cache)
|
||||
public function __construct(BpnConnectClient $bpnConnectClient, MyEpClient $myEpClient, FrontendInterface $cache)
|
||||
{
|
||||
$this->apiClient = $apiClient;
|
||||
$this->bpnConnectClient = $bpnConnectClient;
|
||||
$this->myEpClient = $myEpClient;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
public function priceCalendarAction(Hotel $hotel, int $months = 12): void
|
||||
{
|
||||
$hotelCode = trim($hotel->getCode() ?? '');
|
||||
$dateRange = DateUtility::getDateRange(null, null, $months);
|
||||
$today = new \DateTimeImmutable('today');
|
||||
|
||||
$priceDataByDate = [];
|
||||
$error = false;
|
||||
$errorMessage = '';
|
||||
|
||||
if ($hotelCode !== '') {
|
||||
try {
|
||||
$cacheIdentifier = 'myep_price_calendar_' . sha1(implode('|', [
|
||||
$hotelCode,
|
||||
$dateRange['period']->getStartDate()->format('Y-m-d'),
|
||||
$dateRange['period']->getEndDate()->format('Y-m-d'),
|
||||
]));
|
||||
$cachedData = $this->cache->get($cacheIdentifier);
|
||||
|
||||
if (false !== $cachedData) {
|
||||
$priceDataByDate = $cachedData;
|
||||
} else {
|
||||
$rawData = $this->myEpClient->getPriceConfigData(
|
||||
$hotelCode,
|
||||
$dateRange['period']->getStartDate(),
|
||||
$dateRange['period']->getEndDate()
|
||||
);
|
||||
|
||||
$availableDates = [];
|
||||
foreach ($rawData as $item) {
|
||||
if (($item['status'] ?? '') === 'OK') {
|
||||
$availableDates[$item['date']] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rawData as $item) {
|
||||
$date = $item['date'];
|
||||
$dt = \DateTimeImmutable::createFromFormat('Y-m-d', $date);
|
||||
if ($dt < $today) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$prevDate = $dt->modify('-1 day')->format('Y-m-d');
|
||||
$isAvailable = ($item['status'] ?? '') === 'OK';
|
||||
$prevAvailable = isset($availableDates[$prevDate]);
|
||||
|
||||
if ($isAvailable) {
|
||||
$dayStatus = $prevAvailable ? 'ok' : 'blocked-to-ok';
|
||||
} elseif ($prevAvailable) {
|
||||
$dayStatus = 'checkout-only';
|
||||
} else {
|
||||
$dayStatus = 'blocked';
|
||||
}
|
||||
|
||||
$priceDataByDate[$date] = [
|
||||
'status' => $dayStatus,
|
||||
'available' => $isAvailable ? 1 : 0,
|
||||
'tooltip' => $this->buildTooltip($dayStatus, $item),
|
||||
'pricePerNight' => $item['pricePerNight'] ?? null,
|
||||
'defaultPricePerNight' => $item['defaultPricePerNight'] ?? null,
|
||||
'type' => $item['type'] ?? null,
|
||||
'currency' => $item['currency'] ?? null,
|
||||
'includedPax' => $item['includedPax'] ?? null,
|
||||
'minNights' => (int)($item['minNights'] ?? 0),
|
||||
];
|
||||
}
|
||||
|
||||
$this->cache->set($cacheIdentifier, $priceDataByDate, [], self::CACHE_TTL);
|
||||
}
|
||||
} catch (ApiException $e) {
|
||||
$error = true;
|
||||
$errorMessage = $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
$error = true;
|
||||
$errorMessage = 'Missing hotel code';
|
||||
}
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'priceDataByDate' => $priceDataByDate,
|
||||
'calendarMonths' => $this->buildCalendarMonths($dateRange['period']),
|
||||
'error' => $error,
|
||||
'errorMessage' => $errorMessage,
|
||||
]);
|
||||
}
|
||||
|
||||
public function priceConfigAction(Hotel $hotel, string $year = null, string $month = null, int $months = 12)
|
||||
{
|
||||
$dateRange = DateUtility::getDateRange($year, $month, $months);
|
||||
|
||||
$apiDateFrom = $dateRange['period']->getStartDate();
|
||||
$apiDateTo = $dateRange['period']->getEndDate();
|
||||
$hotelCode = trim($hotel->getCode() ?? '');
|
||||
|
||||
$priceConfig = [
|
||||
'data' => [],
|
||||
'success' => true,
|
||||
'error' => null,
|
||||
];
|
||||
|
||||
try {
|
||||
$priceConfig['data'] = $this->myEpClient->getPriceConfigData($hotelCode, $apiDateFrom, $apiDateTo);
|
||||
} catch (ApiException $e) {
|
||||
$priceConfig['success'] = false;
|
||||
$priceConfig['error'] = $e->getMessage();
|
||||
}
|
||||
|
||||
$this->view->assign('priceConfig', $priceConfig);
|
||||
}
|
||||
|
||||
public function priceTableAction(Hotel $hotel, string $year = null): void
|
||||
{
|
||||
$year = $year ?? (new \DateTimeImmutable())->format('Y');
|
||||
$hotelCode = trim($hotel->getCode() ?? '');
|
||||
|
||||
$priceTable = [
|
||||
'data' => [],
|
||||
'success' => true,
|
||||
'error' => null,
|
||||
];
|
||||
|
||||
try {
|
||||
$priceTable['data'] = $this->myEpClient->getPriceTableData($hotelCode, $year);
|
||||
} catch (ApiException $e) {
|
||||
$priceTable['success'] = false;
|
||||
$priceTable['error'] = $e->getMessage();
|
||||
}
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'hotel' => $hotel,
|
||||
'year' => $year,
|
||||
'priceTable' => $priceTable,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Hotel $hotel
|
||||
* @param string $year
|
||||
@@ -91,7 +219,7 @@ class AjaxCalendarController extends ActionController
|
||||
if (false !== $cachedCalendar) {
|
||||
$calendar = $cachedCalendar;
|
||||
} else {
|
||||
$calendar = $this->apiClient->getCalendar(
|
||||
$calendar = $this->bpnConnectClient->getCalendar(
|
||||
$hotelCode,
|
||||
new \DateTimeImmutable($apiDateFrom),
|
||||
new \DateTimeImmutable($apiDateTo),
|
||||
@@ -112,6 +240,46 @@ class AjaxCalendarController extends ActionController
|
||||
]);
|
||||
}
|
||||
|
||||
private function buildTooltip(string $status, array $item): string
|
||||
{
|
||||
if ($status === 'blocked') {
|
||||
return 'Nicht verfügbar';
|
||||
}
|
||||
if ($status === 'checkout-only') {
|
||||
return 'Nur Abreise';
|
||||
}
|
||||
return $this->buildPriceTooltip($item);
|
||||
}
|
||||
|
||||
private function buildPriceTooltip(array $item): string
|
||||
{
|
||||
$price = $item['pricePerNight'] ?? null;
|
||||
$currency = $this->getCurrencySymbol($item['currency'] ?? null);
|
||||
|
||||
if ($price !== null) {
|
||||
$priceStr = (($item['type'] ?? null) === 'discount')
|
||||
? $price . ' ' . $currency
|
||||
: 'ab ' . $price . ' ' . $currency;
|
||||
} else {
|
||||
$priceStr = 'Anfrage';
|
||||
}
|
||||
|
||||
$minNights = (int)($item['minNights'] ?? 0);
|
||||
|
||||
return $minNights > 1
|
||||
? $priceStr . ' · min. ' . $minNights . ' Nächte'
|
||||
: $priceStr;
|
||||
}
|
||||
|
||||
private function getCurrencySymbol(?string $currency): string
|
||||
{
|
||||
if (null === $currency || '' === $currency) {
|
||||
return '€';
|
||||
}
|
||||
|
||||
return 'EUR' === $currency ? '€' : $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
<?php
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2020 Björn Fromme <[email protected]>, dreipunktnull
|
||||
*
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use EP\EpProducts\Domain\Model\Dto\GroupsPriceInquiry;
|
||||
use EP\EpProducts\Domain\Model\GroupsPriceBoard;
|
||||
use EP\EpProducts\Domain\Model\GroupsPriceOption;
|
||||
use EP\EpProducts\Domain\Model\Hotel;
|
||||
use EP\EpProducts\Domain\Repository\GroupsPriceOptionRepository;
|
||||
use EP\EpProducts\Service\EmailService;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
use TYPO3\CMS\Extbase\Persistence\Exception\InvalidQueryException;
|
||||
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
|
||||
|
||||
class AjaxGroupsPriceController extends ActionController
|
||||
{
|
||||
/**
|
||||
* @var GroupsPriceOptionRepository
|
||||
*/
|
||||
protected $groupsPriceOptionRepository;
|
||||
|
||||
/**
|
||||
* @var EmailService
|
||||
*/
|
||||
protected $emailService;
|
||||
|
||||
public function __construct(GroupsPriceOptionRepository $groupsPriceOptionRepository, EmailService $emailService)
|
||||
{
|
||||
$this->groupsPriceOptionRepository = $groupsPriceOptionRepository;
|
||||
$this->emailService = $emailService;
|
||||
}
|
||||
|
||||
public function initializeProcessFormAction()
|
||||
{
|
||||
if ($this->request->hasArgument('groupsPriceInquiry')) {
|
||||
$this->arguments->getArgument('groupsPriceInquiry')
|
||||
->getPropertyMappingConfiguration()->allowAllProperties();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Hotel $hotel
|
||||
* @param GroupsPriceInquiry $groupsPriceInquiry
|
||||
* @return string
|
||||
*/
|
||||
public function processFormAction(Hotel $hotel, GroupsPriceInquiry $groupsPriceInquiry)
|
||||
{
|
||||
$mode = $groupsPriceInquiry->getMode();
|
||||
$country = $hotel->getCountry()->getCode();
|
||||
$effectivePax = $groupsPriceInquiry->getEffectivePax();
|
||||
$nights = $groupsPriceInquiry->getNights();
|
||||
|
||||
if (false === in_array($mode, [GroupsPriceInquiry::MODE_BOOKING, GroupsPriceInquiry::MODE_INQUIRY])) {
|
||||
$mode = GroupsPriceInquiry::MODE_BOOKING;
|
||||
}
|
||||
|
||||
$subject = GroupsPriceInquiry::MODE_BOOKING ?
|
||||
'Gruppenhaus Preisberechnung/Buchung' : 'Gruppenhaus Preisberechnung/Anfrage';
|
||||
|
||||
$emailOptions = [
|
||||
'toEmail' => $this->settings['groupsPriceToEmail'],
|
||||
'toName' => $this->settings['groupsPriceToName'],
|
||||
'fromEmail' => $this->settings['groupsPriceToEmail'],
|
||||
'fromName' => $this->settings['groupsPriceToName'],
|
||||
'subject' => $subject,
|
||||
'templateName' => 'GroupsPrice',
|
||||
];
|
||||
|
||||
$optionPrice = function (GroupsPriceOption $option) use ($country, $effectivePax, $nights) {
|
||||
$price = 'CH' === $country ? $option->getPriceChf() : $option->getPrice();
|
||||
$currency = 'CH' === $country ? 'CHF' : '€';
|
||||
|
||||
if (GroupsPriceOption::TYPE_PER_PAX === $option->getType()) {
|
||||
$price = $price * $effectivePax;
|
||||
} elseif (GroupsPriceOption::TYPE_PER_NIGHT === $option->getType()) {
|
||||
$price = $price * $nights;
|
||||
} elseif (GroupsPriceOption::TYPE_PER_PAX_AND_NIGHT === $option->getType()) {
|
||||
$price = $price * $nights * $effectivePax;
|
||||
}
|
||||
|
||||
return $price.' '.$currency;
|
||||
};
|
||||
|
||||
try {
|
||||
$options = $this->groupsPriceOptionRepository->findByUids($groupsPriceInquiry->getOptions());
|
||||
$selectedOptions = array_map(function ($option) use ($optionPrice) {
|
||||
return $option->getTitle().': '.$optionPrice($option);
|
||||
}, $options);
|
||||
}
|
||||
catch (InvalidQueryException $e) {
|
||||
$selectedOptions = [];
|
||||
}
|
||||
|
||||
$variables = [
|
||||
'mode' => $mode,
|
||||
'hotel' => $hotel,
|
||||
'name' => $groupsPriceInquiry->getName(),
|
||||
'group' => $groupsPriceInquiry->getGroup(),
|
||||
'street' => $groupsPriceInquiry->getStreet(),
|
||||
'postcode' => $groupsPriceInquiry->getPostcode(),
|
||||
'city' => $groupsPriceInquiry->getCity(),
|
||||
'email' => $groupsPriceInquiry->getEmail(),
|
||||
'phone' => $groupsPriceInquiry->getPhone(),
|
||||
'remarks' => $groupsPriceInquiry->getRemarks(),
|
||||
'dateFrom' => $groupsPriceInquiry->getDateFrom(),
|
||||
'dateTo' => $groupsPriceInquiry->getDateTo(),
|
||||
'nights' => $groupsPriceInquiry->getNights(),
|
||||
'pax' => $groupsPriceInquiry->getPax(),
|
||||
'children' => $groupsPriceInquiry->getChildren(),
|
||||
'minors' => $groupsPriceInquiry->getMinors(),
|
||||
'adolescents' => $groupsPriceInquiry->getAdolescents(),
|
||||
'adolescentsAge' => $hotel->getGroupsPriceAdolescentsAge(),
|
||||
'options' => $selectedOptions,
|
||||
'board' => $groupsPriceInquiry->getBoard(),
|
||||
'summary' => $groupsPriceInquiry->getSummary(),
|
||||
];
|
||||
|
||||
$this->emailService->send($emailOptions, $variables);
|
||||
|
||||
return json_encode(['status' => 'ok'], JSON_THROW_ON_ERROR, 512);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function errorAction() {
|
||||
$formErrors = [];
|
||||
if ($this->arguments->validate()->hasErrors()) {
|
||||
foreach ($this->arguments->validate()->getFlattenedErrors() as $key => $errors) {
|
||||
$parts = explode('.', $key);
|
||||
$fieldName = array_pop($parts);
|
||||
$errorsRaw = [];
|
||||
foreach ($errors as $error) {
|
||||
$translationKey = sprintf('tx_eptheme.message.%s.%s', $fieldName, $error->getCode());
|
||||
$errorsRaw[] = LocalizationUtility::translate($translationKey, 'ep_theme');
|
||||
}
|
||||
$formErrors[$fieldName] = implode(', ', $errorsRaw);
|
||||
}
|
||||
}
|
||||
|
||||
$response['status'] = 'validation';
|
||||
$response['errors'] = $formErrors;
|
||||
|
||||
return json_encode($response);
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace EP\EpProducts\Controller;
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
* Copyright notice
|
||||
*
|
||||
* (c) 2020 Björn Fromme <[email protected]>, dreipunktnull
|
||||
*
|
||||
* All rights reserved
|
||||
*
|
||||
* This script is part of the TYPO3 project. The TYPO3 project is
|
||||
* free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The GNU General Public License can be found at
|
||||
* http://www.gnu.org/copyleft/gpl.html.
|
||||
*
|
||||
* This script is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* This copyright notice MUST APPEAR in all copies of the script!
|
||||
***************************************************************/
|
||||
|
||||
use EP\EpProducts\Domain\Model\Hotel;
|
||||
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
|
||||
|
||||
class GroupsPriceController extends ActionController
|
||||
{
|
||||
public function indexAction(Hotel $hotel)
|
||||
{
|
||||
// Sort configs by date to properly determine earliest date in js component
|
||||
$configs = $hotel->getGroupsPriceConfigs()->toArray();
|
||||
uasort($configs, function ($a, $b) {
|
||||
return $a->getDateFrom() > $b->getDateFrom();
|
||||
});
|
||||
|
||||
$mainSeasonFrom = $mainSeasonTo = null;
|
||||
|
||||
if (null !== $hotel->getMainSeasonFrom()) {
|
||||
$mainSeasonFrom = $hotel->getMainSeasonFrom()->format('d.m.Y');
|
||||
}
|
||||
if (null !== $hotel->getMainSeasonTo()) {
|
||||
$mainSeasonTo = $hotel->getMainSeasonTo()->format('d.m.Y');
|
||||
}
|
||||
|
||||
$this->view->assign('hotel', $hotel);
|
||||
$this->view->assign('runningCostsEUR', $this->settings['runningCostsEUR']);
|
||||
$this->view->assign('runningCostsCHF', $this->settings['runningCostsCHF']);
|
||||
$this->view->assign('undersubscription30EUR', $this->settings['undersubscription30EUR']);
|
||||
$this->view->assign('undersubscription30CHF', $this->settings['undersubscription30CHF']);
|
||||
$this->view->assign('undersubscription40EUR', $this->settings['undersubscription40EUR']);
|
||||
$this->view->assign('undersubscription40CHF', $this->settings['undersubscription40CHF']);
|
||||
$this->view->assign('countryCode', $hotel->getCountry()->getCode());
|
||||
$this->view->assign('configs', json_encode(array_values($configs), JSON_HEX_APOS));
|
||||
$this->view->assign('boards', json_encode($hotel->getGroupsPriceBoards()->toArray(), JSON_HEX_APOS));
|
||||
$this->view->assign('options', json_encode($hotel->getGroupsPriceOptions()->toArray(), JSON_HEX_APOS));
|
||||
$this->view->assign('mainSeasonFrom', $mainSeasonFrom);
|
||||
$this->view->assign('mainSeasonTo', $mainSeasonTo);
|
||||
$this->view->assign('adolescentsAge', $hotel->getGroupsPriceAdolescentsAge() ?? 0);
|
||||
}
|
||||
}
|
||||
@@ -217,27 +217,50 @@ class ApiMiddleware implements MiddlewareInterface
|
||||
|
||||
$images = $this->serializeImages($this->hotelImageService->getImages((int) $hotel['uid']));
|
||||
|
||||
// map fields to icon ids and labels
|
||||
$icons = [];
|
||||
|
||||
if (($hotel['beds_count'] ?? 0) > 0) {
|
||||
$icons['bed'] = sprintf('%d Betten', $hotel['beds_count']);
|
||||
}
|
||||
if (($hotel['parking_count'] ?? 0) > 0) {
|
||||
$icons['parking'] = sprintf('%d Parkplätze', $hotel['parking_count']);
|
||||
}
|
||||
if ($hotel['altitude'] ?? null) {
|
||||
$icons['mountain'] = $hotel['altitude'];
|
||||
}
|
||||
if ($hotel['distance_bus'] ?? null) {
|
||||
$icons['bus'] = $hotel['distance_bus'];
|
||||
}
|
||||
if ($hotel['distance_lift'] ?? null) {
|
||||
$icons['lift'] = $hotel['distance_lift'];
|
||||
}
|
||||
if ($hotel['shower'] ?? null) {
|
||||
$icons['shower'] = $hotel['shower'];
|
||||
}
|
||||
if ($hotel['partyroom'] ?? false) {
|
||||
$icons['party'] = 'Partyzimmer';
|
||||
}
|
||||
if ($hotel['gamesroom'] ?? false) {
|
||||
$icons['dice'] = 'Spielezimmer';
|
||||
}
|
||||
if ($hotel['sauna'] ?? false) {
|
||||
$icons['sauna'] = 'Sauna';
|
||||
}
|
||||
if ($hotel['wifi'] ?? false) {
|
||||
$icons['wifi'] = 'WiFi';
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => $hotel['name'],
|
||||
'code' => $hotel['code'],
|
||||
'description' => $hotel['description'],
|
||||
'features' => $hotel['features'],
|
||||
'roomTypes' => $hotel['room_types'],
|
||||
'additionalInformation' => $hotel['additional_information'],
|
||||
'room_types' => $hotel['room_types'],
|
||||
'additional_information' => $hotel['additional_information'],
|
||||
'address' => $hotel['address'],
|
||||
'images' => $images,
|
||||
'icons' => [
|
||||
'bedsCount' => (int) $hotel['beds_count'],
|
||||
'parkingCount' => (int) $hotel['parking_count'],
|
||||
'altitude' => $hotel['altitude'],
|
||||
'shower' => $hotel['shower'],
|
||||
'partyroom' => (bool) $hotel['partyroom'],
|
||||
'gamesroom' => (bool) $hotel['gamesroom'],
|
||||
'sauna' => (bool) $hotel['sauna'],
|
||||
'wifi' => (bool) $hotel['wifi'],
|
||||
'distanceBus' => $hotel['distance_bus'],
|
||||
'distanceLift' => $hotel['distance_lift'],
|
||||
],
|
||||
'icons' => $icons,
|
||||
'region' => $this->fetchRegionData((int) $hotel['region']),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -111,6 +111,33 @@ class ApiClient implements LoggerAwareInterface
|
||||
return $this->requestJson('GET', 'pickups-planning/' . $travelCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function getPriceConfigData(string $hotelCode, \DateTimeImmutable $dateFrom, \DateTimeImmutable $dateTo): array
|
||||
{
|
||||
return $this->requestJson('GET', 'contingents/calendar', [
|
||||
'query' => [
|
||||
'hotelCode' => $hotelCode,
|
||||
'dateFrom' => $dateFrom->format('Y-m-d'),
|
||||
'dateTo' => $dateTo->format('Y-m-d'),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
public function getPriceTableData(string $hotelCode, string $year): array
|
||||
{
|
||||
return $this->requestJson('GET', 'contingents/prices', [
|
||||
'query' => [
|
||||
'hotelCode' => $hotelCode,
|
||||
'year' => $year,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiException
|
||||
*/
|
||||
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
<T3DataStructure>
|
||||
<meta>
|
||||
<langDisable>1</langDisable>
|
||||
</meta>
|
||||
<sheets>
|
||||
<sDEF>
|
||||
<ROOT>
|
||||
<TCEforms>
|
||||
<sheetTitle>Konfiguration</sheetTitle>
|
||||
</TCEforms>
|
||||
<type>array</type>
|
||||
<el>
|
||||
<settings.runningCostsEUR>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Strom- und Entsorgungspauschale EUR</label>
|
||||
<config>
|
||||
<type>input</type>
|
||||
<default>2.5</default>
|
||||
<eval>double2,required</eval>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.runningCostsEUR>
|
||||
<settings.runningCostsCHF>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Strom- und Entsorgungspauschale CHF</label>
|
||||
<config>
|
||||
<type>input</type>
|
||||
<default>2.9</default>
|
||||
<eval>double2,required</eval>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.runningCostsCHF>
|
||||
<settings.undersubscription30EUR>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Unterbelegung 30-39 Personen EUR</label>
|
||||
<config>
|
||||
<type>input</type>
|
||||
<default>5.0</default>
|
||||
<eval>double2,required</eval>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.undersubscription30EUR>
|
||||
<settings.undersubscription30CHF>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Unterbelegung 30-39 Personen CHF</label>
|
||||
<config>
|
||||
<type>input</type>
|
||||
<default>5.0</default>
|
||||
<eval>double2,required</eval>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.undersubscription30CHF>
|
||||
<settings.undersubscription40EUR>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Unterbelegung 40-49 Personen EUR</label>
|
||||
<config>
|
||||
<type>input</type>
|
||||
<default>2.5</default>
|
||||
<eval>double2,required</eval>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.undersubscription40EUR>
|
||||
<settings.undersubscription40CHF>
|
||||
<TCEforms>
|
||||
<exclude>0</exclude>
|
||||
<label>Unterbelegung 40-49 Personen CHF</label>
|
||||
<config>
|
||||
<type>input</type>
|
||||
<default>2.5</default>
|
||||
<eval>double2,required</eval>
|
||||
</config>
|
||||
</TCEforms>
|
||||
</settings.undersubscription40CHF>
|
||||
</el>
|
||||
</ROOT>
|
||||
</sDEF>
|
||||
</sheets>
|
||||
</T3DataStructure>
|
||||
@@ -83,12 +83,6 @@ call_user_func(function () {
|
||||
'Hotel: Details'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'hotel_groups_price',
|
||||
'Hotel: Preiskalulator Gruppen'
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
|
||||
'EP.EpProducts',
|
||||
'hotel_detail_event',
|
||||
@@ -274,10 +268,4 @@ call_user_func(function () {
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_teammembers.xml'
|
||||
);
|
||||
|
||||
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist']['epproducts_hotel_groups_price'] = 'pi_flexform';
|
||||
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
|
||||
'epproducts_hotel_groups_price',
|
||||
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_groups_price_calculator.xml'
|
||||
);
|
||||
|
||||
});
|
||||
-2
@@ -30,8 +30,6 @@ return [
|
||||
--div--;Texte, teaser, description, features, room_types, additional_information,
|
||||
--div--;Verknüpfungen, facts, teamer, additional_codes, mappings,
|
||||
--div--;Bilder/Dateien, teaser_images, header_images, images, reseller_images,
|
||||
--div--;Gruppenhaus Preise, --palette--;;season,--palette--;;others, groups_price_configs,
|
||||
groups_price_boards, groups_price_options,
|
||||
--div--;Gruppenhaus Icons, --palette--;;icons',
|
||||
],
|
||||
],
|
||||
|
||||
@@ -48,6 +48,8 @@ plugin.tx_epproducts {
|
||||
groupsPriceToEmail = [email protected]
|
||||
# cat=epproducts/130/120; type=string; label=Email recipient for groups price inquiries
|
||||
groupsPriceToName = EP Reisen
|
||||
# cat=epproducts/130/130; type=string; label=Email recipient for groups price inquiries
|
||||
groupsBookingUrl = https://myep.ddev.site/groups/booking/init
|
||||
# cat=epproducts/140/100; type=string; label=Room types for pricetables (CSV)
|
||||
priceTableRoomTypes = 1,2,3,4,5,6,7,8,9,10
|
||||
# cat=epproducts/140/110; type=string; label=Ignore following IPs in searchlog
|
||||
|
||||
@@ -54,6 +54,7 @@ plugin.tx_epproducts {
|
||||
groupsPriceToEmail = {$plugin.tx_epproducts.settings.groupsPriceToEmail}
|
||||
groupsPriceToName = {$plugin.tx_epproducts.settings.groupsPriceToName}
|
||||
groupInquiryFormConceptUids = {$plugin.tx_epproducts.settings.groupInquiryFormConceptUids}
|
||||
groupsBookingUrl = {$plugin.tx_epproducts.settings.groupsBookingUrl}
|
||||
logoImage = {$plugin.tx_eptheme.settings.logoImage}
|
||||
themekey = {$plugin.tx_eptheme.settings.themekey}
|
||||
globalConceptCode = {$plugin.tx_eptheme.settings.globalConceptCode}
|
||||
@@ -173,6 +174,9 @@ tx_epproducts_ajax_json {
|
||||
}
|
||||
AjaxCalendar {
|
||||
1 = range
|
||||
2 = priceConfig
|
||||
3 = priceTable
|
||||
4 = priceCalendar
|
||||
}
|
||||
AjaxContingent {
|
||||
1 = list
|
||||
|
||||
@@ -149,14 +149,6 @@ $boot = function () {
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'hotel_groups_price',
|
||||
[
|
||||
'GroupsPrice' => 'index',
|
||||
]
|
||||
);
|
||||
|
||||
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
|
||||
'EP.ep_products',
|
||||
'hotel_detail_event',
|
||||
@@ -276,9 +268,8 @@ $boot = function () {
|
||||
'AjaxDate' => 'dates',
|
||||
'AjaxContingent' => 'list,rooms',
|
||||
'AjaxTable' => 'datestable,pricetable,pricetableHtml,eventPricetable,daytripRooms',
|
||||
'AjaxCalendar' => 'range,contingents,availableRooms',
|
||||
'AjaxCalendar' => 'range,priceConfig,priceCalendar,priceTable',
|
||||
'AjaxWatchlist' => 'list',
|
||||
'AjaxGroupsPrice' => 'processForm',
|
||||
'AjaxTeaserPopup' => 'concept',
|
||||
],
|
||||
[
|
||||
@@ -287,9 +278,8 @@ $boot = function () {
|
||||
'AjaxDate' => 'dates',
|
||||
'AjaxContingent' => 'list,rooms',
|
||||
'AjaxTable' => 'datestable,pricetable,pricetableHtml,eventPricetable,daytripRooms',
|
||||
'AjaxCalendar' => 'range,contingents,availableRooms',
|
||||
'AjaxCalendar' => 'range,priceConfig,priceCalendar,priceTable',
|
||||
'AjaxWatchlist' => 'list',
|
||||
'AjaxGroupsPrice' => 'processForm',
|
||||
'AjaxTeaserPopup' => 'concept',
|
||||
]
|
||||
);
|
||||
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
import { Controller } from '@hotwired/stimulus'
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
static targets = ['mount', 'error', 'message', 'button', 'resetButton', 'day', 'month', 'prevButton', 'nextButton']
|
||||
|
||||
static values = {
|
||||
hotelCode: String,
|
||||
groupsBookingUrl: String,
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.startDate = null
|
||||
this.endDate = null
|
||||
this.currentIndex = 0
|
||||
|
||||
// mountTarget carries hx-get, so HTMX fires its events there; listening here
|
||||
// scopes to this calendar instance and avoids catching events from other HTMX elements.
|
||||
this.mountTarget.addEventListener('htmx:afterSwap', () => {
|
||||
this.showMonths(0)
|
||||
this.showButton()
|
||||
})
|
||||
this.mountTarget.addEventListener('htmx:responseError', () => this.showError())
|
||||
}
|
||||
|
||||
showMonths(startIndex) {
|
||||
this.currentIndex = startIndex
|
||||
this.monthTargets.forEach((m, i) => {
|
||||
m.classList.toggle('hidden', i < startIndex || i >= startIndex + 2)
|
||||
})
|
||||
if (this.hasPrevButtonTarget) this.prevButtonTarget.disabled = startIndex === 0
|
||||
if (this.hasNextButtonTarget) this.nextButtonTarget.disabled = startIndex >= this.monthTargets.length - 2
|
||||
}
|
||||
|
||||
prevMonths() {
|
||||
this.showMonths(Math.max(0, this.currentIndex - 1))
|
||||
}
|
||||
|
||||
nextMonths() {
|
||||
this.showMonths(Math.min(this.currentIndex + 1, this.monthTargets.length - 2))
|
||||
}
|
||||
|
||||
selectDate(event) {
|
||||
const btn = event.currentTarget
|
||||
// cooltipz shows on :focus as well as :hover; blurring dismisses it after a click.
|
||||
btn.blur()
|
||||
const date = btn.dataset.date
|
||||
const status = btn.dataset.status
|
||||
|
||||
// All day buttons carry data-action for template simplicity; non-selectable ones are filtered here.
|
||||
if (!status || status === 'blocked') return
|
||||
|
||||
if (this.startDate && this.endDate) {
|
||||
this.resetSelection()
|
||||
}
|
||||
|
||||
if (!this.startDate) {
|
||||
// checkout-only days allow departure but not arrival
|
||||
if (status === 'checkout-only') {
|
||||
this.showMessage('Bitte wähle einen Anreisetag.')
|
||||
return
|
||||
}
|
||||
this.startDate = date
|
||||
this.endDate = null
|
||||
this.updateDisplay()
|
||||
this.showMessage('Bitte wähle das Abreisedatum.')
|
||||
this.disableButton()
|
||||
return
|
||||
}
|
||||
|
||||
if (date === this.startDate) {
|
||||
this.resetSelection()
|
||||
return
|
||||
}
|
||||
|
||||
// Normalize so from < to regardless of which date the user clicked first.
|
||||
const [from, to] = date < this.startDate ? [date, this.startDate] : [this.startDate, date]
|
||||
|
||||
if (this.hasBlockedInRange(from, to)) {
|
||||
this.resetSelection()
|
||||
this.showMessage('Dieser Zeitraum enthält nicht verfügbare Daten.')
|
||||
return
|
||||
}
|
||||
|
||||
const startBtn = this.dayTargets.find(b => b.dataset.date === from)
|
||||
const minNights = parseInt(startBtn?.dataset.minNights) || 0
|
||||
const nights = (new Date(to) - new Date(from)) / 86400000 // ms → days
|
||||
|
||||
// Short-stay warning is advisory only; the booking link is still enabled below.
|
||||
if (minNights > 0 && nights < minNights) {
|
||||
this.showMessage(`Weniger als ${minNights} Nächte nur auf Anfrage.`)
|
||||
} else {
|
||||
this.hideMessage()
|
||||
}
|
||||
|
||||
this.startDate = from
|
||||
this.endDate = to
|
||||
this.updateDisplay()
|
||||
this.enableButton(from, to)
|
||||
this.dispatch('range-select', { detail: { dateFrom: from, dateTo: to } })
|
||||
}
|
||||
|
||||
hasBlockedInRange(from, to) {
|
||||
for (const btn of this.dayTargets) {
|
||||
const d = btn.dataset.date
|
||||
// End date is exclusive: guests may check out of a blocked day, so it is not a hard blocker.
|
||||
if (d >= from && d < to && btn.dataset.status === 'blocked') return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
updateDisplay() {
|
||||
for (const btn of this.dayTargets) {
|
||||
const d = btn.dataset.date
|
||||
btn.classList.remove('pc-day--pending-start', 'pc-day--selected-start', 'pc-day--selected-end', 'pc-day--in-range')
|
||||
if (!this.startDate) continue
|
||||
if (d === this.startDate) {
|
||||
btn.classList.add(this.endDate ? 'pc-day--selected-start' : 'pc-day--pending-start')
|
||||
} else if (this.endDate) {
|
||||
if (d === this.endDate) btn.classList.add('pc-day--selected-end')
|
||||
else if (d > this.startDate && d < this.endDate) btn.classList.add('pc-day--in-range')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetSelection() {
|
||||
this.startDate = null
|
||||
this.endDate = null
|
||||
this.updateDisplay()
|
||||
this.hideMessage()
|
||||
this.disableButton()
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.resetSelection()
|
||||
}
|
||||
|
||||
showButton() {
|
||||
if (this.hasButtonTarget) this.buttonTarget.classList.remove('hidden')
|
||||
}
|
||||
|
||||
enableButton(dateFrom, dateTo) {
|
||||
if (!this.hasButtonTarget) return
|
||||
const params = new URLSearchParams({
|
||||
hotel_code: this.hotelCodeValue,
|
||||
date_from: dateFrom,
|
||||
date_to: dateTo,
|
||||
})
|
||||
this.buttonTarget.href = `${this.groupsBookingUrlValue}?${params}`
|
||||
this.buttonTarget.textContent = `${this.formatDate(dateFrom)}–${this.formatDate(dateTo)} Anfragen / Buchen`
|
||||
this.buttonTarget.classList.remove('opacity-50', 'cursor-not-allowed', 'pointer-events-none')
|
||||
if (this.hasResetButtonTarget) this.resetButtonTarget.classList.remove('hidden')
|
||||
}
|
||||
|
||||
disableButton() {
|
||||
if (!this.hasButtonTarget) return
|
||||
this.buttonTarget.removeAttribute('href')
|
||||
this.buttonTarget.textContent = 'Anfragen / Buchen'
|
||||
this.buttonTarget.classList.add('opacity-50', 'cursor-not-allowed', 'pointer-events-none')
|
||||
if (this.hasResetButtonTarget) this.resetButtonTarget.classList.add('hidden')
|
||||
}
|
||||
|
||||
formatDate(iso) {
|
||||
const [y, m, d] = iso.split('-')
|
||||
return `${d}.${m}.${y.slice(2)}`
|
||||
}
|
||||
|
||||
showMessage(text) {
|
||||
if (this.hasMessageTarget) {
|
||||
this.messageTarget.textContent = text
|
||||
}
|
||||
}
|
||||
|
||||
hideMessage() {
|
||||
if (this.hasMessageTarget) {
|
||||
this.messageTarget.textContent = ''
|
||||
}
|
||||
}
|
||||
|
||||
showError() {
|
||||
if (this.hasErrorTarget) {
|
||||
this.errorTarget.classList.remove('hidden')
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-6
@@ -1,5 +1,4 @@
|
||||
import { Controller } from '@hotwired/stimulus'
|
||||
import { useDispatch } from 'stimulus-use'
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
@@ -9,10 +8,6 @@ export default class extends Controller {
|
||||
|
||||
static values = { activeTab: String }
|
||||
|
||||
initialize() {
|
||||
useDispatch(this)
|
||||
}
|
||||
|
||||
connect() {
|
||||
this.activeTabValue = this.tabTargets[0].dataset.tab
|
||||
}
|
||||
@@ -20,7 +15,8 @@ export default class extends Controller {
|
||||
select(e) {
|
||||
let selectedTab = e.currentTarget.dataset.tab
|
||||
this.activeTabValue = selectedTab
|
||||
this.dispatch('selected', selectedTab)
|
||||
this.dispatch('selected', { detail: selectedTab })
|
||||
this.dispatch('tab-' + selectedTab)
|
||||
}
|
||||
|
||||
activeTabValueChanged() {
|
||||
|
||||
@@ -44,6 +44,47 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Price calendar (hand-rolled)
|
||||
.pc-loading-indicator {
|
||||
display: none;
|
||||
|
||||
&.htmx-request {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.pc-day {
|
||||
@apply relative w-full text-center py-1 px-0.5 text-sm leading-tight rounded text-white cursor-pointer;
|
||||
|
||||
// Status colors — [data-status] attribute adds specificity (0,2,0)
|
||||
&[data-status="ok"] {
|
||||
@apply bg-emerald-500;
|
||||
}
|
||||
&[data-status="blocked-to-ok"] {
|
||||
background: linear-gradient(to bottom right, theme('colors.gray.400') 50%, theme('colors.emerald.500') 50%);
|
||||
}
|
||||
&[data-status="checkout-only"] {
|
||||
background: linear-gradient(to bottom right, theme('colors.emerald.500') 50%, theme('colors.gray.400') 50%);
|
||||
}
|
||||
&[data-status="blocked"] {
|
||||
@apply bg-gray-400 cursor-default;
|
||||
}
|
||||
&[data-status=""], &:not([data-status]) {
|
||||
@apply text-gray-400 cursor-default;
|
||||
}
|
||||
|
||||
// Compound selector gives (0,2,0) specificity, matching [data-status] rules; source order wins.
|
||||
&.pc-day--pending-start,
|
||||
&.pc-day--selected-start,
|
||||
&.pc-day--selected-end {
|
||||
@apply bg-none outline-none bg-ep-secondary text-gray-700;
|
||||
}
|
||||
|
||||
&.pc-day--in-range {
|
||||
@apply bg-none bg-ep-secondary text-gray-700 opacity-55;
|
||||
}
|
||||
}
|
||||
|
||||
// Maps
|
||||
@import "~leaflet/dist/leaflet.css";
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<html data-namespace-typo3-fluid="true" lang="en"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers"
|
||||
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers">
|
||||
|
||||
<div data-controller="price-calendar"
|
||||
data-price-calendar-hotel-code-value="{product.calendarHotel.code}"
|
||||
data-price-calendar-groups-booking-url-value="{settings.groupsBookingUrl}"
|
||||
class="relative p-4 bg-zinc-50">
|
||||
<div class="pc-loading-indicator items-center justify-center space-x-4 text-sm p-4"
|
||||
id="pc-loading-{product.calendarHotel.uid}">
|
||||
<f:image class="block w-4 h-4" src="EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif" alt=""/>
|
||||
<span>Preiskalender wird geladen …</span>
|
||||
</div>
|
||||
<div data-price-calendar-target="mount"
|
||||
hx-get="{ep:uri.ajax(action: 'priceCalendar', controller: 'AjaxCalendar', extensionName: 'epproducts', pageUid: settings.defaultAjaxUid, arguments: '{hotel: product.calendarHotel}', format: 'html')}"
|
||||
hx-trigger="load"
|
||||
hx-indicator="#pc-loading-{product.calendarHotel.uid}">
|
||||
</div>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="h-8 text-sm" data-price-calendar-target="message"></div>
|
||||
<div class="h-8 text-sm text-right">
|
||||
<button type="button"
|
||||
class="hidden underline"
|
||||
data-price-calendar-target="resetButton"
|
||||
data-action="click->price-calendar#reset">
|
||||
Auswahl zurücksetzen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<a class="hidden button bg-button w-full mt-2 opacity-50 cursor-not-allowed pointer-events-none"
|
||||
data-price-calendar-target="button"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
Anfragen / Buchen
|
||||
</a>
|
||||
<div class="hidden p-4 text-sm text-red-600" data-price-calendar-target="error">
|
||||
Der Kalender konnte aktuell nicht geladen werden.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</html>
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
<html data-namespace-typo3-fluid="true" lang="en"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
|
||||
|
||||
<f:if condition="{error}">
|
||||
<f:then>
|
||||
<div class="p-4 text-sm text-red-600">
|
||||
Der Kalender konnte aktuell nicht geladen werden.
|
||||
</div>
|
||||
<div class="hidden" data-price-calendar-error-detail>{errorMessage}</div>
|
||||
</f:then>
|
||||
<f:else>
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<button type="button" class="px-3 py-1 text-sm bg-zinc-100 hover:bg-zinc-200 rounded transition-colors disabled:opacity-40 disabled:cursor-default disabled:pointer-events-none"
|
||||
data-price-calendar-target="prevButton"
|
||||
data-action="click->price-calendar#prevMonths"
|
||||
disabled>← früher</button>
|
||||
<button type="button" class="px-3 py-1 text-sm bg-zinc-100 hover:bg-zinc-200 rounded transition-colors disabled:opacity-40 disabled:cursor-default disabled:pointer-events-none"
|
||||
data-price-calendar-target="nextButton"
|
||||
data-action="click->price-calendar#nextMonths">später →</button>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<f:for each="{calendarMonths}" as="month" iteration="i">
|
||||
<div data-month-index="{i.index}" data-price-calendar-target="month">
|
||||
<div class="font-semibold text-center py-2 text-zinc-700">
|
||||
<f:format.date format="%B %Y">{month.date}</f:format.date>
|
||||
</div>
|
||||
<table class="w-full border-collapse">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="py-1 text-center text-xs text-zinc-500 font-normal">Mo</th>
|
||||
<th class="py-1 text-center text-xs text-zinc-500 font-normal">Di</th>
|
||||
<th class="py-1 text-center text-xs text-zinc-500 font-normal">Mi</th>
|
||||
<th class="py-1 text-center text-xs text-zinc-500 font-normal">Do</th>
|
||||
<th class="py-1 text-center text-xs text-zinc-500 font-normal">Fr</th>
|
||||
<th class="py-1 text-center text-xs text-zinc-500 font-normal">Sa</th>
|
||||
<th class="py-1 text-center text-xs text-zinc-500 font-normal">So</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<f:for each="{month.weeks}" as="week">
|
||||
<tr>
|
||||
<f:for each="{week}" as="day">
|
||||
<td class="p-px">
|
||||
<f:if condition="{day.inMonth}">
|
||||
<f:then>
|
||||
<f:variable name="dateKey" value="{f:format.date(format: 'Y-m-d', date: day.date)}"/>
|
||||
<f:variable name="dayData" value="{priceDataByDate.{dateKey}}"/>
|
||||
<button type="button"
|
||||
class="pc-day"
|
||||
data-price-calendar-target="day"
|
||||
data-action="click->price-calendar#selectDate"
|
||||
data-date="{dateKey}"
|
||||
data-status="{dayData.status}"
|
||||
data-min-nights="{dayData.minNights}"
|
||||
<f:if condition="{dayData.tooltip}">aria-label="{dayData.tooltip}" data-cooltipz-dir="top"</f:if>>
|
||||
{f:format.date(format: 'j', date: day.date)}
|
||||
</button>
|
||||
</f:then>
|
||||
<f:else>
|
||||
<div class="pc-day"> </div>
|
||||
</f:else>
|
||||
</f:if>
|
||||
</td>
|
||||
</f:for>
|
||||
</tr>
|
||||
</f:for>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</f:for>
|
||||
</div>
|
||||
</f:else>
|
||||
</f:if>
|
||||
|
||||
</html>
|
||||
+1
@@ -0,0 +1 @@
|
||||
{priceConfig -> f:format.json() ->f:format.raw()}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
<html data-namespace-typo3-fluid="true" lang="en"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
|
||||
|
||||
<f:if condition="{priceTable.success} && {priceTable.data -> f:count()}">
|
||||
<div class="w-full overflow-x-auto mb-4">
|
||||
<h3 class="font-bold mt-4 mb-2">
|
||||
Preise {year}
|
||||
</h3>
|
||||
<table class="w-full mb-4 bg-zinc-200">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="border-r border-white/50 px-2 py-1 md:p-2 text-left text-sm md:text-base" scope="col">
|
||||
von
|
||||
</th>
|
||||
<th class="border-r border-white/50 px-2 py-1 md:p-2 text-left text-sm md:text-base" scope="col">
|
||||
bis
|
||||
</th>
|
||||
<th class="border-r border-white/50 px-2 py-1 md:p-2 text-left text-sm md:text-base" scope="col">
|
||||
Saison
|
||||
</th>
|
||||
<th class="border-r border-white/50 px-2 py-1 md:p-2 text-right text-sm md:text-base" scope="col">
|
||||
Pax bis
|
||||
</th>
|
||||
<th class="border-r border-white/50 px-2 py-1 md:p-2 text-right text-sm md:text-base" scope="col">
|
||||
Mindestmiete pro Nacht
|
||||
</th>
|
||||
<th class="px-2 py-1 md:p-2 text-right text-sm md:text-base" scope="col">
|
||||
weitere Personen pro Nacht
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<f:for each="{priceTable.data}" as="row">
|
||||
<tr class="odd:bg-zinc-50 hover:bg-zinc-100 odd:hover:bg-zinc-100">
|
||||
<td class="border-r border-zinc-200 px-2 py-1 md:p-2 text-sm md:text-base">
|
||||
{row.dateFrom -> f:format.date(format: 'd.m.Y')}
|
||||
</td>
|
||||
<td class="border-r border-zinc-200 px-2 py-1 md:p-2 text-sm md:text-base">
|
||||
{row.dateTo -> f:format.date(format: 'd.m.Y')}
|
||||
</td>
|
||||
<td class="border-r border-zinc-200 px-2 py-1 md:p-2 text-sm md:text-base">
|
||||
<f:switch expression="{row.season}">
|
||||
<f:case value="adv_secondary">VNS</f:case>
|
||||
<f:case value="secondary">NS</f:case>
|
||||
<f:case value="peak">HS</f:case>
|
||||
<f:defaultCase>{row.season}</f:defaultCase>
|
||||
</f:switch>
|
||||
</td>
|
||||
<td class="border-r border-zinc-200 px-2 py-1 md:p-2 text-right text-sm md:text-base">
|
||||
{row.includedPax}
|
||||
</td>
|
||||
<td class="border-r border-zinc-200 px-2 py-1 md:p-2 text-right text-sm md:text-base">
|
||||
<f:if condition="{row.type} == 'discount'">
|
||||
<f:then>
|
||||
<f:if condition="{row.defaultPricePerNight}">
|
||||
<span class="line-through text-zinc-400 mr-1">{row.defaultPricePerNight -> f:format.currency(currencySign: row.currency)}</span>
|
||||
</f:if>
|
||||
{row.pricePerNight -> f:format.currency(currencySign: row.currency)}
|
||||
</f:then>
|
||||
<f:else>
|
||||
{row.pricePerNight -> f:format.currency(currencySign: row.currency)}
|
||||
</f:else>
|
||||
</f:if>
|
||||
</td>
|
||||
<td class="px-2 py-1 md:p-2 text-right text-sm md:text-base">
|
||||
{row.priceAdditionalPerson -> f:format.currency(currencySign: row.currency)}
|
||||
</td>
|
||||
</tr>
|
||||
</f:for>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
VNS = Vorteils-Nebensaison, NS = Nebensaison, HS = Hauptsaison
|
||||
</div>
|
||||
</div>
|
||||
</f:if>
|
||||
|
||||
</html>
|
||||
+1
-1
@@ -19,7 +19,7 @@
|
||||
</f:section>
|
||||
|
||||
<f:section name="Table">
|
||||
<div class="w-full max-w-full overflow-x-scroll md:overflow-x-auto">
|
||||
<div class="w-full max-w-full overflow-x-auto">
|
||||
<table class="min-w-full border border-zinc-200 border-collapse mb-2">
|
||||
<f:for each="{categories}" as="category" key="categoryKey">
|
||||
<f:if condition="{v:variable.get(name: 'pricetable.{categoryKey}', useRawKeys: 1) -> f:count()} > 0">
|
||||
|
||||
@@ -37,40 +37,20 @@
|
||||
<div id="main" class="w-full lg:w-2/3">
|
||||
<div class="lg:pr-4 flex flex-col space-y-8">
|
||||
<div class="grid grid-cols-3 md:grid-cols-6 gap-px uppercase text-white text-sm md:text-base">
|
||||
<f:if condition="{settings.hotelOnTop}">
|
||||
<f:then>
|
||||
<button type="button"
|
||||
data-action="tabs#select"
|
||||
data-tabs-target="button"
|
||||
data-tab="hotel"
|
||||
class="py-2 uppercase bg-button bg-button--dark">
|
||||
Unterkunft
|
||||
</button>
|
||||
<button type="button"
|
||||
data-action="tabs#select"
|
||||
data-tabs-target="button"
|
||||
data-tab="dates"
|
||||
class="col-span-2 py-2 uppercase bg-button bg-button--dark">
|
||||
Termine/Preise
|
||||
</button>
|
||||
</f:then>
|
||||
<f:else>
|
||||
<button type="button"
|
||||
data-action="tabs#select"
|
||||
data-tabs-target="button"
|
||||
data-tab="dates"
|
||||
class="col-span-2 py-2 uppercase bg-button bg-button--dark">
|
||||
Termine/Preise
|
||||
</button>
|
||||
<button type="button"
|
||||
data-action="tabs#select"
|
||||
data-tabs-target="button"
|
||||
data-tab="hotel"
|
||||
class="py-2 uppercase bg-button bg-button--dark">
|
||||
Unterkunft
|
||||
</button>
|
||||
</f:else>
|
||||
</f:if>
|
||||
<button type="button"
|
||||
data-action="tabs#select"
|
||||
data-tabs-target="button"
|
||||
data-tab="dates"
|
||||
class="col-span-2 py-2 uppercase bg-button bg-button--dark">
|
||||
Termine/Preise
|
||||
</button>
|
||||
<button type="button"
|
||||
data-action="tabs#select"
|
||||
data-tabs-target="button"
|
||||
data-tab="hotel"
|
||||
class="py-2 uppercase bg-button bg-button--dark">
|
||||
Unterkunft
|
||||
</button>
|
||||
<button type="button"
|
||||
data-action="tabs#select"
|
||||
data-tabs-target="button"
|
||||
@@ -95,16 +75,8 @@
|
||||
</button>
|
||||
</f:if>
|
||||
</div>
|
||||
<f:if condition="{settings.hotelOnTop}">
|
||||
<f:then>
|
||||
<f:render section="Hotel" arguments="{_all}"/>
|
||||
<f:render section="Dates" arguments="{_all}"/>
|
||||
</f:then>
|
||||
<f:else>
|
||||
<f:render section="Dates" arguments="{_all}"/>
|
||||
<f:render section="Hotel" arguments="{_all}"/>
|
||||
</f:else>
|
||||
</f:if>
|
||||
<f:render section="Dates" arguments="{_all}"/>
|
||||
<f:render section="Hotel" arguments="{_all}"/>
|
||||
<f:render section="City" arguments="{_all}"/>
|
||||
<f:render section="Region" arguments="{_all}"/>
|
||||
<f:render section="Journey" arguments="{_all}"/>
|
||||
@@ -123,14 +95,32 @@
|
||||
</f:section>
|
||||
|
||||
<f:section name="Dates">
|
||||
<div class="mb-4{f:if(condition: settings.hotelOnTop, then: ' hidden')}"
|
||||
<div class="mb-4"
|
||||
data-tabs-target="tab"
|
||||
data-tab="dates">
|
||||
|
||||
<f:if condition="{hotel.groupsPriceConfigs} && {nonBookableInfo}">
|
||||
<div class="alert alert-info mb-4" data-rte-content>
|
||||
{nonBookableInfo.text -> f:format.html()}
|
||||
</div>
|
||||
</f:if>
|
||||
|
||||
<f:if condition="{product.calendarHotel}">
|
||||
<f:render partial="Product/PriceCalendar.html" arguments="{_all}"/>
|
||||
|
||||
<f:variable name="currentYear" value="{f:format.date(date: 'now', format: 'Y')}"/>
|
||||
<div hx-get="{ep:uri.ajax(action: 'priceTable', controller: 'AjaxCalendar', extensionName: 'epproducts', pageUid: settings.defaultAjaxUid, arguments: '{hotel: product.calendarHotel, year: currentYear}', format: 'html')}"
|
||||
hx-trigger="load">
|
||||
<f:render section="TableLoadingIndicator"/>
|
||||
</div>
|
||||
|
||||
<f:variable name="nextYear" value="{f:format.date(date: '+1 year', format: 'Y')}"/>
|
||||
<div hx-get="{ep:uri.ajax(action: 'priceTable', controller: 'AjaxCalendar', extensionName: 'epproducts', pageUid: settings.defaultAjaxUid, arguments: '{hotel: product.calendarHotel, year: nextYear}', format: 'html')}"
|
||||
hx-trigger="load">
|
||||
<f:render section="TableLoadingIndicator"/>
|
||||
</div>
|
||||
</f:if>
|
||||
|
||||
<f:if condition="{isProductWithExcludedConcept}">
|
||||
<f:if condition="{product.region.season} == 'w'">
|
||||
<div class="bg-ep-primary-light text-white p-4">
|
||||
@@ -146,6 +136,7 @@
|
||||
</div>
|
||||
</f:if>
|
||||
</f:if>
|
||||
|
||||
<f:if condition="{product.daytrip}">
|
||||
<f:then>
|
||||
<f:render section="DaytripDateSelect" arguments="{_all}"/>
|
||||
@@ -164,17 +155,19 @@
|
||||
<div class="hidden" data-product-details-target="priceTableContainer"></div>
|
||||
</f:else>
|
||||
</f:if>
|
||||
|
||||
<div class="lg:hidden">
|
||||
<f:render section="SidebarGallery" arguments="{_all}"/>
|
||||
<f:render section="SidebarButtons" arguments="{_all}"/>
|
||||
</div>
|
||||
|
||||
<f:render partial="Product/Details" arguments="{_all}"/>
|
||||
</div>
|
||||
</f:section>
|
||||
|
||||
<f:section name="Hotel">
|
||||
|
||||
<div class="mb-4{f:if(condition: settings.hotelOnTop, else: ' hidden')}"
|
||||
<div class="mb-4 hidden"
|
||||
data-tabs-target="tab"
|
||||
data-tab="hotel">
|
||||
<f:render partial="Hotel/Details" arguments="{hotel: hotel, bars: 1, showNonBookableHint: 0, currentPageUid: currentPageUid, showInquiryForm: isProductWithGroupInquiryForm}"/>
|
||||
@@ -209,7 +202,6 @@
|
||||
|
||||
<f:section name="Sidebar">
|
||||
<f:render section="SidebarGallery" arguments="{_all}"/>
|
||||
<f:render section="Calendar" arguments="{_all}"/>
|
||||
<f:if condition="{product.tourLink}">
|
||||
<div class="bg-zinc-50 p-4 mb-4"
|
||||
data-controller="lightbox">
|
||||
@@ -468,4 +460,10 @@
|
||||
</f:if>
|
||||
</f:section>
|
||||
|
||||
<f:section name="TableLoadingIndicator">
|
||||
<div class="flex items-center justify-center space-x-4 text-sm p-4">
|
||||
<f:image class="block w-4 h-4" src="EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif" alt=""/>
|
||||
<span>Preistabelle wird geladen …</span>
|
||||
</div>
|
||||
</f:section>
|
||||
</html>
|
||||
Reference in new issue
Block a user