@shopbite-de/storefront 1.12.0 → 1.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/build.yaml +1 -1
- package/app/app.vue +10 -11
- package/app/components/Address/Detail.vue +40 -11
- package/app/components/Address/Fields.vue +1 -1
- package/app/components/Address/Form.vue +33 -25
- package/app/components/Category/Breadcrumb.vue +1 -1
- package/app/components/Category/Listing.vue +1 -7
- package/app/components/Checkout/LoginOrRegister.vue +0 -2
- package/app/components/Checkout/PaymentAndDelivery.vue +2 -2
- package/app/components/Checkout/Summary.vue +19 -4
- package/app/components/Footer.vue +32 -11
- package/app/components/Header/Body.vue +8 -20
- package/app/components/Header/Right.vue +77 -59
- package/app/components/Header.vue +3 -22
- package/app/components/Navigation/DesktopLeft2.vue +4 -9
- package/app/components/Navigation/MobileTop2.vue +3 -4
- package/app/components/Order/Detail.vue +44 -26
- package/app/components/SalesChannelSwitch.vue +2 -4
- package/app/components/User/Detail.vue +38 -5
- package/app/components/User/RegistrationForm.vue +9 -11
- package/app/composables/useCategory.ts +37 -0
- package/app/composables/useNavigation.ts +86 -0
- package/app/pages/anmelden.vue +1 -1
- package/app/pages/bestellung.vue +1 -9
- package/app/pages/konto/adressen.vue +10 -3
- package/app/pages/order/[id].vue +1 -1
- package/package.json +7 -6
- package/test/e2e/simple-checkout-as-recurring-customer.test.ts +67 -10
- package/test/nuxt/HeaderRight.test.ts +2 -14
- package/test/nuxt/PaymentAndDelivery.test.ts +1 -3
- package/test/nuxt/RegistrationForm.test.ts +90 -30
- package/app/components/Navigation/DesktopLeft.vue +0 -47
- package/app/components/Navigation/MobileTop.vue +0 -55
- package/app/layouts/listing.vue +0 -32
- package/app/pages/menu/[...all].vue +0 -52
- package/content/navigation.yml +0 -57
- /package/content/{unternehmen/agb.md → agb.md} +0 -0
- /package/content/{unternehmen/datenschutz.md → datenschutz.md} +0 -0
- /package/content/{unternehmen/zahlung-und-versand.md → zahlung-und-versand.md} +0 -0
package/app/app.vue
CHANGED
|
@@ -26,18 +26,17 @@ const { isClosedHoliday, refresh: refreshHolidays } = useHolidays();
|
|
|
26
26
|
|
|
27
27
|
await Promise.all([refreshBusinessHours(), refreshHolidays()]);
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
const { data: sessionContextData } = await useAsyncData(
|
|
31
|
-
"session-context",
|
|
32
|
-
async () => {
|
|
33
|
-
const response = await apiClient.invoke("readContext get /context");
|
|
34
|
-
return response.data as Schemas["SalesChannelContext"];
|
|
35
|
-
},
|
|
36
|
-
);
|
|
29
|
+
const sessionContextData = ref<Schemas["SalesChannelContext"]>();
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
31
|
+
const contextResponse = await apiClient
|
|
32
|
+
.invoke("readContext get /context")
|
|
33
|
+
.catch((error) => {
|
|
34
|
+
console.error("Error fetching session context data:", error);
|
|
35
|
+
return { data: undefined };
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
sessionContextData.value = contextResponse.data;
|
|
39
|
+
useSessionContext(sessionContextData.value);
|
|
41
40
|
|
|
42
41
|
// Toast configuration
|
|
43
42
|
const TOAST_CONFIG = {
|
|
@@ -1,22 +1,51 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { Schemas } from "#shopware";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
defineProps<{
|
|
5
5
|
address: Schemas["CustomerAddress"] | undefined | null;
|
|
6
|
+
withEditButton?: boolean;
|
|
6
7
|
}>();
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
+
const emit = defineEmits<{
|
|
10
|
+
"update:address": [address: Schemas["CustomerAddress"]];
|
|
11
|
+
}>();
|
|
12
|
+
|
|
13
|
+
const editMode = ref(false);
|
|
14
|
+
|
|
15
|
+
function onSubmit(updatedAddress: Schemas["CustomerAddress"] | undefined) {
|
|
16
|
+
if (!updatedAddress) return;
|
|
17
|
+
|
|
18
|
+
emit("update:address", updatedAddress);
|
|
19
|
+
editMode.value = false;
|
|
20
|
+
}
|
|
9
21
|
</script>
|
|
10
22
|
|
|
11
23
|
<template>
|
|
12
|
-
<div v-if="address">
|
|
13
|
-
<div
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
<div v-if="address" class="flex flex-col gap-2">
|
|
25
|
+
<div v-if="!editMode" class="flex flex-col gap-2">
|
|
26
|
+
<div>{{ address.firstName }} {{ address.lastName }}</div>
|
|
27
|
+
<div>{{ address.phoneNumber }}</div>
|
|
28
|
+
<div v-if="address.company">{{ address.company }}</div>
|
|
29
|
+
<div v-if="address.department">{{ address.department }}</div>
|
|
30
|
+
<div v-if="address.additionalAddressLine1">
|
|
31
|
+
{{ address.additionalAddressLine1 }}
|
|
32
|
+
</div>
|
|
33
|
+
<div v-if="address.additionalAddressLine2">
|
|
34
|
+
{{ address.additionalAddressLine2 }}
|
|
35
|
+
</div>
|
|
36
|
+
<div>{{ address.street }}</div>
|
|
37
|
+
<div>{{ address.zipcode }} {{ address.city }}</div>
|
|
38
|
+
<UButton
|
|
39
|
+
v-if="withEditButton"
|
|
40
|
+
variant="subtle"
|
|
41
|
+
icon="i-lucide-pen"
|
|
42
|
+
label="Bearbeiten"
|
|
43
|
+
block
|
|
44
|
+
@click="editMode = true"
|
|
45
|
+
/>
|
|
46
|
+
</div>
|
|
47
|
+
<div v-else>
|
|
48
|
+
<AddressForm :address="address" @submit-success="onSubmit" />
|
|
49
|
+
</div>
|
|
21
50
|
</div>
|
|
22
51
|
</template>
|
|
@@ -109,7 +109,7 @@ defineExpose({
|
|
|
109
109
|
>
|
|
110
110
|
<template #title>
|
|
111
111
|
An diese Adresse können wir leider nicht liefern.
|
|
112
|
-
<ULink to="/
|
|
112
|
+
<ULink to="/zahlung-und-versand">Weitere Infos.</ULink>
|
|
113
113
|
</template>
|
|
114
114
|
</UAlert>
|
|
115
115
|
|
|
@@ -10,23 +10,21 @@ const props = defineProps<{
|
|
|
10
10
|
address?: Schemas["CustomerAddress"] | undefined;
|
|
11
11
|
}>();
|
|
12
12
|
|
|
13
|
-
const
|
|
14
|
-
|
|
13
|
+
const config = useRuntimeConfig();
|
|
15
14
|
const { updateCustomerAddress, createCustomerAddress } = useAddress();
|
|
16
15
|
|
|
17
16
|
const state = reactive({
|
|
18
|
-
id: address
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
countryId: "018d9f162ade709b9ccc92929b44d236",
|
|
17
|
+
id: props.address?.id,
|
|
18
|
+
firstName: props.address?.firstName ?? undefined,
|
|
19
|
+
lastName: props.address?.lastName ?? undefined,
|
|
20
|
+
company: props.address?.company ?? undefined,
|
|
21
|
+
department: props.address?.department ?? undefined,
|
|
22
|
+
additionalAddressLine1: props.address?.additionalAddressLine1 ?? undefined,
|
|
23
|
+
phoneNumber: props.address?.phoneNumber ?? undefined,
|
|
24
|
+
street: props.address?.street ?? undefined,
|
|
25
|
+
zipcode: props.address?.zipcode ?? undefined,
|
|
26
|
+
city: props.address?.city ?? undefined,
|
|
27
|
+
countryId: config.public.site.countryId,
|
|
30
28
|
});
|
|
31
29
|
|
|
32
30
|
const schema = computed(() => createAddressSchema(state));
|
|
@@ -34,23 +32,33 @@ const schema = computed(() => createAddressSchema(state));
|
|
|
34
32
|
const toast = useToast();
|
|
35
33
|
|
|
36
34
|
async function onSubmit(event: FormSubmitEvent<AddressSchema>) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
try {
|
|
36
|
+
let response: undefined | Schemas["CustomerAddress"] = undefined;
|
|
37
|
+
if (event.data.id) {
|
|
38
|
+
response = await updateCustomerAddress(event.data);
|
|
39
|
+
} else {
|
|
40
|
+
response = await createCustomerAddress(event.data);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
toast.add({
|
|
44
|
+
title: "Erfolgreich gespeichert",
|
|
45
|
+
color: "success",
|
|
46
|
+
});
|
|
47
|
+
emit("submit-success", response);
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error("Address save failed:", error);
|
|
50
|
+
toast.add({
|
|
51
|
+
title: "Speichern fehlgeschlagen",
|
|
52
|
+
description: "Bitte versuchen Sie es erneut.",
|
|
53
|
+
color: "error",
|
|
54
|
+
});
|
|
41
55
|
}
|
|
42
|
-
|
|
43
|
-
toast.add({
|
|
44
|
-
title: "Erfolgreich gespeichert",
|
|
45
|
-
color: "success",
|
|
46
|
-
});
|
|
47
|
-
emit("submit-success", event.data);
|
|
48
56
|
}
|
|
49
57
|
|
|
50
58
|
const accountType = ref("privat");
|
|
51
59
|
|
|
52
60
|
const emit = defineEmits<{
|
|
53
|
-
"submit-success": [data:
|
|
61
|
+
"submit-success": [data: Schemas["CustomerAddress"]];
|
|
54
62
|
}>();
|
|
55
63
|
</script>
|
|
56
64
|
|
|
@@ -40,7 +40,7 @@ const { data } = await useAsyncData(cacheKey, async () => {
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
const items = computed<BreadcrumbItem[]>(() => {
|
|
43
|
-
if (!data.value) return [];
|
|
43
|
+
if (!data.value) return [{ label: "Kategorie", to: "#" }];
|
|
44
44
|
return data.value?.map((item: Schemas["Breadcrumb"]) => {
|
|
45
45
|
return {
|
|
46
46
|
label: item.name,
|
|
@@ -58,13 +58,7 @@ const {
|
|
|
58
58
|
defaultSearchCriteria: searchCriteria,
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
const {
|
|
62
|
-
|
|
63
|
-
const categoryCacheKey = computed(() => `category-${categoryId.value}`);
|
|
64
|
-
|
|
65
|
-
const { data: category } = await useAsyncData(categoryCacheKey, async () => {
|
|
66
|
-
return await categorySearch(categoryId.value);
|
|
67
|
-
});
|
|
61
|
+
const { category } = useCategory(categoryId);
|
|
68
62
|
|
|
69
63
|
useCategorySeo(category);
|
|
70
64
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import type { TabsItem } from "@nuxt/ui";
|
|
3
3
|
|
|
4
|
-
const { refreshUser } = useUser();
|
|
5
4
|
const items = [
|
|
6
5
|
{
|
|
7
6
|
label: "Daten erfassen",
|
|
@@ -18,7 +17,6 @@ const toast = useToast();
|
|
|
18
17
|
const { mergeWishlistProducts } = useWishlist();
|
|
19
18
|
|
|
20
19
|
async function handleLoginSuccess() {
|
|
21
|
-
await refreshUser();
|
|
22
20
|
mergeWishlistProducts();
|
|
23
21
|
toast.add({
|
|
24
22
|
title: "Wilkommen!",
|
|
@@ -89,7 +89,7 @@ watch(
|
|
|
89
89
|
<UIcon name="i-lucide-badge-euro" class="size-8" />
|
|
90
90
|
<h2 class="text-2xl text-blackish my-8">Zahlungsarten</h2>
|
|
91
91
|
<UButton
|
|
92
|
-
to="/
|
|
92
|
+
to="/zahlung-und-versand"
|
|
93
93
|
size="md"
|
|
94
94
|
variant="ghost"
|
|
95
95
|
icon="i-lucide-circle-question-mark"
|
|
@@ -106,7 +106,7 @@ watch(
|
|
|
106
106
|
<UIcon name="i-lucide-car" class="size-8" />
|
|
107
107
|
<h2 class="text-2xl text-blackish my-8">Versandarten</h2>
|
|
108
108
|
<UButton
|
|
109
|
-
to="/
|
|
109
|
+
to="/zahlung-und-versand"
|
|
110
110
|
size="md"
|
|
111
111
|
variant="ghost"
|
|
112
112
|
icon="i-lucide-circle-question-mark"
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import QuickView from "~/components/Cart/QuickView.vue";
|
|
3
3
|
import { useIntervalFn } from "@vueuse/core";
|
|
4
4
|
|
|
5
|
-
const { selectedPaymentMethod, selectedShippingMethod } =
|
|
6
|
-
|
|
5
|
+
const { createOrder, selectedPaymentMethod, selectedShippingMethod } =
|
|
6
|
+
useCheckout();
|
|
7
7
|
const { refreshCart } = useCart();
|
|
8
|
-
const { isLoggedIn, isGuestSession } = useUser();
|
|
8
|
+
const { isLoggedIn, isGuestSession, refreshUser } = useUser();
|
|
9
9
|
const { isCheckoutEnabled, refresh } = useShopBiteConfig();
|
|
10
10
|
const { trackOrder } = useTrackEvent();
|
|
11
11
|
|
|
@@ -13,6 +13,14 @@ const toast = useToast();
|
|
|
13
13
|
|
|
14
14
|
onMounted(() => {
|
|
15
15
|
refresh();
|
|
16
|
+
refreshUser({
|
|
17
|
+
associations: {
|
|
18
|
+
defaultShippingAddress: {},
|
|
19
|
+
defaultBillingAddress: {},
|
|
20
|
+
activeShippingAddress: {},
|
|
21
|
+
activeBillingAddress: {},
|
|
22
|
+
},
|
|
23
|
+
});
|
|
16
24
|
});
|
|
17
25
|
|
|
18
26
|
watch(isCheckoutEnabled, () => console.log(isCheckoutEnabled.value));
|
|
@@ -40,9 +48,16 @@ const customerDataAvailable = computed<boolean>(
|
|
|
40
48
|
() => isLoggedIn.value || isGuestSession.value,
|
|
41
49
|
);
|
|
42
50
|
|
|
51
|
+
const shippingAndPaymentSet = computed(
|
|
52
|
+
() => selectedPaymentMethod.value && selectedShippingMethod.value,
|
|
53
|
+
);
|
|
54
|
+
|
|
43
55
|
const isValidToProceed = computed(
|
|
44
56
|
() =>
|
|
45
|
-
customerDataAvailable.value &&
|
|
57
|
+
customerDataAvailable.value &&
|
|
58
|
+
isCheckoutEnabled.value &&
|
|
59
|
+
isValidTime.value &&
|
|
60
|
+
shippingAndPaymentSet.value,
|
|
46
61
|
);
|
|
47
62
|
|
|
48
63
|
const selectedDeliveryTime = ref("");
|
|
@@ -1,12 +1,33 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { useNavigation } from "~/composables/useNavigation";
|
|
3
|
+
import type {
|
|
4
|
+
FooterColumn,
|
|
5
|
+
FooterColumnLink,
|
|
6
|
+
NavigationMenuItem,
|
|
7
|
+
} from "@nuxt/ui";
|
|
8
|
+
|
|
9
|
+
const { footerMenu } = useNavigation(true);
|
|
5
10
|
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
const menuItemToFooterColumnLink = (
|
|
12
|
+
item: NavigationMenuItem,
|
|
13
|
+
): FooterColumnLink => ({
|
|
14
|
+
label: item.label ?? "",
|
|
15
|
+
to: item.to as string | undefined,
|
|
16
|
+
target: item.target as string | undefined,
|
|
17
|
+
icon: item.icon,
|
|
9
18
|
});
|
|
19
|
+
|
|
20
|
+
const menuItemsToFooterColumns = (
|
|
21
|
+
items: NavigationMenuItem[],
|
|
22
|
+
): FooterColumn[] =>
|
|
23
|
+
items.map((item) => ({
|
|
24
|
+
label: item.label ?? "",
|
|
25
|
+
children: item.children?.map(menuItemToFooterColumnLink) ?? [],
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
const footerColumns = computed<FooterColumn[]>(() =>
|
|
29
|
+
menuItemsToFooterColumns(footerMenu.value),
|
|
30
|
+
);
|
|
10
31
|
</script>
|
|
11
32
|
|
|
12
33
|
<template>
|
|
@@ -15,7 +36,7 @@ const columns = computed(() => {
|
|
|
15
36
|
<UFooter :ui="{ top: 'border-b border-default' }">
|
|
16
37
|
<template #top>
|
|
17
38
|
<UContainer>
|
|
18
|
-
<UFooterColumns :columns="
|
|
39
|
+
<UFooterColumns :columns="footerColumns" />
|
|
19
40
|
</UContainer>
|
|
20
41
|
</template>
|
|
21
42
|
|
|
@@ -29,15 +50,15 @@ const columns = computed(() => {
|
|
|
29
50
|
</NuxtLink>
|
|
30
51
|
</template>
|
|
31
52
|
|
|
32
|
-
<p
|
|
33
|
-
|
|
53
|
+
<p class="text-muted text-sm">
|
|
54
|
+
Alle Preise inkl. gesetzlicher Mehrwertsteuer zzgl. Versandkosten, wenn
|
|
55
|
+
nicht anders beschrieben
|
|
34
56
|
</p>
|
|
35
57
|
|
|
36
58
|
<template #right>
|
|
37
|
-
<UColorModeButton
|
|
59
|
+
<UColorModeButton />
|
|
38
60
|
|
|
39
61
|
<UButton
|
|
40
|
-
v-if="navigationData?.footer.withGithubLink"
|
|
41
62
|
to="https://github.com/shopbite-de/storefront"
|
|
42
63
|
target="_blank"
|
|
43
64
|
icon="i-simple-icons-github"
|
|
@@ -1,36 +1,24 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { useNavigation } from "~/composables/useNavigation";
|
|
3
3
|
|
|
4
|
-
const
|
|
4
|
+
const config = useRuntimeConfig();
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
|
|
6
|
+
const multiChannelEnabled = computed(
|
|
7
|
+
() => config.public.shopBite.feature.multiChannel === "true",
|
|
8
8
|
);
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
return navigationData.value.main.map((item) => ({
|
|
14
|
-
label: item.label,
|
|
15
|
-
icon: item.icon,
|
|
16
|
-
to: item.to,
|
|
17
|
-
target: item.target,
|
|
18
|
-
active:
|
|
19
|
-
item.to === "/"
|
|
20
|
-
? route.path.length === 1
|
|
21
|
-
: route.path.startsWith(item.to),
|
|
22
|
-
}));
|
|
23
|
-
});
|
|
10
|
+
console.log(multiChannelEnabled.value);
|
|
11
|
+
const { mainMenu } = useNavigation(false);
|
|
24
12
|
</script>
|
|
25
13
|
|
|
26
14
|
<template>
|
|
27
15
|
<UNavigationMenu
|
|
28
16
|
color="primary"
|
|
29
|
-
:items="
|
|
17
|
+
:items="mainMenu"
|
|
30
18
|
orientation="vertical"
|
|
31
19
|
class="-mx-2.5"
|
|
32
20
|
/>
|
|
33
|
-
<div class="my-4">
|
|
21
|
+
<div v-if="multiChannelEnabled" class="my-4">
|
|
34
22
|
<SalesChannelSwitch />
|
|
35
23
|
</div>
|
|
36
24
|
</template>
|
|
@@ -3,9 +3,10 @@ import { useUser } from "@shopware/composables";
|
|
|
3
3
|
import type { DropdownMenuItem } from "@nuxt/ui";
|
|
4
4
|
|
|
5
5
|
const cartQuickViewOpen = ref(false);
|
|
6
|
-
const { count } = useCart();
|
|
6
|
+
const { count: cartCount } = useCart();
|
|
7
|
+
const { count: wishListCount } = useWishlist();
|
|
7
8
|
const { isCheckoutEnabled } = useShopBiteConfig();
|
|
8
|
-
const { isLoggedIn, isGuestSession,
|
|
9
|
+
const { isLoggedIn, isGuestSession, logout } = useUser();
|
|
9
10
|
const toast = useToast();
|
|
10
11
|
|
|
11
12
|
const logoutHandler = () => {
|
|
@@ -17,50 +18,58 @@ const logoutHandler = () => {
|
|
|
17
18
|
});
|
|
18
19
|
};
|
|
19
20
|
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
21
|
+
const dropDownMenu = computed<DropdownMenuItem[][]>(() => {
|
|
22
|
+
if (isLoggedIn.value) {
|
|
23
|
+
return [
|
|
24
|
+
[
|
|
25
|
+
{
|
|
26
|
+
label: "Mein Konto",
|
|
27
|
+
type: "label",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
label: "Übersicht",
|
|
31
|
+
icon: "i-lucide-user",
|
|
32
|
+
to: "/konto",
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
label: "Bestellungen",
|
|
36
|
+
icon: "i-lucide-pizza",
|
|
37
|
+
to: "/konto/bestellungen",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
label: "Adressen",
|
|
41
|
+
icon: "i-lucide-house",
|
|
42
|
+
to: "/konto/adressen",
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
[
|
|
46
|
+
{
|
|
47
|
+
label: "Abmelden",
|
|
48
|
+
icon: "i-lucide-log-out",
|
|
49
|
+
onSelect: () => logoutHandler(),
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
];
|
|
53
|
+
} else {
|
|
54
|
+
return [
|
|
55
|
+
[
|
|
56
|
+
{
|
|
57
|
+
label: "Mein Konto",
|
|
58
|
+
type: "label",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
label: "Anmelden",
|
|
62
|
+
icon: "i-lucide-user",
|
|
63
|
+
to: "/anmelden",
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
label: "Registrieren",
|
|
67
|
+
icon: "i-lucide-user-plus",
|
|
68
|
+
to: "/registrierung",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
];
|
|
72
|
+
}
|
|
64
73
|
});
|
|
65
74
|
</script>
|
|
66
75
|
|
|
@@ -73,9 +82,7 @@ const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
|
|
|
73
82
|
icon="i-lucide-phone"
|
|
74
83
|
aria-label="Anrufen"
|
|
75
84
|
/>
|
|
76
|
-
<UDropdownMenu
|
|
77
|
-
:items="isLoggedIn || isGuestSession ? loggedInDropDown : loggedOutDropDown"
|
|
78
|
-
>
|
|
85
|
+
<UDropdownMenu :items="dropDownMenu">
|
|
79
86
|
<UChip v-if="isLoggedIn || isGuestSession" size="3xl" text="✓">
|
|
80
87
|
<UButton
|
|
81
88
|
aria-label="Konto Dropdown öffnen"
|
|
@@ -89,29 +96,42 @@ const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
|
|
|
89
96
|
aria-label="Konto Dropdown öffnen"
|
|
90
97
|
icon="i-lucide-user"
|
|
91
98
|
color="neutral"
|
|
92
|
-
variant="
|
|
99
|
+
variant="ghost"
|
|
93
100
|
/>
|
|
94
101
|
</UDropdownMenu>
|
|
102
|
+
<div>
|
|
103
|
+
<UChip :text="wishListCount" size="3xl">
|
|
104
|
+
<UButton
|
|
105
|
+
aria-label="Zur Merkliste"
|
|
106
|
+
color="neutral"
|
|
107
|
+
variant="ghost"
|
|
108
|
+
to="/merkliste"
|
|
109
|
+
icon="i-lucide-heart"
|
|
110
|
+
/>
|
|
111
|
+
</UChip>
|
|
112
|
+
</div>
|
|
95
113
|
<UDrawer
|
|
96
114
|
v-if="isCheckoutEnabled"
|
|
97
115
|
v-model:open="cartQuickViewOpen"
|
|
98
116
|
title="Warenkorb"
|
|
99
117
|
direction="right"
|
|
100
118
|
>
|
|
101
|
-
<UChip :text="
|
|
119
|
+
<UChip :text="cartCount" size="3xl">
|
|
102
120
|
<UButton
|
|
103
121
|
aria-label="Zum Warenkorb"
|
|
104
122
|
color="neutral"
|
|
105
|
-
variant="
|
|
106
|
-
icon="i-lucide-shopping-
|
|
123
|
+
variant="ghost"
|
|
124
|
+
icon="i-lucide-shopping-bag"
|
|
107
125
|
/>
|
|
108
126
|
</UChip>
|
|
109
127
|
|
|
110
128
|
<template #header>
|
|
111
|
-
<
|
|
112
|
-
<
|
|
113
|
-
|
|
114
|
-
|
|
129
|
+
<div class="h-full flex flex-col justify-center">
|
|
130
|
+
<h2 class="flex items-center gap-2 text-3xl md:text-4xl mt-8 mb-3 pb-2">
|
|
131
|
+
<UIcon name="i-lucide-shopping-bag" class="size-8" color="primary" />
|
|
132
|
+
Warenkorb
|
|
133
|
+
</h2>
|
|
134
|
+
</div>
|
|
115
135
|
</template>
|
|
116
136
|
<template #body>
|
|
117
137
|
<CartQuickView
|
|
@@ -122,5 +142,3 @@ const loggedOutDropDown = computed<DropdownMenuItem[][]>(() => {
|
|
|
122
142
|
</template>
|
|
123
143
|
</UDrawer>
|
|
124
144
|
</template>
|
|
125
|
-
|
|
126
|
-
<style scoped></style>
|
|
@@ -1,26 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import
|
|
2
|
+
import { useNavigation } from "~/composables/useNavigation";
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
const { data: navigationData } = await useAsyncData("navigation", () =>
|
|
7
|
-
queryCollection("navigation").first(),
|
|
8
|
-
);
|
|
9
|
-
|
|
10
|
-
const navi = computed<NavigationMenuItem[]>(() => {
|
|
11
|
-
if (!navigationData.value?.main) return [];
|
|
12
|
-
|
|
13
|
-
return navigationData.value.main.map((item) => ({
|
|
14
|
-
label: item.label,
|
|
15
|
-
icon: item.icon,
|
|
16
|
-
to: item.to,
|
|
17
|
-
target: item.target,
|
|
18
|
-
active:
|
|
19
|
-
item.to === "/"
|
|
20
|
-
? route.path.length === 1
|
|
21
|
-
: route.path.startsWith(item.to),
|
|
22
|
-
}));
|
|
23
|
-
});
|
|
4
|
+
const { mainMenu } = useNavigation(false);
|
|
24
5
|
|
|
25
6
|
const loginSlide = ref(false);
|
|
26
7
|
</script>
|
|
@@ -31,7 +12,7 @@ const loginSlide = ref(false);
|
|
|
31
12
|
<HeaderTitle />
|
|
32
13
|
</template>
|
|
33
14
|
|
|
34
|
-
<UNavigationMenu color="primary" variant="pill" :items="
|
|
15
|
+
<UNavigationMenu color="primary" variant="pill" :items="mainMenu" />
|
|
35
16
|
|
|
36
17
|
<template #right>
|
|
37
18
|
<HeaderRight />
|