Display all bands grouped by genre, create m:n association between Band and Genre in database

This commit is contained in:
2024-09-27 23:25:24 +02:00
parent 848e7abf92
commit 9b325c849e
29 changed files with 275 additions and 165 deletions

View File

@@ -8,7 +8,7 @@
"descriptionDe": "Red Hot Chili Peppers (Abkürzung: RHCP) ist eine 1983 gegründete US-amerikanische Funk- und Alternative-Rockband. Sie zählt zu den kommerziell erfolgreichsten Vertretern des Crossover. Ihr Album Blood Sugar Sex Magik gilt als eines der bedeutendsten dieses Genres.", "descriptionDe": "Red Hot Chili Peppers (Abkürzung: RHCP) ist eine 1983 gegründete US-amerikanische Funk- und Alternative-Rockband. Sie zählt zu den kommerziell erfolgreichsten Vertretern des Crossover. Ihr Album Blood Sugar Sex Magik gilt als eines der bedeutendsten dieses Genres.",
"images": [ "red-hot-chili-peppers-1.jpg" ], "images": [ "red-hot-chili-peppers-1.jpg" ],
"logo": "red-hot-chili-peppers-logo.png", "logo": "red-hot-chili-peppers-logo.png",
"genreId": 0, "genreId": [ 0, 2, 3 ],
"members": [ "members": [
{ {
"name": "Anthony Kiedis", "name": "Anthony Kiedis",
@@ -47,7 +47,7 @@
"descriptionDe": "Radiohead ist eine britische Rockband, die 1985 in Oxford, England gegründet wurde. Die Band besteht aus Thom Yorke (Gesang, Rhythmusgitarre, Piano), Jonny Greenwood (Lead-Gitarre, Keyboard, Ondes Martenot), Colin Greenwood (E-Bass, Keyboard), Ed OBrien (Gitarre, Backgroundvocals) und Phil Selway (Schlagzeug, Backgroundvocals). Radioheads experimenteller Ansatz gilt als Wegbereiter für den Sound des Alternative Rocks.", "descriptionDe": "Radiohead ist eine britische Rockband, die 1985 in Oxford, England gegründet wurde. Die Band besteht aus Thom Yorke (Gesang, Rhythmusgitarre, Piano), Jonny Greenwood (Lead-Gitarre, Keyboard, Ondes Martenot), Colin Greenwood (E-Bass, Keyboard), Ed OBrien (Gitarre, Backgroundvocals) und Phil Selway (Schlagzeug, Backgroundvocals). Radioheads experimenteller Ansatz gilt als Wegbereiter für den Sound des Alternative Rocks.",
"images": [ "radiohead-1.jpg" ], "images": [ "radiohead-1.jpg" ],
"logo": "radiohead-logo.jpg", "logo": "radiohead-logo.jpg",
"genreId": 1, "genreId": [ 1, 2, 4, 5, 6 ],
"members": [ "members": [
{ {
"name": "Thom Yorke", "name": "Thom Yorke",
@@ -96,7 +96,7 @@
"descriptionDe": "Die Arctic Monkeys sind eine vierköpfige britische Alternative-Rock-Band mit Einflüssen aus Post-Punk und Garage Rock. Sie wurde 2002 im englischen Sheffield gegründet und veröffentlichte 2006 ihr Debütalbum, das Platz eins der britischen Charts erreichte. 2007, 2009, 2011, 2013 und 2018 erschienen jeweils weitere Alben der Musikgruppe, die alle ebenfalls die Spitzenposition in Großbritannien erreichten. Aktuelles Album der Band ist das am 21. Oktober 2022 erschienene The Car.", "descriptionDe": "Die Arctic Monkeys sind eine vierköpfige britische Alternative-Rock-Band mit Einflüssen aus Post-Punk und Garage Rock. Sie wurde 2002 im englischen Sheffield gegründet und veröffentlichte 2006 ihr Debütalbum, das Platz eins der britischen Charts erreichte. 2007, 2009, 2011, 2013 und 2018 erschienen jeweils weitere Alben der Musikgruppe, die alle ebenfalls die Spitzenposition in Großbritannien erreichten. Aktuelles Album der Band ist das am 21. Oktober 2022 erschienene The Car.",
"images": [ "arctic-monkeys-1.jpg", "arctic-monkeys-2.jpg" ], "images": [ "arctic-monkeys-1.jpg", "arctic-monkeys-2.jpg" ],
"logo": "arctic-monkeys-logo.png", "logo": "arctic-monkeys-logo.png",
"genreId": 2, "genreId": [ 2, 7, 8 ],
"members": [ "members": [
{ {
"name": "Glyn Jones", "name": "Glyn Jones",
@@ -150,7 +150,7 @@
"descriptionDe": "Coldplay ist eine britische Pop-Rock-Band, bestehend aus Chris Martin, Jonny Buckland, Will Champion und Guy Berryman. Sie ist eine der weltweit erfolgreichsten Bands der 2000er-Jahre und hat knapp 80 Millionen Tonträger weltweit verkauft, davon 50 Millionen Alben.", "descriptionDe": "Coldplay ist eine britische Pop-Rock-Band, bestehend aus Chris Martin, Jonny Buckland, Will Champion und Guy Berryman. Sie ist eine der weltweit erfolgreichsten Bands der 2000er-Jahre und hat knapp 80 Millionen Tonträger weltweit verkauft, davon 50 Millionen Alben.",
"images": [ "coldplay-1.jpg" ], "images": [ "coldplay-1.jpg" ],
"logo": "coldplay-logo.jpg", "logo": "coldplay-logo.jpg",
"genreId": 2, "genreId": [ 2, 9 ],
"members": [ "members": [
{ {
"name": "Chris Martin", "name": "Chris Martin",
@@ -174,7 +174,7 @@
}, },
{ {
"name": "Phil Harvey", "name": "Phil Harvey",
"bandId": 2, "bandId": 3,
"image": "phil-harvey.jpg" "image": "phil-harvey.jpg"
} }
], ],
@@ -199,7 +199,7 @@
"descriptionDe": "Foo Fighters ist eine US-amerikanische Rockband. Prominentestes Mitglied und Band-Gründer ist der ehemalige Nirvana-Schlagzeuger Dave Grohl. ", "descriptionDe": "Foo Fighters ist eine US-amerikanische Rockband. Prominentestes Mitglied und Band-Gründer ist der ehemalige Nirvana-Schlagzeuger Dave Grohl. ",
"images": [ "foo-fighters-1.jpg" ], "images": [ "foo-fighters-1.jpg" ],
"logo": "foo-fighters-logo.png", "logo": "foo-fighters-logo.png",
"genreId": 2, "genreId": [ 2, 10 ],
"members": [ "members": [
{ {
"name": "Dave Grohl", "name": "Dave Grohl",

View File

@@ -2,15 +2,47 @@
"data": [ "data": [
{ {
"id": 0, "id": 0,
"name": "Funk rock" "name": "Funk Rock"
}, },
{ {
"id": 1, "id": 1,
"name": "Art rock" "name": "Art Rock"
}, },
{ {
"id": 2, "id": 2,
"name": "Alternative Rock" "name": "Alternative Rock"
},
{
"id": 3,
"name": "Crossover"
},
{
"id": 4,
"name": "Electronica"
},
{
"id": 5,
"name": "Post-Rock"
},
{
"id": 6,
"name": "Britpop"
},
{
"id": 7,
"name": "Post-Punk"
},
{
"id": 8,
"name": "Garage Rock"
},
{
"id": 9,
"name": "Pop-Rock"
},
{
"id": 10,
"name": "Post-Grunge"
} }
] ]
} }

View File

@@ -16,6 +16,7 @@ import { Member } from "./models/acts/member.model"
import { Rating } from "./models/acts/rating.model" import { Rating } from "./models/acts/rating.model"
import { Tour } from "./models/acts/tour.model" import { Tour } from "./models/acts/tour.model"
import { City } from "./models/acts/city.model" import { City } from "./models/acts/city.model"
import { BandGenre } from "./models/acts/bandGenre.model"
const dbName = "database" const dbName = "database"
const dbUser = "root" const dbUser = "root"
@@ -30,7 +31,7 @@ export const sequelize = new Sequelize({
storage: "database.sqlite", storage: "database.sqlite",
models: [ models: [
AccountRole, Account, Payment, Address, AccountRole, Account, Payment, Address,
City, Location, Genre, Band, Rating, Member, Tour, Show, City, Location, Genre, Band, BandGenre, Rating, Member, Tour, Show,
Order, OrderItem Order, OrderItem
] ]
}) })

View File

@@ -1,8 +1,9 @@
import { BelongsTo, Column, DataType, ForeignKey, HasMany, Model, Table } from "sequelize-typescript"; import { BelongsTo, BelongsToMany, Column, DataType, ForeignKey, HasMany, Model, Table } from "sequelize-typescript";
import { Member } from "./member.model"; import { Member } from "./member.model";
import { Genre } from "./genre.model"; import { Genre } from "./genre.model";
import { Rating } from "./rating.model"; import { Rating } from "./rating.model";
import { Tour } from "./tour.model"; import { Tour } from "./tour.model";
import { BandGenre } from "./bandGenre.model";
@Table({ timestamps: false }) @Table({ timestamps: false })
export class Band extends Model { export class Band extends Model {
@@ -32,10 +33,6 @@ export class Band extends Model {
@Column @Column
logo: String logo: String
@ForeignKey(() => Genre)
@Column
genreId: Number
// Relations // Relations
@@ -48,6 +45,6 @@ export class Band extends Model {
@HasMany(() => Tour) @HasMany(() => Tour)
tours: Tour[] tours: Tour[]
@BelongsTo(() => Genre) @BelongsToMany(() => Genre, () => BandGenre)
genre: Genre genres: Genre[]
} }

View File

@@ -0,0 +1,16 @@
import { AutoIncrement, Column, ForeignKey, Model, PrimaryKey, Table, Unique } from "sequelize-typescript";
import { Genre } from "./genre.model";
import { Band } from "./band.model";
@Table({ timestamps: false })
export class BandGenre extends Model {
@PrimaryKey
@Column({autoIncrement: true})
declare id: number
@ForeignKey(() => Genre)
genreId: number
@ForeignKey(() => Band)
bandId: number
}

View File

@@ -1,5 +1,6 @@
import { Column, HasMany, Model, Table } from "sequelize-typescript"; import { BelongsToMany, Column, Model, Table } from "sequelize-typescript";
import { Band } from "./band.model"; import { Band } from "./band.model";
import { BandGenre } from "./bandGenre.model";
@Table({ timestamps: false }) @Table({ timestamps: false })
export class Genre extends Model { export class Genre extends Model {
@@ -9,6 +10,6 @@ export class Genre extends Model {
// Relations // Relations
@HasMany(() => Band) @BelongsToMany(() => Band, () => BandGenre)
bands: Band[] bands: Band[]
} }

View File

@@ -1,10 +1,19 @@
import { Rating } from "../models/acts/rating.model";
import { Band } from "../models/acts/band.model";
import { Genre } from "../models/acts/genre.model"; import { Genre } from "../models/acts/genre.model";
import { Request, Response, Router } from "express"; import { Request, Response, Router } from "express";
export const genre = Router() export const genre = Router()
genre.get("/", (req: Request, res: Response) => { genre.get("/", (req: Request, res: Response) => {
Genre.findAll() Genre.findAll({
include: [
{
model: Band,
include: [ Rating ]
}
]
})
.then(genres => { .then(genres => {
res.status(200).json(genres) res.status(200).json(genres)
}) })

View File

@@ -12,6 +12,7 @@ import { Location } from '../models/acts/location.model'
import { Show } from '../models/acts/show.model' import { Show } from '../models/acts/show.model'
import { Tour } from '../models/acts/tour.model' import { Tour } from '../models/acts/tour.model'
import { City } from '../models/acts/city.model' import { City } from '../models/acts/city.model'
import { BandGenre } from '../models/acts/bandGenre.model'
import accounts from "./../data/accounts.json" import accounts from "./../data/accounts.json"
import orders from "./../data/orders.json" import orders from "./../data/orders.json"
@@ -69,8 +70,17 @@ export async function prepopulateDatabase() {
for(let band of bands.data) { for(let band of bands.data) {
// Create a band dataset
await Band.create(band) await Band.create(band)
.then(dataset => { .then(async dataset => {
// Create the m:n associations for the genres
for (let genreId of band.genreId) {
await BandGenre.create({
genreId: Number(genreId),
bandId: dataset.dataValues.id
})
}
Rating.bulkCreate(band.ratings) Rating.bulkCreate(band.ratings)
Member.bulkCreate(band.members) Member.bulkCreate(band.members)
}) })

View File

@@ -65,16 +65,10 @@ watch(() => preferencesStore.language, () => {
<!-- Here changes the router the content --> <!-- Here changes the router the content -->
<v-container max-width="1200" class="pt-0 pb-5"> <v-container max-width="1200" class="pt-0 pb-5">
<v-sheet> <v-sheet color="sheet">
<router-view></router-view> <router-view></router-view>
</v-sheet> </v-sheet>
</v-container> </v-container>
</v-main> </v-main>
</v-app> </v-app>
</template> </template>
<style scoped>
.v-sheet {
background-color: #333333;
}
</style>

View File

@@ -7,7 +7,7 @@ defineProps({
<template> <template>
<v-card <v-card
variant="outlined" variant="tonal"
link link
> >
<v-img <v-img

View File

@@ -15,7 +15,20 @@
height="100%" height="100%"
:rounded="false" :rounded="false"
> >
{{ $t('menu.shopping.allEvents', 2) }} {{ $t('menu.allEvents', 2) }}
</v-btn>
<v-divider vertical />
<v-btn
variant="text"
to="/shows/bands"
prepend-icon="mdi-music-clef-treble"
height="100%"
:rounded="false"
>
{{ $t('menu.allBands') }}
</v-btn> </v-btn>
<v-divider vertical /> <v-divider vertical />
@@ -28,20 +41,7 @@
height="100%" height="100%"
:rounded="false" :rounded="false"
> >
{{ $t('menu.shopping.allLocations', 2) }} {{ $t('menu.allLocations', 2) }}
</v-btn>
<v-divider vertical />
<v-btn
variant="text"
to="/shows/genres"
prepend-icon="mdi-music-clef-treble"
height="100%"
:rounded="false"
>
{{ $t('menu.shopping.allGenres', 2) }}
</v-btn> </v-btn>
<v-divider vertical /> <v-divider vertical />

View File

@@ -3,7 +3,7 @@ defineProps({
prependIcon: String, prependIcon: String,
color: { color: {
type: String, type: String,
default: "primary" default: "secondary"
} }
}) })
</script> </script>

View File

@@ -3,13 +3,6 @@ defineProps({
title: String, title: String,
image: String image: String
}) })
function backgroundStyle(image: string) {
return {
"background-image": 'http://localhost:3000/static/cities/hannover.jpg',
height: `100px`
}
}
</script> </script>
<template> <template>
@@ -29,7 +22,7 @@ function backgroundStyle(image: string) {
<v-spacer /> <v-spacer />
<v-col class="v-col-auto"> <v-col class="v-col-auto">
<span class="text-h3" style="color: white;">{{ title }}</span> <span class="text-h4" style="color: white;">{{ title }}</span>
</v-col> </v-col>
<v-spacer /> <v-spacer />
@@ -44,7 +37,7 @@ function backgroundStyle(image: string) {
</v-col> </v-col>
<v-col class="v-col-auto"> <v-col class="v-col-auto">
<span class="text-h6">{{ title }}</span> <span class="text-h4">{{ title }}</span>
</v-col> </v-col>
<v-col class="d-flex justify-center align-center"> <v-col class="d-flex justify-center align-center">

View File

@@ -1,7 +1,6 @@
import axios from "axios" import axios from "axios"
import { OrderModel } from "../models/orderModel" import { OrderModel } from "../models/orderModel"
import { BasketItemModel } from "../models/basketItemModel" import { BasketItemModel } from "../models/basketItemModel"
import { calcPrice } from "@/scripts/productScripts"
const BASE_URL = "http://localhost:3000/orders" const BASE_URL = "http://localhost:3000/orders"
@@ -17,13 +16,13 @@ export async function addOrder(
) { ) {
let orderItems = [] let orderItems = []
for (let basketItem of basketItems) { // for (let basketItem of basketItems) {
orderItems.push({ // orderItems.push({
productId: basketItem.product.id, // productId: basketItem.product.id,
quantity: basketItem.quantity, // quantity: basketItem.quantity,
orderPrice: calcPrice(basketItem.product.price, basketItem.product.discount) // orderPrice: calcPrice(basketItem.product.price, basketItem.product.discount)
}) // })
} // }
return axios.post(BASE_URL, { return axios.post(BASE_URL, {
accountId: accountId, accountId: accountId,

View File

@@ -1,9 +1,5 @@
export enum ThemeEnum { export enum ThemeEnum {
DARKRED = "darkRed", DARKBLUE = "dark",
LIGHTRED = "lightRed", LIGHTBLUE = "light",
DARKBLUE = "darkBlue",
LIGHTBLUE = "lightBlue",
DARKGREEN = "darkGreen",
LIGHTGREEN = "lightGreen"
} }

View File

@@ -10,7 +10,9 @@ export class BandModel {
descriptionDe: string descriptionDe: string
images: Array<string> images: Array<string>
logo: string logo: string
genre: GenreModel
ratings: Array<RatingModel> ratings: Array<RatingModel>
members: Array<MemberModel> members: Array<MemberModel>
genre: {
name: string
}
} }

View File

@@ -1,4 +1,19 @@
import { MemberModel } from "./memberModel"
import { RatingModel } from "./ratingModel"
export class GenreModel { export class GenreModel {
id: number id: number
name: string name: string
bands: Array<
{
name: string
foundingYear: number
descriptionEn: string
descriptionDe: string
images: Array<string>
logo: string
ratings: Array<RatingModel>
members: Array<MemberModel>
}
>
} }

View File

@@ -6,7 +6,6 @@ import { useFeedbackStore } from "./feedbackStore";
import { loginAccount, registerAccount, updateAccount } from "../api/accountApi"; import { loginAccount, registerAccount, updateAccount } from "../api/accountApi";
import { getUserOrders } from "../api/orderApi"; import { getUserOrders } from "../api/orderApi";
import { BannerStateEnum } from "../enums/bannerStateEnum"; import { BannerStateEnum } from "../enums/bannerStateEnum";
import { calcPrice } from "@/scripts/productScripts";
import { AddressModel } from "../models/addressModel"; import { AddressModel } from "../models/addressModel";
import { PaymentModel } from "../models/paymentModel"; import { PaymentModel } from "../models/paymentModel";
@@ -86,9 +85,9 @@ export const useAccountStore = defineStore("accountStore", {
let totalPrice = 0 let totalPrice = 0
let order: OrderModel = this.orders.find((order: OrderModel) => order.id == orderId) let order: OrderModel = this.orders.find((order: OrderModel) => order.id == orderId)
for (let item of order.orderItems) { // for (let item of order.orderItems) {
totalPrice += calcPrice(item.orderPrice, 0, item.quantity) // totalPrice += calcPrice(item.orderPrice, 0, item.quantity)
} // }
return Math.round(totalPrice * 100) / 100 return Math.round(totalPrice * 100) / 100
}, },

View File

@@ -1,6 +1,5 @@
import { defineStore } from "pinia"; import { defineStore } from "pinia";
import { useLocalStorage } from "@vueuse/core"; import { useLocalStorage } from "@vueuse/core";
import { calcPrice } from "@/scripts/productScripts";
import { BasketItemModel } from "../models/basketItemModel"; import { BasketItemModel } from "../models/basketItemModel";
import { useFeedbackStore } from "./feedbackStore"; import { useFeedbackStore } from "./feedbackStore";
import { BannerStateEnum } from "../enums/bannerStateEnum"; import { BannerStateEnum } from "../enums/bannerStateEnum";
@@ -26,9 +25,9 @@ export const useBasketStore = defineStore('basketStore', {
getTotalPrice() { getTotalPrice() {
let result = 0 let result = 0
for (let item of this.itemsInBasket) { // for (let item of this.itemsInBasket) {
result += calcPrice(item.product.price, item.product.discount, item.quantity) // result += calcPrice(item.product.price, item.product.discount, item.quantity)
} // }
return Math.round(result * 100) / 100 return Math.round(result * 100) / 100
} }

View File

@@ -1,13 +1,14 @@
{ {
"menu": { "menu": {
"shopping": {
"allEvents": "Alle Events", "allEvents": "Alle Events",
"allLocations": "Alle Orte", "allLocations": "Alle Veranstaltungsorte",
"allGenres": "Alle Genres" "allBands": "Alle Bands"
}
}, },
"shows": { "shows": {
"tickets": "Ticket | Tickets" "tickets": "Ticket | Tickets",
"topEvents": "Top Events",
"topBands": "Top Bands",
"topLocations": "Top Veranstaltungsorte"
}, },

View File

@@ -1,13 +1,14 @@
{ {
"menu": { "menu": {
"shopping": {
"allEvents": "All Events", "allEvents": "All Events",
"allLocations": "All Locations", "allLocations": "All Locations",
"allGenres": "All Genres" "allBands": "All Bands"
}
}, },
"shows": { "shows": {
"tickets": "Ticket | Tickets" "tickets": "Ticket | Tickets",
"topEvents": "Top Events",
"topBands": "Top Bands",
"topLocations": "Top Locations"
}, },

View File

@@ -1,7 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { BasketItemModel } from '@/data/models/basketItemModel'; import { BasketItemModel } from '@/data/models/basketItemModel';
import { useBasketStore } from '@/data/stores/basketStore'; import { useBasketStore } from '@/data/stores/basketStore';
import { calcPrice } from '@/scripts/productScripts';
const basketStore = useBasketStore() const basketStore = useBasketStore()
@@ -58,7 +57,7 @@ function editQuantity(basketItem: BasketItemModel) {
</td> </td>
<!-- Price per unit --> <!-- Price per unit -->
<td class="text-right"> <!-- <td class="text-right">
<div v-if="basketItem.product.discount > 0"> <div v-if="basketItem.product.discount > 0">
<strong class="font-weight-bold text-body-1 text-red-lighten-1"> <strong class="font-weight-bold text-body-1 text-red-lighten-1">
{{ calcPrice(basketItem.product.price, basketItem.product.discount) }} {{ calcPrice(basketItem.product.price, basketItem.product.discount) }}
@@ -70,7 +69,7 @@ function editQuantity(basketItem: BasketItemModel) {
<div v-else> <div v-else>
{{ basketItem.product.price }} {{ basketItem.product.price }}
</div> </div>
</td> </td> -->
<!-- Total price --> <!-- Total price -->
<td class="text-right"> <td class="text-right">

View File

@@ -3,19 +3,11 @@ import { useShowStore } from '@/data/stores/showStore';
import highlightCarousel from './highlightCarousel.vue'; import highlightCarousel from './highlightCarousel.vue';
import sectionDivider from '@/components/sectionDivider.vue'; import sectionDivider from '@/components/sectionDivider.vue';
import cardWithTopImage from '@/components/cardWithTopImage.vue'; import cardWithTopImage from '@/components/cardWithTopImage.vue';
import { RatingModel } from '@/data/models/ratingModel'; import { calcRating } from '@/scripts/showsScripts';
import OutlinedButton from '@/components/outlinedButton.vue';
import router from '@/plugins/router';
const showStore = useShowStore() const showStore = useShowStore()
function calcRating(ratings: Array<RatingModel>) {
let sum = 0
for (let rating of ratings) {
sum += rating.rating
}
return sum / ratings.length
}
</script> </script>
<template> <template>
@@ -24,7 +16,7 @@ function calcRating(ratings: Array<RatingModel>) {
<v-container> <v-container>
<v-row> <v-row>
<v-col> <v-col>
<section-divider title="Top Tours" /> <section-divider :title="$t('shows.topEvents')" />
</v-col> </v-col>
</v-row> </v-row>
@@ -41,7 +33,20 @@ function calcRating(ratings: Array<RatingModel>) {
<v-row> <v-row>
<v-col> <v-col>
<section-divider title="Top Bands" /> <outlined-button
append-icon="mdi-chevron-right"
@click="router.push('/shows/events')"
block
>
{{ $t('menu.allEvents') }}
</outlined-button>
</v-col>
</v-row>
<v-row>
<v-col>
<section-divider :title="$t('shows.topBands')" />
</v-col> </v-col>
</v-row> </v-row>
@@ -69,21 +74,46 @@ function calcRating(ratings: Array<RatingModel>) {
<v-row> <v-row>
<v-col> <v-col>
<section-divider title="Top Locations" /> <outlined-button
append-icon="mdi-chevron-right"
@click="router.push('/shows/bands')"
block
>
{{ $t('menu.allBands') }}
</outlined-button>
</v-col>
</v-row>
<v-row>
<v-col>
<section-divider :title="$t('shows.topLocations')" />
</v-col> </v-col>
</v-row> </v-row>
<v-row> <v-row>
<v-col v-for="location in showStore.locations" cols="3"> <v-col v-for="i in 4" cols="3">
<card-with-top-image <card-with-top-image
:image="'locations/' + location.image" :image="'locations/' + showStore.locations[i + 2].image"
:title="location.name" :title="showStore.locations[i + 2].name"
> >
{{ location.address }} <div>{{ showStore.locations[i + 2].address }}</div>
{{ location.city.name }}, {{ location.city.country }} {{ showStore.locations[i + 2].city.name }}, {{ showStore.locations[i + 2].city.country }}
</card-with-top-image> </card-with-top-image>
</v-col> </v-col>
</v-row> </v-row>
<v-row>
<v-col>
<outlined-button
append-icon="mdi-chevron-right"
@click="router.push('/shows/locations')"
block
>
{{ $t('menu.allLocations') }}
</outlined-button>
</v-col>
</v-row>
</v-container> </v-container>
</template> </template>

View File

@@ -0,0 +1,42 @@
<script setup lang="ts">
import sectionDivider from '@/components/sectionDivider.vue';
import { useShowStore } from '@/data/stores/showStore';
import cardWithTopImage from '@/components/cardWithTopImage.vue';
import { calcRating } from '@/scripts/showsScripts';
const showStore = useShowStore()
</script>
<template>
<v-container>
<div v-for="genre in showStore.genres">
<v-row>
<v-col>
<section-divider
:title="genre.name"
/>
</v-col>
</v-row>
<v-row>
<v-col v-for="band in genre.bands" cols="3">
<card-with-top-image
:image="'bands/' + band.images[0]"
:title="band.name"
>
<div class="d-flex justify-center pt-3">
<v-rating
density="compact"
readonly
size="large"
half-increments
active-color="orange"
:model-value="calcRating(band.ratings)"
/>
</div>
</card-with-top-image>
</v-col>
</v-row>
</div>
</v-container>
</template>

View File

@@ -1,18 +0,0 @@
<script setup lang="ts">
import sectionDivider from '@/components/sectionDivider.vue';
import { useShowStore } from '@/data/stores/showStore';
const showStore = useShowStore()
</script>
<template>
<v-container>
<div v-for="genre in showStore.genres">
<v-row>
<v-col>
<section-divider :title="genre.name" />
</v-col>
</v-row>
</div>
</v-container>
</template>

View File

@@ -13,7 +13,6 @@ const showStore = useShowStore()
<v-col> <v-col>
<section-divider <section-divider
:title="city.name" :title="city.name"
:image="'cities/' + city.image"
/> />
</v-col> </v-col>
</v-row> </v-row>

View File

@@ -13,48 +13,22 @@ const vuetify = createVuetify({
theme: { theme: {
defaultTheme: 'dark', defaultTheme: 'dark',
themes: { themes: {
darkRed: { dark: {
dark: true,
colors: {
primary: colors.red.darken1,
secondary: colors.red.lighten2
}
},
lightRed: {
dark: false,
colors: {
primary: colors.red.darken1,
secondary: colors.red.darken4
}
},
darkBlue: {
dark: true, dark: true,
colors: { colors: {
primary: colors.blue.darken4, primary: colors.blue.darken4,
secondary: colors.blue.lighten2 secondary: colors.blue.lighten2,
sheet: colors.grey.darken4
} }
}, },
lightBlue: { light: {
dark: false, dark: false,
colors: { colors: {
primary: colors.blue.darken1, primary: colors.blue.darken4,
secondary: colors.blue.darken4 secondary: colors.blue.darken2,
sheet: colors.grey.lighten3
} }
}, },
darkGreen: {
dark: true,
colors: {
primary: colors.green.darken1,
secondary: colors.green.lighten2
}
},
lightGreen: {
dark: false,
colors: {
primary: colors.green.darken1,
secondary: colors.green.darken4
}
}
} }
} }
}) })

View File

@@ -1,11 +1,11 @@
import EventsPage from "@/pages/shows/eventsPage/index.vue"; import EventsPage from "@/pages/shows/eventsPage/index.vue";
import GenresPage from "@/pages/shows/genresPage/index.vue"; import BandsPage from "@/pages/shows/bandsPage/index.vue";
import LocationsPage from "@/pages/shows/locationsPage/index.vue" import LocationsPage from "@/pages/shows/locationsPage/index.vue"
import SearchPage from "@/pages/shows/searchPage/index.vue" import SearchPage from "@/pages/shows/searchPage/index.vue"
export const showRoutes = [ export const showRoutes = [
{ path: '/shows/events', component: EventsPage }, { path: '/shows/events', component: EventsPage },
{ path: '/shows/genres', component: GenresPage }, { path: '/shows/bands', component: BandsPage },
{ path: '/shows/locations', component: LocationsPage }, { path: '/shows/locations', component: LocationsPage },
{ path: '/shows/search', component: SearchPage }, { path: '/shows/search', component: SearchPage },
] ]

View File

@@ -1,3 +1,5 @@
import { RatingModel } from "@/data/models/ratingModel"
/** /**
* Calculate a price based on parameters * Calculate a price based on parameters
* *
@@ -10,3 +12,20 @@
export function calcPrice(price: number, discount: number = 0, quantity: number = 1): number { export function calcPrice(price: number, discount: number = 0, quantity: number = 1): number {
return Math.round(quantity * price * ((100 - discount) / 100) * 100) / 100 return Math.round(quantity * price * ((100 - discount) / 100) * 100) / 100
} }
/**
* Calculate the average of an Array of ratings
*
* @param ratings Array of ratings
*
* @returns Average rating as number
*/
export function calcRating(ratings: Array<RatingModel>) {
let sum = 0
for (let rating of ratings) {
sum += rating.rating
}
return sum / ratings.length
}