More skelton loader, add optional parameters to /locations and /events

This commit is contained in:
2024-10-04 15:20:40 +02:00
parent e2f6fb9c52
commit bfffd72a4a
16 changed files with 106 additions and 48 deletions

View File

@@ -53,7 +53,7 @@ The application host it's data in a SQLite database. The access is managed by an
#### Listing existing #### Listing existing
<details> <details>
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/events?city=cityName&genre=genreName</b></code> <code> (Get all events, filtered by city and genre)</code> <summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/events?city=cityName&genre=genreName&count=nrOfItems&sort=sortDirection</b></code> <code> (Get all events, filtered by city and genre)</code>
</summary> </summary>
##### Parameters ##### Parameters
@@ -61,16 +61,31 @@ The application host it's data in a SQLite database. The access is managed by an
> | :---: | --- | --- | --- | > | :---: | --- | --- | --- |
> | `cityName` | optional | string | Name of the city to filter for | > | `cityName` | optional | string | Name of the city to filter for |
> | `genreName` | optional | string | Name of the genre to filter for | > | `genreName` | optional | string | Name of the genre to filter for |
> | `nrOfItems` | optional | number | Limits number of results |
> | `sortDirection` | optional | string | Sort by number of concerts, 'asc' or 'desc' |
##### Responses ##### Responses
> | http code | content-type | response | > | http code | content-type | response |
> | :---: | --- | --- | > | :---: | --- | --- |
> | `200` | `application/json` | `Event` + `Array<Concert + Location>` + `Array<Band>` | > | `200` | `application/json` | `Array<Event + Array<Concert + Location + City> + Band & Genre>` |
</details> </details>
<details>
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/locations?count=nrOfItems&sort=sortDirection</b></code> <code> (Get all locations)</code>
</summary>
##### Parameters
> | name | type | data type | description |
> | :---: | --- | --- | --- |
> | `nrOfItems` | optional | number | Limits number of results |
> | `sortDirection` | optional | string | Sort by number of concerts, 'asc' or 'desc' |
##### Responses
> | http code | content-type | response |
> | :---: | --- | --- |
> | `200` | `application/json` | `Array<Location + City + Array<Concert + Event>>` |
</details>
Down here: todo! Down here: todo!
@@ -156,18 +171,7 @@ Down here: todo!
<details>
<summary><code><span style="color:#70AFFD"><b>GET</b></span></code> <code><b>/locations</b></code> <code> (Get all locations)</code>
</summary>
##### Parameters
> None
##### Responses
> | http code | content-type | response |
> | :---: | --- | --- |
> | `200` | `application/json` | `Array<Location>` + `City` |
</details>

View File

@@ -5,7 +5,7 @@
"name": "Unlimited Love", "name": "Unlimited Love",
"bandId": 0, "bandId": 0,
"offered": true, "offered": true,
"image": "unlimited-love-tour.jpg", "image": "events/unlimited-love-tour.jpg",
"concerts": [ "concerts": [
{ {
"id": 0, "id": 0,
@@ -49,7 +49,7 @@
"name": "The Bends", "name": "The Bends",
"bandId": 1, "bandId": 1,
"offered": true, "offered": true,
"image": "the-bends-tour.jpg", "image": "events/the-bends-tour.jpg",
"concerts": [ "concerts": [
{ {
"id": 5, "id": 5,
@@ -79,7 +79,7 @@
"name": "European Tour", "name": "European Tour",
"bandId": 2, "bandId": 2,
"offered": true, "offered": true,
"image": "european-tour-arctic-monkeys.jpg", "image": "events/european-tour-arctic-monkeys.jpg",
"concerts": [ "concerts": [
{ {
"id": 8, "id": 8,
@@ -102,7 +102,7 @@
"name": "Music of the Spheres", "name": "Music of the Spheres",
"bandId": 3, "bandId": 3,
"offered": true, "offered": true,
"image": "music-of-the-spheres.png", "image": "events/music-of-the-spheres.png",
"concerts": [ "concerts": [
{ {
"id": 10, "id": 10,
@@ -132,7 +132,7 @@
"name": "But Here We Are Tour", "name": "But Here We Are Tour",
"bandId": 4, "bandId": 4,
"offered": true, "offered": true,
"image": "but-here-we-are.jpg", "image": "events/but-here-we-are.jpg",
"concerts": [ "concerts": [
{ {
"id": 13, "id": 13,
@@ -148,7 +148,7 @@
"name": "Crisis of Faith", "name": "Crisis of Faith",
"bandId": 5, "bandId": 5,
"offered": true, "offered": true,
"image": "crisis-of-faith-tour.jpg", "image": "events/crisis-of-faith-tour.jpg",
"concerts": [ "concerts": [
{ {
"id": 14, "id": 14,
@@ -171,7 +171,7 @@
"name": "Back to the Water Below", "name": "Back to the Water Below",
"bandId": 6, "bandId": 6,
"offered": true, "offered": true,
"image": "back-to-the-water-below.jpg", "image": "events/back-to-the-water-below.jpg",
"concerts": [ "concerts": [
{ {
"id": 16, "id": 16,
@@ -194,7 +194,7 @@
"name": "Will of the People Tour", "name": "Will of the People Tour",
"bandId": 7, "bandId": 7,
"offered": true, "offered": true,
"image": "will-of-the-people-tour.jpg", "image": "events/will-of-the-people-tour.jpg",
"concerts": [ "concerts": [
{ {
"id": 18, "id": 18,

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 336 KiB

After

Width:  |  Height:  |  Size: 336 KiB

View File

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 208 KiB

View File

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

View File

Before

Width:  |  Height:  |  Size: 492 KiB

After

Width:  |  Height:  |  Size: 492 KiB

View File

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 57 KiB

View File

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 113 KiB

View File

Before

Width:  |  Height:  |  Size: 250 KiB

After

Width:  |  Height:  |  Size: 250 KiB

View File

@@ -11,6 +11,8 @@ export const events = Router()
events.get("/", async (req: Request, res: Response) => { events.get("/", async (req: Request, res: Response) => {
let cityName = req.query.city let cityName = req.query.city
let genreName = req.query.genre let genreName = req.query.genre
let sort = req.query.sort
let count = req.query.count
let cityFilter = {} let cityFilter = {}
let genreFilter = {} let genreFilter = {}
@@ -44,14 +46,16 @@ events.get("/", async (req: Request, res: Response) => {
include: [ include: [
{ {
model: Location, model: Location,
required: true,
include: [ include: [
cityFilter cityFilter
] ]
} }
] ],
}, },
{ {
model: Band, model: Band,
required: true,
include: [ include: [
genreFilter genreFilter
] ]
@@ -59,21 +63,21 @@ events.get("/", async (req: Request, res: Response) => {
] ]
}) })
.then(events => { .then(events => {
let resultArray = [] if (sort != undefined) {
events.sort((event1, event2) => {
// Remove datasets which not fulfill the optional parameter if (sort == "desc") {
for (let event of events) { return event2.dataValues.concerts.length - event1.dataValues.concerts.length
if (event.dataValues.band != null) { } else if (sort == "asc") {
for (let concert of event.dataValues.concerts) { return event1.dataValues.concerts.length - event2.dataValues.concerts.length
if (concert.dataValues.location != null) {
resultArray.push(event)
break
}
} }
} })
} }
res.status(200).json(resultArray) if (count != undefined) {
events.splice(Number(count))
}
res.status(200).json(events)
}) })
}) })

View File

@@ -12,6 +12,9 @@ import { Op } from "sequelize";
export const location = Router() export const location = Router()
location.get("/", (req: Request, res: Response) => { location.get("/", (req: Request, res: Response) => {
let sort = req.query.sort
let count = req.query.count
Location.findAll({ Location.findAll({
include: [ include: [
City, City,
@@ -49,13 +52,25 @@ location.get("/", (req: Request, res: Response) => {
} }
} }
if (sort != undefined) {
locations.sort((location1, location2) => {
if (sort == "desc") {
return location2.dataValues.concerts.length - location1.dataValues.concerts.length
} else if (sort == "asc") {
return location1.dataValues.concerts.length - location2.dataValues.concerts.length
}
})
}
if (count != undefined) {
locations.splice(Number(count))
}
res.status(200).json(locations) res.status(200).json(locations)
}) })
}) })
location.get("/:name", (req: Request, res: Response) => { location.get("/:name", (req: Request, res: Response) => {
console.log(req.params.name)
Location.findOne({ Location.findOne({
where: { name: { [Op.like]: req.params.name } }, where: { name: { [Op.like]: req.params.name } },
include: [ include: [

View File

@@ -15,7 +15,7 @@ defineProps({
<v-col> <v-col>
<card-with-left-image <card-with-left-image
:title="title" :title="title"
:image="'http://localhost:3000/static/tours/' + image" :image="'http://localhost:3000/static/' + image"
> >
<div class="text-body-1 font-weight-bold"> <div class="text-body-1 font-weight-bold">
<div v-if="!$slots.description"> <div v-if="!$slots.description">

View File

@@ -9,3 +9,9 @@ export async function fetchEvents(city: string = "", genre: string = "") {
return await axios.get(url) return await axios.get(url)
} }
export async function getTopEvents(nrOfEvents) {
let url = BASE_URL + "?sort=desc&count=" + nrOfEvents
return await axios.get(url)
}

View File

@@ -1,6 +1,6 @@
import axios from "axios" import axios from "axios"
let BASE_URL = "http://localhost:3000/locations" const BASE_URL = "http://localhost:3000/locations"
export async function getAllLocations() { export async function getAllLocations() {
return await axios.get(BASE_URL) return await axios.get(BASE_URL)
@@ -9,3 +9,9 @@ export async function getAllLocations() {
export async function getLocation(locationName: string) { export async function getLocation(locationName: string) {
return await axios.get(BASE_URL + "/" + locationName) return await axios.get(BASE_URL + "/" + locationName)
} }
export async function getTopLocations(nrOfLocations: number) {
let url = BASE_URL + "?sort=desc&count=" + nrOfLocations
return await axios.get(url)
}

View File

@@ -3,12 +3,33 @@ import { useConcertStore } from '@/data/stores/concertStore';
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 { calcRating, lowestTicketPrice } from '@/scripts/concertScripts'; import { lowestTicketPrice } from '@/scripts/concertScripts';
import OutlinedButton from '@/components/outlinedButton.vue'; import OutlinedButton from '@/components/outlinedButton.vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { useFeedbackStore } from '@/data/stores/feedbackStore';
import { ref } from 'vue';
import { EventModel } from '@/data/models/acts/eventModel';
import { getTopEvents } from '@/data/api/eventApi';
import { LocationModel } from '@/data/models/locations/locationModel';
import { getTopLocations } from '@/data/api/locationApi';
const router = useRouter() const router = useRouter()
const concertStore = useConcertStore() const feedbackStore = useFeedbackStore()
const topEvents = ref<Array<EventModel>>(Array.from({length: 4}, () => new EventModel()))
const topLocations = ref<Array<LocationModel>>(Array.from({length: 8}, () => new LocationModel()))
feedbackStore.fetchDataFromServerInProgress = true
getTopEvents(4)
.then(events => {
topEvents.value = events.data
getTopLocations(8)
.then(locations => {
topLocations.value = locations.data
feedbackStore.fetchDataFromServerInProgress = false
})
})
</script> </script>
<template> <template>
@@ -28,12 +49,13 @@ const concertStore = useConcertStore()
<v-row> <v-row>
<v-col v-for="i in 4" cols="3"> <v-col v-for="i in 4" cols="3">
<card-with-top-image <card-with-top-image
:image="'tours/' + concertStore.tours[i - 1].image" :image="topEvents[i - 1].image"
:title="concertStore.tours[i - 1].band.name" :title="topEvents[i - 1].band.name"
smaller-title smaller-title
@click="router.push('/bands/' + concertStore.tours[i - 1].band.name.replaceAll(' ', '-').toLowerCase())" @click="router.push('/bands/' + topEvents[i - 1].band.name.replaceAll(' ', '-').toLowerCase())"
:loading="feedbackStore.fetchDataFromServerInProgress"
> >
ab {{ lowestTicketPrice(concertStore.tours[i - 1]) }} ab {{ lowestTicketPrice(topEvents[i - 1]) }}
</card-with-top-image> </card-with-top-image>
</v-col> </v-col>
</v-row> </v-row>
@@ -59,12 +81,13 @@ const concertStore = useConcertStore()
<v-row> <v-row>
<v-col v-for="i in 8" cols="3"> <v-col v-for="i in 8" cols="3">
<card-with-top-image <card-with-top-image
:image="'locations/' + concertStore.locations[i + 2].image" :image="topLocations[i - 1].image"
:title="concertStore.locations[i + 2].name" :title="topLocations[i - 1].name"
smaller-title smaller-title
@click="router.push('/locations/' + concertStore.locations[i + 2].name.replaceAll(' ', '-').toLowerCase())" @click="router.push('/locations/' + topLocations[i - 1].name.replaceAll(' ', '-').toLowerCase())"
:loading="feedbackStore.fetchDataFromServerInProgress"
> >
{{ concertStore.locations[i + 2].city.name }}, {{ concertStore.locations[i + 2].city.country }} {{ topLocations[i - 1].city.name }}, {{ topLocations[i - 1].city.country }}
</card-with-top-image> </card-with-top-image>
</v-col> </v-col>
</v-row> </v-row>