WIP Migrate to stimulus.js and tailwind
This commit is contained in:
@@ -71,19 +71,6 @@ class AjaxContingentController extends ActionController
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Hotel $hotel
|
||||
* @param Product $product
|
||||
* @return string
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function listAction(Hotel $hotel, Product $product)
|
||||
{
|
||||
$enabled = $this->contingentDataService->getAvailableContingents($hotel, $product);
|
||||
|
||||
return \json_encode($enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Hotel $hotel
|
||||
* @param Product $product
|
||||
|
||||
@@ -31,6 +31,7 @@ use EP\EpProducts\Domain\Model\Date;
|
||||
use EP\EpProducts\Domain\Model\Hotel;
|
||||
use EP\EpProducts\Domain\Model\Product;
|
||||
use EP\EpProducts\Domain\Repository\ProductRepository;
|
||||
use EP\EpProducts\Service\ContingentDataService;
|
||||
use EP\EpProducts\Service\DateService;
|
||||
use EP\EpProducts\Service\FilterService;
|
||||
use EP\EpProducts\Service\ResellerDataService;
|
||||
@@ -65,22 +66,31 @@ class AjaxTableController extends ActionController
|
||||
protected $resellerDataService;
|
||||
|
||||
/**
|
||||
* @var ContingentDataService
|
||||
*/
|
||||
protected $contingentDataService;
|
||||
|
||||
/**
|
||||
* @param ProductRepository $productRepository
|
||||
* @param DateService $dateService
|
||||
* @param FilterService $filterService
|
||||
* @param ResellerDataService $resellerDataService
|
||||
* @param ContingentDataService $contingentDataService
|
||||
*/
|
||||
public function __construct
|
||||
(
|
||||
ProductRepository $productRepository,
|
||||
DateService $dateService,
|
||||
FilterService $filterService,
|
||||
ResellerDataService $resellerDataService
|
||||
ResellerDataService $resellerDataService,
|
||||
ContingentDataService $contingentDataService
|
||||
) {
|
||||
parent::__construct();
|
||||
$this->productRepository = $productRepository;
|
||||
$this->dateService = $dateService;
|
||||
$this->filterService = $filterService;
|
||||
$this->resellerDataService = $resellerDataService;
|
||||
$this->contingentDataService = $contingentDataService;
|
||||
}
|
||||
|
||||
public function initializeDatesAction()
|
||||
@@ -252,4 +262,20 @@ class AjaxTableController extends ActionController
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Hotel $hotel
|
||||
* @param Product $product
|
||||
* @param string $dateFrom
|
||||
* @param string $dateTo
|
||||
*/
|
||||
public function daytripRoomsAction(Hotel $hotel, Product $product, $dateFrom, $dateTo)
|
||||
{
|
||||
$template = $this->settings['bpnBookingUrlTemplateCode'];
|
||||
$rooms = $this
|
||||
->contingentDataService
|
||||
->getAvailableRooms($dateFrom, $dateTo, $hotel, $product, $template);
|
||||
|
||||
$this->view->assign('rooms', $rooms);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ use EP\EpProducts\Domain\Model\Hotel;
|
||||
use EP\EpProducts\Domain\Model\Product;
|
||||
use EP\EpProducts\Domain\Repository\HotelRepository;
|
||||
use EP\EpProducts\Domain\Repository\ProductRepository;
|
||||
use EP\EpProducts\Service\ContingentDataService;
|
||||
use EP\EpProducts\Service\DateService;
|
||||
use EP\EpProducts\Service\FilterService;
|
||||
use EP\EpProducts\Service\HotelDataService;
|
||||
@@ -70,12 +71,17 @@ class ProductController extends ActionController
|
||||
* @var HotelDataService
|
||||
*/
|
||||
protected $hotelDataService;
|
||||
/**
|
||||
* @var ContingentDataService
|
||||
*/
|
||||
private $contingentDataService;
|
||||
|
||||
/**
|
||||
* @param ProductRepository $productRepository
|
||||
* @param ProductDataService $productDataService
|
||||
* @param HotelRepository $hotelRepository
|
||||
* @param HotelDataService $hotelDataService
|
||||
* @param ContingentDataService $contingentDataService
|
||||
* @param DateService $dateService
|
||||
* @param FilterService $filterService
|
||||
*/
|
||||
@@ -84,6 +90,7 @@ class ProductController extends ActionController
|
||||
ProductDataService $productDataService,
|
||||
HotelRepository $hotelRepository,
|
||||
HotelDataService $hotelDataService,
|
||||
ContingentDataService $contingentDataService,
|
||||
DateService $dateService,
|
||||
FilterService $filterService
|
||||
) {
|
||||
@@ -91,8 +98,9 @@ class ProductController extends ActionController
|
||||
$this->productRepository = $productRepository;
|
||||
$this->productDataService = $productDataService;
|
||||
$this->hotelRepository = $hotelRepository;
|
||||
$this->dateService = $dateService;
|
||||
$this->hotelDataService = $hotelDataService;
|
||||
$this->contingentDataService = $contingentDataService;
|
||||
$this->dateService = $dateService;
|
||||
$this->filterService = $filterService;
|
||||
}
|
||||
|
||||
@@ -146,6 +154,14 @@ class ProductController extends ActionController
|
||||
}
|
||||
}
|
||||
|
||||
if ($product->isDaytrip()) {
|
||||
$availableContingents = $this
|
||||
->contingentDataService
|
||||
->getAvailableContingents($hotel, $product)
|
||||
;
|
||||
$enabledDates = array_keys($availableContingents);
|
||||
}
|
||||
|
||||
$excludedConceptUids = GeneralUtility::trimExplode(',', $this->settings['excludedConceptUids']);
|
||||
$isProductWithExcludedConcept = ($product->getConcept() !== null) && \in_array($product->getConcept()->getUid(),
|
||||
$excludedConceptUids, false);
|
||||
@@ -157,29 +173,10 @@ class ProductController extends ActionController
|
||||
$backlinkUrl = GeneralUtility::_GET('ref');
|
||||
$backLinkLabel = strpos($backlinkUrl, 'suche') !== -1 ? 'zurück zum Suchergebnis' : 'zurück';
|
||||
|
||||
// Generate dates uri
|
||||
$datesArguments = [
|
||||
'dateFrom' => $dateFrom,
|
||||
'dateTo' => $dateTo,
|
||||
'product' => $product,
|
||||
'hotel' => $hotel
|
||||
];
|
||||
$datesUri = $this->uriBuilder
|
||||
->reset()
|
||||
->setCreateAbsoluteUri(true)
|
||||
->setTargetPageType(1702)
|
||||
->setTargetPageUid(855)
|
||||
->uriFor(
|
||||
'dates',
|
||||
$datesArguments,
|
||||
'AjaxDate',
|
||||
'EpProducts',
|
||||
'ajax'
|
||||
);
|
||||
|
||||
$this->view->assignMultiple([
|
||||
'hotel' => $hotel,
|
||||
'product' => $product,
|
||||
'enabledDates' => $enabledDates ?? [],
|
||||
'isProductWithExcludedConcept' => $isProductWithExcludedConcept,
|
||||
'isProductWithNoInfoConcept' => $isProductWithNoInfoConcept,
|
||||
'currentPageUid' => $GLOBALS['TSFE']->id,
|
||||
@@ -187,7 +184,6 @@ class ProductController extends ActionController
|
||||
'dateTo' => $dateTo,
|
||||
'referringUrl' => $backlinkUrl,
|
||||
'backlinkLabel' => $backLinkLabel,
|
||||
'datesUri' => $datesUri,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -140,14 +140,14 @@ class ContingentRepository extends AbstractRepository implements ProviderInterfa
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTime $dateFrom
|
||||
* @param \DateTime $dateTo
|
||||
* @param string $dateFrom
|
||||
* @param string $dateTo
|
||||
* @param Hotel $hotel
|
||||
* @param Product $product
|
||||
* @return array
|
||||
* @throws DBALException
|
||||
*/
|
||||
public function getAvailableRooms(\DateTime $dateFrom, \DateTime $dateTo, Hotel $hotel, Product $product)
|
||||
public function getAvailableRooms(string $dateFrom, string $dateTo, Hotel $hotel, Product $product)
|
||||
{
|
||||
$qb = $this->getDbConnection()->createQueryBuilder();
|
||||
|
||||
@@ -157,7 +157,7 @@ class ContingentRepository extends AbstractRepository implements ProviderInterfa
|
||||
'c.additional_night_min_price as additionalNightPrice',
|
||||
'c.additional_night_min_nights as additionalNightMinNights', 'd.bus_pro_id as busProId',
|
||||
'd.services_included as servicesIncluded', 'd.services_general as servicesOptional',
|
||||
'd.skipass_included as skipassIncluded')
|
||||
'd.skipass_included as skipassIncluded', 'd.season as season')
|
||||
->from('tx_epproducts_domain_model_contingent', 'c')
|
||||
->innerJoin('c', 'tx_epproducts_domain_model_date', 'd', 'c.date = d.date_start AND c.hotel_code = d.hotel_code')
|
||||
->where('c.hotel = :hotelUid')
|
||||
@@ -168,8 +168,8 @@ class ContingentRepository extends AbstractRepository implements ProviderInterfa
|
||||
->setParameters([
|
||||
'hotelUid' => $hotel->getUid(),
|
||||
'productUid' => $product->getUid(),
|
||||
'dateFrom' => $dateFrom->format('Y-m-d'),
|
||||
'dateTo' => $dateTo->format('Y-m-d'),
|
||||
'dateFrom' => $dateFrom,
|
||||
'dateTo' => $dateTo,
|
||||
])
|
||||
->groupBy('c.room_code')
|
||||
->orderBy('c.pax')
|
||||
|
||||
@@ -31,6 +31,7 @@ use EP\EpProducts\Domain\Model\Hotel;
|
||||
use EP\EpProducts\Domain\Model\Product;
|
||||
use EP\EpProducts\Domain\Repository\ContingentRepository;
|
||||
use EP\EpProducts\Utility\BookingUrlUtility;
|
||||
use League\Period\Period;
|
||||
|
||||
class ContingentDataService
|
||||
{
|
||||
@@ -82,27 +83,32 @@ class ContingentDataService
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function getAvailableRooms(
|
||||
\DateTime $dateFrom,
|
||||
\DateTime $dateTo,
|
||||
string $dateFrom,
|
||||
string $dateTo,
|
||||
Hotel $hotel,
|
||||
Product $product,
|
||||
$template = 'base'
|
||||
) {
|
||||
$data = $this->contingentRepository->getAvailableRooms($dateFrom, $dateTo, $hotel, $product);
|
||||
$period = new Period($dateFrom, $dateTo);
|
||||
$nights = $period->getDateInterval()->format('%a');
|
||||
|
||||
$rooms = [];
|
||||
|
||||
foreach ($data as $row)
|
||||
{
|
||||
foreach ($data as $row) {
|
||||
$row['bookingUrl'] = BookingUrlUtility::generateUrl([
|
||||
'bookingId' => $row['busProId'],
|
||||
'hotelId' => $row['hotelBusProId'],
|
||||
'dateEnd' => $dateTo->format('Y-m-d'),
|
||||
'dateEnd' => $dateTo,
|
||||
'template' => $template,
|
||||
]);
|
||||
|
||||
$row['servicesIncluded'] = unserialize($row['servicesIncluded']);
|
||||
$row['servicesOptional'] = unserialize($row['servicesOptional']);
|
||||
$row['summer'] = $row['season'] === 's';
|
||||
|
||||
$row['servicesIncluded'] = unserialize($row['servicesIncluded'], ['allowed_classes' => false]);
|
||||
$row['servicesOptional'] = unserialize($row['servicesOptional'], ['allowed_classes' => false]);
|
||||
|
||||
$row['priceForSelection'] = $row['price'] + ($nights - $row['minNights']) * $row['additionalNightPrice'];
|
||||
|
||||
$rooms[] = $row;
|
||||
}
|
||||
|
||||
@@ -161,6 +161,7 @@ tx_epproducts_ajax_json {
|
||||
2 = pricetable
|
||||
3 = pricetableHtml
|
||||
4 = eventPricetable
|
||||
5 = daytripRooms
|
||||
}
|
||||
AjaxCalendar {
|
||||
1 = range
|
||||
|
||||
@@ -366,7 +366,7 @@ $iconRegistry->registerIcon(
|
||||
'AjaxSearch' => 'searchresult',
|
||||
'AjaxDate' => 'dates',
|
||||
'AjaxContingent' => 'list,rooms',
|
||||
'AjaxTable' => 'datestable,pricetable,pricetableHtml,eventPricetable',
|
||||
'AjaxTable' => 'datestable,pricetable,pricetableHtml,eventPricetable,daytripRooms',
|
||||
'AjaxCalendar' => 'range,contingents,availableRooms',
|
||||
'AjaxWatchlist' => 'list',
|
||||
'AjaxGroupsPrice' => 'processForm',
|
||||
|
||||
@@ -10,12 +10,8 @@ smoothscroll.polyfill()
|
||||
|
||||
// Alpine stuff
|
||||
import Alpine from 'alpinejs'
|
||||
import daytripDateSelect from './components/daytrip-date-select'
|
||||
import searchBar from './components/search-bar'
|
||||
import contactForm from './components/contact-form'
|
||||
|
||||
Alpine.data('daytripDateSelect', daytripDateSelect)
|
||||
Alpine.data('searchBar', searchBar)
|
||||
Alpine.data('contactForm', contactForm)
|
||||
Alpine.start()
|
||||
|
||||
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
import axios from 'axios'
|
||||
import flatpickr from 'flatpickr'
|
||||
import { German } from 'flatpickr/dist/l10n/de'
|
||||
import dayjs from 'dayjs'
|
||||
import 'dayjs/locale/de'
|
||||
|
||||
export default props => ({
|
||||
hotelName: props.hotelName,
|
||||
hotelUid: props.hotelUid,
|
||||
productUid: props.productUid,
|
||||
contingentEndpointUri: props.contingentEndpointUri,
|
||||
roomsEndpointUri: props.roomsEndpointUri,
|
||||
loading: false,
|
||||
picker: null,
|
||||
displayedFrom: dayjs().startOf('month'),
|
||||
displayedTo: dayjs().endOf('month'),
|
||||
selectedFrom: null,
|
||||
selectedTo: null,
|
||||
selectedNumberOfNights: 0,
|
||||
minNightsForSelectedDate: 0,
|
||||
availableDates: [],
|
||||
availableRooms: [],
|
||||
init() {
|
||||
this.picker = flatpickr(this.$refs.field, {
|
||||
mode: 'range',
|
||||
dateFormat: 'Y-m-d',
|
||||
locale: German,
|
||||
inline: true,
|
||||
onChange: selectedDates => {
|
||||
this.availableRooms = []
|
||||
if (selectedDates.length === 2) {
|
||||
this.selectedFrom = dayjs(selectedDates[0])
|
||||
this.selectedTo = dayjs(selectedDates[1])
|
||||
this.selectedNumberOfNights = this.getSelectedNumberOfNights()
|
||||
this.minNightsForSelectedDate = this.getMinNightsForSelectedDate()
|
||||
if (this.selectedNumberOfNights >= this.minNightsForSelectedDate) {
|
||||
this.fetchAvailableRooms()
|
||||
}
|
||||
}
|
||||
},
|
||||
onDayCreate: (dObj, dStr, fp, dayElem) => {
|
||||
const day = dayElem.dateObj.getFullYear() + '-' + ('0' + (dayElem.dateObj.getMonth()+1)).slice(-2)
|
||||
+ '-' + ('0' + dayElem.dateObj.getDate()).slice(-2)
|
||||
if (day in this.availableDates) {
|
||||
dayElem.classList.add('available')
|
||||
}
|
||||
}
|
||||
})
|
||||
this.$nextTick(() => {
|
||||
this.fetchEnabledDates()
|
||||
})
|
||||
},
|
||||
headerLabel () {
|
||||
let label = 'Buchungsoptionen'
|
||||
if (this.hotelName) {
|
||||
label += ' ' + this.hotelName
|
||||
}
|
||||
if (this.selectedFrom && this.selectedTo) {
|
||||
label += ' ' + this.selectedFrom.format('DD.MM.YY') + ' - ' + this.selectedTo.format('DD.MM.YY')
|
||||
label += ' (' + this.selectedNumberOfNights + ' Nächte)'
|
||||
}
|
||||
return label
|
||||
},
|
||||
message() {
|
||||
if (this.loading) {
|
||||
return ''
|
||||
}
|
||||
if (this.selectedFrom === null || this.selectedTo === null) {
|
||||
return 'Bitte einen Zeitraum auswählen.'
|
||||
}
|
||||
if (this.selectedNumberOfNights < this.minNightsForSelectedDate) {
|
||||
return 'Bitte mindestens ' + this.minNightsForSelectedDate + ' Nächte auswählen.'
|
||||
}
|
||||
if (this.availableRooms.length === 0) {
|
||||
return 'Im gewählten Zeitraum sind leider keine Zimmer verfügbar.'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
onDateSelected(date) {
|
||||
this.selectedDate = dayjs(date)
|
||||
},
|
||||
fetchEnabledDates() {
|
||||
this.loading = true
|
||||
const data = new FormData()
|
||||
data.set('tx_epproducts_ajax[hotel]', this.hotelUid)
|
||||
data.set('tx_epproducts_ajax[product]', this.productUid)
|
||||
axios({
|
||||
url: this.contingentEndpointUri,
|
||||
method: 'post',
|
||||
data
|
||||
}).then(response => {
|
||||
const json = response.data
|
||||
if (json) {
|
||||
this.availableDates = json
|
||||
const enabledDates = []
|
||||
for (const date in this.availableDates) {
|
||||
if (this.availableDates.hasOwnProperty(date)) {
|
||||
enabledDates.push(this.availableDates[date].date)
|
||||
}
|
||||
}
|
||||
this.picker.set('enable', enabledDates)
|
||||
this.picker.set('minDate', enabledDates[0])
|
||||
this.picker.set('maxDate', enabledDates[enabledDates.length - 1])
|
||||
this.picker.jumpToDate(enabledDates[0])
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
fetchAvailableRooms() {
|
||||
this.loading = true
|
||||
const data = new FormData()
|
||||
data.set('tx_epproducts_ajax[hotel]', this.hotelUid)
|
||||
data.set('tx_epproducts_ajax[product]', this.productUid)
|
||||
data.set('tx_epproducts_ajax[dateFrom]', this.selectedFrom.format('YYYY-MM-DD'))
|
||||
data.set('tx_epproducts_ajax[dateTo]', this.selectedTo.format('YYYY-MM-DD'))
|
||||
axios({
|
||||
url: this.roomsEndpointUri,
|
||||
method: 'post',
|
||||
data
|
||||
}).then(response => {
|
||||
this.availableRooms = response.data
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
calculatePrice (roomCode) {
|
||||
const room = this.availableRooms.find(obj => {
|
||||
return obj.code === roomCode
|
||||
});
|
||||
if (room) {
|
||||
const nights = this.getSelectedNumberOfNights()
|
||||
return room.price + (nights - room.minNights) * room.additionalNightPrice
|
||||
}
|
||||
return null;
|
||||
},
|
||||
getMinNightsForSelectedDate () {
|
||||
if (this.selectedFrom === null) {
|
||||
return 0
|
||||
}
|
||||
const key = this.selectedFrom.format('YYYY-MM-DD')
|
||||
if (!key in this.availableDates) {
|
||||
return 0
|
||||
}
|
||||
return this.availableDates[key].minNights
|
||||
},
|
||||
getSelectedNumberOfNights () {
|
||||
if (this.selectedFrom === null || this.selectedTo === null) {
|
||||
return 0
|
||||
}
|
||||
return this.selectedTo.diff(this.selectedFrom, 'days');
|
||||
}
|
||||
})
|
||||
@@ -1,143 +0,0 @@
|
||||
import axios from 'axios'
|
||||
import flatpickr from 'flatpickr'
|
||||
import { German } from 'flatpickr/dist/l10n/de'
|
||||
|
||||
export default props => ({
|
||||
loading: false,
|
||||
picker: null,
|
||||
uri: props.uri,
|
||||
sticky: props.sticky || false,
|
||||
searchParams: props.initialSearchParams,
|
||||
filterOptions: props.initialFilterOptions,
|
||||
datePresets: props.datePresets,
|
||||
show: null,
|
||||
destinationName: '',
|
||||
conceptSelected: false,
|
||||
destinationSelected: false,
|
||||
dateRangeSelected: { from: null, to: null },
|
||||
dateRangeLabel: '',
|
||||
init() {
|
||||
this.$watch('dateRangeSelected', () => {
|
||||
if (null === this.dateRangeSelected.from && null === this.dateRangeSelected.to) {
|
||||
this.searchParams.dateFrom = null
|
||||
this.searchParams.dateTo = null
|
||||
} else {
|
||||
let dateFrom = this.dateRangeSelected.from
|
||||
let dateTo = this.dateRangeSelected.to
|
||||
this.searchParams.dateFrom = flatpickr.formatDate(dateFrom, 'Y-m-d')
|
||||
this.searchParams.dateTo = flatpickr.formatDate(dateTo, 'Y-m-d')
|
||||
}
|
||||
this.updateDateRangeLabel()
|
||||
this.load()
|
||||
})
|
||||
},
|
||||
load() {
|
||||
this.loading = true
|
||||
const data = new FormData()
|
||||
data.set('tx_epproducts_ajax[searchParams]', JSON.stringify(this.searchParams))
|
||||
axios.post(this.uri, data)
|
||||
.then(response => {
|
||||
this.applyOptions(response.data)
|
||||
this.show = null
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
applyOptions(json) {
|
||||
this.filterOptions.totalResults = json.totalResults
|
||||
const filterOptions = json.filterOptions
|
||||
this.filterOptions = {
|
||||
...this.filterOptions,
|
||||
totalResults: json.totalResults,
|
||||
priceRanges: filterOptions.priceRanges,
|
||||
pax: filterOptions.pax,
|
||||
destinations: filterOptions.destinations
|
||||
}
|
||||
if (filterOptions.dateFrom !== null) {
|
||||
this.filterOptions.selectableRangeFrom = filterOptions.dateFrom
|
||||
if (this.picker !== null) {
|
||||
this.picker.set('minDate', new Date(filterOptions.dateFrom))
|
||||
}
|
||||
}
|
||||
if (filterOptions.dateTo !== null) {
|
||||
this.filterOptions.selectableRangeTo = filterOptions.dateTo
|
||||
if (this.picker !== null) {
|
||||
this.picker.set('maxDate', new Date(filterOptions.dateTo))
|
||||
}
|
||||
}
|
||||
},
|
||||
updateSearchParam(param, value) {
|
||||
this.searchParams = {...this.searchParams, [param]: value}
|
||||
this.load()
|
||||
},
|
||||
selectDateRangePreset(preset) {
|
||||
let dateFrom = new Date(preset.dateFrom)
|
||||
let dateTo = new Date(preset.dateTo)
|
||||
this.dateRangeSelected = { from: dateFrom, to: dateTo }
|
||||
this.picker.setDate([ dateFrom, dateTo ])
|
||||
},
|
||||
resetDateRange () {
|
||||
this.dateRangeSelected = { from: null, to: null }
|
||||
this.picker.clear()
|
||||
this.picker.jumpToDate()
|
||||
},
|
||||
selectDestination(uid, name, type) {
|
||||
this.destinationName = name
|
||||
this.destinationSelected = type !== 'concept'
|
||||
this.conceptSelected = type === 'concept'
|
||||
this.searchParams = {...this.searchParams, destinationUid: uid, destinationType: type}
|
||||
this.load()
|
||||
},
|
||||
resetDestination() {
|
||||
this.destinationName = ''
|
||||
this.destinationSelected = false
|
||||
this.conceptSelected = false
|
||||
this.searchParams = {...this.searchParams, destinationUid: null, destinationType: null}
|
||||
this.load()
|
||||
},
|
||||
initDatePicker() {
|
||||
this.picker = flatpickr(this.$refs.picker, {
|
||||
mode: 'range',
|
||||
locale: German,
|
||||
inline: true,
|
||||
onChange: selectedDates => {
|
||||
if (selectedDates.length === 2) {
|
||||
this.dateRangeSelected = { from: selectedDates[0], to: selectedDates[1] }
|
||||
}
|
||||
}
|
||||
})
|
||||
let minDate = this.filterOptions.dateFrom ? new Date(this.filterOptions.dateFrom) : new Date
|
||||
this.picker.set('minDate', minDate)
|
||||
if (this.filterOptions.dateTo) {
|
||||
this.picker.set('maxDate', new Date(this.filterOptions.dateTo))
|
||||
}
|
||||
},
|
||||
priceRangeLabel() {
|
||||
if (null === this.searchParams.priceRange) {
|
||||
return ''
|
||||
}
|
||||
let range = this.filterOptions.priceRanges[this.searchParams.priceRange]
|
||||
return this.priceRangeFormatted(range)
|
||||
},
|
||||
priceRangeFormatted(range) {
|
||||
let min = range.min;
|
||||
let max = range.max;
|
||||
if (min === 1) {
|
||||
return 'bis ' + max + ' €'
|
||||
}
|
||||
if (max === 999) {
|
||||
return 'ab ' + min + ' €'
|
||||
}
|
||||
return min + ' - ' + max + ' €'
|
||||
},
|
||||
updateDateRangeLabel() {
|
||||
let dateRangeLabel = ''
|
||||
if (null !== this.dateRangeSelected.from && null !== this.dateRangeSelected.to) {
|
||||
let dateFrom = this.dateRangeSelected.from
|
||||
let dateTo = this.dateRangeSelected.to
|
||||
dateRangeLabel = `${flatpickr.formatDate(dateFrom, 'd.m.Y')} - ${flatpickr.formatDate(dateTo, 'd.m.Y')}`
|
||||
}
|
||||
this.dateRangeLabel = dateRangeLabel
|
||||
},
|
||||
})
|
||||
+19
@@ -15,6 +15,7 @@ export default class extends Controller {
|
||||
minDate: String,
|
||||
dateFrom: String,
|
||||
dateTo: String,
|
||||
enabledDates: Array,
|
||||
}
|
||||
|
||||
initialize() {
|
||||
@@ -33,6 +34,24 @@ export default class extends Controller {
|
||||
}
|
||||
}
|
||||
})
|
||||
if (this.hasEnabledDatesValue) {
|
||||
let enabledDates = this.enabledDatesValue
|
||||
let minDate = enabledDates[0]
|
||||
let maxDate = enabledDates[enabledDates.length - 1]
|
||||
if (this.hasMinDateValue && this.minDateValue > minDate) {
|
||||
minDate = this.minDateValue
|
||||
}
|
||||
this.picker.set('enable', enabledDates)
|
||||
this.picker.set('minDate', minDate)
|
||||
this.picker.set('maxDate', maxDate)
|
||||
this.picker.jumpToDate(minDate)
|
||||
this.picker.set('onDayCreate', (dObj, dStr, fp, dayElem) => {
|
||||
let day = flatpickr.formatDate(dayElem.dateObj, 'Y-m-d')
|
||||
if (day >= minDate && -1 !== this.enabledDatesValue.indexOf(day)) {
|
||||
dayElem.classList.add('available')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
connect() {
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
import { Controller } from 'stimulus'
|
||||
import { useDispatch } from 'stimulus-use'
|
||||
import { useFetch } from '../mixins/use_fetch'
|
||||
|
||||
export default class extends Controller {
|
||||
|
||||
static targets = [
|
||||
'headerLabel',
|
||||
'container',
|
||||
'loadingIndicator',
|
||||
'message',
|
||||
]
|
||||
|
||||
static values = {
|
||||
loading: Boolean,
|
||||
contingentsUri: String,
|
||||
roomsUri: String,
|
||||
hotelUid: Number,
|
||||
productUid: Number,
|
||||
dateFrom: String,
|
||||
dateTo: String,
|
||||
}
|
||||
|
||||
initialize() {
|
||||
useDispatch(this)
|
||||
useFetch(this)
|
||||
}
|
||||
|
||||
openModal(e) {
|
||||
let eventName = `${e.currentTarget.dataset.type}-modal:open`
|
||||
this.dispatch(eventName, e.currentTarget.dataset.uid)
|
||||
}
|
||||
|
||||
load(e) {
|
||||
this.loadingValue = true
|
||||
this.dateFromValue = e.detail.from
|
||||
this.dateToValue = e.detail.to
|
||||
let data = new FormData()
|
||||
data.set('tx_epproducts_ajax[hotel]', this.hotelUidValue)
|
||||
data.set('tx_epproducts_ajax[product]', this.productUidValue)
|
||||
data.set('tx_epproducts_ajax[dateFrom]', this.dateFromValue)
|
||||
data.set('tx_epproducts_ajax[dateTo]', this.dateToValue)
|
||||
fetch(this.roomsUriValue, { method: 'POST', body: data })
|
||||
.then(this.checkStatus)
|
||||
.then(this.parseHTML)
|
||||
.then(html => {
|
||||
this.containerTarget.innerHTML = html
|
||||
this.messageTarget.classList.add('hidden')
|
||||
})
|
||||
.finally(() => {
|
||||
this.loadingValue = false
|
||||
})
|
||||
}
|
||||
|
||||
loadingValueChanged() {
|
||||
this.loadingIndicatorTarget.classList.toggle('hidden', this.loadingValue === false)
|
||||
}
|
||||
}
|
||||
+8
-3
@@ -18,6 +18,7 @@ export default class extends Controller {
|
||||
loading: Boolean,
|
||||
loaded: Boolean,
|
||||
mode: String,
|
||||
daytrip: Boolean,
|
||||
}
|
||||
|
||||
initialize() {
|
||||
@@ -26,7 +27,7 @@ export default class extends Controller {
|
||||
}
|
||||
|
||||
connect() {
|
||||
if ('dates' === this.modeValue) {
|
||||
if (false === this.dayTripValue && 'dates' === this.modeValue) {
|
||||
this.loadDates()
|
||||
}
|
||||
}
|
||||
@@ -86,7 +87,11 @@ export default class extends Controller {
|
||||
}
|
||||
|
||||
modeValueChanged() {
|
||||
this.datesTableContainerTarget.classList.toggle('hidden', this.modeValue === 'prices')
|
||||
this.priceTableContainerTarget.classList.toggle('hidden', this.modeValue === 'dates')
|
||||
if (this.hasDatesTableContainerTarget) {
|
||||
this.datesTableContainerTarget.classList.toggle('hidden', this.modeValue === 'prices')
|
||||
}
|
||||
if (this.hasPriceTableContainerTarget) {
|
||||
this.priceTableContainerTarget.classList.toggle('hidden', this.modeValue === 'dates')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-5
@@ -24,7 +24,7 @@ export default class extends Controller {
|
||||
this.dateRangeLabelTarget.value = e.detail.label
|
||||
this.dateFromTarget.value = e.detail.from
|
||||
this.dateToTarget.value = e.detail.to
|
||||
this.dispatch('input')
|
||||
this.dispatch('input', this.getDetails())
|
||||
}
|
||||
|
||||
setPax(e) {
|
||||
@@ -32,7 +32,7 @@ export default class extends Controller {
|
||||
let pax = e.currentTarget.dataset.option
|
||||
this.paxTarget.value = pax
|
||||
this.paxLabelTarget.value = pax
|
||||
this.dispatch('input')
|
||||
this.dispatch('input', this.getDetails())
|
||||
}
|
||||
|
||||
setDestination(e) {
|
||||
@@ -40,7 +40,7 @@ export default class extends Controller {
|
||||
this.destinationUidTarget.value = e.currentTarget.dataset.optionUid
|
||||
this.destinationTypeTarget.value = e.currentTarget.dataset.optionType
|
||||
this.destinationLabelTarget.value = e.currentTarget.dataset.optionLabel
|
||||
this.dispatch('input')
|
||||
this.dispatch('input', this.getDetails())
|
||||
}
|
||||
|
||||
resetDestination(e) {
|
||||
@@ -48,13 +48,24 @@ export default class extends Controller {
|
||||
this.destinationUidTarget.value = ''
|
||||
this.destinationTypeTarget.value = ''
|
||||
this.destinationLabelTarget.value = ''
|
||||
this.dispatch('input')
|
||||
this.dispatch('input', this.getDetails())
|
||||
}
|
||||
|
||||
setPriceRange(e) {
|
||||
e.preventDefault()
|
||||
this.priceRangeTarget.value = e.currentTarget.dataset.optionValue
|
||||
this.priceRangeLabelTarget.value = e.currentTarget.dataset.labelValue
|
||||
this.dispatch('input')
|
||||
this.dispatch('input', this.getDetails())
|
||||
}
|
||||
|
||||
getDetails() {
|
||||
return {
|
||||
dateFrom: this.dateFromTarget.value,
|
||||
dateTo: this.dateToTarget.value,
|
||||
pax: this.paxTarget.value,
|
||||
destinationUid: this.destinationUidTarget.value,
|
||||
destinationType: this.destinationTypeTarget.value,
|
||||
priceRange: this.priceRangeTarget.value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -33,6 +33,7 @@ export default class extends Controller {
|
||||
}
|
||||
|
||||
stickyValueChanged() {
|
||||
this.element.classList.toggle(this.stickyClass, this.stickyValue)
|
||||
let stickyClass = this.hasStickyClass ? this.stickyClass : 'sticky'
|
||||
this.element.classList.toggle(stickyClass, this.stickyValue)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<html data-namespace-typo3-fluid="true" lang="en"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,57 @@
|
||||
<html data-namespace-typo3-fluid="true" lang="en"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers">
|
||||
|
||||
<f:form id="contactform" object="{contactForm}" name="contactForm"
|
||||
action="processForm" controller="AjaxForm" pluginName="Ajax" pageType="1803"
|
||||
pageUid="{settings.defaultAjaxUid}"
|
||||
data="{'contactform-target': 'form', 'action': 'contactform#submit'}">
|
||||
<f:form.hidden property="pageUrl"/>
|
||||
<label class="block mb-4 hidden">
|
||||
<span class="text-gray-700">Betreff*</span>
|
||||
<f:form.textfield class="border-gray-400 focus:border-gray-800 mt-1 w-full" property="subject"/>
|
||||
</label>
|
||||
<label class="block mb-4" x-bind:class="'has-validation-error' && formErrors.gender">
|
||||
<span x-bind:class="formErrors.gender ? 'text-red-500' : 'text-gray-700'">Gender*</span>
|
||||
<f:form.select class="border-gray-400 focus:border-gray-800 mt-1 w-full" property="gender" options="{M: 'M', W: 'W', D: 'D'}"/>
|
||||
<div class="text-red-500" x-show="formErrors.gender" x-html="formErrors.gender"></div>
|
||||
</label>
|
||||
<label class="block mb-4" x-bind:class="'has-validation-error' && formErrors.name">
|
||||
<span x-bind:class="formErrors.name ? 'text-red-500' : 'text-gray-700'">Name*</span>
|
||||
<f:form.textfield class="border-gray-400 focus:border-gray-800 mt-1 w-full" property="name"/>
|
||||
<div class="text-red-500" x-show="formErrors.name" x-html="formErrors.name"></div>
|
||||
</label>
|
||||
<label class="block mb-4" x-bind:class="'has-validation-error' && formErrors.firstName">
|
||||
<span x-bind:class="formErrors.firstName ? 'text-red-500' : 'text-gray-700'">Vorname*</span>
|
||||
<f:form.textfield class="border-gray-400 focus:border-gray-800 mt-1 w-full" property="firstName"/>
|
||||
<div class="text-red-500" x-show="formErrors.firstName" x-html="formErrors.firstName"></div>
|
||||
</label>
|
||||
<label class="block mb-4" x-bind:class="'has-validation-error' && formErrors.email">
|
||||
<span x-bind:class="formErrors.email ? 'text-red-500' : 'text-gray-700'">E-Mail*</span>
|
||||
<f:form.textfield class="border-gray-400 focus:border-gray-800 mt-1 w-full" property="email"/>
|
||||
<div class="text-red-500" x-show="formErrors.email" x-html="formErrors.email"></div>
|
||||
</label>
|
||||
<label class="block mb-4" x-bind:class="'has-validation-error' && formErrors.phone">
|
||||
<span x-bind:class="formErrors.phone ? 'text-red-500' : 'text-gray-700'">Telefon/Fax*</span>
|
||||
<f:form.textfield class="border-gray-400 focus:border-gray-800 mt-1 w-full" property="phone"/>
|
||||
<div class="text-red-500" x-show="formErrors.phone" x-html="formErrors.phone"></div>
|
||||
</label>
|
||||
<label class="block mb-4" x-bind:class="'has-validation-error' && formErrors.inquiry">
|
||||
<span x-bind:class="formErrors.inquiry ? 'text-red-500' : 'text-gray-700'">(Zusatz-) Wünsche</span>
|
||||
<f:form.textarea class="border-gray-400 focus:border-gray-800 mt-1 w-full"
|
||||
property="inquiry"
|
||||
placeholder="z. B. Reiseleiter, Halbpension, Bus Anreise, Programm"
|
||||
cols="30" rows="5"/>
|
||||
<div class="text-red-500" x-show="formErrors.inquiry" x-html="formErrors.inquiry"></div>
|
||||
</label>
|
||||
<div class="mb-4">
|
||||
Ich habe die <f:link.typolink parameter="{settings.dataProtectionPageUid}"
|
||||
title="Datenschutzerklärung"
|
||||
target="_blank">Datenschutzbestimmungen</f:link.typolink> gelesen und akzeptiert.
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<button type="submit" class="button button-warning">Jetzt anfragen</button>
|
||||
</div>
|
||||
</f:form>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,11 @@
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" lang="en"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers"
|
||||
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers">
|
||||
|
||||
<f:layout name="Form/Default"/>
|
||||
|
||||
<f:section name="Main">
|
||||
<f:render partial="ContactForm/Simple" arguments="{_all}"/>
|
||||
</f:section>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" lang="en"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers"
|
||||
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers">
|
||||
|
||||
<f:layout name="Form/Default"/>
|
||||
|
||||
<f:section name="Main">
|
||||
<div class="form form--border"
|
||||
data-controller="contactform">
|
||||
<div data-contactform-target="container">
|
||||
<f:render partial="ContactForm/Simple" arguments="{_all}"/>
|
||||
</div>
|
||||
<div class="hidden form__overlay"
|
||||
data-contactform-target="loadingIndicator">
|
||||
<img src="{f:uri.resource(path: 'images/ajax-loader-white.gif', extensionName: 'ep_theme')}" alt="Processing...">
|
||||
</div>
|
||||
</div>
|
||||
</f:section>
|
||||
|
||||
</div>
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="en"
|
||||
xmlns:f="http://typo3.org/ns/fluid/ViewHelpers"
|
||||
xmlns:ep="http://typo3.org/ns/EP/EpTheme/ViewHelpers">
|
||||
|
||||
<f:layout name="Default"/>
|
||||
|
||||
<f:section name="Main">
|
||||
<table class="table table-striped pricetable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Zimmerart</th>
|
||||
<th>Preis</th>
|
||||
<th>inkl.</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<f:for each="{rooms}" as="row" iteration="iteration">
|
||||
<tr>
|
||||
<td>
|
||||
{row.label}
|
||||
</td>
|
||||
<td class="whitespace-nowrap">
|
||||
ab {row.priceForSelection} €
|
||||
</td>
|
||||
<td>
|
||||
<f:if condition="{row.skipassIncluded}">
|
||||
<span data-microtip-position="top"
|
||||
aria-label="{f:if(condition: row.summer, then: 'Bergbahnticket inklusive', else: 'Skipass inklusive')}"
|
||||
role="tooltip">
|
||||
<svg class="w-4 h-4">
|
||||
<use href="#icon-tag"></use>
|
||||
</svg>
|
||||
</span>
|
||||
</f:if>
|
||||
<button class="button button--light button--small hidden md:block"
|
||||
data-action="daytrip#openModal"
|
||||
data-type="services"
|
||||
data-uid="{iteration.cycle}"
|
||||
data-microtip-position="top"
|
||||
aria-label="Alle Inklusivleistungen anzeigen"
|
||||
role="tooltip">
|
||||
Leistungen
|
||||
</button>
|
||||
</td>
|
||||
<td>
|
||||
<a class="button button--small bg-green-500 border-green-500"
|
||||
href="{row.bookingUrl}" target="_blank">
|
||||
Buchen
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</f:for>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="hidden fixed inset-0 w-full h-full z-50"
|
||||
data-controller="modal"
|
||||
data-action="daytrip:services-modal:open@window->modal#open">
|
||||
<div class="absolute inset-0 w-full h-full bg-overlay-black z-25 flex items-center justify-center"
|
||||
data-action="click->modal#close"></div>
|
||||
<div class="absolute top-1/2 left-1/2 transform -translate-xy-1/2 bg-white shadow w-full max-w-xl rounded">
|
||||
<div class="shadow flex items-center justify-between p-4 bg-ep-primary text-white rounded-t">
|
||||
<span class="text-xl font-bold">
|
||||
Inklusivleistungen
|
||||
</span>
|
||||
<button class="inline-block"
|
||||
data-action="modal#close">
|
||||
<svg class="w-8 h-8">
|
||||
<use href="#icon-close"></use>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<f:for each="{rooms}" as="row" iteration="iteration">
|
||||
<table class="hidden table table-striped"
|
||||
data-modal-target="content"
|
||||
data-uid="{iteration.cycle}">
|
||||
<tbody>
|
||||
<f:for each="{row.servicesIncluded}" as="service">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="flex items-center space-x-2">
|
||||
<svg class="w-6 h-6 text-ep-primary">
|
||||
<use href="#icon-check"></use>
|
||||
</svg>
|
||||
<span>
|
||||
{service}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</f:for>
|
||||
</tbody>
|
||||
</table>
|
||||
</f:for>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</f:section>
|
||||
|
||||
</html>
|
||||
@@ -18,7 +18,8 @@
|
||||
</f:if>
|
||||
data-product-details-datestable-uri-value="{ep:uri.ajax(action: 'datestable', controller: 'AjaxTable', arguments: '{product: product, hotel: hotel}', format: 'html', pageUid: settings.defaultAjaxUid)}"
|
||||
data-product-details-pricetable-uri-value="{ep:uri.ajax(action: 'pricetable', controller: 'AjaxTable', arguments: '{product: product, hotel: hotel}', format: 'html', pageUid: settings.defaultAjaxUid)}"
|
||||
data-product-details-travel-alert-uri-value="{f:uri.typolink(parameter: settings.travelAlertPageUid)}">
|
||||
data-product-details-travel-alert-uri-value="{f:uri.typolink(parameter: settings.travelAlertPageUid)}"
|
||||
data-product-details-daytrip-value="{product.daytrip -> f:format.json()}">
|
||||
<f:render partial="Header/Header" arguments="{layout: 8, subheader: '{product.region.name} / {product.name}', header: product.headline}"/>
|
||||
<div class="flex flex-col lg:flex-row-reverse lg:items-start"
|
||||
data-controller="tabs">
|
||||
@@ -245,92 +246,40 @@
|
||||
</f:section>
|
||||
|
||||
<f:section name="DaytripDateSelect">
|
||||
<f:comment><!--
|
||||
<div x-data='daytripDateSelect({
|
||||
<f:format.raw>
|
||||
hotelName: "{hotel.name}",
|
||||
hotelUid: {hotel.uid},
|
||||
productUid: {product.uid},
|
||||
contingentEndpointUri: "{ep:uri.ajax(action: 'list', controller: 'AjaxContingent', format: 'json', pageUid: settings.defaultAjaxUid)}",
|
||||
roomsEndpointUri: "{ep:uri.ajax(action: 'rooms', controller: 'AjaxContingent', format: 'json', pageUid: settings.defaultAjaxUid)}"
|
||||
</f:format.raw>
|
||||
})'>
|
||||
<div class="headerbar" x-text="headerLabel"></div>
|
||||
<div data-controller="daytrip"
|
||||
data-daytrip-hotel-uid-value="{hotel.uid}"
|
||||
data-daytrip-product-uid-value="{product.uid}"
|
||||
data-daytrip-rooms-uri-value="{ep:uri.ajax(action: 'daytripRooms', controller: 'AjaxTable', format: 'html', pageUid: settings.defaultAjaxUid)}"
|
||||
data-action="datepicker:range-select->daytrip#load">
|
||||
<div class="headerbar"
|
||||
data-daytrip-target="headerLabel"></div>
|
||||
<div class="grid grid-cols-2 gap-8">
|
||||
<div class="col-span-2 md:col-span-1">
|
||||
<div class="date-select">
|
||||
<div class="date-select__picker">
|
||||
<div class="daterange__panel">
|
||||
<input x-ref="field" type="hidden">
|
||||
<div class="daterange__panel"
|
||||
data-controller="datepicker"
|
||||
data-datepicker-min-date-value="{f:format.date(date: 'now', format: 'Y-m-d')}"
|
||||
data-datepicker-enabled-dates-value='{enabledDates -> f:format.json()}'>
|
||||
<input type="hidden"
|
||||
data-datepicker-target="field">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-span-2 md:col-span-1">
|
||||
<table class="table table-striped pricetable" x-show="availableRooms.length">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Zimmerart</th>
|
||||
<th>Preis</th>
|
||||
<th>inkl.</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template x-for="(row, index) in availableRooms">
|
||||
<tr>
|
||||
<td x-text="row.label"></td>
|
||||
<td style="white-space: nowrap" x-text="'ab ' + calculatePrice(row.code) + ' €'"></td>
|
||||
<td>
|
||||
<i x-show="row.skipassIncluded" aria-label="Skipass inklusive" role="tooltip" data-microtip-position="top" class="fa fa-tag"></i>
|
||||
<a href="#" data-toggle="modal"
|
||||
data-target="'#services' + index"
|
||||
data-microtip-position="top" aria-label="Inklusivleistungen zeigen" role="tooltip">
|
||||
<svg class="w-4 h-4">
|
||||
<use href="#icon-info-circle"></use>
|
||||
</svg>
|
||||
</a>
|
||||
<div class="modal fade" id="'services' + index" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
<h5 class="modal-title">Inklusivleistungen</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<tbody>
|
||||
<tr v-for="service of row.servicesIncluded">
|
||||
<td><span class="glyphicon glyphicon-ok" aria-hidden="true"></span> {{ service }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<a x-bind:href="row.bookingUrl" target="_blank"
|
||||
class="button button--small button--action">Buchen</a>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
<div x-show="loading" class="loader flex items-center space-x-2">
|
||||
<div data-daytrip-target="container"></div>
|
||||
<div class="hidden flex items-center space-x-2"
|
||||
data-daytrip-target="loadingIndicator">
|
||||
<span>Loading...</span>
|
||||
<f:image class="block w-4 h-4" src="EXT:ep_theme/Resources/Public/images/ajax-loader-white.gif" alt="Loading"/>
|
||||
</div>
|
||||
<div x-show="message" x-text="message"></div>
|
||||
<div data-daytrip-target="message">
|
||||
Bitte einen Zeitraum auswählen.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
--></f:comment>
|
||||
</f:section>
|
||||
|
||||
<f:section name="Calendar">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<f:section name="Main">
|
||||
<div data-controller="searchbar"
|
||||
{f:if(condition: fixed, else: ' data-controller="sticky" data-sticky-offset-value="650" data-sticky-sticky-class="sticky"')}
|
||||
{f:if(condition: fixed, else: ' data-controller="sticky" data-sticky-offset-value="650"')}
|
||||
data-action="datepicker:range-select->searchbar#setDateRange"
|
||||
data-searchbar-uri-value="{ep:uri.ajax(controller: 'Searchbar', action: 'index', pageUid: settings.defaultAjaxUid, format: 'html')}">
|
||||
<div class="searchbar {f:if(condition: fixed, then: ' sticky')}"
|
||||
|
||||
Reference in New Issue
Block a user