diff --git a/composer.json b/composer.json index 634df32d..34bcb641 100644 --- a/composer.json +++ b/composer.json @@ -21,6 +21,7 @@ "helhum/typo3-console": "^5.6", "league/csv": "^9.2", "pixelant/pxa-social-feed": "^1.10", + "symfony/http-client": "^4.3", "symfony/options-resolver": "^4.2", "symfony/property-access": "^4.3", "symfony/serializer": "^4.2", diff --git a/composer.lock b/composer.lock index b837f6b5..2b9cd1e2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d4ae2398be4121ef52aadf3eb1277575", + "content-hash": "65c7db27e084cf03eddd1ddb83812563", "packages": [ { "name": "algo26-matthias/idna-convert", @@ -2122,6 +2122,125 @@ "homepage": "https://symfony.com", "time": "2019-08-14T12:26:46+00:00" }, + { + "name": "symfony/http-client", + "version": "v4.3.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "9a4fa769269ed730196a5c52c742b30600cf1e87" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/9a4fa769269ed730196a5c52c742b30600cf1e87", + "reference": "9a4fa769269ed730196a5c52c742b30600cf1e87", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "psr/log": "^1.0", + "symfony/http-client-contracts": "^1.1.6", + "symfony/polyfill-php73": "^1.11" + }, + "provide": { + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "1.1" + }, + "require-dev": { + "nyholm/psr7": "^1.0", + "psr/http-client": "^1.0", + "symfony/http-kernel": "^4.3", + "symfony/process": "^4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony HttpClient component", + "homepage": "https://symfony.com", + "time": "2019-08-20T14:27:59+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v1.1.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "6005fe61a33724405d56eb5b055d5d370192a1bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/6005fe61a33724405d56eb5b055d5d370192a1bd", + "reference": "6005fe61a33724405d56eb5b055d5d370192a1bd", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "time": "2019-08-08T10:05:21+00:00" + }, { "name": "symfony/inflector", "version": "v4.3.4", diff --git a/public/typo3conf/ext/ep_theme/Classes/Controller/AjaxFormController.php b/public/typo3conf/ext/ep_theme/Classes/Controller/AjaxFormController.php index 45f1853a..dda85a56 100644 --- a/public/typo3conf/ext/ep_theme/Classes/Controller/AjaxFormController.php +++ b/public/typo3conf/ext/ep_theme/Classes/Controller/AjaxFormController.php @@ -26,6 +26,7 @@ namespace EP\EpTheme\Controller; * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ +use EP\EpTheme\Service\BookingApiService; use EP\EpTheme\Service\EmailService; use EP\EpTheme\Domain\Model\Dto\ContactForm; use TYPO3\CMS\Extbase\Mvc\Controller\ActionController; @@ -40,12 +41,20 @@ class AjaxFormController extends ActionController protected $emailService; /** - * @param EmailService $emailService + * @var BookingApiService */ - public function __construct(EmailService $emailService) + protected $bookingApiService; + + /** + * @param EmailService $emailService + * @param BookingApiService $bookingApiService + */ + public function __construct(EmailService $emailService, BookingApiService $bookingApiService) { parent::__construct(); + $this->emailService = $emailService; + $this->bookingApiService = $bookingApiService; } /** @@ -63,6 +72,15 @@ class AjaxFormController extends ActionController [ 'contactForm' => $contactForm ] ); + $addressData = [ + 'lastName' => $contactForm->getName(), + 'firstName' => $contactForm->getFirstName(), + 'email' => $contactForm->getEmail(), + 'gender' => $contactForm->getGender(), + ]; + + $this->bookingApiService->registerAddress($addressData); + return json_encode($response); } diff --git a/public/typo3conf/ext/ep_theme/Classes/Domain/Model/Dto/ContactForm.php b/public/typo3conf/ext/ep_theme/Classes/Domain/Model/Dto/ContactForm.php index 164d718c..3c046ddb 100644 --- a/public/typo3conf/ext/ep_theme/Classes/Domain/Model/Dto/ContactForm.php +++ b/public/typo3conf/ext/ep_theme/Classes/Domain/Model/Dto/ContactForm.php @@ -42,6 +42,18 @@ class ContactForm */ protected $name; + /** + * @var string + * @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty") + */ + protected $firstName; + + /** + * @var string + * @TYPO3\CMS\Extbase\Annotation\Validate("NotEmpty") + */ + protected $gender; + /** * @var string */ @@ -121,6 +133,38 @@ class ContactForm $this->name = $name; } + /** + * @return string + */ + public function getFirstName() + { + return $this->firstName; + } + + /** + * @param string $firstName + */ + public function setFirstName($firstName) + { + $this->firstName = $firstName; + } + + /** + * @return string + */ + public function getGender() + { + return $this->gender; + } + + /** + * @param string $gender + */ + public function setGender($gender) + { + $this->gender = $gender; + } + /** * @return string */ diff --git a/public/typo3conf/ext/ep_theme/Classes/Form/BpnApiFinisher.php b/public/typo3conf/ext/ep_theme/Classes/Form/BpnApiFinisher.php new file mode 100644 index 00000000..6f1f3fa2 --- /dev/null +++ b/public/typo3conf/ext/ep_theme/Classes/Form/BpnApiFinisher.php @@ -0,0 +1,52 @@ +, 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\EpTheme\Service\BookingApiService; +use TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher; + +class BpnApiFinisher extends AbstractFinisher +{ + /** + * @var BookingApiService + */ + protected $bookingApiService; + + /** + * @param BookingApiService $bookingApiService + */ + public function injectBookingApiService(BookingApiService $bookingApiService) + { + $this->bookingApiService = $bookingApiService; + } + + protected function executeInternal() + { + $formValues = $this->finisherContext->getFormValues(); + $this->bookingApiService->registerAddress($formValues); + } +} \ No newline at end of file diff --git a/public/typo3conf/ext/ep_theme/Classes/Service/BookingApiService.php b/public/typo3conf/ext/ep_theme/Classes/Service/BookingApiService.php new file mode 100644 index 00000000..ffbcbfa4 --- /dev/null +++ b/public/typo3conf/ext/ep_theme/Classes/Service/BookingApiService.php @@ -0,0 +1,91 @@ +, 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 Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use TYPO3\CMS\Core\SingletonInterface; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Configuration\ConfigurationManagerInterface; + +class BookingApiService implements SingletonInterface, LoggerAwareInterface +{ + use LoggerAwareTrait; + + /** + * @var string + */ + protected $apiToken; + + /** + * @var string + */ + protected $apiEndpointUrl; + + /** + * @var int + */ + protected $apiTimeout; + + /** + * @param ConfigurationManagerInterface $manager + */ + public function __construct(ConfigurationManagerInterface $manager) + { + $settings = GeneralUtility::removeDotsFromTS( + $manager->getConfiguration(ConfigurationManagerInterface::CONFIGURATION_TYPE_FULL_TYPOSCRIPT) + ); + + $this->apiToken = $settings['plugin']['tx_eptheme']['settings']['myEpApiToken']; + $this->apiEndpointUrl = $settings['plugin']['tx_eptheme']['settings']['myEpApiEndpointUrl']; + $this->apiTimeout = $settings['plugin']['tx_eptheme']['settings']['myEpApiTimeout']; + } + + /** + * @param array $addressData + */ + public function registerAddress(array $addressData) + { + $client = HttpClient::create(); + + try { + $client->request('POST', $this->apiEndpointUrl . '/api/contactform', [ + 'headers' => [ + 'X-AUTH-TOKEN' => $this->apiToken, + 'Content-type' => 'application/json', + ], + 'timeout' => $this->apiTimeout, + 'body' => json_encode($addressData), + ]); + } + catch (TransportExceptionInterface $e) { + $this->logger->error($e->getMessage()); + } + } +} \ No newline at end of file diff --git a/public/typo3conf/ext/ep_theme/Configuration/Forms/FormSetup.yaml b/public/typo3conf/ext/ep_theme/Configuration/Forms/FormSetup.yaml index 3bea7e5e..ec06bc77 100644 --- a/public/typo3conf/ext/ep_theme/Configuration/Forms/FormSetup.yaml +++ b/public/typo3conf/ext/ep_theme/Configuration/Forms/FormSetup.yaml @@ -11,6 +11,9 @@ TYPO3: prototypes: standard: + finishersDefinition: + BpnApiFinisher: + implementationClassName: 'EP\EpTheme\Form\BpnApiFinisher' formElementsDefinition: Form: renderingOptions: diff --git a/public/typo3conf/ext/ep_theme/Configuration/TypoScript/constants.typoscript b/public/typo3conf/ext/ep_theme/Configuration/TypoScript/constants.typoscript index d2f59e8e..114b9ba5 100644 --- a/public/typo3conf/ext/ep_theme/Configuration/TypoScript/constants.typoscript +++ b/public/typo3conf/ext/ep_theme/Configuration/TypoScript/constants.typoscript @@ -156,8 +156,12 @@ plugin.tx_eptheme { # cat=eptheme.events; type=string; label=Partner ID selection label partnerIdSelectLabel = - # cat=eptheme/900/100; type=string; label=MyE&P API base url - myEpApiBaseUrl = https://myep.burn.dpn + # cat=eptheme/900/100; type=string; label=MyE&P API endpoint url for contactforms + myEpApiEndpointUrl = https://myep.burn.dpn/api/contactform + # cat=eptheme/900/110; type=string; label=MyE&P API timeout in seconds + myEpApiTimeout = 10 + # cat=eptheme/900/120; type=string; label=MyE&P API auth token + myEpApiToken = thisisnotsecretsochangeit } } diff --git a/public/typo3conf/ext/ep_theme/Configuration/TypoScript/setup.typoscript b/public/typo3conf/ext/ep_theme/Configuration/TypoScript/setup.typoscript index b08396db..5d7df14c 100644 --- a/public/typo3conf/ext/ep_theme/Configuration/TypoScript/setup.typoscript +++ b/public/typo3conf/ext/ep_theme/Configuration/TypoScript/setup.typoscript @@ -87,7 +87,9 @@ plugin.tx_eptheme { germanPageUid = {$plugin.tx_eptheme.settings.germanPageUid} conceptsPageUid = {$plugin.tx_eptheme.settings.conceptsPageUid} myEpPageUid = {$plugin.tx_eptheme.settings.myEpPageUid} - myEpApiBaseUrl = {$plugin.tx_eptheme.settings.myEpApiBaseUrl} + myEpApiEndpointUrl = {$plugin.tx_eptheme.settings.myEpApiEndpointUrl} + myEpApiToken = {$plugin.tx_eptheme.settings.myEpApiToken} + myEpApiTimeout = {$plugin.tx_eptheme.settings.myEpApiTimeout} facebookViewContentValues { productUid = {$plugin.tx_eptheme.settings.facebookViewContentProductUid} nameInternal = {$plugin.tx_eptheme.settings.facebookViewContentNameInternal} diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_app.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_app.js index 059117b3..addd73e5 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_app.js +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_app.js @@ -45,7 +45,7 @@ Vue.filter('date', (value) => { }); // Store -import store from './_store'; +import store from './store'; // Initialize vue app new Vue({ @@ -65,7 +65,7 @@ new Vue({ Watchlist, HotelList, BackLink, - MyEp: () => import('./myep/components/App.vue'), + MyEp: () => import('./myep/App.vue'), FacebookPixel }, data () { @@ -355,8 +355,7 @@ new Vue({ } }, created () { - this.$store.commit('initConfig'); - this.$store.commit('initWatchlist'); + this.$store.dispatch('init'); EventBus.$on('ajaxContentLoaded', () => { Vue.nextTick(() => { this.initContentsliders(); diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_store.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_store.js deleted file mode 100644 index e04e000a..00000000 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/_store.js +++ /dev/null @@ -1,249 +0,0 @@ -import Vue from 'vue' -import Vuex from 'vuex' -import axios from 'axios' - -import AddressStore from './myep/stores/address' -import CrmDataStore from './myep/stores/crmdata' -import TeamerStore from './myep/stores/teamer' -import EventsStore from './myep/stores/events' -import NewsletterStore from './myep/stores/newsletter' - -Vue.use(Vuex); - -export default new Vuex.Store({ - modules: { - address: AddressStore, - crmdata: CrmDataStore, - teamer: TeamerStore, - events: EventsStore, - newsletter: NewsletterStore - }, - state: { - config: {}, - watchlist: [], - loading: false, - authToken: sessionStorage.getItem('token'), - loggedIn: !!sessionStorage.getItem('token'), - isTeamer: JSON.parse(sessionStorage.getItem('isTeamer')), - memberId: JSON.parse(sessionStorage.getItem('memberId')), - memberName: sessionStorage.getItem('memberName'), - countries: [], - abilities: [], - timeFrames: [], - jobProfiles: [], - message: { - text: '', - class: '' - } - }, - mutations: { - initConfig (state) { - const configElement = document.getElementById('appconfig'); - state.config = JSON.parse(configElement.innerHTML); - axios.defaults.baseURL = state.config.myEpApiBaseUrl; - }, - initWatchlist (state, list = null) { - if (list) { - sessionStorage.setItem('watchlist', JSON.stringify(list)); - } else if (!sessionStorage.getItem('watchlist')) { - sessionStorage.setItem('watchlist', JSON.stringify({ id: null, items: [] })); - } - state.watchlist = JSON.parse(sessionStorage.getItem('watchlist')); - }, - watchlistToggle (state, uid) { - let list = state.watchlist.items; - let watchlistIndex = list.indexOf(uid); - if (watchlistIndex === -1) { - list.push(uid) - } else { - list.splice(watchlistIndex, 1) - } - state.watchlist.items = list; - sessionStorage.setItem('watchlist', JSON.stringify(state.watchlist)); - - if (state.loggedIn) { - const client = axios.create({ - headers: { - 'X-Auth-Token': state.authToken - } - }); - client.put('/api/watchlists/' + state.watchlist.id, state.watchlist); - } - }, - loginSuccess (state, token) { - state.loggedIn = true; - state.authToken = token; - sessionStorage.setItem('token', token); - }, - loginFailure (state) { - state.loggedIn = false; - }, - logout (state) { - state.loggedIn = false; - state.isTeamer = false; - state.teamerId = null; - state.authToken = null; - state.watchlist = { id: null, items: [] }; - sessionStorage.removeItem('token'); - sessionStorage.removeItem('isTeamer'); - sessionStorage.removeItem('memberId'); - sessionStorage.removeItem('memberName'); - sessionStorage.removeItem('watchlist'); - }, - alert (state, payload) { - state.message.text = payload.message; - state.message.class = payload.class; - }, - isTeamer (state) { - state.isTeamer = true; - sessionStorage.setItem('isTeamer', JSON.stringify(true)); - }, - setMember (state, member) { - state.memberId = member.id; - state.memberName = member.name; - sessionStorage.setItem('memberId', member.id); - sessionStorage.setItem('memberName', member.name); - }, - loadingBegin (state) { - state.loading = true; - state.message.text = ''; - state.message.class = ''; - }, - loadingFinish (state) { - state.loading = false; - }, - setCountries (state, countries) { - state.countries = countries; - }, - setAbilities (state, abilities) { - state.abilities = abilities; - }, - setTimeFrames (state, timeFrames) { - state.timeFrames = timeFrames; - }, - setJobProfiles (state, jobProfiles) { - state.jobProfiles = jobProfiles; - } - }, - actions: { - login({ commit }, credentials) { - commit('loadingBegin'); - const formData = new FormData(); - formData.append('_username', credentials.email); - formData.append('_password', credentials.password); - return axios({ - url: '/api/login', - data: formData, - method: 'post', - withCredentials: true - }).then((response) => { - let memberId = parseInt(response.data.member_id); - commit('setMember', { id: memberId, name: response.data.member_name }); - if (response.data.watchlist) { - commit('initWatchlist', response.data.watchlist); - } - if (response.data.is_teamer) { - commit('isTeamer'); - } - commit('loginSuccess', response.data.token); - commit('loadingFinish'); - }).catch((error) => { - commit('loginFailure'); - commit('alert', { - message: 'Der Login ist fehlgeschlagen :(', - class: 'alert-danger' - }); - commit('loadingFinish'); - throw error; - }); - }, - logout({ commit, state }) { - commit('loadingBegin'); - return axios({ - url: '/api/logout', - headers: { - 'x-auth-token': state.authToken - } - }).then(() => { - commit('logout'); - commit('loadingFinish'); - }).catch((error) => { - commit('alert', { - message: 'Der Logout ist fehlgeschlagen :(', - class: 'alert-danger' - }); - commit('loadingFinish'); - throw error; - }); - }, - resetPassword({ commit }, email) { - commit('loadingBegin'); - const formData = new FormData(); - formData.append('email', email); - return axios({ - url: '/api/reset-password', - data: formData, - method: 'post' - }).then((response) => { - commit('loadingFinish'); - return response; - }).catch((error) => { - commit('loadingFinish'); - throw error; - }); - }, - register({ commit }, userData) { - commit('loadingBegin'); - return axios({ - url: '/api/addresses', - data: userData, - method: 'post' - }).then((response) => { - commit('loadingFinish'); - return response; - }).catch((error) => { - commit('loadingFinish'); - throw error; - }); - }, - loadSelectableValues ({ commit }) { - axios({ - url: '/api/countries', - }).then((response) => { - commit('setCountries', response.data['hydra:member']); - }); - axios({ - url: '/api/teamer-abilities', - }).then((response) => { - commit('setAbilities', response.data['hydra:member']); - }); - axios({ - url: '/api/timeframes', - }).then((response) => { - commit('setTimeFrames', response.data['hydra:member']); - }); - axios({ - url: '/api/teamer-job-profiles', - }).then((response) => { - commit('setJobProfiles', response.data['hydra:member']); - }); - } - }, - getters: { - watchlistCount: state => { - return state.watchlist.items.length; - }, - onWatchlist: (state) => (uid) => { - return state.watchlist.items.indexOf(uid) !== -1; - }, - authToken: state => { - return state.authToken; - }, - isTeamer: state => { - return state.isTeamer; - }, - teamerId: state => { - return state.teamerId; - } - } -}); diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/api/index.js b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/api/index.js new file mode 100644 index 00000000..12f1a1c8 --- /dev/null +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/api/index.js @@ -0,0 +1,77 @@ +// See https://www.techynovice.com/setting-up-JWT-token-refresh-mechanism-with-axios/ + +import axios from 'axios'; + +const authenticatedClient = axios.create({ + headers: { + 'Authentication': 'Bearer ' + sessionStorage.getItem('token') + } +}); + +authenticatedClient.interceptors.response.use( + response => response, + error => { + const errorResponse = error.response; + if (isTokenExpiredError(errorResponse)) { + return resetTokenAndReattemptRequest(error) + } + return Promise.reject(error) + } +); + +function isTokenExpiredError (errorResponse) { + if (errorResponse.config.code !== 401) { + return false + } + + return errorResponse.message.match(/expired/); +} + +let isAlreadyFetchingAccessToken = false; +let subscribers = []; + +async function resetTokenAndReattemptRequest (error) { + try { + const { response: errorResponse } = error; + const refreshToken = await getRefreshToken(); + if (!refreshToken) { + return Promise.reject(error); + } + const retryOriginalRequest = new Promise(resolve => { + addSubscriber(authToken => { + errorResponse.config.headers.Authorization = 'Bearer ' + authToken; + resolve(axios(errorResponse.config)); + }); + }); + if (!isAlreadyFetchingAccessToken) { + isAlreadyFetchingAccessToken = true; + axios({ + method: 'post', + url: ``, + data: { + refresh_token: refreshToken + } + }).then(response => { + if (!response.data) { + return Promise.reject(error); + } + const newToken = response.data.refresh_token; + saveRefreshToken(newToken); + isAlreadyFetchingAccessToken = false; + onAccessTokenFetched(newToken); + }); + } + return retryOriginalRequest; + } catch (err) { + return Promise.reject(err); + } +} + +function onAccessTokenFetched(access_token) { + subscribers.forEach(callback => callback(access_token)); + subscribers = []; +} + +function addSubscriber(callback) { + subscribers.push(callback); +} diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/HotelList.vue b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/HotelList.vue index d6dad1a4..64a58fd3 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/HotelList.vue +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/components/HotelList.vue @@ -1,11 +1,13 @@ diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/components/App.vue b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/App.vue similarity index 63% rename from public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/components/App.vue rename to public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/App.vue index cc1f19c3..90c0e79c 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/components/App.vue +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/App.vue @@ -2,7 +2,8 @@
-
+
-
+
- {{ $store.state.message.text }} + {{ alert.message }}
-
-
- -
+
+
- diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/components/CrmData.vue b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/CrmData.vue similarity index 60% rename from public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/components/CrmData.vue rename to public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/CrmData.vue index ddaa56ba..1e905daf 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/components/CrmData.vue +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/CrmData.vue @@ -1,10 +1,10 @@ diff --git a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/components/Login.vue b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Login.vue similarity index 68% rename from public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/components/Login.vue rename to public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Login.vue index 5f98f635..4abd5b96 100644 --- a/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/components/Login.vue +++ b/public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/myep/Login.vue @@ -4,18 +4,12 @@
-
- - -
-
- - -
+ + + + + +