From f6167d5a1246745b0bf100b006dcfc44a064c9e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Dziedzi=C5=84ski?= <32803679+Michal-Dziedzinski@users.noreply.github.com> Date: Thu, 7 May 2020 10:34:37 +0200 Subject: [PATCH] feat: add MegaMenu component (#593) * feat: add MegaMenu component * feat(helpers): getCategoryUrl Co-authored-by: Patryk Tomczyk <13100280+patzick@users.noreply.github.com> Co-authored-by: martaradziszewska --- api/composables.api.md | 15 +++- api/helpers.api.md | 4 + .../models/content/category/Category.ts | 3 + .../__tests__/useNavigation.spec.ts | 21 +++++ .../composables/src/hooks/useNavigation.ts | 30 ++++++-- .../default-theme/components/SwMegaMenu.vue | 77 +++++++++++++++++++ ...{TopNavigation.vue => SwTopNavigation.vue} | 70 +++++++++-------- packages/default-theme/layouts/default.vue | 6 +- .../default-theme/pages/account/orders.vue | 15 ++-- .../__tests__/category/getCategoryUrl.spec.ts | 23 ++++++ .../helpers/src/category/getCategoryUrl.ts | 9 +++ packages/helpers/src/category/index.ts | 1 + 12 files changed, 229 insertions(+), 45 deletions(-) create mode 100644 packages/default-theme/components/SwMegaMenu.vue rename packages/default-theme/components/{TopNavigation.vue => SwTopNavigation.vue} (82%) create mode 100644 packages/helpers/__tests__/category/getCategoryUrl.spec.ts create mode 100644 packages/helpers/src/category/getCategoryUrl.ts diff --git a/api/composables.api.md b/api/composables.api.md index c91c93228..2e43a983f 100644 --- a/api/composables.api.md +++ b/api/composables.api.md @@ -16,6 +16,7 @@ import { CustomerUpdateEmailParam } from '@shopware-pwa/shopware-6-client'; import { CustomerUpdatePasswordParam } from '@shopware-pwa/shopware-6-client'; import { CustomerUpdateProfileParam } from '@shopware-pwa/shopware-6-client'; import { GuestOrderParams } from '@shopware-pwa/commons/interfaces/request/GuestOrderParams'; +import { NavigationElement } from '@shopware-pwa/commons/interfaces/models/content/navigation/Navigation'; import { Order } from '@shopware-pwa/commons/interfaces/models/checkout/order/Order'; import { PaymentMethod } from '@shopware-pwa/commons/interfaces/models/checkout/payment/PaymentMethod'; import { Product } from '@shopware-pwa/commons/interfaces/models/content/product/Product'; @@ -154,7 +155,19 @@ export interface UseCurrency { export const useCurrency: () => UseCurrency; // @alpha (undocumented) -export const useNavigation: () => any; +export interface UseNavigation { + // (undocumented) + fetchNavigationElements: (depth: number) => Promise; + // (undocumented) + fetchRoutes: () => Promise; + // (undocumented) + navigationElements: NavigationElement[]; + // (undocumented) + routes: Ref>; +} + +// @alpha (undocumented) +export const useNavigation: () => UseNavigation; // @alpha (undocumented) export interface UseProduct { diff --git a/api/helpers.api.md b/api/helpers.api.md index d0d68ede9..336363a03 100644 --- a/api/helpers.api.md +++ b/api/helpers.api.md @@ -4,6 +4,7 @@ ```ts +import { Category } from '@shopware-pwa/commons/interfaces/models/content/category/Category'; import { CmsPage } from '@shopware-pwa/commons/interfaces/models/content/cms/CmsPage'; import { CmsSection } from '@shopware-pwa/commons/interfaces/models/content/cms/CmsPage'; import { Country } from '@shopware-pwa/commons/interfaces/models/system/country/Country'; @@ -72,6 +73,9 @@ export function getCategoryAvailableSorting({ sorting, }?: { sorting?: Sorting; }): UiCategorySorting[]; +// @alpha +export const getCategoryUrl: (category: Partial) => string; + // @alpha (undocumented) export function getCmsSections(content: CmsPage): CmsSection[]; diff --git a/packages/commons/interfaces/models/content/category/Category.ts b/packages/commons/interfaces/models/content/category/Category.ts index fcfec6f22..09576d830 100644 --- a/packages/commons/interfaces/models/content/category/Category.ts +++ b/packages/commons/interfaces/models/content/category/Category.ts @@ -39,4 +39,7 @@ export interface Category extends Entity { parentVersionId: string; childrenCount: number; afterCategoryVersionId: string; + route?: { + path?: string; + }; } diff --git a/packages/composables/__tests__/useNavigation.spec.ts b/packages/composables/__tests__/useNavigation.spec.ts index 1e67c7d67..5b455d395 100644 --- a/packages/composables/__tests__/useNavigation.spec.ts +++ b/packages/composables/__tests__/useNavigation.spec.ts @@ -7,6 +7,9 @@ jest.mock("@shopware-pwa/shopware-6-client"); const mockedGetPage = shopwareClient as jest.Mocked; describe("Composables - useNavigation", () => { + beforeEach(() => { + jest.clearAllMocks(); + }); describe("computed", () => { describe("routes", () => { it("should get null when routeNames are not fetched", () => { @@ -41,5 +44,23 @@ describe("Composables - useNavigation", () => { expect(routes.value).toHaveLength(3); }); }); + describe("fetchNavigationElements", () => { + it("should fetch navigation elements correcly", async () => { + mockedGetPage.getNavigation.mockResolvedValueOnce({ + count: 3, + children: [ + { name: "Clothin", route: { path: "clothing/" } }, + { name: "Sports", route: { path: "sports/" } }, + { + name: "Accessories & Others", + route: { path: "accessories-others/" }, + }, + ], + } as any); + const { navigationElements, fetchNavigationElements } = useNavigation(); + await fetchNavigationElements(2); + expect(navigationElements).toHaveLength(3); + }); + }); }); }); diff --git a/packages/composables/src/hooks/useNavigation.ts b/packages/composables/src/hooks/useNavigation.ts index 19cd6f1b1..8a8301e8e 100644 --- a/packages/composables/src/hooks/useNavigation.ts +++ b/packages/composables/src/hooks/useNavigation.ts @@ -1,27 +1,47 @@ import Vue from "vue"; -import { reactive, computed } from "@vue/composition-api"; +import { reactive, computed, Ref } from "@vue/composition-api"; import { getNavigation } from "@shopware-pwa/shopware-6-client"; import { getNavigationRoutes } from "@shopware-pwa/helpers"; +import { NavigationElement } from "@shopware-pwa/commons/interfaces/models/content/navigation/Navigation"; + +/** + * @alpha + */ +export interface UseNavigation { + routes: Ref>; + navigationElements: NavigationElement[]; + fetchNavigationElements: (depth: number) => Promise; + fetchRoutes: () => Promise; +} const sharedNavigation = Vue.observable({ routes: null, + navigationElements: [], } as any); /** * @alpha */ -export const useNavigation = (): any => { +export const useNavigation = (): UseNavigation => { const localNavigation = reactive(sharedNavigation); const routes = computed(() => localNavigation.routes); const fetchRoutes = async (params?: any): Promise => { - const navigation = await getNavigation(params); - if (typeof navigation.children === "undefined") return; - sharedNavigation.routes = getNavigationRoutes(navigation.children); + const { children } = await getNavigation(params); + if (typeof children === "undefined") return; + sharedNavigation.routes = getNavigationRoutes(children); + }; + + const fetchNavigationElements = async (depth: number) => { + const { children } = await getNavigation({ depth }); + localNavigation.navigationElements.length = 0; + localNavigation.navigationElements.push(...children); }; return { routes, + navigationElements: localNavigation.navigationElements, + fetchNavigationElements, fetchRoutes, }; }; diff --git a/packages/default-theme/components/SwMegaMenu.vue b/packages/default-theme/components/SwMegaMenu.vue new file mode 100644 index 000000000..ff154874b --- /dev/null +++ b/packages/default-theme/components/SwMegaMenu.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/packages/default-theme/components/TopNavigation.vue b/packages/default-theme/components/SwTopNavigation.vue similarity index 82% rename from packages/default-theme/components/TopNavigation.vue rename to packages/default-theme/components/SwTopNavigation.vue index 107a4b2ac..96a90e2ed 100644 --- a/packages/default-theme/components/TopNavigation.vue +++ b/packages/default-theme/components/SwTopNavigation.vue @@ -1,5 +1,6 @@