New page for all concerts
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.17 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.17">
|
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.17 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.17">
|
||||||
<diagram name="Page-1" id="WevClHWmhzPAQ7FDN5po">
|
<diagram name="Page-1" id="WevClHWmhzPAQ7FDN5po">
|
||||||
<mxGraphModel dx="3437" dy="1720" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
<mxGraphModel dx="3676" dy="1858" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
<root>
|
<root>
|
||||||
<mxCell id="0" />
|
<mxCell id="0" />
|
||||||
<mxCell id="1" parent="0" />
|
<mxCell id="1" parent="0" />
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
<mxCell id="EQeajuEG8KHzwlrw_xps-44" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">name: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
<mxCell id="EQeajuEG8KHzwlrw_xps-44" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">name: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||||
<mxGeometry x="-597.97" y="450" width="160" height="30" as="geometry" />
|
<mxGeometry x="-597.97" y="450" width="160" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="EQeajuEG8KHzwlrw_xps-47" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">image: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
<mxCell id="EQeajuEG8KHzwlrw_xps-47" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">imageIndoor: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||||
<mxGeometry x="-597.97" y="510" width="160" height="30" as="geometry" />
|
<mxGeometry x="-597.97" y="510" width="160" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="EQeajuEG8KHzwlrw_xps-48" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">address: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
<mxCell id="EQeajuEG8KHzwlrw_xps-48" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">address: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||||
@@ -562,8 +562,8 @@
|
|||||||
<mxPoint x="-114.13999999999999" y="240" as="sourcePoint" />
|
<mxPoint x="-114.13999999999999" y="240" as="sourcePoint" />
|
||||||
<mxPoint x="-1638.2900000000004" y="280" as="targetPoint" />
|
<mxPoint x="-1638.2900000000004" y="280" as="targetPoint" />
|
||||||
<Array as="points">
|
<Array as="points">
|
||||||
<mxPoint x="-1598.1399999999999" y="-85" />
|
<mxPoint x="-1598" y="-85" />
|
||||||
<mxPoint x="-1598.1399999999999" y="275" />
|
<mxPoint x="-1598" y="115" />
|
||||||
</Array>
|
</Array>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
@@ -584,7 +584,7 @@
|
|||||||
<mxGeometry x="-457.08000000000004" y="285" width="9.43" height="20" as="geometry" />
|
<mxGeometry x="-457.08000000000004" y="285" width="9.43" height="20" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="XtTKw7a9ly-3XTzy1tri-23" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">cityId: Number</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
<mxCell id="XtTKw7a9ly-3XTzy1tri-23" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">cityId: Number</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||||
<mxGeometry x="-597.97" y="540" width="160" height="30" as="geometry" />
|
<mxGeometry x="-597.97" y="600" width="160" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="XtTKw7a9ly-3XTzy1tri-24" value="<blockquote style="margin: 0px; border: none; padding: 0px;"><b><u>Cities</u></b></blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=center;fillColor=#d80073;strokeColor=#A50040;fontColor=#ffffff;" parent="1" vertex="1">
|
<mxCell id="XtTKw7a9ly-3XTzy1tri-24" value="<blockquote style="margin: 0px; border: none; padding: 0px;"><b><u>Cities</u></b></blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=center;fillColor=#d80073;strokeColor=#A50040;fontColor=#ffffff;" parent="1" vertex="1">
|
||||||
<mxGeometry x="-358.1399999999999" y="470" width="160" height="30" as="geometry" />
|
<mxGeometry x="-358.1399999999999" y="470" width="160" height="30" as="geometry" />
|
||||||
@@ -599,15 +599,15 @@
|
|||||||
<mxGeometry x="-217.86000000000004" y="505" width="9.43" height="20" as="geometry" />
|
<mxGeometry x="-217.86000000000004" y="505" width="9.43" height="20" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="XtTKw7a9ly-3XTzy1tri-28" value="" style="sketch=0;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;outlineConnect=0;align=center;shape=mxgraph.office.security.key_permissions;fillColor=#CCCCCC;" parent="1" vertex="1">
|
<mxCell id="XtTKw7a9ly-3XTzy1tri-28" value="" style="sketch=0;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;outlineConnect=0;align=center;shape=mxgraph.office.security.key_permissions;fillColor=#CCCCCC;" parent="1" vertex="1">
|
||||||
<mxGeometry x="-457.69" y="545" width="9.43" height="20" as="geometry" />
|
<mxGeometry x="-457.69" y="605" width="9.43" height="20" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="XtTKw7a9ly-3XTzy1tri-29" value="" style="endArrow=open;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="XtTKw7a9ly-3XTzy1tri-23" target="XtTKw7a9ly-3XTzy1tri-26" edge="1">
|
<mxCell id="XtTKw7a9ly-3XTzy1tri-29" value="" style="endArrow=open;endSize=12;startArrow=diamondThin;startSize=14;startFill=0;edgeStyle=orthogonalEdgeStyle;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="XtTKw7a9ly-3XTzy1tri-23" target="XtTKw7a9ly-3XTzy1tri-26" edge="1">
|
||||||
<mxGeometry x="389.35999999999996" y="350" as="geometry">
|
<mxGeometry x="389.35999999999996" y="350" as="geometry">
|
||||||
<mxPoint x="-779.74" y="570" as="sourcePoint" />
|
<mxPoint x="-779.74" y="570" as="sourcePoint" />
|
||||||
<mxPoint x="-779.74" y="240" as="targetPoint" />
|
<mxPoint x="-779.74" y="240" as="targetPoint" />
|
||||||
<Array as="points">
|
<Array as="points">
|
||||||
<mxPoint x="-398.14" y="555" />
|
<mxPoint x="-398" y="615" />
|
||||||
<mxPoint x="-398.14" y="515" />
|
<mxPoint x="-398" y="515" />
|
||||||
</Array>
|
</Array>
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
@@ -618,7 +618,7 @@
|
|||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="XtTKw7a9ly-3XTzy1tri-31" value="1" style="resizable=0;align=right;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="XtTKw7a9ly-3XTzy1tri-29" connectable="0" vertex="1">
|
<mxCell id="XtTKw7a9ly-3XTzy1tri-31" value="1" style="resizable=0;align=right;verticalAlign=top;labelBackgroundColor=#ffffff;fontSize=10;strokeColor=#003366;shadow=1;fillColor=#D4E1F5;fontColor=#003366" parent="XtTKw7a9ly-3XTzy1tri-29" connectable="0" vertex="1">
|
||||||
<mxGeometry x="1" relative="1" as="geometry">
|
<mxGeometry x="1" relative="1" as="geometry">
|
||||||
<mxPoint x="16" y="-30" as="offset" />
|
<mxPoint x="-12" y="-35" as="offset" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="XtTKw7a9ly-3XTzy1tri-32" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">country: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
<mxCell id="XtTKw7a9ly-3XTzy1tri-32" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">country: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||||
@@ -645,8 +645,8 @@
|
|||||||
<mxCell id="6UZwBTI8mqE8-S_CcwA3-35" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">name: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
<mxCell id="6UZwBTI8mqE8-S_CcwA3-35" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">name: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||||
<mxGeometry x="-376.94999999999993" y="697" width="160" height="30" as="geometry" />
|
<mxGeometry x="-376.94999999999993" y="697" width="160" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="6UZwBTI8mqE8-S_CcwA3-36" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">seatSchema: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
<mxCell id="6UZwBTI8mqE8-S_CcwA3-36" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">imageOutdoor: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||||
<mxGeometry x="-597.97" y="570" width="160" height="30" as="geometry" />
|
<mxGeometry x="-597.97" y="540" width="160" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="6UZwBTI8mqE8-S_CcwA3-37" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">locationId: Number</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
<mxCell id="6UZwBTI8mqE8-S_CcwA3-37" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">locationId: Number</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" parent="1" vertex="1">
|
||||||
<mxGeometry x="-376.94999999999993" y="667" width="160" height="30" as="geometry" />
|
<mxGeometry x="-376.94999999999993" y="667" width="160" height="30" as="geometry" />
|
||||||
@@ -838,6 +838,9 @@
|
|||||||
<mxCell id="q2-4bsxMYXESQ5WjL4G4-1" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">name: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" vertex="1" parent="1">
|
<mxCell id="q2-4bsxMYXESQ5WjL4G4-1" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">name: String</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" vertex="1" parent="1">
|
||||||
<mxGeometry x="-597.97" y="130" width="160" height="30" as="geometry" />
|
<mxGeometry x="-597.97" y="130" width="160" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
|
<mxCell id="q2-4bsxMYXESQ5WjL4G4-3" value="<blockquote style="margin: 0px 0px 0px 8px; border: none; padding: 0px;">layout: Number</blockquote>" style="rounded=0;whiteSpace=wrap;html=1;align=left;" vertex="1" parent="1">
|
||||||
|
<mxGeometry x="-597.97" y="570" width="160" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
</root>
|
</root>
|
||||||
</mxGraphModel>
|
</mxGraphModel>
|
||||||
</diagram>
|
</diagram>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ export const sequelize = new Sequelize({
|
|||||||
})
|
})
|
||||||
|
|
||||||
export function startDatabase() {
|
export function startDatabase() {
|
||||||
let recreateDb = true
|
let recreateDb = false
|
||||||
|
|
||||||
// Create database and tables
|
// Create database and tables
|
||||||
sequelize.sync({ force: recreateDb })
|
sequelize.sync({ force: recreateDb })
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ import { Concert } from "./concert.model";
|
|||||||
@Table({ timestamps: false })
|
@Table({ timestamps: false })
|
||||||
export class Band extends Model {
|
export class Band extends Model {
|
||||||
@Column
|
@Column
|
||||||
name: String
|
name: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
foundingYear: Number
|
foundingYear: number
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
descriptionEn: String
|
descriptionEn: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
descriptionDe: String
|
descriptionDe: string
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
type: DataType.STRING,
|
type: DataType.STRING,
|
||||||
@@ -28,13 +28,13 @@ export class Band extends Model {
|
|||||||
this.setDataValue('images', value.join(';'))
|
this.setDataValue('images', value.join(';'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
images: Array<String>
|
images: Array<string>
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
imageMembers: String
|
imageMembers: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
logo: String
|
logo: string
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|||||||
@@ -6,34 +6,37 @@ import { Band } from "./band.model";
|
|||||||
@Table({ timestamps: false })
|
@Table({ timestamps: false })
|
||||||
export class Concert extends Model {
|
export class Concert extends Model {
|
||||||
@Column
|
@Column
|
||||||
date: String
|
date: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
name: String
|
name: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
price: Number
|
price: number
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
image: String
|
image: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
inStock: Number
|
inStock: number
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
offered: Boolean
|
offered: boolean
|
||||||
|
|
||||||
@ForeignKey(() => Band)
|
@ForeignKey(() => Band)
|
||||||
@Column
|
@Column
|
||||||
bandId: Number
|
bandId: number
|
||||||
|
|
||||||
@ForeignKey(() => Location)
|
@ForeignKey(() => Location)
|
||||||
@Column
|
@Column
|
||||||
locationId: Number
|
locationId: number
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|
||||||
|
@BelongsTo(() => Band)
|
||||||
|
band: Band
|
||||||
|
|
||||||
@BelongsTo(() => Location)
|
@BelongsTo(() => Location)
|
||||||
location: Location
|
location: Location
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { BandGenre } from "./bandGenre.model";
|
|||||||
@Table({ timestamps: false })
|
@Table({ timestamps: false })
|
||||||
export class Genre extends Model {
|
export class Genre extends Model {
|
||||||
@Column
|
@Column
|
||||||
name: String
|
name: string
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import { Band } from "./band.model";
|
|||||||
@Table({ timestamps: false })
|
@Table({ timestamps: false })
|
||||||
export class Member extends Model {
|
export class Member extends Model {
|
||||||
@Column
|
@Column
|
||||||
name: String
|
name: string
|
||||||
|
|
||||||
@ForeignKey(() => Band)
|
@ForeignKey(() => Band)
|
||||||
@Column
|
@Column
|
||||||
bandId: Number
|
bandId: number
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
image: String
|
image: string
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ export class Rating extends Model {
|
|||||||
|
|
||||||
@ForeignKey(() => Account)
|
@ForeignKey(() => Account)
|
||||||
@Column
|
@Column
|
||||||
accountId: Number
|
accountId: number
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
rating: Number
|
rating: number
|
||||||
|
|
||||||
@ForeignKey(() => Band)
|
@ForeignKey(() => Band)
|
||||||
@Column
|
@Column
|
||||||
bandId: Number
|
bandId: number
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|||||||
@@ -4,26 +4,26 @@ import { ExerciseGroup } from "./exerciseGroup.model";
|
|||||||
@Table({ timestamps: false })
|
@Table({ timestamps: false })
|
||||||
export class Exercise extends Model {
|
export class Exercise extends Model {
|
||||||
@Column
|
@Column
|
||||||
nameDe: String
|
nameDe: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
nameEn: String
|
nameEn: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
exerciseNr: Number
|
exerciseNr: number
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
descriptionDe: String
|
descriptionDe: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
descriptionEn: String
|
descriptionEn: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
solved: Boolean
|
solved: boolean
|
||||||
|
|
||||||
@ForeignKey(() => ExerciseGroup)
|
@ForeignKey(() => ExerciseGroup)
|
||||||
@Column
|
@Column
|
||||||
exerciseGroupId: Number
|
exerciseGroupId: number
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import { Exercise } from "./exercise.model";
|
|||||||
@Table({ timestamps: false })
|
@Table({ timestamps: false })
|
||||||
export class ExerciseGroup extends Model {
|
export class ExerciseGroup extends Model {
|
||||||
@Column
|
@Column
|
||||||
nameDe: String
|
nameDe: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
nameEn: String
|
nameEn: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
groupNr: Number
|
groupNr: number
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import { Location } from "./location.model";
|
|||||||
@Table({ timestamps: false })
|
@Table({ timestamps: false })
|
||||||
export class City extends Model {
|
export class City extends Model {
|
||||||
@Column
|
@Column
|
||||||
name: String
|
name: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
country: String
|
country: string
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|||||||
@@ -9,20 +9,20 @@ export class Location extends Model {
|
|||||||
urlName: string
|
urlName: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
name: String
|
name: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
address: String
|
address: string
|
||||||
|
|
||||||
@ForeignKey(() => City)
|
@ForeignKey(() => City)
|
||||||
@Column
|
@Column
|
||||||
cityId: Number
|
cityId: number
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
imageIndoor: String
|
imageIndoor: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
imageOutdoor: String
|
imageOutdoor: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Layout identifier of the location
|
* Layout identifier of the location
|
||||||
@@ -31,7 +31,7 @@ export class Location extends Model {
|
|||||||
* 3 = Stage in the middle of the stay area, seat places all around
|
* 3 = Stage in the middle of the stay area, seat places all around
|
||||||
*/
|
*/
|
||||||
@Column
|
@Column
|
||||||
layout: Number
|
layout: number
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export class Seat extends Model {
|
|||||||
|
|
||||||
@ForeignKey(() => SeatRow)
|
@ForeignKey(() => SeatRow)
|
||||||
@Column
|
@Column
|
||||||
seatRowId: Number
|
seatRowId: number
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|||||||
@@ -5,21 +5,21 @@ import { SeatRow } from "./seatRow.model";
|
|||||||
@Table({ timestamps: false })
|
@Table({ timestamps: false })
|
||||||
export class SeatGroup extends Model {
|
export class SeatGroup extends Model {
|
||||||
@Column
|
@Column
|
||||||
name: String
|
name: string
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
surcharge: Number
|
surcharge: number
|
||||||
|
|
||||||
@Column
|
@Column
|
||||||
capacity: Number
|
capacity: number
|
||||||
|
|
||||||
@Default(false)
|
@Default(false)
|
||||||
@Column
|
@Column
|
||||||
standingArea: Boolean
|
standingArea: boolean
|
||||||
|
|
||||||
@ForeignKey(() => Location)
|
@ForeignKey(() => Location)
|
||||||
@Column
|
@Column
|
||||||
locationId: Number
|
locationId: number
|
||||||
|
|
||||||
|
|
||||||
// Relations
|
// Relations
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Concert } from "../models/acts/concert.model";
|
|||||||
import { Location } from "../models/locations/location.model";
|
import { Location } from "../models/locations/location.model";
|
||||||
import { City } from "../models/locations/city.model";
|
import { City } from "../models/locations/city.model";
|
||||||
import { Op } from "sequelize";
|
import { Op } from "sequelize";
|
||||||
|
import { calcOverallRating, calcRatingValues } from "../scripts/calcScripts";
|
||||||
|
|
||||||
export const band = Router()
|
export const band = Router()
|
||||||
|
|
||||||
@@ -14,37 +15,33 @@ export const band = Router()
|
|||||||
band.get("/", (req: Request, res: Response) => {
|
band.get("/", (req: Request, res: Response) => {
|
||||||
Band.findAll({
|
Band.findAll({
|
||||||
include: [
|
include: [
|
||||||
{
|
|
||||||
model: Member,
|
|
||||||
attributes: {
|
|
||||||
exclude: [ "id", "bandId" ]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
model: Rating,
|
model: Rating,
|
||||||
attributes: {
|
|
||||||
exclude: [ "id", "bandId" ]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
model: Concert,
|
model: Genre,
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Location,
|
|
||||||
include: [ City ],
|
|
||||||
attributes: {
|
attributes: {
|
||||||
exclude: [ "id" ]
|
exclude: [ "id" ]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
],
|
|
||||||
attributes: {
|
|
||||||
exclude: [ "id", "tourId", "locationId" ]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
Genre
|
Concert
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.then(bands => {
|
.then(bands => {
|
||||||
|
for (let band of bands) {
|
||||||
|
band.dataValues["nrOfConcerts"] = band.dataValues.concerts.length
|
||||||
|
band.dataValues["rating"] = calcOverallRating(band.dataValues.ratings)
|
||||||
|
|
||||||
|
|
||||||
|
// Delete unnecessary Arrays
|
||||||
|
delete band.dataValues.ratings
|
||||||
|
delete band.dataValues.concerts
|
||||||
|
|
||||||
|
for (let genre of band.dataValues.genres) {
|
||||||
|
delete genre.dataValues.BandGenre
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res.status(200).json(bands)
|
res.status(200).json(bands)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -90,6 +87,16 @@ band.get("/band/:name", (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(band => {
|
.then(band => {
|
||||||
|
band.dataValues["rating"] = calcOverallRating(band.dataValues.ratings)
|
||||||
|
band.dataValues["ratingValues"] = calcRatingValues(band.dataValues.ratings)
|
||||||
|
|
||||||
|
// Delete unnecessary Arrays
|
||||||
|
delete band.dataValues.ratings
|
||||||
|
|
||||||
|
for (let genre of band.dataValues.genres) {
|
||||||
|
delete genre.dataValues.BandGenre
|
||||||
|
}
|
||||||
|
|
||||||
res.status(200).json(band)
|
res.status(200).json(band)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,26 +1,11 @@
|
|||||||
import { Location } from "../models/locations/location.model";
|
|
||||||
import { City } from "../models/locations/city.model";
|
import { City } from "../models/locations/city.model";
|
||||||
import { Request, Response, Router } from "express";
|
import { Request, Response, Router } from "express";
|
||||||
import { Concert } from "../models/acts/concert.model";
|
|
||||||
|
|
||||||
export const city = Router()
|
export const city = Router()
|
||||||
|
|
||||||
city.get("/", (req: Request, res: Response) => {
|
city.get("/", (req: Request, res: Response) => {
|
||||||
City.findAll({
|
City.findAll()
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: Location,
|
|
||||||
include: [ Concert ]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
|
||||||
.then(cities => {
|
.then(cities => {
|
||||||
// for (let city of cities) {
|
|
||||||
// for (let location of city.dataValues.locations) {
|
|
||||||
// location.dataValues.nrOfConcerts = location.dataValues.concerts.length
|
|
||||||
// delete location.dataValues.concerts
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
res.status(200).json(cities)
|
res.status(200).json(cities)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -7,10 +7,23 @@ import { SeatRow } from "../models/locations/seatRow.model";
|
|||||||
import { Seat } from "../models/locations/seat.model";
|
import { Seat } from "../models/locations/seat.model";
|
||||||
import { Ticket } from "../models/ordering/ticket.model";
|
import { Ticket } from "../models/ordering/ticket.model";
|
||||||
import { Band } from "../models/acts/band.model";
|
import { Band } from "../models/acts/band.model";
|
||||||
import { Op } from "sequelize";
|
|
||||||
|
|
||||||
export const concert = Router()
|
export const concert = Router()
|
||||||
|
|
||||||
|
|
||||||
|
concert.get("/", (req: Request, res: Response) => {
|
||||||
|
Concert.findAll({
|
||||||
|
include: [ Band, Location ],
|
||||||
|
order: [
|
||||||
|
[ 'date', 'ASC' ]
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.then(concerts => {
|
||||||
|
res.status(200).json(concerts)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
concert.get("/concert/:id", (req: Request, res: Response) => {
|
concert.get("/concert/:id", (req: Request, res: Response) => {
|
||||||
Concert.findByPk(req.params.id, {
|
Concert.findByPk(req.params.id, {
|
||||||
include: [
|
include: [
|
||||||
|
|||||||
@@ -20,15 +20,6 @@ location.get("/", (req: Request, res: Response) => {
|
|||||||
{
|
{
|
||||||
model: Concert,
|
model: Concert,
|
||||||
include: [ Band ],
|
include: [ Band ],
|
||||||
},
|
|
||||||
{
|
|
||||||
model: SeatGroup,
|
|
||||||
include: [
|
|
||||||
{
|
|
||||||
model: SeatRow,
|
|
||||||
include: [ Seat ]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
attributes: {
|
attributes: {
|
||||||
@@ -46,6 +37,12 @@ location.get("/", (req: Request, res: Response) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (let location of locations) {
|
||||||
|
location.dataValues["nrOfConcerts"] = location.dataValues.concerts.length
|
||||||
|
delete location.dataValues.concerts
|
||||||
|
}
|
||||||
|
|
||||||
|
// Limit number of items
|
||||||
if (count != undefined) {
|
if (count != undefined) {
|
||||||
locations.splice(Number(count))
|
locations.splice(Number(count))
|
||||||
}
|
}
|
||||||
@@ -86,7 +83,6 @@ location.get("/location/:urlName", (req: Request, res: Response) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
res.status(200).json(location)
|
res.status(200).json(location)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
41
software/backend/scripts/calcScripts.ts
Normal file
41
software/backend/scripts/calcScripts.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import { Rating } from "../models/acts/rating.model";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the average of an Array of ratings
|
||||||
|
*
|
||||||
|
* @param ratings Array of ratings
|
||||||
|
*
|
||||||
|
* @returns Average rating as number
|
||||||
|
*/
|
||||||
|
export function calcOverallRating(ratings: Array<Rating>): number {
|
||||||
|
let sum = 0
|
||||||
|
|
||||||
|
for (let rating of ratings) {
|
||||||
|
sum += rating.dataValues.rating
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum / ratings.length
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classifies a bunch of ratings to groups from 1 to 5 stars
|
||||||
|
*
|
||||||
|
* @param ratings Array of RatingModels
|
||||||
|
*
|
||||||
|
* @returns Array of Objects: { value: number[1-5], count: number }
|
||||||
|
*/
|
||||||
|
export function calcRatingValues(ratings: Array<Rating>) {
|
||||||
|
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.dataValues.rating - 1].count += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return ratingValues
|
||||||
|
}
|
||||||
@@ -29,9 +29,9 @@ const path = require('path')
|
|||||||
app.use('/static', express.static(path.join(__dirname, 'images')))
|
app.use('/static', express.static(path.join(__dirname, 'images')))
|
||||||
|
|
||||||
// Add delay for more realistic response times
|
// Add delay for more realistic response times
|
||||||
app.use((req, res, next) => {
|
// app.use((req, res, next) => {
|
||||||
setTimeout(next, Math.floor((Math.random () * 2000) + 100))
|
// setTimeout(next, Math.floor((Math.random () * 2000) + 100))
|
||||||
})
|
// })
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
app.use("/api", api)
|
app.use("/api", api)
|
||||||
|
|||||||
@@ -10,19 +10,29 @@
|
|||||||
<v-divider vertical />
|
<v-divider vertical />
|
||||||
|
|
||||||
<v-btn
|
<v-btn
|
||||||
to="/events"
|
to="/bands"
|
||||||
|
prepend-icon="mdi-guitar-electric"
|
||||||
|
height="100%"
|
||||||
|
:rounded="false"
|
||||||
|
>
|
||||||
|
{{ $t('allBands', 2) }}
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
|
<v-divider vertical />
|
||||||
|
|
||||||
|
<v-btn
|
||||||
|
to="/concerts"
|
||||||
prepend-icon="mdi-ticket"
|
prepend-icon="mdi-ticket"
|
||||||
height="100%"
|
height="100%"
|
||||||
:rounded="false"
|
:rounded="false"
|
||||||
>
|
>
|
||||||
{{ $t('allEvents', 2) }}
|
{{ $t('allConcerts', 2) }}
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
|
||||||
<v-divider vertical />
|
<v-divider vertical />
|
||||||
|
|
||||||
|
|
||||||
<v-btn
|
<v-btn
|
||||||
variant="text"
|
|
||||||
to="/locations"
|
to="/locations"
|
||||||
prepend-icon="mdi-city"
|
prepend-icon="mdi-city"
|
||||||
height="100%"
|
height="100%"
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { BandModel } from '@/data/models/acts/bandModel';
|
import { BandModel } from '@/data/models/acts/bandModel';
|
||||||
import { lowestTicketPrice, lowestTicketPriceEvents } from '@/scripts/concertScripts';
|
import { lowestTicketPrice } from '@/scripts/concertScripts';
|
||||||
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
|
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
|
||||||
import { EventModel } from '@/data/models/acts/eventModel';
|
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { GenreModel } from '@/data/models/acts/genreModel';
|
import { GenreModel } from '@/data/models/acts/genreModel';
|
||||||
import { EventApiModel } from '@/data/models/acts/eventApiModel';
|
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@@ -16,9 +15,8 @@ defineProps({
|
|||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Events where the band participate */
|
concerts: {
|
||||||
events: {
|
type: Array<ConcertModel>,
|
||||||
type: Array<EventApiModel>,
|
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -37,7 +35,7 @@ defineProps({
|
|||||||
v-if="!loading"
|
v-if="!loading"
|
||||||
:title="band.name"
|
:title="band.name"
|
||||||
:image="'http://localhost:3000/static/' + band.logo"
|
:image="'http://localhost:3000/static/' + band.logo"
|
||||||
@click="router.push('/bands/' + band.name.replaceAll(' ', '-').toLowerCase())"
|
@click="router.push('/bands/details/' + band.name.replaceAll(' ', '-').toLowerCase())"
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div>
|
<div>
|
||||||
@@ -54,12 +52,12 @@ defineProps({
|
|||||||
<template #append>
|
<template #append>
|
||||||
<div>
|
<div>
|
||||||
<div class="text-secondary font-weight-medium text-h6 pb-1">
|
<div class="text-secondary font-weight-medium text-h6 pb-1">
|
||||||
{{ $t('from') + ' ' + lowestTicketPriceEvents(events) + ' €' }}
|
{{ $t('from') + ' ' + lowestTicketPrice(concerts) + ' €' }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<v-btn variant="flat" color="secondary">
|
<v-btn variant="flat" color="secondary">
|
||||||
{{ events.length }} {{ $t('event', events.length) }}
|
{{ concerts.length }} {{ $t('event', concerts.length) }}
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
|
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
|
||||||
|
import { BandModel } from '@/data/models/acts/bandModel';
|
||||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||||
|
import { LocationModel } from '@/data/models/locations/locationModel';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
/** Concert to display */
|
/** Concert to display */
|
||||||
@@ -9,8 +14,15 @@ defineProps({
|
|||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
|
||||||
/** Card title */
|
band: {
|
||||||
title: String,
|
type: BandModel,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
|
||||||
|
location: {
|
||||||
|
type: LocationModel,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
|
||||||
/** Display text parts as skeleton */
|
/** Display text parts as skeleton */
|
||||||
loading: Boolean,
|
loading: Boolean,
|
||||||
@@ -19,19 +31,16 @@ defineProps({
|
|||||||
showButton: {
|
showButton: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
}
|
||||||
|
|
||||||
/** Behaviour if user clicks on button or card */
|
|
||||||
onClick: Function
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<card-view-horizontal
|
<card-view-horizontal
|
||||||
:title="title"
|
:title="concert.name"
|
||||||
v-if="!loading"
|
v-if="!loading"
|
||||||
:link="showButton && concert.inStock > 0"
|
:link="showButton && concert.inStock > 0"
|
||||||
@click="showButton && concert.inStock > 0 ? onClick() : () => {}"
|
@click="showButton && concert.inStock > 0 ? router.push('/concerts/booking/' + concert.id) : () => {}"
|
||||||
>
|
>
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<div>
|
<div>
|
||||||
@@ -50,7 +59,13 @@ defineProps({
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #content>
|
<template #content>
|
||||||
<slot name="description" />
|
<div>
|
||||||
|
{{ band.name }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{{ location.name }}
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #append>
|
<template #append>
|
||||||
|
|||||||
@@ -1,86 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { createDateRangeString, lowestTicketPrice } from '@/scripts/concertScripts';
|
|
||||||
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
|
|
||||||
import { EventModel } from '@/data/models/acts/eventModel';
|
|
||||||
import { useRouter } from 'vue-router';
|
|
||||||
import { BandModel } from '@/data/models/acts/bandModel';
|
|
||||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
defineProps({
|
|
||||||
/** Event to display */
|
|
||||||
event: {
|
|
||||||
type: EventModel,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
|
|
||||||
/** Band which plays the event */
|
|
||||||
band: {
|
|
||||||
type: BandModel,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
|
|
||||||
/** All concerts in the event */
|
|
||||||
concerts: {
|
|
||||||
type: Array<ConcertModel>,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
|
|
||||||
/** Display text parts as skeleton */
|
|
||||||
loading: Boolean
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<card-view-horizontal
|
|
||||||
v-if="!loading"
|
|
||||||
:title="band.name + ' - ' + event.name"
|
|
||||||
:image="'http://localhost:3000/static/' + event.image"
|
|
||||||
@click="router.push('/bands/' + band.name.replaceAll(' ', '-').toLowerCase())"
|
|
||||||
>
|
|
||||||
<template #content>
|
|
||||||
<div class="oneLine my-2 pr-4 text-disabled" >
|
|
||||||
{{ band.descriptionDe }}
|
|
||||||
<!-- todo: Englisch text -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="text-disabled oneLine">
|
|
||||||
{{ createDateRangeString(concerts) }} - {{ concerts.length }}
|
|
||||||
{{ $t('concert', concerts.length) }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #append>
|
|
||||||
<div>
|
|
||||||
<div class="text-secondary font-weight-medium text-h6 pb-1">
|
|
||||||
{{ $t('from') + ' ' + lowestTicketPrice(concerts) + ' €' }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<v-btn variant="flat" color="secondary">
|
|
||||||
{{ concerts.length }} {{ $t('concert', concerts.length) }}
|
|
||||||
</v-btn>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</card-view-horizontal>
|
|
||||||
|
|
||||||
<card-view-horizontal
|
|
||||||
:loading="loading"
|
|
||||||
v-else
|
|
||||||
>
|
|
||||||
<v-skeleton-loader
|
|
||||||
type="text" />
|
|
||||||
</card-view-horizontal>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.oneLine {
|
|
||||||
overflow: hidden;
|
|
||||||
display: -webkit-box;
|
|
||||||
-webkit-line-clamp: 1; /* number of lines to show */
|
|
||||||
line-clamp: 1;
|
|
||||||
-webkit-box-orient: vertical;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
import cardViewTopImage from '../basics/cardViewTopImage.vue';
|
import cardViewTopImage from '../basics/cardViewTopImage.vue';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { LocationModel } from '@/data/models/locations/locationModel';
|
import { LocationModel } from '@/data/models/locations/locationModel';
|
||||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@@ -11,9 +10,8 @@ defineProps({
|
|||||||
type: LocationModel,
|
type: LocationModel,
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
concerts: {
|
nrOfConcerts: {
|
||||||
type: Array<ConcertModel>,
|
type: Number
|
||||||
required: true
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -22,10 +20,10 @@ defineProps({
|
|||||||
<card-view-top-image
|
<card-view-top-image
|
||||||
:image="location.imageOutdoor"
|
:image="location.imageOutdoor"
|
||||||
:title="location.name"
|
:title="location.name"
|
||||||
@click="router.push('locations/' + location.name.replaceAll(' ', '-').toLowerCase())"
|
@click="router.push('locations/details/' + location.name.replaceAll(' ', '-').toLowerCase())"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
{{ concerts.length }} {{ $t('concert', concerts.length) }}
|
{{ nrOfConcerts }} {{ $t('concert', nrOfConcerts) }}
|
||||||
</div>
|
</div>
|
||||||
</card-view-top-image>
|
</card-view-top-image>
|
||||||
</template>
|
</template>
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||||
import cardWithLeftImage from '../basics/cardViewHorizontal.vue';
|
import cardWithLeftImage from '../basics/cardViewHorizontal.vue';
|
||||||
import { dateStringToHumanReadableString } from '@/scripts/dateTimeScripts';
|
import { dateStringToHumanReadableString } from '@/scripts/dateTimeScripts';
|
||||||
import { EventModel } from '@/data/models/acts/eventModel';
|
|
||||||
import { BandModel } from '@/data/models/acts/bandModel';
|
import { BandModel } from '@/data/models/acts/bandModel';
|
||||||
import { LocationModel } from '@/data/models/locations/locationModel';
|
import { LocationModel } from '@/data/models/locations/locationModel';
|
||||||
import { CityModel } from '@/data/models/locations/cityModel';
|
import { CityModel } from '@/data/models/locations/cityModel';
|
||||||
@@ -13,11 +12,6 @@ defineProps({
|
|||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
|
|
||||||
event: {
|
|
||||||
type: EventModel,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
|
|
||||||
band: {
|
band: {
|
||||||
type: BandModel,
|
type: BandModel,
|
||||||
required: true
|
required: true
|
||||||
@@ -54,7 +48,7 @@ defineProps({
|
|||||||
:image="'http://localhost:3000/static/' + image"
|
:image="'http://localhost:3000/static/' + image"
|
||||||
:link="false"
|
:link="false"
|
||||||
color-header="primary"
|
color-header="primary"
|
||||||
:title="band.name + ' - ' + event.name"
|
:title="band.name + ' - ' + concert.name"
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="text-caption">
|
<div class="text-caption">
|
||||||
|
|||||||
@@ -2,10 +2,14 @@
|
|||||||
import { SeatGroupModel } from '@/data/models/locations/seatGroupModel';
|
import { SeatGroupModel } from '@/data/models/locations/seatGroupModel';
|
||||||
import seatGroupSheet from './seatGroupSheet.vue';
|
import seatGroupSheet from './seatGroupSheet.vue';
|
||||||
import { ConcertModel } from '@/data/models/acts/concertModel';
|
import { ConcertModel } from '@/data/models/acts/concertModel';
|
||||||
import { LocationApiModel } from '@/data/models/locations/locationApiModel';
|
import { LocationModel } from '@/data/models/locations/locationModel';
|
||||||
|
|
||||||
let props = defineProps({
|
let props = defineProps({
|
||||||
location: LocationApiModel,
|
location: LocationModel,
|
||||||
|
seatGroups: {
|
||||||
|
type: Array<SeatGroupModel>,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
concert: {
|
concert: {
|
||||||
type: ConcertModel,
|
type: ConcertModel,
|
||||||
default: new ConcertModel()
|
default: new ConcertModel()
|
||||||
@@ -13,7 +17,7 @@ let props = defineProps({
|
|||||||
})
|
})
|
||||||
|
|
||||||
function findSeatCategory(name: string): SeatGroupModel {
|
function findSeatCategory(name: string): SeatGroupModel {
|
||||||
return props.location.seatGroups.find(category =>
|
return props.seatGroups.find(category =>
|
||||||
category.name == name
|
category.name == name
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ import axios from "axios"
|
|||||||
|
|
||||||
let BASE_URL = "http://localhost:3000/concerts"
|
let BASE_URL = "http://localhost:3000/concerts"
|
||||||
|
|
||||||
|
export async function fetchConcerts() {
|
||||||
|
return await axios.get(BASE_URL)
|
||||||
|
}
|
||||||
|
|
||||||
export async function getConcert(id: number) {
|
export async function getConcert(id: number) {
|
||||||
if (id != undefined) {
|
if (id != undefined) {
|
||||||
return await axios.get(BASE_URL + "/concert/" + id)
|
return await axios.get(BASE_URL + "/concert/" + id)
|
||||||
@@ -9,3 +13,7 @@ export async function getConcert(id: number) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function searchConcert(searchTerm: string) {
|
||||||
|
return await axios.get(BASE_URL + '/search?value=' + searchTerm)
|
||||||
|
}
|
||||||
@@ -2,11 +2,12 @@ import axios from "axios"
|
|||||||
|
|
||||||
const BASE_URL = "http://localhost:3000/locations"
|
const BASE_URL = "http://localhost:3000/locations"
|
||||||
|
|
||||||
export async function getAllLocations() {
|
export async function fetchAllLocations() {
|
||||||
return await axios.get(BASE_URL)
|
return await axios.get(BASE_URL)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getLocation(locationName: string) {
|
export async function getLocation(locationName: string) {
|
||||||
|
console.log(locationName)
|
||||||
return await axios.get(BASE_URL + "/location/" + locationName)
|
return await axios.get(BASE_URL + "/location/" + locationName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import { BandModel } from "./bandModel";
|
import { BandModel } from "./bandModel";
|
||||||
import { EventApiModel } from "./eventApiModel";
|
|
||||||
import { GenreModel } from "./genreModel"
|
import { GenreModel } from "./genreModel"
|
||||||
import { MemberModel } from "./memberModel"
|
|
||||||
import { RatingModel } from "./ratingModel"
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replica of the API endpoint /bands
|
||||||
|
*/
|
||||||
export class BandApiModel extends BandModel {
|
export class BandApiModel extends BandModel {
|
||||||
ratings: Array<RatingModel> = []
|
|
||||||
members: Array<MemberModel> = []
|
|
||||||
genres: Array<GenreModel> = []
|
genres: Array<GenreModel> = []
|
||||||
events: Array<EventApiModel> = []
|
rating: number = 0
|
||||||
|
nrOfConcerts: number = 0
|
||||||
}
|
}
|
||||||
15
software/src/data/models/acts/bandDetailsApiModel.ts
Normal file
15
software/src/data/models/acts/bandDetailsApiModel.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { BandModel } from "./bandModel";
|
||||||
|
import { ConcertApiModel } from "./concertApiModel";
|
||||||
|
import { GenreModel } from "./genreModel"
|
||||||
|
import { MemberModel } from "./memberModel";
|
||||||
|
import { RatingModel } from "./ratingModel"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replica of the API endpoint /bands/band/:name
|
||||||
|
*/
|
||||||
|
export class BandDetailsApiModel extends BandModel {
|
||||||
|
members: Array<MemberModel> = []
|
||||||
|
ratingValues: Array<RatingModel> = []
|
||||||
|
genres: Array<GenreModel> = []
|
||||||
|
concerts: Array<ConcertApiModel> = []
|
||||||
|
}
|
||||||
@@ -7,4 +7,5 @@ export class BandModel {
|
|||||||
images: Array<string> = []
|
images: Array<string> = []
|
||||||
imageMembers: string = ""
|
imageMembers: string = ""
|
||||||
logo: string = ""
|
logo: string = ""
|
||||||
|
rating: number = 0
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { LocationApiModel } from "../locations/locationApiModel"
|
import { LocationApiModel } from "../locations/locationApiModel"
|
||||||
|
import { BandModel } from "./bandModel"
|
||||||
import { ConcertModel } from "./concertModel"
|
import { ConcertModel } from "./concertModel"
|
||||||
import { EventApiModel } from "./eventApiModel"
|
|
||||||
|
|
||||||
export class ConcertApiModel extends ConcertModel {
|
export class ConcertApiModel extends ConcertModel {
|
||||||
location: LocationApiModel = new LocationApiModel()
|
location: LocationApiModel = new LocationApiModel()
|
||||||
event: EventApiModel = new EventApiModel()
|
band: BandModel = new BandModel()
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
export class ConcertModel {
|
export class ConcertModel {
|
||||||
id: number = -1
|
id: number = -1
|
||||||
inStock: number = 0
|
|
||||||
date: string = ""
|
date: string = ""
|
||||||
|
name: string = ""
|
||||||
price: number = 0
|
price: number = 0
|
||||||
|
image: string = ""
|
||||||
|
inStock: number = 0
|
||||||
|
offered: boolean = true
|
||||||
}
|
}
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
import { EventModel } from "./eventModel";
|
|
||||||
import { BandModel } from "./bandModel"
|
|
||||||
import { ConcertApiModel } from "./concertApiModel";
|
|
||||||
|
|
||||||
export class EventApiModel extends EventModel {
|
|
||||||
concerts: Array<ConcertApiModel> = []
|
|
||||||
band: BandModel = new BandModel()
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
export class EventModel {
|
|
||||||
id: number = -1
|
|
||||||
name: string = ""
|
|
||||||
offered: boolean = true
|
|
||||||
image: string = ""
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export class RatingModel {
|
export class RatingModel {
|
||||||
id: number = -1
|
value: number = 0
|
||||||
rating: number = 1
|
count: number = 0
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
import { ConcertApiModel } from "../acts/concertApiModel"
|
|
||||||
import { CityModel } from "./cityModel"
|
import { CityModel } from "./cityModel"
|
||||||
import { LocationModel } from "./locationModel"
|
import { LocationModel } from "./locationModel"
|
||||||
import { SeatGroupModel } from "./seatGroupModel"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replica of the API endpoint /locations
|
* Replica of the API endpoint /locations
|
||||||
*/
|
*/
|
||||||
export class LocationApiModel extends LocationModel {
|
export class LocationApiModel extends LocationModel {
|
||||||
city: CityModel = new CityModel()
|
city: CityModel = new CityModel()
|
||||||
concerts: Array<ConcertApiModel> = []
|
nrOfConcerts: number = 0
|
||||||
seatGroups: Array<SeatGroupModel> = []
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { ConcertApiModel } from "../acts/concertApiModel"
|
||||||
|
import { CityModel } from "./cityModel"
|
||||||
|
import { LocationModel } from "./locationModel"
|
||||||
|
import { SeatGroupModel } from "./seatGroupModel"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replica of the API endpoint /locations/location/:name
|
||||||
|
*/
|
||||||
|
export class LocationDetailsApiModel extends LocationModel {
|
||||||
|
city: CityModel = new CityModel()
|
||||||
|
concerts: Array<ConcertApiModel> = []
|
||||||
|
seatGroups: Array<SeatGroupModel> = []
|
||||||
|
}
|
||||||
@@ -8,7 +8,6 @@ import { PaymentModel } from "../models/user/paymentModel";
|
|||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { SelectedSeatModel } from "../models/ordering/selectedSeatModel";
|
import { SelectedSeatModel } from "../models/ordering/selectedSeatModel";
|
||||||
import { calcPrice } from "@/scripts/concertScripts";
|
import { calcPrice } from "@/scripts/concertScripts";
|
||||||
import { EventModel } from "../models/acts/eventModel";
|
|
||||||
import { BandModel } from "../models/acts/bandModel";
|
import { BandModel } from "../models/acts/bandModel";
|
||||||
|
|
||||||
export const useBasketStore = defineStore('basketStore', {
|
export const useBasketStore = defineStore('basketStore', {
|
||||||
@@ -51,28 +50,29 @@ export const useBasketStore = defineStore('basketStore', {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
moveSeatSelectionsToBasket(event: EventModel, band: BandModel) {
|
moveSeatSelectionsToBasket(event, band: BandModel) {
|
||||||
for (let selectedSeat of this.selectedSeats) {
|
// todo
|
||||||
let itemInBasket: BasketItemModel = this.itemsInBasket.find((basketItem: BasketItemModel) => {
|
// for (let selectedSeat of this.selectedSeats) {
|
||||||
return basketItem.concert.id == selectedSeat.concert.id
|
// let itemInBasket: BasketItemModel = this.itemsInBasket.find((basketItem: BasketItemModel) => {
|
||||||
})
|
// return basketItem.concert.id == selectedSeat.concert.id
|
||||||
|
// })
|
||||||
|
|
||||||
if (itemInBasket != undefined) {
|
// if (itemInBasket != undefined) {
|
||||||
itemInBasket.seats.push(selectedSeat.seat)
|
// itemInBasket.seats.push(selectedSeat.seat)
|
||||||
} else {
|
// } else {
|
||||||
this.itemsInBasket.push(
|
// this.itemsInBasket.push(
|
||||||
new BasketItemModel(
|
// new BasketItemModel(
|
||||||
selectedSeat.concert,
|
// selectedSeat.concert,
|
||||||
event,
|
// event,
|
||||||
band,
|
// band,
|
||||||
selectedSeat.seat,
|
// selectedSeat.seat,
|
||||||
selectedSeat.concert.price
|
// selectedSeat.concert.price
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
this.selectedSeats = []
|
// this.selectedSeats = []
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
24
software/src/data/stores/concertStore.ts
Normal file
24
software/src/data/stores/concertStore.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { ConcertApiModel } from "../models/acts/concertApiModel";
|
||||||
|
import { useFeedbackStore } from "./feedbackStore";
|
||||||
|
import { fetchConcerts } from "../api/concertApi";
|
||||||
|
|
||||||
|
export const useConcertStore = defineStore("concertStore", {
|
||||||
|
state: () => ({
|
||||||
|
concerts: ref<Array<ConcertApiModel>>([])
|
||||||
|
}),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
async getConcerts() {
|
||||||
|
const feedbackStore = useFeedbackStore()
|
||||||
|
feedbackStore.fetchDataFromServerInProgress = true
|
||||||
|
|
||||||
|
await fetchConcerts()
|
||||||
|
.then(result => {
|
||||||
|
this.concerts = result.data
|
||||||
|
feedbackStore.fetchDataFromServerInProgress = false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
36
software/src/data/stores/locationStore.ts
Normal file
36
software/src/data/stores/locationStore.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useFeedbackStore } from "./feedbackStore";
|
||||||
|
import { fetchAllLocations } from "../api/locationApi";
|
||||||
|
import { LocationApiModel } from "../models/locations/locationApiModel";
|
||||||
|
import { CityModel } from "../models/locations/cityModel";
|
||||||
|
import { fetchAllCities } from "../api/cityApi";
|
||||||
|
|
||||||
|
export const useLocationStore = defineStore("locationStore", {
|
||||||
|
state: () => ({
|
||||||
|
locations: ref<Array<LocationApiModel>>([]),
|
||||||
|
cities: ref<Array<CityModel>>([])
|
||||||
|
}),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
async getLocations() {
|
||||||
|
const feedbackStore = useFeedbackStore()
|
||||||
|
feedbackStore.fetchDataFromServerInProgress = true
|
||||||
|
|
||||||
|
await fetchAllLocations()
|
||||||
|
.then(result => {
|
||||||
|
this.locations = result.data
|
||||||
|
})
|
||||||
|
|
||||||
|
await fetchAllCities()
|
||||||
|
.then(result => {
|
||||||
|
this.cities = result.data
|
||||||
|
feedbackStore.fetchDataFromServerInProgress = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getLocationsByCity(city: string): Array<LocationApiModel> {
|
||||||
|
return this.locations.filter(location => location.city.name == city)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
60
software/src/data/stores/shopStore.ts
Normal file
60
software/src/data/stores/shopStore.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { ConcertApiModel } from "../models/acts/concertApiModel";
|
||||||
|
import { BandApiModel } from "../models/acts/bandApiModel";
|
||||||
|
import { CityApiModel } from "../models/locations/cityApiModel";
|
||||||
|
import { GenreApiModel } from "../models/acts/genreApiModel";
|
||||||
|
import { searchBand } from "../api/bandApi";
|
||||||
|
import { searchLocation } from "../api/locationApi";
|
||||||
|
import { fetchConcerts, searchConcert } from "../api/concertApi";
|
||||||
|
import { useFeedbackStore } from "./feedbackStore";
|
||||||
|
|
||||||
|
export const useShopStore = defineStore("shopStore", {
|
||||||
|
state: () => ({
|
||||||
|
concertsFiltered: ref<Array<ConcertApiModel>>([]),
|
||||||
|
bandsFiltered: ref<Array<BandApiModel>>([]),
|
||||||
|
cities: ref<Array<CityApiModel>>([]),
|
||||||
|
cityFilterName: ref<string>(),
|
||||||
|
genreFilterName: ref<string>(),
|
||||||
|
genres: ref<Array<GenreApiModel>>([]),
|
||||||
|
alreadySearched: ref(false),
|
||||||
|
searchInProgress: ref(false)
|
||||||
|
}),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
/**
|
||||||
|
* Search for the termin in all bands, locations, events
|
||||||
|
*/
|
||||||
|
async startSearch() {
|
||||||
|
this.alreadySearched = true
|
||||||
|
this.searchInProgress = true
|
||||||
|
|
||||||
|
await searchBand(this.searchTerm)
|
||||||
|
.then(result => {
|
||||||
|
this.bands = result.data
|
||||||
|
})
|
||||||
|
|
||||||
|
await searchLocation(this.searchTerm)
|
||||||
|
.then(result => {
|
||||||
|
this.locations = result.data
|
||||||
|
})
|
||||||
|
|
||||||
|
await searchConcert(this.searchTerm)
|
||||||
|
.then(result => {
|
||||||
|
this.concerts = result.data
|
||||||
|
})
|
||||||
|
|
||||||
|
this.searchInProgress = false
|
||||||
|
},
|
||||||
|
|
||||||
|
async getConcerts() {
|
||||||
|
const feedbackStore = useFeedbackStore()
|
||||||
|
feedbackStore.fetchDataFromServerInProgress = true
|
||||||
|
|
||||||
|
await fetchConcerts()
|
||||||
|
.then(result => {
|
||||||
|
this.concerts = result.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -5,12 +5,10 @@ import { fetchAllCities } from "../api/cityApi";
|
|||||||
import { fetchAllGenres } from "../api/genreApi";
|
import { fetchAllGenres } from "../api/genreApi";
|
||||||
import { useFeedbackStore } from "./feedbackStore";
|
import { useFeedbackStore } from "./feedbackStore";
|
||||||
import { CityApiModel } from "../models/locations/cityApiModel";
|
import { CityApiModel } from "../models/locations/cityApiModel";
|
||||||
import { EventApiModel } from "../models/acts/eventApiModel";
|
|
||||||
import { GenreApiModel } from "../models/acts/genreApiModel";
|
import { GenreApiModel } from "../models/acts/genreApiModel";
|
||||||
|
|
||||||
export const useShoppingStore = defineStore("shoppingStore", {
|
export const useShoppingStore = defineStore("shoppingStore", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
events: ref<Array<EventApiModel>>([]),
|
|
||||||
cities: ref<Array<CityApiModel>>([]),
|
cities: ref<Array<CityApiModel>>([]),
|
||||||
genres: ref<Array<GenreApiModel>>([]),
|
genres: ref<Array<GenreApiModel>>([]),
|
||||||
cityFilterName: ref<string>(),
|
cityFilterName: ref<string>(),
|
||||||
|
|||||||
@@ -173,5 +173,7 @@
|
|||||||
"selectedConcert": "Ausgewähltes Konzert",
|
"selectedConcert": "Ausgewähltes Konzert",
|
||||||
"enterSomeKeywords": "Füge Schlagworte ein um nach Bands, Events, Konzerten und Veranstaltungsorten zu suchen",
|
"enterSomeKeywords": "Füge Schlagworte ein um nach Bands, Events, Konzerten und Veranstaltungsorten zu suchen",
|
||||||
"noBandFound": "Keine Band gefunden",
|
"noBandFound": "Keine Band gefunden",
|
||||||
"noLocationsFound": "Keine Veranstaltungsorte gefunden"
|
"noLocationsFound": "Keine Veranstaltungsorte gefunden",
|
||||||
|
"allBands": "Alle Bands",
|
||||||
|
"allConcerts": "Alle Konzerte"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,5 +173,7 @@
|
|||||||
"selectedConcert": "Selected Concert",
|
"selectedConcert": "Selected Concert",
|
||||||
"enterSomeKeywords": "Enter keywords to search for bands, events, concerts and locations",
|
"enterSomeKeywords": "Enter keywords to search for bands, events, concerts and locations",
|
||||||
"noBandFound": "No band found",
|
"noBandFound": "No band found",
|
||||||
"noLocationsFound": "No location found"
|
"noLocationsFound": "No location found",
|
||||||
|
"allBands": "All Bands",
|
||||||
|
"allConcerts": "All Concerts"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { BandApiModel } from '@/data/models/acts/bandApiModel';
|
import { BandApiModel } from '@/data/models/acts/bandApiModel';
|
||||||
import { RatingModel } from '@/data/models/acts/ratingModel';
|
import { RatingModel } from '@/data/models/acts/ratingModel';
|
||||||
import { calcRating, calcRatingValues } from '@/scripts/concertScripts';
|
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
|
rating: Number,
|
||||||
ratings: {
|
ratings: {
|
||||||
type: Array<RatingModel>,
|
type: Array<RatingModel>,
|
||||||
required: true
|
required: true
|
||||||
@@ -16,12 +16,12 @@ defineProps({
|
|||||||
<v-col>
|
<v-col>
|
||||||
<div class="d-flex align-center justify-center flex-column" style="height: 100%;">
|
<div class="d-flex align-center justify-center flex-column" style="height: 100%;">
|
||||||
<div class="text-h2 mt-5">
|
<div class="text-h2 mt-5">
|
||||||
{{ calcRating(ratings).toFixed(1) }}
|
{{ rating.toFixed(1) }}
|
||||||
<span class="text-h6 ml-n3">/5</span>
|
<span class="text-h6 ml-n3">/5</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-rating
|
<v-rating
|
||||||
:model-value="calcRating(ratings)"
|
:model-value="rating"
|
||||||
color="yellow-darken-3"
|
color="yellow-darken-3"
|
||||||
half-increments
|
half-increments
|
||||||
size="x-large"
|
size="x-large"
|
||||||
@@ -34,7 +34,7 @@ defineProps({
|
|||||||
|
|
||||||
<v-col>
|
<v-col>
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item v-for="ratingValue in calcRatingValues(ratings)">
|
<v-list-item v-for="ratingValue in ratings">
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<span>{{ ratingValue.value }}</span>
|
<span>{{ ratingValue.value }}</span>
|
||||||
<v-icon class="ml-3 mr-n3" icon="mdi-star" />
|
<v-icon class="ml-3 mr-n3" icon="mdi-star" />
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
Bands
|
||||||
</template>
|
</template>
|
||||||
@@ -50,7 +50,7 @@ getConcert(Number(router.currentRoute.value.params.id))
|
|||||||
>
|
>
|
||||||
<template #description>
|
<template #description>
|
||||||
<p>{{ concertModel.location.name }}</p>
|
<p>{{ concertModel.location.name }}</p>
|
||||||
<p>{{ concertModel.event.band.name }} - {{ concertModel.event.name }}</p>
|
<!-- todo <p>{{ concertModel.event.band.name }} - {{ concertModel.event.name }}</p> -->
|
||||||
</template>
|
</template>
|
||||||
</concert-list-item>
|
</concert-list-item>
|
||||||
</v-col>
|
</v-col>
|
||||||
@@ -102,7 +102,7 @@ getConcert(Number(router.currentRoute.value.params.id))
|
|||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<v-row class="pb-5">
|
<v-row class="pb-5">
|
||||||
<outlined-button
|
<!-- <outlined-button todo
|
||||||
prepend-icon="mdi-basket-plus"
|
prepend-icon="mdi-basket-plus"
|
||||||
@click="basketStore.moveSeatSelectionsToBasket(concertModel.event, concertModel.event.band);
|
@click="basketStore.moveSeatSelectionsToBasket(concertModel.event, concertModel.event.band);
|
||||||
router.push('/basket')"
|
router.push('/basket')"
|
||||||
@@ -110,7 +110,7 @@ getConcert(Number(router.currentRoute.value.params.id))
|
|||||||
block
|
block
|
||||||
>
|
>
|
||||||
{{ $t('addToBasket') }}
|
{{ $t('addToBasket') }}
|
||||||
</outlined-button>
|
</outlined-button> -->
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,69 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { useConcertStore } from '@/data/stores/concertStore';
|
||||||
|
import concertListItem from '@/components/pageParts/concertListItem.vue';
|
||||||
|
import { useFeedbackStore } from '@/data/stores/feedbackStore';
|
||||||
|
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
|
||||||
|
import sectionDivider from '@/components/basics/sectionDivider.vue';
|
||||||
|
|
||||||
|
const concertStore = useConcertStore()
|
||||||
|
const feedbackStore = useFeedbackStore()
|
||||||
|
|
||||||
|
concertStore.getConcerts()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
Concerts
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-spacer />
|
||||||
|
|
||||||
|
<v-col cols="10">
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
Filterbar
|
||||||
|
<!-- todo: Filterbar? -->
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row
|
||||||
|
v-if="feedbackStore.fetchDataFromServerInProgress"
|
||||||
|
v-for="i in 3"
|
||||||
|
>
|
||||||
|
<v-col>
|
||||||
|
<card-view-horizontal :loading="true" />
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-else-if="concertStore.concerts.length > 0"
|
||||||
|
v-for="(concert, index) of concertStore.concerts"
|
||||||
|
>
|
||||||
|
<v-row
|
||||||
|
v-if="index == 0 ||
|
||||||
|
new Date(concertStore.concerts[index - 1].date).getMonth() !=
|
||||||
|
new Date(concertStore.concerts[index].date).getMonth()"
|
||||||
|
>
|
||||||
|
<v-col>
|
||||||
|
<section-divider
|
||||||
|
:title="new Date(concert.date).toLocaleString('default', { month: 'long' }) + ' ' + new Date(concert.date).getFullYear()"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
|
<concert-list-item
|
||||||
|
:concert="concert"
|
||||||
|
:band="concert.band"
|
||||||
|
:location="concert.location"
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</div>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<v-spacer />
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
@@ -3,7 +3,6 @@ import filterBar from './filterBar.vue';
|
|||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { useShoppingStore } from '@/data/stores/shoppingStore';
|
import { useShoppingStore } from '@/data/stores/shoppingStore';
|
||||||
import { useFeedbackStore } from '@/data/stores/feedbackStore';
|
import { useFeedbackStore } from '@/data/stores/feedbackStore';
|
||||||
import eventListItem from '../../../components/pageParts/eventListItem.vue';
|
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const shoppingStore = useShoppingStore()
|
const shoppingStore = useShoppingStore()
|
||||||
|
|||||||
@@ -7,29 +7,25 @@ import OutlinedButton from '@/components/basics/outlinedButton.vue';
|
|||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import { useFeedbackStore } from '@/data/stores/feedbackStore';
|
import { useFeedbackStore } from '@/data/stores/feedbackStore';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { EventModel } from '@/data/models/acts/eventModel';
|
|
||||||
import { getTopEvents } from '@/data/api/eventApi';
|
|
||||||
import { getTopLocations } from '@/data/api/locationApi';
|
import { getTopLocations } from '@/data/api/locationApi';
|
||||||
import { LocationApiModel } from '@/data/models/locations/locationApiModel';
|
import { LocationApiModel } from '@/data/models/locations/locationApiModel';
|
||||||
import { EventApiModel } from '@/data/models/acts/eventApiModel';
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const feedbackStore = useFeedbackStore()
|
const feedbackStore = useFeedbackStore()
|
||||||
const topEvents = ref<Array<EventApiModel>>(Array.from({length: 4}, () => new EventApiModel()))
|
|
||||||
const topLocations = ref<Array<LocationApiModel>>(Array.from({length: 8}, () => new LocationApiModel()))
|
const topLocations = ref<Array<LocationApiModel>>(Array.from({length: 8}, () => new LocationApiModel()))
|
||||||
|
|
||||||
feedbackStore.fetchDataFromServerInProgress = true
|
feedbackStore.fetchDataFromServerInProgress = true
|
||||||
|
|
||||||
getTopEvents(4)
|
// todo getTopEvents(4)
|
||||||
.then(events => {
|
// .then(events => {
|
||||||
topEvents.value = events.data
|
// topEvents.value = events.data
|
||||||
|
|
||||||
getTopLocations(8)
|
// getTopLocations(8)
|
||||||
.then(locations => {
|
// .then(locations => {
|
||||||
topLocations.value = locations.data
|
// topLocations.value = locations.data
|
||||||
feedbackStore.fetchDataFromServerInProgress = false
|
// feedbackStore.fetchDataFromServerInProgress = false
|
||||||
})
|
// })
|
||||||
})
|
// })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -46,7 +42,7 @@ getTopEvents(4)
|
|||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<v-row>
|
<!-- <v-row> todo
|
||||||
<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="topEvents[i - 1].image"
|
:image="topEvents[i - 1].image"
|
||||||
@@ -58,7 +54,7 @@ getTopEvents(4)
|
|||||||
ab {{ lowestTicketPrice(topEvents[i - 1].concerts) }} €
|
ab {{ lowestTicketPrice(topEvents[i - 1].concerts) }} €
|
||||||
</card-with-top-image>
|
</card-with-top-image>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row> -->
|
||||||
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
|
|||||||
@@ -7,15 +7,15 @@ import { ref } from 'vue';
|
|||||||
import { useFeedbackStore } from '@/data/stores/feedbackStore';
|
import { useFeedbackStore } from '@/data/stores/feedbackStore';
|
||||||
import heroImage from '@/components/pageParts/heroImage.vue';
|
import heroImage from '@/components/pageParts/heroImage.vue';
|
||||||
import concertListItem from '@/components/pageParts/concertListItem.vue';
|
import concertListItem from '@/components/pageParts/concertListItem.vue';
|
||||||
import { LocationApiModel } from '@/data/models/locations/locationApiModel';
|
import { LocationDetailsApiModel } from '@/data/models/locations/locationDetailsApiModel';
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const feedbackStore = useFeedbackStore()
|
const feedbackStore = useFeedbackStore()
|
||||||
const location = ref<LocationApiModel>(new LocationApiModel())
|
const location = ref<LocationDetailsApiModel>(new LocationDetailsApiModel())
|
||||||
|
|
||||||
feedbackStore.fetchDataFromServerInProgress = true
|
feedbackStore.fetchDataFromServerInProgress = true
|
||||||
|
|
||||||
getLocation(String(router.currentRoute.value.params.locationName))
|
getLocation(String(router.currentRoute.value.params.name))
|
||||||
.then(result => {
|
.then(result => {
|
||||||
location.value = result.data
|
location.value = result.data
|
||||||
feedbackStore.fetchDataFromServerInProgress = false
|
feedbackStore.fetchDataFromServerInProgress = false
|
||||||
@@ -61,11 +61,11 @@ getLocation(String(router.currentRoute.value.params.locationName))
|
|||||||
<v-col>
|
<v-col>
|
||||||
<concert-list-item
|
<concert-list-item
|
||||||
:concert="concert"
|
:concert="concert"
|
||||||
:title="concert.event.name"
|
:title="concert.name"
|
||||||
:onClick="() => router.push('/bands/' + concert.event.band.name.replaceAll(' ', '-').toLowerCase())"
|
:onClick="() => router.push('/bands/' + concert.band.name.replaceAll(' ', '-').toLowerCase())"
|
||||||
>
|
>
|
||||||
<template #description>
|
<template #description>
|
||||||
{{ concert.event.band.name }}
|
{{ concert.band.name }}
|
||||||
</template>
|
</template>
|
||||||
</concert-list-item>
|
</concert-list-item>
|
||||||
</v-col>
|
</v-col>
|
||||||
@@ -97,6 +97,7 @@ getLocation(String(router.currentRoute.value.params.locationName))
|
|||||||
<v-col>
|
<v-col>
|
||||||
<seat-plan-map
|
<seat-plan-map
|
||||||
:location="location"
|
:location="location"
|
||||||
|
:seat-groups="location.seatGroups"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import sectionDivider from '@/components/basics/sectionDivider.vue';
|
import sectionDivider from '@/components/basics/sectionDivider.vue';
|
||||||
import cardWithTopImage from '@/components/basics/cardViewTopImage.vue';
|
import cardWithTopImage from '@/components/basics/cardViewTopImage.vue';
|
||||||
import { useShoppingStore } from '@/data/stores/shoppingStore';
|
|
||||||
import { useFeedbackStore } from '@/data/stores/feedbackStore';
|
import { useFeedbackStore } from '@/data/stores/feedbackStore';
|
||||||
import locationListItem from '@/components/pageParts/locationListItem.vue';
|
import locationListItem from '@/components/pageParts/locationListItem.vue';
|
||||||
|
import { useLocationStore } from '@/data/stores/locationStore';
|
||||||
|
|
||||||
const shoppingStore = useShoppingStore()
|
const locationStore = useLocationStore()
|
||||||
const feedbackStore = useFeedbackStore()
|
const feedbackStore = useFeedbackStore()
|
||||||
|
|
||||||
shoppingStore.getCities()
|
locationStore.getLocations()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -37,9 +37,11 @@ shoppingStore.getCities()
|
|||||||
|
|
||||||
<!-- When all data are downloaded -->
|
<!-- When all data are downloaded -->
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else-if="locationStore.locations.length > 0"
|
||||||
v-for="city in shoppingStore.cities"
|
v-for="city in locationStore.cities"
|
||||||
>
|
>
|
||||||
|
<v-row>
|
||||||
|
<v-col>
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
<section-divider
|
<section-divider
|
||||||
@@ -49,20 +51,23 @@ shoppingStore.getCities()
|
|||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
<v-row>
|
<v-row>
|
||||||
<v-col v-for="location in city.locations" cols="3">
|
<v-col
|
||||||
|
v-for="location in locationStore.getLocationsByCity(city.name)"
|
||||||
|
cols="3"
|
||||||
|
>
|
||||||
<location-list-item
|
<location-list-item
|
||||||
:location="location"
|
:location="location"
|
||||||
:concerts="location.concerts"
|
:nrOfConcerts="location.nrOfConcerts"
|
||||||
/>
|
/>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
</div>
|
</div>
|
||||||
</v-col>
|
</v-col>
|
||||||
|
|
||||||
<v-spacer />
|
<v-spacer />
|
||||||
</v-row>
|
</v-row>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import searchBar from './searchBar.vue';
|
import searchBar from './searchBar.vue';
|
||||||
import eventListItem from '@/components/pageParts/eventListItem.vue';
|
|
||||||
import sectionDivider from '@/components/basics/sectionDivider.vue';
|
import sectionDivider from '@/components/basics/sectionDivider.vue';
|
||||||
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
|
import cardViewHorizontal from '@/components/basics/cardViewHorizontal.vue';
|
||||||
import locationListItem from '@/components/pageParts/locationListItem.vue';
|
import locationListItem from '@/components/pageParts/locationListItem.vue';
|
||||||
@@ -45,7 +44,7 @@ const searchStore = useSearchStore()
|
|||||||
<v-col>
|
<v-col>
|
||||||
<band-list-item
|
<band-list-item
|
||||||
:band="band"
|
:band="band"
|
||||||
:events="band.events"
|
:concerts="band.concerts"
|
||||||
:genres="band.genres"
|
:genres="band.genres"
|
||||||
:loading="searchStore.searchInProgress"
|
:loading="searchStore.searchInProgress"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const routes = [
|
|||||||
|
|
||||||
// Bands
|
// Bands
|
||||||
{ path: '/bands', component: BandsPage },
|
{ path: '/bands', component: BandsPage },
|
||||||
{ path: '/bands/detail/:name', component: BandDetailPage },
|
{ path: '/bands/details/:name', component: BandDetailPage },
|
||||||
|
|
||||||
// Concerts
|
// Concerts
|
||||||
{ path: '/concerts', component: ConcertsPage },
|
{ path: '/concerts', component: ConcertsPage },
|
||||||
@@ -38,7 +38,7 @@ const routes = [
|
|||||||
|
|
||||||
// Locations
|
// Locations
|
||||||
{ path: '/locations', component: LocationsPage },
|
{ path: '/locations', component: LocationsPage },
|
||||||
{ path: '/locations/detail/:name', name: 'locationDetails', component: LocationDetailPage },
|
{ path: '/locations/details/:name', name: 'locationDetails', component: LocationDetailPage },
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
{ path: '/search', component: SearchPage },
|
{ path: '/search', component: SearchPage },
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import { RatingModel } from "@/data/models/acts/ratingModel"
|
|
||||||
import { dateToHumanReadableString } from "./dateTimeScripts"
|
import { dateToHumanReadableString } from "./dateTimeScripts"
|
||||||
import { ConcertModel } from "@/data/models/acts/concertModel"
|
import { ConcertModel } from "@/data/models/acts/concertModel"
|
||||||
import { EventModel } from "@/data/models/acts/eventModel"
|
|
||||||
import { EventApiModel } from "@/data/models/acts/eventApiModel"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate a price based on parameters
|
* Calculate a price based on parameters
|
||||||
@@ -18,48 +15,6 @@ export function calcPrice(price: number, quantity: number = 1): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Classifies a bunch of ratings to groups from 1 to 5 stars
|
|
||||||
*
|
|
||||||
* @param ratings Array of RatingModels
|
|
||||||
*
|
|
||||||
* @returns Array of Objects: { value: number[1-5], count: number }
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a date range string of all concerts from an Event
|
* Create a date range string of all concerts from an Event
|
||||||
*
|
*
|
||||||
@@ -110,21 +65,3 @@ export function lowestTicketPrice(concerts: Array<ConcertModel>): string {
|
|||||||
return "0"
|
return "0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function lowestTicketPriceEvents(events: Array<EventApiModel>) {
|
|
||||||
const priceArray : Array<number> = []
|
|
||||||
|
|
||||||
for (let event of events) {
|
|
||||||
for (let concert of event.concerts) {
|
|
||||||
priceArray.push(concert.price)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
priceArray.sort()
|
|
||||||
|
|
||||||
try {
|
|
||||||
return priceArray[0].toFixed(2)
|
|
||||||
} catch(e) {
|
|
||||||
return "0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user