Refactor frontend, display tours with cards on ToursPage

This commit is contained in:
2024-09-26 16:06:20 +02:00
parent 169fcdf03c
commit e2dd49e21b
39 changed files with 397 additions and 349 deletions

View File

@@ -4,21 +4,19 @@ import { i18n } from './plugins/i18n';
import { ref, watch } from 'vue';
import vuetify from './plugins/vuetify';
import navigationItems from './components/navigationItems.vue';
import { useProductStore } from './data/stores/productStore';
import { usePreferencesStore } from './data/stores/preferencesStore';
import { useFeedbackStore } from './data/stores/feedbackStore';
import { useTourStore } from './data/stores/tourStore';
const preferencesStore = usePreferencesStore()
const productStore = useProductStore()
const tourStore = useTourStore()
const feedbackStore = useFeedbackStore()
const theme = useTheme()
const navRail = ref(vuetify.display.mobile)
theme.global.name.value = preferencesStore.theme
productStore.fetchAllProducts()
productStore.fetchAllCategories()
productStore.fetchAllBrands()
tourStore.fetchAllTours()
// Global watcher
watch(() => preferencesStore.language, () => {

View File

@@ -7,28 +7,72 @@ defineProps({
},
subtitle: {
type: String,
},
prependImage: {
type: String,
default: ""
}
})
</script>
<template>
<v-card
:title="title"
:subtitle="subtitle"
:prepend-icon="icon"
>
<!-- Show default container only, if there is content -->
<v-container v-if="$slots.default">
<v-card>
<v-row v-if="prependImage != ''">
<v-col cols="3" class="pr-0">
<v-img
:src="prependImage"
height="220"
cover
>
<template #placeholder>
<v-skeleton-loader
type="image"
height="300"
cover
/>
</template>
</v-img>
</v-col>
<v-col class="pl-0" >
<v-card-title>
{{ title }}
</v-card-title>
<v-card-subtitle>
{{ subtitle }}
</v-card-subtitle>
<div class="pa-4">
<slot></slot>
</div>
<v-card-actions v-if="$slots.actions" class="card-actions position-absolute bottom-0 right-0">
<v-spacer />
<slot name="actions"></slot>
</v-card-actions>
</v-col>
</v-row>
<v-container v-else>
<slot></slot>
</v-container>
<!-- Show default container only, if there is content -->
<!-- <v-container v-if="$slots.default">
<slot></slot>
</v-container> -->
<!-- Slot for content without padding -->
<slot name="withoutContainer"></slot>
<!-- <slot name="withoutContainer"></slot> -->
<!-- Slot for Action Buttons in the right bottom corner -->
<v-card-actions v-if="$slots.actions" class="card-actions">
<!-- <v-card-actions v-if="$slots.actions" class="card-actions">
<v-spacer />
<slot name="actions"></slot>
</v-card-actions>
</v-card-actions> -->
</v-card>
</template>

View File

@@ -12,12 +12,12 @@ const navRail = defineModel("navRail", { type: Boolean })
<!-- Shopping Section -->
<v-list-subheader>
<div v-if="!navRail">{{ $t('menu.shopping') }}</div>
<div v-if="!navRail">{{ $t('menu.shopping.shopping') }}</div>
<div v-else></div>
</v-list-subheader>
<v-list-item :title="$t('menu.products')" prepend-icon="mdi-store" to="/" link />
<v-list-item :title="$t('menu.basket')" to="/basket" link >
<v-list-item :title="$t('menu.shopping.ticket', 2)" prepend-icon="mdi-ticket" to="/" link />
<v-list-item :title="$t('menu.shopping.basket')" to="/basket" link >
<template v-slot:prepend>
<v-badge color="primary" :content="basketStore.itemsInBasket.length">
<v-icon icon="mdi-cart" />
@@ -31,21 +31,21 @@ const navRail = defineModel("navRail", { type: Boolean })
<!-- Account Section -->
<v-list-subheader>
<div v-if="!navRail">{{ $t('menu.account') }}</div>
<div v-if="!navRail">{{ $t('menu.account.accountManagement') }}</div>
<div v-else></div>
</v-list-subheader>
<v-expand-transition>
<div v-if="accountStore.userAccount.id == null">
<v-list-item v-if="accountStore.userAccount.id == null" :title="$t('menu.login')" prepend-icon="mdi-login" to="/login" link />
<v-list-item v-if="accountStore.userAccount.id == null" :title="$t('menu.account.login')" prepend-icon="mdi-login" to="/login" link />
</div>
</v-expand-transition>
<v-expand-transition>
<div v-if="accountStore.userAccount.id != null">
<v-list-item :title="$t('menu.account')" prepend-icon="mdi-account" to="/account" link />
<v-list-item :title="$t('menu.orders')" prepend-icon="mdi-cart-check" to="/orders" link />
<v-list-item :title="$t('menu.logout')" prepend-icon="mdi-logout" @click="accountStore.logout" link />
<v-list-item :title="$t('menu.account.account')" prepend-icon="mdi-account" to="/account" link />
<v-list-item :title="$t('menu.account.order', 2)" prepend-icon="mdi-cart-check" to="/orders" link />
<v-list-item :title="$t('menu.account.logout')" prepend-icon="mdi-logout" @click="accountStore.logout" link />
</div>
</v-expand-transition>
@@ -55,12 +55,12 @@ const navRail = defineModel("navRail", { type: Boolean })
<!-- System and help section -->
<v-list-subheader>
<div v-if="!navRail">{{ $t('menu.systemAndHelp') }}</div>
<div v-if="!navRail">{{ $t('menu.systemAndHelp.systemAndHelp') }}</div>
<div v-else></div>
</v-list-subheader>
<v-list-item :title="$t('menu.helpInstructions')" prepend-icon="mdi-chat-question" to="/help" link />
<v-list-item :title="$t('menu.scoreBoard')" prepend-icon="mdi-podium-gold" to="/scoreBoard" link />
<v-list-item :title="$t('menu.preferences')" prepend-icon="mdi-cog" to="/preferences" link />
<v-list-item :title="$t('menu.systemAndHelp.helpInstructions')" prepend-icon="mdi-chat-question" to="/help" link />
<v-list-item :title="$t('menu.systemAndHelp.scoreBoard')" prepend-icon="mdi-podium-gold" to="/scoreBoard" link />
<v-list-item :title="$t('menu.systemAndHelp.preferences')" prepend-icon="mdi-cog" to="/preferences" link />
<div v-if="accountStore.userAccount.accountRole.privilegeAdminPanel">
@@ -72,10 +72,6 @@ const navRail = defineModel("navRail", { type: Boolean })
</v-list-subheader>
<v-list-item :title="$t('menu.admin.dashboard')" prepend-icon="mdi-view-dashboard" to="/admin/dashboard" link />
<v-list-item :title="$t('menu.admin.categories')" prepend-icon="mdi-label" to="/admin/categories" link />
<v-list-item :title="$t('brand', 2)" prepend-icon="mdi-factory" to="/admin/brands" link />
<v-list-item :title="$t('menu.admin.products')" prepend-icon="mdi-store-cog" to="/admin/products" link />
<v-list-item :title="$t('menu.admin.accounts')" prepend-icon="mdi-account-multiple" to="/admin/accounts" link />
</div>
</v-list>

View File

@@ -0,0 +1,11 @@
import axios from "axios"
let BASE_URL = "http://localhost:3000/bands"
export async function getAllBands() {
return await axios.get(BASE_URL)
}
export async function getOneBand(id: number) {
return await axios.get(BASE_URL + '/' + id)
}

View File

@@ -1,7 +0,0 @@
import axios from "axios";
let BASE_URL = "http://localhost:3000/brands"
export async function getAllBrands() {
return await axios.get(BASE_URL)
}

View File

@@ -1,7 +0,0 @@
import axios from "axios"
let BASE_URL = "http://localhost:3000/categories"
export async function getAllCategories() {
return await axios.get(BASE_URL)
}

View File

@@ -0,0 +1,7 @@
import axios from "axios"
let BASE_URL = "http://localhost:3000/genres"
export async function getAllGenres() {
return await axios.get(BASE_URL)
}

View File

@@ -0,0 +1,7 @@
import axios from "axios"
let BASE_URL = "http://localhost:3000/locations"
export async function getAllLocations() {
return await axios.get(BASE_URL)
}

View File

@@ -1,10 +0,0 @@
import axios from "axios"
let BASE_URL = "http://localhost:3000/products"
/**
* Fetch all products from API
*/
export async function getAllProducts() {
return await axios.get(BASE_URL)
}

View File

@@ -0,0 +1,7 @@
import axios from "axios"
let BASE_URL = "http://localhost:3000/shows"
export async function getAllShows() {
return await axios.get(BASE_URL)
}

View File

@@ -0,0 +1,10 @@
import axios from "axios"
let BASE_URL = "http://localhost:3000/tours"
/**
* Fetch all tours from API
*/
export async function getAllTours() {
return await axios.get(BASE_URL)
}

View File

@@ -1,11 +1,11 @@
import { ProductModel } from "./productModel"
import { ShowModel } from "./showModel"
export class BasketItemModel {
id: number = -1
quantity: number = 1
product: ProductModel = new ProductModel()
product: ShowModel = new ShowModel()
constructor(quantity: number, product: ProductModel) {
constructor(quantity: number, product: ShowModel) {
this.quantity = quantity
this.product = product
}

View File

@@ -0,0 +1,5 @@
export class CityModel {
id: Number
name: String
country: String
}

View File

@@ -1,7 +1,9 @@
import { CityModel } from "./cityModel"
export class LocationModel {
id: Number
name: String
address: String
city: String
city: CityModel
image: String
}

View File

@@ -3,6 +3,5 @@ import { BandModel } from "./bandModel"
export class MemberModel {
id: Number
name: String
band: BandModel
image: String
}

View File

@@ -3,7 +3,6 @@ import { BandModel } from "./bandModel"
export class RatingModel {
id: Number
account: AccountModel
rating: Number
band: BandModel
}

View File

@@ -2,9 +2,9 @@ import { BandModel } from "./bandModel"
import { ShowModel } from "./showModel"
export class TourModel {
id: Number
name: String
id: number
name: string
offered: boolean
band: BandModel
offered: Boolean
shows: Array<ShowModel>
}

View File

@@ -6,8 +6,7 @@ import { useFeedbackStore } from "./feedbackStore";
import { BannerStateEnum } from "../enums/bannerStateEnum";
import { addOrder } from "../api/orderApi";
import { useAccountStore } from "./accountStore";
import { ProductModel } from "../models/productModel";
import { useProductStore } from "./productStore";
import { ShowModel } from "../models/showModel";
import { AddressModel } from "../models/addressModel";
import { PaymentModel } from "../models/paymentModel";
@@ -53,21 +52,21 @@ export const useBasketStore = defineStore('basketStore', {
/**
* Add an item to the basket. If the product is already in the basket, the quantity will increase
*
* @param product Product to add
* @param show Show to add
* @param quantity Quantity of the product
*/
addItemToBasket(product: ProductModel, quantity: number) {
addItemToBasket(show: ShowModel, quantity: number) {
const feedbackStore = useFeedbackStore()
feedbackStore.changeBanner(BannerStateEnum.BASKETPRODUCTADDED)
// Product is already in the basket, increase number of items
if (this.itemsInBasket.find((basketItem: BasketItemModel) =>
basketItem.product.id == product.id))
basketItem.product.id == show.id))
{
this.itemsInBasket.find((basketItem: BasketItemModel) =>
basketItem.product.id == product.id).quantity += quantity
basketItem.product.id == show.id).quantity += quantity
} else {
this.itemsInBasket.push(new BasketItemModel(quantity, product))
this.itemsInBasket.push(new BasketItemModel(quantity, show))
}
},
@@ -75,22 +74,23 @@ export const useBasketStore = defineStore('basketStore', {
* Take an order to the server. Sends all articles in the basket and creates an order entry in the backend database
*/
async takeOrder() {
const accountStore = useAccountStore()
const productStore = useProductStore()
const feedbackStore = useFeedbackStore()
// todo
// const accountStore = useAccountStore()
// const productStore = useProductStore()
// const feedbackStore = useFeedbackStore()
await addOrder(accountStore.userAccount.id, this.itemsInBasket, this.usedPayment.id, this.usedAddress.id)
.then(async result => {
if (result.status == 201) {
await accountStore.refreshOrders()
await productStore.fetchAllProducts()
// await addOrder(accountStore.userAccount.id, this.itemsInBasket, this.usedPayment.id, this.usedAddress.id)
// .then(async result => {
// if (result.status == 201) {
// await accountStore.refreshOrders()
// await productStore.fetchAllProducts()
this.itemsInBasket = []
feedbackStore.changeBanner(BannerStateEnum.ORDERPLACESUCCESSFUL)
} else {
feedbackStore.changeBanner(BannerStateEnum.ERROR)
}
})
// this.itemsInBasket = []
// feedbackStore.changeBanner(BannerStateEnum.ORDERPLACESUCCESSFUL)
// } else {
// feedbackStore.changeBanner(BannerStateEnum.ERROR)
// }
// })
}
}
})

View File

@@ -1,92 +0,0 @@
import { useLocalStorage } from "@vueuse/core";
import { defineStore } from "pinia";
import { getAllProducts } from "../api/productApi";
import { SortOrder } from "../enums/sortOrderEnum";
import { CategoryModel } from "../models/categoryModel";
import { ProductModel } from "../models/productModel";
import { BrandModel } from "../models/brandModel";
import { getAllCategories } from "../api/categoryApi";
import { getAllBrands } from "../api/brandApi";
export const useProductStore = defineStore("productStore", {
state: () => ({
products: useLocalStorage<Array<ProductModel>>("hackmycart/productStore/products", []),
filteredProducts: useLocalStorage<Array<ProductModel>>("hackmycart/productStore/filteredProducts", []),
sortOrder: useLocalStorage<SortOrder>("hackmycart/productStore/sortOrder", SortOrder.NAMEATOZ),
filteredCategory: useLocalStorage<CategoryModel>("hackmycart/productStore/filteredCategory", new CategoryModel()),
onlyDiscounts: useLocalStorage<Boolean>("hackmycart/productStore/onlyDiscounts", false),
brands: useLocalStorage<Array<BrandModel>>("hackmycart/productStore/brands", []),
categories: useLocalStorage<Array<CategoryModel>>("hackmycart/productStore/categories", [])
}),
actions: {
async fetchAllProducts() {
await getAllProducts()
.then(products => {
this.products = products.data
this.filteredProducts = products.data
})
},
async fetchAllCategories() {
await getAllCategories()
.then(categories => {
this.categories = categories.data
})
},
async fetchAllBrands() {
await getAllBrands()
.then(brands => {
this.brands = brands.data
})
},
async filterProducts() {
if (this.filteredCategory.id == -1 || this.filteredCategory.id == 0) {
this.filteredProducts = this.products
} else {
this.filteredProducts = this.products.filter((product: ProductModel) =>
product.category.id == this.filteredCategory.id
)
}
if (this.onlyDiscounts) {
this.filteredProducts = this.filteredProducts.filter((product: ProductModel) =>
product.discount > 0
)
}
},
sortProducts() {
this.filteredProducts.sort((a: ProductModel, b: ProductModel) => {
switch (this.sortOrder)
{
case SortOrder.PRICELOWTOHIGH: {
return a.price - b.price
}
case SortOrder.PRICEHIGHTOLOW: {
return b.price - a.price
}
case SortOrder.NAMEATOZ: {
if (b.name > a.name) {
return -1
}
else {
return 1
}
}
case SortOrder.NAMEZTOA: {
if (b.name < a.name) {
return -1
}
else {
return 1
}
}
}
})
}
}
})

View File

@@ -0,0 +1,21 @@
import { useLocalStorage } from "@vueuse/core";
import { defineStore } from "pinia";
import { TourModel } from "../models/tourModel";
import { getAllTours } from "../api/tourApi";
import { GenreModel } from "../models/genreModel";
export const useTourStore = defineStore("tourStore", {
state: () => ({
tours: useLocalStorage<Array<TourModel>>("hackmycart/tourStore/tours", []),
genres: useLocalStorage<Array<GenreModel>>("hackmycart/tourStore/genres", [])
}),
actions: {
async fetchAllTours() {
await getAllTours()
.then(result => {
this.tours = result.data
})
}
}
})

View File

@@ -1,24 +1,32 @@
{
"menu": {
"shopping": "Einkaufen",
"products": "Produkte",
"basket": "Warenkorb",
"login": "Login",
"account": "Account",
"orders": "Bestellungen",
"systemAndHelp": "System & Hilfe",
"helpInstructions": "Hilfestellung",
"preferences": "Einstellungen",
"logout": "Ausloggen",
"scoreBoard": "Score Board",
"shopping": {
"shopping": "Einkaufen",
"ticket": "Ticket | Tickets",
"basket": "Warenkorb"
},
"account": {
"accountManagement": "Kontoverwaltung",
"account": "Account",
"login": "Login",
"order": "Bestellung | Bestellungen",
"logout": "Ausloggen"
},
"systemAndHelp": {
"systemAndHelp": "System & Hilfe",
"helpInstructions": "Hilfestellung",
"preferences": "Einstellungen",
"scoreBoard": "Score Board"
},
"admin": {
"admin": "Administration",
"dashboard": "Dashboard",
"categories": "Kategorien",
"products": "Produkte",
"accounts": "Accounts"
"dashboard": "Dashboard"
}
},
"tours": {
"concert": "Konzert | Konzerte"
},
"preferences": {
"pageSetup": "Seiteneinstellungen",
"selectedTheme": "Ausgewähltes Theme",

View File

@@ -1,24 +1,33 @@
{
"menu": {
"shopping": "Shopping",
"products": "Products",
"basket": "Basket",
"login": "Login",
"account": "Account",
"orders": "Orders",
"systemAndHelp": "System & Help",
"helpInstructions": "Help instructions",
"preferences": "Preferences",
"logout": "Logout",
"scoreBoard": "Score Board",
"shopping": {
"shopping": "Shopping",
"ticket": "Ticket | Tickets",
"basket": "Basket"
},
"account": {
"account": "Account Management",
"login": "Login",
"order": "Order | Orders",
"logout": "Logout",
"accountManagement": "Account Management"
},
"systemAndHelp": {
"systemAndHelp": "System & Help",
"helpInstructions": "Help Instructions",
"preferences": "Preferences",
"scoreBoard": "Score Board"
},
"admin": {
"admin": "Administration",
"dashboard": "Dashboard",
"categories": "Categories",
"products": "Products",
"accounts": "Accounts"
"dashboard": "Dashboard"
}
},
"tours": {
"concert": "Concert | Concerts"
},
"preferences": {
"pageSetup": "Page setup",
"selectedTheme": "Selected theme",

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import cardView from '@/components/cardView.vue';
import { useProductStore } from '@/data/stores/productStore';
// import { useProductStore } from '@/data/stores/productStore';
const productStore = useProductStore()
// const productStore = useProductStore()
const headers = [
{ title: "Name", value: "name" },
@@ -11,7 +11,7 @@ const headers = [
</script>
<template>
<v-container max-width="800">
<!-- <v-container max-width="800">
<v-row>
<v-col>
<card-view
@@ -24,9 +24,8 @@ const headers = [
:headers="headers"
>
</v-data-table>
<!-- todo: Edit/Delete -->
</card-view>
</v-col>
</v-row>
</v-container>
</v-container> -->
</template>

View File

@@ -1,8 +1,5 @@
<script setup lang="ts">
import cardView from '@/components/cardView.vue';
import { useProductStore } from '@/data/stores/productStore';
const productStore = useProductStore()
const headers = [
{ title: "Name", value: "name" },
@@ -12,24 +9,5 @@ const headers = [
</script>
<template>
<v-container max-width="800">
<v-row>
<v-col>
<card-view
:title="$t('category', 2)"
icon="mdi-label"
:subtitle="productStore.categories.length + ' ' + $t('category', productStore.categories.length)"
>
<v-data-table
:items="productStore.categories"
:headers="headers"
>
<template v-slot:item.icon="{ item }">
<v-icon :icon="item.icon" />
</template>
</v-data-table>
</card-view>
</v-col>
</v-row>
</v-container>
</template>

View File

@@ -1,12 +1,10 @@
<script setup lang="ts">
import cardView from '@/components/cardView.vue';
import { ProductModel } from '@/data/models/productModel';
import { useProductStore } from '@/data/stores/productStore';
import productEditDialog from './productEditDialog.vue';
import { ref } from 'vue';
const productStore = useProductStore()
const editProduct = ref(new ProductModel())
// const productStore = useProductStore()
// const editProduct = ref(new ProductModel())
const showEditProductDialog = ref(false)
const headers = [
@@ -20,16 +18,16 @@ const headers = [
{ title: "Edit", value: "edit" },
]
function openEditProductDialog(product: ProductModel) {
editProduct.value = product
showEditProductDialog.value = true
}
// function openEditProductDialog(product: ProductModel) {
// editProduct.value = product
// showEditProductDialog.value = true
// }
</script>
<template>
<v-container>
<v-row>
<v-col>
<!-- <v-col>
<card-view
:title="$t('product.product', 2)"
:subtitle="productStore.products.length + ' ' + $t('product.product', productStore.products.length)"
@@ -88,11 +86,11 @@ function openEditProductDialog(product: ProductModel) {
</template>
</v-data-table>
</card-view>
</v-col>
</v-col> -->
</v-row>
</v-container>
<product-edit-dialog
<!-- <product-edit-dialog
v-model="showEditProductDialog"
:edit-product="editProduct" />
:edit-product="editProduct" /> -->
</template>

View File

@@ -1,53 +0,0 @@
<script setup lang="ts">
import productCard from "./productCard.vue"
import productDetails from "./productDetailsDialog.vue"
import { ref, watch } from "vue";
import { useProductStore } from "@/data/stores/productStore";
import filterNavDrawer from "./filterNavDrawer.vue";
import { ProductModel } from '@/data/models/productModel';
const productStore = useProductStore()
const showProductDetails = ref(false)
const dialogProduct = ref(new ProductModel())
function showProductDialog(product: ProductModel) {
dialogProduct.value = product
showProductDetails.value = true
}
watch(() => productStore.filteredCategory, async () => { productStore.filterProducts() })
watch(() => productStore.sortOrder, async () => { productStore.sortProducts() })
watch(() => productStore.onlyDiscounts, async () => { productStore.filterProducts() })
</script>
<template>
<v-container max-width="1000">
<v-row dense>
<v-col
v-if="productStore.filteredProducts.length > 0"
v-for="product in productStore.filteredProducts"
cols="12"
>
<product-card
:product="product"
@click="showProductDialog(product)"
/>
</v-col>
<v-col v-else>
<v-empty-state
icon="mdi-magnify"
headline="Keine Artikel gefunden"
/>
</v-col>
</v-row>
</v-container>
<filter-nav-drawer />
<product-details
v-model="showProductDetails"
:product="dialogProduct"
/>
</template>

View File

@@ -0,0 +1,6 @@
<script setup lang="ts">
</script>
<template>
</template>

View File

@@ -1,8 +1,8 @@
<script setup lang="ts">
import { SortOrder } from '@/data/enums/sortOrderEnum';
import { useProductStore } from '@/data/stores/productStore';
import { useTourStore } from '@/data/stores/tourStore';
const productStore = useProductStore()
const tourStore = useTourStore()
const sortOrderItems = Object.values(SortOrder)
</script>
@@ -11,15 +11,10 @@ const sortOrderItems = Object.values(SortOrder)
<v-list>
<v-list-subheader>Filter</v-list-subheader>
<v-list-item>
<v-checkbox :label="$t('offers')" v-model="productStore.onlyDiscounts" />
</v-list-item>
<v-list-item>
<!-- <v-list-item>
<v-select
:items="productStore.categories"
:items="tourStore.genres"
:label="$t('category', 2)"
v-model="productStore.filteredCategory"
>
<template v-slot:item="{ props, item }">
<v-list-item v-bind="props" :prepend-icon="item.raw.icon" :title="item.raw.name" />
@@ -29,12 +24,12 @@ const sortOrderItems = Object.values(SortOrder)
<v-list-item :prepend-icon="item.raw.icon" :title="item.raw.name" />
</template>
</v-select>
</v-list-item>
</v-list-item> -->
<v-divider />
<v-list-subheader>Sort</v-list-subheader>
<v-list-item>
<!-- <v-list-item>
<v-select :label="$t('sortBy')" :items="sortOrderItems" v-model="productStore.sortOrder" >
<template v-slot:item="{ props, item }">
<v-list-item v-bind="props" :title="item.title" />
@@ -44,7 +39,7 @@ const sortOrderItems = Object.values(SortOrder)
<v-list-item :title="item.title" />
</template>
</v-select>
</v-list-item>
</v-list-item> -->
</v-list>
</v-navigation-drawer>
</template>

View File

@@ -0,0 +1,50 @@
<script setup lang="ts">
import tourCard from "./tourCard.vue"
import { ref, watch } from "vue";
import filterNavDrawer from "./filterNavDrawer.vue";
import { useTourStore } from "@/data/stores/tourStore";
const tourStore = useTourStore()
const showProductDetails = ref(false)
// const dialogProduct = ref(new ProductModel())
// function showProductDialog(product: ProductModel) {
// dialogProduct.value = product
// showProductDetails.value = true
// }
// watch(() => productStore.filteredCategory, async () => { productStore.filterProducts() })
// watch(() => productStore.sortOrder, async () => { productStore.sortProducts() })
// watch(() => productStore.onlyDiscounts, async () => { productStore.filterProducts() })
</script>
<template>
<v-container max-width="1200">
<v-row dense>
<v-col
v-if="tourStore.tours.length > 0"
v-for="tour in tourStore.tours"
cols="12"
>
<tour-card
:tour="tour"
/>
</v-col>
<v-col v-else>
<v-empty-state
icon="mdi-magnify"
headline="Keine Artikel gefunden"
/>
</v-col>
</v-row>
</v-container>
<filter-nav-drawer />
<!-- <product-details
v-model="showProductDetails"
:product="dialogProduct"
/> -->
</template>

View File

@@ -1,35 +1,33 @@
<script setup lang="ts">
import { ProductModel } from '@/data/models/productModel';
import { TourModel } from '@/data/models/tourModel';
import cardView from '@/components/cardView.vue';
import OutlinedButton from '@/components/outlinedButton.vue';
defineProps({
product: {
tour: {
required: true,
type: ProductModel
type: TourModel
}
})
</script>
<template>
<card-view link>
<template #withoutContainer>
<v-row>
<v-col cols="3">
<v-sheet color="white">
<v-img
:src="'http://127.0.0.1:3000/static/' + product.images[0]"
height="200"
>
<template #placeholder>
<v-skeleton-loader type="image" />
</template>
</v-img>
</v-sheet>
</v-col>
<card-view
:title="tour.band.name"
:subtitle="tour.name"
:prepend-image="'http://127.0.0.1:3000/static/bands/' + tour.band.images[0]"
link
>
{{ tour.band.descriptionDe }}
<v-col cols="7" class="pl-0 pt-5">
<div class="text-h6">{{ product.name }}</div>
<div>
<template #actions>
<OutlinedButton>
{{ tour.shows.length }} {{ $t('tours.concert', tour.shows.length) }}
</OutlinedButton>
</template>
<!-- <template> -->
<!-- <div>
<v-rating
size="medium"
:model-value="product.rating"
@@ -40,19 +38,19 @@ defineProps({
/>
{{ product.rating }}/5
</div>
</div> -->
<div>
<!-- <div>
<v-list class="pa-0">
<v-list-item v-for="i in 2" class="pa-0 ma-0">
<v-icon icon="mdi-circle-small" /> {{ product.specs[i - 1] }}
</v-list-item>
</v-list>
</div>
</v-col>
</div> -->
<!-- </v-col> -->
<v-col cols="2" class="pt-5 pr-7">
<div v-if="product.discount == 0" class="font-weight-bold text-h5 text-right">
<!-- <v-col cols="2" class="pt-5 pr-7"> -->
<!-- <div v-if="product.discount == 0" class="font-weight-bold text-h5 text-right">
{{ product.price }}
</div>
@@ -63,9 +61,9 @@ defineProps({
<div>
<div class="text-decoration-line-through text-right">{{ product.price }} </div>
</div>
</div>
</div> -->
<div style="position: absolute; bottom: 0; right: 0;" class="pr-2 pb-2">
<!-- <div style="position: absolute; bottom: 0; right: 0;" class="pr-2 pb-2">
<div v-if="product.inStock > 5" class="text-green-lighten-1">
{{ $t("product.storedItemsAvailable", [product.inStock]) }}
</div>
@@ -75,10 +73,8 @@ defineProps({
<div v-else class="text-red">
{{ $t("product.soldOut") }}
</div>
</div>
</v-col>
</v-row>
</template>
</div> -->
<!-- </template> -->
</card-view>
</template>

View File

@@ -1,7 +1,7 @@
import AccountPage from "@/pages/accountPage/index.vue";
import OrdersPage from "@/pages/ordersPage/index.vue";
import PreferencesPage from "@/pages/preferencesPage/index.vue";
import ProductsPage from "@/pages/productsPage/index.vue";
import TourPage from "@/pages/toursPage/index.vue";
import LoginPage from "@/pages/loginPage/index.vue"
import BasketPage from "@/pages/basketPage/index.vue"
import HelpPage from "@/pages/helpPage/index.vue"
@@ -9,7 +9,7 @@ import ScoreBoardPage from "@/pages/scoreBoardPage/index.vue"
import adminRoutes from "./admin.routes";
const routes = [
{ path: '/', component: ProductsPage },
{ path: '/', component: TourPage },
{ path: '/account', component: AccountPage },
{ path: '/orders', component: OrdersPage },
{ path: '/preferences', component: PreferencesPage },