Skip to content

Commit

Permalink
feat(helpers): extract navigation URL (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkucmus authored Mar 30, 2023
1 parent 68a0b80 commit 909ffcd
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changeset/fast-planes-double.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"vue-demo-store": patch
---

Use correct URLs and target for navigation links
5 changes: 5 additions & 0 deletions .changeset/purple-pans-grin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"docs": patch
---

Expand Navigation building section
5 changes: 5 additions & 0 deletions .changeset/thick-cheetahs-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shopware-pwa/types": patch
---

Expand Category type
5 changes: 5 additions & 0 deletions .changeset/two-badgers-brush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@shopware-pwa/helpers-next": patch
---

Use technical URL as a fallback for navigation link
10 changes: 9 additions & 1 deletion apps/docs/src/getting-started/navigation.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ await loadNavigationElements({ depth: 2 });

Now all values can be accessed in the template to build a navigation menu

Note that all the navigation items are in type `Category`, and thanks to this the `getCategoryUrl` helper can be used to extract the correct pretty URL or technical URL as a fallback.

```vue
<script setup lang="ts">
import { getCategoryUrl } from "@shopware-pwa/helpers-next";
const { loadNavigationElements, navigationElements } = useNavigation();
await loadNavigationElements({ depth: 2 });
</script>
Expand All @@ -50,14 +53,19 @@ await loadNavigationElements({ depth: 2 });
v-for="navigationElement in navigationElements"
:key="navigationElement.id"
>
<RouterLink :to="'/' + navigationElement.seoUrls[0]?.seoPathInfo">
<RouterLink
:to="getCategoryUrl(navigationElement)"
:target="(navigationElement.externalLink || navigationElement.linkNewTab) ? '_blank' : ''"
>
{{ navigationElement.translated.name }}
</RouterLink>
</li>
</ul>
</template>
```

There is an additional attribute `target` used, in order to open a link in another window (external links or configured as `new tab` link).

## Next steps

<PageRef page="routing" title="Work with routing" sub="Resolve paths and fetch content dynamically" />
77 changes: 77 additions & 0 deletions packages/helpers/src/category/getCategoryUrl.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { describe, expect, it } from "vitest";
import { getCategoryUrl } from "./getCategoryUrl";

describe("getCategoryUrl", () => {
it("should return / if passed category is an empty object", () => {
expect(getCategoryUrl({} as any)).toBe("/");
});

it("should return / if passed category is undefined", () => {
expect(getCategoryUrl(undefined as any)).toBe("/");
});

it("should return technical URL for navigation", () => {
expect(
getCategoryUrl({
type: "link",
linkType: "category",
internalLink: "123",
} as any)
).toBe("/navigation/123");
});
it("should return technical URL for product", () => {
expect(
getCategoryUrl({
type: "link",
linkType: "product",
internalLink: "123",
} as any)
).toBe("/detail/123");
});

it("should return technical URL for landing page", () => {
expect(
getCategoryUrl({
type: "link",
linkType: "landing_page",
internalLink: "123",
} as any)
).toBe("/landingPage/123");
});

it("should return external URL", () => {
expect(
getCategoryUrl({
type: "link",
externalLink: "https://shopware.com",
} as any)
).toBe("https://shopware.com");
});

it("should return SEO URL", () => {
expect(
getCategoryUrl({
type: "link",
seoUrls: [{ seoPathInfo: "/test" }],
} as any)
).toBe("/test");
});

it("should try to return SEO URL for unknown type", () => {
expect(
getCategoryUrl({
type: "unknown",
seoUrls: [{ seoPathInfo: "test" }],
} as any)
).toBe("/test");
});
it("should try to return technical URL for unknown type", () => {
expect(
getCategoryUrl({
type: "unknown",
id: "123",
linkType: "category",
} as any)
).toBe("/navigation/123");
});
});
41 changes: 31 additions & 10 deletions packages/helpers/src/category/getCategoryUrl.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,47 @@
import { Category } from "@shopware-pwa/types";
import { getTranslatedProperty } from "../getTranslatedProperty";

type LinkedCategory = Pick<
Category,
"type" | "externalLink" | "seoUrls" | "internalLink" | "id" | "linkType"
>;

/**
* Extract prefix for technical URL
*/
function getEntityPrefix(category: LinkedCategory) {
switch (category.linkType) {
case "category":
return "navigation";
case "product":
return "detail";
case "landing_page":
return "landingPage";
}
}

/**
* Get URL for category.
* Some link {@link isLinkCategory}
*
* @param {Category} category category entity
*
* @beta
* @public
*/
export const getCategoryUrl = (category: Partial<Category>): string => {
export function getCategoryUrl(category: LinkedCategory): string {
if (!category) return "/";

switch (category.type) {
case "link":
return getTranslatedProperty(category, "externalLink") || "/";
case "folder":
case undefined:
return "/";
case "link":
return (
category.externalLink ||
category?.seoUrls?.[0]?.seoPathInfo ||
`/${getEntityPrefix(category)}/${category.internalLink}`
);
default:
return category.seoUrls?.[0]?.seoPathInfo
? `/${category.seoUrls[0].seoPathInfo}`
: category.id
? `/navigation/${category.id}`
: "/";
: `/${getEntityPrefix(category)}/${category.id}`;
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,6 @@ export type Category = Entity & {
metaDescription: string | null;
keywords: string | null;
};
linkType: "product" | "category" | "landing_page" | string;
internalLink: string | null;
};
5 changes: 3 additions & 2 deletions templates/vue-demo-store/components/layout/LayoutFooter.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { getTranslatedProperty } from "@shopware-pwa/helpers-next";
import { getTranslatedProperty, getCategoryUrl } from "@shopware-pwa/helpers-next";
const { navigationElements } = useNavigation({ type: "footer-navigation" });
const gridColumns = computed<number>(() =>
Expand Down Expand Up @@ -37,7 +37,8 @@ const gridColumns = computed<number>(() =>
class="pb-3 md:pb-1"
>
<NuxtLink
:to="'/' + navigationChild.seoUrls[0]?.seoPathInfo"
:target="(navigationChild.externalLink || navigationChild.linkNewTab) ? '_blank' : ''"
:to="getCategoryUrl(navigationChild)"
class="text-base font-normal text-gray-500 hover:text-gray-900"
>
{{ getTranslatedProperty(navigationChild, "name") }}
Expand Down
16 changes: 5 additions & 11 deletions templates/vue-demo-store/components/layout/LayoutTopNavigation.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script setup lang="ts">
import {
getCategoryUrl,
getTranslatedProperty,
getSmallestThumbnailUrl,
} from "@shopware-pwa/helpers-next";
Expand All @@ -23,7 +24,8 @@ onClickOutside(menuHtmlElement, () => (currentMenuPosition.value = null));
@mouseover="currentMenuPosition = navigationElement.id"
>
<NuxtLink
:to="'/' + navigationElement.seoUrls?.[0]?.seoPathInfo"
:target="(navigationElement.externalLink || navigationElement.linkNewTab) ? '_blank' : ''"
:to="getCategoryUrl(navigationElement)"
class="text-base font-medium text-gray-500 hover:text-gray-900 p-2 inline-block"
>
{{ getTranslatedProperty(navigationElement, "name") }}
Expand Down Expand Up @@ -62,11 +64,8 @@ onClickOutside(menuHtmlElement, () => (currentMenuPosition.value = null));
class="relative grid gap-6 bg-white px-3 py-2 sm:gap-6 sm:p-3"
>
<NuxtLink
v-if="
typeof childElement?.seoUrls?.[0]?.seoPathInfo !==
'undefined'
"
:to="'/' + childElement?.seoUrls?.[0]?.seoPathInfo"
:to="getCategoryUrl(childElement)"
:target="(childElement.externalLink || childElement.linkNewTab) ? '_blank' : ''"
class="flex justify-between rounded-lg hover:bg-gray-50 p-2"
>
<div
Expand Down Expand Up @@ -94,11 +93,6 @@ onClickOutside(menuHtmlElement, () => (currentMenuPosition.value = null));
/>
</div>
</NuxtLink>
<div v-else class="px-4 py-2 sm:py-3">
<p class="text-base font-medium text-gray-500">
{{ getTranslatedProperty(childElement, "name") }}
</p>
</div>
</div>
</template>
<div
Expand Down

2 comments on commit 909ffcd

@vercel
Copy link

@vercel vercel bot commented on 909ffcd Mar 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 909ffcd Mar 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

frontends-demo – ./templates/vue-demo-store

frontends-demo.vercel.app
frontends-demo-shopware-frontends.vercel.app
frontends-demo-git-main-shopware-frontends.vercel.app

Please sign in to comment.