Streamlined stores

This commit is contained in:
2024-10-22 18:47:27 +02:00
parent 3e53a606a6
commit 4e6be355ea
45 changed files with 384 additions and 387 deletions

View File

@@ -7,6 +7,7 @@ import { SeatRow } from "../models/locations/seatRow.model";
import { Seat } from "../models/locations/seat.model"; import { Seat } from "../models/locations/seat.model";
import { Ticket } from "../models/ordering/ticket.model"; import { Ticket } from "../models/ordering/ticket.model";
import { Band } from "../models/acts/band.model"; import { Band } from "../models/acts/band.model";
import { Op } from "sequelize";
export const concert = Router() export const concert = Router()
@@ -95,3 +96,19 @@ concert.get("/concert/:id", (req: Request, res: Response) => {
res.status(200).json(concert) res.status(200).json(concert)
}) })
}) })
// Concert search
concert.get("/search", (req: Request, res: Response) => {
Concert.findAll({
where: {
name: {
[Op.substring]: req.query.value
}
},
include: [ Band, Location ]
})
.then(concerts => {
res.status(200).json(concerts)
})
})

View File

@@ -93,13 +93,23 @@ location.get("/location/:urlName", (req: Request, res: Response) => {
location.get("/search", (req: Request, res: Response) => { location.get("/search", (req: Request, res: Response) => {
Location.findAll({ Location.findAll({
where: { where: {
[Op.or]: [
{
name: { name: {
[Op.substring]: req.query.value [Op.substring]: req.query.value
}
}, },
include: [ Concert ] },
{
"$city.name$": {
[Op.substring]: req.query.value
}
}
]
},
include: [ City, Concert ]
}) })
.then(locations => { .then(locations => {
console.log(locations)
res.status(200).json(locations) res.status(200).json(locations)
}) })
}) })

View File

@@ -4,8 +4,8 @@ import { i18n } from './plugins/i18n';
import { watch } from 'vue'; import { watch } from 'vue';
import navigationAppendItems from './components/navigation/navigationAppendItems.vue'; import navigationAppendItems from './components/navigation/navigationAppendItems.vue';
import navigationPrependItems from './components/navigation/navigationPrependItems.vue'; import navigationPrependItems from './components/navigation/navigationPrependItems.vue';
import { usePreferencesStore } from './stores/preferencesStore'; import { usePreferencesStore } from './stores/preferences.store';
import { useFeedbackStore } from './stores/feedbackStore'; import { useFeedbackStore } from './stores/feedback.store';
import footerItems from './components/navigation/footerItems.vue'; import footerItems from './components/navigation/footerItems.vue';
import urlBar from './components/navigation/urlBar.vue'; import urlBar from './components/navigation/urlBar.vue';

View File

@@ -6,10 +6,10 @@ export async function fetchAllBands() {
return await axios.get(BASE_URL) return await axios.get(BASE_URL)
} }
export async function getBand(bandName: string) { export async function fetchBandByName(bandName: string) {
return await axios.get(BASE_URL + '/band/' + bandName) return await axios.get(BASE_URL + '/band/' + bandName)
} }
export async function searchBand(searchTerm: string) { export async function fetchBandsBySearchTerm(searchTerm: string) {
return await axios.get(BASE_URL + '/search?value=' + searchTerm) return await axios.get(BASE_URL + '/search?value=' + searchTerm)
} }

View File

@@ -2,13 +2,6 @@ import axios from "axios"
const BASE_URL = "http://localhost:3000/cities" const BASE_URL = "http://localhost:3000/cities"
/**
* @deprecated Use fetchAllCities
*/
export async function getAllCities() {
return await axios.get(BASE_URL)
}
export async function fetchAllCities() { export async function fetchAllCities() {
return await axios.get(BASE_URL) return await axios.get(BASE_URL)
} }

View File

@@ -2,11 +2,11 @@ import axios from "axios"
let BASE_URL = "http://localhost:3000/concerts" let BASE_URL = "http://localhost:3000/concerts"
export async function fetchConcerts() { export async function fetchAllConcerts() {
return await axios.get(BASE_URL) return await axios.get(BASE_URL)
} }
export async function fetchConcert(id: number) { export async function fetchConcertById(id: number) {
if (id != undefined) { if (id != undefined) {
return await axios.get(BASE_URL + "/concert/" + id) return await axios.get(BASE_URL + "/concert/" + id)
} else { } else {
@@ -27,6 +27,6 @@ export async function fetchUpcomingConcerts(nrOfConcerts: number) {
return await axios.get(url) return await axios.get(url)
} }
export async function searchConcert(searchTerm: string) { export async function fetchConcertsBySearchTerm(searchTerm: string) {
return await axios.get(BASE_URL + '/search?value=' + searchTerm) return await axios.get(BASE_URL + '/search?value=' + searchTerm)
} }

View File

@@ -2,13 +2,6 @@ import axios from "axios"
let BASE_URL = "http://localhost:3000/genres" let BASE_URL = "http://localhost:3000/genres"
/**
* @deprecated Use fetchAllGenres()
*/
export async function getAllGenres() {
return await axios.get(BASE_URL)
}
export async function fetchAllGenres() { export async function fetchAllGenres() {
return await axios.get(BASE_URL) return await axios.get(BASE_URL)
} }

View File

@@ -6,7 +6,7 @@ export async function fetchAllLocations() {
return await axios.get(BASE_URL) return await axios.get(BASE_URL)
} }
export async function getLocation(locationName: string) { export async function fetchLocationByName(locationName: string) {
return await axios.get(BASE_URL + "/location/" + locationName) return await axios.get(BASE_URL + "/location/" + locationName)
} }
@@ -16,6 +16,6 @@ export async function fetchTopLocations(nrOfLocations: number) {
return await axios.get(url) return await axios.get(url)
} }
export async function searchLocation(searchTerm: string) { export async function fetchLocationsBySearchTerm(searchTerm: string) {
return await axios.get(BASE_URL + "/search?value=" + searchTerm) return await axios.get(BASE_URL + "/search?value=" + searchTerm)
} }

View File

@@ -2,9 +2,8 @@ import axios from "axios"
const BASE_URL = "http://localhost:3000/api" const BASE_URL = "http://localhost:3000/api"
export function getServerState() { export function fetchServerState() {
return axios.get(BASE_URL) return axios.get(BASE_URL)
} }
export function resetDatabase() { export function resetDatabase() {

View File

@@ -3,7 +3,7 @@ import { BasketItemModel } from "../models/ordering/basketItemModel"
const BASE_URL = "http://localhost:3000/orders" const BASE_URL = "http://localhost:3000/orders"
export async function getUserOrders(userId: number) { export async function fetchUserOrders(userId: number) {
return axios.get(BASE_URL + "/" + userId) return axios.get(BASE_URL + "/" + userId)
} }
@@ -25,8 +25,6 @@ export async function createOrder(
} }
} }
console.log(tickets)
return axios.post(BASE_URL, { return axios.post(BASE_URL, {
accountId: accountId, accountId: accountId,
tickets: tickets, tickets: tickets,

View File

@@ -5,7 +5,7 @@ import vuetify from './plugins/vuetify'
import router from './plugins/router' import router from './plugins/router'
import pinia from './plugins/pinia' import pinia from './plugins/pinia'
import { i18n } from './plugins/i18n' import { i18n } from './plugins/i18n'
import { useFeedbackStore } from './stores/feedbackStore' import { useFeedbackStore } from './stores/feedback.store'
createApp(App) createApp(App)
.use(vuetify) .use(vuetify)

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import cardView from '@/components/basics/cardView.vue'; import cardView from '@/components/basics/cardView.vue';
import { useAccountStore } from '@/stores/account.store'; import { useAccountStore } from '@/stores/account.store';
import { useFeedbackStore } from '@/stores/feedbackStore'; import { useFeedbackStore } from '@/stores/feedback.store';
const accountStore = useAccountStore() const accountStore = useAccountStore()
const feedbackStore = useFeedbackStore() const feedbackStore = useFeedbackStore()

View File

@@ -6,20 +6,7 @@ import { useAccountStore } from '@/stores/account.store';
import { ref } from 'vue'; import { ref } from 'vue';
const showConfirmDialog = ref(false) const showConfirmDialog = ref(false)
const updateInProgress = ref(false)
const accountStore = useAccountStore() const accountStore = useAccountStore()
function deleteAccount() {
// todo
}
async function updateAccount() {
updateInProgress.value = true
await accountStore.updateAccount()
updateInProgress.value = false
}
</script> </script>
<template> <template>
@@ -32,6 +19,7 @@ async function updateAccount() {
<outlined-button <outlined-button
prepend-icon="mdi-delete" prepend-icon="mdi-delete"
color="red" color="red"
:loading="accountStore.fetchInProgress"
@click="showConfirmDialog = true" @click="showConfirmDialog = true"
> >
{{ $t("account.delete") }} {{ $t("account.delete") }}
@@ -42,7 +30,8 @@ async function updateAccount() {
<outlined-button <outlined-button
prepend-icon="mdi-content-save" prepend-icon="mdi-content-save"
color="green" color="green"
@click="updateAccount" :loading="accountStore.fetchInProgress"
@click="accountStore.updateAccount()"
> >
{{ $t("save") }} {{ $t("save") }}
</outlined-button> </outlined-button>
@@ -54,6 +43,6 @@ async function updateAccount() {
v-model="showConfirmDialog" v-model="showConfirmDialog"
:title="$t('dialog.deleteAccount.title')" :title="$t('dialog.deleteAccount.title')"
:description="$t('dialog.deleteAccount.description')" :description="$t('dialog.deleteAccount.description')"
:onConfirm="deleteAccount"
/> />
<!-- todo :onConfirm="deleteAccount" -->
</template> </template>

View File

@@ -1,5 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue';
import cardView from '@/components/basics/cardView.vue'; import cardView from '@/components/basics/cardView.vue';
import outlinedButton from '@/components/basics/outlinedButton.vue'; import outlinedButton from '@/components/basics/outlinedButton.vue';
import { useAccountStore } from '@/stores/account.store'; import { useAccountStore } from '@/stores/account.store';
@@ -7,37 +6,15 @@ import { useRouter } from 'vue-router';
const accountStore = useAccountStore() const accountStore = useAccountStore()
const showRegisterCard = defineModel("showRegisterCard", { type: Boolean, default: false }) const showRegisterCard = defineModel("showRegisterCard", { type: Boolean, default: false })
const loginInProgress = ref(false)
const username = ref("duranduran")
const password = ref("H4nn0ver")
const usernameWrong = ref(false)
const passwordWrong = ref(false)
const router = useRouter() const router = useRouter()
async function startLogin() { async function startLogin() {
loginInProgress.value = true accountStore.login()
usernameWrong.value = false .then(result => {
passwordWrong.value = false
if (username.value == null || username.value.length == 0) {
usernameWrong.value = true
}
if (password.value == null || password.value.length == 0) {
passwordWrong.value = true
}
if (username.value != null && username.value.length > 0 &&
password.value != null && password.value.length > 0)
{
await accountStore.login(username.value, password.value)
if (accountStore.userAccount.id != undefined) { if (accountStore.userAccount.id != undefined) {
router.push("/account/home") router.push("/account/home")
} }
} })
loginInProgress.value = false
} }
</script> </script>
@@ -52,8 +29,7 @@ async function startLogin() {
<v-text-field <v-text-field
:label="$t('account.username')" :label="$t('account.username')"
prepend-icon="mdi-account" prepend-icon="mdi-account"
v-model="username" v-model="accountStore.loginData.username"
:error="usernameWrong"
clearable clearable
/> />
</v-col> </v-col>
@@ -65,8 +41,7 @@ async function startLogin() {
:label="$t('account.password')" :label="$t('account.password')"
prepend-icon="mdi-key" prepend-icon="mdi-key"
type="password" type="password"
v-model="password" v-model="accountStore.loginData.password"
:error="passwordWrong"
clearable clearable
/> />
</v-col> </v-col>
@@ -76,7 +51,7 @@ async function startLogin() {
<outlined-button <outlined-button
@click="showRegisterCard = true" @click="showRegisterCard = true"
prepend-icon="mdi-plus" prepend-icon="mdi-plus"
:disabled="loginInProgress" :loading="accountStore.fetchInProgress"
> >
{{ $t('account.noAccountRegister') }} {{ $t('account.noAccountRegister') }}
</outlined-button> </outlined-button>
@@ -84,7 +59,7 @@ async function startLogin() {
<outlined-button <outlined-button
append-icon="mdi-arrow-right" append-icon="mdi-arrow-right"
@click="startLogin" @click="startLogin"
:loading="loginInProgress" :loading="accountStore.fetchInProgress"
> >
{{ $t('login') }} {{ $t('login') }}
</outlined-button> </outlined-button>

View File

@@ -1,21 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import { AccountModel } from '@/data/models/user/accountModel';
import { ref } from 'vue';
import cardView from '@/components/basics/cardView.vue'; import cardView from '@/components/basics/cardView.vue';
import outlinedButton from '@/components/basics/outlinedButton.vue'; import outlinedButton from '@/components/basics/outlinedButton.vue';
import { useAccountStore } from '@/stores/account.store'; import { useAccountStore } from '@/stores/account.store';
import { getEmailRules, getPasswordRules, getStringRules } from '@/scripts/validationRules'; import { getEmailRules, getPasswordRules, getStringRules } from '@/scripts/validationRules';
import { useRouter } from 'vue-router';
const newUser = ref(new AccountModel())
const showRegisterCard = defineModel("showRegisterCard", { type: Boolean, default: false }) const showRegisterCard = defineModel("showRegisterCard", { type: Boolean, default: false })
const accountStore = useAccountStore() const accountStore = useAccountStore()
const registerInProgress = ref(false) const router = useRouter()
async function registerAccount() { async function registerAccount() {
registerInProgress.value = true accountStore.registerAccount()
.then(result => {
await accountStore.registerAccount(newUser.value) if (result) {
registerInProgress.value = false router.push("/account/home")
}
})
} }
</script> </script>
@@ -29,7 +29,7 @@ async function registerAccount() {
<v-text-field <v-text-field
:label="$t('account.username')" :label="$t('account.username')"
prepend-icon="mdi-account" prepend-icon="mdi-account"
v-model="newUser.username" v-model="accountStore.registerData.username"
clearable clearable
:rules="getStringRules()" :rules="getStringRules()"
/> />
@@ -42,7 +42,7 @@ async function registerAccount() {
:label="$t('account.password')" :label="$t('account.password')"
prepend-icon="mdi-key" prepend-icon="mdi-key"
type="password" type="password"
v-model="newUser.password" v-model="accountStore.registerData.password"
clearable clearable
:rules="getPasswordRules()" :rules="getPasswordRules()"
/> />
@@ -54,7 +54,7 @@ async function registerAccount() {
<v-text-field <v-text-field
:label="$t('account.email')" :label="$t('account.email')"
prepend-icon="mdi-mail" prepend-icon="mdi-mail"
v-model="newUser.email" v-model="accountStore.registerData.email"
:rules="getEmailRules()" :rules="getEmailRules()"
clearable clearable
/> />
@@ -65,7 +65,7 @@ async function registerAccount() {
<outlined-button <outlined-button
prepend-icon="mdi-arrow-left" prepend-icon="mdi-arrow-left"
@click="showRegisterCard = false" @click="showRegisterCard = false"
:disabled="registerInProgress" :disabled="accountStore.fetchInProgress"
> >
{{ $t('account.backToLogin') }} {{ $t('account.backToLogin') }}
</outlined-button> </outlined-button>
@@ -73,7 +73,7 @@ async function registerAccount() {
<outlined-button <outlined-button
prepend-icon="mdi-account-plus" prepend-icon="mdi-account-plus"
@click="registerAccount" @click="registerAccount"
:loading="registerInProgress" :loading="accountStore.fetchInProgress"
> >
{{ $t('account.register') }} {{ $t('account.register') }}
</outlined-button> </outlined-button>

View File

@@ -1,9 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import cardWithTopImage from '@/components/basics/cardViewTopImage.vue'; import cardWithTopImage from '@/components/basics/cardViewTopImage.vue';
import { useFeedbackStore } from '@/stores/feedbackStore';
import { BandApiModel } from '@/data/models/acts/bandApiModel'; import { BandApiModel } from '@/data/models/acts/bandApiModel';
import { useBandStore } from '@/stores/band.store';
const feedbackStore = useFeedbackStore() const bandStore = useBandStore()
defineProps({ defineProps({
band: { band: {
@@ -14,7 +14,7 @@ defineProps({
</script> </script>
<template> <template>
<v-row v-if="feedbackStore.fetchDataFromServerInProgress" > <v-row v-if="bandStore.fetchInProgress" >
<v-col cols="3" v-for="i in 4"> <v-col cols="3" v-for="i in 4">
<card-with-top-image :loading="true" /> <card-with-top-image :loading="true" />
</v-col> </v-col>

View File

@@ -3,7 +3,7 @@ import concertListItem from '@/components/pageParts/concertListItem.vue';
import { BandApiModel } from '@/data/models/acts/bandApiModel'; import { BandApiModel } from '@/data/models/acts/bandApiModel';
import { ConcertApiModel } from '@/data/models/acts/concertApiModel'; import { ConcertApiModel } from '@/data/models/acts/concertApiModel';
import CardViewHorizontal from '@/components/basics/cardViewHorizontal.vue'; import CardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
import { useConcertStore } from '@/stores/concertStore'; import { useConcertStore } from '@/stores/concert.store';
const concertStore = useConcertStore() const concertStore = useConcertStore()

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { BandModel } from '@/data/models/acts/bandModel'; import { BandModel } from '@/data/models/acts/bandModel';
import { useBandStore } from '@/stores/bandStore'; import { useBandStore } from '@/stores/band.store';
const bandStore = useBandStore() const bandStore = useBandStore()

View File

@@ -6,7 +6,7 @@ import gallerySection from './gallerySection.vue';
import concertSection from './concertSection.vue'; import concertSection from './concertSection.vue';
import heroImage from '@/components/pageParts/heroImage.vue'; import heroImage from '@/components/pageParts/heroImage.vue';
import sectionDivider from '@/components/basics/sectionDivider.vue'; import sectionDivider from '@/components/basics/sectionDivider.vue';
import { useBandStore } from '@/stores/bandStore'; import { useBandStore } from '@/stores/band.store';
const router = useRouter() const router = useRouter()
const bandStore = useBandStore() const bandStore = useBandStore()

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { useBandStore } from '@/stores/bandStore'; import { useBandStore } from '@/stores/band.store';
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue'; import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
import bandListItem from '@/components/pageParts/bandListItem.vue'; import bandListItem from '@/components/pageParts/bandListItem.vue';

View File

@@ -5,7 +5,7 @@ import sectionDivider from '@/components/basics/sectionDivider.vue';
import { useBasketStore } from '@/stores/basket.store'; import { useBasketStore } from '@/stores/basket.store';
import concertListItem from '@/components/pageParts/concertListItem.vue'; import concertListItem from '@/components/pageParts/concertListItem.vue';
import outlinedButton from '@/components/basics/outlinedButton.vue'; import outlinedButton from '@/components/basics/outlinedButton.vue';
import { useConcertStore } from '@/stores/concertStore'; import { useConcertStore } from '@/stores/concert.store';
const router = useRouter() const router = useRouter()
const basketStore = useBasketStore() const basketStore = useBasketStore()
@@ -93,7 +93,7 @@ concertStore.getConcert(Number(router.currentRoute.value.params.id))
<v-row class="pb-5"> <v-row class="pb-5">
<outlined-button todo <outlined-button todo
prepend-icon="mdi-basket-plus" prepend-icon="mdi-basket-plus"
@click="basketStore.moveSeatSelectionsToBasket(concertStore.concert, concertStore.concert.band); @click="basketStore.moveSeatSelectionsToBasket(concertStore.concert.band);
router.push('/basket')" router.push('/basket')"
:disabled="basketStore.selectedSeats.length == 0" :disabled="basketStore.selectedSeats.length == 0"
block block

View File

@@ -1,5 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { useConcertStore } from '@/stores/concertStore'; import { useConcertStore } from '@/stores/concert.store';
import concertListItem from '@/components/pageParts/concertListItem.vue'; import concertListItem from '@/components/pageParts/concertListItem.vue';
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue'; import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
import sectionDivider from '@/components/basics/sectionDivider.vue'; import sectionDivider from '@/components/basics/sectionDivider.vue';

View File

@@ -1,12 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import OutlinedButton from '@/components/basics/outlinedButton.vue'; import OutlinedButton from '@/components/basics/outlinedButton.vue';
import { useShoppingStore } from '@/stores/shoppingStore';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
const shoppingStore = useShoppingStore()
const router = useRouter() const router = useRouter()
shoppingStore.getEvents()
</script> </script>
<template> <template>

View File

@@ -2,12 +2,11 @@
import highlightCarousel from './highlightCarousel.vue'; import highlightCarousel from './highlightCarousel.vue';
import sectionDivider from '@/components/basics/sectionDivider.vue'; import sectionDivider from '@/components/basics/sectionDivider.vue';
import cardWithTopImage from '@/components/basics/cardViewTopImage.vue'; import cardWithTopImage from '@/components/basics/cardViewTopImage.vue';
import { lowestTicketPrice } from '@/scripts/concertScripts';
import OutlinedButton from '@/components/basics/outlinedButton.vue'; import OutlinedButton from '@/components/basics/outlinedButton.vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useConcertStore } from '@/stores/concertStore'; import { useConcertStore } from '@/stores/concert.store';
import { useLocationStore } from '@/stores/locationStore'; import { useLocationStore } from '@/stores/location.store';
import { useBandStore } from '@/stores/bandStore'; import { useBandStore } from '@/stores/band.store';
const router = useRouter() const router = useRouter()
const concertStore = useConcertStore() const concertStore = useConcertStore()

View File

@@ -2,38 +2,30 @@
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import sectionDivider from '@/components/basics/sectionDivider.vue'; import sectionDivider from '@/components/basics/sectionDivider.vue';
import seatPlanMap from '@/components/seatPlanMap/seatPlanMap.vue'; import seatPlanMap from '@/components/seatPlanMap/seatPlanMap.vue';
import { getLocation } from '@/data/api/locationApi';
import { ref } from 'vue'; import { ref } from 'vue';
import { useFeedbackStore } from '@/stores/feedbackStore';
import heroImage from '@/components/pageParts/heroImage.vue'; import heroImage from '@/components/pageParts/heroImage.vue';
import concertListItem from '@/components/pageParts/concertListItem.vue'; import concertListItem from '@/components/pageParts/concertListItem.vue';
import { LocationDetailsApiModel } from '@/data/models/locations/locationDetailsApiModel'; import { LocationDetailsApiModel } from '@/data/models/locations/locationDetailsApiModel';
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue'; import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
import { useLocationStore } from '@/stores/location.store';
const router = useRouter() const router = useRouter()
const feedbackStore = useFeedbackStore() const locationStore = useLocationStore()
const location = ref<LocationDetailsApiModel>(new LocationDetailsApiModel())
feedbackStore.fetchDataFromServerInProgress = true locationStore.getLocationByName(String(router.currentRoute.value.params.name))
getLocation(String(router.currentRoute.value.params.name))
.then(result => {
location.value = result.data
feedbackStore.fetchDataFromServerInProgress = false
})
</script> </script>
<template> <template>
<hero-image <hero-image
:title="location.name" :title="locationStore.location.name"
:image="location.imageIndoor" :image="locationStore.location.imageIndoor"
:description="location.address + location.city.name" :description="locationStore.location.address + locationStore.location.city.name"
:loading="feedbackStore.fetchDataFromServerInProgress" :loading="locationStore.fetchInProgress"
:logo="location.imageOutdoor" :logo="locationStore.location.imageOutdoor"
> >
<template #description> <template #description>
<p class="text-h6">{{ location.address }}</p> <p class="text-h6">{{ locationStore.location.address }}</p>
<p class="text-h6">{{ location.city.name }}</p> <p class="text-h6">{{ locationStore.location.city.name }}</p>
</template> </template>
</hero-image> </hero-image>
@@ -48,21 +40,21 @@ getLocation(String(router.currentRoute.value.params.name))
</v-col> </v-col>
</v-row> </v-row>
<v-row v-if="feedbackStore.fetchDataFromServerInProgress" v-for="i in 3"> <v-row v-if="locationStore.fetchInProgress" v-for="i in 3">
<v-col class="text-center"> <v-col class="text-center">
<card-view-horizontal :loading="true" /> <card-view-horizontal :loading="true" />
</v-col> </v-col>
</v-row> </v-row>
<v-row <v-row
v-else-if="location.concerts.length > 0" v-else-if="locationStore.location.concerts.length > 0"
v-for="concert of location.concerts" v-for="concert of locationStore.location.concerts"
> >
<v-col> <v-col>
<concert-list-item <concert-list-item
:concert="concert" :concert="concert"
:band="concert.band" :band="concert.band"
:location="location" :location="locationStore.location"
:title="concert.name" :title="concert.name"
> >
<template #description> <template #description>
@@ -88,7 +80,7 @@ getLocation(String(router.currentRoute.value.params.name))
</v-col> </v-col>
</v-row> </v-row>
<div v-if="feedbackStore.fetchDataFromServerInProgress"> <div v-if="locationStore.fetchInProgress">
<v-col class="text-center"> <v-col class="text-center">
<v-progress-circular indeterminate :size="128" :width="12" color="primary" /> <v-progress-circular indeterminate :size="128" :width="12" color="primary" />
</v-col> </v-col>
@@ -97,8 +89,8 @@ getLocation(String(router.currentRoute.value.params.name))
<v-row v-else> <v-row v-else>
<v-col> <v-col>
<seat-plan-map <seat-plan-map
:location="location" :location="locationStore.location"
:seat-groups="location.seatGroups" :seat-groups="locationStore.location.seatGroups"
/> />
</v-col> </v-col>
</v-row> </v-row>

View File

@@ -1,12 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import sectionDivider from '@/components/basics/sectionDivider.vue'; import sectionDivider from '@/components/basics/sectionDivider.vue';
import cardWithTopImage from '@/components/basics/cardViewTopImage.vue'; import cardWithTopImage from '@/components/basics/cardViewTopImage.vue';
import { useFeedbackStore } from '@/stores/feedbackStore';
import locationListItem from '@/components/pageParts/locationListItem.vue'; import locationListItem from '@/components/pageParts/locationListItem.vue';
import { useLocationStore } from '@/stores/locationStore'; import { useLocationStore } from '@/stores/location.store';
const locationStore = useLocationStore() const locationStore = useLocationStore()
const feedbackStore = useFeedbackStore()
locationStore.getLocations() locationStore.getLocations()
</script> </script>
@@ -21,7 +19,7 @@ locationStore.getLocations()
<v-col cols="10"> <v-col cols="10">
<!-- During fetching --> <!-- During fetching -->
<div v-if="feedbackStore.fetchDataFromServerInProgress" v-for="i in 2"> <div v-if="locationStore.fetchInProgress" v-for="i in 2">
<v-row> <v-row>
<v-col> <v-col>
<section-divider :loading="true" /> <section-divider :loading="true" />

View File

@@ -26,7 +26,6 @@ async function doOrder() {
} }
if (basketStore.usedAddress != null && basketStore.usedPayment != null) { if (basketStore.usedAddress != null && basketStore.usedPayment != null) {
await basketStore.takeOrder() await basketStore.takeOrder()
showDialog.value = false showDialog.value = false
} }

View File

@@ -2,24 +2,21 @@
import { getAllExerciseGroups } from '@/data/api/exerciseApi'; import { getAllExerciseGroups } from '@/data/api/exerciseApi';
import scoreCard from './scoreCard.vue'; import scoreCard from './scoreCard.vue';
import { ref } from 'vue'; import { ref } from 'vue';
import { useFeedbackStore } from '@/stores/feedbackStore';
import { ExerciseGroupApiModel } from '@/data/models/exercises/exerciseGroupApiModel'; import { ExerciseGroupApiModel } from '@/data/models/exercises/exerciseGroupApiModel';
import { usePreferencesStore } from '@/stores/preferences.store';
const exerciseGroups = ref<Array<ExerciseGroupApiModel>>([]) const exerciseGroups = ref<Array<ExerciseGroupApiModel>>([])
const feedbackStore = useFeedbackStore() const preferencesStore = usePreferencesStore()
feedbackStore.fetchDataFromServerInProgress = true
getAllExerciseGroups() getAllExerciseGroups()
.then(result => { .then(result => {
exerciseGroups.value = result.data exerciseGroups.value = result.data
feedbackStore.fetchDataFromServerInProgress = false
}) })
</script> </script>
<template> <template>
<v-container max-width="1000"> <v-container max-width="1000">
<v-row v-if="feedbackStore.fetchDataFromServerInProgress" v-for="i in 3"> <v-row v-if="preferencesStore.fetchInProgress" v-for="i in 3">
<v-col> <v-col>
<score-card :loading="true" <score-card :loading="true"
/> />

View File

@@ -3,7 +3,7 @@ import { ThemeEnum } from '@/data/enums/themeEnums';
import { useTheme } from 'vuetify/lib/framework.mjs'; import { useTheme } from 'vuetify/lib/framework.mjs';
import { i18n } from '@/plugins/i18n'; import { i18n } from '@/plugins/i18n';
import cardView from '@/components/basics/cardView.vue'; import cardView from '@/components/basics/cardView.vue';
import { usePreferencesStore } from '@/stores/preferencesStore'; import { usePreferencesStore } from '@/stores/preferences.store';
const preferencesStore = usePreferencesStore() const preferencesStore = usePreferencesStore()
const theme = useTheme() const theme = useTheme()

View File

@@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import { BannerStateEnum } from '@/data/enums/bannerStateEnum'; import { BannerStateEnum } from '@/data/enums/bannerStateEnum';
import { useFeedbackStore } from '@/stores/feedbackStore'; import { useFeedbackStore } from '@/stores/feedback.store';
import cardView from '@/components/basics/cardView.vue'; import cardView from '@/components/basics/cardView.vue';
import outlinedButton from '@/components/basics/outlinedButton.vue'; import outlinedButton from '@/components/basics/outlinedButton.vue';
import { ref } from 'vue'; import { ref } from 'vue';
import confirmDialog from '@/components/basics/confirmDialog.vue'; import confirmDialog from '@/components/basics/confirmDialog.vue';
import { getServerState, resetDatabase, resetExerciseProgress } from '@/data/api/mainApi'; import { fetchServerState, resetDatabase, resetExerciseProgress } from '@/data/api/mainApi';
import { ServerStateEnum } from '@/data/enums/serverStateEnum'; import { ServerStateEnum } from '@/data/enums/serverStateEnum';
import packageJson from './../../../../package.json' import packageJson from './../../../../package.json'
@@ -14,7 +14,7 @@ const showConfirmDeleteDbDialog = ref(false)
const showConfirmDeleteExerciseProgressDialog = ref(false) const showConfirmDeleteExerciseProgressDialog = ref(false)
const serverOnline = ref(ServerStateEnum.PENDING) const serverOnline = ref(ServerStateEnum.PENDING)
getServerState() fetchServerState()
.then(result => { .then(result => {
if (result.status == 200) { if (result.status == 200) {
serverOnline.value = ServerStateEnum.ONLINE serverOnline.value = ServerStateEnum.ONLINE

View File

@@ -5,7 +5,8 @@ import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
import locationListItem from '@/components/pageParts/locationListItem.vue'; import locationListItem from '@/components/pageParts/locationListItem.vue';
import cardViewTopImage from '@/components/basics/cardViewTopImage.vue'; import cardViewTopImage from '@/components/basics/cardViewTopImage.vue';
import bandListItem from '@/components/pageParts/bandListItem.vue'; import bandListItem from '@/components/pageParts/bandListItem.vue';
import { useSearchStore } from '@/stores/searchStore'; import { useSearchStore } from '@/stores/search.store';
import ConcertListItem from '@/components/pageParts/concertListItem.vue';
const searchStore = useSearchStore() const searchStore = useSearchStore()
</script> </script>
@@ -30,7 +31,7 @@ const searchStore = useSearchStore()
</v-row> </v-row>
<v-row <v-row
v-if="searchStore.searchInProgress" v-if="searchStore.fetchInProgress"
v-for="i in 2" v-for="i in 2"
> >
<v-col> <v-col>
@@ -46,7 +47,7 @@ const searchStore = useSearchStore()
:band="band" :band="band"
:concerts="band.concerts" :concerts="band.concerts"
:genres="band.genres" :genres="band.genres"
:loading="searchStore.searchInProgress" :loading="searchStore.fetchInProgress"
/> />
</v-col> </v-col>
</v-row> </v-row>
@@ -62,6 +63,46 @@ const searchStore = useSearchStore()
<!-- Section Concert results -->
<v-row>
<v-col>
<section-divider :title="$t('event', 2)" />
</v-col>
</v-row>
<v-row
v-if="searchStore.fetchInProgress"
v-for="i in 2"
>
<v-col>
<card-view-horizontal :loading="true" />
</v-col>
</v-row>
<v-row
v-else-if="searchStore.concerts.length > 0"
v-for="concert in searchStore.concerts"
>
<v-col>
<concert-list-item
:concert="concert"
:band="concert.band"
:location="concert.location"
/>
</v-col>
</v-row>
<v-row v-else >
<v-col>
<v-empty-state
:title="$t('noEventsFound')"
icon="mdi-party-popper"
/>
</v-col>
</v-row>
<!-- Section Location results --> <!-- Section Location results -->
<v-row> <v-row>
<v-col> <v-col>
@@ -70,7 +111,7 @@ const searchStore = useSearchStore()
</v-row> </v-row>
<v-row <v-row
v-if="searchStore.searchInProgress" v-if="searchStore.fetchInProgress"
> >
<v-col v-for="i in 4"> <v-col v-for="i in 4">
<card-view-top-image :loading="true" /> <card-view-top-image :loading="true" />
@@ -82,11 +123,11 @@ const searchStore = useSearchStore()
> >
<v-col <v-col
cols="3" cols="3"
v-for="locaiton in searchStore.locations" v-for="location in searchStore.locations"
> >
<location-list-item <location-list-item
:location="locaiton" :location="location"
:concerts="locaiton.concerts" :nr-of-concerts="location.concerts.length"
/> />
</v-col> </v-col>
</v-row> </v-row>
@@ -99,49 +140,7 @@ const searchStore = useSearchStore()
/> />
</v-col> </v-col>
</v-row> </v-row>
<!-- Section Event results -->
<v-row>
<v-col>
<section-divider :title="$t('event', 2)" />
</v-col>
</v-row>
<v-row
v-if="searchStore.searchInProgress"
v-for="i in 2"
>
<v-col>
<card-view-horizontal :loading="true" />
</v-col>
</v-row>
<!-- <v-row
v-else-if="searchStore.events.length > 0"
v-for="event in searchStore.events"
>
<v-col>
<event-list-item
:event="event"
:band="event.band"
:concerts="event.concerts"
:loading="searchStore.searchInProgress"
/>
</v-col>
</v-row> -->
<v-row v-else >
<v-col>
<v-empty-state
:title="$t('noEventsFound')"
icon="mdi-party-popper"
/>
</v-col>
</v-row>
</div> </div>
</v-col> </v-col>
<v-spacer /> <v-spacer />

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import cardView from '@/components/basics/cardView.vue'; import cardView from '@/components/basics/cardView.vue';
import { useSearchStore } from '@/stores/searchStore'; import { useSearchStore } from '@/stores/search.store';
const searchStore = useSearchStore() const searchStore = useSearchStore()
</script> </script>

View File

@@ -1,4 +1,4 @@
import { useFeedbackStore } from "@/stores/feedbackStore" import { useFeedbackStore } from "@/stores/feedback.store"
/** /**
* Check a string for no numbers and more than four digits * Check a string for no numbers and more than four digits

View File

@@ -2,9 +2,9 @@ import { useLocalStorage } from "@vueuse/core";
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { AccountModel } from "../data/models/user/accountModel"; import { AccountModel } from "../data/models/user/accountModel";
import { OrderModel } from "../data/models/ordering/orderModel"; import { OrderModel } from "../data/models/ordering/orderModel";
import { useFeedbackStore } from "./feedbackStore"; import { useFeedbackStore } from "./feedback.store";
import { loginAccount, registerAccount, updateAccount } from "../data/api/accountApi"; import { loginAccount, registerAccount, updateAccount } from "../data/api/accountApi";
import { getUserOrders } from "../data/api/orderApi"; import { fetchUserOrders } from "../data/api/orderApi";
import { BannerStateEnum } from "../data/enums/bannerStateEnum"; import { BannerStateEnum } from "../data/enums/bannerStateEnum";
import { AddressModel } from "../data/models/user/addressModel"; import { AddressModel } from "../data/models/user/addressModel";
import { PaymentModel } from "../data/models/user/paymentModel"; import { PaymentModel } from "../data/models/user/paymentModel";
@@ -17,27 +17,49 @@ export const useAccountStore = defineStore("accountStore", {
/** Useraccount which is currently logged in */ /** Useraccount which is currently logged in */
userAccount: useLocalStorage("hackmycart/accountStore/userAccount", new AccountApiModel()), userAccount: useLocalStorage("hackmycart/accountStore/userAccount", new AccountApiModel()),
/** User input on login screen */
loginData: ref<{ username: String, password: String}>(
{ username: "duranduran", password: "H4nn0ver" }
),
/** */
registerData: ref<AccountModel>(new AccountModel()),
/** All orders of the user */ /** All orders of the user */
orders: ref<Array<OrderApiModel>>([]) orders: ref<Array<OrderApiModel>>([]),
/** Request to server sent, waiting for data response */
fetchInProgress: ref(false)
}), }),
actions: { actions: {
/** /**
* Start the login process * Start the login process
* *
* @param username Account username * @returns True on success
* @param password Account password
*/ */
async login(username: string, password: string) { async login(): Promise<boolean> {
const feedbackStore = useFeedbackStore() const feedbackStore = useFeedbackStore()
this.fetchInProgress = true
await loginAccount(username, password) // Validate
if (this.loginData.username == null || this.loginData.username.length == 0 ||
this.loginData.password == null || this.loginData.password.length == 0
) {
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTLOGINWRONGLOGIN)
this.fetchInProgress = false
return false
}
else
{
await loginAccount(this.loginData.username, this.loginData.password)
.then(async result => { .then(async result => {
this.userAccount = result.data this.userAccount = result.data
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTLOGINSUCCESSFUL) feedbackStore.changeBanner(BannerStateEnum.ACCOUNTLOGINSUCCESSFUL)
this.refreshOrders() this.fetchInProgress = false
return true
}) })
.catch(error => { .catch(error => {
if (error.status == 400) { if (error.status == 400) {
@@ -45,22 +67,39 @@ export const useAccountStore = defineStore("accountStore", {
} else if (error.status == 401) { } else if (error.status == 401) {
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTLOGINWRONGLOGIN) feedbackStore.changeBanner(BannerStateEnum.ACCOUNTLOGINWRONGLOGIN)
} }
this.fetchInProgress = false
return false
}) })
}
}, },
/** /**
* Register a new account to the database * Register a new account to the database
* Log in on success
* *
* @param userAccount New account dataset * @returns True on success
*/ */
async registerAccount(userAccount: AccountModel) { async registerAccount(): Promise<boolean> {
const feedbackStore = useFeedbackStore() const feedbackStore = useFeedbackStore()
this.fetchInProgress = true
await registerAccount(userAccount) await registerAccount(this.registerData)
.then(res => { .then(async res => {
if (res.status == 201) { if (res.status == 201) {
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTREGISTERSUCCESSFUL) feedbackStore.changeBanner(BannerStateEnum.ACCOUNTREGISTERSUCCESSFUL)
} }
this.loginData = {
username: this.registerData.username,
password: this.registerData.password
}
await this.login()
.then(result => {
this.fetchInProgress = false
return true
})
}) })
.catch((error) => { .catch((error) => {
if (error.status == 400) { if (error.status == 400) {
@@ -68,9 +107,17 @@ export const useAccountStore = defineStore("accountStore", {
} else if (error.status == 409) { } else if (error.status == 409) {
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTREGISTERUSERNAMEINUSE) feedbackStore.changeBanner(BannerStateEnum.ACCOUNTREGISTERUSERNAMEINUSE)
} }
this.fetchInProgress = false
return false
}) })
return false
}, },
/**
* Update values of an existing account on server
*/
async updateAccount() { async updateAccount() {
const feedbackStore = useFeedbackStore() const feedbackStore = useFeedbackStore()
@@ -82,6 +129,9 @@ export const useAccountStore = defineStore("accountStore", {
}) })
}, },
/**
* Logout user
*/
logout() { logout() {
const feedbackStore = useFeedbackStore() const feedbackStore = useFeedbackStore()
@@ -95,9 +145,12 @@ export const useAccountStore = defineStore("accountStore", {
* Get all orders from current user * Get all orders from current user
*/ */
async refreshOrders() { async refreshOrders() {
await getUserOrders(this.userAccount.id) this.fetchInProgress = true
await fetchUserOrders(this.userAccount.id)
.then(result => { .then(result => {
this.orders = result.data this.orders = result.data
this.fetchInProgress = false
}) })
}, },

View File

@@ -1,13 +1,18 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { ref } from "vue"; import { ref } from "vue";
import { BandApiModel } from "../data/models/acts/bandApiModel"; import { BandApiModel } from "../data/models/acts/bandApiModel";
import { fetchAllBands, getBand } from "../data/api/bandApi"; import { fetchAllBands, fetchBandByName } from "../data/api/bandApi";
import { BandDetailsApiModel } from "../data/models/acts/bandDetailsApiModel"; import { BandDetailsApiModel } from "../data/models/acts/bandDetailsApiModel";
export const useBandStore = defineStore("bandStore", { export const useBandStore = defineStore("bandStore", {
state: () => ({ state: () => ({
/** All available bands */
bands: ref<Array<BandApiModel>>([]), bands: ref<Array<BandApiModel>>([]),
/** All information about a single band */
band: ref<BandDetailsApiModel>(new BandDetailsApiModel()), band: ref<BandDetailsApiModel>(new BandDetailsApiModel()),
/** Request to server sent, waiting for data response */
fetchInProgress: ref(false) fetchInProgress: ref(false)
}), }),
@@ -25,7 +30,7 @@ export const useBandStore = defineStore("bandStore", {
async getBand(name: string) { async getBand(name: string) {
this.fetchInProgress = true this.fetchInProgress = true
getBand(name) fetchBandByName(name)
.then(result => { .then(result => {
this.band = result.data this.band = result.data
this.fetchInProgress = false this.fetchInProgress = false

View File

@@ -1,7 +1,7 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { useLocalStorage } from "@vueuse/core"; import { useLocalStorage } from "@vueuse/core";
import { BasketItemModel } from "../data/models/ordering/basketItemModel"; import { BasketItemModel } from "../data/models/ordering/basketItemModel";
import { useFeedbackStore } from "./feedbackStore"; import { useFeedbackStore } from "./feedback.store";
import { BannerStateEnum } from "../data/enums/bannerStateEnum"; import { BannerStateEnum } from "../data/enums/bannerStateEnum";
import { AddressModel } from "../data/models/user/addressModel"; import { AddressModel } from "../data/models/user/addressModel";
import { PaymentModel } from "../data/models/user/paymentModel"; import { PaymentModel } from "../data/models/user/paymentModel";
@@ -15,9 +15,16 @@ import { createOrder } from "@/data/api/orderApi";
export const useBasketStore = defineStore('basketStore', { export const useBasketStore = defineStore('basketStore', {
state: () => ({ state: () => ({
itemsInBasket: useLocalStorage<Array<BasketItemModel>>("hackmycart/basketStore/productsInBasket", []), /** Items in customers basket */
itemsInBasket: useLocalStorage<Array<BasketItemModel>>("hackmycart/basketStore/itemsInBasket", []),
/** Address used in the order dialog */
usedAddress: useLocalStorage("hackmycart/basketStore/usedAddress", new AddressModel()), usedAddress: useLocalStorage("hackmycart/basketStore/usedAddress", new AddressModel()),
/** Payment method used in the order dialog */
usedPayment: useLocalStorage("hackmycart/basketStore/usedPayment", new PaymentModel()), usedPayment: useLocalStorage("hackmycart/basketStore/usedPayment", new PaymentModel()),
/** Selected seats in the booking page */
selectedSeats: ref<Array<SelectedSeatModel>>([]) selectedSeats: ref<Array<SelectedSeatModel>>([])
}), }),
@@ -53,9 +60,16 @@ export const useBasketStore = defineStore('basketStore', {
) )
}, },
moveSeatSelectionsToBasket(concert: ConcertModel, band: BandModel) { /**
* Move all selected seats from selectedSeats to itemsInBasket variable
*
* @param band Band of the concert
*/
moveSeatSelectionsToBasket(band: BandModel) {
for (let selectedSeat of this.selectedSeats) { for (let selectedSeat of this.selectedSeats) {
let itemInBasket: BasketItemModel = this.itemsInBasket.find((basketItem: BasketItemModel) => { let itemInBasket: BasketItemModel =
this.itemsInBasket.find((basketItem: BasketItemModel) =>
{
return basketItem.concert.id == selectedSeat.concert.id return basketItem.concert.id == selectedSeat.concert.id
}) })
@@ -77,13 +91,19 @@ export const useBasketStore = defineStore('basketStore', {
}, },
/** /**
* Take an order to the server. Sends all articles in the basket and creates an order entry in the backend database * Take an order to the server. Sends all articles in the basket and
* creates an order entry in the backend database
*/ */
async takeOrder() { async takeOrder() {
const accountStore = useAccountStore() const accountStore = useAccountStore()
const feedbackStore = useFeedbackStore() const feedbackStore = useFeedbackStore()
await createOrder(accountStore.userAccount.id, this.itemsInBasket, this.usedPayment.id, this.usedAddress.id) await createOrder(
accountStore.userAccount.id,
this.itemsInBasket,
this.usedPayment.id,
this.usedAddress.id
)
.then(async result => { .then(async result => {
if (result.status == 201) { if (result.status == 201) {
await accountStore.refreshOrders() await accountStore.refreshOrders()

View File

@@ -1,14 +1,21 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { ref } from "vue"; import { ref } from "vue";
import { ConcertApiModel } from "../data/models/acts/concertApiModel"; import { ConcertApiModel } from "../data/models/acts/concertApiModel";
import { fetchConcert, fetchConcerts, fetchUpcomingConcerts } from "../data/api/concertApi"; import { fetchConcertById, fetchAllConcerts, fetchUpcomingConcerts } from "../data/api/concertApi";
import { ConcertDetailsApiModel } from "../data/models/acts/concertDetailsApiModel"; import { ConcertDetailsApiModel } from "../data/models/acts/concertDetailsApiModel";
export const useConcertStore = defineStore("concertStore", { export const useConcertStore = defineStore("concertStore", {
state: () => ({ state: () => ({
/** All available concerts */
concerts: ref<Array<ConcertApiModel>>([]), concerts: ref<Array<ConcertApiModel>>([]),
/** Next upcoming concerts */
upcomingConcerts: ref<Array<ConcertApiModel>>([]), upcomingConcerts: ref<Array<ConcertApiModel>>([]),
/** Enhanced data about a specific concert */
concert: ref<ConcertDetailsApiModel>(new ConcertDetailsApiModel()), concert: ref<ConcertDetailsApiModel>(new ConcertDetailsApiModel()),
/** Request to server sent, waiting for data response */
fetchInProgress: ref(false) fetchInProgress: ref(false)
}), }),
@@ -19,23 +26,31 @@ export const useConcertStore = defineStore("concertStore", {
async getConcerts() { async getConcerts() {
this.fetchInProgress = true this.fetchInProgress = true
fetchConcerts() fetchAllConcerts()
.then(result => { .then(result => {
this.concerts = result.data this.concerts = result.data
this.fetchInProgress = false this.fetchInProgress = false
}) })
}, },
/**
* Get all data about a specific concert
*
* @param id ID of the concert in the database
*/
async getConcert(id: number) { async getConcert(id: number) {
this.fetchInProgress = true this.fetchInProgress = true
fetchConcert(id) fetchConcertById(id)
.then(result => { .then(result => {
this.concert = result.data this.concert = result.data
this.fetchInProgress = false this.fetchInProgress = false
}) })
}, },
/**
* Download the next four upcoming concerts from server
*/
async getUpcomingConcerts() { async getUpcomingConcerts() {
this.fetchInProgress = true this.fetchInProgress = true

View File

@@ -3,13 +3,16 @@ import { ref } from "vue";
import { BannerStateEnum } from "../data/enums/bannerStateEnum"; import { BannerStateEnum } from "../data/enums/bannerStateEnum";
import { Composer } from 'vue-i18n'; import { Composer } from 'vue-i18n';
/**
* Logic of the bubble notifications
* Includes an i18n object for translation
*/
export const useFeedbackStore = defineStore("feedbackStore", { export const useFeedbackStore = defineStore("feedbackStore", {
state: () => ({ state: () => ({
showBanner: ref(false), showBanner: ref(false),
title: ref(""), title: ref(""),
color: ref(""), color: ref(""),
icon: ref(""), icon: ref(""),
fetchDataFromServerInProgress: ref(false),
$i18n: {} $i18n: {}
}), }),
@@ -50,21 +53,27 @@ export const useFeedbackStore = defineStore("feedbackStore", {
case BannerStateEnum.ACCOUNTLOGINSUCCESSFUL: { case BannerStateEnum.ACCOUNTLOGINSUCCESSFUL: {
this.title = this.i18n.t('bannerMessages.loginSuccessful'); break; this.title = this.i18n.t('bannerMessages.loginSuccessful'); break;
} }
case BannerStateEnum.ACCOUNTLOGINWRONGLOGIN: { case BannerStateEnum.ACCOUNTLOGINWRONGLOGIN: {
this.title = this.i18n.t('bannerMessages.wrongLogin'); break; this.title = this.i18n.t('bannerMessages.wrongLogin'); break;
} }
case BannerStateEnum.ACCOUNTLOGINERROR: { case BannerStateEnum.ACCOUNTLOGINERROR: {
this.title = this.i18n.t('bannerMessages.error'); break; this.title = this.i18n.t('bannerMessages.error'); break;
} }
case BannerStateEnum.ACCOUNTREGISTERSUCCESSFUL: { case BannerStateEnum.ACCOUNTREGISTERSUCCESSFUL: {
this.title = this.i18n.t("bannerMessages.registerSuccessful"); break; this.title = this.i18n.t("bannerMessages.registerSuccessful"); break;
} }
case BannerStateEnum.ACCOUNTREGISTERUSERNAMEINUSE: { case BannerStateEnum.ACCOUNTREGISTERUSERNAMEINUSE: {
this.title = this.i18n.t("bannerMessages.usernameInUse"); break; this.title = this.i18n.t("bannerMessages.usernameInUse"); break;
} }
case BannerStateEnum.ACCOUNTUPDATESUCCESSFUL: { case BannerStateEnum.ACCOUNTUPDATESUCCESSFUL: {
this.title = this.i18n.t("bannerMessages.accountUpdated"); break; this.title = this.i18n.t("bannerMessages.accountUpdated"); break;
} }
case BannerStateEnum.ACCOUNTLOGOUTSUCCESSFUL: { case BannerStateEnum.ACCOUNTLOGOUTSUCCESSFUL: {
this.title = this.i18n.t('bannerMessages.logoutSuccessful'); break; this.title = this.i18n.t('bannerMessages.logoutSuccessful'); break;
} }
@@ -75,12 +84,15 @@ export const useFeedbackStore = defineStore("feedbackStore", {
case BannerStateEnum.CATEGORYCREATESUCCESSFUL: { case BannerStateEnum.CATEGORYCREATESUCCESSFUL: {
this.title = this.i18n.t('bannerMessages.categoryCreateSuccessful'); break; this.title = this.i18n.t('bannerMessages.categoryCreateSuccessful'); break;
} }
case BannerStateEnum.CATEGORYDELETESUCESSFUL: { case BannerStateEnum.CATEGORYDELETESUCESSFUL: {
this.title = this.i18n.t('bannerMessages.categoryDeleteSuccessful'); break; this.title = this.i18n.t('bannerMessages.categoryDeleteSuccessful'); break;
} }
case BannerStateEnum.CATEGORYCREATEERROR: { case BannerStateEnum.CATEGORYCREATEERROR: {
this.title = this.i18n.t('bannerMessages.categoryCreateError'); break; this.title = this.i18n.t('bannerMessages.categoryCreateError'); break;
} }
case BannerStateEnum.CATEGORYDELETEERROR: { case BannerStateEnum.CATEGORYDELETEERROR: {
this.title = this.i18n.t('bannerMessages.categoryDeleteError'); break; this.title = this.i18n.t('bannerMessages.categoryDeleteError'); break;
} }
@@ -98,17 +110,21 @@ export const useFeedbackStore = defineStore("feedbackStore", {
case BannerStateEnum.PRODUCTCREATESUCCESSFUL: { case BannerStateEnum.PRODUCTCREATESUCCESSFUL: {
this.title = this.i18n.t('bannerMessages.productCreateSuccessful'); break; this.title = this.i18n.t('bannerMessages.productCreateSuccessful'); break;
} }
case BannerStateEnum.PRODUCTCREATEERROR: { case BannerStateEnum.PRODUCTCREATEERROR: {
this.title = this.i18n.t('bannerMessages.productCreateError'); break; this.title = this.i18n.t('bannerMessages.productCreateError'); break;
} }
case BannerStateEnum.PRODUCTDELETESUCCESSFUL: { case BannerStateEnum.PRODUCTDELETESUCCESSFUL: {
this.title = this.i18n.t('bannerMessages.productDeleteSuccessful'); break; this.title = this.i18n.t('bannerMessages.productDeleteSuccessful'); break;
} }
case BannerStateEnum.PRODUCTDELETEERROR: { case BannerStateEnum.PRODUCTDELETEERROR: {
this.title = this.i18n.t('bannerMessages.productDeleteError'); break; this.title = this.i18n.t('bannerMessages.productDeleteError'); break;
} }
} }
// Banner color // Banner color
switch (bannerState) { switch (bannerState) {
@@ -201,9 +217,6 @@ export const useFeedbackStore = defineStore("feedbackStore", {
break; break;
} }
this.showBanner = true this.showBanner = true
} }
} }

View File

@@ -1,15 +1,26 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { ref } from "vue"; import { ref } from "vue";
import { fetchAllLocations, fetchTopLocations } from "../data/api/locationApi"; import { fetchAllLocations, fetchLocationByName, fetchTopLocations } from "../data/api/locationApi";
import { LocationApiModel } from "../data/models/locations/locationApiModel"; import { LocationApiModel } from "../data/models/locations/locationApiModel";
import { CityModel } from "../data/models/locations/cityModel"; import { CityModel } from "../data/models/locations/cityModel";
import { fetchAllCities } from "../data/api/cityApi"; import { fetchAllCities } from "../data/api/cityApi";
import { LocationDetailsApiModel } from "@/data/models/locations/locationDetailsApiModel";
export const useLocationStore = defineStore("locationStore", { export const useLocationStore = defineStore("locationStore", {
state: () => ({ state: () => ({
/** All available locations */
locations: ref<Array<LocationApiModel>>([]), locations: ref<Array<LocationApiModel>>([]),
/** Locations with the most concerts */
topLocations: ref<Array<LocationApiModel>>([]), topLocations: ref<Array<LocationApiModel>>([]),
/** Enhanced data about a specific location */
location: ref<LocationDetailsApiModel>(),
/** All available cities */
cities: ref<Array<CityModel>>([]), cities: ref<Array<CityModel>>([]),
/** Request to server sent, waiting for data response */
fetchInProgress: ref(false) fetchInProgress: ref(false)
}), }),
@@ -32,6 +43,16 @@ export const useLocationStore = defineStore("locationStore", {
}) })
}, },
getLocationByName(name: string) {
this.fetchInProgress = true
fetchLocationByName(name)
.then(result => {
this.location = result.data
this.fetchInProgress = false
})
},
/** /**
* Get all locations in a specific city * Get all locations in a specific city
* *
@@ -46,6 +67,9 @@ export const useLocationStore = defineStore("locationStore", {
}, },
/**
* Fetch top 8 locations from server
*/
async getTopLocations() { async getTopLocations() {
await fetchTopLocations(8) await fetchTopLocations(8)
.then(result => { .then(result => {

View File

@@ -2,10 +2,17 @@ import { defineStore } from "pinia";
import { useLocalStorage } from "@vueuse/core"; import { useLocalStorage } from "@vueuse/core";
import { ThemeEnum } from "../data/enums/themeEnums"; import { ThemeEnum } from "../data/enums/themeEnums";
import { LanguageEnum } from "../data/enums/languageEnum"; import { LanguageEnum } from "../data/enums/languageEnum";
import { ref } from "vue";
export const usePreferencesStore = defineStore('preferencesStore', { export const usePreferencesStore = defineStore('preferencesStore', {
state: () => ({ state: () => ({
/** Selected theme by user */
theme: useLocalStorage<ThemeEnum>("hackmycart/preferencesStore/theme", ThemeEnum.DARKBLUE), theme: useLocalStorage<ThemeEnum>("hackmycart/preferencesStore/theme", ThemeEnum.DARKBLUE),
language: useLocalStorage<LanguageEnum>("hackmycart/preferencesStore/language", LanguageEnum.GERMAN)
/** Selected language by user */
language: useLocalStorage<LanguageEnum>("hackmycart/preferencesStore/language", LanguageEnum.GERMAN),
/** Request to server sent, waiting for data response */
fetchInProgress: ref(false)
}), }),
}) })

View File

@@ -0,0 +1,55 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import { fetchBandsBySearchTerm } from "../data/api/bandApi";
import { fetchLocationsBySearchTerm } from "../data/api/locationApi";
import { fetchConcertsBySearchTerm } from "../data/api/concertApi";
import { ConcertApiModel } from "@/data/models/acts/concertApiModel";
export const useSearchStore = defineStore("searchStore", {
state: () => ({
/** Search term */
searchTerm: ref(""),
/** Band results */
bands: ref(),
/** Location results */
locations: ref(),
/** Concert results */
concerts: ref<Array<ConcertApiModel>>([]),
/** One or more searches are already performed */
alreadySearched: ref(false),
/** Request to server sent, waiting for data response */
fetchInProgress: ref(false)
}),
actions: {
/**
* Search for the term in all bands, locations, events
*/
async startSearch() {
this.alreadySearched = true
this.fetchInProgress = true
await fetchBandsBySearchTerm(this.searchTerm)
.then(result => {
this.bands = result.data
})
await fetchLocationsBySearchTerm(this.searchTerm)
.then(result => {
this.locations = result.data
})
await fetchConcertsBySearchTerm(this.searchTerm)
.then(result => {
this.concerts = result.data
})
this.fetchInProgress = false
}
}
})

View File

@@ -1,43 +0,0 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import { searchBand } from "../data/api/bandApi";
import { searchLocation } from "../data/api/locationApi";
import { searchConcert } from "../data/api/concertApi";
export const useSearchStore = defineStore("searchStore", {
state: () => ({
searchTerm: ref(""),
bands: ref(),
locations: ref(),
concerts: ref(),
alreadySearched: ref(false),
searchInProgress: ref(false)
}),
actions: {
/**
* Search for the termin in all bands, locations, events
*/
async startSearch() {
this.alreadySearched = true
this.searchInProgress = true
await searchBand(this.searchTerm)
.then(result => {
this.bands = result.data
})
await searchLocation(this.searchTerm)
.then(result => {
this.locations = result.data
})
await searchConcert(this.searchTerm)
.then(result => {
this.concerts = result.data
})
this.searchInProgress = false
}
}
})

View File

@@ -1,60 +0,0 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import { ConcertApiModel } from "../data/models/acts/concertApiModel";
import { BandApiModel } from "../data/models/acts/bandApiModel";
import { CityApiModel } from "../data/models/locations/cityApiModel";
import { GenreApiModel } from "../data/models/acts/genreApiModel";
import { searchBand } from "../data/api/bandApi";
import { searchLocation } from "../data/api/locationApi";
import { fetchConcerts, searchConcert } from "../data/api/concertApi";
import { useFeedbackStore } from "./feedbackStore";
export const useShopStore = defineStore("shopStore", {
state: () => ({
concertsFiltered: ref<Array<ConcertApiModel>>([]),
bandsFiltered: ref<Array<BandApiModel>>([]),
cities: ref<Array<CityApiModel>>([]),
cityFilterName: ref<string>(),
genreFilterName: ref<string>(),
genres: ref<Array<GenreApiModel>>([]),
alreadySearched: ref(false),
searchInProgress: ref(false)
}),
actions: {
/**
* Search for the termin in all bands, locations, events
*/
async startSearch() {
this.alreadySearched = true
this.searchInProgress = true
await searchBand(this.searchTerm)
.then(result => {
this.bands = result.data
})
await searchLocation(this.searchTerm)
.then(result => {
this.locations = result.data
})
await searchConcert(this.searchTerm)
.then(result => {
this.concerts = result.data
})
this.searchInProgress = false
},
async getConcerts() {
const feedbackStore = useFeedbackStore()
feedbackStore.fetchDataFromServerInProgress = true
await fetchConcerts()
.then(result => {
this.concerts = result.data
})
}
}
})

View File

@@ -1,48 +0,0 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import { fetchAllCities } from "../data/api/cityApi";
import { fetchAllGenres } from "../data/api/genreApi";
import { useFeedbackStore } from "./feedbackStore";
import { CityApiModel } from "../data/models/locations/cityApiModel";
import { GenreApiModel } from "../data/models/acts/genreApiModel";
/**
* @deprecated
*/
export const useShoppingStore = defineStore("shoppingStore", {
state: () => ({
cities: ref<Array<CityApiModel>>([]),
genres: ref<Array<GenreApiModel>>([]),
cityFilterName: ref<string>(),
genreFilterName: ref<string>()
}),
actions: {
async getEvents() {
const feedbackStore = useFeedbackStore()
feedbackStore.fetchDataFromServerInProgress = true
},
async getCities() {
const feedbackStore = useFeedbackStore()
feedbackStore.fetchDataFromServerInProgress = true
await fetchAllCities()
.then(result => {
this.cities = result.data
feedbackStore.fetchDataFromServerInProgress = false
})
},
async getGenres() {
const feedbackStore = useFeedbackStore()
feedbackStore.fetchDataFromServerInProgress = true
await fetchAllGenres()
.then(result => {
this.genres = result.data
feedbackStore.fetchDataFromServerInProgress = false
})
}
}
})

View File

@@ -1,7 +1,8 @@
{ {
"include": [ "include": [
"src/**/*", "src/**/*",
"src/**/*.vue" "src/**/*.vue",
"package.json"
], ],
"compilerOptions": { "compilerOptions": {
"composite": true, "composite": true,