@scayle/storefront-product-listing 2.2.0 → 2.3.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,120 @@
1
1
  # @scayle/storefront-product-listing
2
2
 
3
+ ## 2.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Deprecated the `sortLinks` property in `useProductListSort` to improve SEO by preventing sort links from appearing as crawlable URLs in the DOM.
8
+
9
+ The `sortLinks` property was a computed property that automatically added a `to` property to sorting options.
10
+ Search engines can crawl these links, potentially indexing duplicate content with different sort parameters.
11
+ By removing href attributes from sort controls and using click handlers with programmatic navigation instead, we ensure that sorting doesn't create separate indexable pages, improving SEO performance.
12
+
13
+ **Migration Required:** Replace usage of `sortLinks` with direct handling of `sortingOptions` and implement click handlers that use `router.push()` to update query parameters.
14
+
15
+ - **Before:**
16
+
17
+ ```ts
18
+ const sortingOptions = computed<SelectedSort[]>(() => {
19
+ return [
20
+ {
21
+ ...createDefaultSortingOption(currentCategory.value ?? undefined),
22
+ label: i18n.t('sorting_select.top_seller'),
23
+ },
24
+ {
25
+ ...SORT_DATE_NEWEST,
26
+ label: i18n.t('sorting_select.date_newest'),
27
+ },
28
+ {
29
+ ...SORT_PRICE_DESC,
30
+ label: i18n.t('sorting_select.price_desc'),
31
+ },
32
+ {
33
+ ...SORT_PRICE_ASC,
34
+ label: i18n.t('sorting_select.price_asc'),
35
+ },
36
+ {
37
+ ...SORT_REDUCTION_DESC,
38
+ label: i18n.t('sorting_select.reduction_desc'),
39
+ },
40
+ ]
41
+ })
42
+
43
+ const { selectedSort, sortLinks } = useProductListSort(route, {
44
+ sortingOptions: sortingOptions,
45
+ })
46
+
47
+ // This created a href in the DOM to apply a sort.
48
+ <SFLocalizedLink :to="sortLinks[0].to" />
49
+ ```
50
+
51
+ - **After:**
52
+
53
+ ```ts
54
+ const sortingOptions = computed<SelectedSort[]>(() => {
55
+ return [
56
+ {
57
+ ...createDefaultSortingOption(currentCategory.value ?? undefined),
58
+ label: i18n.t('sorting_select.top_seller'),
59
+ },
60
+ {
61
+ ...SORT_DATE_NEWEST,
62
+ label: i18n.t('sorting_select.date_newest'),
63
+ },
64
+ {
65
+ ...SORT_PRICE_DESC,
66
+ label: i18n.t('sorting_select.price_desc'),
67
+ },
68
+ {
69
+ ...SORT_PRICE_ASC,
70
+ label: i18n.t('sorting_select.price_asc'),
71
+ },
72
+ {
73
+ ...SORT_REDUCTION_DESC,
74
+ label: i18n.t('sorting_select.reduction_desc'),
75
+ },
76
+ ]
77
+ })
78
+
79
+ const { selectedSort } = useProductListSort(route, {
80
+ sortingOptions: sortingOptions,
81
+ })
82
+
83
+ // No href in the DOM to apply a sort.
84
+ const applySort = (sort: SelectedSort) => {
85
+ router.push({ query: { ...route.query, sort: sort.key } })
86
+ }
87
+
88
+ <SFButton @click="applySort(sortingOptions[0])" />
89
+ ```
90
+
91
+ ### Patch Changes
92
+
93
+ - Enhanced data fetching composables to support reactive keys, aligning with [Nuxt 3.17 data fetching improvements](https://nuxt.com/blog/v3-17#data-fetching-improvements).
94
+
95
+ You can now pass a `ref`, `computed`, or getter function as the `key` parameter to `useRpc` and derived composables (like `useProducts`, `useBrand` etc.). When the reactive key changes, the data will automatically re-fetch.
96
+
97
+ - **Before:** Keys were static strings.
98
+ - **After:** Keys can be reactive, enabling dynamic caching and automatic updates.
99
+
100
+ ```ts
101
+ // Before
102
+ const { data } = await useRpc('getProduct', 'my-static-product-key', {
103
+ productId: 123,
104
+ })
105
+
106
+ // After
107
+ const productId = ref(123)
108
+
109
+ // The key is now reactive. If `productId` changes, the key updates
110
+ // to 'product-456' (for example) and triggers a new fetch.
111
+ const { data } = await useRpc(
112
+ 'getProduct',
113
+ () => `product-${productId.value}`,
114
+ { productId },
115
+ )
116
+ ```
117
+
3
118
  ## 2.2.0
4
119
 
5
120
  ### Minor Changes
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@scayle/storefront-product-listing",
3
3
  "configKey": "product-listing",
4
- "version": "2.2.0",
4
+ "version": "2.3.0",
5
5
  "compatibility": {
6
6
  "bridge": false,
7
7
  "nuxt": ">=3.13"
package/dist/module.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { defineNuxtModule, createResolver, addImportsDir } from '@nuxt/kit';
2
2
 
3
3
  const PACKAGE_NAME = "@scayle/storefront-product-listing";
4
- const PACKAGE_VERSION = "2.2.0";
5
- const module = defineNuxtModule({
4
+ const PACKAGE_VERSION = "2.3.0";
5
+ const module$1 = defineNuxtModule({
6
6
  meta: {
7
7
  name: PACKAGE_NAME,
8
8
  configKey: "product-listing",
@@ -35,4 +35,4 @@ const module = defineNuxtModule({
35
35
  }
36
36
  });
37
37
 
38
- export { module as default };
38
+ export { module$1 as default };
@@ -1,7 +1,7 @@
1
- import type { KeysOf, NormalizedRpcResponse, UseRpcOptions, UseRpcReturn } from '@scayle/storefront-nuxt/composables';
1
+ import type { KeysOf, NormalizedRpcResponse, UseRpcOptions, UseRpcReturn, UseRpcCacheKey } from '@scayle/storefront-nuxt/composables';
2
2
  import type { MaybeRefOrGetter } from 'vue';
3
3
  import type { RpcMethodParameters } from '@scayle/storefront-nuxt';
4
4
  export declare function useAllShopCategoriesForId<DataT = NormalizedRpcResponse<'getAllShopCategoriesForId'>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>, DefaultT = null>({ params, options, }?: Partial<{
5
5
  params: MaybeRefOrGetter<RpcMethodParameters<'getAllShopCategoriesForId'>>;
6
6
  options: UseRpcOptions<'getAllShopCategoriesForId', DataT, PickKeys, DefaultT>;
7
- }>, key?: string): UseRpcReturn<'getAllShopCategoriesForId', DataT, PickKeys, DefaultT>;
7
+ }>, key?: UseRpcCacheKey): UseRpcReturn<'getAllShopCategoriesForId', DataT, PickKeys, DefaultT>;
@@ -1,5 +1,6 @@
1
1
  import type { FetchFiltersParams, FilterItemWithValues } from '@scayle/storefront-nuxt';
2
2
  import { useFilters } from '@scayle/storefront-nuxt/composables';
3
+ import type { UseRpcCacheKey } from '@scayle/storefront-nuxt/composables';
3
4
  import type { ComputedRef, Ref } from 'vue';
4
5
  export type FiltersForListingOptions = Partial<{
5
6
  params: Ref<Omit<FetchFiltersParams, 'category'>>;
@@ -7,7 +8,7 @@ export type FiltersForListingOptions = Partial<{
7
8
  lazy: boolean;
8
9
  immediate: boolean;
9
10
  }>;
10
- fetchingKey: string;
11
+ fetchingKey: UseRpcCacheKey;
11
12
  }>;
12
13
  export type UseFiltersForListingReturn = Pick<Awaited<ReturnType<typeof useFilters>>, 'error' | 'status' | 'refresh'> & {
13
14
  /** Returns computed available filters. */
@@ -14,7 +14,7 @@ export function useFiltersForListing({
14
14
  params,
15
15
  options: fetchingOptions
16
16
  },
17
- fetchingKey ?? params?.value.categoryId ? `${params?.value.categoryId}-filters` : "search-filters"
17
+ fetchingKey ?? params?.value.categoryId ? () => `${params?.value.categoryId}-filters` : "search-filters"
18
18
  );
19
19
  const {
20
20
  data,
@@ -4,7 +4,10 @@ import type { SelectedSort, SortLink } from '../types/sort.js';
4
4
  export interface UseProductListSortReturn {
5
5
  /** The currently selected sorting option. */
6
6
  selectedSort: ComputedRef<SelectedSort | undefined>;
7
- /** Links with updated query parameters for each sorting option. */
7
+ /**
8
+ * @deprecated This property is deprecated. Use passed `sortingOptions` directly instead.
9
+ * Links with updated query parameters for each sorting option.
10
+ */
8
11
  sortLinks: ComputedRef<SortLink[]>;
9
12
  /** Indicating if the default sort is selected. */
10
13
  isDefaultSortSelected: ComputedRef<boolean>;
@@ -1,6 +1,7 @@
1
1
  import type { FetchProductsByCategoryParams, Product, Pagination } from '@scayle/storefront-nuxt';
2
2
  import type { Ref, ComputedRef } from 'vue';
3
3
  import { useProducts } from '@scayle/storefront-nuxt/composables';
4
+ import type { UseRpcCacheKey } from '@scayle/storefront-nuxt/composables';
4
5
  export type UseProductsForListingReturn = Pick<Awaited<ReturnType<typeof useProducts>>, 'error' | 'status'> & {
5
6
  /** A computed array of products in the specified category. */
6
7
  products: ComputedRef<Product[]>;
@@ -16,7 +17,7 @@ export interface ProductsForListingOptions {
16
17
  lazy: boolean;
17
18
  immediate: boolean;
18
19
  }>;
19
- fetchingKey: string;
20
+ fetchingKey: UseRpcCacheKey;
20
21
  }
21
22
  /**
22
23
  * Composable to fetch and manage products by category with configurable options.
@@ -21,7 +21,7 @@ export function useProductsForListing({
21
21
  ...params.value
22
22
  }),
23
23
  options: fetchingOptions
24
- }, fetchingKey || `${params.value.categoryId ?? 0}-products`);
24
+ }, fetchingKey ?? (() => `${params?.value?.categoryId ?? 0}-products`));
25
25
  const products = computed(() => {
26
26
  return productsData.data.value?.products ?? [];
27
27
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scayle/storefront-product-listing",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Collection of essential composables and utilities to work with product listing",
5
5
  "author": "SCAYLE Commerce Engine",
6
6
  "license": "MIT",
@@ -45,12 +45,12 @@
45
45
  "@nuxt/module-builder": "1.0.2",
46
46
  "@nuxt/schema": "3.20.0",
47
47
  "@nuxt/test-utils": "3.20.1",
48
- "@types/node": "22.18.13",
49
- "@vitest/coverage-v8": "3.2.4",
48
+ "@types/node": "22.19.1",
49
+ "@vitest/coverage-v8": "4.0.14",
50
50
  "@vueuse/core": "13.9.0",
51
51
  "dprint": "0.50.2",
52
52
  "eslint-formatter-gitlab": "6.0.1",
53
- "eslint": "9.38.0",
53
+ "eslint": "9.39.1",
54
54
  "fishery": "2.3.1",
55
55
  "happy-dom": "20.0.10",
56
56
  "nuxt": "3.20.0",
@@ -58,12 +58,12 @@
58
58
  "schema-dts": "1.1.5",
59
59
  "typescript": "5.9.3",
60
60
  "unbuild": "3.6.1",
61
- "vitest": "3.2.4",
61
+ "vitest": "4.0.14",
62
62
  "vue-router": "4.6.3",
63
- "vue-tsc": "3.1.2",
64
- "vue": "3.5.22",
65
- "@scayle/eslint-config-storefront": "4.7.11",
66
- "@scayle/storefront-nuxt": "8.47.0",
63
+ "vue-tsc": "3.1.5",
64
+ "vue": "3.5.25",
65
+ "@scayle/eslint-config-storefront": "4.7.14",
66
+ "@scayle/storefront-nuxt": "8.53.3",
67
67
  "@scayle/vitest-config-storefront": "1.0.0"
68
68
  },
69
69
  "scripts": {