Create OrdersPage, load orders from backend, move NavDrawer items to Component

This commit is contained in:
2024-09-11 20:49:55 +02:00
parent 463b49ba93
commit 0c20ef4366
34 changed files with 361 additions and 178 deletions

View File

@@ -1,8 +1,24 @@
{
"data": [
{ "id": 0, "icon": "mdi-chip", "name": "Electronic" },
{ "id": 1, "icon": "mdi-soccer", "name": "Sports" },
{ "id": 2, "icon": "mdi-tshirt-crew", "name": "Clothes" },
{ "id": 3, "icon": "mdi-bookshelf", "name": "Books" }
{
"id": 0,
"icon": "mdi-chip",
"name": "Electronic"
},
{
"id": 1,
"icon": "mdi-soccer",
"name": "Sports"
},
{
"id": 2,
"icon": "mdi-tshirt-crew",
"name": "Clothes"
},
{
"id": 3,
"icon": "mdi-bookshelf",
"name": "Books"
}
]
}

View File

@@ -0,0 +1,28 @@
{
"data": [
{
"id": 0,
"orderId": 0,
"productId": 0,
"quantity": 2
},
{
"id": 1,
"orderId": 1,
"productId": 6,
"quantity": 1
},
{
"id": 2,
"orderId": 2,
"productId": 3,
"quantity": 3
},
{
"id": 3,
"orderId": 2,
"productId": 2,
"quantity": 1
}
]
}

View File

@@ -1,10 +0,0 @@
{
"data": [
{
"orderId": 0,
"productId": 4,
"quantity": 2,
"totalPrice": 0
}
]
}

View File

@@ -1,16 +1,19 @@
{
"data": [
{ "id": 0, "accountId": 0, "totalPrice": 0 },
{ "id": 1, "accountId": 1, "totalPrice": 0 },
{ "id": 2, "accountId": 1, "totalPrice": 0 },
{ "id": 3, "accountId": 2, "totalPrice": 0 },
{ "id": 4, "accountId": 2, "totalPrice": 0 },
{ "id": 5, "accountId": 3, "totalPrice": 0 },
{ "id": 6, "accountId": 3, "totalPrice": 0 },
{ "id": 7, "accountId": 3, "totalPrice": 0 },
{ "id": 8, "accountId": 4, "totalPrice": 0 },
{ "id": 9, "accountId": 5, "totalPrice": 0 },
{ "id": 10, "accountId": 6, "totalPrice": 0 },
{ "id": 11, "accountId": 6, "totalPrice": 0 }
]
{
"id": 0,
"accountId": 0,
"totalPrice": 0
},
{
"id": 1,
"accountId": 3,
"totalPrice": 0
},
{
"id": 2,
"accountId": 3,
"totalPrice": 0
}
]
}

View File

@@ -2,8 +2,8 @@ import { Sequelize } from "sequelize-typescript"
// Models
import { Category } from "./models/category.model"
import { OrderedItem } from "./models/orderedItem.model"
import { Order } from "./models/order.model"
import { OrderItem } from "./models/orderItem.model"
import { Product } from "./models/product.model"
import { Account } from "./models/account.model"
@@ -18,7 +18,7 @@ export const sequelize = new Sequelize({
username: dbUser,
password: dbPassword,
storage: "database.sqlite",
models: [ Category, Product, Account, Order, OrderedItem ]
models: [ Category, Product, Account, Order, OrderItem ]
})
export function startDatabase() {

View File

@@ -1,7 +1,6 @@
import { Table, Column, Model, BelongsTo, ForeignKey, HasMany, BelongsToMany } from 'sequelize-typescript';
import { Account } from './account.model';
import { OrderedItem } from './orderedItem.model';
import { Product } from './product.model';
import { OrderItem } from './orderItem.model';
@Table
export class Order extends Model {
@@ -12,10 +11,11 @@ export class Order extends Model {
@Column
totalPrice: number
// Relations
@BelongsTo(() => Account)
user: Account
account: Account
@BelongsToMany(() => Product, () => OrderedItem)
orderedItems: OrderedItem
}
@HasMany(() => OrderItem)
orderItem: OrderItem[]
}

View File

@@ -0,0 +1,25 @@
import { Model, BelongsTo, Column, ForeignKey, HasMany, HasOne, Table } from "sequelize-typescript";
import { Product } from "./product.model";
import { Order } from "./order.model";
@Table
export class OrderItem extends Model {
@Column
@ForeignKey(() => Order)
orderId: number
@Column
quantity: number
@Column
@ForeignKey(() => Product)
productId: number
// Relations
@BelongsTo(() => Order)
order: Order
@BelongsTo(() => Product)
product: Product
}

View File

@@ -1,20 +0,0 @@
import { Table, Column, Model, BelongsTo, ForeignKey, HasMany } from 'sequelize-typescript';
import { Order } from './order.model';
import { Product } from './product.model';
@Table
export class OrderedItem extends Model {
@Column
@ForeignKey(() => Order)
orderId: number
@Column
@ForeignKey(() => Product)
productId: number
@Column
quantity: number
@Column
totalPrice: number
}

View File

@@ -1,7 +1,6 @@
import { Table, Column, Model, ForeignKey, BelongsTo, BelongsToMany } from 'sequelize-typescript';
import { Table, Column, Model, ForeignKey, BelongsTo, BelongsToMany, HasMany } from 'sequelize-typescript';
import { Category } from './category.model';
import { OrderedItem } from './orderedItem.model';
import { Order } from './order.model';
import { OrderItem } from './orderItem.model';
@Table
export class Product extends Model {
@@ -34,6 +33,6 @@ export class Product extends Model {
@BelongsTo(() => Category)
category: Category
@BelongsToMany(() => Order,() => OrderedItem)
orderedItem: OrderedItem
@HasMany(() => OrderItem)
order: OrderItem
}

View File

@@ -1,12 +1,18 @@
import { Router, Request, Response, NextFunction } from "express";
import { Order } from "../models/order.model";
import { Product } from "../models/product.model";
import { OrderItem } from "../models/orderItem.model";
export const order = Router()
order.get("/", (req: Request, res: Response, next: NextFunction) => {
Order.findAll()
Order.findAll({
where: { accountId: req.query.accountId },
include: [
{ model: OrderItem, include: [ Product ] }
]
})
.then(orders => {
res.json(orders)
res.send(orders)
})
.catch(next)
})

View File

@@ -0,0 +1,6 @@
import { Product } from "../models/product.model";
import { OrderItem } from "../models/orderItem.model";
import { Router, Request, Response, NextFunction } from "express";
export const orderItem = Router()

View File

@@ -1,12 +0,0 @@
import { Router, Request, Response, NextFunction } from "express";
import { OrderedItem } from "../models/orderedItem.model";
export const orderedItem = Router()
orderedItem.get("/", (req: Request, res: Response, next: NextFunction) => {
OrderedItem.findAll()
.then(orderedItems => {
res.json(orderedItems)
})
.catch(next)
})

View File

@@ -1,6 +1,6 @@
import { Category } from '../models/category.model'
import { OrderedItem } from '../models/orderedItem.model'
import { Order } from '../models/order.model'
import { OrderItem } from '../models/orderItem.model'
import { Product } from '../models/product.model'
import { Account } from '../models/account.model'
@@ -8,15 +8,15 @@ import categories from "./../data/categories.json"
import products from "./../data/products.json"
import accounts from "./../data/accounts.json"
import orders from "./../data/orders.json"
import orderedItems from "./../data/orderedItems.json"
import orderItems from "./../data/orderItems.json"
/**
* Delete all datasets in every database table
*/
export function deleteAllTables() {
Category.destroy({ truncate: true })
OrderedItem.destroy({ truncate: true })
Order.destroy({ truncate: true })
OrderItem.destroy({truncate: true })
Product.destroy({ truncate: true })
Account.destroy({ truncate: true })
}
@@ -29,5 +29,5 @@ export function prepopulateDatabase() {
Product.bulkCreate(products.data)
Account.bulkCreate(accounts.data)
Order.bulkCreate(orders.data)
OrderedItem.bulkCreate(orderedItems.data)
OrderItem.bulkCreate(orderItems.data)
}

View File

@@ -6,8 +6,8 @@ import { startDatabase } from './database'
import { category } from './routes/category.routes'
import { product } from './routes/product.routes'
import { order } from './routes/order.routes'
import { orderedItem } from './routes/orderedItem.routes'
import { account } from './routes/account.routes'
import { orderItem } from './routes/orderItem.routes'
const app = express()
const port = 3000
@@ -26,8 +26,8 @@ app.use("/api", api)
app.use("/categories", category)
app.use("/products", product)
app.use("/orders", order)
app.use("/ordereditems", orderedItem)
app.use("/accounts", account)
app.use("/orderItems", orderItem)
// Static files
const path = require('path')

View File

@@ -22,7 +22,7 @@
"sqlite3": "^5.1.7",
"ts-node": "^10.9.2",
"vue": "^3.4.29",
"vue-i18n": "^9.14.0",
"vue-i18n": "^10.0.0",
"vue-router": "^4.4.3",
"vuetify": "^3.7.1",
"wait-on": "^8.0.0"
@@ -521,13 +521,13 @@
}
},
"node_modules/@intlify/core-base": {
"version": "9.14.0",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.14.0.tgz",
"integrity": "sha512-zJn0imh9HIsZZUtt9v8T16PeVstPv6bP2YzlrYJwoF8F30gs4brZBwW2KK6EI5WYKFi3NeqX6+UU4gniz5TkGg==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.0.tgz",
"integrity": "sha512-o4d4Nve7YzU1YMR5VMqgPr8jDGTgT2pOOUtZa3JwCAhFnm40JYxfHdWToT7OEx6oJCBs/Q8HosJOhsimlF0C0Q==",
"license": "MIT",
"dependencies": {
"@intlify/message-compiler": "9.14.0",
"@intlify/shared": "9.14.0"
"@intlify/message-compiler": "10.0.0",
"@intlify/shared": "10.0.0"
},
"engines": {
"node": ">= 16"
@@ -537,12 +537,12 @@
}
},
"node_modules/@intlify/message-compiler": {
"version": "9.14.0",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.14.0.tgz",
"integrity": "sha512-sXNsoMI0YsipSXW8SR75drmVK56tnJHoYbPXUv2Cf9lz6FzvwsosFm6JtC1oQZI/kU+n7qx0qRrEWkeYFTgETA==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.0.tgz",
"integrity": "sha512-OcaWc63NC/9p1cMdgoNKBj4d61BH8sUW1Hfs6YijTd9656ZR4rNqXAlRnBrfS5ABq0vjQjpa8VnyvH9hK49yBw==",
"license": "MIT",
"dependencies": {
"@intlify/shared": "9.14.0",
"@intlify/shared": "10.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
@@ -553,9 +553,9 @@
}
},
"node_modules/@intlify/shared": {
"version": "9.14.0",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.0.tgz",
"integrity": "sha512-r+N8KRQL7LgN1TMTs1A2svfuAU0J94Wu9wWdJVJqYsoMMLIeJxrPjazihfHpmJqfgZq0ah3Y9Q4pgWV2O90Fyg==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.0.tgz",
"integrity": "sha512-6ngLfI7DOTew2dcF9WMJx+NnMWghMBhIiHbGg+wRvngpzD5KZJZiJVuzMsUQE1a5YebEmtpTEfUrDp/NqVGdiw==",
"license": "MIT",
"engines": {
"node": ">= 16"
@@ -4696,13 +4696,13 @@
}
},
"node_modules/vue-i18n": {
"version": "9.14.0",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.14.0.tgz",
"integrity": "sha512-LxmpRuCt2rI8gqU+kxeflRZMQn4D5+4M3oP3PWZdowW/ePJraHqhF7p4CuaME52mUxdw3Mmy2yAUKgfZYgCRjA==",
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.0.tgz",
"integrity": "sha512-KxTfTEuZEGN5Bvgc9F49rgp94XyBFlSIszwF2SQlr3WoxOklySXdUuoVxIw5qPZthV0mJlGP8tjJR7loMJgKrQ==",
"license": "MIT",
"dependencies": {
"@intlify/core-base": "9.14.0",
"@intlify/shared": "9.14.0",
"@intlify/core-base": "10.0.0",
"@intlify/shared": "10.0.0",
"@vue/devtools-api": "^6.5.0"
},
"engines": {

View File

@@ -31,7 +31,7 @@
"sqlite3": "^5.1.7",
"ts-node": "^10.9.2",
"vue": "^3.4.29",
"vue-i18n": "^9.14.0",
"vue-i18n": "^10.0.0",
"vue-router": "^4.4.3",
"vuetify": "^3.7.1",
"wait-on": "^8.0.0"

View File

@@ -4,7 +4,7 @@ import { useUserStore } from './data/stores/userStore';
import { i18n } from './plugins/i18n';
import { ref } from 'vue';
import vuetify from './plugins/vuetify';
import navigationDrawer from './components/navigationDrawer.vue';
import navigationItems from './components/navigationItems.vue';
const userStore = useUserStore()
const theme = useTheme()
@@ -23,7 +23,7 @@ i18n.global.locale = userStore.language
</v-app-bar>
<v-navigation-drawer :rail="navRail" permanent>
<navigation-drawer v-model:nav-rail="navRail" />
<navigation-items v-model:nav-rail="navRail" />
</v-navigation-drawer>
<v-main>

View File

@@ -1,15 +1,61 @@
<script setup lang="ts">
import { BannerStateEnum } from '@/data/enums/bannerStateEnum';
import BannerModel from '@/data/models/bannerModel';
import { getBannerMessage } from '@/scripts/contentScripts';
import { ref, watch } from 'vue';
import { useI18n } from 'vue-i18n';
const i18n = useI18n()
const alertBanner = defineModel("alertBanner", { required: true, type: BannerModel })
const title = ref("")
const color = ref("")
const icon = ref("")
function refreshBanner() {
switch (alertBanner.value.bannerState) {
case BannerStateEnum.ERROR: {
title.value = i18n.t('bannerMessages.error'); break;
}
case BannerStateEnum.DATABASERESETSUCCESSFUL: {
title.value = i18n.t('bannerMessages.databaseResetSuccessful'); break;
}
case BannerStateEnum.LOGINSUCCESSFUL: {
title.value = i18n.t('bannerMessages.loginSuccessful'); break;
}
case BannerStateEnum.WRONGLOGIN: {
title.value = i18n.t('bannerMessages.wrongLogin'); break;
}
}
switch (alertBanner.value.bannerState) {
case BannerStateEnum.ERROR:
case BannerStateEnum.WRONGLOGIN:
color.value = "red"
icon.value = "mdi-alert-circle"
break;
case BannerStateEnum.DATABASERESETSUCCESSFUL:
case BannerStateEnum.LOGINSUCCESSFUL:
color.value = "green"
icon.value = "mdi-check-circle"
break
}
}
watch(() => alertBanner.value.bannerState, () => {
refreshBanner()
})
refreshBanner()
</script>
<template>
<v-expand-transition>
<v-row v-if="alertBanner.show">
<v-col>
<v-alert v-model="alertBanner.show" :color="alertBanner.color" :icon="alertBanner.icon" closable>
{{ alertBanner.message }}
<v-alert v-model="alertBanner.show" :color="color" :icon="icon" closable>
{{ title }}
</v-alert>
</v-col>
</v-row>

View File

@@ -1,7 +1,6 @@
<script setup lang="ts">
import { useUserStore } from '@/data/stores/userStore';
import { useBasketStore } from '@/data/stores/basketStore';
import vuetify from '@/plugins/vuetify';
const userStore = useUserStore()
const basketStore = useBasketStore()
@@ -10,6 +9,8 @@ const navRail = defineModel("navRail", { type: Boolean })
<template>
<v-list>
<!-- Shopping Section -->
<v-list-subheader>
<div v-if="!navRail">{{ $t('menu.shopping') }}</div>
<div v-else></div>
@@ -25,17 +26,32 @@ const navRail = defineModel("navRail", { type: Boolean })
<v-divider />
<!-- Account Section -->
<v-list-subheader>
<div v-if="!navRail">{{ $t('menu.account') }}</div>
<div v-else></div>
</v-list-subheader>
<v-list-item v-if="userStore.userAccountId == -1" :title="$t('menu.login')" prepend-icon="mdi-login" to="/login" link />
<v-list-item v-else :title="$t('logout')" prepend-icon="mdi-logout" @click="userStore.userAccountId = -1" link />
<v-list-item v-if="userStore.userAccountId != -1" :title="$t('menu.account')" prepend-icon="mdi-account" to="/account" link />
<v-list-item v-if="userStore.userAccountId != -1" :title="$t('menu.orders')" prepend-icon="mdi-cart-check" to="/orders" link />
<v-expand-transition>
<div v-if="userStore.userAccountId == -1">
<v-list-item v-if="userStore.userAccountId == -1" :title="$t('menu.login')" prepend-icon="mdi-login" to="/login" link />
</div>
</v-expand-transition>
<v-expand-transition>
<div v-if="userStore.userAccountId != -1">
<v-list-item :title="$t('menu.logout')" prepend-icon="mdi-logout" @click="userStore.userAccountId = -1" link />
<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 />
</div>
</v-expand-transition>
<v-divider />
<!-- System and help section -->
<v-list-subheader>
<div v-if="!navRail">{{ $t('menu.systemAndHelp') }}</div>

View File

@@ -0,0 +1,6 @@
export enum BannerStateEnum {
DATABASERESETSUCCESSFUL,
ERROR,
WRONGLOGIN,
LOGINSUCCESSFUL
}

View File

@@ -1,6 +1,6 @@
import { BannerStateEnum } from "../enums/bannerStateEnum"
export default class BannerModel {
message: string = "Success!"
show: boolean = false
color: string = "green"
icon: string = "mdi-check"
bannerState: BannerStateEnum = BannerStateEnum.ERROR
}

View File

@@ -1,6 +1,5 @@
{
"menu":
{
"menu": {
"shopping": "Shopping",
"products": "Products",
"basket": "Basket",
@@ -9,7 +8,8 @@
"orders": "Orders",
"systemAndHelp": "System & Help",
"helpInstructions": "Help instructions",
"preferences": "Preferences"
"preferences": "Preferences",
"logout": "Logout"
},
"preferences": {
"pageSetup": "Page setup",
@@ -19,8 +19,14 @@
"resetDatabase": "Reset database",
"resetPreferences": "Reset preferences"
},
"products": "Products",
"product": "Product",
"product": {
"product": "Product",
"products": "Products",
"productName": "Product name",
"brand": "Brand",
"productPrice": "Unit price",
"category": "Category"
},
"offers": "Offers",
"categories": "Categories",
"sortBy": "Sort by",
@@ -30,14 +36,7 @@
"emptyBasketText": "Go to our products and add some of them to the basket",
"totalPrice": "Total price",
"orderNow": "Order now",
"category": "Category",
"brand": "Brand",
"productPrice": "Unit price",
"username": "Username",
"password": "Password",
"login": "Login",
"noAccountRegister": "Create new Account!",
"register": "Create Account",
"userInfo": {
"firstName": "First Name",
"lastName": "Family Name",
@@ -46,6 +45,19 @@
"postalCode": "Postal Code",
"city": "City"
},
"backToLogin": "Back to Login",
"logout": "Logout"
"account": {
"backToLogin": "Back to Login",
"username": "Username",
"password": "Password",
"noAccountRegister": "Create new Account!",
"register": "Create Account"
},
"bannerMessages": {
"loginSuccessful": "Login erfolgreich!",
"wrongLogin": "Falscher Username oder falsches Passwort!",
"error": "Some error occurred...",
"databaseResetSuccessful": "Database reset successful!"
}
}

View File

@@ -9,7 +9,8 @@
"orders": "Bestellungen",
"systemAndHelp": "System & Hilfe",
"helpInstructions": "Hilfestellung",
"preferences": "Einstellungen"
"preferences": "Einstellungen",
"logout": "Ausloggen"
},
"preferences": {
"pageSetup": "Seiteneinstellungen",
@@ -19,8 +20,14 @@
"resetDatabase": "Datenbank zurücksetzen",
"resetPreferences": "Einstellungen zurücksetzen"
},
"products": "Produkte",
"product": "Produkt",
"product": {
"product": "Produkt",
"products": "Produkte",
"productName": "Product Name",
"brand": "Marke",
"productPrice": "Einzelpreis",
"category": "Kategorie"
},
"offers": "Angebote",
"categories": "Kategorien",
"sortBy": "Sortieren nach",
@@ -29,15 +36,8 @@
"emptyBasketTitle": "Keine Artikel im Warenkorb",
"emptyBasketText": "Gehe zu unseren Produkten und lege Artikel in den Warenkorb",
"totalPrice": "Gesamtpreis",
"orderNow": "Jetzt bestellen",
"category": "Kategorie",
"brand": "Marke",
"productPrice": "Einzelpreis",
"username": "Username",
"password": "Passwort",
"login": "Login",
"noAccountRegister": "Neuen Account erstellen!",
"register": "Account erstellen",
"orderNow": "Jetzt bestellen",
"userInfo": {
"firstName": "Vorname",
"lastName": "Nachname",
@@ -46,6 +46,19 @@
"postalCode": "Postleitzahl",
"city": "Stadt"
},
"backToLogin": "Zurück zum Login",
"logout": "Ausloggen"
"account": {
"username": "Username",
"password": "Passwort",
"noAccountRegister": "Neuen Account erstellen!",
"register": "Account erstellen",
"backToLogin": "Zurück zum Login"
},
"bannerMessages": {
"loginSuccessful": "Login erfolgreich!",
"wrongLogin": "Falscher Username oder falsches Passwort!",
"error": "Es ist ein Fehler aufgetreten...",
"databaseResetSuccessful": "Datenbank erfolgreich zurück gesetzt!"
}
}

View File

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

View File

@@ -12,10 +12,10 @@ const basketStore = useBasketStore()
<v-card :title="$t('menu.basket')" prepend-icon="mdi-cart">
<v-card-subtitle v-if="basketStore.itemsInBasket.length > 0">
<div v-if="basketStore.itemsInBasket.length == 1">
{{ basketStore.itemsInBasket.length }} {{ $t('product') }}
{{ basketStore.itemsInBasket.length }} {{ $t('product.product') }}
</div>
<div v-else>
{{ basketStore.itemsInBasket.length }} {{ $t('products') }}
{{ basketStore.itemsInBasket.length }} {{ $t('product.products') }}
</div>
</v-card-subtitle>

View File

@@ -15,11 +15,11 @@ function removeFromBasket(basketItem: BasketItemModel) {
<thead>
<tr>
<th></th>
<th>{{ $t('category') }}</th>
<th>{{ $t('brand') }}</th>
<th>{{ $t('products') }}</th>
<th>{{ $t('product.category') }}</th>
<th>{{ $t('product.brand') }}</th>
<th>{{ $t('product.products') }}</th>
<th class="text-center">{{ $t('quantity') }}</th>
<th class="text-right">{{ $t('productPrice') }}</th>
<th class="text-right">{{ $t('product.productPrice') }}</th>
<th class="text-right">{{ $t('totalPrice') }}</th>
</tr>
</thead>

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import { BannerStateEnum } from '@/data/enums/bannerStateEnum';
import BannerModel from '@/data/models/bannerModel';
import { useUserStore } from '@/data/stores/userStore';
import axios from 'axios';
@@ -17,18 +18,14 @@ function startLogin() {
})
.then(res => {
if (res.status == 200) {
banner.value.message = "Logged in!"
banner.value.color = "green"
banner.value.icon = "mdi-check"
banner.value.bannerState = BannerStateEnum.LOGINSUCCESSFUL
banner.value.show = true
userStore.userAccountId = res.data.userAccountId
}
})
.catch(res => {
banner.value.message = "Wrong Username or Password!"
banner.value.color = "red"
banner.value.icon = "mdi-alert-circle"
banner.value.bannerState = BannerStateEnum.WRONGLOGIN
banner.value.show = true
})
}
@@ -39,23 +36,25 @@ function startLogin() {
<v-container>
<v-row>
<v-col>
<v-text-field :label="$t('username')" prepend-icon="mdi-account" clearable v-model="username"/>
<v-text-field :label="$t('account.username')" prepend-icon="mdi-account" clearable v-model="username"/>
</v-col>
</v-row>
<v-row>
<v-col>
<v-text-field :label="$t('password')" prepend-icon="mdi-key" type="password" clearable v-model="password" />
<v-text-field :label="$t('account.password')" prepend-icon="mdi-key" type="password"
clearable v-model="password" />
</v-col>
</v-row>
</v-container>
<v-card-actions>
<v-btn variant="outlined" @click="showRegisterCard = true" color="primary" prepend-icon="mdi-plus">
{{ $t('noAccountRegister') }}
{{ $t('account.noAccountRegister') }}
</v-btn>
<v-spacer />
<v-btn variant="outlined" append-icon="mdi-arrow-right" color="primary" @click="startLogin">{{ $t('login') }}</v-btn>
<v-btn variant="outlined" append-icon="mdi-arrow-right" color="primary"
@click="startLogin">{{ $t('menu.login') }}</v-btn>
</v-card-actions>
</v-card>

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import { BannerStateEnum } from '@/data/enums/bannerStateEnum';
import { AccountModel } from '@/data/models/accountModel';
import BannerModel from '@/data/models/bannerModel';
import axios from 'axios';
@@ -13,18 +14,14 @@ function registerUser() {
.then(res => {
console.log(res)
if (res.status == 200) {
banner.value.message = "Created!"
banner.value.color = "green"
banner.value.icon = "mdi-check"
banner.value.bannerState = BannerStateEnum.LOGINSUCCESSFUL
banner.value.show = true
}
})
.catch((error) => {
console.log(error)
if (error.status == 400) {
banner.value.color = "red"
banner.value.icon = "mdi-alert-circle"
banner.value.message = error.response.data.error
banner.value.bannerState = BannerStateEnum.WRONGLOGIN
banner.value.show = true
}
})
@@ -32,12 +29,12 @@ function registerUser() {
</script>
<template>
<v-card :title="$t('register')">
<v-card :title="$t('account.register')">
<v-container>
<v-row>
<v-col>
<v-text-field
:label="$t('username')"
:label="$t('account.username')"
prepend-icon="mdi-account"
v-model="newUser.username"
clearable
@@ -46,7 +43,7 @@ function registerUser() {
<v-col>
<v-text-field
:label="$t('password')"
:label="$t('account.password')"
prepend-icon="mdi-key"
type="password"
v-model="newUser.password"
@@ -100,9 +97,15 @@ function registerUser() {
</v-container>
<template #actions>
<v-btn prepend-icon="mdi-arrow-left" color="primary" variant="outlined" @click="showRegisterCard = false">{{ $t('backToLogin') }}</v-btn>
<v-btn prepend-icon="mdi-arrow-left" color="primary" variant="outlined"
@click="showRegisterCard = false">
{{ $t('backToLogin') }}
</v-btn>
<v-spacer />
<v-btn prepend-icon="mdi-account-plus" color="primary" variant="outlined" @click="registerUser">{{ $t('register') }}</v-btn>
<v-btn prepend-icon="mdi-account-plus" color="primary" variant="outlined"
@click="registerUser">
{{ $t('register') }}
</v-btn>
</template>
</v-card>
</template>

View File

@@ -0,0 +1,49 @@
<script setup lang="ts">
import { useUserStore } from '@/data/stores/userStore';
import axios from 'axios';
import { ref } from 'vue';
const userStore = useUserStore()
const orders = ref([])
axios.get("http://127.0.0.1:3000/orders", {
params: {
accountId: userStore.userAccountId
}
})
.then(res => {
orders.value = res.data
})
</script>
<template>
<v-container>
<v-row v-for="order in orders">
<v-col>
<v-card
:title="'Bestellung vom ' + order.createdAt"
:subtitle="$t('totalPrice') + ': ' + order.totalPrice + ' €'"
>
<v-table>
<thead>
<tr>
<th>{{ $t('quantity') }}</th>
<th>{{ $t('product.brand') }}</th>
<th>{{ $t('product.productName') }}</th>
<th>{{ $t('product.productPrice') }}</th>
</tr>
</thead>
<tbody>
<tr v-for="orderItem in order.orderItem">
<td>{{ orderItem.quantity }}x</td>
<td>{{ orderItem.product.brand }}</td>
<td>{{ orderItem.product.name }}</td>
<td>{{ orderItem.product.price }} </td>
</tr>
</tbody>
</v-table>
</v-card>
</v-col>
</v-row>
</v-container>
</template>

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import { BannerStateEnum } from '@/data/enums/bannerStateEnum';
import BannerModel from '@/data/models/bannerModel';
import axios from 'axios';
@@ -8,6 +9,7 @@ function resetDb() {
axios.get("http://127.0.0.1:3000/api/resetdatabase")
.then(res => {
if (res.status == 200) {
alertBanner.value.bannerState = BannerStateEnum.DATABASERESETSUCCESSFUL
alertBanner.value.show = true
}
})

View File

@@ -28,10 +28,10 @@ const onlyDiscounts = defineModel("onlyDiscounts", { required: true, type: Boole
<v-card>
<v-card-title>
<div v-if="numberOfItems == 1">
{{ numberOfItems }} {{ $t('product') }}
{{ numberOfItems }} {{ $t('product.product') }}
</div>
<div v-else>
{{ numberOfItems }} {{ $t('products') }}
{{ numberOfItems }} {{ $t('product.products') }}
</div>
</v-card-title>
<v-container class="pb-0">

View File

@@ -5,6 +5,7 @@ import english from './../locales/english.json'
type MessageSchema = typeof german
export const i18n = createI18n<[MessageSchema], 'de' | 'en'>({
legacy: false,
locale: 'de',
messages: {
'de': german,

View File

@@ -1,5 +1,5 @@
import AccountPage from "@/pages/AccountPage.vue";
import OrdersPage from "@/pages/OrdersPage.vue";
import OrdersPage from "@/pages/ordersPage/index.vue";
import PreferencesPage from "@/pages/preferencesPage/index.vue";
import ProductsPage from "@/pages/productsPage/index.vue";
import LoginPage from "@/pages/loginPage/index.vue"