Integrate booking edit into myep spa
This commit is contained in:
committed by
Björn Fromme
parent
213b75b863
commit
dbe4336550
Generated
+3422
-2750
File diff suppressed because it is too large
Load Diff
+15
-13
@@ -7,41 +7,43 @@
|
|||||||
"repository": "https://gitlab.com/dreipunktnull/ep_theme.git",
|
"repository": "https://gitlab.com/dreipunktnull/ep_theme.git",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "./node_modules/.bin/encore dev --watch",
|
"dev": "./node_modules/.bin/encore dev --watch",
|
||||||
"build": "./node_modules/.bin/encore production"
|
"build": "NODE_ENV=production ./node_modules/.bin/encore production"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fancyapps/fancybox": "^3.5.7",
|
"@fancyapps/fancybox": "^3.5.7",
|
||||||
|
"@tailwindcss/custom-forms": "^0.2.1",
|
||||||
"axios": "^0.18.0",
|
"axios": "^0.18.0",
|
||||||
"axios-auth-refresh": "^1.0.7",
|
"axios-auth-refresh": "^1.0.7",
|
||||||
"bootstrap-sass": "^3.4.1",
|
"bootstrap-sass": "^3.4.1",
|
||||||
"bourbon": "^4.3.2",
|
"bourbon": "^4.3.2",
|
||||||
"cookieconsent": "^3.1.0",
|
"cookieconsent": "^3.1.0",
|
||||||
"dayjs": "^1.8.12",
|
"dayjs": "^1.8.36",
|
||||||
"flatpickr": "^4.5.7",
|
"flatpickr": "^4.6.6",
|
||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"jquery": "^1.12.4",
|
"jquery": "^1.12.4",
|
||||||
"lazysizes": "^4.1.8",
|
"lazysizes": "^4.1.8",
|
||||||
"leaflet": "^1.4.0",
|
"leaflet": "^1.7.1",
|
||||||
"normalize.css": "^7.0.0",
|
"normalize.css": "^7.0.0",
|
||||||
"picturefill": "^3.0.3",
|
"picturefill": "^3.0.3",
|
||||||
"sass-mq": "^3.3.2",
|
"sass-mq": "^3.3.2",
|
||||||
"slick-carousel": "^1.8.0",
|
"slick-carousel": "^1.8.0",
|
||||||
"sticky-js": "^1.2.0",
|
"sticky-js": "^1.3.0",
|
||||||
"vue": "^2.6.10",
|
"tailwindcss": "^1.8.10",
|
||||||
"vue-router": "^3.0.6",
|
"vue": "^2.6.12",
|
||||||
|
"vue-router": "^3.4.3",
|
||||||
"vue-session": "^1.0.0",
|
"vue-session": "^1.0.0",
|
||||||
"vuex": "^3.1.0"
|
"vuex": "^3.5.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-object-rest-spread": "^7.8.3",
|
"@babel/plugin-proposal-object-rest-spread": "^7.11.0",
|
||||||
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
|
||||||
"@symfony/webpack-encore": "^0.28.2",
|
"@symfony/webpack-encore": "^0.28.3",
|
||||||
"autoprefixer": "^8.6.5",
|
"autoprefixer": "^8.6.5",
|
||||||
"node-sass": "^4.11.0",
|
"node-sass": "^4.14.1",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^3.0.0",
|
||||||
"sass-loader": "^7.3.1",
|
"sass-loader": "^7.3.1",
|
||||||
"vue-loader": "^15.8.3",
|
"vue-loader": "^15.9.3",
|
||||||
"vue-template-compiler": "^2.6.10"
|
"vue-template-compiler": "^2.6.12"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 2 versions",
|
"last 2 versions",
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
parser: false,
|
plugins: [
|
||||||
plugins: {
|
require('tailwindcss'),
|
||||||
'autoprefixer': {},
|
require('autoprefixer'),
|
||||||
}
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="myep" class="relative">
|
||||||
<nav class="navbar navbar-default" v-if="isLoggedIn">
|
<nav class="navbar navbar-default" v-if="isLoggedIn">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<button type="button" class="navbar-toggle collapsed"
|
<button type="button" class="navbar-toggle collapsed"
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<router-link :to="{ name: 'address' }" tag="li" active-class="active" :class="{ disabled: loading }"><a>Adressdaten</a></router-link>
|
<router-link :to="{ name: 'address' }" tag="li" active-class="active" :class="{ disabled: loading }"><a>Adressdaten</a></router-link>
|
||||||
<router-link :to="{ name: 'newsletter' }" tag="li" active-class="active" :class="{ disabled: loading }"><a>Newsletter</a></router-link>
|
<router-link :to="{ name: 'newsletter' }" tag="li" active-class="active" :class="{ disabled: loading }"><a>Newsletter</a></router-link>
|
||||||
<router-link :to="{ name: 'profile' }" tag="li" active-class="active" :class="{ disabled: loading }"><a>Mein Profil</a></router-link>
|
<router-link :to="{ name: 'profile' }" tag="li" active-class="active" :class="{ disabled: loading }"><a>Mein Profil</a></router-link>
|
||||||
<router-link :to="{ name: 'events' }" tag="li" active-class="active" :class="{ disabled: loading }"><a>Reise-Historie</a></router-link>
|
<router-link :to="{ name: 'events' }" tag="li" active-class="active" :class="{ disabled: loading }"><a>Buchungen</a></router-link>
|
||||||
<router-link :to="{ name: 'teamer' }" tag="li" active-class="active" :class="{ disabled: loading }" v-if="isTeamer"><a>Teamer</a></router-link>
|
<router-link :to="{ name: 'teamer' }" tag="li" active-class="active" :class="{ disabled: loading }" v-if="isTeamer"><a>Teamer</a></router-link>
|
||||||
</ul>
|
</ul>
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
@@ -34,8 +34,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="loader" v-show="loading">
|
<div class="absolute top-0 left-0 w-full h-full z-100 bg-overlay-white" v-show="loading">
|
||||||
<img :src="config.loaderUrl" alt="">
|
<img :src="config.loaderUrl" alt="" class="absolute top-1/2 left-1/2 transform -translate-xy-1/2">
|
||||||
</div>
|
</div>
|
||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</div>
|
</div>
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
logout () {
|
logout () {
|
||||||
this.$store.dispatch('logout')
|
this.$store.dispatch('logout')
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.$router.push({ name: 'login' })
|
this.$router.replace({ name: 'login' })
|
||||||
}).catch(error => {});
|
}).catch(error => {});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -63,30 +63,9 @@
|
|||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
if (this.isLoggedIn) {
|
if (this.isLoggedIn) {
|
||||||
this.$router.push({ name: 'address' })
|
this.$router.replace({ name: 'address' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
#app {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.loader {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 10;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
background-color: rgba(255, 255, 255, 0.75);
|
|
||||||
|
|
||||||
img {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -0,0 +1,510 @@
|
|||||||
|
<template>
|
||||||
|
<div class="wrapper">
|
||||||
|
<div class="grid lg:grid-cols-2 gap-4" v-if="initialized">
|
||||||
|
<div>
|
||||||
|
<panel title="Reisedaten">
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item"><strong>Reise:</strong> {{ travelData.productName }}</li>
|
||||||
|
<li class="list-group-item"><strong>Zeitraum:</strong> {{ travelData.dateFrom }} - {{ travelData.dateTo }}</li>
|
||||||
|
<li class="list-group-item"><strong>Inklusivleistungen:</strong> {{ travelData.servicesIncluded.join(', ') }}</li>
|
||||||
|
<li class="list-group-item"><strong>Anmelder:</strong> {{ bookingData.applicant.firstName }} {{ bookingData.applicant.lastName }}</li>
|
||||||
|
<li class="list-group-item"><strong>Gesamtpreis:</strong> {{ totalPrice.toFixed(2) }}€</li>
|
||||||
|
<li class="list-group-item"><strong>Teilnehmer:</strong> {{ participantsCount.active }}</li>
|
||||||
|
<li class="list-group-item"><strong>Stornos:</strong> {{ participantsCount.canceled }}</li>
|
||||||
|
</ul>
|
||||||
|
</panel>
|
||||||
|
<services-overview :services="services.other" :participant-data="participantData"/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<mutable-fields :mutable-fields="mutableFields"></mutable-fields>
|
||||||
|
<contingents-overview :contingents="contingents"/>
|
||||||
|
<panel title="Beförderungsart (alle Teilnehmer)" :body="true">
|
||||||
|
<transportation-select :services="services.transportation"
|
||||||
|
:initial-transportation-ids="bookingData.selectedTransportationIds"
|
||||||
|
:mutable="mutableFields.transportation.mutable"
|
||||||
|
v-on:updated="onTransportationUpdated($event)"
|
||||||
|
/>
|
||||||
|
</panel>
|
||||||
|
<panel title="Anmerkungen" :body="true">
|
||||||
|
<textarea class="form-textarea block w-full" rows="2" v-model="bookingData.remarks" @change="dirty = true"/>
|
||||||
|
</panel>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="py-4 lg:flex lg:justify-between space-y-1 lg:space-y-0" v-show="!loading">
|
||||||
|
<button class="btn btn-primary" :disabled="!dirty" @click.prevent="storeBookingData()" v-if="initialized">
|
||||||
|
Buchung aktualisieren
|
||||||
|
</button>
|
||||||
|
<router-link :to="{ name: 'events' }" class="btn btn-primary">
|
||||||
|
zur Übersicht
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
<div class="py-4" v-if="initialized">
|
||||||
|
<h2>Teilnehmer</h2>
|
||||||
|
<collapsible-panel :title="'#' + (index + 1) + ' ' + participant.data.lastName + ', ' + participant.data.firstName"
|
||||||
|
:class="invalidParticipantData[participant.data.id] ? 'panel-danger' : 'panel-default'" parent="#participant-list"
|
||||||
|
v-for="(participant, index) in participantData" :key="participant.data.id">
|
||||||
|
<template v-if="participant.data.canceled">
|
||||||
|
Storniert am {{ participant.data.cancellationDate }}, Stornokosten {{ participant.data.cancellationFee.toFixed(2) }} €
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div class="panel-body-section">
|
||||||
|
<participant-data-form :participant="participant"
|
||||||
|
:mutable="mutableFields.participantData.mutable"
|
||||||
|
:countries="countries"
|
||||||
|
v-on:updated="onParticipantDataUpdated($event, index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="lg:flex lg:space-x-1 space-y-1 lg:space-y-0 py-4">
|
||||||
|
<participant-address-form :participant="participant"
|
||||||
|
:countries="countries"
|
||||||
|
:mutable="mutableFields.participantData.mutable"
|
||||||
|
v-on:updated="onParticipantDataUpdated($event, index)"
|
||||||
|
/>
|
||||||
|
<accommodation-select :participant="participant"
|
||||||
|
:contingents="availableContingents"
|
||||||
|
:mutable="mutableFields.accommodation.mutable"
|
||||||
|
v-on:selected="onAccommodationSelected($event, index)"
|
||||||
|
/>
|
||||||
|
<service-select v-for="subType in servicesSubTypes"
|
||||||
|
:key="subType.code"
|
||||||
|
:sub-type="subType"
|
||||||
|
:services="services.other"
|
||||||
|
:participant="participant"
|
||||||
|
:mutable="mutableFields.services.mutable"
|
||||||
|
v-on:updated="onServiceUpdated($event, index)"
|
||||||
|
/>
|
||||||
|
<participant-sizes-form :services="services.other"
|
||||||
|
:participant="participant"
|
||||||
|
:mutable="mutableFields.services.mutable"
|
||||||
|
v-on:updated="[onParticipantDataUpdated($event, index)]"
|
||||||
|
/>
|
||||||
|
<pickup-select
|
||||||
|
:pickups="services.pickups"
|
||||||
|
:participant="participant"
|
||||||
|
:mutable="mutableFields.transportation.mutable"
|
||||||
|
v-on:selected="onPickupSelected($event, index)"
|
||||||
|
v-show="showPickups"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="grid lg:grid-cols-2 gap-4">
|
||||||
|
<table class="table table-condensed text-sm mb-0">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th class="w-1/5">Zimmer</th>
|
||||||
|
<td>{{ getAccommodationLabel(participant) }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Zusatzleistungen</th>
|
||||||
|
<td>{{ getSelectedServicesLabels(participant.serviceIds, services.other) }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Beförderung</th>
|
||||||
|
<td>{{ getSelectedServicesLabels(participant.transportationIds, services.transportation) }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Gesamtpreis</th>
|
||||||
|
<td>{{ calculateSinglePrice(participant).toFixed(2) }} €</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<textarea rows="2" class="form-textarea block w-full"
|
||||||
|
v-model="participant.data.accommodationRequest"
|
||||||
|
@change="dirty = true"
|
||||||
|
placeholder="Anmerkungen"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</collapsible-panel>
|
||||||
|
</div>
|
||||||
|
<div class="py-4 lg:flex lg:justify-between space-y-1 lg:space-y-0" v-show="!loading">
|
||||||
|
<button class="btn btn-primary" :disabled="!dirty" @click.prevent="storeBookingData()" v-if="initialized">
|
||||||
|
Buchung aktualisieren
|
||||||
|
</button>
|
||||||
|
<router-link :to="{ name: 'events' }" class="btn btn-primary">
|
||||||
|
zur Übersicht
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
<div class="py-4 text-center" v-show="statusMessage" v-text="statusMessage" />
|
||||||
|
<div class="modal fade" tabindex="-1" role="dialog" ref="modal">
|
||||||
|
<div class="modal-dialog" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h4 class="modal-title">{{ modal.title }}</h4>
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<p v-html="modal.message"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import AccommodationSelect from './components/AccommodationSelect'
|
||||||
|
import ContingentsOverview from './components/ContingentsOverview';
|
||||||
|
import MutableFields from './components/MutableFields';
|
||||||
|
import Panel from './components/Panel';
|
||||||
|
import CollapsiblePanel from './components/CollapsiblePanel'
|
||||||
|
import ParticipantAddressForm from './components/ParticipantAddressForm'
|
||||||
|
import ParticipantDataForm from './components/ParticipantDataForm'
|
||||||
|
import ParticipantSizesForm from './components/ParticipantSizesForm'
|
||||||
|
import PickupSelect from './components/PickupSelect'
|
||||||
|
import ServiceSelect from './components/ServiceSelect'
|
||||||
|
import ServicesOverview from './components/ServicesOverview';
|
||||||
|
import TransportationSelect from './components/TransportationSelect';
|
||||||
|
|
||||||
|
import authenticatedClient from "../api";
|
||||||
|
import {mapMutations, mapState} from 'vuex';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BookingEdit',
|
||||||
|
components: {
|
||||||
|
Panel,
|
||||||
|
CollapsiblePanel,
|
||||||
|
MutableFields,
|
||||||
|
TransportationSelect,
|
||||||
|
ServicesOverview,
|
||||||
|
ContingentsOverview,
|
||||||
|
AccommodationSelect,
|
||||||
|
ParticipantDataForm,
|
||||||
|
ParticipantAddressForm,
|
||||||
|
ParticipantSizesForm,
|
||||||
|
PickupSelect,
|
||||||
|
ServiceSelect
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
bookingId: null,
|
||||||
|
initialized: false,
|
||||||
|
dirty: false,
|
||||||
|
processing: false,
|
||||||
|
statusMessage: '',
|
||||||
|
bookingData: null,
|
||||||
|
participantData: null,
|
||||||
|
invalidParticipantData: {},
|
||||||
|
eventData: null,
|
||||||
|
travelData: null,
|
||||||
|
mutableFields: null,
|
||||||
|
contingents: null,
|
||||||
|
services: null,
|
||||||
|
servicesSubTypes: [
|
||||||
|
{ 'code': 'KUR', 'label': 'Kurse' },
|
||||||
|
{ 'code': 'SON', 'label': 'Zusatzleistungen' },
|
||||||
|
{ 'code': 'SPA', 'label': 'Skipass' },
|
||||||
|
{ 'code': 'VPF', 'label': 'Verpflegung' },
|
||||||
|
{ 'code': 'VER', 'label': 'Verleih' },
|
||||||
|
{ 'code': 'EIN', 'label': '???' }
|
||||||
|
],
|
||||||
|
modal: {
|
||||||
|
title: 'Hinweis',
|
||||||
|
message: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations(['alert', 'beginLoading', 'endLoading']),
|
||||||
|
loadFormOptions () {
|
||||||
|
this.beginLoading();
|
||||||
|
return authenticatedClient({
|
||||||
|
url: '/api/countries',
|
||||||
|
}).then(response => {
|
||||||
|
this.countries = response.data
|
||||||
|
}).catch(error => {
|
||||||
|
}).finally(() => {
|
||||||
|
this.endLoading()
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showModal (message, title = 'Hinweis') {
|
||||||
|
this.modal = {
|
||||||
|
message: message,
|
||||||
|
title: title
|
||||||
|
};
|
||||||
|
$(this.$refs.modal).modal('show');
|
||||||
|
},
|
||||||
|
loadBookingData () {
|
||||||
|
this.beginLoading()
|
||||||
|
this.statusMessage = 'Lade Reise- und Buchungsdaten';
|
||||||
|
return authenticatedClient.get(`/api/booking/${this.bookingId}`)
|
||||||
|
.then(response => {
|
||||||
|
this.bookingData = response.data.bookingData;
|
||||||
|
this.participantData = response.data.participantData;
|
||||||
|
this.travelData = response.data.travelData;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
throw new Error('Reise- und Buchungsdaten konnten nicht geladen werden.');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.statusMessage = '';
|
||||||
|
this.endLoading()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadEventData () {
|
||||||
|
this.beginLoading()
|
||||||
|
this.statusMessage = 'Lade Vorgangsdaten';
|
||||||
|
return authenticatedClient.get(`/api/event/${this.bookingData.bookingNumber}`)
|
||||||
|
.then(response => {
|
||||||
|
this.eventData = response.data;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
throw new Error(error.response.data.message);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.statusMessage = '';
|
||||||
|
this.endLoading()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadMutableFields () {
|
||||||
|
this.beginLoading()
|
||||||
|
this.statusMessage = 'Lade mögliche Änderungen';
|
||||||
|
return authenticatedClient.get(`/api/mutable-fields/${this.travelData.busproId}`)
|
||||||
|
.then(response => {
|
||||||
|
this.mutableFields = response.data;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
throw new Error('Mögliche Änderungen konnten nicht geladen werden.');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.statusMessage = '';
|
||||||
|
this.endLoading()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadContingents () {
|
||||||
|
this.beginLoading()
|
||||||
|
this.statusMessage = 'Lade Kontingente';
|
||||||
|
return authenticatedClient.get(`/api/contingents/${this.travelData.busproId}`)
|
||||||
|
.then(response => {
|
||||||
|
this.contingents = response.data;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
throw new Error('Kontingente konnten nicht geladen werden.');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.statusMessage = '';
|
||||||
|
this.endLoading()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
loadServices () {
|
||||||
|
this.beginLoading()
|
||||||
|
this.statusMessage = 'Lade Leistungen';
|
||||||
|
return authenticatedClient.get(`/api/services/${this.travelData.busproId}`)
|
||||||
|
.then(response => {
|
||||||
|
this.services = response.data;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
throw new Error('Leistungen konnten nicht geladen werden.');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.statusMessage = '';
|
||||||
|
this.endLoading()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getAccommodationLabel (participant) {
|
||||||
|
if (participant.hasOwnProperty('accommodationId') && participant.accommodationId in this.contingents) {
|
||||||
|
return this.contingents[participant.accommodationId].name
|
||||||
|
}
|
||||||
|
|
||||||
|
return '-';
|
||||||
|
},
|
||||||
|
getSelectedServicesLabels (serviceIds, services) {
|
||||||
|
const labels = [];
|
||||||
|
for (let serviceId of serviceIds) {
|
||||||
|
if (services[serviceId]) {
|
||||||
|
labels.push(services[serviceId].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return labels.join(', ');
|
||||||
|
},
|
||||||
|
calculateSinglePrice (participant) {
|
||||||
|
let singlePrice = 0;
|
||||||
|
if (participant.hasOwnProperty('accommodationId') && participant.accommodationId in this.contingents) {
|
||||||
|
let accommodation = this.contingents[participant.accommodationId];
|
||||||
|
singlePrice += accommodation.price;
|
||||||
|
}
|
||||||
|
for (let serviceId of participant.serviceIds) {
|
||||||
|
if (this.services.other[serviceId]) {
|
||||||
|
singlePrice += this.services.other[serviceId].price;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let serviceId of participant.transportationIds) {
|
||||||
|
if (this.services.transportation[serviceId]) {
|
||||||
|
singlePrice += this.services.transportation[serviceId].price;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ('S' === participant.data.status && participant.data.cancellationFee) {
|
||||||
|
singlePrice += participant.data.cancellationFee;
|
||||||
|
}
|
||||||
|
return singlePrice;
|
||||||
|
},
|
||||||
|
onAccommodationSelected (accommodation, index) {
|
||||||
|
const participant = this.participantData[index];
|
||||||
|
if (participant.hasOwnProperty('accommodationId')) {
|
||||||
|
const currentAccommodationId = this.participantData[index].accommodationId;
|
||||||
|
if (currentAccommodationId in this.contingents) {
|
||||||
|
this.contingents[currentAccommodationId].available++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const newAccommodationId = accommodation.id;
|
||||||
|
if (this.participantData[index].accommodationId === newAccommodationId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.participantData[index].accommodationId = newAccommodationId;
|
||||||
|
this.contingents[newAccommodationId].available--;
|
||||||
|
this.dirty = true;
|
||||||
|
},
|
||||||
|
onPickupSelected (pickupId, index) {
|
||||||
|
this.participantData[index].pickupId = pickupId;
|
||||||
|
this.dirty = true;
|
||||||
|
},
|
||||||
|
onParticipantDataUpdated (participant, index) {
|
||||||
|
this.participantData[index] = participant;
|
||||||
|
this.dirty = true;
|
||||||
|
},
|
||||||
|
onServiceUpdated (event, index) {
|
||||||
|
let delta = event.action === 'select' ? -1 : 1;
|
||||||
|
this.services.other[event.service.id].available += delta;
|
||||||
|
this.participantData[index] = event.participant;
|
||||||
|
this.dirty = true;
|
||||||
|
},
|
||||||
|
onTransportationUpdated (event) {
|
||||||
|
let factor = event.action === 'select' ? -1 : 1;
|
||||||
|
this.services.transportation[event.service.id].available += this.participantData.length * factor;
|
||||||
|
this.bookingData.selectedTransportationIds = event.selectedTransportationIds;
|
||||||
|
this.dirty = true;
|
||||||
|
},
|
||||||
|
hasSelectedRentals (participant) {
|
||||||
|
let result = false;
|
||||||
|
for (let id of participant.serviceIds) {
|
||||||
|
if (typeof this.services.other[id] === 'undefined') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ('VER' === this.services.other[id].subType) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
validateInput () {
|
||||||
|
let messages = [];
|
||||||
|
this.invalidParticipantData = {};
|
||||||
|
for (let participant of this.participantData) {
|
||||||
|
let participantId = participant.data.id;
|
||||||
|
if (!participant.data.nationality) {
|
||||||
|
this.invalidParticipantData[participantId] = {
|
||||||
|
invalid: 'Nationalität',
|
||||||
|
};
|
||||||
|
messages.push('Teilnehmer #'+participantId+': Nationalität')
|
||||||
|
}
|
||||||
|
if (!this.hasSelectedRentals(participant)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!participant.data.height) {
|
||||||
|
this.invalidParticipantData[participantId] = {
|
||||||
|
invalid: 'Körpergröße',
|
||||||
|
};
|
||||||
|
messages.push('Teilnehmer #'+participantId+': Körpergröße')
|
||||||
|
}
|
||||||
|
if (!participant.data.shoeSize) {
|
||||||
|
this.invalidParticipantData[participantId] = {
|
||||||
|
invalid: 'Schuhgröße',
|
||||||
|
};
|
||||||
|
messages.push('Teilnehmer #'+participantId+': Schuhgröße')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return messages
|
||||||
|
},
|
||||||
|
storeBookingData() {
|
||||||
|
let messages = this.validateInput();
|
||||||
|
if (false === this.dataValid) {
|
||||||
|
this.showModal(messages.join('<br>'), 'Daten unvollständig');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.beginLoading()
|
||||||
|
authenticatedClient.put(`/api/booking/${this.bookingId}`, {
|
||||||
|
participantData: this.participantData,
|
||||||
|
selectedTransportations: this.selectedTransportations,
|
||||||
|
remarks: this.bookingData.remarks
|
||||||
|
}).then(response => {
|
||||||
|
this.showModal(response.data.message);
|
||||||
|
this.dirty = false;
|
||||||
|
}).catch(error => {
|
||||||
|
this.showModal(error.response.data.message)
|
||||||
|
}).finally(() => {
|
||||||
|
this.endLoading()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(['loading']),
|
||||||
|
availableContingents () {
|
||||||
|
let filteredContingents = {};
|
||||||
|
for (let id of Object.keys(this.contingents)) {
|
||||||
|
if (this.contingents[id].available > 0) {
|
||||||
|
filteredContingents[id] = this.contingents[id];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filteredContingents;
|
||||||
|
},
|
||||||
|
selectedTransportations () {
|
||||||
|
let selectedTransportations = [];
|
||||||
|
for (let id of this.bookingData.selectedTransportationIds) {
|
||||||
|
selectedTransportations.push(this.services.transportation[id]);
|
||||||
|
}
|
||||||
|
return selectedTransportations;
|
||||||
|
},
|
||||||
|
showPickups () {
|
||||||
|
for (let id of this.bookingData.selectedTransportationIds) {
|
||||||
|
if ('BUS' === this.services.transportation[id].subType) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
totalPrice () {
|
||||||
|
let totalPrice = 0;
|
||||||
|
this.participantData.forEach(participant => {
|
||||||
|
totalPrice += this.calculateSinglePrice(participant);
|
||||||
|
});
|
||||||
|
return totalPrice;
|
||||||
|
},
|
||||||
|
participantsCount () {
|
||||||
|
let active = 0;
|
||||||
|
let canceled = 0;
|
||||||
|
for (const participant of this.participantData) {
|
||||||
|
if (participant.data.canceled) {
|
||||||
|
canceled++;
|
||||||
|
} else {
|
||||||
|
active++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {active: active, canceled: canceled};
|
||||||
|
},
|
||||||
|
dataValid () {
|
||||||
|
return Object.keys(this.invalidParticipantData).length === 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.bookingId = this.$route.params.id
|
||||||
|
this.loadFormOptions()
|
||||||
|
.then(() => this.loadBookingData())
|
||||||
|
.then(() => this.loadEventData())
|
||||||
|
.then(() => this.loadMutableFields())
|
||||||
|
.then(() => this.loadContingents())
|
||||||
|
.then(() => this.loadServices())
|
||||||
|
.then(() => {
|
||||||
|
this.initialized = true;
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
this.showModal(error.message, 'Fehler');
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.statusMessage = '';
|
||||||
|
this.endLoading()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -1,18 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="myep-main" v-show="!loading">
|
<div id="myep-main" v-show="!loading">
|
||||||
<h1>Reise-Historie</h1>
|
<h1>Meine Buchungen</h1>
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-striped table-condensed">
|
<table class="table table-striped table-condensed">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Buchungsdatum</th>
|
<th>Buchungsdatum</th>
|
||||||
<th>Reisedatum</th>
|
<th>Reisedatum</th>
|
||||||
<th>Reise</th>
|
<th class="w-1/4">Reise</th>
|
||||||
<th>Teilnehmer</th>
|
|
||||||
<th>Preis</th>
|
<th>Preis</th>
|
||||||
<th>offen</th>
|
<th>offen</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Dokumente</th>
|
<th></th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -20,19 +19,19 @@
|
|||||||
<td>{{ formatBookingDate(event.dateBooking) }}</td>
|
<td>{{ formatBookingDate(event.dateBooking) }}</td>
|
||||||
<td>{{ event.dateTravel | date }}</td>
|
<td>{{ event.dateTravel | date }}</td>
|
||||||
<td>{{ event.product }}</td>
|
<td>{{ event.product }}</td>
|
||||||
<td>
|
|
||||||
<ul class="list-unstyled">
|
|
||||||
<li v-for="customer in event.customers">{{ customer.lastName }}, {{ customer.firstName }}</li>
|
|
||||||
</ul>
|
|
||||||
</td>
|
|
||||||
<td style="white-space: nowrap">{{ event.price }} €</td>
|
<td style="white-space: nowrap">{{ event.price }} €</td>
|
||||||
<td style="white-space: nowrap">{{ calculateBalance(event) }}</td>
|
<td style="white-space: nowrap">{{ calculateBalance(event) }}</td>
|
||||||
<td>{{ status[event.status] }}</td>
|
<td>{{ status[event.status] }}</td>
|
||||||
<td>
|
<td class="flex space-x-1">
|
||||||
<a :href="getDownloadUrl(event, 'confirmation')" target="_blank">Bestätigung</a>
|
<a :href="getDownloadUrl(event, 'confirmation')" target="_blank" class="btn btn-primary btn-sm">
|
||||||
<template v-if="event.documents">
|
Bestätigung
|
||||||
<a :href="getDownloadUrl(event, 'documents')" target="_blank">Reiseinfos</a>
|
</a>
|
||||||
</template>
|
<a :href="getDownloadUrl(event, 'documents')" target="_blank" class="btn btn-primary btn-sm" v-if="event.documents">
|
||||||
|
Reiseinfos
|
||||||
|
</a>
|
||||||
|
<router-link :to="{ name: 'bookingEdit', params: { id: event.id } }" v-if="isGroupManager && event.editable" class="btn btn-primary btn-sm">
|
||||||
|
bearbeiten
|
||||||
|
</router-link>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@@ -42,7 +41,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState, mapMutations } from 'vuex'
|
import {mapState, mapMutations, mapGetters} from 'vuex'
|
||||||
import authenticatedClient from "../api";
|
import authenticatedClient from "../api";
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import 'dayjs/locale/de'
|
import 'dayjs/locale/de'
|
||||||
@@ -103,7 +102,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['config', 'loading'])
|
...mapState(['config', 'loading']),
|
||||||
|
...mapGetters(['isGroupManager'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
<template>
|
||||||
|
<div class="relative" v-if="mutable">
|
||||||
|
<button class="btn btn-primary btn-sm w-full lg:w-auto" type="button" @click.prevent="visible = !visible">
|
||||||
|
Zimmer <span class="glyphicon" :class="{ 'glyphicon-chevron-up': visible, 'glyphicon-chevron-down': !visible }"></span>
|
||||||
|
</button>
|
||||||
|
<ul class="absolute top-100 left-0 z-10 mt-4 border shadow-md p-4 bg-white w-screen max-w-xs divide-y" v-show="visible">
|
||||||
|
<li v-for="accommodation in selectableAccommodations" :key="accommodation.id" class="py-1">
|
||||||
|
<a href="#" @click.prevent="selectAccommodation(accommodation)">
|
||||||
|
{{ accommodation.name}}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'AccommodationSelect',
|
||||||
|
props: {
|
||||||
|
participant: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
contingents: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
mutable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
selectAccommodation (accommodation) {
|
||||||
|
this.$emit('selected', accommodation);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
selectableAccommodations () {
|
||||||
|
let accommodations = []
|
||||||
|
for (let accommodationId of Object.keys(this.contingents)) {
|
||||||
|
if (this.participant.accommodationId !== parseInt(accommodationId)) {
|
||||||
|
accommodations.push(this.contingents[accommodationId])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.visible = false
|
||||||
|
return accommodations
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-heading" role="tab" :id="'heading-' + id">
|
||||||
|
<h3 class="panel-title">
|
||||||
|
<a role="button" data-toggle="collapse" :data-parent="parent" :href="'#collapse-' + id"
|
||||||
|
aria-expanded="false" :aria-controls="'collapse-' + id">
|
||||||
|
{{ title }}
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div :id="'collapse-' + id" class="panel-collapse collapse" role="tabpanel" :aria-labelledby="'headine-' + id">
|
||||||
|
<div class="panel-body">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'CollapsiblePanel',
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
id: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
parent: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.id = this._uid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
<template>
|
||||||
|
<panel title="Kontingente" :body="true">
|
||||||
|
<table class="table table-condensed">
|
||||||
|
<colgroup>
|
||||||
|
<col style="width: 75%">
|
||||||
|
<col style="width: 25%">
|
||||||
|
</colgroup>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="contingent in contingents" :key="contingent.id">
|
||||||
|
<th>{{ contingent.name }}</th>
|
||||||
|
<td><span class="label" :class="contingent.available > 0 ? 'label-success' : 'label-danger'">{{ contingent.available }}</span></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Panel from './Panel'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ContingentsOverview',
|
||||||
|
components: {
|
||||||
|
Panel
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
contingents: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
<template>
|
||||||
|
<panel title="Änderungen möglich bis" :body="true">
|
||||||
|
<table class="table table-condensed">
|
||||||
|
<colgroup>
|
||||||
|
<col style="width: 75%">
|
||||||
|
<col style="width: 25%">
|
||||||
|
</colgroup>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Unterkunft</th>
|
||||||
|
<td>
|
||||||
|
<span class="label" :class="mutableFields.accommodation.mutable ? 'label-success' : 'label-danger'">
|
||||||
|
{{ mutableFields.accommodation.mutable ? mutableFields.accommodation.until : 'keine Änderung möglich' }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Teilnehmer</th>
|
||||||
|
<td>
|
||||||
|
<span class="label" :class="mutableFields.participantData.mutable ? 'label-success' : 'label-danger'">
|
||||||
|
{{ mutableFields.participantData.mutable ? mutableFields.participantData.until : 'keine Änderung möglich' }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Leistungen</th>
|
||||||
|
<td>
|
||||||
|
<span class="label" :class="mutableFields.services.mutable ? 'label-success' : 'label-danger'">
|
||||||
|
{{ mutableFields.services.until ? mutableFields.services.until : 'keine Änderung möglich' }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Beförderung</th>
|
||||||
|
<td>
|
||||||
|
<span class="label" :class="mutableFields.transportation.mutable ? 'label-success' : 'label-danger'">
|
||||||
|
{{ mutableFields.transportation.until ? mutableFields.transportation.until : 'keine Änderung möglich' }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Zustiege</th>
|
||||||
|
<td>
|
||||||
|
<span class="label" :class="mutableFields.pickup.mutable ? 'label-success' : 'label-danger'">
|
||||||
|
{{ mutableFields.pickup.until ? mutableFields.pickup.until : 'keine Änderung möglich' }}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Panel from './Panel';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'MutableFields',
|
||||||
|
components: {
|
||||||
|
Panel
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
mutableFields: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.table-condensed {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<template>
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">{{ title }}</h3>
|
||||||
|
</div>
|
||||||
|
<template v-if="body">
|
||||||
|
<div class="panel-body">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<slot></slot>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Panel',
|
||||||
|
props: {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
<template>
|
||||||
|
<div class="relative">
|
||||||
|
<button class="btn btn-primary btn-sm w-full lg:w-auto" type="button" @click.prevent="visible = !visible">
|
||||||
|
Adresse/Telefon <span class="glyphicon" :class="{ 'glyphicon-chevron-up': visible, 'glyphicon-chevron-down': !visible }"></span>
|
||||||
|
</button>
|
||||||
|
<div class="absolute top-100 left-0 z-10 mt-4 border shadow-md p-4 bg-white w-screen max-w-xs space-y-2" v-show="visible">
|
||||||
|
<input class="form-input w-full" type="text" placeholder="Straße"
|
||||||
|
v-model="participant.data.street" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<input class="form-input w-full" type="text" placeholder="PLZ"
|
||||||
|
v-model="participant.data.zipCode" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<input class="form-input w-full" type="text" placeholder="Ort"
|
||||||
|
v-model="participant.data.city" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<select class="form-select w-full"
|
||||||
|
v-model="participant.data.country" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<option value="">Land...</option>
|
||||||
|
<option v-for="country in countries" :key="country.code" :value="country.code">{{ country.name }}</option>
|
||||||
|
</select>
|
||||||
|
<input class="form-input w-full" type="text" placeholder="Telefon"
|
||||||
|
v-model="participant.data.phonePrivate" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<input class="form-input w-full" type="text" placeholder="Mobil"
|
||||||
|
v-model="participant.data.phoneMobile" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ParticipantAddressForm',
|
||||||
|
props: {
|
||||||
|
participant: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
countries: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
mutable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
<template>
|
||||||
|
<div class="lg:flex lg:space-x-1 space-y-1 lg:space-y-0">
|
||||||
|
<input class="form-input w-full lg:w-1/6" type="text" placeholder="Nachname"
|
||||||
|
v-model="participant.data.lastName" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<input class="form-input w-full lg:w-1/6" type="text" placeholder="Vorname"
|
||||||
|
v-model="participant.data.firstName" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<input class="form-input w-full lg:w-1/6" type="text" placeholder="E-Mail"
|
||||||
|
v-model="participant.data.email" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<select class="form-select w-full lg:w-1/6"
|
||||||
|
v-model="participant.data.gender" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<option value="W">weiblich</option>
|
||||||
|
<option value="M">männlich</option>
|
||||||
|
<option value="D">divers</option>
|
||||||
|
</select>
|
||||||
|
<select class="form-select w-full lg:w-1/6"
|
||||||
|
v-model="participant.data.nationality" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<option value="">Nationalität...</option>
|
||||||
|
<option v-for="country in countries" :key="country.code" :value="country.code">{{ country.adjective }}</option>
|
||||||
|
</select>
|
||||||
|
<input type="date" class="form-input w-full lg:w-1/6" placeholder="Geburtsdatum"
|
||||||
|
v-model="participant.data.dateOfBirth" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ParticipantDataForm',
|
||||||
|
props: {
|
||||||
|
participant: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
countries: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
mutable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.form-control {
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
.dropdown-menu {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
<template>
|
||||||
|
<div class="relative" v-if="hasSelectedRentals">
|
||||||
|
<button class="btn btn-secondary btn-sm w-full lg:w-auto" @click.prevent="visible = !visible">
|
||||||
|
Größen <span class="glyphicon" :class="{ 'glyphicon-chevron-up': visible, 'glyphicon-chevron-down': !visible }"></span>
|
||||||
|
</button>
|
||||||
|
<div class="absolute top-100 left-0 z-10 mt-4 border shadow-md p-4 bg-white w-screen max-w-xs space-y-2" v-show="visible">
|
||||||
|
<input class="form-input w-full" type="text" placeholder="Körpergröße"
|
||||||
|
v-model="participant.data.height" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<input class="form-input w-full" type="text" placeholder="Schuhgröße"
|
||||||
|
v-model="participant.data.shoeSize" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
<input class="form-input w-full" type="text" placeholder="Gewicht"
|
||||||
|
v-model="participant.data.weight" :disabled="!mutable"
|
||||||
|
@change="$emit('updated', participant)"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ParticipantSizesForm',
|
||||||
|
props: {
|
||||||
|
participant: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
services: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
mutable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
hasSelectedRentals () {
|
||||||
|
let result = false;
|
||||||
|
for (let id of this.participant.serviceIds) {
|
||||||
|
if (typeof this.services[id] === 'undefined') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ('VER' === this.services[id].subType) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.dropdown {
|
||||||
|
margin: 0 2px 2px 0;
|
||||||
|
}
|
||||||
|
.dropdown-menu {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
<template>
|
||||||
|
<div class="relative">
|
||||||
|
<button class="btn btn-primary btn-sm w-full lg:w-auto" @click.prevent="visible = !visible">
|
||||||
|
Zustieg <span class="glyphicon" :class="{ 'glyphicon-chevron-up': visible, 'glyphicon-chevron-down': !visible }"></span>
|
||||||
|
</button>
|
||||||
|
<div class="absolute top-100 left-0 z-10 mt-4 border shadow-md p-4 bg-white w-screen max-w-xs" v-show="visible">
|
||||||
|
<div class="py-1" v-for="pickup in pickups" :key="pickup.id">
|
||||||
|
<label class="inline-flex items-center text-sm">
|
||||||
|
<input type="radio" class="form-radio"
|
||||||
|
:name="'pickup-' + participant.data.id"
|
||||||
|
v-model="pickupId"
|
||||||
|
:value="pickup.busproId"
|
||||||
|
:disabled="!mutable"
|
||||||
|
@change="$emit('selected', pickupId)"
|
||||||
|
>
|
||||||
|
<span class="ml-2">{{ pickup.city }} ({{ pickup.street }})</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import 'bootstrap-sass/assets/javascripts/bootstrap/dropdown'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'PickupSelect',
|
||||||
|
props: {
|
||||||
|
pickups: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
participant: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
mutable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
pickupId: this.participant.pickupId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.dropdown {
|
||||||
|
margin: 0 2px 2px 0;
|
||||||
|
}
|
||||||
|
.dropdown-menu {
|
||||||
|
padding: 5px;
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+78
@@ -0,0 +1,78 @@
|
|||||||
|
<template>
|
||||||
|
<div class="relative" v-if="hasServices">
|
||||||
|
<button class="btn btn-primary btn-sm w-full lg:w-auto" type="button" @click.prevent="visible = !visible">
|
||||||
|
{{ subType.label }} <span class="glyphicon" :class="{ 'glyphicon-chevron-up': visible, 'glyphicon-chevron-down': !visible }"></span>
|
||||||
|
</button>
|
||||||
|
<div class="absolute top-100 left-0 z-10 mt-4 border shadow-md p-4 bg-white w-screen max-w-xs" v-show="visible">
|
||||||
|
<div class="py-1" v-for="service in availableServices" :key="service.id">
|
||||||
|
<label class="inline-flex items-center text-sm">
|
||||||
|
<input type="checkbox" class="form-checkbox"
|
||||||
|
v-model="participant.serviceIds"
|
||||||
|
:value="service.id"
|
||||||
|
:disabled="false === isServiceSelectable(service)"
|
||||||
|
@change="selectService(service, $event)"
|
||||||
|
>
|
||||||
|
<span class="ml-2">{{ service.name }} ({{ service.price }}€)</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'ServiceSelect',
|
||||||
|
props: {
|
||||||
|
subType: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
services: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
participant: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
mutable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
selectService(service, event) {
|
||||||
|
const action = event.target.checked ? 'selected' : 'unselected';
|
||||||
|
this.$emit('updated', { action, participant: this.participant, service });
|
||||||
|
},
|
||||||
|
isServiceSelectable(service) {
|
||||||
|
// Service is mandatory so check current selection state
|
||||||
|
if (service.mandatory) {
|
||||||
|
return this.participant.serviceIds.indexOf(service.id) === -1
|
||||||
|
}
|
||||||
|
// Service is mutable and available
|
||||||
|
return true === this.mutable && service.available > 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
availableServices () {
|
||||||
|
let filteredServices = {};
|
||||||
|
for (let id of Object.keys(this.services)) {
|
||||||
|
if (this.services[id].subType !== undefined && this.services[id].subType !== this.subType.code) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
filteredServices[id] = this.services[id];
|
||||||
|
}
|
||||||
|
return filteredServices;
|
||||||
|
},
|
||||||
|
hasServices () {
|
||||||
|
return Object.keys(this.availableServices).length > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
<template>
|
||||||
|
<panel title="Gebuchte Zusatzleistungen">
|
||||||
|
<ul class="list-group">
|
||||||
|
<li class="list-group-item" v-for="(assignment, serviceId) in serviceAssignments">
|
||||||
|
{{ services[serviceId].name }}: {{ assignment.join(', ')}}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</panel>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Panel from './Panel'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ServicesOverview',
|
||||||
|
components: {
|
||||||
|
Panel
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
services: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
participantData: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
serviceAssignments () {
|
||||||
|
let assignments = {};
|
||||||
|
for (let participant of this.participantData) {
|
||||||
|
for (let id of participant.serviceIds) {
|
||||||
|
if (typeof this.services[id] === 'undefined') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!assignments.hasOwnProperty(id)) {
|
||||||
|
assignments[id] = [];
|
||||||
|
}
|
||||||
|
assignments[id].push(participant.data.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return assignments;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
+65
@@ -0,0 +1,65 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="hasServices">
|
||||||
|
<label v-for="service in services" :key="service.id" class="flex items-center mb-1">
|
||||||
|
<input type="checkbox" class="form-checkbox"
|
||||||
|
v-model="selectedTransportationIds"
|
||||||
|
:value="service.id"
|
||||||
|
:disabled="isServiceUnavailable(service) || !mutable"
|
||||||
|
@change="selectService(service, $event)"
|
||||||
|
>
|
||||||
|
<span class="ml-2">{{ service.name }}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'TransportationSelect',
|
||||||
|
props: {
|
||||||
|
services: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
initialTransportationIds: {
|
||||||
|
type: Array,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
mutable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
selectedTransportationIds: this.initialTransportationIds
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
selectService(service, event) {
|
||||||
|
let action = event.target.checked ? 'select' : 'unselect';
|
||||||
|
this.$emit('updated', { action, service, selectedTransportationIds: this.selectedTransportationIds });
|
||||||
|
},
|
||||||
|
isServiceUnavailable(service) {
|
||||||
|
return service.available === 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
hasServices () {
|
||||||
|
return Object.keys(this.services).length > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.dropdown {
|
||||||
|
margin: 0 2px 2px 0;
|
||||||
|
}
|
||||||
|
.form-check-label {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.dropdown-menu {
|
||||||
|
padding: 5px;
|
||||||
|
min-width: 300px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -5,12 +5,12 @@ import store from '../store';
|
|||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
const guard = (to, from, next) => {
|
const guard = (to, from, next) => {
|
||||||
if (store.state.loading) {
|
if (store.getters.isLoggedIn === false) {
|
||||||
next(false);
|
|
||||||
} else if (store.getters.isLoggedIn === false) {
|
|
||||||
next({ name: 'login' });
|
next({ name: 'login' });
|
||||||
} else if (to.meta.requiresTeamer && store.getters.isTeamer === false) {
|
} else if (to.meta.requiresTeamer && store.getters.isTeamer === false) {
|
||||||
next(false);
|
next(false);
|
||||||
|
} else if (to.meta.requiresGroupManager && store.getters.isGroupManager === false) {
|
||||||
|
next(false);
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
@@ -23,8 +23,9 @@ import CrmData from '../myep/CrmData'
|
|||||||
import Newsletter from '../myep/Newsletter'
|
import Newsletter from '../myep/Newsletter'
|
||||||
import Registration from '../myep/Registration'
|
import Registration from '../myep/Registration'
|
||||||
|
|
||||||
// Lazy load teamer component when required
|
// Lazy load some components when they become required
|
||||||
const Teamer = () => import('../myep/Teamer');
|
const Teamer = () => import('../myep/Teamer')
|
||||||
|
const BookingEdit = () => import('../myep/BookingEdit')
|
||||||
|
|
||||||
export default new VueRouter({
|
export default new VueRouter({
|
||||||
routes: [
|
routes: [
|
||||||
@@ -74,6 +75,13 @@ export default new VueRouter({
|
|||||||
name: 'events',
|
name: 'events',
|
||||||
path: '/vorgaenge',
|
path: '/vorgaenge',
|
||||||
component: Events,
|
component: Events,
|
||||||
|
beforeEnter: guard,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'bookingEdit',
|
||||||
|
path: '/buchung/:id',
|
||||||
|
component: BookingEdit,
|
||||||
|
meta: { requiresGroupManager: true },
|
||||||
beforeEnter: guard
|
beforeEnter: guard
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ Vue.use(Vuex);
|
|||||||
|
|
||||||
const defaultUserData = {
|
const defaultUserData = {
|
||||||
isTeamer: false,
|
isTeamer: false,
|
||||||
|
isGroupManager: false,
|
||||||
email: '',
|
email: '',
|
||||||
firstName: '',
|
firstName: '',
|
||||||
lastName: '',
|
lastName: '',
|
||||||
@@ -210,6 +211,7 @@ export default new Vuex.Store({
|
|||||||
watchlistCount: state => state.userData.watchList.length,
|
watchlistCount: state => state.userData.watchList.length,
|
||||||
onWatchlist: state => uid => state.userData.watchList.indexOf(uid) !== -1,
|
onWatchlist: state => uid => state.userData.watchList.indexOf(uid) !== -1,
|
||||||
isLoggedIn: state => !!state.authToken,
|
isLoggedIn: state => !!state.authToken,
|
||||||
isTeamer: state => !!state.userData.isTeamer
|
isTeamer: state => !!state.userData.isTeamer,
|
||||||
|
isGroupManager: state => !!state.userData.isGroupManager,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,67 +1,85 @@
|
|||||||
@import "variables";
|
@tailwind base;
|
||||||
@import "color";
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
@import "remix/variables";
|
@layer base {
|
||||||
@import "remix/colors";
|
@import "variables";
|
||||||
|
@import "color";
|
||||||
|
|
||||||
// vendor styles
|
@import "remix/variables";
|
||||||
$icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
|
@import "remix/colors";
|
||||||
@import "~bootstrap-sass/assets/stylesheets/bootstrap";
|
|
||||||
|
|
||||||
@import "mixins";
|
// vendor styles
|
||||||
|
$icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
|
||||||
|
@import "~bootstrap-sass/assets/stylesheets/bootstrap";
|
||||||
|
|
||||||
// remix
|
@import "mixins";
|
||||||
$output-bourbon-deprecation-warnings: false;
|
|
||||||
@import "~bourbon/app/assets/stylesheets/bourbon";
|
|
||||||
@import "remix/breakpoints";
|
|
||||||
@import "remix/mixins";
|
|
||||||
@import "remix/base";
|
|
||||||
@import "remix/overrides";
|
|
||||||
@import "remix/badges";
|
|
||||||
@import "remix/buttons";
|
|
||||||
@import "remix/area-nav";
|
|
||||||
@import "remix/pagehead";
|
|
||||||
@import "remix/slider";
|
|
||||||
@import "remix/header";
|
|
||||||
@import "remix/herounit";
|
|
||||||
@import "remix/calendar";
|
|
||||||
@import "remix/partnerlogos";
|
|
||||||
@import "remix/osm-map";
|
|
||||||
@import "remix/video";
|
|
||||||
@import "remix/newsletterform";
|
|
||||||
@import "remix/layout";
|
|
||||||
@import "remix/teaserbox";
|
|
||||||
@import "remix/searchresult";
|
|
||||||
@import "remix/tables";
|
|
||||||
@import "remix/product";
|
|
||||||
@import "remix/socialmedia";
|
|
||||||
@import "remix/datepicker";
|
|
||||||
@import "remix/sidebar";
|
|
||||||
@import "remix/blog";
|
|
||||||
@import "remix/forms";
|
|
||||||
@import "remix/contactnav";
|
|
||||||
@import "remix/faq";
|
|
||||||
@import "remix/destination-pulldown";
|
|
||||||
@import "remix/watchlist";
|
|
||||||
@import "remix/calculator";
|
|
||||||
|
|
||||||
// core config
|
// remix
|
||||||
@import "fonts";
|
$output-bourbon-deprecation-warnings: false;
|
||||||
@import "base";
|
@import "~bourbon/app/assets/stylesheets/bourbon";
|
||||||
@import "btn";
|
@import "remix/breakpoints";
|
||||||
@import "input";
|
@import "remix/mixins";
|
||||||
@import "breadcrumb";
|
@import "remix/base";
|
||||||
@import "modal";
|
@import "remix/overrides";
|
||||||
|
@import "remix/badges";
|
||||||
|
@import "remix/buttons";
|
||||||
|
@import "remix/area-nav";
|
||||||
|
@import "remix/pagehead";
|
||||||
|
@import "remix/slider";
|
||||||
|
@import "remix/header";
|
||||||
|
@import "remix/herounit";
|
||||||
|
@import "remix/calendar";
|
||||||
|
@import "remix/partnerlogos";
|
||||||
|
@import "remix/osm-map";
|
||||||
|
@import "remix/video";
|
||||||
|
@import "remix/newsletterform";
|
||||||
|
@import "remix/layout";
|
||||||
|
@import "remix/teaserbox";
|
||||||
|
@import "remix/searchresult";
|
||||||
|
@import "remix/tables";
|
||||||
|
@import "remix/product";
|
||||||
|
@import "remix/socialmedia";
|
||||||
|
@import "remix/datepicker";
|
||||||
|
@import "remix/sidebar";
|
||||||
|
@import "remix/blog";
|
||||||
|
@import "remix/forms";
|
||||||
|
@import "remix/contactnav";
|
||||||
|
@import "remix/faq";
|
||||||
|
@import "remix/destination-pulldown";
|
||||||
|
@import "remix/watchlist";
|
||||||
|
@import "remix/calculator";
|
||||||
|
|
||||||
//components
|
// core config
|
||||||
@import "mainnavi";
|
@import "fonts";
|
||||||
@import "footer";
|
@import "base";
|
||||||
@import "searchbar";
|
@import "btn";
|
||||||
@import "searchbox";
|
@import "input";
|
||||||
@import "newsletter";
|
@import "breadcrumb";
|
||||||
@import "disturber";
|
@import "modal";
|
||||||
@import "product";
|
|
||||||
@import "sidebar";
|
//components
|
||||||
@import "subpage";
|
@import "mainnavi";
|
||||||
@import "searchpage";
|
@import "footer";
|
||||||
@import "employee";
|
@import "searchbar";
|
||||||
|
@import "searchbox";
|
||||||
|
@import "newsletter";
|
||||||
|
@import "disturber";
|
||||||
|
@import "product";
|
||||||
|
@import "sidebar";
|
||||||
|
@import "subpage";
|
||||||
|
@import "searchpage";
|
||||||
|
@import "employee";
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer utilities {
|
||||||
|
.top-1\/2 {
|
||||||
|
top: 50%;
|
||||||
|
}
|
||||||
|
.left-1\/2 {
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
.-translate-xy-1\/2 {
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ html {
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
*, *::after, *::before {
|
*, *::after, *::before {
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
module.exports = {
|
||||||
|
future: {
|
||||||
|
removeDeprecatedGapUtilities: true,
|
||||||
|
purgeLayersByDefault: true,
|
||||||
|
},
|
||||||
|
purge: {
|
||||||
|
mode: 'layers',
|
||||||
|
layers: ['components', 'utilities'],
|
||||||
|
content: [
|
||||||
|
'./public/typo3conf/ext/ep_theme/Resources/Private/Layouts/**/*.html',
|
||||||
|
'./public/typo3conf/ext/ep_theme/Resources/Private/Partials/**/*.html',
|
||||||
|
'./public/typo3conf/ext/ep_theme/Resources/Private/Templates/**/*.html',
|
||||||
|
'./public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/**/*.js',
|
||||||
|
'./public/typo3conf/ext/ep_theme/Resources/Private/Assets/js/**/*.vue',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
overlay: {
|
||||||
|
'white': 'rgba(255, 255, 255, 0.85)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variants: {},
|
||||||
|
plugins: [
|
||||||
|
require('@tailwindcss/custom-forms'),
|
||||||
|
],
|
||||||
|
corePlugins: {
|
||||||
|
container: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user