Improved user feedback system, improved Product detail view
This commit is contained in:
@@ -14,14 +14,22 @@ defineProps({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-dialog max-width="800" v-model="showDialog">
|
||||
<v-card :title="title" >
|
||||
<v-img v-if="imageUrl != ''" :src="imageUrl" max-height="300" />
|
||||
|
||||
<v-card-text>
|
||||
<slot name="content"></slot>
|
||||
</v-card-text>
|
||||
<v-dialog max-width="1000" v-model="showDialog">
|
||||
<v-card :title="title" :subtitle="subtitle" >
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-img v-if="imageUrl != ''" :src="imageUrl" max-height="600" />
|
||||
</v-col>
|
||||
|
||||
<v-col>
|
||||
<v-card-text>
|
||||
<slot name="content"></slot>
|
||||
</v-card-text>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
||||
<v-card-actions>
|
||||
<slot name="actions"></slot>
|
||||
</v-card-actions>
|
||||
|
||||
@@ -3,13 +3,17 @@ import { AccountModel } from "../models/accountModel"
|
||||
|
||||
const BASE_URL = "http://localhost:3000/accounts"
|
||||
|
||||
export async function login(username: string, password: string) {
|
||||
export async function loginAccount(username: string, password: string) {
|
||||
return await axios.post(BASE_URL + "/login", {
|
||||
username: username,
|
||||
password: password
|
||||
})
|
||||
}
|
||||
|
||||
export async function register(account: AccountModel) {
|
||||
return await axios.post(BASE_URL + "/register", account)
|
||||
export async function registerAccount(account: AccountModel) {
|
||||
return await axios.post(BASE_URL, account)
|
||||
}
|
||||
|
||||
export async function updateAccount(account: AccountModel) {
|
||||
return await axios.patch(BASE_URL, account)
|
||||
}
|
||||
@@ -1,8 +1,79 @@
|
||||
export enum BannerStateEnum {
|
||||
DATABASERESETSUCCESSFUL,
|
||||
////////// System feedback //////////
|
||||
|
||||
// Some error
|
||||
ERROR,
|
||||
WRONGLOGIN,
|
||||
LOGINSUCCESSFUL,
|
||||
REGISTERSUCCESSFUL,
|
||||
USERNAMEINUSE
|
||||
|
||||
BASKETPRODUCTADDED,
|
||||
|
||||
BASKETPRODUCTREMOVED,
|
||||
|
||||
|
||||
////////// API Endpoint /api //////////
|
||||
|
||||
// Status: 200 OK
|
||||
DATABASERESETSUCCESSFUL,
|
||||
|
||||
|
||||
////////// API Endpoint /accounts //////////
|
||||
|
||||
// Status: 200 OK
|
||||
ACCOUNTLOGINSUCCESSFUL,
|
||||
|
||||
// Status: 400 Bad request
|
||||
ACCOUNTLOGINERROR,
|
||||
|
||||
// Status: 401 Unauthorized
|
||||
ACCOUNTLOGINWRONGLOGIN,
|
||||
|
||||
// Status: 201 Created
|
||||
ACCOUNTREGISTERSUCCESSFUL,
|
||||
|
||||
// Status: 400 Bad request
|
||||
ACCOUNTREGISTERERROR,
|
||||
|
||||
// Status: 409 Conflict
|
||||
ACCOUNTREGISTERUSERNAMEINUSE,
|
||||
|
||||
// Status: 200 OK
|
||||
ACCOUNTUPDATESUCCESSFUL,
|
||||
|
||||
// No status code, runs in local cache
|
||||
ACCOUNTLOGOUTSUCCESSFUL,
|
||||
|
||||
|
||||
////////// API Endpoint /categories //////////
|
||||
|
||||
// Status: 201 Created
|
||||
CATEGORYCREATESUCCESSFUL,
|
||||
|
||||
// Status: 200 OK
|
||||
CATEGORYDELETESUCESSFUL,
|
||||
|
||||
// Status: 400 Bad request
|
||||
CATEGORYCREATEERROR,
|
||||
|
||||
// Status: 400 Bad request
|
||||
CATEGORYDELETEERROR,
|
||||
|
||||
|
||||
////////// API Endpoint /orders //////////
|
||||
|
||||
// Status: 201 Created
|
||||
ORDERPLACESUCCESSFUL,
|
||||
|
||||
|
||||
////////// API Endpoint /products //////////
|
||||
|
||||
// Status: 201 Created
|
||||
PRODUCTCREATESUCCESSFUL,
|
||||
|
||||
// Status: 400 Bad request
|
||||
PRODUCTCREATEERROR,
|
||||
|
||||
// Status: 200 OK
|
||||
PRODUCTDELETESUCCESSFUL,
|
||||
|
||||
// Status: 400 Bad request
|
||||
PRODUCTDELETEERROR
|
||||
}
|
||||
@@ -2,6 +2,8 @@ import { defineStore } from "pinia";
|
||||
import { useLocalStorage } from "@vueuse/core";
|
||||
import { calcProductPrice } from "@/scripts/productScripts";
|
||||
import { BasketItemModel } from "../models/basketItemModel";
|
||||
import { useFeedbackStore } from "./feedbackStore";
|
||||
import { BannerStateEnum } from "../enums/bannerStateEnum";
|
||||
|
||||
export const useBasketStore = defineStore('basket', {
|
||||
state: () => ({
|
||||
@@ -22,12 +24,18 @@ export const useBasketStore = defineStore('basket', {
|
||||
|
||||
actions: {
|
||||
removeItemFromBasket(item: BasketItemModel) {
|
||||
const feedbackStore = useFeedbackStore()
|
||||
feedbackStore.changeBanner(BannerStateEnum.BASKETPRODUCTREMOVED)
|
||||
|
||||
this.itemsInBasket = this.itemsInBasket.filter((basketItemModel: BasketItemModel) =>
|
||||
basketItemModel.productId != item.productId
|
||||
)
|
||||
},
|
||||
|
||||
addItemToBasket(item: BasketItemModel) {
|
||||
const feedbackStore = useFeedbackStore()
|
||||
feedbackStore.changeBanner(BannerStateEnum.BASKETPRODUCTADDED)
|
||||
|
||||
// Product is already in the basket, increase number of items
|
||||
if (this.itemsInBasket.find((basketItem) => basketItem.productId == item.productId)) {
|
||||
this.itemsInBasket.find((basketItem) => basketItem.productId == item.productId).quantity += item.quantity
|
||||
|
||||
@@ -21,37 +21,116 @@ export const useFeedbackStore = defineStore("feedbackStore", {
|
||||
actions: {
|
||||
changeBanner(bannerState: BannerStateEnum) {
|
||||
switch (bannerState) {
|
||||
////////// System feedback //////////
|
||||
|
||||
case BannerStateEnum.ERROR: {
|
||||
this.title = this.i18n.t('bannerMessages.error'); break;
|
||||
}
|
||||
|
||||
case BannerStateEnum.BASKETPRODUCTADDED: {
|
||||
this.title = this.i18n.t('bannerMessages.basketProductAdded'); break;
|
||||
}
|
||||
|
||||
case BannerStateEnum.BASKETPRODUCTREMOVED: {
|
||||
this.title = this.i18n.t("bannerMessages.basketProductRemoved"); break;
|
||||
}
|
||||
|
||||
|
||||
////////// API Endpoint /api //////////
|
||||
|
||||
case BannerStateEnum.DATABASERESETSUCCESSFUL: {
|
||||
this.title = this.i18n.t('bannerMessages.databaseResetSuccessful'); break;
|
||||
}
|
||||
case BannerStateEnum.LOGINSUCCESSFUL: {
|
||||
|
||||
|
||||
////////// API Endpoint /accounts //////////
|
||||
|
||||
case BannerStateEnum.ACCOUNTLOGINSUCCESSFUL: {
|
||||
this.title = this.i18n.t('bannerMessages.loginSuccessful'); break;
|
||||
}
|
||||
case BannerStateEnum.WRONGLOGIN: {
|
||||
case BannerStateEnum.ACCOUNTLOGINWRONGLOGIN: {
|
||||
this.title = this.i18n.t('bannerMessages.wrongLogin'); break;
|
||||
}
|
||||
case BannerStateEnum.REGISTERSUCCESSFUL: {
|
||||
case BannerStateEnum.ACCOUNTLOGINERROR: {
|
||||
this.title = this.i18n.t('bannerMessages.error'); break;
|
||||
}
|
||||
case BannerStateEnum.ACCOUNTREGISTERSUCCESSFUL: {
|
||||
this.title = this.i18n.t("bannerMessages.registerSuccessful"); break;
|
||||
}
|
||||
case BannerStateEnum.USERNAMEINUSE: {
|
||||
case BannerStateEnum.ACCOUNTREGISTERUSERNAMEINUSE: {
|
||||
this.title = this.i18n.t("bannerMessages.usernameInUse"); break;
|
||||
}
|
||||
case BannerStateEnum.ACCOUNTUPDATESUCCESSFUL: {
|
||||
this.title = this.i18n.t("bannerMessages.accountUpdated"); break;
|
||||
}
|
||||
case BannerStateEnum.ACCOUNTLOGOUTSUCCESSFUL: {
|
||||
this.title = this.i18n.t('bannerMessages.logoutSuccessful'); break;
|
||||
}
|
||||
|
||||
|
||||
////////// API Endpoint /categories //////////
|
||||
|
||||
case BannerStateEnum.CATEGORYCREATESUCCESSFUL: {
|
||||
this.title = this.i18n.t('bannerMessages.categoryCreateSuccessful'); break;
|
||||
}
|
||||
case BannerStateEnum.CATEGORYDELETESUCESSFUL: {
|
||||
this.title = this.i18n.t('bannerMessages.categoryDeleteSuccessful'); break;
|
||||
}
|
||||
case BannerStateEnum.CATEGORYCREATEERROR: {
|
||||
this.title = this.i18n.t('bannerMessages.categoryCreateError'); break;
|
||||
}
|
||||
case BannerStateEnum.CATEGORYDELETEERROR: {
|
||||
this.title = this.i18n.t('bannerMessages.categoryDeleteError'); break;
|
||||
}
|
||||
|
||||
|
||||
////////// API Endpoint /orders //////////
|
||||
|
||||
case BannerStateEnum.ORDERPLACESUCCESSFUL: {
|
||||
this.title = this.i18n.t('bannerMessages.orderPlaceSuccessfull'); break;
|
||||
}
|
||||
|
||||
|
||||
////////// API Endpoint /products //////////
|
||||
|
||||
case BannerStateEnum.PRODUCTCREATESUCCESSFUL: {
|
||||
this.title = this.i18n.t('bannerMessages.productCreateSuccessful'); break;
|
||||
}
|
||||
case BannerStateEnum.PRODUCTCREATEERROR: {
|
||||
this.title = this.i18n.t('bannerMessages.productCreateError'); break;
|
||||
}
|
||||
case BannerStateEnum.PRODUCTDELETESUCCESSFUL: {
|
||||
this.title = this.i18n.t('bannerMessages.productDeleteSuccessful'); break;
|
||||
}
|
||||
case BannerStateEnum.PRODUCTDELETEERROR: {
|
||||
this.title = this.i18n.t('bannerMessages.productDeleteError'); break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (bannerState) {
|
||||
case BannerStateEnum.ERROR:
|
||||
case BannerStateEnum.WRONGLOGIN:
|
||||
case BannerStateEnum.USERNAMEINUSE:
|
||||
case BannerStateEnum.ACCOUNTLOGINERROR:
|
||||
case BannerStateEnum.ACCOUNTLOGINWRONGLOGIN:
|
||||
case BannerStateEnum.ACCOUNTREGISTERERROR:
|
||||
case BannerStateEnum.ACCOUNTREGISTERUSERNAMEINUSE:
|
||||
case BannerStateEnum.CATEGORYCREATEERROR:
|
||||
case BannerStateEnum.CATEGORYDELETEERROR:
|
||||
case BannerStateEnum.PRODUCTDELETESUCCESSFUL:
|
||||
case BannerStateEnum.PRODUCTDELETEERROR:
|
||||
this.color = "red"
|
||||
this.icon = "mdi-alert-circle"
|
||||
break;
|
||||
|
||||
case BannerStateEnum.DATABASERESETSUCCESSFUL:
|
||||
case BannerStateEnum.LOGINSUCCESSFUL:
|
||||
case BannerStateEnum.REGISTERSUCCESSFUL:
|
||||
case BannerStateEnum.ACCOUNTLOGINSUCCESSFUL:
|
||||
case BannerStateEnum.ACCOUNTREGISTERSUCCESSFUL:
|
||||
case BannerStateEnum.ACCOUNTUPDATESUCCESSFUL:
|
||||
case BannerStateEnum.ACCOUNTLOGOUTSUCCESSFUL:
|
||||
case BannerStateEnum.CATEGORYCREATESUCCESSFUL:
|
||||
case BannerStateEnum.CATEGORYDELETESUCESSFUL:
|
||||
case BannerStateEnum.ORDERPLACESUCCESSFUL:
|
||||
case BannerStateEnum.PRODUCTCREATESUCCESSFUL:
|
||||
case BannerStateEnum.PRODUCTCREATEERROR:
|
||||
this.color = "green"
|
||||
this.icon = "mdi-check-circle"
|
||||
break
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useLocalStorage } from "@vueuse/core";
|
||||
import { ThemeEnum } from "../enums/themeEnums";
|
||||
import { LanguageEnum } from "../enums/languageEnum";
|
||||
import { AccountModel } from "../models/accountModel";
|
||||
import { login, register } from "../api/accountApi";
|
||||
import { loginAccount, registerAccount, updateAccount } from "../api/accountApi";
|
||||
import { useFeedbackStore } from "./feedbackStore";
|
||||
import { BannerStateEnum } from "../enums/bannerStateEnum";
|
||||
|
||||
@@ -19,44 +19,60 @@ export const useUserStore = defineStore('userStore', {
|
||||
async login(username: string, password: string) {
|
||||
const feedbackStore = useFeedbackStore()
|
||||
|
||||
await login(username, password)
|
||||
await loginAccount(username, password)
|
||||
.then(result => {
|
||||
if (result.data.loginSuccessful) {
|
||||
this.userAccount = result.data.account
|
||||
this.loggedIn = true
|
||||
this.userAccount = result.data.account
|
||||
this.loggedIn = true
|
||||
|
||||
feedbackStore.changeBanner(BannerStateEnum.LOGINSUCCESSFUL)
|
||||
}
|
||||
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTLOGINSUCCESSFUL)
|
||||
})
|
||||
.catch(error => {
|
||||
this.userAccount = new AccountModel()
|
||||
this.loggedIn = false
|
||||
|
||||
feedbackStore.changeBanner(BannerStateEnum.WRONGLOGIN)
|
||||
if (error.status == 400) {
|
||||
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTLOGINERROR)
|
||||
} else if (error.status == 401) {
|
||||
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTLOGINWRONGLOGIN)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async registerAccount(account: AccountModel) {
|
||||
async registerAccount(userAccount: AccountModel) {
|
||||
const feedbackStore = useFeedbackStore()
|
||||
|
||||
await register(account)
|
||||
await registerAccount(userAccount)
|
||||
.then(res => {
|
||||
console.log(res)
|
||||
if (res.status == 200) {
|
||||
feedbackStore.changeBanner(BannerStateEnum.REGISTERSUCCESSFUL)
|
||||
if (res.status == 201) {
|
||||
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTREGISTERSUCCESSFUL)
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
if (error.status == 400) {
|
||||
feedbackStore.changeBanner(BannerStateEnum.USERNAMEINUSE)
|
||||
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTREGISTERERROR)
|
||||
} else if (error.status == 409) {
|
||||
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTREGISTERUSERNAMEINUSE)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
async updateAccount() {
|
||||
const feedbackStore = useFeedbackStore()
|
||||
|
||||
await updateAccount(this.userAccount)
|
||||
.then(res => {
|
||||
if (res.status == 200) {
|
||||
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTUPDATESUCCESSFUL)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
logout() {
|
||||
const feedbackStore = useFeedbackStore()
|
||||
|
||||
this.userAccount = new AccountModel()
|
||||
this.loggedIn = false
|
||||
|
||||
feedbackStore.changeBanner(BannerStateEnum.ACCOUNTLOGOUTSUCCESSFUL)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -25,7 +25,8 @@
|
||||
"productName": "Produkt Name",
|
||||
"brand": "Marke",
|
||||
"productPrice": "Einzelpreis",
|
||||
"category": "Kategorie"
|
||||
"category": "Kategorie",
|
||||
"description": "Beschreibung"
|
||||
},
|
||||
"offers": "Angebote",
|
||||
"categories": "Kategorien",
|
||||
@@ -64,7 +65,20 @@
|
||||
"error": "Es ist ein Fehler aufgetreten...",
|
||||
"databaseResetSuccessful": "Datenbank erfolgreich zurück gesetzt!",
|
||||
"registerSuccessful": "Account erfolgreich erstellt!",
|
||||
"usernameInUse": "Der Accountname ist bereits vergeben!"
|
||||
"usernameInUse": "Der Accountname ist bereits vergeben!",
|
||||
"accountUpdated": "Account erfolgreich aktualisiert",
|
||||
"logoutSuccessful": "Logout erfolgreich",
|
||||
"categoryCreateSuccessful": "Kategorie hinzugefügt",
|
||||
"categoryDeleteSuccessful": "Kategorie gelöscht",
|
||||
"categoryCreateError": "Fehler beim Erstellen der Kategorie",
|
||||
"categoryDeleteError": "Fehler beim Löschen der Kategorie",
|
||||
"orderPlaceSuccessfull": "Bestellung erfolgreich aufgegeben",
|
||||
"productCreateSuccessful": "Produkt hinzugefügt",
|
||||
"productCreateError": "Fehler beim Erstellen des Produktes",
|
||||
"productDeleteSuccessful": "Produkt erfolgreich entfernt",
|
||||
"productDeleteError": "Fehler beim Entfernen des Produktes",
|
||||
"basketProductAdded": "Artikel zum Warenkorb hinzugefügt",
|
||||
"basketProductRemoved": "Artikel aus Warenkorb entfernt"
|
||||
},
|
||||
"oclock": "Uhr"
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
"productName": "Product name",
|
||||
"brand": "Brand",
|
||||
"productPrice": "Unit price",
|
||||
"category": "Category"
|
||||
"category": "Category",
|
||||
"description": "Description"
|
||||
},
|
||||
"offers": "Offers",
|
||||
"categories": "Categories",
|
||||
@@ -64,7 +65,20 @@
|
||||
"error": "Some error occurred...",
|
||||
"databaseResetSuccessful": "Database reset successful!",
|
||||
"usernameInUse": "Username always in use!",
|
||||
"registerSuccessful": "Account successfully created!"
|
||||
"registerSuccessful": "Account successfully created!",
|
||||
"accountUpdated": "Account successfully updated",
|
||||
"logoutSuccessful": "Logout successful",
|
||||
"categoryCreateSuccessful": "Category created",
|
||||
"categoryDeleteSuccessful": "Category deleted",
|
||||
"categoryCreateError": "Error on creating category",
|
||||
"categoryDeleteError": "Error on deleting category",
|
||||
"orderPlaceSuccessfull": "Order successfully placed",
|
||||
"productCreateSuccessful": "Product created",
|
||||
"productCreateError": "Error on product creation",
|
||||
"productDeleteSuccessful": "Product successfully deleted",
|
||||
"productDeleteError": "Error on product delete",
|
||||
"basketProductAdded": "Add product to basket",
|
||||
"basketProductRemoved": "Product removed from basket"
|
||||
},
|
||||
"oclock": "o'clock"
|
||||
}
|
||||
|
||||
77
software/src/pages/accountPage/accountDataCard.vue
Normal file
77
software/src/pages/accountPage/accountDataCard.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<script setup lang="ts">
|
||||
import { useUserStore } from '@/data/stores/userStore';
|
||||
|
||||
const userStore = useUserStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-card title="Account">
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('account.username')"
|
||||
v-model="userStore.userAccount.username"
|
||||
disabled
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('account.password')"
|
||||
v-model="userStore.userAccount.password"
|
||||
type="password"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.firstName')"
|
||||
v-model="userStore.userAccount.firstName"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.lastName')"
|
||||
v-model="userStore.userAccount.lastName"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.street')"
|
||||
v-model="userStore.userAccount.street"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.houseNumber')"
|
||||
v-model="userStore.userAccount.houseNumber"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.postalCode')"
|
||||
v-model="userStore.userAccount.postalCode"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.city')"
|
||||
v-model="userStore.userAccount.city"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
||||
<v-card-actions>
|
||||
<v-btn @click="userStore.updateAccount()" >Save</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</template>
|
||||
@@ -1,84 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { useUserStore } from '@/data/stores/userStore';
|
||||
|
||||
|
||||
const userStore = useUserStore()
|
||||
import alertBanner from '@/components/alertBanner.vue';
|
||||
import accountDataCard from './accountDataCard.vue';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-container max-width="1000">
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-card title="Account">
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('account.username')"
|
||||
v-model="userStore.userAccount.username"
|
||||
disabled
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('account.password')"
|
||||
v-model="userStore.userAccount.password"
|
||||
type="password"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<alert-banner />
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.firstName')"
|
||||
v-model="userStore.userAccount.firstName"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.lastName')"
|
||||
v-model="userStore.userAccount.lastName"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.street')"
|
||||
v-model="userStore.userAccount.street"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.houseNumber')"
|
||||
v-model="userStore.userAccount.houseNumber"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.postalCode')"
|
||||
v-model="userStore.userAccount.postalCode"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col>
|
||||
<v-text-field
|
||||
:label="$t('userInfo.city')"
|
||||
v-model="userStore.userAccount.city"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
||||
<v-card-actions>
|
||||
<!-- todo -->
|
||||
<v-btn >Save</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<account-data-card />
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { useBasketStore } from '@/data/stores/basketStore';
|
||||
import productsTable from './productsTable.vue';
|
||||
import alertBanner from '@/components/alertBanner.vue';
|
||||
|
||||
const basketStore = useBasketStore()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<v-container max-width="1000">
|
||||
<v-row>
|
||||
<v-col>
|
||||
<alert-banner />
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-card :title="$t('menu.basket')" prepend-icon="mdi-cart">
|
||||
|
||||
@@ -2,15 +2,13 @@
|
||||
import productCard from "./productCard.vue"
|
||||
import productDetails from "./productDetails.vue"
|
||||
import filterBar from "./filterBar.vue"
|
||||
import { Ref, ref, watch } from "vue";
|
||||
import { CategoryModel } from "@/data/models/categoryModel";
|
||||
import { ref, watch } from "vue";
|
||||
import { FilterModel } from "@/data/models/filterModel";
|
||||
import { useProductStore } from "@/data/stores/productStore";
|
||||
import { useCategoryStore } from "@/data/stores/categoryStore";
|
||||
import { ProductWithCategoryModel } from "@/data/models/productWithCategoryModel";
|
||||
import alertBanner from "@/components/alertBanner.vue";
|
||||
|
||||
const productStore = useProductStore()
|
||||
const categoryStore = useCategoryStore()
|
||||
|
||||
const showProductDetails = ref(false)
|
||||
const dialogProduct = ref(new ProductWithCategoryModel())
|
||||
@@ -34,6 +32,11 @@ watch(() => productStore.onlyDiscounts, async () => { productStore.filterProduct
|
||||
|
||||
<template>
|
||||
<v-container>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<alert-banner />
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<filter-bar />
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { VNumberInput } from 'vuetify/labs/VNumberInput'
|
||||
import { ProductModel } from '@/data/models/productModel';
|
||||
import { CategoryModel } from '@/data/models/categoryModel';
|
||||
import { ModelRef, ref } from 'vue';
|
||||
import { useBasketStore } from '@/data/stores/basketStore';
|
||||
import { calcProductPrice, productToBasketItem } from '@/scripts/productScripts';
|
||||
import ActionDialog from '@/components/actionDialog.vue'
|
||||
import { ProductWithCategoryModel } from '@/data/models/productWithCategoryModel';
|
||||
import { BasketItemModel } from '@/data/models/basketItemModel';
|
||||
|
||||
const showDialog: ModelRef<boolean> = defineModel()
|
||||
const nrOfArticles = ref(1)
|
||||
@@ -17,7 +16,10 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
function addProductToBasket() {
|
||||
// todo basketStore.addItemToBasket(productToBasketItem(props.product, props.productCategory, nrOfArticles.value))
|
||||
basketStore.addItemToBasket(
|
||||
new BasketItemModel()
|
||||
)
|
||||
basketStore.addItemToBasket(productToBasketItem(props.product, nrOfArticles.value))
|
||||
nrOfArticles.value = 1
|
||||
showDialog.value = false
|
||||
}
|
||||
@@ -31,17 +33,38 @@ function addProductToBasket() {
|
||||
v-model="showDialog"
|
||||
>
|
||||
<template #content>
|
||||
<v-row>
|
||||
<!-- todo <v-col>
|
||||
<v-icon :icon="productCategory.icon" />
|
||||
{{ productCategory.name }}
|
||||
</v-col> -->
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-icon :icon="product.category.icon" />
|
||||
{{ product.category.name }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col class="text-h6">
|
||||
{{ $t("product.description") }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col class="text-body-1">
|
||||
{{ product.description }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-divider class="my-4" />
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<div class="d-flex align-center flex-column my-auto">
|
||||
<div class="text-h3"> {{ product.rating }} <span class="text-h6 ml-n3">/5</span> </div>
|
||||
<v-rating :model-value="product.rating" color="yellow-darken-3" half-increments disabled />
|
||||
</div>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-divider class="my-4" />
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-number-input
|
||||
@@ -56,10 +79,10 @@ function addProductToBasket() {
|
||||
density="comfortable"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-spacer />
|
||||
|
||||
<v-col cols="2" class="justify-center d-flex">
|
||||
<v-row>
|
||||
<v-col class="d-flex align-center flex-column my-auto text-h3">
|
||||
{{ calcProductPrice(product, nrOfArticles) }} €
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
@@ -29,7 +29,7 @@ export function calcPrice(price: number, discount: number = 0, quantity: number
|
||||
*
|
||||
* @returns BasketItemModel
|
||||
*/
|
||||
export function productToBasketItem(product: ProductModel, productCategory: CategoryModel, quantity: number): BasketItemModel {
|
||||
export function productToBasketItem(product: ProductWithCategoryModel, quantity: number): BasketItemModel {
|
||||
let result = new BasketItemModel()
|
||||
|
||||
result.productId = product.id
|
||||
@@ -38,8 +38,8 @@ export function productToBasketItem(product: ProductModel, productCategory: Cate
|
||||
result.brand = product.brand
|
||||
result.discount = product.discount
|
||||
result.name = product.name
|
||||
result.categoryName = productCategory.name
|
||||
result.categoryIcon = productCategory.icon
|
||||
result.categoryName = product.category.name
|
||||
result.categoryIcon = product.category.icon
|
||||
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user