Creating whole Band details page
This commit is contained in:
BIN
software/backend/images/artists/alex-turner.jpg
Normal file
BIN
software/backend/images/artists/alex-turner.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
BIN
software/backend/images/artists/andy-nicholson.jpg
Normal file
BIN
software/backend/images/artists/andy-nicholson.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
BIN
software/backend/images/artists/unknown-artist.jpg
Normal file
BIN
software/backend/images/artists/unknown-artist.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 18 KiB |
BIN
software/backend/images/bands/red-hot-chili-peppers-2.jpg
Normal file
BIN
software/backend/images/bands/red-hot-chili-peppers-2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 356 KiB |
@@ -3,13 +3,54 @@ import { Band } from "../models/acts/band.model";
|
|||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import { Rating } from "../models/acts/rating.model";
|
import { Rating } from "../models/acts/rating.model";
|
||||||
import { Genre } from "../models/acts/genre.model";
|
import { Genre } from "../models/acts/genre.model";
|
||||||
|
import { Tour } from "../models/acts/tour.model";
|
||||||
|
import { Concert } from "../models/acts/concert.model";
|
||||||
|
import { Location } from "../models/acts/location.model";
|
||||||
|
import { City } from "../models/acts/city.model";
|
||||||
|
|
||||||
export const band = Router()
|
export const band = Router()
|
||||||
|
|
||||||
// Get all bands
|
// Get all bands
|
||||||
band.get("/", (req: Request, res: Response) => {
|
band.get("/", (req: Request, res: Response) => {
|
||||||
Band.findAll({
|
Band.findAll({
|
||||||
include: [ Genre, Rating ]
|
include: [
|
||||||
|
{
|
||||||
|
model: Member,
|
||||||
|
attributes: {
|
||||||
|
exclude: [ "id", "bandId" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Rating,
|
||||||
|
attributes: {
|
||||||
|
exclude: [ "id", "bandId" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
model: Tour,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Concert,
|
||||||
|
include: [
|
||||||
|
{
|
||||||
|
model: Location,
|
||||||
|
include: [ City ],
|
||||||
|
attributes: {
|
||||||
|
exclude: [ "id" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
attributes: {
|
||||||
|
exclude: [ "id", "tourId", "locationId" ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
attributes: {
|
||||||
|
exclude: [ "id", "bandId" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Genre
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.then(bands => {
|
.then(bands => {
|
||||||
res.status(200).json(bands)
|
res.status(200).json(bands)
|
||||||
|
|||||||
@@ -1,21 +1,30 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps({
|
defineProps({
|
||||||
image: String,
|
image: String,
|
||||||
title: String
|
title: String,
|
||||||
|
link: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<v-card
|
<v-card
|
||||||
variant="tonal"
|
variant="tonal"
|
||||||
link
|
:link="link"
|
||||||
>
|
>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="auto" class="pr-0">
|
<v-col cols="auto" class="pr-0">
|
||||||
<v-img :src="image" aspect-ratio="1" width="140" cover />
|
<v-img
|
||||||
|
:src="image"
|
||||||
|
aspect-ratio="1"
|
||||||
|
width="140"
|
||||||
|
cover
|
||||||
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col class="pl-0">
|
<v-col class="pl-0" cols="7">
|
||||||
<v-card-title v-if="title">
|
<v-card-title v-if="title">
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</v-card-title>
|
</v-card-title>
|
||||||
@@ -25,7 +34,16 @@ defineProps({
|
|||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-col cols="2" height="100%">
|
<v-spacer />
|
||||||
|
|
||||||
|
<v-divider vertical height="100%" color="blue"/>
|
||||||
|
|
||||||
|
<v-col
|
||||||
|
cols="2"
|
||||||
|
height="100%"
|
||||||
|
style="flex-wrap: nowrap; align-self: center;"
|
||||||
|
class="text-h5 text-center mr-3"
|
||||||
|
>
|
||||||
<slot name="append"></slot>
|
<slot name="append"></slot>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
defineProps({
|
defineProps({
|
||||||
image: String,
|
image: String,
|
||||||
|
errorImage: {
|
||||||
|
type: String,
|
||||||
|
default: "artists/unknown-artist.jpg"
|
||||||
|
},
|
||||||
title: String,
|
title: String,
|
||||||
smallerTitle: {
|
smallerTitle: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@@ -19,7 +23,15 @@ defineProps({
|
|||||||
aspect-ratio="1"
|
aspect-ratio="1"
|
||||||
style="background-color: aliceblue;"
|
style="background-color: aliceblue;"
|
||||||
cover
|
cover
|
||||||
/>
|
>
|
||||||
|
<template #error>
|
||||||
|
<v-img
|
||||||
|
:src="'http://localhost:3000/static/' + errorImage"
|
||||||
|
aspect-ratio="1"
|
||||||
|
style="background-color: aliceblue;"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</v-img>
|
||||||
|
|
||||||
<div v-if="title">
|
<div v-if="title">
|
||||||
<v-card-title v-if="!smallerTitle">
|
<v-card-title v-if="!smallerTitle">
|
||||||
|
|||||||
@@ -21,19 +21,6 @@
|
|||||||
<v-divider vertical />
|
<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-divider vertical />
|
|
||||||
|
|
||||||
|
|
||||||
<v-btn
|
<v-btn
|
||||||
variant="text"
|
variant="text"
|
||||||
to="/shows/locations"
|
to="/shows/locations"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { RatingModel } from "./ratingModel"
|
import { RatingModel } from "./ratingModel"
|
||||||
|
import { TourModel } from "./tourModel"
|
||||||
|
|
||||||
export class BandModel {
|
export class BandModel {
|
||||||
id: number
|
id: number
|
||||||
@@ -16,4 +17,5 @@ export class BandModel {
|
|||||||
genres: Array<{
|
genres: Array<{
|
||||||
name: string
|
name: string
|
||||||
}>
|
}>
|
||||||
|
tours: Array<TourModel>
|
||||||
}
|
}
|
||||||
@@ -5,8 +5,9 @@ import sectionDivider from '@/components/sectionDivider.vue';
|
|||||||
import cardWithTopImage from '@/components/cardWithTopImage.vue';
|
import cardWithTopImage from '@/components/cardWithTopImage.vue';
|
||||||
import { calcRating, lowestTicketPrice } from '@/scripts/concertScripts';
|
import { calcRating, lowestTicketPrice } from '@/scripts/concertScripts';
|
||||||
import OutlinedButton from '@/components/outlinedButton.vue';
|
import OutlinedButton from '@/components/outlinedButton.vue';
|
||||||
import router from '@/plugins/router';
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
const concertStore = useConcertStore()
|
const concertStore = useConcertStore()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -44,48 +45,6 @@ const concertStore = useConcertStore()
|
|||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
|
|
||||||
<v-row>
|
|
||||||
<v-col>
|
|
||||||
<section-divider :title="$t('shows.topBands')" />
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row>
|
|
||||||
<v-col v-for="i in 4" cols="3">
|
|
||||||
<card-with-top-image
|
|
||||||
:image="'bands/' + concertStore.bands[i - 1].logo"
|
|
||||||
:title="concertStore.bands[i - 1].name"
|
|
||||||
>
|
|
||||||
{{ concertStore.bands[i - 1].genres.name }}
|
|
||||||
|
|
||||||
<div class="d-flex justify-center pt-3">
|
|
||||||
<v-rating
|
|
||||||
density="compact"
|
|
||||||
readonly
|
|
||||||
size="large"
|
|
||||||
half-increments
|
|
||||||
active-color="orange"
|
|
||||||
:model-value="calcRating(concertStore.bands[i - 1].ratings)"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</card-with-top-image>
|
|
||||||
</v-col>
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<v-row>
|
|
||||||
<v-col>
|
|
||||||
<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-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
<section-divider :title="$t('shows.topLocations')" />
|
<section-divider :title="$t('shows.topLocations')" />
|
||||||
|
|||||||
@@ -1,6 +1,191 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useConcertStore } from '@/data/stores/concertStore';
|
||||||
|
import { BandModel } from '@/data/models/acts/bandModel';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
import sectionDivider from '@/components/sectionDivider.vue';
|
||||||
|
import cardWithTopImage from '@/components/cardWithTopImage.vue';
|
||||||
|
import cardWithLeftImage from '@/components/cardWithLeftImage.vue';
|
||||||
|
import outlinedButton from '@/components/outlinedButton.vue';
|
||||||
|
import { dateStringToHumanReadableString } from '@/scripts/dateTimeScripts';
|
||||||
|
import { calcRating, calcRatingValues } from '@/scripts/concertScripts';
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const concertStore = useConcertStore()
|
||||||
|
const band: BandModel = concertStore.bands.find(band =>
|
||||||
|
band.name.replaceAll(' ', '-').toLowerCase() == router.currentRoute.value.params.bandName
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
Tour Detail
|
<div class="position-relative top-0 left-0">
|
||||||
|
<v-img
|
||||||
|
:src="'http://localhost:3000/static/bands/' + band.images[0]"
|
||||||
|
height="600"
|
||||||
|
cover
|
||||||
|
gradient="to top, rgba(0, 0, 0, .8), rgba(255, 255, 255, 0.1)"
|
||||||
|
>
|
||||||
|
<div class="position-absolute bottom-0 pa-5">
|
||||||
|
<p class="text-h3">{{ band.name }}</p>
|
||||||
|
<p class="text-h6">{{ band.descriptionDe }}</p>
|
||||||
|
</div>
|
||||||
|
</v-img>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-spacer />
|
||||||
|
|
||||||
|
<v-col cols="10">
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<section-divider title="Band Mitglieder" />
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col v-for="member of band.members">
|
||||||
|
<card-with-top-image
|
||||||
|
:title="member.name"
|
||||||
|
:image="'artists/' + member.image"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<section-divider title="Konzerte" />
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row v-for="concert of band.tours[0].concerts">
|
||||||
|
<v-col>
|
||||||
|
<card-with-left-image
|
||||||
|
:title="dateStringToHumanReadableString(concert.date)"
|
||||||
|
:image="'http://localhost:3000/static/locations/' + concert.location.image"
|
||||||
|
:link="false"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{{ concert.location.name }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{{ concert.location.address }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{{ concert.location.city.name }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #append>
|
||||||
|
<div class="pb-3">
|
||||||
|
{{ concert.price.toFixed(2) }} €
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<outlined-button
|
||||||
|
prepend-icon="mdi-basket-plus"
|
||||||
|
>
|
||||||
|
Hinzufügen
|
||||||
|
</outlined-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</card-with-left-image>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<section-divider title="Bewertungen" />
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<div class="d-flex align-center justify-center flex-column" style="height: 100%;">
|
||||||
|
<div class="text-h2 mt-5">
|
||||||
|
{{ calcRating(band.ratings).toFixed(1) }}
|
||||||
|
<span class="text-h6 ml-n3">/5</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-rating
|
||||||
|
:model-value="calcRating(band.ratings)"
|
||||||
|
color="yellow-darken-3"
|
||||||
|
half-increments
|
||||||
|
size="x-large"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="px-3">{{ band.ratings.length }} Bewertungen</div>
|
||||||
|
</div>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-col>
|
||||||
|
<v-list>
|
||||||
|
<v-list-item v-for="ratingValue in calcRatingValues(band.ratings)">
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<span>{{ ratingValue.value }}</span>
|
||||||
|
<v-icon class="ml-3 mr-n3" icon="mdi-star" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<v-progress-linear
|
||||||
|
:model-value="(ratingValue.count / band.ratings.length) * 100"
|
||||||
|
height="20"
|
||||||
|
color="yellow-darken-3"
|
||||||
|
rounded
|
||||||
|
/>
|
||||||
|
|
||||||
|
<template v-slot:append>
|
||||||
|
<span class="d-flex justify-end" style="width: 25px;"> {{ ratingValue.count }} </span>
|
||||||
|
</template>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<section-divider title="Fotos" />
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<v-carousel
|
||||||
|
show-arrows
|
||||||
|
hide-delimiter-background
|
||||||
|
hide-delimiters
|
||||||
|
height="900"
|
||||||
|
>
|
||||||
|
<template #prev="{ props }">
|
||||||
|
<v-btn
|
||||||
|
variant="text"
|
||||||
|
@click="props.onClick"
|
||||||
|
icon="mdi-chevron-left"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #next="{ props }">
|
||||||
|
<v-btn
|
||||||
|
variant="text"
|
||||||
|
@click="props.onClick"
|
||||||
|
icon="mdi-chevron-right"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<v-carousel-item
|
||||||
|
v-for="image in band.images"
|
||||||
|
:src="'http://localhost:3000/static/bands/' + image"
|
||||||
|
cover
|
||||||
|
/>
|
||||||
|
</v-carousel>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-spacer />
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import sectionDivider from '@/components/sectionDivider.vue';
|
|
||||||
import { useConcertStore } from '@/data/stores/concertStore';
|
|
||||||
import cardWithTopImage from '@/components/cardWithTopImage.vue';
|
|
||||||
import { calcRating } from '@/scripts/concertScripts';
|
|
||||||
|
|
||||||
const concertStore = useConcertStore()
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<v-container>
|
|
||||||
<div v-for="genre in concertStore.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>
|
|
||||||
@@ -3,7 +3,9 @@ import cardWithLeftImage from '@/components/cardWithLeftImage.vue';
|
|||||||
import { useConcertStore } from '@/data/stores/concertStore';
|
import { useConcertStore } from '@/data/stores/concertStore';
|
||||||
import { createDateRangeString, lowestTicketPrice } from '@/scripts/concertScripts';
|
import { createDateRangeString, lowestTicketPrice } from '@/scripts/concertScripts';
|
||||||
import filterBar from './filterBar.vue';
|
import filterBar from './filterBar.vue';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
const concertStore = useConcertStore()
|
const concertStore = useConcertStore()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -27,14 +29,13 @@ const concertStore = useConcertStore()
|
|||||||
<card-with-left-image
|
<card-with-left-image
|
||||||
:title="tour.band.name + ' - ' + tour.name"
|
:title="tour.band.name + ' - ' + tour.name"
|
||||||
:image="'http://localhost:3000/static/tours/' + tour.image"
|
:image="'http://localhost:3000/static/tours/' + tour.image"
|
||||||
|
@click="router.push('/shows/band/' + tour.band.name.replaceAll(' ', '-').toLowerCase())"
|
||||||
>
|
>
|
||||||
{{ createDateRangeString(tour) }}
|
{{ createDateRangeString(tour) }}
|
||||||
<div>{{ tour.concerts.length }} {{ $t('tours.concert', tour.concerts.length) }}</div>
|
<div>{{ tour.concerts.length }} {{ $t('tours.concert', tour.concerts.length) }}</div>
|
||||||
|
|
||||||
<template #append>
|
<template #append>
|
||||||
<div class="d-flex justify-center align-center text-h5" style="height: 100%;">
|
ab {{ lowestTicketPrice(tour) }} €
|
||||||
ab {{ lowestTicketPrice(tour) }} €
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
</card-with-left-image>
|
</card-with-left-image>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import ToursPage from "@/pages/shows/toursPage/index.vue";
|
import ToursPage from "@/pages/shows/toursPage/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"
|
||||||
|
import BandDetailPage from "@/pages/shows/bandDetailPage/index.vue"
|
||||||
|
|
||||||
export const showRoutes = [
|
export const showRoutes = [
|
||||||
{ path: '/shows/tours', component: ToursPage },
|
{ path: '/shows/tours', component: ToursPage },
|
||||||
{ 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 },
|
||||||
|
{ path: '/shows/band/:bandName', component: BandDetailPage }
|
||||||
]
|
]
|
||||||
@@ -32,6 +32,22 @@ export function calcRating(ratings: Array<RatingModel>) {
|
|||||||
return sum / ratings.length
|
return sum / ratings.length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function calcRatingValues(ratings: Array<RatingModel>) {
|
||||||
|
let ratingValues = [
|
||||||
|
{ value: 1, count: 0 },
|
||||||
|
{ value: 2, count: 0 },
|
||||||
|
{ value: 3, count: 0 },
|
||||||
|
{ value: 4, count: 0 },
|
||||||
|
{ value: 5, count: 0 }
|
||||||
|
]
|
||||||
|
|
||||||
|
for (let rating of ratings) {
|
||||||
|
ratingValues[rating.rating - 1].count += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return ratingValues
|
||||||
|
}
|
||||||
|
|
||||||
export function createDateRangeString(tour: TourModel) {
|
export function createDateRangeString(tour: TourModel) {
|
||||||
const dateArray = []
|
const dateArray = []
|
||||||
|
|
||||||
|
|||||||
@@ -3,3 +3,7 @@ export function dateToHumanReadableString(date: Date) {
|
|||||||
String(date.getMonth() + 1).padStart(2, '0') + '.' +
|
String(date.getMonth() + 1).padStart(2, '0') + '.' +
|
||||||
date.getFullYear()
|
date.getFullYear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function dateStringToHumanReadableString(string: string) {
|
||||||
|
return dateToHumanReadableString(new Date(string))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user