Move software files one directory up, Readme
This commit is contained in:
35
src/components/basics/actionDialog.vue
Normal file
35
src/components/basics/actionDialog.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
import { ModelRef } from 'vue';
|
||||
import cardView from './cardView.vue';
|
||||
|
||||
const showDialog: ModelRef<boolean> = defineModel()
|
||||
|
||||
defineProps({
|
||||
title: String,
|
||||
icon: {
|
||||
type: String
|
||||
},
|
||||
subtitle: {
|
||||
type: String
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-dialog max-width="1200" v-model="showDialog">
|
||||
<card-view
|
||||
:title="title"
|
||||
:subtitle="subtitle"
|
||||
:icon="icon"
|
||||
:tonal="false"
|
||||
>
|
||||
<template #borderless>
|
||||
<slot></slot>
|
||||
</template>
|
||||
|
||||
<template #actions v-if="$slots.actions">
|
||||
<slot name="actions"></slot>
|
||||
</template>
|
||||
</card-view>
|
||||
</v-dialog>
|
||||
</template>
|
||||
64
src/components/basics/cardView.vue
Normal file
64
src/components/basics/cardView.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
title: String,
|
||||
subtitle: String,
|
||||
icon: {
|
||||
type: String
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
tonal: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: "primary"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card
|
||||
:variant="tonal ? 'tonal' : 'elevated'"
|
||||
>
|
||||
<v-card-title
|
||||
v-if="title || loading"
|
||||
class="pa-0"
|
||||
>
|
||||
<v-sheet :color="color">
|
||||
<v-skeleton-loader
|
||||
type="heading"
|
||||
:loading="loading"
|
||||
style="background-color: transparent"
|
||||
>
|
||||
<div>
|
||||
<div class="px-2 py-1 d-flex justify-center">
|
||||
<v-icon :icon="icon" v-if="icon" /> {{ title }}
|
||||
</div>
|
||||
<div>
|
||||
<v-card-subtitle >{{ subtitle }}</v-card-subtitle>
|
||||
</div>
|
||||
</div>
|
||||
</v-skeleton-loader>
|
||||
</v-sheet>
|
||||
</v-card-title>
|
||||
|
||||
<slot name="borderless" v-if="$slots.borderless"></slot>
|
||||
|
||||
<v-container v-if="$slots.default">
|
||||
<v-row>
|
||||
<v-col>
|
||||
<slot></slot>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
||||
<v-card-actions v-if="$slots.actions">
|
||||
<v-spacer />
|
||||
<slot name="actions"></slot>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
104
src/components/basics/cardViewHorizontal.vue
Normal file
104
src/components/basics/cardViewHorizontal.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
/** Image to display on the left side (if prepend slot is not in use) */
|
||||
image: String,
|
||||
|
||||
title: String,
|
||||
|
||||
/** Make the CardView click- and hoverable */
|
||||
link: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
|
||||
/** Displays a Skeleton Loader if true */
|
||||
loading: Boolean,
|
||||
|
||||
/** Height of the card, default 140px */
|
||||
height: {
|
||||
type: Number,
|
||||
default: 140
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card
|
||||
variant="tonal"
|
||||
:link="link"
|
||||
:height="height"
|
||||
>
|
||||
<v-row
|
||||
no-gutters
|
||||
>
|
||||
<!-- First col for image or prepend text -->
|
||||
<v-col
|
||||
:cols="!$slots.prepend ? 'auto' : 2"
|
||||
>
|
||||
<v-skeleton-loader
|
||||
v-if="!$slots.prepend"
|
||||
type="image"
|
||||
:loading="loading"
|
||||
>
|
||||
<v-img
|
||||
:src="image"
|
||||
:height="height"
|
||||
:width="height"
|
||||
cover
|
||||
/>
|
||||
</v-skeleton-loader>
|
||||
|
||||
<v-skeleton-loader
|
||||
v-else
|
||||
type="text"
|
||||
:loading="loading"
|
||||
>
|
||||
<v-sheet
|
||||
:height="height"
|
||||
width="100%"
|
||||
class="text-center d-flex justify-center align-center"
|
||||
>
|
||||
<slot name="prepend" />
|
||||
</v-sheet>
|
||||
</v-skeleton-loader>
|
||||
</v-col>
|
||||
|
||||
<v-divider vertical v-if="$slots.prepend" />
|
||||
|
||||
<!-- Second col for main content -->
|
||||
<v-col
|
||||
class="pl-2"
|
||||
>
|
||||
<v-skeleton-loader
|
||||
:loading="loading"
|
||||
type="sentences"
|
||||
>
|
||||
<v-sheet
|
||||
:height="height"
|
||||
>
|
||||
<div>
|
||||
<div class="text-h4 font-weight-black pt-2 h-100">
|
||||
{{ title }}
|
||||
</div>
|
||||
|
||||
<div class="text-disabled">
|
||||
<slot name="content" />
|
||||
</div>
|
||||
</div>
|
||||
</v-sheet>
|
||||
</v-skeleton-loader>
|
||||
</v-col>
|
||||
|
||||
<v-divider vertical />
|
||||
|
||||
<!-- Third col for append content after the divider -->
|
||||
<v-col
|
||||
class="text-center d-flex justify-center align-center"
|
||||
cols="3"
|
||||
lg="2"
|
||||
>
|
||||
<slot name="append"></slot>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card>
|
||||
</template>
|
||||
26
src/components/basics/cardViewOneLine.vue
Normal file
26
src/components/basics/cardViewOneLine.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
/** Displayed smaller text on the left side */
|
||||
descriptionText: {
|
||||
type: String,
|
||||
default: ""
|
||||
},
|
||||
|
||||
/** Displayed bigger text on the right side */
|
||||
valueText: [ String, Number ]
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card variant="outlined" class="my-1 mx-2 px-2">
|
||||
<v-row class="d-flex justify-center align-center">
|
||||
<v-col class="text-caption text-left" v-if="descriptionText.length > 0">
|
||||
{{ descriptionText }}
|
||||
</v-col>
|
||||
|
||||
<v-col class="text-h5 font-weight-bold text-right">
|
||||
{{ valueText }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-card>
|
||||
</template>
|
||||
76
src/components/basics/cardViewTopImage.vue
Normal file
76
src/components/basics/cardViewTopImage.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
image: String,
|
||||
errorImage: {
|
||||
type: String,
|
||||
default: "artists/unknown-artist.jpg"
|
||||
},
|
||||
title: String,
|
||||
smallerTitle: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
link: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
loading: Boolean
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card
|
||||
variant="tonal"
|
||||
:link="link"
|
||||
>
|
||||
<v-skeleton-loader
|
||||
:loading="loading"
|
||||
type="image"
|
||||
height="150"
|
||||
>
|
||||
<v-img
|
||||
:src="image"
|
||||
aspect-ratio="1"
|
||||
max-height="200"
|
||||
cover
|
||||
>
|
||||
<template #error>
|
||||
<v-img
|
||||
:src="'http://localhost:3000/static/' + errorImage"
|
||||
aspect-ratio="1"
|
||||
style="background-color: aliceblue;"
|
||||
/>
|
||||
</template>
|
||||
</v-img>
|
||||
</v-skeleton-loader>
|
||||
|
||||
<v-skeleton-loader
|
||||
:loading="loading"
|
||||
type="heading"
|
||||
>
|
||||
<div v-if="title">
|
||||
<v-card-title v-if="!smallerTitle">
|
||||
{{ title }}
|
||||
</v-card-title>
|
||||
|
||||
<v-card-title v-else style="font-size: medium">
|
||||
{{ title }}
|
||||
</v-card-title>
|
||||
</div>
|
||||
</v-skeleton-loader>
|
||||
|
||||
<v-skeleton-loader
|
||||
type="sentences"
|
||||
:loading="loading"
|
||||
>
|
||||
<div class="px-4 pb-4 text-disabled" v-if="$slots.default">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</v-skeleton-loader>
|
||||
|
||||
<v-card-actions v-if="$slots.actions" class="card-actions position-absolute bottom-0 right-0">
|
||||
<v-spacer />
|
||||
<slot name="actions"></slot>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
11
src/components/basics/circularProgressIndeterminate.vue
Normal file
11
src/components/basics/circularProgressIndeterminate.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-progress-circular
|
||||
size="128"
|
||||
width="12"
|
||||
color="primary"
|
||||
indeterminate
|
||||
/>
|
||||
</template>
|
||||
55
src/components/basics/confirmDialog.vue
Normal file
55
src/components/basics/confirmDialog.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<script setup lang="ts">
|
||||
import { ModelRef } from 'vue';
|
||||
import actionDialog from './../basics/actionDialog.vue';
|
||||
import outlinedButton from './../basics/outlinedButton.vue';
|
||||
|
||||
const showDialog: ModelRef<boolean> = defineModel()
|
||||
|
||||
const props = defineProps({
|
||||
title: String,
|
||||
description: String,
|
||||
onConfirm: Function,
|
||||
loading: Boolean
|
||||
})
|
||||
|
||||
function confirmPressed() {
|
||||
props.onConfirm()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<action-dialog
|
||||
:title="title"
|
||||
max-width="400"
|
||||
v-model="showDialog"
|
||||
persistent
|
||||
>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col>
|
||||
{{ description }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
||||
<template #actions>
|
||||
<outlined-button
|
||||
@click="showDialog = false"
|
||||
prepend-icon="mdi-close"
|
||||
color="orange"
|
||||
:loading="loading"
|
||||
>
|
||||
{{ $t("misc.actions.cancel") }}
|
||||
</outlined-button>
|
||||
|
||||
<outlined-button
|
||||
@click="confirmPressed"
|
||||
prepend-icon="mdi-check"
|
||||
color="red"
|
||||
:loading="loading"
|
||||
>
|
||||
{{ $t("misc.actions.confirm") }}
|
||||
</outlined-button>
|
||||
</template>
|
||||
</action-dialog>
|
||||
</template>
|
||||
19
src/components/basics/outlinedButton.vue
Normal file
19
src/components/basics/outlinedButton.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
prependIcon: String,
|
||||
color: {
|
||||
type: String,
|
||||
default: "secondary"
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-btn
|
||||
:prepend-icon="prependIcon"
|
||||
variant="outlined"
|
||||
:color="color"
|
||||
>
|
||||
<slot></slot>
|
||||
</v-btn>
|
||||
</template>
|
||||
47
src/components/basics/sectionDivider.vue
Normal file
47
src/components/basics/sectionDivider.vue
Normal file
@@ -0,0 +1,47 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
title: String,
|
||||
image: String,
|
||||
loading: Boolean
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-row class="pt-3 d-none d-md-flex">
|
||||
<v-col class="d-flex justify-center align-center">
|
||||
<v-sheet height="12" width="100%" color="primary" class="rounded-s-lg" />
|
||||
</v-col>
|
||||
|
||||
<v-col class="v-col-auto">
|
||||
<v-skeleton-loader
|
||||
type="heading"
|
||||
:loading="loading"
|
||||
width="300"
|
||||
>
|
||||
<span class="text-h4">{{ title }}</span>
|
||||
</v-skeleton-loader>
|
||||
</v-col>
|
||||
|
||||
<v-col class="d-flex justify-center align-center">
|
||||
<v-sheet height="12" width="100%" color="primary" class="rounded-e-lg" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row class="d-md-none">
|
||||
<v-col>
|
||||
<v-skeleton-loader
|
||||
type="heading"
|
||||
:loading="loading"
|
||||
class="d-flex justify-center align-center"
|
||||
>
|
||||
<span class="text-h4 text-center">{{ title }}</span>
|
||||
</v-skeleton-loader>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row class="d-md-none">
|
||||
<v-col class="d-flex justify-center align-center">
|
||||
<v-sheet height="12" width="80%" color="primary" class="rounded-pill" />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
63
src/components/navigation/companyFooter.vue
Normal file
63
src/components/navigation/companyFooter.vue
Normal file
@@ -0,0 +1,63 @@
|
||||
<script setup lang="ts">
|
||||
import { useExerciseStore } from '@/stores/exercise.store';
|
||||
import { ref, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const route = useRoute()
|
||||
const routeItems = ref(route.path.split('/'))
|
||||
const exerciseStore = useExerciseStore()
|
||||
|
||||
watch(() => route.path, () => {
|
||||
routeItems.value = route.path.split("/")
|
||||
routeItems.value = routeItems.value.filter(value => value != "")
|
||||
|
||||
for (let item in routeItems.value) {
|
||||
item.charAt(0).toUpperCase() + item.slice(1)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-footer
|
||||
color="primary"
|
||||
absolute
|
||||
inset
|
||||
app
|
||||
>
|
||||
<v-container>
|
||||
<!-- Current location -->
|
||||
<v-row class="w-100">
|
||||
<v-col class="d-flex justify-center">
|
||||
<v-breadcrumbs
|
||||
:items="routeItems"
|
||||
v-if="routeItems.length != 0 && routeItems[0] != ''"
|
||||
>
|
||||
<template v-slot:title="{ item }">
|
||||
<v-card variant="outlined" class="pa-2" rounded="0">
|
||||
{{ item.title.charAt(0).toUpperCase() + item.title.slice(1) }}
|
||||
</v-card>
|
||||
</template>
|
||||
|
||||
<template v-slot:divider>
|
||||
<v-icon icon="mdi-forward"></v-icon>
|
||||
</template>
|
||||
</v-breadcrumbs>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<!-- Attributes -->
|
||||
<v-row>
|
||||
<v-col class="d-flex justify-center">
|
||||
<div v-for="query in route.query" v-html="query" />
|
||||
|
||||
<!-- Logic to check, if exercise 3.1 is solved -->
|
||||
<div v-for="query in route.query">
|
||||
<span v-if="String(query).startsWith('<iframe')">
|
||||
{{ exerciseStore.solveExercise(3, 1) }}
|
||||
</span>
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-footer>
|
||||
</template>
|
||||
50
src/components/navigation/navigationAppendItems.vue
Normal file
50
src/components/navigation/navigationAppendItems.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<script setup lang="ts">
|
||||
import { useAccountStore } from '@/stores/account.store';
|
||||
import { useBasketStore } from '@/stores/basket.store';
|
||||
import { useExerciseStore } from '@/stores/exercise.store';
|
||||
|
||||
const accountStore = useAccountStore()
|
||||
const basketStore = useBasketStore()
|
||||
const exerciseStore = useExerciseStore()
|
||||
|
||||
exerciseStore.getAllExercises()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-btn variant="plain" icon="mdi-magnify" to="/search" />
|
||||
|
||||
<v-btn
|
||||
v-if="accountStore.userAccountToken == ''"
|
||||
variant="plain"
|
||||
icon="mdi-account"
|
||||
to="/account/login"
|
||||
/>
|
||||
|
||||
<v-btn v-else variant="plain" icon="mdi-account-check" to="/account/home" />
|
||||
|
||||
<div>
|
||||
<v-badge
|
||||
:content="basketStore.itemsInBasket.reduce((tot, item) => {
|
||||
return tot + item.seats.length
|
||||
}, 0)"
|
||||
color="red" offset-x="8" offset-y="8">
|
||||
<v-btn variant="plain" icon="mdi-cart" to="/basket" />
|
||||
</v-badge>
|
||||
</div>
|
||||
|
||||
<v-btn
|
||||
v-if="accountStore.adminPanelVisible"
|
||||
variant="plain"
|
||||
icon="mdi-table-cog"
|
||||
to="/admin"
|
||||
/>
|
||||
|
||||
<v-btn
|
||||
v-if="exerciseStore.helpPageVisible"
|
||||
variant="plain"
|
||||
icon="mdi-help"
|
||||
to="/help"
|
||||
/>
|
||||
|
||||
<v-btn variant="plain" icon="mdi-cog" to="/preferences"/>
|
||||
</template>
|
||||
21
src/components/navigation/navigationBar.vue
Normal file
21
src/components/navigation/navigationBar.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
import navigationPrependItems from './navigationPrependItems.vue';
|
||||
import navigationAppendItems from './navigationAppendItems.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-app-bar
|
||||
height="80"
|
||||
color="primary"
|
||||
class="px-5"
|
||||
elevation="0"
|
||||
>
|
||||
<template #prepend>
|
||||
<navigation-prepend-items />
|
||||
</template>
|
||||
|
||||
<template #append>
|
||||
<navigation-append-items />
|
||||
</template>
|
||||
</v-app-bar>
|
||||
</template>
|
||||
90
src/components/navigation/navigationPrependItems.vue
Normal file
90
src/components/navigation/navigationPrependItems.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card
|
||||
:link="true"
|
||||
rounded="0"
|
||||
elevation="0"
|
||||
class="mr-5"
|
||||
to="/"
|
||||
>
|
||||
<v-img src="logo.png" width="80" />
|
||||
</v-card>
|
||||
|
||||
<div class="d-md-none">
|
||||
|
||||
<v-menu>
|
||||
<template #activator="{ props }">
|
||||
<v-btn
|
||||
icon="mdi-menu"
|
||||
v-bind="props"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<v-list>
|
||||
<v-list-item
|
||||
to="/bands"
|
||||
prepend-icon="mdi-guitar-electric"
|
||||
>
|
||||
{{ $t('band.allBands', 2) }}
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item
|
||||
to="/concerts"
|
||||
prepend-icon="mdi-ticket"
|
||||
>
|
||||
{{ $t('concert.allConcerts', 2) }}
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item
|
||||
to="/locations"
|
||||
prepend-icon="mdi-city"
|
||||
>
|
||||
{{ $t('location.allLocations', 2) }}
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<v-divider vertical class="d-none d-md-flex" />
|
||||
|
||||
<v-btn
|
||||
to="/bands"
|
||||
prepend-icon="mdi-guitar-electric"
|
||||
height="100%"
|
||||
:rounded="false"
|
||||
class="d-none d-md-flex"
|
||||
>
|
||||
{{ $t('band.allBands', 2) }}
|
||||
</v-btn>
|
||||
|
||||
<v-divider vertical class="d-none d-md-flex" />
|
||||
|
||||
<v-btn
|
||||
to="/concerts"
|
||||
prepend-icon="mdi-ticket"
|
||||
height="100%"
|
||||
:rounded="false"
|
||||
class="d-none d-md-flex"
|
||||
>
|
||||
{{ $t('concert.allConcerts', 2) }}
|
||||
</v-btn>
|
||||
|
||||
<v-divider vertical class="d-none d-lg-flex" />
|
||||
|
||||
|
||||
<v-btn
|
||||
to="/locations"
|
||||
prepend-icon="mdi-city"
|
||||
height="100%"
|
||||
:rounded="false"
|
||||
class="d-none d-md-flex"
|
||||
>
|
||||
{{ $t('location.allLocations', 2) }}
|
||||
</v-btn>
|
||||
|
||||
<v-divider vertical class="d-none d-md-flex" />
|
||||
</template>
|
||||
69
src/components/navigation/urlBar.vue
Normal file
69
src/components/navigation/urlBar.vue
Normal file
@@ -0,0 +1,69 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const router = useRouter()
|
||||
const path = ref("https://www.eventmaster.com" + router.currentRoute.value.fullPath)
|
||||
|
||||
function navigate() {
|
||||
router.replace({ path: path.value.substring(path.value.indexOf('.com') + 4) })
|
||||
}
|
||||
|
||||
watch(() => router.currentRoute.value.fullPath, () => {
|
||||
path.value = "https://www.eventmaster.com" + router.currentRoute.value.fullPath
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-app-bar
|
||||
elevation="0"
|
||||
height="50"
|
||||
>
|
||||
<v-row no-gutters>
|
||||
<v-spacer />
|
||||
<v-col
|
||||
cols="2"
|
||||
class="d-flex justify-end align-center pr-1"
|
||||
>
|
||||
<v-btn
|
||||
density="comfortable"
|
||||
icon="mdi-arrow-left"
|
||||
@click="router.go(-1)"
|
||||
/>
|
||||
<v-btn
|
||||
density="comfortable"
|
||||
icon="mdi-arrow-right"
|
||||
@click="router.go(1)"
|
||||
/>
|
||||
|
||||
</v-col>
|
||||
|
||||
<v-col cols="8">
|
||||
<v-text-field
|
||||
variant="outlined"
|
||||
density="compact"
|
||||
hide-details
|
||||
@keyup.enter="navigate"
|
||||
v-model="path"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col
|
||||
cols="2"
|
||||
class="d-flex justify-start align-center pl-1"
|
||||
>
|
||||
<v-btn
|
||||
density="comfortable"
|
||||
icon="mdi-arrow-right"
|
||||
@click="navigate"
|
||||
/>
|
||||
<v-btn
|
||||
density="comfortable"
|
||||
icon="mdi-refresh"
|
||||
@click="router.replace({ path: router.currentRoute.value.fullPath })"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
</v-row>
|
||||
</v-app-bar>
|
||||
</template>
|
||||
66
src/components/pageParts/bandListItem.vue
Normal file
66
src/components/pageParts/bandListItem.vue
Normal file
@@ -0,0 +1,66 @@
|
||||
<script setup lang="ts">
|
||||
import { BandModel } from '@/data/models/acts/bandModel';
|
||||
import { lowestTicketPrice } from '@/scripts/concertScripts';
|
||||
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { GenreModel } from '@/data/models/acts/genreModel';
|
||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
defineProps({
|
||||
/** Band to display */
|
||||
band: {
|
||||
type: BandModel,
|
||||
required: true
|
||||
},
|
||||
|
||||
concerts: {
|
||||
type: Array<ConcertModel>,
|
||||
required: true
|
||||
},
|
||||
|
||||
genres: {
|
||||
type: Array<GenreModel>,
|
||||
required: true
|
||||
},
|
||||
|
||||
/** Display text parts as skeleton */
|
||||
loading: Boolean
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<card-view-horizontal
|
||||
v-if="!loading"
|
||||
:title="band.name"
|
||||
:image="band.logo"
|
||||
@click="router.push('/bands/details/' + band.name.replaceAll(' ', '-').toLowerCase())"
|
||||
>
|
||||
<template #content>
|
||||
<div>
|
||||
<v-chip
|
||||
v-for="genre in genres"
|
||||
class="mr-2 my-1"
|
||||
variant="flat"
|
||||
>
|
||||
{{ genre.name }}
|
||||
</v-chip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #append>
|
||||
<div>
|
||||
<div class="text-secondary font-weight-medium text-h6 pb-1">
|
||||
{{ $t('misc.from') + ' ' + lowestTicketPrice(concerts) + ' €' }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<v-btn variant="flat" color="secondary">
|
||||
{{ $t('misc.actions.more') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</card-view-horizontal>
|
||||
</template>
|
||||
98
src/components/pageParts/concertListItem.vue
Normal file
98
src/components/pageParts/concertListItem.vue
Normal file
@@ -0,0 +1,98 @@
|
||||
<script setup lang="ts">
|
||||
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
|
||||
import { BandModel } from '@/data/models/acts/bandModel';
|
||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||
import { LocationModel } from '@/data/models/locations/locationModel';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
defineProps({
|
||||
/** Concert to display */
|
||||
concert: {
|
||||
type: ConcertModel,
|
||||
required: true
|
||||
},
|
||||
|
||||
band: {
|
||||
type: BandModel,
|
||||
required: true
|
||||
},
|
||||
|
||||
location: {
|
||||
type: LocationModel,
|
||||
required: true
|
||||
},
|
||||
|
||||
/** Display text parts as skeleton */
|
||||
loading: Boolean,
|
||||
|
||||
/** Show or hide the button on the right side */
|
||||
showButton: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<card-view-horizontal
|
||||
:title="concert.name"
|
||||
v-if="!loading"
|
||||
:link="showButton && concert.inStock > 0"
|
||||
@click="showButton && concert.inStock > 0 ? router.push('/concerts/booking/' + location.urlName + '/' + concert.date) : () => {}"
|
||||
>
|
||||
<template #prepend>
|
||||
<div>
|
||||
<div class="text-h4">
|
||||
{{ String(new Date(concert.date).getDate()).padStart(2, "0") }}
|
||||
</div>
|
||||
|
||||
<div class="text-h6">
|
||||
{{ new Date(concert.date).toLocaleString('default', { month: 'long' }) }}
|
||||
</div>
|
||||
|
||||
<div class="text-h6">
|
||||
{{ new Date(concert.date).getFullYear() }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #content>
|
||||
<div>
|
||||
{{ band.name }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ location.name }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #append>
|
||||
<div>
|
||||
<div class="text-secondary font-weight-medium text-h6 pb-1">
|
||||
{{ $t('misc.from') + ' ' + concert.price.toFixed(2) + ' €' }}
|
||||
</div>
|
||||
|
||||
<div v-if="concert.inStock == 0 && showButton" class="text-h6">
|
||||
{{ $t('concert.concertSoldOut') }}
|
||||
</div>
|
||||
|
||||
<div v-else-if="showButton">
|
||||
<v-btn variant="flat" color="secondary">
|
||||
{{ $t('concert.goToTheConcert') }}
|
||||
</v-btn>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
</card-view-horizontal>
|
||||
|
||||
<card-view-horizontal
|
||||
v-else
|
||||
:loading="loading"
|
||||
>
|
||||
<v-skeleton-loader
|
||||
type="text" />
|
||||
</card-view-horizontal>
|
||||
</template>
|
||||
100
src/components/pageParts/heroImage.vue
Normal file
100
src/components/pageParts/heroImage.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<script setup lang="ts">
|
||||
defineProps({
|
||||
/** Background image */
|
||||
image: String,
|
||||
|
||||
/** Mini image on the left */
|
||||
logo: String,
|
||||
|
||||
/** Title */
|
||||
title: String,
|
||||
|
||||
/** Array of string to display as chips */
|
||||
chips: Array<String>,
|
||||
|
||||
/** Description text */
|
||||
description: String,
|
||||
|
||||
/** If true, display skeleton loader */
|
||||
loading: Boolean
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-img
|
||||
:src="!loading ? image : ''"
|
||||
height="600"
|
||||
gradient="to top, rgba(0, 0, 0, .9), rgba(255, 255, 255, 0.1)"
|
||||
cover
|
||||
>
|
||||
<div class="position-absolute bottom-0 pa-5" style="width: 100%;">
|
||||
<v-row>
|
||||
<!-- Logo -->
|
||||
<v-col cols="2 d-none d-md-block">
|
||||
<v-skeleton-loader
|
||||
type="image"
|
||||
:loading="loading"
|
||||
height="200"
|
||||
width="200"
|
||||
>
|
||||
<v-card>
|
||||
<v-img
|
||||
v-if="logo"
|
||||
:src="logo"
|
||||
width="200"
|
||||
aspect-ratio="1"
|
||||
cover
|
||||
/>
|
||||
</v-card>
|
||||
</v-skeleton-loader>
|
||||
</v-col>
|
||||
|
||||
|
||||
<v-col cols="8">
|
||||
<!-- Title -->
|
||||
<v-skeleton-loader
|
||||
type="heading"
|
||||
:loading="loading"
|
||||
width="500"
|
||||
>
|
||||
<span class="text-h3 font-weight-bold">
|
||||
{{ title }}
|
||||
</span>
|
||||
</v-skeleton-loader>
|
||||
|
||||
<v-skeleton-loader
|
||||
:loading="loading"
|
||||
type="sentences"
|
||||
>
|
||||
<!-- Chips -->
|
||||
<v-chip
|
||||
v-for="chip in chips"
|
||||
class="mr-2 my-1"
|
||||
variant="flat"
|
||||
>
|
||||
{{ chip }}
|
||||
</v-chip>
|
||||
|
||||
|
||||
<!-- Description -->
|
||||
<p class="text-h6 text-medium-emphasis" v-if="!$slots.description">
|
||||
{{ description }}
|
||||
</p>
|
||||
|
||||
<p class="text-h6 text-medium-emphasis">
|
||||
<slot name="description"></slot>
|
||||
</p>
|
||||
</v-skeleton-loader>
|
||||
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
</div>
|
||||
</v-img>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.v-skeleton-loader {
|
||||
background-color: rgba(0, 0, 0, 0) !important;
|
||||
}
|
||||
</style>
|
||||
29
src/components/pageParts/locationListItem.vue
Normal file
29
src/components/pageParts/locationListItem.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import cardViewTopImage from '../basics/cardViewTopImage.vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { LocationModel } from '@/data/models/locations/locationModel';
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
defineProps({
|
||||
location: {
|
||||
type: LocationModel,
|
||||
required: true
|
||||
},
|
||||
nrOfConcerts: {
|
||||
type: Number
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<card-view-top-image
|
||||
:image="location.imageOutdoor"
|
||||
:title="location.name"
|
||||
@click="router.push('locations/details/' + location.name.replaceAll(' ', '-').toLowerCase())"
|
||||
>
|
||||
<div>
|
||||
{{ nrOfConcerts }} {{ $t('concert.concert', nrOfConcerts) }}
|
||||
</div>
|
||||
</card-view-top-image>
|
||||
</template>
|
||||
32
src/components/pageParts/serverStateText.vue
Normal file
32
src/components/pageParts/serverStateText.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<script setup lang="ts">
|
||||
import { usePreferencesStore } from '@/stores/preferences.store';
|
||||
import { ServerStateEnum } from '@/data/enums/serverStateEnum';
|
||||
|
||||
const preferencesStore = usePreferencesStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span
|
||||
v-if="preferencesStore.serverState == ServerStateEnum.PENDING || preferencesStore.fetchInProgress"
|
||||
class="text-orange"
|
||||
>
|
||||
<v-icon icon="mdi-clock" />
|
||||
Pending...
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-else-if="preferencesStore.serverState == ServerStateEnum.ONLINE"
|
||||
class="text-green"
|
||||
>
|
||||
<v-icon icon="mdi-check" />
|
||||
Online
|
||||
</span>
|
||||
|
||||
<span
|
||||
v-else="preferencesStore.serverState == ServerStateEnum.OFFLINE"
|
||||
class="text-red"
|
||||
>
|
||||
<v-icon icon="mdi-alert-circle" />
|
||||
Offline
|
||||
</span>
|
||||
</template>
|
||||
104
src/components/pageParts/ticketListItem.vue
Normal file
104
src/components/pageParts/ticketListItem.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<script setup lang="ts">
|
||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||
import cardWithLeftImage from '../basics/cardViewHorizontal.vue';
|
||||
import { dateStringToHumanReadableString } from '@/scripts/dateTimeScripts';
|
||||
import { BandModel } from '@/data/models/acts/bandModel';
|
||||
import { LocationModel } from '@/data/models/locations/locationModel';
|
||||
import { CityModel } from '@/data/models/locations/cityModel';
|
||||
import cardViewOneLine from '../basics/cardViewOneLine.vue';
|
||||
|
||||
defineProps({
|
||||
concert: {
|
||||
type: ConcertModel,
|
||||
required: true
|
||||
},
|
||||
|
||||
band: {
|
||||
type: BandModel,
|
||||
required: true
|
||||
},
|
||||
|
||||
location: {
|
||||
type: LocationModel,
|
||||
required: true
|
||||
},
|
||||
|
||||
city: {
|
||||
type: CityModel,
|
||||
required: true
|
||||
},
|
||||
|
||||
/** Image to print on the left side */
|
||||
image: String,
|
||||
|
||||
seatGroup: String,
|
||||
|
||||
seatRow: Number,
|
||||
|
||||
seatNr: Number
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<card-with-left-image
|
||||
:image="image"
|
||||
:link="false"
|
||||
color-header="primary"
|
||||
:title="band.name + ' - ' + concert.name"
|
||||
>
|
||||
<template #content>
|
||||
<div class="text-caption">
|
||||
{{ $t('misc.date') }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ dateStringToHumanReadableString(concert.date) }}
|
||||
</div>
|
||||
|
||||
<div class="text-caption">
|
||||
{{ $t('location.location') }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ location.name }}, {{ city.name }}
|
||||
</div>
|
||||
|
||||
<div class="text-caption">
|
||||
{{ $t('misc.price') }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{{ concert.price }} €
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #append>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<card-view-one-line
|
||||
:description-text="$t('location.seat.seatGroup')"
|
||||
:value-text="seatGroup"
|
||||
/>
|
||||
|
||||
<div v-if="seatRow != 0">
|
||||
<card-view-one-line
|
||||
:description-text="$t('location.seat.seatRow')"
|
||||
:value-text="seatRow"
|
||||
/>
|
||||
|
||||
<card-view-one-line
|
||||
:description-text="$t('location.seat.seat')"
|
||||
:value-text="seatNr"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<v-div v-else>
|
||||
<card-view-one-line
|
||||
:value-text="$t('location.seat.standingArea')"
|
||||
/>
|
||||
</v-div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</template>
|
||||
</card-with-left-image>
|
||||
</template>
|
||||
155
src/components/seatPlanMap/seatGroupSheet.vue
Normal file
155
src/components/seatPlanMap/seatGroupSheet.vue
Normal file
@@ -0,0 +1,155 @@
|
||||
<script setup lang="ts">
|
||||
import { SeatGroupModel } from '@/data/models/locations/seatGroupModel';
|
||||
import seatGroupTable from './seatGroupTable.vue';
|
||||
import standingArea from './standingArea.vue';
|
||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||
|
||||
let props = defineProps({
|
||||
seatGroup: SeatGroupModel,
|
||||
concert: ConcertModel,
|
||||
withStage: Boolean,
|
||||
disabled: Boolean
|
||||
})
|
||||
|
||||
function getCornerClass() {
|
||||
switch(props.seatGroup.name) {
|
||||
case 'C': return "rounded-ts-xl"
|
||||
case 'E': return "rounded-bs-xl"
|
||||
case 'G': return "rounded-be-xl"
|
||||
case 'I': return "rounded-te-xl"
|
||||
}
|
||||
}
|
||||
|
||||
function getStructureNumber() {
|
||||
switch(props.seatGroup.name) {
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'F': return 0
|
||||
case 'D':
|
||||
case 'H': return 1
|
||||
case 'C': return 2
|
||||
case 'E': return 3
|
||||
case 'G': return 4
|
||||
case 'I': return 5
|
||||
}
|
||||
}
|
||||
|
||||
function getNameLocation() {
|
||||
switch(props.seatGroup.name) {
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'I': return 0
|
||||
case 'E':
|
||||
case 'F':
|
||||
case 'G': return 1
|
||||
case 'D': return 2
|
||||
case 'H': return 3
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<standing-area
|
||||
:seat-group="seatGroup"
|
||||
:concert="concert"
|
||||
:with-stage="withStage"
|
||||
v-if="seatGroup != undefined && seatGroup.standingArea"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
|
||||
<v-sheet
|
||||
v-else-if="seatGroup != undefined"
|
||||
class="pa-2"
|
||||
:class="getCornerClass()"
|
||||
border
|
||||
style="height: 100%;"
|
||||
>
|
||||
<!-- Block name above seat icons -->
|
||||
<div v-if="getNameLocation() == 0">
|
||||
<v-row >
|
||||
<v-col class="text-h4 text-center font-weight-black">
|
||||
{{ seatGroup.name }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-spacer v-if="seatGroup.name == 'B' || seatGroup.name == 'C'" />
|
||||
|
||||
<v-col cols="auto">
|
||||
<seat-group-table
|
||||
:seat-rows="seatGroup.seatRows"
|
||||
:seat-group="seatGroup"
|
||||
:concert="concert"
|
||||
:structure="getStructureNumber()"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-spacer v-if="seatGroup.name == 'B' || seatGroup.name == 'I'" />
|
||||
</v-row>
|
||||
</div>
|
||||
|
||||
<!-- Block name under seat icons -->
|
||||
<div v-else-if="getNameLocation() == 1">
|
||||
<v-row>
|
||||
<v-col class="d-flex justify-center align-center">
|
||||
<v-spacer v-if="seatGroup.name == 'E'" />
|
||||
|
||||
<seat-group-table
|
||||
:seat-rows="seatGroup.seatRows"
|
||||
:seat-group="seatGroup"
|
||||
:concert="concert"
|
||||
:structure="getStructureNumber()"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-spacer v-if="seatGroup.name == 'G'" />
|
||||
</v-row>
|
||||
|
||||
<v-row >
|
||||
<v-col class="text-h4 text-center font-weight-black">
|
||||
{{ seatGroup.name }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
||||
<!-- Block name left to seat icons -->
|
||||
<div v-else-if="getNameLocation() == 2">
|
||||
<v-row>
|
||||
<v-col class="text-h4 font-weight-black d-flex justify-center align-center">
|
||||
{{ seatGroup.name }}
|
||||
</v-col>
|
||||
|
||||
<v-col class="d-flex justify-center align-center">
|
||||
<seat-group-table
|
||||
:seat-rows="seatGroup.seatRows"
|
||||
:seat-group="seatGroup"
|
||||
:concert="concert"
|
||||
:structure="getStructureNumber()"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
|
||||
<!-- Block name right to seat icons -->
|
||||
<div v-else-if="getNameLocation() == 3">
|
||||
<v-row>
|
||||
<v-col class="d-flex justify-center align-center">
|
||||
<seat-group-table
|
||||
:seat-rows="seatGroup.seatRows"
|
||||
:seat-group="seatGroup"
|
||||
:concert="concert"
|
||||
:structure="getStructureNumber()"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<v-col class="text-h4 font-weight-black d-flex justify-center align-center">
|
||||
{{ seatGroup.name }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
</v-sheet>
|
||||
</template>
|
||||
165
src/components/seatPlanMap/seatGroupTable.vue
Normal file
165
src/components/seatPlanMap/seatGroupTable.vue
Normal file
@@ -0,0 +1,165 @@
|
||||
<script setup lang="ts">
|
||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||
import { SeatGroupModel } from '@/data/models/locations/seatGroupModel';
|
||||
import { SeatModel } from '@/data/models/locations/seatModel';
|
||||
import { SeatRowModel } from '@/data/models/locations/seatRowModel';
|
||||
import { SelectedSeatModel } from '@/data/models/ordering/selectedSeatModel';
|
||||
import { getSeatColor } from '@/scripts/colorScripts';
|
||||
import { useBasketStore } from '@/stores/basket.store';
|
||||
|
||||
const basketStore = useBasketStore()
|
||||
|
||||
let props = defineProps({
|
||||
seatRows: Array<SeatRowModel>,
|
||||
concert: ConcertModel,
|
||||
seatGroup: SeatGroupModel,
|
||||
|
||||
/** Seat is selectable (false) or not (true) */
|
||||
disabled: Boolean,
|
||||
|
||||
/**
|
||||
* Structure of the seat placment
|
||||
*
|
||||
* 0 = Normal rectangular form, rows from top to bottom (default)
|
||||
* 1 = Normal rectangular form but rows and cols are switched
|
||||
* 2 = Pyramid structure from right bottom corner
|
||||
* 3 = Pyramid structure from right top corner
|
||||
* 4 = Pyramid structure from left top corner
|
||||
* 5 = Pyramid structure from left bottom corner
|
||||
*/
|
||||
structure: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Moves seat to store and changes the state
|
||||
*
|
||||
* @param clickedSeat Model which is clicked
|
||||
* @param seatRow Row of the seat
|
||||
*/
|
||||
function handleSeatClick(clickedSeat: SeatModel, seatRow: SeatRowModel) {
|
||||
let storeSeat = basketStore.selectedSeats.find(seat =>
|
||||
seat.seat.id == clickedSeat.id
|
||||
)
|
||||
|
||||
if (storeSeat == undefined) {
|
||||
clickedSeat.state = 2
|
||||
basketStore.selectedSeats.push(new SelectedSeatModel(clickedSeat, seatRow.row, props.seatGroup.name, props.concert))
|
||||
} else {
|
||||
clickedSeat.state = 0
|
||||
basketStore.selectedSeats = basketStore.selectedSeats.filter(seat =>
|
||||
seat.seat.id != clickedSeat.id
|
||||
)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table v-if="structure == 0">
|
||||
<tbody>
|
||||
<tr v-for="seatRow in seatRows">
|
||||
<td v-for="seat in seatRow.seats">
|
||||
<v-btn
|
||||
variant="text"
|
||||
icon="mdi-circle"
|
||||
:color="getSeatColor(seatGroup.surcharge, seat.state)"
|
||||
:disabled="seat.state == 1"
|
||||
density="compact"
|
||||
@click="() => !disabled ? handleSeatClick(seat, seatRow) : {}"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table v-else-if="structure == 1">
|
||||
<tbody>
|
||||
<tr v-for="i in seatRows[0].seats.length">
|
||||
<td v-for="row in seatRows">
|
||||
<v-btn
|
||||
variant="text"
|
||||
icon="mdi-circle"
|
||||
:color="getSeatColor(seatGroup.surcharge, row.seats[i - 1].state)"
|
||||
:disabled="row.seats[i - 1].state == 1"
|
||||
density="compact"
|
||||
@click="() => !disabled ? handleSeatClick(row.seats[i - 1], row) : {}"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table v-else-if="structure == 2">
|
||||
<tbody>
|
||||
<tr v-for="i in seatRows.length">
|
||||
<td v-for="j in seatRows[i - 1].seats.length">
|
||||
<v-btn
|
||||
v-if="seatRows[i - 1].seats.length - i < j"
|
||||
variant="text"
|
||||
icon="mdi-circle"
|
||||
:color="getSeatColor(seatGroup.surcharge, seatRows[i - 1].seats[j - 1].state)"
|
||||
:disabled="seatRows[i - 1].seats[j - 1].state == 1"
|
||||
density="compact"
|
||||
@click="() => !disabled ? handleSeatClick(seatRows[i - 1].seats[j - 1], seatRows[i - 1]) : {}"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table v-else-if="structure == 3">
|
||||
<tbody>
|
||||
<tr v-for="i in seatRows.length">
|
||||
<td v-for="j in seatRows[i - 1].seats.length">
|
||||
<v-btn
|
||||
v-if="j >= i"
|
||||
variant="text"
|
||||
icon="mdi-circle"
|
||||
:color="getSeatColor(seatGroup.surcharge, seatRows[i - 1].seats[j - 1].state)"
|
||||
:disabled="seatRows[i - 1].seats[j - 1].state == 1"
|
||||
density="compact"
|
||||
@click="() => !disabled ? handleSeatClick(seatRows[i - 1].seats[j - 1], seatRows[i - 1]) : {}"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table v-else-if="structure == 4">
|
||||
<tbody>
|
||||
<tr v-for="i in seatRows.length">
|
||||
<td v-for="j in seatRows[i - 1].seats.length">
|
||||
<v-btn
|
||||
v-if="seatRows[i - 1].seats.length - i >= j - 1"
|
||||
variant="text"
|
||||
icon="mdi-circle"
|
||||
:color="getSeatColor(seatGroup.surcharge, seatRows[i - 1].seats[j - 1].state)"
|
||||
:disabled="seatRows[i - 1].seats[j - 1].state == 1"
|
||||
density="compact"
|
||||
@click="() => !disabled ? handleSeatClick(seatRows[i - 1].seats[j - 1], seatRows[i - 1]) : {}"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table v-else-if="structure == 5">
|
||||
<tbody>
|
||||
<tr v-for="i in seatRows.length">
|
||||
<td v-for="j in seatRows[i - 1].seats.length">
|
||||
<v-btn
|
||||
v-if="j <= i"
|
||||
variant="text"
|
||||
icon="mdi-circle"
|
||||
:color="getSeatColor(seatGroup.surcharge, seatRows[i - 1].seats[j - 1].state)"
|
||||
:disabled="seatRows[i - 1].seats[j - 1].state == 1"
|
||||
density="compact"
|
||||
@click="() => !disabled ? handleSeatClick(seatRows[i - 1].seats[j - 1], seatRows[i - 1]) : {}"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
150
src/components/seatPlanMap/seatPlanMap.vue
Normal file
150
src/components/seatPlanMap/seatPlanMap.vue
Normal file
@@ -0,0 +1,150 @@
|
||||
<script setup lang="ts">
|
||||
import { SeatGroupModel } from '@/data/models/locations/seatGroupModel';
|
||||
import seatGroupSheet from './seatGroupSheet.vue';
|
||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||
import { LocationModel } from '@/data/models/locations/locationModel';
|
||||
|
||||
let props = defineProps({
|
||||
location: LocationModel,
|
||||
seatGroups: {
|
||||
type: Array<SeatGroupModel>,
|
||||
required: true
|
||||
},
|
||||
concert: {
|
||||
type: ConcertModel,
|
||||
default: new ConcertModel()
|
||||
},
|
||||
disabled: Boolean
|
||||
})
|
||||
|
||||
function findSeatCategory(name: string): SeatGroupModel {
|
||||
return props.seatGroups.find(category =>
|
||||
category.name == name
|
||||
)
|
||||
}
|
||||
|
||||
const seatGroupA = findSeatCategory("A")
|
||||
const seatGroupB = findSeatCategory("B")
|
||||
const seatGroupC = findSeatCategory("C")
|
||||
const seatGroupD = findSeatCategory("D")
|
||||
const seatGroupE = findSeatCategory("E")
|
||||
const seatGroupF = findSeatCategory("F")
|
||||
const seatGroupG = findSeatCategory("G")
|
||||
const seatGroupH = findSeatCategory("H")
|
||||
const seatGroupI = findSeatCategory("I")
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-sheet border class="pa-5">
|
||||
<v-row>
|
||||
<!-- Seat Group C -->
|
||||
<v-col cols="4" class="pa-0">
|
||||
<seat-group-sheet
|
||||
:seat-group="seatGroupC"
|
||||
:concert="concert"
|
||||
background-color="grey"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<!-- Seat Group B -->
|
||||
<v-col cols="4" class="pa-0">
|
||||
<seat-group-sheet
|
||||
:seat-group="seatGroupB"
|
||||
:concert="concert"
|
||||
background-color="grey"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<!-- Seat Group I -->
|
||||
<v-col cols="4" class="pa-0">
|
||||
<seat-group-sheet
|
||||
:seat-group="seatGroupI"
|
||||
:concert="concert"
|
||||
background-color="grey"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<!-- Seat Group D -->
|
||||
<v-col cols="4" class="pa-0">
|
||||
<seat-group-sheet
|
||||
v-if="location.layout != 1"
|
||||
:seat-group="seatGroupD"
|
||||
:concert="concert"
|
||||
background-color="grey"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<!-- Seat Group A -->
|
||||
<v-col :cols="location.layout == 1 ? 10 : 4" class="pa-0">
|
||||
<seat-group-sheet
|
||||
:seat-group="seatGroupA"
|
||||
:concert="concert"
|
||||
background-color="grey"
|
||||
:withStage="location.layout == 3"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<!-- Stage of layout != 3 -->
|
||||
<v-col v-if="location.layout != 3">
|
||||
<v-sheet
|
||||
color="grey-darken-3"
|
||||
height="100%"
|
||||
width="50"
|
||||
class="px-5 py-2 d-flex justify-center align-center"
|
||||
>
|
||||
{{ $t('location.stage') }}
|
||||
</v-sheet>
|
||||
</v-col>
|
||||
|
||||
<!-- Seat Group H if layout == 3 -->
|
||||
<v-col v-else cols="4" class="pa-0">
|
||||
<seat-group-sheet
|
||||
:seat-group="seatGroupH"
|
||||
:concert="concert"
|
||||
background-color="grey"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
|
||||
<v-row v-if="location.layout != 1">
|
||||
<!-- Seat Group E -->
|
||||
<v-col cols="4" class="pa-0">
|
||||
<seat-group-sheet
|
||||
:seat-group="seatGroupE"
|
||||
:concert="concert"
|
||||
background-color="grey"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<!-- Seat Group F -->
|
||||
<v-col cols="4" class="pa-0">
|
||||
<seat-group-sheet
|
||||
:seat-group="seatGroupF"
|
||||
:concert="concert"
|
||||
background-color="grey"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
|
||||
<!-- Seat Group G -->
|
||||
<v-col cols="4" class="pa-0">
|
||||
<seat-group-sheet
|
||||
:seat-group="seatGroupG"
|
||||
:concert="concert"
|
||||
background-color="grey"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-sheet>
|
||||
</template>
|
||||
84
src/components/seatPlanMap/standingArea.vue
Normal file
84
src/components/seatPlanMap/standingArea.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<script setup lang="ts">
|
||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||
import { SeatGroupModel } from '@/data/models/locations/seatGroupModel';
|
||||
import { SelectedSeatModel } from '@/data/models/ordering/selectedSeatModel';
|
||||
import { useBasketStore } from '@/stores/basket.store';
|
||||
|
||||
const basketStore = useBasketStore()
|
||||
|
||||
let props = defineProps({
|
||||
seatGroup: SeatGroupModel,
|
||||
concert: ConcertModel,
|
||||
backgroundColor: String,
|
||||
withStage: Boolean,
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
function handleSeatClick() {
|
||||
let freeSeat = props.seatGroup.seatRows[0].seats.find(seat =>
|
||||
seat.state == 0
|
||||
)
|
||||
|
||||
freeSeat.state = 2
|
||||
|
||||
basketStore.selectedSeats.push(new SelectedSeatModel(freeSeat, 0, props.seatGroup.name, props.concert))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-hover>
|
||||
<template v-slot:default="{ isHovering, props}">
|
||||
<v-sheet
|
||||
v-bind="props"
|
||||
class="pa-5"
|
||||
min-height="200"
|
||||
height="100%"
|
||||
border
|
||||
:color="isHovering ? 'orange' : ''"
|
||||
@click="() => { !disabled ? handleSeatClick() : {} }"
|
||||
>
|
||||
<v-row class="d-flex justify-center align-center h-100">
|
||||
<v-col>
|
||||
<v-row>
|
||||
<v-spacer />
|
||||
|
||||
<v-col class="text-center" cols="6">
|
||||
<v-icon
|
||||
v-if="!withStage"
|
||||
icon="mdi-account-group"
|
||||
size="x-large"
|
||||
/>
|
||||
|
||||
<v-sheet
|
||||
v-else
|
||||
color="grey-darken-3"
|
||||
height="100"
|
||||
width="100%"
|
||||
|
||||
>
|
||||
{{ $t('location.stage') }}
|
||||
</v-sheet>
|
||||
</v-col>
|
||||
|
||||
<v-spacer />
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col class="text-center text-h6">
|
||||
{{ seatGroup.occupied != undefined
|
||||
? seatGroup.capacity - seatGroup.occupied
|
||||
: seatGroup.capacity
|
||||
}}
|
||||
{{ $t('location.seat.standingPlace', 2) }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-sheet>
|
||||
</template>
|
||||
</v-hover>
|
||||
</template>
|
||||
Reference in New Issue
Block a user