Merge branch 'develop' into feature/sass-remove

This commit is contained in:
Björn Fromme
2022-08-22 21:17:48 +02:00
28 changed files with 760 additions and 531 deletions
Generated
+13 -13
View File
@@ -8857,23 +8857,23 @@
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
"version": "9.2.15", "version": "9.2.16",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f" "reference": "2593003befdcc10db5e213f9f28814f5aa8ac073"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2e9da11878c4202f97915c1cb4bb1ca318a63f5f", "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/2593003befdcc10db5e213f9f28814f5aa8ac073",
"reference": "2e9da11878c4202f97915c1cb4bb1ca318a63f5f", "reference": "2593003befdcc10db5e213f9f28814f5aa8ac073",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-dom": "*", "ext-dom": "*",
"ext-libxml": "*", "ext-libxml": "*",
"ext-xmlwriter": "*", "ext-xmlwriter": "*",
"nikic/php-parser": "^4.13.0", "nikic/php-parser": "^4.14",
"php": ">=7.3", "php": ">=7.3",
"phpunit/php-file-iterator": "^3.0.3", "phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-text-template": "^2.0.2", "phpunit/php-text-template": "^2.0.2",
@@ -8922,7 +8922,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.15" "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.16"
}, },
"funding": [ "funding": [
{ {
@@ -8930,7 +8930,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2022-03-07T09:28:20+00:00" "time": "2022-08-20T05:26:47+00:00"
}, },
{ {
"name": "phpunit/php-file-iterator", "name": "phpunit/php-file-iterator",
@@ -9175,16 +9175,16 @@
}, },
{ {
"name": "phpunit/phpunit", "name": "phpunit/phpunit",
"version": "9.5.21", "version": "9.5.22",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git", "url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1" "reference": "e329ac6e8744f461518272612a479fde958752fe"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0e32b76be457de00e83213528f6bb37e2a38fcb1", "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e329ac6e8744f461518272612a479fde958752fe",
"reference": "0e32b76be457de00e83213528f6bb37e2a38fcb1", "reference": "e329ac6e8744f461518272612a479fde958752fe",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -9261,7 +9261,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues", "issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.21" "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.22"
}, },
"funding": [ "funding": [
{ {
@@ -9273,7 +9273,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2022-06-19T12:14:25+00:00" "time": "2022-08-20T08:25:46+00:00"
}, },
{ {
"name": "pimple/pimple", "name": "pimple/pimple",
-27
View File
@@ -27,7 +27,6 @@
"stimulus-use": "^0.25.4", "stimulus-use": "^0.25.4",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-router": "^3.5.2", "vue-router": "^3.5.2",
"vue-scrollto": "^2.20.0",
"vue-session": "^1.0.0", "vue-session": "^1.0.0",
"vuex": "^3.6.2", "vuex": "^3.6.2",
"whatwg-fetch": "^3.6.2" "whatwg-fetch": "^3.6.2"
@@ -2773,11 +2772,6 @@
"integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
"dev": true "dev": true
}, },
"node_modules/bezier-easing": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz",
"integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig=="
},
"node_modules/big.js": { "node_modules/big.js": {
"version": "5.2.2", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -8175,14 +8169,6 @@
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.4.tgz", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.4.tgz",
"integrity": "sha512-x+/DLAJZv2mcQ7glH2oV9ze8uPwcI+H+GgTgTmb5I55bCgY3+vXWIsqbYUzbBSZnwFHEJku4eoaH/x98veyymQ==" "integrity": "sha512-x+/DLAJZv2mcQ7glH2oV9ze8uPwcI+H+GgTgTmb5I55bCgY3+vXWIsqbYUzbBSZnwFHEJku4eoaH/x98veyymQ=="
}, },
"node_modules/vue-scrollto": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/vue-scrollto/-/vue-scrollto-2.20.0.tgz",
"integrity": "sha512-7i+AGKJTThZnMEkhIPgrZjyAX+fXV7/rGdg+CV283uZZwCxwiMXaBLTmIc5RTA4uwGnT+E6eJle3mXQfM2OD3A==",
"dependencies": {
"bezier-easing": "2.1.0"
}
},
"node_modules/vue-session": { "node_modules/vue-session": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/vue-session/-/vue-session-1.0.0.tgz", "resolved": "https://registry.npmjs.org/vue-session/-/vue-session-1.0.0.tgz",
@@ -10777,11 +10763,6 @@
"integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
"dev": true "dev": true
}, },
"bezier-easing": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz",
"integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig=="
},
"big.js": { "big.js": {
"version": "5.2.2", "version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -14702,14 +14683,6 @@
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.4.tgz", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.5.4.tgz",
"integrity": "sha512-x+/DLAJZv2mcQ7glH2oV9ze8uPwcI+H+GgTgTmb5I55bCgY3+vXWIsqbYUzbBSZnwFHEJku4eoaH/x98veyymQ==" "integrity": "sha512-x+/DLAJZv2mcQ7glH2oV9ze8uPwcI+H+GgTgTmb5I55bCgY3+vXWIsqbYUzbBSZnwFHEJku4eoaH/x98veyymQ=="
}, },
"vue-scrollto": {
"version": "2.20.0",
"resolved": "https://registry.npmjs.org/vue-scrollto/-/vue-scrollto-2.20.0.tgz",
"integrity": "sha512-7i+AGKJTThZnMEkhIPgrZjyAX+fXV7/rGdg+CV283uZZwCxwiMXaBLTmIc5RTA4uwGnT+E6eJle3mXQfM2OD3A==",
"requires": {
"bezier-easing": "2.1.0"
}
},
"vue-session": { "vue-session": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/vue-session/-/vue-session-1.0.0.tgz", "resolved": "https://registry.npmjs.org/vue-session/-/vue-session-1.0.0.tgz",
-1
View File
@@ -30,7 +30,6 @@
"stimulus-use": "^0.25.4", "stimulus-use": "^0.25.4",
"vue": "^2.6.14", "vue": "^2.6.14",
"vue-router": "^3.5.2", "vue-router": "^3.5.2",
"vue-scrollto": "^2.20.0",
"vue-session": "^1.0.0", "vue-session": "^1.0.0",
"vuex": "^3.6.2", "vuex": "^3.6.2",
"whatwg-fetch": "^3.6.2" "whatwg-fetch": "^3.6.2"
@@ -83,7 +83,7 @@ class ConceptController extends ActionController
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids'], true); $excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids'], true);
$limit = $this->settings['showMoreLink'] ? 4 : 0; $limit = $this->settings['showMoreLink'] ? 4 : 0;
$teasers = $this->productDataService->getTeasergroup($filterSettings, $excludedConceptUids, $limit); $teasers = $this->productDataService->getTeasergroup($filterSettings, $excludedConceptUids, $limit);
$pages = $this->pageRepository->findPagesByPid($this->settings['conceptsPageUid']); $pages = $this->pageRepository->findPagesByPid((int)$this->settings['conceptsPageUid']);
$data = $this->configurationManager->getContentObject()->data; $data = $this->configurationManager->getContentObject()->data;
$this->view->assignMultiple([ $this->view->assignMultiple([
@@ -41,6 +41,7 @@ class GroupsPriceController extends ActionController
}); });
$this->view->assign('hotel', $hotel); $this->view->assign('hotel', $hotel);
$this->view->assign('runningCosts', $this->settings['runningCosts']);
$this->view->assign('configs', json_encode(array_values($configs), JSON_HEX_APOS)); $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('boards', json_encode($hotel->getGroupsPriceBoards()->toArray(), JSON_HEX_APOS));
$this->view->assign('options', json_encode($hotel->getGroupsPriceOptions()->toArray(), JSON_HEX_APOS)); $this->view->assign('options', json_encode($hotel->getGroupsPriceOptions()->toArray(), JSON_HEX_APOS));
@@ -90,6 +90,11 @@ class Concept extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity implements
*/ */
protected $headerImages; protected $headerImages;
/**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
*/
protected $images;
/** /**
* @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Product> * @var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\EP\EpProducts\Domain\Model\Product>
*/ */
@@ -110,6 +115,7 @@ class Concept extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity implements
$this->products = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); $this->products = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->teaserImages = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); $this->teaserImages = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->headerImages = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage(); $this->headerImages = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
$this->images = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
} }
/** /**
@@ -326,6 +332,22 @@ class Concept extends \TYPO3\CMS\Extbase\DomainObject\AbstractEntity implements
$this->headerImages = $headerImages; $this->headerImages = $headerImages;
} }
/**
* @return \TYPO3\CMS\Extbase\Persistence\ObjectStorage
*/
public function getImages()
{
return $this->images;
}
/**
* @param \TYPO3\CMS\Extbase\Persistence\ObjectStorage $images
*/
public function setImages($images)
{
$this->images = $images;
}
/** /**
* @param \EP\EpProducts\Domain\Model\Product $product * @param \EP\EpProducts\Domain\Model\Product $product
*/ */
@@ -0,0 +1,28 @@
<T3DataStructure>
<meta>
<langDisable>1</langDisable>
</meta>
<sheets>
<sDEF>
<ROOT>
<TCEforms>
<sheetTitle>Konfiguration</sheetTitle>
</TCEforms>
<type>array</type>
<el>
<settings.runningCosts>
<TCEforms>
<exclude>0</exclude>
<label>Strom- und Entsorgungspauschale</label>
<config>
<type>input</type>
<default>1.7</default>
<eval>double2,required</eval>
</config>
</TCEforms>
</settings.runningCosts>
</el>
</ROOT>
</sDEF>
</sheets>
</T3DataStructure>
@@ -262,4 +262,10 @@ call_user_func(function () {
'FILE:EXT:ep_products/Configuration/FlexForms/flexform_teammembers.xml' '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'
);
}); });
@@ -24,8 +24,8 @@ return [
], ],
'types' => [ 'types' => [
'1' => [ '1' => [
'showitem' => '--palette--;;top, --palette--;;naming, --palette--;;header, teaser, description, description_extended, 'showitem' => '--palette--;;top, --palette--;;naming, --palette--;;header, teaser, description, description_extended,
--div--;Bilder/Dateien, teaser_images, header_images', --div--;Bilder/Dateien, teaser_images, header_images, images',
], ],
], ],
'palettes' => [ 'palettes' => [
@@ -310,6 +310,55 @@ return [
], ],
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext'] $GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
), ),
],
'images' => [
'exclude' => 0,
'label' => 'Galeriebilder',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
'images',
[
'appearance' => [
'createNewRelationLinkTitle' => 'LLL:EXT:frontend/Resources/Private/Language/locallang_ttc.xlf:images.addFileReference'
],
'overrideChildTca' => [
'types' => [
\TYPO3\CMS\Core\Resource\File::FILETYPE_IMAGE => [
'showitem' => '
--palette--;LLL:EXT:lang/locallang_tca.xlf:sys_file_reference.imageoverlayPalette;imageoverlayPalette,
--palette--;;filePalette',
],
],
'columns' => [
'crop' => [
'config' => [
'cropVariants' => [
'default' => [
'title' => 'Preview',
'allowedAspectRatios' => [
'preview' => [
'title' => 'Standard',
'value' => 1.8,
],
],
],
'zoom' => [
'title' => 'Zoom',
'allowedAspectRatios' => [
'free' => [
'title' => 'frei',
'value' => 'NaN',
],
],
],
],
],
],
],
],
'maxitems' => 10
],
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
),
], ],
'products' => [ 'products' => [
'exclude' => 0, 'exclude' => 0,
@@ -529,6 +529,7 @@ CREATE TABLE tx_epproducts_domain_model_concept
header_subtitle varchar(255) DEFAULT '' NOT NULL, header_subtitle varchar(255) DEFAULT '' NOT NULL,
teaser_images int(11) unsigned NOT NULL default '0', teaser_images int(11) unsigned NOT NULL default '0',
header_images int(11) unsigned NOT NULL default '0', header_images int(11) unsigned NOT NULL default '0',
images int(11) unsigned NOT NULL default '0',
tstamp int(11) unsigned DEFAULT '0' NOT NULL, tstamp int(11) unsigned DEFAULT '0' NOT NULL,
crdate int(11) unsigned DEFAULT '0' NOT NULL, crdate int(11) unsigned DEFAULT '0' NOT NULL,
@@ -69,14 +69,14 @@ class BackendController extends ActionController
public function initializeAction() public function initializeAction()
{ {
$this->pageUid = (integer)GeneralUtility::_GET('id'); $this->pageUid = (int)GeneralUtility::_GET('id');
parent::initializeAction(); parent::initializeAction();
} }
public function listPagesAction() public function listPagesAction()
{ {
$pages = $this->pageRepository->findPagesByPid($this->pageUid); $pages = $this->pageRepository->findPagesByPid($this->pageUid, true);
$this->view->assign('pages', $pages); $this->view->assign('pages', $pages);
} }
@@ -2,6 +2,7 @@
namespace EP\EpTheme\Domain\Repository; namespace EP\EpTheme\Domain\Repository;
use TYPO3\CMS\Core\Domain\Repository\PageRepository as CorePageRepository;
use TYPO3\CMS\Extbase\Persistence\Repository; use TYPO3\CMS\Extbase\Persistence\Repository;
class PageRepository extends Repository class PageRepository extends Repository
@@ -13,23 +14,20 @@ class PageRepository extends Repository
'sorting' => 'ASC', 'sorting' => 'ASC',
]; ];
/** public function findPagesByPid(int $pid, bool $includeDisabled = false)
* @param int $pid
* @return array|\TYPO3\CMS\Extbase\Persistence\QueryResultInterface
*/
public function findPagesByPid($pid)
{ {
$query = $this->createQuery(); $query = $this->createQuery();
$query $query
->getQuerySettings() ->getQuerySettings()
->setRespectStoragePage(false) ->setRespectStoragePage(false)
->setIgnoreEnableFields(true) ->setIgnoreEnableFields($includeDisabled)
->setIncludeDeleted(false) ->setIncludeDeleted(false)
->setRespectSysLanguage(false) ->setRespectSysLanguage(false)
; ;
$query->matching($query->logicalAnd([ $query->matching($query->logicalAnd([
$query->equals('pid', $pid), $query->equals('pid', $pid),
$query->equals('doktype', \TYPO3\CMS\Core\Domain\Repository\PageRepository::DOKTYPE_DEFAULT) $query->equals('doktype', CorePageRepository::DOKTYPE_DEFAULT),
$query->equals('navHide', false),
])); ]));
return $query->execute(); return $query->execute();
@@ -62,13 +62,12 @@
<script> <script>
import Vue from 'vue' import Vue from 'vue'
import { mapState, mapMutations } from 'vuex' import { mapState, mapMutations, mapActions } from 'vuex'
import axios from 'axios'
import flatpickr from 'flatpickr' import flatpickr from 'flatpickr'
import { German } from 'flatpickr/dist/l10n/de' import { German } from 'flatpickr/dist/l10n/de'
import FormGroup from './components/FormGroup' import FormGroup from './components/FormGroup'
export default { export default {
components: { components: {
FormGroup FormGroup
}, },
@@ -76,15 +75,18 @@
return { return {
picker: null, picker: null,
formErrors: {}, formErrors: {},
countries: []
} }
}, },
created () { created () {
this.loadFormOptions(); this.loadAddress()
this.$store.dispatch('loadAddress')
.then(() => { .then(() => {
this.picker.setDate(new Date(this.userData.dateOfBirth), true); this.picker.setDate(new Date(this.userData.dateOfBirth), true);
}); this.$emit('loaded')
})
.catch(() => {
this.logout()
this.$router.push({name: 'login'})
})
}, },
mounted () { mounted () {
Vue.nextTick(() => { Vue.nextTick(() => {
@@ -99,37 +101,32 @@
}) })
}, },
methods: { methods: {
...mapMutations(['alert', 'beginLoading', 'endLoading']), ...mapMutations(['logout', 'alert']),
loadFormOptions () { ...mapActions(['loadAddress', 'saveAddress']),
this.beginLoading();
return axios({
url: '/api/countries'
}).then(response => {
this.countries = response.data
}).catch(error => {
}).finally(() => {
this.endLoading()
});
},
save () { save () {
this.formErrors = {}; this.formErrors = {}
this.$store.dispatch('saveAddress', this.userData) this.saveAddress(this.userData)
.then(() => {
this.$emit('loaded')
})
.catch(error => { .catch(error => {
this.alert({ this.alert({
message: 'Bitte überprüfe deine Eingaben.', message: 'Bitte überprüfe deine Eingaben.',
success: false, success: false,
}); })
const violations = error.response.data.violations; error.response.then(data => {
if (typeof violations !== 'undefined') { const violations = data.violations
for (let violation of violations) { if (typeof violations !== 'undefined') {
this.$set(this.formErrors, violation.property_path, violation.message); for (let violation of violations) {
this.$set(this.formErrors, violation.property_path, violation.message)
}
} }
} })
}); })
} }
}, },
computed: { computed: {
...mapState(['loading', 'userData']) ...mapState(['loading', 'userData', 'countries'])
} }
} }
</script> </script>
@@ -1,8 +1,9 @@
<template> <template>
<div id="myep" class="relative mb-16"> <div class="relative mb-16">
<nav class="w-full bg-zinc-50 flex items-center justify-between mb-8 relative" v-if="isLoggedIn"> <a ref="container" class="block w-0 h-0 pt-24 -mt-24"></a>
<span class="block text-2xl px-4">My E&P</span> <nav class="w-full bg-zinc-50 flex items-center mb-8 relative" v-if="isLoggedIn">
<div class="absolute z-50 top-100 left-0 w-full bg-zinc-50 shadow lg:relative lg:top-auto lg:left-auto lg:w-auto lg:shadow-none lg:flex lg:space-x-4" <div class="flex-1 block text-2xl px-4">My E&P</div>
<div class="bg-zinc-50 shadow w-full lg:w-auto absolute lg:relative z-10 lg:z-auto top-full lg:top-auto bg-white left-0 lg:relative lg:shadow-none lg:flex lg:space-x-4"
:class="{ 'hidden': !navVisible }"> :class="{ 'hidden': !navVisible }">
<div class="lg:flex lg:items-center m-0"> <div class="lg:flex lg:items-center m-0">
<router-link @click.native="navVisible = false" :to="{ name: 'address' }" class="block p-4 text-black hover:bg-zinc-400 hover:text-zinc-800" active-class="bg-zinc-400 text-zinc-800">Adressdaten</router-link> <router-link @click.native="navVisible = false" :to="{ name: 'address' }" class="block p-4 text-black hover:bg-zinc-400 hover:text-zinc-800" active-class="bg-zinc-400 text-zinc-800">Adressdaten</router-link>
@@ -11,7 +12,7 @@
<router-link @click.native="navVisible = false" :to="{ name: 'events' }" class="block p-4 text-black hover:bg-zinc-400 hover:text-zinc-800" active-class="bg-zinc-400 text-zinc-800">Buchungen</router-link> <router-link @click.native="navVisible = false" :to="{ name: 'events' }" class="block p-4 text-black hover:bg-zinc-400 hover:text-zinc-800" active-class="bg-zinc-400 text-zinc-800">Buchungen</router-link>
<router-link @click.native="navVisible = false" :to="{ name: 'teamer' }" class="block p-4 text-black hover:bg-zinc-400 hover:text-zinc-800" active-class="bg-zinc-400 text-zinc-800" v-if="isTeamer">Teamer</router-link> <router-link @click.native="navVisible = false" :to="{ name: 'teamer' }" class="block p-4 text-black hover:bg-zinc-400 hover:text-zinc-800" active-class="bg-zinc-400 text-zinc-800" v-if="isTeamer">Teamer</router-link>
</div> </div>
<a class="block px-4 py-4 text-black hover:bg-zinc-400 hover:text-zinc-800" href="#" @click.prevent="logout()">Logout</a> <a class="block px-4 py-4 text-black hover:bg-zinc-400 hover:text-zinc-800" href="#" @click.prevent="performLogout()">Logout</a>
</div> </div>
<a href="#" class="lg:hidden p-4 text-black hover:text-zinc-800" :class="{ 'rotate-90': navVisible }" @click.prevent="navVisible = !navVisible"> <a href="#" class="lg:hidden p-4 text-black hover:text-zinc-800" :class="{ 'rotate-90': navVisible }" @click.prevent="navVisible = !navVisible">
<svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path></svg> <svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path></svg>
@@ -19,7 +20,7 @@
</nav> </nav>
<div class="p-4 mb-8 text-white" :class="{'bg-emerald-600': alert.success, 'bg-red-600': !alert.success}" v-if="alert.message" v-html="alert.message"></div> <div class="p-4 mb-8 text-white" :class="{'bg-emerald-600': alert.success, 'bg-red-600': !alert.success}" v-if="alert.message" v-html="alert.message"></div>
<div class="relative"> <div class="relative">
<router-view></router-view> <router-view @loaded="scrollTop()"></router-view>
<div class="absolute top-0 left-0 inset-0 bg-white/85" v-show="loading"> <div class="absolute top-0 left-0 inset-0 bg-white/85" v-show="loading">
<div class="absolute top-1/2 left-1/2 transform -translate-xy-1/2 flex items-center space-x-2 h-8"> <div class="absolute top-1/2 left-1/2 transform -translate-xy-1/2 flex items-center space-x-2 h-8">
<img :src="config.loaderUrl" alt="" class="block w-4 h-4"> <img :src="config.loaderUrl" alt="" class="block w-4 h-4">
@@ -31,7 +32,7 @@
</template> </template>
<script> <script>
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState, mapActions, mapMutations } from 'vuex'
import store from './store' import store from './store'
import router from './router' import router from './router'
@@ -39,12 +40,23 @@
store, store,
router, router,
methods: { methods: {
logout () { performLogout () {
this.$store.dispatch('logout') this.logout()
.then(() => { .then(() => {
this.$router.replace({ name: 'login' }) this.$router.replace({ name: 'login' })
}).catch(error => {}); }).catch(error => {});
} },
scrollTop() {
this.$refs.container.scrollIntoView({behavior: 'smooth', block: 'start'})
},
...mapMutations([
'initConfig',
]),
...mapActions([
'checkLoginState',
'loadCountries',
'logout',
]),
}, },
data () { data () {
return { return {
@@ -56,11 +68,16 @@
...mapGetters(['isLoggedIn', 'isTeamer']) ...mapGetters(['isLoggedIn', 'isTeamer'])
}, },
mounted () { mounted () {
this.$store.dispatch('init').then(() => { this.initConfig()
if (this.isLoggedIn) { this.checkLoginState()
this.$router.replace({ name: 'address' }) .then(() => {
} if (this.isLoggedIn) {
}) this.loadCountries()
.then(() => {
this.$router.replace({ name: 'address' })
})
}
})
}, },
} }
</script> </script>
@@ -158,7 +158,6 @@
<script> <script>
import Vue from 'vue' import Vue from 'vue'
import VueScrollTo from 'vue-scrollto'
import AccommodationSelect from './components/AccommodationSelect' import AccommodationSelect from './components/AccommodationSelect'
import ContingentsOverview from './components/ContingentsOverview' import ContingentsOverview from './components/ContingentsOverview'
import MutableFields from './components/MutableFields' import MutableFields from './components/MutableFields'
@@ -171,10 +170,8 @@
import ServiceSelect from './components/ServiceSelect' import ServiceSelect from './components/ServiceSelect'
import ServicesOverview from './components/ServicesOverview' import ServicesOverview from './components/ServicesOverview'
import TransportationSelect from './components/TransportationSelect' import TransportationSelect from './components/TransportationSelect'
import axios from 'axios' import { mapGetters, mapMutations, mapState } from 'vuex'
import {mapGetters, mapMutations, mapState} from 'vuex' import { checkStatus, defaultOptions } from './api'
Vue.use(VueScrollTo)
export default { export default {
name: 'BookingEdit', name: 'BookingEdit',
@@ -222,78 +219,95 @@
}, },
methods: { methods: {
...mapMutations(['alert', 'beginLoading', 'endLoading']), ...mapMutations(['alert', 'beginLoading', 'endLoading']),
loadFormOptions () {
this.beginLoading();
return axios({
url: '/api/countries',
}).then(response => {
this.countries = response.data
}).catch(error => {
}).finally(() => {
this.endLoading()
});
},
loadBookingData () { loadBookingData () {
this.beginLoading('Lade Reise- und Buchungsdaten...') this.beginLoading('Lade Reise- und Buchungsdaten...')
return axios({ const options = {
url: `/api/booking/${this.bookingId}` ...defaultOptions
}).then(response => { }
this.bookingData = response.data.bookingData; return fetch(`${this.config.myEpApiBaseUrl}/api/booking/${this.bookingId}`, options)
this.participantData = response.data.participantData; .then(checkStatus)
this.travelData = response.data.travelData; .then(response => response.json())
}).catch(() => { .then(data => {
throw new Error('Reise- und Buchungsdaten konnten nicht geladen werden.'); this.bookingData = data.bookingData
}).finally(() => { this.participantData = data.participantData
this.endLoading() this.travelData = data.travelData
}) })
.catch(() => {})
.finally(() => {
this.endLoading()
})
}, },
loadEventData () { loadEventData () {
this.beginLoading('Lade Vorgangsdaten...') this.beginLoading('Lade Vorgangsdaten...')
return axios({ const options = {
url: `/api/event/${this.bookingData.bookingNumber}` ...defaultOptions
}).then(response => { }
this.eventData = response.data; return fetch(`${this.config.myEpApiBaseUrl}/api/event/${this.bookingData.bookingNumber}`, options)
}).catch(error => { .then(checkStatus)
throw new Error(error.response.data.message); .then(response => response.json())
}).finally(() => { .then(data => {
this.endLoading() this.eventData = data
}) })
.catch(error => {
throw new Error(error.message)
})
.finally(() => {
this.endLoading()
})
}, },
loadMutableFields () { loadMutableFields () {
this.beginLoading('Lade mögliche Änderungen...') this.beginLoading('Lade mögliche Änderungen...')
return axios({ const options = {
url: `/api/mutable-fields/${this.travelData.busproId}` ...defaultOptions
}).then(response => { }
this.mutableFields = response.data; return fetch(`${this.config.myEpApiBaseUrl}/api/mutable-fields/${this.travelData.busproId}`, options)
}).catch(() => { .then(checkStatus)
throw new Error('Mögliche Änderungen konnten nicht geladen werden.'); .then(response => response.json())
}).finally(() => { .then(data => {
this.endLoading() this.mutableFields = data
}) })
.catch(() => {
throw new Error('Mögliche Änderungen konnten nicht geladen werden.');
})
.finally(() => {
this.endLoading()
})
}, },
loadContingents () { loadContingents () {
this.beginLoading('Lade Kontingente...') this.beginLoading('Lade Kontingente...')
return axios({ const options = {
url: `/api/contingents/${this.travelData.busproId}` ...defaultOptions
}).then(response => { }
this.contingents = response.data; return fetch(`${this.config.myEpApiBaseUrl}/api/contingents/${this.travelData.busproId}`, options)
}).catch(() => { .then(checkStatus)
throw new Error('Kontingente konnten nicht geladen werden.'); .then(response => response.json())
}).finally(() => { .then(data => {
this.endLoading() this.contingents = data
}) })
.catch(() => {
throw new Error('Kontingente konnten nicht geladen werden.');
})
.finally(() => {
this.endLoading()
})
}, },
loadServices () { loadServices () {
this.beginLoading('Lade Leistungen...') this.beginLoading('Lade Leistungen...')
return axios({ const options = {
url: `/api/services/${this.travelData.busproId}` ...defaultOptions
}).then(response => { }
this.services = response.data; return fetch(`${this.config.myEpApiBaseUrl}/api/services/${this.travelData.busproId}`, options)
}).catch(() => { .then(checkStatus)
throw new Error('Leistungen konnten nicht geladen werden.'); .then(response => response.json())
}).finally(() => { .then(data => {
this.endLoading() this.services = data
}) })
.catch(() => {
throw new Error('Leistungen konnten nicht geladen werden.');
})
.finally(() => {
this.endLoading()
})
}, },
getAccommodationLabel (participant) { getAccommodationLabel (participant) {
if (participant.hasOwnProperty('accommodationId') && participant.accommodationId in this.contingents) { if (participant.hasOwnProperty('accommodationId') && participant.accommodationId in this.contingents) {
@@ -413,7 +427,6 @@
return messages return messages
}, },
storeBookingData() { storeBookingData() {
this.$scrollTo('#myep')
let messages = this.validateInput(); let messages = this.validateInput();
if (false === this.dataValid) { if (false === this.dataValid) {
this.alert({ this.alert({
@@ -423,32 +436,41 @@
return; return;
} }
this.beginLoading() this.beginLoading()
axios({ const options = {
url: `/api/booking/${this.bookingId}`, ...defaultOptions,
method: 'put', method: 'PUT',
data: { body: JSON.stringify({
participantData: this.participantData, participantData: this.participantData,
selectedTransportations: this.selectedTransportations, selectedTransportations: this.selectedTransportations,
remarks: this.bookingData.remarks, remarks: this.bookingData.remarks,
},
}).then(response => {
this.alert({
message: response.data.message,
success: true,
});
this.dirty = false;
}).catch(error => {
this.alert({
message: error.response.data.message,
success: false,
}) })
}).finally(() => { }
this.endLoading() fetch(`${this.config.myEpApiBaseUrl}/api/booking/${this.bookingId}`, options)
}) .then(checkStatus)
.then(response => response.json())
.then(data => {
this.alert({
message: data.message,
success: true,
})
this.dirty = false
})
.catch(error => {
error.response.then(data => {
this.alert({
message: data.message,
success: false,
})
})
})
.finally(() => {
this.endLoading()
this.$emit('loaded')
})
} }
}, },
computed: { computed: {
...mapState(['loading']), ...mapState(['config', 'loading']),
...mapGetters(['isGroupManager']), ...mapGetters(['isGroupManager']),
availableContingents () { availableContingents () {
let filteredContingents = {}; let filteredContingents = {};
@@ -500,14 +522,14 @@
}, },
mounted () { mounted () {
this.bookingId = this.$route.params.id this.bookingId = this.$route.params.id
this.loadFormOptions() this.loadBookingData()
.then(() => this.loadBookingData())
.then(() => this.loadEventData()) .then(() => this.loadEventData())
.then(() => this.loadMutableFields()) .then(() => this.loadMutableFields())
.then(() => this.loadContingents()) .then(() => this.loadContingents())
.then(() => this.loadServices()) .then(() => this.loadServices())
.then(() => { .then(() => {
this.initialized = true; this.initialized = true;
this.$emit('loaded')
}) })
.catch(error => { .catch(error => {
this.alert({ this.alert({
@@ -515,9 +537,6 @@
success: false, success: false,
}); });
}) })
.finally(() => {
this.endLoading()
})
} }
} }
</script> </script>
@@ -51,7 +51,7 @@
<script> <script>
import { mapState, mapMutations } from 'vuex' import { mapState, mapMutations } from 'vuex'
import axios from 'axios' import { defaultOptions, checkStatus } from './api'
export default { export default {
data () { data () {
@@ -62,43 +62,59 @@
} }
}, },
created () { created () {
this.beginLoading(); this.beginLoading()
return axios({ const options = {
url: '/api/crm-selections' ...defaultOptions
}).then(response => { }
this.crmData = response.data
}).catch(error => { return fetch(`${this.config.myEpApiBaseUrl}/api/crm-selections`, options)
this.alert({ .then(checkStatus)
message: 'Es ist ein Fehler aufgetreten :(', .then(response => response.json())
success: false, .then(data => {
this.crmData = data
})
.catch(() => {
this.alert({
message: 'Es ist ein Fehler aufgetreten :(',
success: false,
})
})
.finally(() => {
this.endLoading()
this.$emit('loaded')
}) })
}).finally(() => {
this.endLoading()
});
}, },
methods: { methods: {
...mapMutations(['beginLoading', 'endLoading', 'alert']), ...mapMutations(['beginLoading', 'endLoading', 'alert']),
save () { save () {
this.beginLoading(); this.beginLoading()
return axios({ const options = {
url: '/api/crm-selections', ...defaultOptions,
method: 'put', method: 'PUT',
data: this.crmData body: JSON.stringify(this.crmData)
}).then(() => { }
this.alert({
message: 'Die Änderungen wurden gespeichert', return fetch(`${this.config.myEpApiBaseUrl}/api/crm-selections`, options)
success: true, .then(checkStatus)
}); .then(response => response.json())
}).catch(error => { .then(() => {
this.alert({ this.alert({
message: 'Es ist ein Fehler aufgetreten :(', message: 'Die Änderungen wurden gespeichert',
success: false, success: true,
}); })
}).finally(() => { })
this.endLoading(); .catch(() => {
}); this.alert({
message: 'Es ist ein Fehler aufgetreten :(',
success: false,
})
})
.finally(() => {
this.endLoading()
this.$emit('loaded')
})
}, },
hasVisibleSelections (group) { hasVisibleSelections (group) {
if (this.hiddenSelectionGroups.indexOf(group.id) !== -1) { if (this.hiddenSelectionGroups.indexOf(group.id) !== -1) {
@@ -116,7 +132,7 @@
} }
}, },
computed: { computed: {
...mapState(['loading']) ...mapState(['config', 'loading'])
} }
} }
</script> </script>
@@ -75,10 +75,10 @@
</template> </template>
<script> <script>
import {mapState, mapMutations, mapGetters} from 'vuex' import { mapState, mapMutations, mapGetters } from 'vuex'
import axios from 'axios'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import 'dayjs/locale/de' import 'dayjs/locale/de'
import { checkStatus, defaultOptions } from './api'
export default { export default {
data () { data () {
@@ -96,18 +96,26 @@ import {mapState, mapMutations, mapGetters} from 'vuex'
created () { created () {
this.beginLoading(); this.beginLoading();
return axios({ const options = {
url: '/api/events' ...defaultOptions
}).then(response => { }
this.events = response.data;
}).catch(error => { return fetch(`${this.config.myEpApiBaseUrl}/api/events`, options)
this.alert({ .then(checkStatus)
message: 'Es ist ein Fehler aufgetreten :(', .then(response => response.json())
success: false, .then(data => {
}); this.events = data
}).finally(() => { })
this.endLoading(); .catch(() => {
}); this.alert({
message: 'Es ist ein Fehler aufgetreten :(',
success: false,
})
})
.finally(() => {
this.endLoading()
this.$emit('loaded')
})
}, },
methods: { methods: {
...mapMutations(['beginLoading', 'endLoading', 'alert']), ...mapMutations(['beginLoading', 'endLoading', 'alert']),
@@ -118,11 +126,7 @@ import {mapState, mapMutations, mapGetters} from 'vuex'
return dayjs(date).format('DD.MM.YY') return dayjs(date).format('DD.MM.YY')
}, },
getDownloadUrl (event, type) { getDownloadUrl (event, type) {
return this.config.myEpApiBaseUrl return `${this.config.myEpApiBaseUrl}/api/events/${event.id}/${type}`
+ '/api/events/'
+ event.id
+ '/' + type + '?token='
+ sessionStorage.getItem('myep-auth-token');
}, },
calculateBalance (event) { calculateBalance (event) {
if (!event.price) { if (!event.price) {
@@ -51,7 +51,7 @@
</template> </template>
<script> <script>
import { mapState, mapGetters, mapMutations } from 'vuex' import { mapState, mapGetters, mapMutations, mapActions } from 'vuex'
import FormGroup from './components/FormGroup' import FormGroup from './components/FormGroup'
export default { export default {
@@ -66,6 +66,7 @@
}, },
methods: { methods: {
...mapMutations(['alert']), ...mapMutations(['alert']),
...mapActions(['login', 'resetPassword', 'loadCountries']),
toggleMode () { toggleMode () {
this.mode = this.mode === 'login' ? 'reset' : 'login'; this.mode = this.mode === 'login' ? 'reset' : 'login';
this.password = '' this.password = ''
@@ -73,12 +74,12 @@
submit () { submit () {
this.message = ''; this.message = '';
if (this.mode === 'login') { if (this.mode === 'login') {
this.login() this.performLogin()
} else { } else {
this.resetPassword() this.performPasswordReset()
} }
}, },
login () { performLogin () {
this.formErrors = {}; this.formErrors = {};
if (!this.email || !this.password) { if (!this.email || !this.password) {
this.alert({ this.alert({
@@ -87,15 +88,21 @@
}); });
return return
} }
this.$store.dispatch('login', { this.login({
email: this.email, email: this.email,
password: this.password password: this.password
}).then(() => { }).then(() => {
this.$router.push({ name: 'address' }); this.loadCountries()
.then(() => {
this.$router.push({ name: 'address' })
})
}).catch(error => { }).catch(error => {
}); }).finally(() => {
this.email = ''
this.password = ''
})
}, },
resetPassword () { performPasswordReset () {
this.formErrors = {}; this.formErrors = {};
if (!this.email) { if (!this.email) {
this.alert({ this.alert({
@@ -104,9 +111,8 @@
}); });
return; return;
} }
this.$store.dispatch('resetPassword', this.resetPassword(this.email)
this.email .then(response => {
).then(response => {
this.email = ''; this.email = '';
if (response.data.success) { if (response.data.success) {
this.alert({ this.alert({
@@ -130,7 +136,9 @@
this.$set(this.formErrors, violation.property_path, violation.message); this.$set(this.formErrors, violation.property_path, violation.message);
} }
} }
}); }).finally(() => {
this.$emit('loaded')
})
} }
}, },
computed: { computed: {
@@ -12,7 +12,7 @@
<script> <script>
import { mapState, mapMutations } from 'vuex' import { mapState, mapMutations } from 'vuex'
import axios from 'axios' import { checkStatus, defaultOptions } from './api'
export default { export default {
methods: { methods: {
@@ -28,33 +28,44 @@
this.beginLoading(); this.beginLoading();
return axios({ const options = {
url: '/api/newsletter', ...defaultOptions,
method: 'put', method: 'PUT',
data body: JSON.stringify(data)
}).then(() => { }
this.alert({
message: 'Die Änderungen wurden gespeichert', return fetch(`${this.config.myEpApiBaseUrl}/api/newsletter`, options)
success: true, .then(checkStatus)
}); .then(response => response.json())
}).catch(error => { .then(() => {
this.alert({ this.alert({
message: 'Es ist ein Fehler aufgetreten :(', message: 'Die Änderungen wurden gespeichert',
success: false, success: true,
}); })
}).finally(() => { })
this.endLoading(); .catch(() => {
}); this.alert({
message: 'Es ist ein Fehler aufgetreten :(',
success: false,
})
})
.finally(() => {
this.endLoading()
this.$emit('loaded')
})
} }
}, },
computed: { computed: {
...mapState(['loading', 'userData']), ...mapState(['config', 'loading', 'userData']),
statusMessage () { statusMessage () {
let message = 'Du bist aktuell'; let message = 'Du bist aktuell';
message += this.userData.newsletter ? ' ' : ' <strong>nicht</strong> '; message += this.userData.newsletter ? ' ' : ' <strong>nicht</strong> ';
message += 'zum Newsletter angemeldet.'; message += 'zum Newsletter angemeldet.';
return message; return message;
} }
},
created() {
this.$emit('loaded')
} }
} }
</script> </script>
@@ -1,81 +1,77 @@
<template> <template>
<div> <div>
<h1>Teamer</h1> <p class="text-2xl pb-4">Teamer</p>
<form @submit.prevent="save()"> <form @submit.prevent="save()">
<div class="row"> <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
<div class="col-xs-12 col-md-6"> <div>
<h4>Fährst du Ski oder Board?</h4> <h4 class="mb-2">Fährst du Ski oder Board?</h4>
<div class="form-group"> <div class="flex flex-col space-y-1 pb-4">
<div class="checkbox" v-for="ability of abilities"> <label class="flex items-center"
<label> v-for="ability of abilities" :key="ability.id">
<input type="checkbox" class="form-control" v-model="userData.abilities" <input type="checkbox"
:value="ability.id" /> class="border-zinc-400 focus:border-zinc-800 ring-0 focus:ring-0 text-ep-secondary sbw:text-sbw-secondary"
<span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span> v-model="userData.abilities"
{{ ability['title'] }} :value="ability.id"/>
</label> <span class="ml-2">{{ ability.title }}</span>
</div> </label>
</div> </div>
<h4>Mögliche Jobprofile</h4> <h4 class="mb-2">Mögliche Jobprofile</h4>
<div class="form-group"> <div class="flex flex-col space-y-1 pb-4">
<div class="checkbox" v-for="jobProfile of jobProfiles"> <label class="flex items-center"
<label> v-for="jobProfile of jobProfiles" :key="jobProfile.id">
<input type="checkbox" class="form-control" v-model="userData.jobProfiles" <input type="checkbox"
:value="jobProfile.id" /> class="border-zinc-400 focus:border-zinc-800 ring-0 focus:ring-0 text-ep-secondary sbw:text-sbw-secondary"
<span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span> v-model="userData.jobProfiles"
{{ jobProfile['title'] }} :value="jobProfile.id"/>
</label> <span class="ml-2">{{ jobProfile.title }}</span>
</div> </label>
</div> </div>
<h4>Sonstiges</h4> <h4 class="mb-2">Sonstiges</h4>
<div class="form-group"> <div class="flex flex-col space-y-1 pb-4">
<div class="checkbox"> <label class="flex items-center">
<label> <input type="checkbox"
<input type="checkbox" class="form-control" v-model="userData.wantsToLead"/> class="border-zinc-400 focus:border-zinc-800 ring-0 focus:ring-0 text-ep-secondary sbw:text-sbw-secondary"
<span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span> v-model="userData.wantsToLead"/>
Ich möchte eine Fahrtenleitung übernehmen. <span class="ml-2">Ich möchte eine Fahrtenleitung übernehmen</span>
</label> </label>
</div>
</div> </div>
<form-group label="Status"> <form-group label="Status">
<select id="status" v-model="userData.seniority" class="form-control"> <select id="status" v-model="userData.seniority" class="border-zinc-400 focus:border-zinc-800 ring-0 focus:ring-0 mt-1 w-full">
<option v-for="status in this.status" :value="status.value">{{ status.label }}</option> <option v-for="status in this.status" :value="status.value">{{ status.label }}</option>
</select> </select>
</form-group> </form-group>
<form-group label="Jackengröße"> <form-group label="Jackengröße">
<select v-model="userData.jacketSize" class="form-control"> <select v-model="userData.jacketSize" class="border-zinc-400 focus:border-zinc-800 ring-0 focus:ring-0 mt-1 w-full">
<option v-for="size of this.sizes" :value="size">{{ size }}</option> <option v-for="size of this.sizes" :value="size">{{ size }}</option>
</select> </select>
</form-group> </form-group>
<form-group label="Wünsche"> <form-group label="Wünsche">
<textarea class="xxlarge form-control" cols="30" rows="3" v-model="userData.notes"></textarea> <textarea class="w-full" cols="30" rows="3" v-model="userData.notes"></textarea>
</form-group> </form-group>
</div> </div>
<div class="col-xs-12 col-md-6"> <div>
<h4>Verfügbarkeiten</h4> <h4 class="mb-2">Verfügbarkeiten</h4>
<div class="checkbox" v-for="timeFrame in timeFrames"> <div class="flex flex-col space-y-1 pb-4">
<label> <label class="flex items-center"
<input type="checkbox" class="form-control" v-model="userData.availableTimeFrames" v-for="timeFrame of timeFrames" :key="timeFrame.id">
<input type="checkbox"
class="border-zinc-400 focus:border-zinc-800 ring-0 focus:ring-0 text-ep-secondary sbw:text-sbw-secondary"
v-model="userData.availableTimeFrames"
:value="timeFrame.id"/> :value="timeFrame.id"/>
<span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span> <span class="ml-2">{{ timeFrame | period }}</span>
{{ timeFrame | period }}
</label> </label>
</div> <label class="flex items-center">
<div class="checkbox"> <input type="checkbox"
<label> class="border-zinc-400 focus:border-zinc-800 ring-0 focus:ring-0 text-ep-secondary sbw:text-sbw-secondary"
<input type="checkbox" class="form-control" v-model="userData.monthLong"/> v-model="userData.monthLong"/>
<span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span> <span class="ml-2">Ich habe Zeit und würde gerne über einen Monat am Stück in eine Destination.</span>
Ich habe Zeit und würde gerne über einen Monat am Stück in eine Destination.
</label> </label>
</div> </div>
</div> </div>
</div> <div class="col-span-1 md:col-span2">
<div class="row"> <button type="submit" class="button bg-button" :disabled="loading">
<div class="col-xs-12"> Speichern
<div class="form-group"> </button>
<button type="submit" class="button bg-button" :disabled="loading">
Speichern
</button>
</div>
</div> </div>
</div> </div>
</form> </form>
@@ -84,10 +80,10 @@
<script> <script>
import { mapState, mapMutations } from 'vuex' import { mapState, mapMutations } from 'vuex'
import axios from 'axios'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import 'dayjs/locale/de' import 'dayjs/locale/de'
import FormGroup from './components/FormGroup' import FormGroup from './components/FormGroup'
import { checkStatus, defaultOptions } from './api'
export default { export default {
components: { components: {
@@ -121,42 +117,57 @@
this.beginLoading(); this.beginLoading();
return axios({
url: '/api/teamer-data', const options = {
method: 'put', ...defaultOptions,
data method: 'PUT',
}) body: JSON.stringify(data)
.then(() => { }
this.alert({
message: 'Die Änderungen wurden gespeichert', return fetch(`${this.config.myEpApiBaseUrl}/api/teamer-data`, options)
success: true, .then(checkStatus)
}); .then(response => response.json())
}).catch(error => { .then(() => {
this.alert({ this.alert({
message: 'Es ist ein Fehler aufgetreten :(', message: 'Die Änderungen wurden gespeichert',
success: false, success: true,
}); })
}).finally(() => { })
this.endLoading(); .catch(() => {
}); this.alert({
message: 'Es ist ein Fehler aufgetreten :(',
success: false,
})
})
.finally(() => {
this.endLoading()
this.$emit('loaded')
})
} }
}, },
created () { created () {
this.beginLoading(); this.beginLoading();
return axios({ const options = {
url: '/api/teamer-data' ...defaultOptions
}).then(response => { }
this.abilities = response.data.abilities;
this.timeFrames = response.data.timeFrames; return fetch(`${this.config.myEpApiBaseUrl}/api/teamer-data`, options)
this.jobProfiles = response.data.jobProfiles; .then(checkStatus)
}).catch(error => { .then(response => response.json())
}).finally(() => { .then(data => {
this.endLoading(); this.abilities = data.abilities
}); this.timeFrames = data.timeFrames
this.jobProfiles = data.jobProfiles
})
.catch(() => {})
.finally(() => {
this.endLoading()
this.$emit('loaded')
})
}, },
computed: { computed: {
...mapState(['userData', 'loading']) ...mapState(['config', 'userData', 'loading'])
}, },
filters: { filters: {
period (timeFrame) { period (timeFrame) {
@@ -0,0 +1,26 @@
const defaultOptions = {
headers: {
'Content-Type': 'application/json'
},
credentials: 'include',
}
function checkStatus(response) {
if (response.ok) {
return response
} else {
const error = new Error(response.status)
error.response = response.json()
throw error
}
}
function handleError() {
commit('alert', {
message: 'Es ist ein Fehler aufgetreten :(',
success: false,
})
throw error
}
export { checkStatus, handleError, defaultOptions }
@@ -4,7 +4,7 @@
{{ label }}: {{ label }}:
</label> </label>
<slot></slot> <slot></slot>
<span class="block text-sm mt-1" v-show="error"> <span class="block text-sm mt-1 text-red-500" v-show="error">
{{ error }} {{ error }}
</span> </span>
</div> </div>
@@ -1,13 +1,10 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import axios from 'axios' import { checkStatus, handleError, defaultOptions } from '../api'
const configElement = document.getElementById('appconfig') const configElement = document.getElementById('appconfig')
const config = JSON.parse(configElement.innerHTML) const config = JSON.parse(configElement.innerHTML)
axios.defaults.baseURL = config.myEpApiBaseUrl
axios.defaults.withCredentials = true
Vue.use(Vuex) Vue.use(Vuex)
const defaultUserData = { const defaultUserData = {
@@ -33,6 +30,7 @@ export default new Vuex.Store({
statusMessage: '', statusMessage: '',
authenticated: false, authenticated: false,
userData: defaultUserData, userData: defaultUserData,
countries: [],
alert: { alert: {
message: '', message: '',
success: true, success: true,
@@ -72,125 +70,168 @@ export default new Vuex.Store({
} }
}, },
actions: { actions: {
init({commit}) { checkLoginState({commit, state}) {
commit('initConfig'); commit('beginLoading')
commit('beginLoading');
return axios({ const options = {
url: '/api/ping', ...defaultOptions
method: 'get', }
}).then(response => {
commit('login') return fetch(`${state.config.myEpApiBaseUrl}/api/ping`, options)
}).catch(() => { .then(checkStatus)
}).finally(() => { .then(response => response.json())
commit('endLoading'); .then(() => {
}) commit('login')
})
.catch(() => {})
.finally(() => {
commit('endLoading')
})
},
loadCountries({commit, state}) {
commit('beginLoading')
const options = {
...defaultOptions
}
return fetch(`${state.config.myEpApiBaseUrl}/api/countries`, options)
.then(checkStatus)
.then(response => response.json())
.then(data => {
commit('setCountries', data)
})
.catch(handleError)
.finally(() => {
commit('endLoading')
})
}, },
login({commit}, credentials) { login({commit}, credentials) {
commit('beginLoading'); commit('beginLoading')
return axios({ const options = {
url: '/api/login', ...defaultOptions,
method: 'post', method: 'POST',
data: { body: JSON.stringify({
username: credentials.email, username: credentials.email,
password: credentials.password password: credentials.password
}, })
}).then(response => { }
commit('login', response.data);
}).catch(error => {
commit('logout');
commit('alert', {
message: 'Der Login ist fehlgeschlagen :(',
success: false,
});
throw error;
}).finally(() => {
commit('endLoading');
});
},
logout({commit}) {
commit('beginLoading');
return axios({ return fetch(`${config.myEpApiBaseUrl}/api/login`, options)
url: '/api/logout', .then(checkStatus)
}).catch(error => { .then(response => response.json())
}).finally(() => { .then(data => {
commit('logout'); commit('login', data)
commit('endLoading'); })
}); .catch(error => {
}, commit('logout')
resetPassword({commit}, email) {
commit('beginLoading');
return axios({
url: '/api/reset-password',
data: {email: email},
method: 'post'
}).then(response => {
return response;
}).finally(() => {
commit('endLoading');
});
},
register({commit}, userData) {
commit('beginLoading');
return axios({
url: '/api/register',
data: userData,
method: 'post'
}).then(response => {
return response;
}).finally(() => {
commit('endLoading');
});
},
loadAddress({commit}) {
commit('beginLoading');
return axios({
url: '/api/address',
method: 'get',
}).then(response => {
commit('setUserData', response.data);
if (response.data.watchlist) {
commit('setWatchlist', response.data.watchlist);
}
}).catch(() => {
commit('alert', {
message: 'Es ist ein Fehler aufgetreten :(',
success: false,
});
}).finally(() => {
commit('endLoading');
});
},
saveAddress({commit, state}, data) {
commit('beginLoading');
return axios({
url: '/api/address',
method: 'put',
data
}).then(() => {
commit('alert', {
message: 'Die Änderungen wurden gespeichert',
success: true,
});
})
.catch(error => {
if (error.config.status >= 500) {
commit('alert', { commit('alert', {
message: 'Es ist ein Fehler aufgetreten :(', message: 'Der Login ist fehlgeschlagen :(',
success: false, success: false,
}); });
} else { throw error
throw error; })
} .finally(() => {
}).finally(() => { commit('endLoading')
commit('endLoading'); })
}); },
logout({commit}) {
commit('beginLoading')
const options = {
...defaultOptions
}
return fetch(`${config.myEpApiBaseUrl}/api/logout`, options)
.then(checkStatus)
.catch(() => {})
.finally(() => {
commit('logout')
commit('endLoading')
})
},
resetPassword({commit}, email) {
commit('beginLoading')
const options = {
...defaultOptions,
method: 'POST',
body: JSON.stringify({
email
})
}
return fetch(`${config.myEpApiBaseUrl}/api/reset-password`, options)
.then(checkStatus)
.then(response => response.json())
.then(response => response)
.catch(handleError)
.finally(() => {
commit('endLoading')
})
},
register({commit}, userData) {
commit('beginLoading')
const options = {
...defaultOptions,
method: 'POST',
body: JSON.stringify(userData)
}
return fetch(`${config.myEpApiBaseUrl}/api/register`, options)
.then(checkStatus)
.then(response => response.json())
.then(data => data)
.catch(handleError)
.finally(() => {
commit('endLoading')
})
},
loadAddress({commit}) {
commit('beginLoading')
const options = {
...defaultOptions,
}
return fetch(`${config.myEpApiBaseUrl}/api/address`, options)
.then(checkStatus)
.then(response => response.json())
.then(data => {
commit('setUserData', data)
if (data.watchlist) {
commit('setWatchlist', data.watchlist)
}
})
.catch(handleError)
.finally(() => {
commit('endLoading')
})
},
saveAddress({commit, state}, data) {
commit('beginLoading')
const options = {
...defaultOptions,
method: 'PUT',
body: JSON.stringify(data)
}
return fetch(`${config.myEpApiBaseUrl}/api/address`, options)
.then(checkStatus)
.then(response => response.json())
.then(() => {
commit('alert', {
message: 'Die Änderungen wurden gespeichert',
success: true,
})
})
.catch(handleError)
.finally(() => {
commit('endLoading')
})
} }
}, },
getters: { getters: {
@@ -44,7 +44,7 @@
<source>Details</source> <source>Details</source>
</trans-unit> </trans-unit>
<trans-unit id="tx_eptheme.label.to_inquiry_form"> <trans-unit id="tx_eptheme.label.to_inquiry_form">
<source>Inquiry Form</source> <source>Directly to the request form</source>
</trans-unit> </trans-unit>
<trans-unit id="tx_eptheme_domain_model_lineup"> <trans-unit id="tx_eptheme_domain_model_lineup">
<source>Lineup</source> <source>Lineup</source>
@@ -18,32 +18,33 @@
{concept.description -> f:format.html()} {concept.description -> f:format.html()}
</div> </div>
<f:if condition="{teasers}"> <f:if condition="{teasers}">
<a class="anchor" id="teasers"></a> <f:then>
<div class="bg-zinc-50 p-4 mb-4" <a class="anchor" id="teasers"></a>
data-controller="teasergrid" <div class="bg-zinc-50 p-4 mb-4"
data-teasergrid-grid-class="grid-cols-2" data-controller="teasergrid"
data-teasergrid-disabled-value="false"> data-teasergrid-grid-class="grid-cols-2"
<div class="flex items-center space-x-1 mb-2 sm:hidden"> data-teasergrid-disabled-value="false">
<button type="button" <div class="flex items-center space-x-1 mb-2 sm:hidden">
class="opacity-50" <button type="button"
data-action="teasergrid#grid" class="opacity-50"
data-teasergrid-target="button"> data-action="teasergrid#grid"
<svg class="w-5 h-5 text-ep-primary"> data-teasergrid-target="button">
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-teaser-grid"></use> <svg class="w-5 h-5 text-ep-primary">
</svg> <use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-teaser-grid"></use>
</button> </svg>
<button type="button" </button>
data-action="teasergrid#block" <button type="button"
data-teasergrid-target="button"> data-action="teasergrid#block"
<svg class="w-5 h-5 text-ep-primary"> data-teasergrid-target="button">
<use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-teaser-single"></use> <svg class="w-5 h-5 text-ep-primary">
</svg> <use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-teaser-single"></use>
</button> </svg>
</div> </button>
<div class="grid grid-cols-2 xl:grid-cols-3 gap-4 md:gap-8" </div>
data-teasergrid-target="container"> <div class="grid grid-cols-2 xl:grid-cols-3 gap-4 md:gap-8"
<f:for each="{teasers}" as="teaser" iteration="iteration"> data-teasergrid-target="container">
<f:render partial="Product/Teaser" section="Teaser" arguments="{ <f:for each="{teasers}" as="teaser" iteration="iteration">
<f:render partial="Product/Teaser" section="Teaser" arguments="{
concept: teaser.concept, concept: teaser.concept,
hotel: teaser.hotel, hotel: teaser.hotel,
product: teaser.product, product: teaser.product,
@@ -60,26 +61,37 @@
dateTo: dateTo, dateTo: dateTo,
index: iteration.index index: iteration.index
}"/> }"/>
</f:for> </f:for>
</div>
<f:if condition="{settings.hideMoreLink}">
<f:else>
<div class="text-right mt-4">
<f:link.typolink class="button bg-button"
parameter="{settings.defaultSearchPageUid}"
additionalParams="f={filterSettings -> ep:filterSettingsEncoder()}">
Alle anzeigen
</f:link.typolink>
</div>
</f:else>
</f:if>
</div> </div>
<f:if condition="{settings.hideMoreLink}"> </f:then>
<f:else> <f:else>
<div class="text-right mt-4"> <f:if condition="{concept.images -> f:count()} > 0">
<f:link.typolink class="button bg-button" <f:render partial="ImageGallery" arguments="{images: concept.images, id: 'concept-{concept.uid}', thumbnails: 1}"/>
parameter="{settings.defaultSearchPageUid}"
additionalParams="f={filterSettings -> ep:filterSettingsEncoder()}">
Alle anzeigen
</f:link.typolink>
</div>
</f:else>
</f:if> </f:if>
</div> </f:else>
</f:if> </f:if>
<f:if condition="{concept.descriptionExtended}"> <f:if condition="{concept.descriptionExtended}">
<div data-rte-content> <div data-rte-content>
{concept.descriptionExtended -> f:format.html()} {concept.descriptionExtended -> f:format.html()}
</div> </div>
</f:if> </f:if>
<f:if condition="{teasers}">
<f:if condition="{concept.images -> f:count()} > 0">
<f:render partial="ImageGallery" arguments="{images: concept.images, id: 'concept-{concept.uid}', thumbnails: 1}"/>
</f:if>
</f:if>
</div> </div>
<div class="col-span-3 lg:col-span-1"> <div class="col-span-3 lg:col-span-1">
<ul class="list-none p-0 m-0 space-y-2"> <ul class="list-none p-0 m-0 space-y-2">
@@ -13,6 +13,7 @@
configs-json='{configs}' configs-json='{configs}'
boards-json='{boards}' boards-json='{boards}'
options-json='{options}' options-json='{options}'
running-costs-factor="{runningCosts}"
endpoint="{ep:uri.ajax(action: 'processForm', controller: 'AjaxGroupsPrice', pageUid: settings.defaultAjaxUid, arguments: '{hotel: hotel}')}" endpoint="{ep:uri.ajax(action: 'processForm', controller: 'AjaxGroupsPrice', pageUid: settings.defaultAjaxUid, arguments: '{hotel: hotel}')}"
loader-uri="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif')}" loader-uri="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif')}"
> >
@@ -69,19 +69,13 @@
</ul> </ul>
</f:if> </f:if>
<f:if condition="{newsItem.allRelatedSorted}"> <f:if condition="{newsItem.allRelatedSorted}">
<h3 class="headline headline--underlined"> <h3 class="headline headline--underlined mt-8">
Ähnliche Beiträge Ähnliche Beiträge
</h3> </h3>
<ul class="list-none p-0 mb-4"> <f:for each="{newsItem.allRelatedSorted}" as="newsItem" iteration="iterator">
<f:for each="{newsItem.allRelatedSorted}" as="related"> <f:render partial="List/Item"
<li> arguments="{newsItem: newsItem,settings:settings,iterator:iterator}" />
<n:link newsItem="{related}" settings="{settings}" title="{related.title}"> </f:for>
{related.title}
</n:link>
</li>
</f:for>
</ul>
</f:if> </f:if>
<f:if condition="{settings.backPid}"> <f:if condition="{settings.backPid}">
<f:link.typolink parameter="{settings.backPid}" class="button bg-button button--small"> <f:link.typolink parameter="{settings.backPid}" class="button bg-button button--small">
@@ -4,22 +4,17 @@
<f:section name="content"> <f:section name="content">
<f:if condition="{tags}"> <f:if condition="{tags}">
<h3>Themen</h3> <h3 class="headline headline--underlined">Themen</h3>
<ul class="blog-tags"> <ul>
<f:for each="{tags}" as="tag"> <f:for each="{tags}" as="tag">
<li> <li>
<f:if condition="{tag.uid} == {overwriteDemand.tags}"> <f:link.page title="{tag.title}" pageUid="{settings.listPid}" additionalParams="{tx_news_pi1:{overwriteDemand:{tags: tag}}}"
<f:then> class="flex items-center space-x-2 {f:if(condition: '{tag.uid} == {overwriteDemand.tags}', then: 'text-ep-primary-dark')}">
<f:link.page title="{tag.title}" class="active" pageUid="{settings.listPid}" additionalParams="{tx_news_pi1:{overwriteDemand:{tags: tag}}}"> <svg class="w-5 h-5">
{tag.title} <use href="{f:uri.image(src: 'EXT:ep_theme/Resources/Public/images/icons_sprite.svg')}#icon-tag"></use>
</f:link.page> </svg>
</f:then> <span class="flex-1">{tag.title}</span>
<f:else> </f:link.page>
<f:link.page title="{tag.title}" pageUid="{settings.listPid}" additionalParams="{tx_news_pi1:{overwriteDemand:{tags: tag}}}">
{tag.title}
</f:link.page>
</f:else>
</f:if>
</li> </li>
</f:for> </f:for>
</ul> </ul>