New cardView component, add database reset confirm dialog

This commit is contained in:
2024-09-22 15:46:33 +02:00
parent 47fbb564b2
commit d7eae540b1
17 changed files with 224 additions and 95 deletions

View File

@@ -1,33 +1,33 @@
<script setup lang="ts"> <script setup lang="ts">
import { ModelRef } from 'vue'; import { ModelRef } from 'vue';
import cardView from './cardView.vue';
const showDialog: ModelRef<boolean> = defineModel() const showDialog: ModelRef<boolean> = defineModel()
defineProps({ defineProps({
title: String, title: String,
icon: { icon: {
type: String, type: String
default: "mdi-cog"
}, },
subtitle: { subtitle: {
type: String, type: String,
default: "" default: ""
},
imageUrl: {
type: String,
default: ""
} }
}) })
</script> </script>
<template> <template>
<v-dialog max-width="1200" v-model="showDialog"> <v-dialog max-width="1200" v-model="showDialog">
<v-card :title="title" :subtitle="subtitle" :prepend-icon="icon" density="compact"> <card-view
<slot name="content"></slot> :title="title"
:subtitle="subtitle"
<v-card-actions> :icon="icon"
>
<slot></slot>
<template #actions>
<slot name="actions"></slot> <slot name="actions"></slot>
</v-card-actions> </template>
</v-card> </card-view>
</v-dialog> </v-dialog>
</template> </template>

View File

@@ -0,0 +1,31 @@
<script setup lang="ts">
defineProps({
title: String,
icon: {
type: String
},
subtitle: {
type: String,
}
})
</script>
<template>
<v-card
:title="title"
:subtitle="subtitle"
:prepend-icon="icon"
class="card-outter"
>
<slot></slot>
<v-card-actions v-if="$slots.actions" class="card-actions">
<v-spacer />
<slot name="actions"></slot>
</v-card-actions>
</v-card>
</template>
<style>
</style>

View File

@@ -17,7 +17,8 @@
"language": "Sprache", "language": "Sprache",
"systemSetup": "Systemeinstellungen", "systemSetup": "Systemeinstellungen",
"resetDatabase": "Datenbank zurücksetzen", "resetDatabase": "Datenbank zurücksetzen",
"resetPreferences": "Einstellungen zurücksetzen" "resetPreferences": "Einstellungen zurücksetzen",
"resetConfirm": "Soll die Datenbank wirklich zurückgesetzt werden?"
}, },
"product": { "product": {
"product": "Produkt", "product": "Produkt",
@@ -82,5 +83,8 @@
"basketProductAdded": "Artikel zum Warenkorb hinzugefügt", "basketProductAdded": "Artikel zum Warenkorb hinzugefügt",
"basketProductRemoved": "Artikel aus Warenkorb entfernt" "basketProductRemoved": "Artikel aus Warenkorb entfernt"
}, },
"oclock": "Uhr" "oclock": "Uhr",
"ordering": {
"ordering": "Bestellabschluss"
}
} }

View File

@@ -17,7 +17,8 @@
"language": "Language", "language": "Language",
"systemSetup": "System setup", "systemSetup": "System setup",
"resetDatabase": "Reset database", "resetDatabase": "Reset database",
"resetPreferences": "Reset preferences" "resetPreferences": "Reset preferences",
"resetConfirm": "Really reset the database?"
}, },
"product": { "product": {
"product": "Product", "product": "Product",
@@ -82,5 +83,8 @@
"basketProductAdded": "Add product to basket", "basketProductAdded": "Add product to basket",
"basketProductRemoved": "Product removed from basket" "basketProductRemoved": "Product removed from basket"
}, },
"oclock": "o'clock" "oclock": "o'clock",
"ordering": {
"ordering": "Finish order"
}
} }

View File

@@ -1,11 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { useUserStore } from '@/data/stores/userStore'; import { useUserStore } from '@/data/stores/userStore';
import cardView from '@/components/cardView.vue';
const userStore = useUserStore() const userStore = useUserStore()
</script> </script>
<template> <template>
<v-card title="Account"> <card-view title="Account">
<v-container> <v-container>
<v-row> <v-row>
<v-col> <v-col>
@@ -70,8 +71,15 @@ const userStore = useUserStore()
</v-row> </v-row>
</v-container> </v-container>
<v-card-actions> <template #actions>
<v-btn @click="userStore.updateAccount()" >Save</v-btn> <v-btn
</v-card-actions> @click="userStore.updateAccount()"
</v-card> variant="outlined"
prepend-icon="mdi-content-save"
color="green"
>
Save
</v-btn>
</template>
</card-view>
</template> </template>

View File

@@ -2,6 +2,7 @@
import { useBasketStore } from '@/data/stores/basketStore'; import { useBasketStore } from '@/data/stores/basketStore';
import productsTable from './productsTable.vue'; import productsTable from './productsTable.vue';
import alertBanner from '@/components/alertBanner.vue'; import alertBanner from '@/components/alertBanner.vue';
import cardView from '@/components/cardView.vue';
const basketStore = useBasketStore() const basketStore = useBasketStore()
</script> </script>
@@ -15,7 +16,7 @@ const basketStore = useBasketStore()
</v-row> </v-row>
<v-row> <v-row>
<v-col> <v-col>
<v-card :title="$t('menu.basket')" prepend-icon="mdi-cart"> <card-view :title="$t('menu.basket')" prepend-icon="mdi-cart">
<v-card-subtitle v-if="basketStore.itemsInBasket.length > 0"> <v-card-subtitle v-if="basketStore.itemsInBasket.length > 0">
<div v-if="basketStore.itemsInBasket.length == 1"> <div v-if="basketStore.itemsInBasket.length == 1">
{{ basketStore.itemsInBasket.length }} {{ $t('product.product') }} {{ basketStore.itemsInBasket.length }} {{ $t('product.product') }}
@@ -33,19 +34,21 @@ const basketStore = useBasketStore()
:text="$t('emptyBasketText')" :text="$t('emptyBasketText')"
/> />
<v-card-text class="text-right" v-if="basketStore.itemsInBasket.length > 0"> <v-card-text class="text-right text-h5" v-if="basketStore.itemsInBasket.length > 0">
{{ $t('totalPrice') }}: {{ basketStore.getTotalPrice }} {{ $t('totalPrice') }}: {{ basketStore.getTotalPrice }}
</v-card-text> </v-card-text>
<v-card-actions> <template #actions>
<v-btn <v-btn
prepend-icon="mdi-basket-check" prepend-icon="mdi-basket-check"
:disabled="basketStore.itemsInBasket.length == 0" :disabled="basketStore.itemsInBasket.length == 0"
variant="outlined"
color="green"
> >
{{ $t('orderNow') }} {{ $t('orderNow') }}
</v-btn> </v-btn>
</v-card-actions> </template>
</v-card> </card-view>
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>

View File

@@ -0,0 +1,8 @@
<script setup lang="ts">
</script>
<template>
<v-dialog :title="$t('ordering.ordering')">
</v-dialog>
</template>

View File

@@ -8,29 +8,50 @@ const basketStore = useBasketStore()
function removeFromBasket(basketItem: BasketItemModel) { function removeFromBasket(basketItem: BasketItemModel) {
basketStore.removeItemFromBasket(basketItem) basketStore.removeItemFromBasket(basketItem)
} }
function editQuantity(basketItem: BasketItemModel) {
// todo
}
</script> </script>
<template> <template>
<v-table> <v-table>
<thead> <thead>
<tr> <tr>
<th></th>
<th>{{ $t('product.category') }}</th> <th>{{ $t('product.category') }}</th>
<th>{{ $t('product.brand') }}</th> <th>{{ $t('product.brand') }}</th>
<th>{{ $t('product.products') }}</th> <th>{{ $t('product.products') }}</th>
<th class="text-center">{{ $t('quantity') }}</th> <th class="text-center">{{ $t('quantity') }}</th>
<th class="text-right">{{ $t('product.productPrice') }}</th> <th class="text-right">{{ $t('product.productPrice') }}</th>
<th class="text-right">{{ $t('totalPrice') }}</th> <th class="text-right">{{ $t('totalPrice') }}</th>
<th></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="basketItem in basketStore.itemsInBasket"> <tr v-for="basketItem in basketStore.itemsInBasket">
<td><v-btn icon="mdi-delete" flat @click="removeFromBasket(basketItem)"/></td> <td><v-icon :icon="basketItem.categoryIcon" />
<td><v-icon :icon="basketItem.categoryIcon" /> {{ basketItem.categoryName }} </td> {{ basketItem.categoryName }}
<td>{{ basketItem.brand }}</td> </td>
<td>{{ basketItem.name }}</td>
<td class="text-center">{{ basketItem.quantity }}x</td> <td>
{{ basketItem.brand }}
</td>
<td>
{{ basketItem.name }}
</td>
<td class="text-center">
{{ basketItem.quantity }}x
<v-btn
icon="mdi-pencil"
@click="editQuantity(basketItem)"
color="orange"
variant="text"
flat
/>
</td>
<td class="text-right"> <td class="text-right">
<div v-if="basketItem.discount > 0"> <div v-if="basketItem.discount > 0">
@@ -46,7 +67,6 @@ function removeFromBasket(basketItem: BasketItemModel) {
</div> </div>
</td> </td>
<td class="text-right"> <td class="text-right">
<div v-if="basketItem.discount > 0"> <div v-if="basketItem.discount > 0">
<strong class="font-weight-bold text-body-1 text-red-lighten-1"> <strong class="font-weight-bold text-body-1 text-red-lighten-1">
@@ -61,7 +81,11 @@ function removeFromBasket(basketItem: BasketItemModel) {
<div v-else> <div v-else>
{{ calcPrice(basketItem.price, 0, basketItem.quantity) }} {{ calcPrice(basketItem.price, 0, basketItem.quantity) }}
</div> </div>
</td> </td>
<td>
<v-btn icon="mdi-delete" flat @click="removeFromBasket(basketItem)" color="red" variant="text"/>
</td>
</tr> </tr>
</tbody> </tbody>
</v-table> </v-table>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { BannerStateEnum } from '@/data/enums/bannerStateEnum';
import { useUserStore } from '@/data/stores/userStore'; import { useUserStore } from '@/data/stores/userStore';
import { ref } from 'vue'; import { ref } from 'vue';
import cardView from '@/components/cardView.vue';
const userStore = useUserStore() const userStore = useUserStore()
const showRegisterCard = defineModel("showRegisterCard", { type: Boolean, default: false }) const showRegisterCard = defineModel("showRegisterCard", { type: Boolean, default: false })
@@ -14,7 +14,7 @@ function startLogin() {
</script> </script>
<template> <template>
<v-card :title="$t('menu.login')" prepend-icon="mdi-login" elevation="8"> <card-view :title="$t('menu.login')" prepend-icon="mdi-login" elevation="8">
<v-container> <v-container>
<v-row> <v-row>
<v-col> <v-col>
@@ -30,14 +30,14 @@ function startLogin() {
</v-row> </v-row>
</v-container> </v-container>
<v-card-actions> <template #actions>
<v-btn variant="outlined" @click="showRegisterCard = true" color="primary" prepend-icon="mdi-plus"> <v-btn variant="outlined" @click="showRegisterCard = true" color="primary" prepend-icon="mdi-plus">
{{ $t('account.noAccountRegister') }} {{ $t('account.noAccountRegister') }}
</v-btn> </v-btn>
<v-spacer /> <v-spacer />
<v-btn variant="outlined" append-icon="mdi-arrow-right" color="primary" <v-btn variant="outlined" append-icon="mdi-arrow-right" color="primary"
@click="startLogin">{{ $t('menu.login') }}</v-btn> @click="startLogin">{{ $t('menu.login') }}</v-btn>
</v-card-actions> </template>
</v-card> </card-view>
</template> </template>

View File

@@ -1,9 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { BannerStateEnum } from '@/data/enums/bannerStateEnum';
import { AccountModel } from '@/data/models/accountModel'; import { AccountModel } from '@/data/models/accountModel';
import { useUserStore } from '@/data/stores/userStore'; import { useUserStore } from '@/data/stores/userStore';
import axios from 'axios';
import { ref } from 'vue'; import { ref } from 'vue';
import cardView from '@/components/cardView.vue';
const newUser = ref(new AccountModel()) const newUser = ref(new AccountModel())
const showRegisterCard = defineModel("showRegisterCard", { type: Boolean, default: false }) const showRegisterCard = defineModel("showRegisterCard", { type: Boolean, default: false })
@@ -11,7 +10,7 @@ const userStore = useUserStore()
</script> </script>
<template> <template>
<v-card :title="$t('account.register')"> <card-view :title="$t('account.register')">
<v-container> <v-container>
<v-row> <v-row>
<v-col> <v-col>
@@ -89,5 +88,5 @@ const userStore = useUserStore()
{{ $t('account.register') }} {{ $t('account.register') }}
</v-btn> </v-btn>
</template> </template>
</v-card> </card-view>
</template> </template>

View File

@@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { useUserStore } from '@/data/stores/userStore'; import { useUserStore } from '@/data/stores/userStore';
import ordersCard from './ordersCard.vue';
const userStore = useUserStore() const userStore = useUserStore()
@@ -28,47 +29,7 @@ function formatDateTimeString(string: string) {
<v-container max-width="1000"> <v-container max-width="1000">
<v-row v-for="order in userStore.orders"> <v-row v-for="order in userStore.orders">
<v-col> <v-col>
<v-card <orders-card :order="order" />
:title="$t('orders.orderFrom') + ' ' + formatDateTimeString(order.createdAt) + ' ' + $t('oclock')"
:subtitle="$t('totalPrice') + ': ' + order.totalPrice + ' €'"
>
<v-timeline direction="horizontal" side="start">
<v-timeline-item :dot-color="getDotColor(order, 1)" icon="mdi-basket-check">
{{ $t('orders.ordered') }}
</v-timeline-item>
<v-timeline-item :dot-color="getDotColor(order, 2)" icon="mdi-package-variant">
{{ $t('orders.preparingForShipping') }}
</v-timeline-item>
<v-timeline-item :dot-color="getDotColor(order, 3)" icon="mdi-truck-fast">
{{ $t('orders.shipped') }}
</v-timeline-item>
<v-timeline-item :dot-color="getDotColor(order, 4)" icon="mdi-package-check">
{{ $t('orders.delivered') }}
</v-timeline-item>
</v-timeline>
<v-table class="bg-surface-light">
<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-col>
</v-row> </v-row>
</v-container> </v-container>

View File

@@ -0,0 +1,72 @@
<script setup lang="ts">
import cardView from '@/components/cardView.vue';
import { OrderModel } from '@/data/models/orderModel';
defineProps({
order: OrderModel
})
function getDotColor(order, step: number) {
if (order.shippingProgress == step)
{
return "orange"
} else if (order.shippingProgress >= step)
{
return "green"
} else
{
return "grey"
}
}
function formatDateTimeString(string: string) {
let date = new Date(string)
return date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear() + ', ' +
date.getHours() + ':' + date.getMinutes()
}
</script>
<template>
<card-view
:title="$t('orders.orderFrom') + ' ' + formatDateTimeString(order.createdAt) + ' ' + $t('oclock')"
:subtitle="$t('totalPrice') + ': ' + order.totalPrice + ' €'"
>
<v-timeline direction="horizontal" side="start">
<v-timeline-item :dot-color="getDotColor(order, 1)" icon="mdi-basket-check">
{{ $t('orders.ordered') }}
</v-timeline-item>
<v-timeline-item :dot-color="getDotColor(order, 2)" icon="mdi-package-variant">
{{ $t('orders.preparingForShipping') }}
</v-timeline-item>
<v-timeline-item :dot-color="getDotColor(order, 3)" icon="mdi-truck-fast">
{{ $t('orders.shipped') }}
</v-timeline-item>
<v-timeline-item :dot-color="getDotColor(order, 4)" icon="mdi-package-check">
{{ $t('orders.delivered') }}
</v-timeline-item>
</v-timeline>
<v-table class="bg-surface-light">
<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>
</card-view>
</template>

View File

@@ -3,6 +3,7 @@ import { ThemeEnum } from '@/data/enums/themeEnums';
import { useTheme } from 'vuetify/lib/framework.mjs'; import { useTheme } from 'vuetify/lib/framework.mjs';
import { useUserStore } from '@/data/stores/userStore'; import { useUserStore } from '@/data/stores/userStore';
import { i18n } from '@/plugins/i18n'; import { i18n } from '@/plugins/i18n';
import cardView from '@/components/cardView.vue';
const userStore = useUserStore() const userStore = useUserStore()
const theme = useTheme() const theme = useTheme()
@@ -18,7 +19,7 @@ function changeLanguage() {
</script> </script>
<template> <template>
<v-card :title="$t('preferences.pageSetup')" prepend-icon="mdi-view-dashboard" elevation="8"> <card-view :title="$t('preferences.pageSetup')" prepend-icon="mdi-view-dashboard" elevation="8">
<v-container> <v-container>
<v-row> <v-row>
<v-col> <v-col>
@@ -39,5 +40,5 @@ function changeLanguage() {
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>
</v-card> </card-view>
</template> </template>

View File

@@ -2,8 +2,12 @@
import { BannerStateEnum } from '@/data/enums/bannerStateEnum'; import { BannerStateEnum } from '@/data/enums/bannerStateEnum';
import { useFeedbackStore } from '@/data/stores/feedbackStore'; import { useFeedbackStore } from '@/data/stores/feedbackStore';
import axios from 'axios'; import axios from 'axios';
import cardView from '@/components/cardView.vue';
import actionDialog from '@/components/actionDialog.vue';
import { ref } from 'vue';
const feedbackStore = useFeedbackStore() const feedbackStore = useFeedbackStore()
const confirmDialog = ref(false)
function resetDb() { function resetDb() {
axios.get("http://127.0.0.1:3000/api/resetdatabase") axios.get("http://127.0.0.1:3000/api/resetdatabase")
@@ -12,20 +16,22 @@ function resetDb() {
feedbackStore.changeBanner(BannerStateEnum.DATABASERESETSUCCESSFUL) feedbackStore.changeBanner(BannerStateEnum.DATABASERESETSUCCESSFUL)
} }
}) })
confirmDialog.value = false
// todo: Request all data // todo: Request all data
} }
function resetSettings() { function resetSettings() {
// todo
} }
</script> </script>
<template> <template>
<v-card :title="$t('preferences.systemSetup')" prepend-icon="mdi-engine" elevation="8"> <card-view :title="$t('preferences.systemSetup')" prepend-icon="mdi-engine" elevation="8">
<v-container> <v-container>
<v-row> <v-row>
<v-col class="d-flex justify-center align-center"> <v-col class="d-flex justify-center align-center">
<v-btn @click="resetDb" color="primary" prepend-icon="mdi-database-refresh"> <v-btn @click="confirmDialog = true" color="primary" prepend-icon="mdi-database-refresh">
{{ $t('preferences.resetDatabase') }} {{ $t('preferences.resetDatabase') }}
</v-btn> </v-btn>
</v-col> </v-col>
@@ -36,5 +42,14 @@ function resetSettings() {
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>
</v-card> </card-view>
<action-dialog :title="$t('preferences.resetConfirm')" v-model="confirmDialog" width="600">
<template #actions>
<v-btn variant="outlined" @click="resetDb" color="red">
{{ $t('preferences.resetDatabase') }}
</v-btn>
</template>
</action-dialog>
</template> </template>

View File

@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import productCard from "./productCard.vue" import productCard from "./productCard.vue"
import productDetails from "./productDetails.vue" import productDetails from "./productDetailsDialog.vue"
import { ref, watch } from "vue"; import { ref, watch } from "vue";
import { useProductStore } from "@/data/stores/productStore"; import { useProductStore } from "@/data/stores/productStore";
import { ProductWithCategoryModel } from "@/data/models/productWithCategoryModel"; import { ProductWithCategoryModel } from "@/data/models/productWithCategoryModel";

View File

@@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ProductWithCategoryModel } from '@/data/models/productWithCategoryModel'; import { ProductWithCategoryModel } from '@/data/models/productWithCategoryModel';
import cardView from '@/components/cardView.vue';
defineProps({ defineProps({
product: { product: {
@@ -10,7 +11,7 @@ defineProps({
</script> </script>
<template> <template>
<v-card link> <card-view link>
<v-row> <v-row>
<v-col cols="3"> <v-col cols="3">
<v-sheet color="white"> <v-sheet color="white">
@@ -76,7 +77,7 @@ defineProps({
</div> </div>
</v-col> </v-col>
</v-row> </v-row>
</v-card> </card-view>
</template> </template>
<style scoped> <style scoped>

View File

@@ -40,7 +40,6 @@ watch(() => props.product.images, () => {
:subtitle="product.category.name" :subtitle="product.category.name"
v-model="showDialog" v-model="showDialog"
> >
<template #content>
<v-container class="pt-n3"> <v-container class="pt-n3">
<v-row> <v-row>
<!-- Image col --> <!-- Image col -->
@@ -137,7 +136,6 @@ watch(() => props.product.images, () => {
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>
</template>
<template #actions> <template #actions>
<v-number-input <v-number-input