Skeleton loader

This commit is contained in:
2024-10-04 13:16:05 +02:00
parent ed4fa90f75
commit 0cf0c6be76
20 changed files with 458 additions and 286 deletions

View File

@@ -7,13 +7,13 @@
"descriptionEn": "The Red Hot Chili Peppers are an American rock band formed in Los Angeles in 1983, comprising vocalist Anthony Kiedis, bassist Flea, drummer Chad Smith, and guitarist John Frusciante. Their music incorporates elements of alternative rock, funk, punk rock, hard rock, hip hop, and psychedelic rock. Their eclectic range has influenced genres such as funk metal, rap metal, rap rock, and nu metal. With over 120 million records sold worldwide, the Red Hot Chili Peppers are one of the top-selling bands of all time.",
"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",
"red-hot-chili-peppers-2.jpg",
"red-hot-chili-peppers-3.jpg",
"red-hot-chili-peppers-4.jpg"
"bands/red-hot-chili-peppers-1.jpg",
"bands/red-hot-chili-peppers-2.jpg",
"bands/red-hot-chili-peppers-3.jpg",
"bands/red-hot-chili-peppers-4.jpg"
],
"imageMembers": "red-hot-chili-peppers-members.jpg",
"logo": "red-hot-chili-peppers-logo.png",
"imageMembers": "bands/red-hot-chili-peppers-members.jpg",
"logo": "bands/red-hot-chili-peppers-logo.png",
"genreId": [
0,
2,
@@ -23,22 +23,22 @@
{
"name": "Anthony Kiedis",
"bandId": 0,
"image": "anthony-kiedis.jpg"
"image": "artists/anthony-kiedis.jpg"
},
{
"name": "Flea",
"bandId": 0,
"image": "flea.jpg"
"image": "artists/flea.jpg"
},
{
"name": "Chad Smith",
"bandId": 0,
"image": "chad-smith.jpg"
"image": "artists/chad-smith.jpg"
},
{
"name": "John Frusciante",
"bandId": 0,
"image": "john-frusciante.jpg"
"image": "artists/john-frusciante.jpg"
}
],
"ratings": [
@@ -86,12 +86,12 @@
"descriptionEn": "Radiohead are an English rock band formed in Abingdon, Oxfordshire, in 1985. They comprise Thom Yorke (vocals, guitar, piano, keyboards); brothers Jonny Greenwood (guitar, keyboards, other instruments) and Colin Greenwood (bass); Ed O'Brien (guitar, backing vocals); and Philip Selway (drums, percussion). They have worked with the producer Nigel Godrich and the cover artist Stanley Donwood since 1994. Radiohead's experimental approach is credited with advancing the sound of alternative rock.",
"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.png",
"radiohead-2.jpg",
"radiohead-3.jpg"
"bands/radiohead-1.png",
"bands/radiohead-2.jpg",
"bands/radiohead-3.jpg"
],
"imageMembers": "radiohead-members.jpg",
"logo": "radiohead-logo.jpg",
"imageMembers": "bands/radiohead-members.jpg",
"logo": "bands/radiohead-logo.jpg",
"genreId": [
1,
2,
@@ -103,27 +103,27 @@
{
"name": "Thom Yorke",
"bandId": 1,
"image": "thom-yorke.jpg"
"image": "artists/thom-yorke.jpg"
},
{
"name": "Jonny Greenwood",
"bandId": 1,
"image": "jonny-greenwood.jpg"
"image": "artists/jonny-greenwood.jpg"
},
{
"name": "Colin Greenwood",
"bandId": 1,
"image": "colin-greenwood.jpg"
"image": "artists/colin-greenwood.jpg"
},
{
"name": "Ed O'Brien",
"bandId": 1,
"image": "ed-o-brien.jpg"
"image": "artists/ed-o-brien.jpg"
},
{
"name": "Philip Selway",
"bandId": 1,
"image": "philip-selway.jpg"
"image": "artists/philip-selway.jpg"
}
],
"ratings": [
@@ -146,12 +146,12 @@
"descriptionEn": "Arctic Monkeys are an English rock band formed in Sheffield in 2002. The group consists of lead singer Alex Turner, drummer Matt Helders, guitarist Jamie Cook and bassist Nick O'Malley. Former bassist Andy Nicholson left the band in 2006 shortly after their debut album, Whatever People Say I Am, That's What I'm Not, was released.",
"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",
"arctic-monkeys-3.jpg"
"bands/arctic-monkeys-1.jpg",
"bands/arctic-monkeys-2.jpg",
"bands/arctic-monkeys-3.jpg"
],
"imageMembers": "arctic-monkeys-members.jpg",
"logo": "arctic-monkeys-logo.png",
"imageMembers": "bands/arctic-monkeys-members.jpg",
"logo": "bands/arctic-monkeys-logo.png",
"genreId": [
2,
7,
@@ -161,27 +161,27 @@
{
"name": "Glyn Jones",
"bandId": 2,
"image": "glyn-jones.jpg"
"image": "artists/glyn-jones.jpg"
},
{
"name": "Alex Turner",
"bandId": 2,
"image": "alex-turner.jpg"
"image": "artists/alex-turner.jpg"
},
{
"name": "Jamie Cook",
"bandId": 2,
"image": "jamie-cook.jpg"
"image": "artists/jamie-cook.jpg"
},
{
"name": "Matt Helders",
"bandId": 2,
"image": "matt-helders.jpg"
"image": "artists/matt-helders.jpg"
},
{
"name": "Andy Nicholson",
"bandId": 2,
"image": "andy-nicholson.jpg"
"image": "artists/andy-nicholson.jpg"
}
],
"ratings": [
@@ -209,12 +209,12 @@
"descriptionEn": "Coldplay are a British rock band formed in London in 1997. They consist of vocalist and pianist Chris Martin, guitarist Jonny Buckland, bassist Guy Berryman, drummer and percussionist Will Champion, and manager Phil Harvey. They are best known for their live performances, and for impacting popular culture through their artistry, advocacy and achievements.",
"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",
"coldplay-2.jpg",
"coldplay-3.jpg"
"bands/coldplay-1.jpg",
"bands/coldplay-2.jpg",
"bands/coldplay-3.jpg"
],
"imageMembers": "coldplay-members.jpg",
"logo": "coldplay-logo.jpg",
"imageMembers": "bands/coldplay-members.jpg",
"logo": "bands/coldplay-logo.jpg",
"genreId": [
2,
9
@@ -223,27 +223,27 @@
{
"name": "Chris Martin",
"bandId": 3,
"image": "chris-martin.jpg"
"image": "artists/chris-martin.jpg"
},
{
"name": "Jonny Buckland",
"bandId": 3,
"image": "jonny-buckland.jpg"
"image": "artists/jonny-buckland.jpg"
},
{
"name": "Guy Berryman",
"bandId": 3,
"image": "guy-berryman.jpg"
"image": "artists/guy-berryman.jpg"
},
{
"name": "Will Champion",
"bandId": 3,
"image": "will-champion.jpg"
"image": "artists/will-champion.jpg"
},
{
"name": "Phil Harvey",
"bandId": 3,
"image": "phil-harvey.png"
"image": "artists/phil-harvey.png"
}
],
"ratings": [
@@ -266,12 +266,12 @@
"descriptionEn": "Foo Fighters is an American rock band formed in Seattle in 1994. Founded as a one-man project by former Nirvana drummer Dave Grohl, the lineup now consists of Grohl (lead vocals, guitar), Nate Mendel (bass), Chris Shiflett and Pat Smear (guitars), Rami Jaffee (keyboards), and Josh Freese (drums). Drummers William Goldsmith and Taylor Hawkins, along with guitarist Franz Stahl, are former members of the band.",
"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",
"foo-fighters-2.jpg",
"foo-fighters-3.jpg"
"bands/foo-fighters-1.jpg",
"bands/foo-fighters-2.jpg",
"bands/foo-fighters-3.jpg"
],
"imageMembers": "foo-fighters-members.jpg",
"logo": "foo-fighters-logo.png",
"imageMembers": "bands/foo-fighters-members.jpg",
"logo": "bands/foo-fighters-logo.png",
"genreId": [
2,
10
@@ -280,32 +280,32 @@
{
"name": "Dave Grohl",
"bandId": 4,
"image": "dave-grohl.jpg"
"image": "artists/dave-grohl.jpg"
},
{
"name": "Pat Smear",
"bandId": 4,
"image": "pat-smear.jpg"
"image": "artists/pat-smear.jpg"
},
{
"name": "Nate Mendel",
"bandId": 4,
"image": "nate-mendel.jpg"
"image": "artists/nate-mendel.jpg"
},
{
"name": "Chris Shiflett",
"bandId": 4,
"image": "chris-shiflett.jpg"
"image": "artists/chris-shiflett.jpg"
},
{
"name": "Rami Jaffee",
"bandId": 4,
"image": "rami-jaffee.jpg"
"image": "artists/rami-jaffee.jpg"
},
{
"name": "Josh Freese",
"bandId": 4,
"image": "josh-freese.jpg"
"image": "artists/josh-freese.jpg"
}
],
"ratings": [
@@ -323,12 +323,12 @@
"descriptionEn": "Billy Talent is a Canadian rock band from Mississauga, Ontario. They formed in 1993 with lead vocalist Benjamin Kowalewicz, guitarist Ian D'Sa, bassist Jonathan Gallant, and drummer Aaron Solowoniuk. There have been no lineup changes, although Solowoniuk has been on hiatus from the band since 2016 due to a relapse of multiple sclerosis. In the three decades since their inception, Billy Talent has sold well over a million physical albums in Canada alone and nearly 3 million albums internationally. During their most successful period, they were ranked as one of the top 10 best-selling native bands in Canada.",
"descriptionDe": "Billy Talent ist eine kanadische Rockband aus Mississauga, Ontario. Die Band spielte anfangs Punk, ordnet sich auf den späteren Alben jedoch eher im Alternative Rock ein. ",
"images": [
"billy-talent-1.jpg",
"billy-talent-2.jpg",
"billy-talent-3.jpg"
"bands/billy-talent-1.jpg",
"bands/billy-talent-2.jpg",
"bands/billy-talent-3.jpg"
],
"imageMembers": "billy-talent-members.jpg",
"logo": "billy-talent-logo.png",
"imageMembers": "bands/billy-talent-members.jpg",
"logo": "bands/billy-talent-logo.png",
"genreId": [
2,
11,
@@ -344,22 +344,22 @@
{
"name": "Ian D'Sa ",
"bandId": 5,
"image": "ian-d-sa.jpg"
"image": "artists/ian-d-sa.jpg"
},
{
"name": "Jonathan Gallant",
"bandId": 5,
"image": "jonathan-gallant.jpg"
"image": "artists/jonathan-gallant.jpg"
},
{
"name": "Jordan Hastings",
"bandId": 5,
"image": "jordan-hastings.jpg"
"image": "artists/jordan-hastings.jpg"
},
{
"name": "Josh Freese",
"bandId": 5,
"image": "josh-freese.jpg"
"image": "artists/josh-freese.jpg"
}
],
"ratings": [
@@ -387,12 +387,12 @@
"descriptionEn": "Royal Blood are an English rock duo formed in Littlehampton in 2011. The current lineup consists of Mike Kerr (vocals, bass guitar, piano) and Ben Thatcher (drums). Their signature sound is built around Kerr's bass playing style, which sees him using various effects pedals and amps to make his bass guitar sound like an electric guitar and bass guitar at the same time. The duo were signed by Warner Chappell Music in 2013 and have since released four studio albums: Royal Blood (2014), How Did We Get So Dark? (2017), Typhoons (2021), and Back to the Water Below (2023).",
"descriptionDe": "Royal Blood ist ein britisches Garage- und Bluesrock-Duo, das 2013 in Worthing gegründet wurde. Im Gegensatz zu herkömmlichen Rockbands besteht Royal Blood nur aus zwei Mitgliedern, dem Bassisten und Sänger Mike Kerr und dem Schlagzeuger Ben Thatcher. Durch die Verwendung mehrerer Effektpedale emuliert Kerr den Klang einer verzerrten E-Gitarre, wodurch das Fehlen eines Gitarristen kompensiert wird. ",
"images": [
"royal-blood-1.jpg",
"royal-blood-2.jpg",
"royal-blood-3.jpg"
"bands/royal-blood-1.jpg",
"bands/royal-blood-2.jpg",
"bands/royal-blood-3.jpg"
],
"imageMembers": "royal-blood-members.jpg",
"logo": "royal-blood-logo.jpg",
"imageMembers": "bands/royal-blood-members.jpg",
"logo": "bands/royal-blood-logo.jpg",
"genreId": [
8,
14
@@ -401,12 +401,12 @@
{
"name": "Mike Kerr",
"bandId": 6,
"image": "mike-kerr.jpg"
"image": "artists/mike-kerr.jpg"
},
{
"name": "Ben Thatcher",
"bandId": 6,
"image": "ben-thatcher.jpg"
"image": "artists/ben-thatcher.jpg"
}
],
"ratings": [
@@ -434,12 +434,12 @@
"descriptionEn": "Muse are an English rock band from Teignmouth, Devon, formed in 1994. The band consists of Matt Bellamy (lead vocals, guitar, keyboards), Chris Wolstenholme (bass guitar, backing vocals), and Dominic Howard (drums, percussion).",
"descriptionDe": "Muse ist eine britische Rockband, die 1994 in Teignmouth, England gegründet wurde. Die Band besteht aus Matthew Bellamy (Gesang, Gitarre, Klavier und Synthesizers), Chris Wolstenholme (E-Bass, Gesang, Synthesizer) und Dominic Howard (Schlagzeug und Perkussion). Muse verbindet stilistisch Alternative, Hard und Progressive Rock sowie Electronica mit Elementen klassischer Musik zu Rockballaden und wird dem Subgenre New Prog zugeordnet.",
"images": [
"muse-1.jpg",
"muse-2.jpg",
"muse-3.jpg"
"bands/muse-1.jpg",
"bands/muse-2.jpg",
"bands/muse-3.jpg"
],
"imageMembers": "muse-members.jpg",
"logo": "muse-logo.jpg",
"imageMembers": "bands/muse-members.jpg",
"logo": "bands/muse-logo.jpg",
"genreId": [
2,
15,
@@ -449,17 +449,17 @@
{
"name": "Matthew Bellamy",
"bandId": 7,
"image": "matthew-bellamy.jpg"
"image": "artists/matthew-bellamy.jpg"
},
{
"name": "Dominic Howard",
"bandId": 7,
"image": "dominic-howard.jpg"
"image": "artists/dominic-howard.jpg"
},
{
"name": "Chris Wolstenholme",
"bandId": 7,
"image": "chris-wolstenholme.jpg"
"image": "artists/chris-wolstenholme.jpg"
}
],
"ratings": [

View File

@@ -8,7 +8,7 @@
"id": 0,
"name": "Swiss Life Hall",
"address": "Ferdinand-Wilhelm-Fricke-Weg 8",
"image": "swiss-life-hall.jpg",
"image": "locations/swiss-life-hall.jpg",
"seatGroups": [
{
"name": "A",
@@ -57,7 +57,7 @@
"id": 1,
"name": "Capitol",
"address": "Schwarzer Bär 2",
"image": "capitol.jpg",
"image": "locations/capitol.jpg",
"seatGroups": [
{
"name": "A",
@@ -71,7 +71,7 @@
"id": 2,
"name": "ZAG Arena",
"address": "EXPO-Plaza 7",
"image": "zag-arena.jpg",
"image": "locations/zag-arena.jpg",
"seatGroups": [
{
"name": "A",
@@ -120,7 +120,7 @@
"id": 3,
"name": "Kulturzentrum Faust",
"address": "Zur Bettfedernfabrik 3",
"image": "faust-hannover.jpg",
"image": "locations/faust-hannover.jpg",
"seatGroups": [
{
"name": "A",
@@ -140,7 +140,7 @@
"id": 4,
"name": "Olympiahalle München",
"address": "Spiridon-Louis-Ring 21",
"image": "olympiahalle-munich.jpg",
"image": "locations/olympiahalle-munich.jpg",
"seatGroups": [
{
"name": "A",
@@ -154,7 +154,7 @@
"id": 5,
"name": "Schlachthof München",
"address": "Zenettistraße 9",
"image": "schlachthof-munich.jpg",
"image": "locations/schlachthof-munich.jpg",
"seatGroups": [
{
"name": "A",
@@ -168,7 +168,7 @@
"id": 6,
"name": "Muffatwerk",
"address": "Zellstraße 4",
"image": "muffatwerk.jpg",
"image": "locations/muffatwerk.jpg",
"seatGroups": [
{
"name": "A",
@@ -188,7 +188,7 @@
"id": 7,
"name": "Elbphilharmonie Hamburg",
"address": "Platz der deutschen Einheit",
"image": "elbphilharmonie-hamburg.jpg",
"image": "locations/elbphilharmonie-hamburg.jpg",
"seatGroups": [
{
"name": "A",
@@ -202,7 +202,7 @@
"id": 8,
"name": "Volksparkstadion",
"address": "Sylvesterallee 7",
"image": "volksparkstadion-hamburg.jpg",
"image": "locations/volksparkstadion-hamburg.jpg",
"seatGroups": [
{
"name": "A",
@@ -216,7 +216,7 @@
"id": 9,
"name": "Barclays Arena",
"address": "Sylvesterallee 10",
"image": "barclays-arena.jpg",
"image": "locations/barclays-arena.jpg",
"seatGroups": [
{
"name": "A",
@@ -230,7 +230,7 @@
"id": 10,
"name": "Stage Theater im Hafen Hamburg",
"address": "Norderelbestraße 6",
"image": "stage-theater-hamburg.jpg",
"image": "locations/stage-theater-hamburg.jpg",
"seatGroups": [
{
"name": "A",
@@ -250,7 +250,7 @@
"id": 11,
"name": "Waldbühne Berlin",
"address": "Am Glockenturm",
"image": "waldbuehne-berlin.jpg",
"image": "locations/waldbuehne-berlin.jpg",
"seatGroups": [
{
"name": "A",
@@ -264,7 +264,7 @@
"id": 12,
"name": "Olympiastadion Berlin",
"address": "Olympischer Platz 3",
"image": "olympiastadion-berlin.jpg",
"image": "locations/olympiastadion-berlin.jpg",
"seatGroups": [
{
"name": "A",
@@ -278,7 +278,7 @@
"id": 13,
"name": "Uber Arena Berlin",
"address": "Uber-Platz 1",
"image": "uber-arena-berlin.jpg",
"image": "locations/uber-arena-berlin.jpg",
"seatGroups": [
{
"name": "A",
@@ -292,7 +292,7 @@
"id": 14,
"name": "Columbiahalle",
"address": "Columbiadamm 13-21",
"image": "columbiahalle.jpg",
"image": "locations/columbiahalle.jpg",
"seatGroups": [
{
"name": "A",
@@ -306,7 +306,7 @@
"id": 15,
"name": "Astra Kulturhaus",
"address": "Revaler Straße 99",
"image": "astra-kulturhaus.jpg",
"image": "locations/astra-kulturhaus.jpg",
"seatGroups": [
{
"name": "A",
@@ -320,7 +320,7 @@
"id": 16,
"name": "Deutsche Oper Berlin",
"address": "Bismarckstraße 35",
"image": "deutsche-oper-berlin.jpg",
"image": "locations/deutsche-oper-berlin.jpg",
"seatGroups": [
{
"name": "A",

View File

@@ -7,6 +7,7 @@ import { Band } from "../models/acts/band.model";
import { SeatGroup } from "../models/locations/seatGroup.model";
import { Seat } from "../models/locations/seat.model";
import { SeatRow } from "../models/locations/seatRow.model";
import { Op } from "sequelize";
export const location = Router()
@@ -51,3 +52,46 @@ location.get("/", (req: Request, res: Response) => {
res.status(200).json(locations)
})
})
location.get("/:name", (req: Request, res: Response) => {
console.log(req.params.name)
Location.findOne({
where: { name: { [Op.like]: req.params.name } },
include: [
City,
{
model: Concert,
include: [ Event ],
attributes: {
exclude: [ "locationId", "tourId" ]
}
},
{
model: SeatGroup,
include: [
{
model: SeatRow,
include: [ Seat ]
}
]
}
],
attributes: {
exclude: [ "cityId" ]
}
})
.then(async location => {
for (let concert of location.dataValues.concerts) {
let event = concert.dataValues.event
await Band.findByPk(event.dataValues.bandId)
.then(band => {
event.dataValues.bandName = band.dataValues.name
delete event.dataValues.bandId
})
}
res.status(200).json(location)
})
})

View File

@@ -30,7 +30,7 @@ app.use('/static', express.static(path.join(__dirname, 'images')))
// Add delay for more realistic response times
app.use((req, res, next) => {
setTimeout(next, Math.floor((Math.random () * 4000) + 100))
setTimeout(next, Math.floor((Math.random () * 2000) + 100))
})
// Routes

View File

@@ -5,7 +5,8 @@ defineProps({
link: {
type: Boolean,
default: true
}
},
loading: Boolean
})
</script>
@@ -16,21 +17,37 @@ defineProps({
>
<v-row>
<v-col cols="auto" class="pr-0">
<v-skeleton-loader
type="image"
:loading="loading"
width="140"
>
<v-img
:src="image"
aspect-ratio="1"
width="140"
cover
/>
</v-skeleton-loader>
</v-col>
<v-col class="pl-0" cols="7">
<v-skeleton-loader
:loading="loading"
type="heading"
>
<v-card-title v-if="title">
{{ title }}
</v-card-title>
</v-skeleton-loader>
<div class="px-4 pb-4" v-if="$slots.default">
<v-skeleton-loader
:loading="loading"
type="sentences"
>
<slot></slot>
</v-skeleton-loader>
</div>
</v-col>

View File

@@ -13,7 +13,8 @@ defineProps({
link: {
type: Boolean,
default: true
}
},
loading: Boolean
})
</script>
@@ -21,10 +22,16 @@ defineProps({
<v-card
variant="tonal"
:link="link"
>
<v-skeleton-loader
:loading="loading"
type="image"
height="200"
>
<v-img
:src="'http://localhost:3000/static/' + image"
aspect-ratio="1"
max-height="200"
cover
>
<template #error>
@@ -36,6 +43,12 @@ defineProps({
</template>
</v-img>
</v-skeleton-loader>
<v-skeleton-loader
:loading="loading"
type="heading"
>
<div v-if="title">
<v-card-title v-if="!smallerTitle">
{{ title }}
@@ -45,11 +58,16 @@ defineProps({
{{ title }}
</v-card-title>
</div>
</v-skeleton-loader>
<v-skeleton-loader
type="sentences"
:loading="loading"
>
<div class="px-4 pb-4" 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 />

View File

@@ -0,0 +1,52 @@
<script setup lang="ts">
import cardWithLeftImage from '../cardWithLeftImage.vue';
defineProps({
image: String,
title: String,
description: String,
price: String,
loading: Boolean
})
</script>
<template>
<v-row v-if="!loading">
<v-col>
<card-with-left-image
:title="title"
:image="'http://localhost:3000/static/tours/' + image"
>
<div class="text-body-1 font-weight-bold">
<div v-if="!$slots.description">
{{ description }}
</div>
<div v-else>
<slot name="description" />
</div>
</div>
<template #append>
<div>
<v-icon
icon="mdi-ticket"
color="secondary"
size="x-large"
/>
</div>
{{ price }}
</template>
</card-with-left-image>
</v-col>
</v-row>
<v-row v-else>
<v-col>
<card-with-left-image :loading="loading">
<v-skeleton-loader
type="text" />
</card-with-left-image>
</v-col>
</v-row>
</template>

View File

@@ -0,0 +1,57 @@
<script setup lang="ts">
import { useFeedbackStore } from '@/data/stores/feedbackStore';
defineProps({
image: String,
logo: String,
title: String,
chips: Array<String>,
description: String
})
</script>
<template>
<div class="position-relative top-0 left-0">
<v-img
:src="'http://localhost:3000/static/' + 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">
<v-row>
<v-col cols="2">
<v-card>
<v-img
v-if="logo"
:src="'http://localhost:3000/static/' + logo"
height="200"
aspect-ratio="1"
cover
/>
</v-card>
</v-col>
<v-col cols="auto">
<p class="text-h3">{{ title }}</p>
<div>
<v-chip
v-for="chip in chips"
class="mr-2 my-1"
variant="flat"
>
{{ chip }}
</v-chip>
</div>
<p class="text-h6" v-if="!$slots.description">{{ description }}</p>
<slot name="description"></slot>
</v-col>
</v-row>
</div>
</v-img>
</div>
</template>

View File

@@ -1,7 +1,8 @@
<script setup lang="ts">
defineProps({
title: String,
image: String
image: String,
loading: Boolean
})
</script>
@@ -37,7 +38,13 @@ defineProps({
</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">

View File

@@ -6,6 +6,6 @@ export async function getAllBands() {
return await axios.get(BASE_URL)
}
export async function getOneBand(id: number) {
return await axios.get(BASE_URL + '/' + id)
export async function getBand(bandName: string) {
return await axios.get(BASE_URL + '/' + bandName)
}

View File

@@ -5,3 +5,7 @@ let BASE_URL = "http://localhost:3000/locations"
export async function getAllLocations() {
return await axios.get(BASE_URL)
}
export async function getLocation(locationName: string) {
return await axios.get(BASE_URL + "/" + locationName)
}

View File

@@ -1,5 +1,5 @@
import { EventModel } from "./eventModel"
import { RatingModel } from "./ratingModel"
import { TourModel } from "./tourModel"
export class BandModel {
id: number
@@ -18,5 +18,5 @@ export class BandModel {
genres: Array<{
name: string
}>
tours: Array<TourModel>
events: Array<EventModel>
}

View File

@@ -12,13 +12,13 @@ export class LocationModel {
city: {
name: string
country: string
}
} = { name: "", country: "" }
concerts: Array<{
id: number
date: string
price: number
inStock: number
tour: {
event: {
name: string
offered: boolean
image: string

View File

@@ -33,16 +33,24 @@ export const useShoppingStore = defineStore("shoppingStore", {
},
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,51 +0,0 @@
<script setup lang="ts">
import { BandModel } from '@/data/models/acts/bandModel';
defineProps({
band: {
type: BandModel,
required: true
}
})
</script>
<template>
<div class="position-relative top-0 left-0">
<v-img
:src="'http://localhost:3000/static/bands/' + band.imageMembers"
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">
<v-row>
<v-col cols="2">
<v-card>
<v-img
:src="'http://localhost:3000/static/bands/' + band.logo"
height="200"
aspect-ratio="1"
cover
/>
</v-card>
</v-col>
<v-col>
<p class="text-h3">{{ band.name }}</p>
<div>
<v-chip
v-for="genre in band.genres"
class="mr-2 my-1"
variant="flat"
>
{{ genre.name }}
</v-chip>
</div>
<p class="text-h6">{{ band.descriptionDe }}</p>
</v-col>
</v-row>
</div>
</v-img>
</div>
</template>

View File

@@ -5,7 +5,6 @@ import sectionDivider from '@/components/sectionDivider.vue';
import cardWithLeftImage from '@/components/cardWithLeftImage.vue';
import outlinedButton from '@/components/outlinedButton.vue';
import { useRouter } from 'vue-router';
import ticketOrderDialog from './ticketOrderDialog.vue';
import { ref } from 'vue';
import { ConcertModel } from '@/data/models/acts/concertModel';
@@ -31,7 +30,7 @@ function openTicketOrderDialog(concert: ConcertModel) {
</v-col>
</v-row>
<v-row v-for="concert of band.tours[0].concerts">
<v-row v-for="concert of band.events[0].concerts">
<v-col>
<card-with-left-image
:title="dateStringToHumanReadableString(concert.date)"
@@ -84,6 +83,4 @@ function openTicketOrderDialog(concert: ConcertModel) {
</card-with-left-image>
</v-col>
</v-row>
<ticket-order-dialog />
</template>

View File

@@ -2,35 +2,49 @@
import { useConcertStore } from '@/data/stores/concertStore';
import { BandModel } from '@/data/models/acts/bandModel';
import { useRouter } from 'vue-router';
import bandBanner from './bandBanner.vue';
import ratingSection from './ratingSection.vue';
import bandMemberSection from './bandMemberSection.vue';
import gallerySection from './gallerySection.vue';
import concertSection from './concertSection.vue';
import heroImage from '@/components/pageParts/heroImage.vue';
import sectionDivider from '@/components/sectionDivider.vue';
import concertListItem from '@/components/pageParts/concertListItem.vue';
import { useShoppingStore } from '@/data/stores/shoppingStore';
import { ref } from 'vue';
const router = useRouter()
const shoppingStore = useShoppingStore()
const band = ref<BandModel>(new BandModel())
const concertStore = useConcertStore()
const band: BandModel = concertStore.bands.find(band =>
band.name.replaceAll(' ', '-').toLowerCase() == router.currentRoute.value.params.bandName
)
</script>
<template>
<band-banner :band="band" />
<hero-image
:image="band.imageMembers"
:logo="band.logo"
:title="band.name"
:chips="band.genres.map(genre => genre.name)"
:description="band.descriptionDe"
/>
<v-container>
<v-row>
<v-spacer />
<v-col cols="10">
<v-row>
<v-col>
<section-divider :title="$t('concert', 2)" />
</v-col>
</v-row>
<concert-section :band="band" />
<band-member-section :band="band" />
<!-- band-member-section :band="band" />
<rating-section :band="band" />
<gallery-section :band="band" />
<gallery-section :band="band" /> -->
</v-col>
<v-spacer />

View File

@@ -1,10 +1,10 @@
<script setup lang="ts">
import cardWithLeftImage from '@/components/cardWithLeftImage.vue';
import { createDateRangeString, lowestTicketPrice } from '@/scripts/concertScripts';
import filterBar from './filterBar.vue';
import { useRouter } from 'vue-router';
import { useShoppingStore } from '@/data/stores/shoppingStore';
import { useFeedbackStore } from '@/data/stores/feedbackStore';
import concertListItem from '@/components/pageParts/concertListItem.vue';
const router = useRouter()
const shoppingStore = useShoppingStore()
@@ -25,38 +25,25 @@ shoppingStore.getEvents()
</v-col>
</v-row>
<v-row v-if="feedbackStore.fetchDataFromServerInProgress">
<v-col class="text-center">
<v-progress-circular indeterminate :size="128" :width="12" color="primary" />
</v-col>
</v-row>
<concert-list-item
v-if="feedbackStore.fetchDataFromServerInProgress"
v-for="i in 3"
:loading="true"
/>
<v-row
<concert-list-item
v-else-if="shoppingStore.events.length > 0"
v-for="event of shoppingStore.events"
>
<v-col>
<card-with-left-image
:image="event.image"
:title="event.band.name + ' - ' + event.name"
:image="'http://localhost:3000/static/tours/' + event.image"
:price="$t('from') + ' ' + lowestTicketPrice(event) + ' €'"
@click="router.push('/bands/' + event.band.name.replaceAll(' ', '-').toLowerCase())"
>
<template #description>
{{ createDateRangeString(event) }}
<div>{{ event.concerts.length }} {{ $t('concert', event.concerts.length) }}</div>
<template #append>
<div>
<v-icon
icon="mdi-ticket"
color="secondary"
size="x-large"
/>
</div>
ab {{ lowestTicketPrice(event) }}
</template>
</card-with-left-image>
</v-col>
</v-row>
</concert-list-item>
<v-row v-else>
<v-col>

View File

@@ -1,39 +1,41 @@
<script setup lang="ts">
import { LocationModel } from '@/data/models/locations/locationModel';
import { useConcertStore } from '@/data/stores/concertStore';
import { useRouter } from 'vue-router';
import cardWithLeftImage from '@/components/cardWithLeftImage.vue';
import sectionDivider from '@/components/sectionDivider.vue';
import { dateStringToHumanReadableString } from '@/scripts/dateTimeScripts';
import seatPlanMap from '@/components/seatPlanMap/seatPlanMap.vue';
import { useShoppingStore } from '@/data/stores/shoppingStore';
import { getLocation } from '@/data/api/locationApi';
import { ref } from 'vue';
import { useFeedbackStore } from '@/data/stores/feedbackStore';
import heroImage from '@/components/pageParts/heroImage.vue';
import concertListItem from '@/components/pageParts/concertListItem.vue';
const router = useRouter()
const concertStore = useConcertStore()
const shoppingStore = useShoppingStore()
const feedbackStore = useFeedbackStore()
const location = ref<LocationModel>(new LocationModel())
const location: LocationModel = concertStore.locations.find(location =>
location.name.replaceAll(' ', '-').toLowerCase() == router.currentRoute.value.params.locationName
)
feedbackStore.fetchDataFromServerInProgress = true
getLocation(String(router.currentRoute.value.params.locationName).replaceAll('-', ' '))
.then(result => {
location.value = result.data
feedbackStore.fetchDataFromServerInProgress = false
})
</script>
<template>
<div class="position-relative top-0 left-0">
<v-img
:src="'http://localhost:3000/static/locations/' + location.image"
height="500"
gradient="to top, rgba(0, 0, 0, .9), rgba(255, 255, 255, 0.1)"
cover
<hero-image
:title="location.name"
:image="location.image"
:description="location.address + location.city.name"
>
<div class="position-absolute bottom-0 pa-5">
<v-row>
<v-col>
<p class="text-h3">{{ location.name }}</p>
<template #description>
<p class="text-h6">{{ location.address }}</p>
<p class="text-h6">{{ location.city.name }}</p>
</v-col>
</v-row>
</div>
</v-img>
</div>
</template>
</hero-image>
<v-container>
<v-row>
@@ -42,38 +44,25 @@ const location: LocationModel = concertStore.locations.find(location =>
<v-col cols="10">
<v-row>
<v-col>
<section-divider title="Konzerte" />
<section-divider :title="$t('concert', 2)" />
</v-col>
</v-row>
<v-row
v-if="location.concerts.length > 0"
<v-row v-if="feedbackStore.fetchDataFromServerInProgress" v-for="i in 3">
<v-col class="text-center">
<concert-list-item :loading="feedbackStore.fetchDataFromServerInProgress" />
</v-col>
</v-row>
<concert-list-item
v-else-if="location.concerts.length > 0"
v-for="concert of location.concerts"
>
<v-col>
<card-with-left-image
:title="concert.tour.bandName + ' - ' + concert.tour.name"
:image="'http://localhost:3000/static/tours/' + concert.tour.image"
@click="router.push('/bands/' + concert.tour.bandName.replaceAll(' ', '-').toLowerCase())"
>
<div class="text-h6">
{{ dateStringToHumanReadableString(concert.date) }}
</div>
<!-- <div>{{ concert.length }} {{ $t('concert', concert.tour.concerts.length) }}</div> -->
<template #append>
<div>
<v-icon
icon="mdi-ticket"
color="secondary"
size="x-large"
:image="concert.event.image"
:title="concert.event.bandName + ' - ' + concert.event.name"
:description="dateStringToHumanReadableString(concert.date)"
:onClick="() => router.push('/bands/' + concert.event.bandName.replaceAll(' ', '-').toLowerCase())"
:price="$t('from') + ' ' + concert.price.toFixed(2) + ' €'"
/>
</div>
{{ $t('from') }} {{ concert.price.toFixed(2) }}
</template>
</card-with-left-image>
</v-col>
</v-row>
<v-row v-else>
<v-col>
@@ -90,7 +79,13 @@ const location: LocationModel = concertStore.locations.find(location =>
</v-col>
</v-row>
<v-row>
<div v-if="feedbackStore.fetchDataFromServerInProgress">
<v-col class="text-center">
<v-progress-circular indeterminate :size="128" :width="12" color="primary" />
</v-col>
</div>
<v-row v-else>
<v-col>
<seat-plan-map
:seat-groups="location.seatGroups"

View File

@@ -1,11 +1,15 @@
<script setup lang="ts">
import sectionDivider from '@/components/sectionDivider.vue';
import { useConcertStore } from '@/data/stores/concertStore';
import cardWithTopImage from '@/components/cardWithTopImage.vue';
import { useRouter } from 'vue-router';
import { useShoppingStore } from '@/data/stores/shoppingStore';
import { useFeedbackStore } from '@/data/stores/feedbackStore';
const concertStore = useConcertStore()
const shoppingStore = useShoppingStore()
const feedbackStore = useFeedbackStore()
const router = useRouter()
shoppingStore.getCities()
</script>
<template>
@@ -14,7 +18,26 @@ const router = useRouter()
<v-spacer />
<v-col cols="10">
<div v-for="city in concertStore.cities">
<!-- During fetching -->
<div v-if="feedbackStore.fetchDataFromServerInProgress" v-for="i in 2">
<v-row>
<v-col>
<section-divider :loading="true" />
</v-col>
</v-row>
<v-row >
<v-col class="text-center" v-for="i in 4" cols="3">
<card-with-top-image :loading="true" />
</v-col>
</v-row>
</div>
<!-- When all data are downloaded -->
<div
v-else
v-for="city in shoppingStore.cities"
>
<v-row>
<v-col>
<section-divider
@@ -26,7 +49,7 @@ const router = useRouter()
<v-row>
<v-col v-for="location in city.locations" cols="3">
<card-with-top-image
:image="'locations/' + location.image"
:image="location.image"
:title="location.name"
@click="router.push('locations/' + location.name.replaceAll(' ', '-').toLowerCase())"
>