@scayle/storefront-product-listing 0.5.0 → 1.0.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/dist/index.d.mts +3 -48
- package/dist/index.d.ts +3 -48
- package/dist/index.mjs +4 -3
- package/dist/module.json +1 -1
- package/dist/module.mjs +1 -1
- package/dist/runtime/composables/useAppliedFilters.d.ts +9 -19
- package/dist/runtime/composables/useFiltersForListing.d.ts +29 -0
- package/dist/runtime/composables/{useProductListFilter.js → useFiltersForListing.js} +13 -22
- package/dist/runtime/composables/useProductListSort.d.ts +8 -9
- package/dist/runtime/composables/useProductListingSeoData.d.ts +13 -15
- package/dist/runtime/composables/useProductListingSeoData.js +4 -10
- package/dist/runtime/composables/useProductsForListing.d.ts +32 -0
- package/dist/runtime/composables/useProductsForListing.js +52 -0
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.js +2 -2
- package/dist/runtime/utils/filters.d.ts +48 -3
- package/dist/runtime/utils/filters.js +17 -21
- package/package.json +5 -5
- package/dist/runtime/composables/useProductListFilter.d.ts +0 -32
- package/dist/runtime/composables/useProductsByCategory.d.ts +0 -46
- package/dist/runtime/composables/useProductsByCategory.js +0 -76
package/dist/index.d.mts
CHANGED
|
@@ -1,56 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BreadcrumbItem } from '@scayle/storefront-nuxt';
|
|
2
2
|
import { Factory } from 'fishery';
|
|
3
|
+
import { FilterItemWithValues } from '@scayle/storefront-api';
|
|
3
4
|
|
|
4
|
-
interface AttributesFilterValue {
|
|
5
|
-
name: string;
|
|
6
|
-
id: number;
|
|
7
|
-
productCount: number;
|
|
8
|
-
value: string;
|
|
9
|
-
}
|
|
10
|
-
type BooleanFilterValue = [
|
|
11
|
-
{
|
|
12
|
-
name: true | false;
|
|
13
|
-
productCount: number;
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
name: true | false;
|
|
17
|
-
productCount: number;
|
|
18
|
-
}
|
|
19
|
-
];
|
|
20
|
-
type RangeFilterValue = [
|
|
21
|
-
{
|
|
22
|
-
min: CentAmount;
|
|
23
|
-
max: CentAmount;
|
|
24
|
-
productCount: number;
|
|
25
|
-
}
|
|
26
|
-
];
|
|
27
|
-
type FilterItemWithValues = BooleanFilterItemWithValues | AttributesFilterItemWithValues | RangeFilterItemWithValues;
|
|
28
|
-
interface BooleanFilterItemWithValues {
|
|
29
|
-
id: null;
|
|
30
|
-
slug: string;
|
|
31
|
-
name: string;
|
|
32
|
-
values: BooleanFilterValue;
|
|
33
|
-
type: 'boolean';
|
|
34
|
-
}
|
|
35
|
-
interface AttributesFilterItemWithValues {
|
|
36
|
-
id: number | null;
|
|
37
|
-
slug: string;
|
|
38
|
-
name: string;
|
|
39
|
-
values: AttributesFilterValue[];
|
|
40
|
-
type: 'attributes';
|
|
41
|
-
attributeGroupType: string;
|
|
42
|
-
}
|
|
43
|
-
interface RangeFilterItemWithValues {
|
|
44
|
-
id: null;
|
|
45
|
-
slug: string;
|
|
46
|
-
name: string;
|
|
47
|
-
values: RangeFilterValue;
|
|
48
|
-
type: 'range';
|
|
49
|
-
}
|
|
50
5
|
type RangeTuple = [start: number, end: number];
|
|
51
6
|
|
|
52
7
|
declare const breadcrumbsFactory: Factory<BreadcrumbItem[], any, BreadcrumbItem[]>;
|
|
53
8
|
|
|
54
9
|
declare const filtersFactory: Factory<FilterItemWithValues[], any, FilterItemWithValues[]>;
|
|
55
10
|
|
|
56
|
-
export { type
|
|
11
|
+
export { type RangeTuple, breadcrumbsFactory, filtersFactory };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,56 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BreadcrumbItem } from '@scayle/storefront-nuxt';
|
|
2
2
|
import { Factory } from 'fishery';
|
|
3
|
+
import { FilterItemWithValues } from '@scayle/storefront-api';
|
|
3
4
|
|
|
4
|
-
interface AttributesFilterValue {
|
|
5
|
-
name: string;
|
|
6
|
-
id: number;
|
|
7
|
-
productCount: number;
|
|
8
|
-
value: string;
|
|
9
|
-
}
|
|
10
|
-
type BooleanFilterValue = [
|
|
11
|
-
{
|
|
12
|
-
name: true | false;
|
|
13
|
-
productCount: number;
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
name: true | false;
|
|
17
|
-
productCount: number;
|
|
18
|
-
}
|
|
19
|
-
];
|
|
20
|
-
type RangeFilterValue = [
|
|
21
|
-
{
|
|
22
|
-
min: CentAmount;
|
|
23
|
-
max: CentAmount;
|
|
24
|
-
productCount: number;
|
|
25
|
-
}
|
|
26
|
-
];
|
|
27
|
-
type FilterItemWithValues = BooleanFilterItemWithValues | AttributesFilterItemWithValues | RangeFilterItemWithValues;
|
|
28
|
-
interface BooleanFilterItemWithValues {
|
|
29
|
-
id: null;
|
|
30
|
-
slug: string;
|
|
31
|
-
name: string;
|
|
32
|
-
values: BooleanFilterValue;
|
|
33
|
-
type: 'boolean';
|
|
34
|
-
}
|
|
35
|
-
interface AttributesFilterItemWithValues {
|
|
36
|
-
id: number | null;
|
|
37
|
-
slug: string;
|
|
38
|
-
name: string;
|
|
39
|
-
values: AttributesFilterValue[];
|
|
40
|
-
type: 'attributes';
|
|
41
|
-
attributeGroupType: string;
|
|
42
|
-
}
|
|
43
|
-
interface RangeFilterItemWithValues {
|
|
44
|
-
id: null;
|
|
45
|
-
slug: string;
|
|
46
|
-
name: string;
|
|
47
|
-
values: RangeFilterValue;
|
|
48
|
-
type: 'range';
|
|
49
|
-
}
|
|
50
5
|
type RangeTuple = [start: number, end: number];
|
|
51
6
|
|
|
52
7
|
declare const breadcrumbsFactory: Factory<BreadcrumbItem[], any, BreadcrumbItem[]>;
|
|
53
8
|
|
|
54
9
|
declare const filtersFactory: Factory<FilterItemWithValues[], any, FilterItemWithValues[]>;
|
|
55
10
|
|
|
56
|
-
export { type
|
|
11
|
+
export { type RangeTuple, breadcrumbsFactory, filtersFactory };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Factory } from 'fishery';
|
|
2
|
+
import { FilterTypes } from '@scayle/storefront-api';
|
|
2
3
|
|
|
3
4
|
const breadcrumbsFactory = Factory.define(() => [
|
|
4
5
|
{ to: "/de/c/women/clothing/shirts-2045", value: "shirts" },
|
|
@@ -18,7 +19,7 @@ const filtersFactory = Factory.define(
|
|
|
18
19
|
value: "123"
|
|
19
20
|
}
|
|
20
21
|
],
|
|
21
|
-
type:
|
|
22
|
+
type: FilterTypes.ATTRIBUTES,
|
|
22
23
|
attributeGroupType: "group-type"
|
|
23
24
|
}, {
|
|
24
25
|
id: null,
|
|
@@ -34,7 +35,7 @@ const filtersFactory = Factory.define(
|
|
|
34
35
|
productCount: 2
|
|
35
36
|
}
|
|
36
37
|
],
|
|
37
|
-
type:
|
|
38
|
+
type: FilterTypes.BOOLEAN
|
|
38
39
|
}, {
|
|
39
40
|
id: null,
|
|
40
41
|
slug: "prices",
|
|
@@ -46,7 +47,7 @@ const filtersFactory = Factory.define(
|
|
|
46
47
|
productCount: 30
|
|
47
48
|
}
|
|
48
49
|
],
|
|
49
|
-
type:
|
|
50
|
+
type: FilterTypes.RANGE
|
|
50
51
|
}]
|
|
51
52
|
);
|
|
52
53
|
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -7,34 +7,24 @@ export interface AppliedFiltersOptions {
|
|
|
7
7
|
filtersPrefix: string;
|
|
8
8
|
}
|
|
9
9
|
export interface UseAppliedFiltersReturn {
|
|
10
|
+
/** A computed property returning a `ProductSearchQuery` object based on the route's query parameters. */
|
|
10
11
|
appliedFilter: ComputedRef<ProductSearchQuery>;
|
|
12
|
+
/** A computed property that returns the total count of applied filters. Counts minPrice/maxPrice as one and counts each attribute filter separately. */
|
|
11
13
|
appliedFiltersCount: ComputedRef<number>;
|
|
14
|
+
/** A computed property that returns a record mapping attribute keys to their boolean values for boolean filters. */
|
|
12
15
|
appliedBooleanValues: ComputedRef<AppliedBooleanValues>;
|
|
16
|
+
/** A computed property that returns a record mapping attribute keys to arrays of numbers representing selected values for each attribute. */
|
|
13
17
|
appliedAttributeValues: ComputedRef<AppliedAttributeValues>;
|
|
18
|
+
/** A computed property that returns `true` if any filters are currently applied, otherwise `false`. */
|
|
14
19
|
areFiltersApplied: ComputedRef<boolean>;
|
|
15
20
|
}
|
|
16
21
|
/**
|
|
17
22
|
* Composable to manage applied filters based on route query parameters.
|
|
18
23
|
*
|
|
19
|
-
* @param
|
|
20
|
-
* @param
|
|
21
|
-
* @param
|
|
24
|
+
* @param route Route object to handle the queries.
|
|
25
|
+
* @param options Configuration options for applied filters.
|
|
26
|
+
* @param options.filtersPrefix The prefix used to identify filter-related query parameters.
|
|
22
27
|
*
|
|
23
|
-
* @returns
|
|
24
|
-
*
|
|
25
|
-
* - `appliedFilter` {ComputedRef<ProductSearchQuery>}: A computed property returning a `ProductSearchQuery` object based on the route's query parameters.
|
|
26
|
-
* - `attributes`: An array of attribute filters, where each filter has:
|
|
27
|
-
* - `type`: A string, either 'boolean' or 'attributes'.
|
|
28
|
-
* - `key`: The name of the attribute.
|
|
29
|
-
* - `value`: A boolean for boolean filters.
|
|
30
|
-
* - `values`: An array of numbers for attribute filters.
|
|
31
|
-
* - `minPrice`: (Optional) The minimum price filter as a number.
|
|
32
|
-
* - `maxPrice`: (Optional) The maximum price filter as a number.
|
|
33
|
-
* - `term`: (Optional) A search term filter as a string.
|
|
34
|
-
*
|
|
35
|
-
* - `appliedFiltersCount` {ComputedRef<number>}: A computed property that returns the total count of applied filters. Counts minPrice/maxPrice as one and counts each attribute filter separately.
|
|
36
|
-
* - `appliedAttributeValues` {ComputedRef<AppliedAttributeValues>}: A computed property that returns a record mapping attribute keys to arrays of numbers representing selected values for each attribute.
|
|
37
|
-
* - `appliedBooleanValues` {ComputedRef<appliedBooleanValues>}: A computed property that returns a record mapping attribute keys to their boolean values for boolean filters.
|
|
38
|
-
* - `areFiltersApplied` {ComputedRef<boolean>}: A computed property that returns `true` if any filters are currently applied, otherwise `false`.
|
|
28
|
+
* @returns An object containing reactive data and computed properties for managing applied filters:
|
|
39
29
|
*/
|
|
40
30
|
export declare function useAppliedFilters(route: RouteLocationNormalizedLoadedGeneric, { filtersPrefix }?: AppliedFiltersOptions): UseAppliedFiltersReturn;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type FetchFiltersParams } from '@scayle/storefront-nuxt';
|
|
2
|
+
import { useFilters } from '@scayle/storefront-nuxt/composables';
|
|
3
|
+
import { type ComputedRef, type MaybeRefOrGetter } from 'vue';
|
|
4
|
+
import type { FilterItemWithValues } from '@scayle/storefront-api';
|
|
5
|
+
export type FiltersForListingOptions = Partial<{
|
|
6
|
+
params: MaybeRefOrGetter<Omit<FetchFiltersParams, 'category'>>;
|
|
7
|
+
fetchingOptions: Partial<{
|
|
8
|
+
lazy: boolean;
|
|
9
|
+
immediate: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
fetchingKey: string;
|
|
12
|
+
}>;
|
|
13
|
+
export type UseFiltersForListingReturn = Pick<Awaited<ReturnType<typeof useFilters>>, 'error' | 'status' | 'refresh'> & {
|
|
14
|
+
/** Returns computed available filters. */
|
|
15
|
+
availableFilters: ComputedRef<FilterItemWithValues[]>;
|
|
16
|
+
/** Returns the count of the products which the applied filter returns. */
|
|
17
|
+
filteredProductCount: ComputedRef<number>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Composable to manage filters based on current category ID and route query parameters.
|
|
21
|
+
*
|
|
22
|
+
* @param options Configuration options for fetching products.
|
|
23
|
+
* @param options.params Parameters to control product fetch behavior, excluding `category`.
|
|
24
|
+
* @param options.fetchingOptions Options for fetch timing, such as lazy loading or immediate fetching.
|
|
25
|
+
* @param options.fetchingKey Optional unique key to control the fetching cache.
|
|
26
|
+
*
|
|
27
|
+
* @returns {UseFiltersForListingReturn} - An object containing reactive data, computed properties and async RPC call for managing filters:
|
|
28
|
+
*/
|
|
29
|
+
export declare function useFiltersForListing({ params, fetchingKey, fetchingOptions, }?: FiltersForListingOptions): UseFiltersForListingReturn & Promise<UseFiltersForListingReturn>;
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { extendPromise } from "@scayle/storefront-nuxt";
|
|
2
2
|
import { useFilters } from "@scayle/storefront-nuxt/composables";
|
|
3
3
|
import { computed, toValue } from "vue";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
export function useFiltersForListing({
|
|
5
|
+
params = {
|
|
6
|
+
includeSellableForFree: false,
|
|
7
|
+
includeSoldOut: false
|
|
8
|
+
},
|
|
9
|
+
fetchingKey,
|
|
10
|
+
fetchingOptions
|
|
11
|
+
} = {}) {
|
|
9
12
|
const filterData = useFilters({
|
|
10
|
-
params
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
...appliedFilter.value,
|
|
14
|
-
...route.query.term && { term: String(route.query.term) }
|
|
15
|
-
},
|
|
16
|
-
includeSellableForFree: true,
|
|
17
|
-
includeSoldOut: false
|
|
18
|
-
})),
|
|
19
|
-
options: { immediate }
|
|
20
|
-
}, `${toValue(currentCategoryId) ?? keyPrefix}-filters`);
|
|
13
|
+
params,
|
|
14
|
+
options: fetchingOptions
|
|
15
|
+
}, fetchingKey ?? `${toValue(params).categoryId}-filters`);
|
|
21
16
|
const {
|
|
22
17
|
data,
|
|
23
18
|
refresh,
|
|
@@ -38,18 +33,14 @@ export function useProductListFilter(route, currentCategoryId, options = {}) {
|
|
|
38
33
|
return trueValue.productCount !== 0;
|
|
39
34
|
});
|
|
40
35
|
});
|
|
41
|
-
const
|
|
36
|
+
const filteredProductCount = computed(() => {
|
|
42
37
|
return data.value?.unfilteredCount ?? 0;
|
|
43
38
|
});
|
|
44
|
-
const clearedPriceQuery = computed(() => {
|
|
45
|
-
return getClearedPriceQuery(route);
|
|
46
|
-
});
|
|
47
39
|
return extendPromise(filterData.then(() => ({})), {
|
|
48
40
|
refresh,
|
|
49
41
|
status,
|
|
50
42
|
error,
|
|
51
43
|
availableFilters,
|
|
52
|
-
|
|
53
|
-
clearedPriceQuery
|
|
44
|
+
filteredProductCount
|
|
54
45
|
});
|
|
55
46
|
}
|
|
@@ -9,8 +9,11 @@ type SortLink = SelectedSort & {
|
|
|
9
9
|
to: RouteLocationRaw;
|
|
10
10
|
};
|
|
11
11
|
export interface UseProductListSortReturn {
|
|
12
|
+
/** The currently selected sorting option. */
|
|
12
13
|
selectedSort: ComputedRef<SelectedSort | undefined>;
|
|
14
|
+
/** Links with updated query parameters for each sorting option. */
|
|
13
15
|
sortLinks: ComputedRef<SortLink[]>;
|
|
16
|
+
/** Indicating if the default sort is selected. */
|
|
14
17
|
isDefaultSortSelected: ComputedRef<boolean>;
|
|
15
18
|
}
|
|
16
19
|
export interface ProductListSortOptions {
|
|
@@ -20,16 +23,12 @@ export interface ProductListSortOptions {
|
|
|
20
23
|
/**
|
|
21
24
|
* Custom composable to handle product list sorting.
|
|
22
25
|
*
|
|
23
|
-
* @param
|
|
24
|
-
* @param
|
|
25
|
-
* @param
|
|
26
|
-
* @param
|
|
26
|
+
* @param route Route object to handle the queries and path.
|
|
27
|
+
* @param options Options for configuring the sorting behavior.
|
|
28
|
+
* @param options.sortingOptions Array of available sorting options.
|
|
29
|
+
* @param options.defaultSortingKey Default sorting key to be applied if no specific sort is selected.
|
|
27
30
|
*
|
|
28
|
-
* @returns
|
|
29
|
-
*
|
|
30
|
-
* - {ComputedRef<SelectedSort | undefined>} selectedSort - The currently selected sorting option.
|
|
31
|
-
* - {ComputedRef<SortLink[]>} sortLinks - Links with updated query parameters for each sorting option.
|
|
32
|
-
* - {ComputedRef<boolean>} isDefaultSortSelected - Boolean indicating if the default sort is selected.
|
|
31
|
+
* @returns Computed properties and methods related to sorting
|
|
33
32
|
*/
|
|
34
33
|
export declare function useProductListSort(route: RouteLocationNormalizedLoadedGeneric, { sortingOptions, defaultSortingKey }?: ProductListSortOptions): UseProductListSortReturn;
|
|
35
34
|
export {};
|
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
import { type ComputedRef, type
|
|
2
|
-
import type { BreadcrumbItem
|
|
1
|
+
import { type ComputedRef, type MaybeRefOrGetter } from 'vue';
|
|
2
|
+
import type { BreadcrumbItem } from '@scayle/storefront-nuxt';
|
|
3
3
|
import type { BreadcrumbList, WithContext } from 'schema-dts';
|
|
4
4
|
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router';
|
|
5
5
|
type CanonicalLink = Record<'rel' | 'key' | 'href', string>;
|
|
6
6
|
type UrlParams = Record<'baseUrl' | 'fullPath', string>;
|
|
7
7
|
export interface UseProductListingSeoDataReturn {
|
|
8
|
+
/** A computed string that is constructed from breadcrumb values. */
|
|
8
9
|
title: ComputedRef<string>;
|
|
9
|
-
|
|
10
|
+
/** A computed robots. Value can be `index,follow` or `noindex,follow`. */
|
|
10
11
|
robots: ComputedRef<string>;
|
|
12
|
+
/** A computed canonical link. */
|
|
11
13
|
canonicalLink: ComputedRef<CanonicalLink[]>;
|
|
14
|
+
/** A computed breadcrumb schema. */
|
|
12
15
|
categoryBreadcrumbSchema: ComputedRef<WithContext<BreadcrumbList> | []>;
|
|
13
16
|
}
|
|
14
17
|
/**
|
|
15
18
|
* Composable for handling product listing SEO data.
|
|
16
19
|
*
|
|
17
|
-
* @param
|
|
18
|
-
* @param
|
|
19
|
-
* @param
|
|
20
|
-
* @param
|
|
20
|
+
* @param breadcrumbs Breadcrumb items.
|
|
21
|
+
* @param route The route object to handle queries.
|
|
22
|
+
* @param params - URL data for constructing the canonical link.
|
|
23
|
+
* @param params.baseUrl The base URL of the application.
|
|
24
|
+
* @param params.fullPath - The full path of the current route.
|
|
21
25
|
*
|
|
22
|
-
* @returns
|
|
23
|
-
*
|
|
24
|
-
* @property {ComputedRef<string>} title - A computed string that is constructed from breadcrumb values.
|
|
25
|
-
* @property {ComputedRef<string | undefined>} activeCategoryName - A computed active category name.
|
|
26
|
-
* @property {ComputedRef<string>} robots - A computed robots. Value can be "index,follow" or "noindex,follow".
|
|
27
|
-
* @property {ComputedRef<CanonicalLink[]>} canonicalLink - A computed canonical link.
|
|
28
|
-
* @property {ComputedRef<WithContext<BreadcrumbList> | []>} categoryBreadcrumbSchema - A computed breadcrumb schema.
|
|
26
|
+
* @returns An object containing reactive data and computed properties for managing SEO data.
|
|
29
27
|
*/
|
|
30
|
-
export declare function useProductListingSeoData(
|
|
28
|
+
export declare function useProductListingSeoData(breadcrumbs: MaybeRefOrGetter<BreadcrumbItem[]>, route: RouteLocationNormalizedLoadedGeneric, { baseUrl, fullPath }: UrlParams): UseProductListingSeoDataReturn;
|
|
31
29
|
export {};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { computed } from "vue";
|
|
1
|
+
import { computed, toValue } from "vue";
|
|
2
2
|
import {
|
|
3
3
|
generateCategoryBreadcrumbSchema,
|
|
4
4
|
sanitizeCanonicalURL
|
|
5
5
|
} from "@scayle/storefront-nuxt";
|
|
6
6
|
import { useAppliedFilters } from "./useAppliedFilters.js";
|
|
7
7
|
import { useProductListSort } from "./useProductListSort.js";
|
|
8
|
-
export function useProductListingSeoData(
|
|
8
|
+
export function useProductListingSeoData(breadcrumbs, route, { baseUrl, fullPath }) {
|
|
9
9
|
const { areFiltersApplied } = useAppliedFilters(route);
|
|
10
10
|
const { isDefaultSortSelected } = useProductListSort(route);
|
|
11
11
|
const robots = computed(() => {
|
|
@@ -18,20 +18,14 @@ export function useProductListingSeoData(category, breadcrumbs, route, { baseUrl
|
|
|
18
18
|
href: sanitizeCanonicalURL(`${baseUrl}${fullPath}`)
|
|
19
19
|
}]
|
|
20
20
|
);
|
|
21
|
-
const activeCategoryName = computed(
|
|
22
|
-
() => category.value?.name?.toLowerCase()
|
|
23
|
-
);
|
|
24
21
|
const title = computed(() => {
|
|
25
|
-
return
|
|
22
|
+
return toValue(breadcrumbs).map(({ value }) => value).join(" - ");
|
|
26
23
|
});
|
|
27
24
|
const categoryBreadcrumbSchema = computed(
|
|
28
|
-
() =>
|
|
29
|
-
return category.value ? generateCategoryBreadcrumbSchema(breadcrumbs) : [];
|
|
30
|
-
}
|
|
25
|
+
() => generateCategoryBreadcrumbSchema(toValue(breadcrumbs))
|
|
31
26
|
);
|
|
32
27
|
return {
|
|
33
28
|
title,
|
|
34
|
-
activeCategoryName,
|
|
35
29
|
robots,
|
|
36
30
|
canonicalLink,
|
|
37
31
|
categoryBreadcrumbSchema
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type FetchProductsByCategoryParams, type Product } from '@scayle/storefront-nuxt';
|
|
2
|
+
import { type MaybeRefOrGetter, type ComputedRef } from 'vue';
|
|
3
|
+
import { useProducts } from '@scayle/storefront-nuxt/composables';
|
|
4
|
+
import type { Pagination } from '@scayle/storefront-api';
|
|
5
|
+
export type UseProductsForListingReturn = Pick<Awaited<ReturnType<typeof useProducts>>, 'error' | 'status'> & {
|
|
6
|
+
/** A computed array of products in the specified category. */
|
|
7
|
+
products: ComputedRef<Product[]>;
|
|
8
|
+
/** A computed object containing pagination details for the product list. */
|
|
9
|
+
pagination: ComputedRef<Pagination | undefined>;
|
|
10
|
+
/** A computed offset for the current page based on the pagination data. */
|
|
11
|
+
totalProductsCount: ComputedRef<number>;
|
|
12
|
+
paginationOffset: ComputedRef<number>;
|
|
13
|
+
};
|
|
14
|
+
export interface ProductsForListingOptions {
|
|
15
|
+
params: MaybeRefOrGetter<Omit<FetchProductsByCategoryParams, 'category'>>;
|
|
16
|
+
fetchingOptions: Partial<{
|
|
17
|
+
lazy: boolean;
|
|
18
|
+
immediate: boolean;
|
|
19
|
+
}>;
|
|
20
|
+
fetchingKey: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Composable to fetch and manage products by category with configurable options.
|
|
24
|
+
*
|
|
25
|
+
* @param options Configuration options for fetching products.
|
|
26
|
+
* @param options.params Parameters to control product fetch behavior, excluding `category`.
|
|
27
|
+
* @param options.fetchingOptions Options for fetch timing, such as lazy loading or immediate fetching.
|
|
28
|
+
* @param options.fetchingKey Optional unique key to control the fetching cache.
|
|
29
|
+
*
|
|
30
|
+
* @returns An object containing reactive data and computed properties for managing products by category.
|
|
31
|
+
*/
|
|
32
|
+
export declare function useProductsForListing({ params, fetchingKey, fetchingOptions, }?: Partial<ProductsForListingOptions>): UseProductsForListingReturn & Promise<UseProductsForListingReturn>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import {
|
|
2
|
+
extendPromise
|
|
3
|
+
} from "@scayle/storefront-nuxt";
|
|
4
|
+
import { computed, toValue } from "vue";
|
|
5
|
+
import { useProducts } from "@scayle/storefront-nuxt/composables";
|
|
6
|
+
export function useProductsForListing({
|
|
7
|
+
params = {
|
|
8
|
+
includeSoldOut: false,
|
|
9
|
+
includeSellableForFree: false,
|
|
10
|
+
pricePromotionKey: "",
|
|
11
|
+
sort: {}
|
|
12
|
+
},
|
|
13
|
+
fetchingKey,
|
|
14
|
+
fetchingOptions
|
|
15
|
+
} = {}) {
|
|
16
|
+
const productsData = useProducts({
|
|
17
|
+
params: () => ({
|
|
18
|
+
// NOTE: We don't want to include trackSearchAnalyticsEvent parameter when paginating,
|
|
19
|
+
// as this logs the search term on every page request.
|
|
20
|
+
// Instead, we log the term only once, when the search is first performed.
|
|
21
|
+
// See: https://scayle.dev/en/developer-guide/products/search#scayle-search-analytics
|
|
22
|
+
trackSearchAnalyticsEvent: !!(toValue(params).page === 1 && toValue(params)?.where?.term),
|
|
23
|
+
...toValue(params)
|
|
24
|
+
}),
|
|
25
|
+
options: fetchingOptions
|
|
26
|
+
}, fetchingKey || `${toValue(params).categoryId ?? 0}-products`);
|
|
27
|
+
const products = computed(() => {
|
|
28
|
+
return productsData.data.value?.products ?? [];
|
|
29
|
+
});
|
|
30
|
+
const pagination = computed(() => {
|
|
31
|
+
return productsData.data.value?.pagination;
|
|
32
|
+
});
|
|
33
|
+
const totalProductsCount = computed(() => {
|
|
34
|
+
return productsData.data.value?.pagination?.total ?? 0;
|
|
35
|
+
});
|
|
36
|
+
const paginationOffset = computed(() => {
|
|
37
|
+
const page = pagination.value?.page ?? 1;
|
|
38
|
+
const perPage = pagination.value?.perPage ?? toValue(params).perPage ?? 0;
|
|
39
|
+
return (page - 1) * perPage;
|
|
40
|
+
});
|
|
41
|
+
return extendPromise(
|
|
42
|
+
productsData.then(() => ({})),
|
|
43
|
+
{
|
|
44
|
+
error: productsData.error,
|
|
45
|
+
status: productsData.status,
|
|
46
|
+
products,
|
|
47
|
+
pagination,
|
|
48
|
+
totalProductsCount,
|
|
49
|
+
paginationOffset
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from './composables/useProductListSort.js';
|
|
2
2
|
export * from './composables/useAppliedFilters.js';
|
|
3
|
-
export * from './composables/
|
|
3
|
+
export * from './composables/useFiltersForListing.js';
|
|
4
4
|
export * from './composables/useProductListingSeoData.js';
|
|
5
|
-
export * from './composables/
|
|
5
|
+
export * from './composables/useProductsForListing.js';
|
|
6
6
|
export * from './utils/filters.js';
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "./composables/useProductListSort.js";
|
|
2
2
|
export * from "./composables/useAppliedFilters.js";
|
|
3
|
-
export * from "./composables/
|
|
3
|
+
export * from "./composables/useFiltersForListing.js";
|
|
4
4
|
export * from "./composables/useProductListingSeoData.js";
|
|
5
|
-
export * from "./composables/
|
|
5
|
+
export * from "./composables/useProductsForListing.js";
|
|
6
6
|
export * from "./utils/filters.js";
|
|
@@ -1,16 +1,61 @@
|
|
|
1
1
|
import type { LocationQuery, RouteLocationNormalizedLoadedGeneric } from 'vue-router';
|
|
2
2
|
import type { ProductSearchQuery } from '@scayle/storefront-api';
|
|
3
3
|
import type { RangeTuple } from '~/src';
|
|
4
|
+
/**
|
|
5
|
+
* Parses filter data from a Vue Router route object.
|
|
6
|
+
*
|
|
7
|
+
* @param route The Vue Router route object.
|
|
8
|
+
* @param filtersPrefix The prefix used for filter query parameters.
|
|
9
|
+
*
|
|
10
|
+
* @returns An object representing the parsed product search query.
|
|
11
|
+
*/
|
|
4
12
|
export declare const parseFilterDataFromRoute: (route: RouteLocationNormalizedLoadedGeneric, filtersPrefix: string) => ProductSearchQuery;
|
|
5
|
-
|
|
6
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new attribute filter query object.
|
|
15
|
+
*
|
|
16
|
+
* @param route The Vue Router route object.
|
|
17
|
+
* @param appliedFilter The currently applied filter.
|
|
18
|
+
* @param param An object containing the slug and ID of the attribute.
|
|
19
|
+
* @param param.slug The slug of the attribute.
|
|
20
|
+
* @param param.id The ID of the attribute.
|
|
21
|
+
*
|
|
22
|
+
* @returns A new query object with the updated attribute filter.
|
|
23
|
+
*/
|
|
7
24
|
export declare const createNewAttributeQuery: (route: RouteLocationNormalizedLoadedGeneric, appliedFilter: ProductSearchQuery, { slug, id }: {
|
|
8
25
|
slug: string;
|
|
9
26
|
id: number;
|
|
10
27
|
}) => LocationQuery;
|
|
28
|
+
/**
|
|
29
|
+
* Creates a new price filter query object.
|
|
30
|
+
*
|
|
31
|
+
* @param {RouteLocationNormalizedLoadedGeneric} route - The Vue Router route object.
|
|
32
|
+
* @param {ProductSearchQuery} appliedFilter - The currently applied filter.
|
|
33
|
+
* @param {RangeTuple} prices - The new price range.
|
|
34
|
+
*
|
|
35
|
+
* @returns {LocationQuery} A new query object with the updated price filter.
|
|
36
|
+
*/
|
|
11
37
|
export declare const createNewPriceQuery: (route: RouteLocationNormalizedLoadedGeneric, appliedFilter: ProductSearchQuery, prices: RangeTuple) => LocationQuery;
|
|
38
|
+
/**
|
|
39
|
+
* Creates a new boolean attribute filter query object.
|
|
40
|
+
*
|
|
41
|
+
* @param route - The Vue Router route object.
|
|
42
|
+
* @param appliedFilter - The currently applied filter.
|
|
43
|
+
* @param param - An object containing the slug and value of the boolean attribute.
|
|
44
|
+
* @param param.slug - The slug of the attribute.
|
|
45
|
+
* @param param.value - The value of the attribute.
|
|
46
|
+
*
|
|
47
|
+
* @returns A new query object with the updated boolean attribute filter.
|
|
48
|
+
*/
|
|
12
49
|
export declare const createNewBoolAttributeQuery: (route: RouteLocationNormalizedLoadedGeneric, appliedFilter: ProductSearchQuery, { slug, value }: {
|
|
13
50
|
slug: string;
|
|
14
51
|
value: boolean;
|
|
15
52
|
}) => LocationQuery;
|
|
16
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Returns a new query object with the filter for the specified key cleared.
|
|
55
|
+
*
|
|
56
|
+
* @param route - The Vue Router route object.
|
|
57
|
+
* @param key - The key of the filter to clear.
|
|
58
|
+
*
|
|
59
|
+
* @returns A new query object with the filter cleared.
|
|
60
|
+
*/
|
|
61
|
+
export declare const getClearedFilterQueryByKey: (route: RouteLocationNormalizedLoadedGeneric, key: string) => LocationQuery;
|
|
@@ -45,22 +45,6 @@ export const parseFilterDataFromRoute = (route, filtersPrefix) => {
|
|
|
45
45
|
});
|
|
46
46
|
return productSearchQuery;
|
|
47
47
|
};
|
|
48
|
-
export const getClearedFilterQueryByKey = (route, key) => {
|
|
49
|
-
const query = { ...route.query };
|
|
50
|
-
const filterKey = `filters[${key}]`;
|
|
51
|
-
if (!query[filterKey]) {
|
|
52
|
-
return query;
|
|
53
|
-
}
|
|
54
|
-
delete query[filterKey];
|
|
55
|
-
return query;
|
|
56
|
-
};
|
|
57
|
-
export const getNewQueryFilters = (route, filter) => {
|
|
58
|
-
return {
|
|
59
|
-
sort: route.query.sort,
|
|
60
|
-
term: route.query.term,
|
|
61
|
-
...filter
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
48
|
export const createNewAttributeQuery = (route, appliedFilter, { slug, id }) => {
|
|
65
49
|
const attributeFilterQuery = {};
|
|
66
50
|
const query = { ...route.query };
|
|
@@ -117,12 +101,24 @@ export const createNewBoolAttributeQuery = (route, appliedFilter, { slug, value
|
|
|
117
101
|
booleanFilterQuery[key] = String(value);
|
|
118
102
|
return { ...query, ...booleanFilterQuery };
|
|
119
103
|
};
|
|
120
|
-
|
|
104
|
+
const getClearedPriceQuery = (route) => {
|
|
121
105
|
const query = { ...route.query };
|
|
122
|
-
if (
|
|
123
|
-
|
|
106
|
+
if (query["filters[maxPrice]"]) {
|
|
107
|
+
delete query["filters[maxPrice]"];
|
|
108
|
+
}
|
|
109
|
+
if (query["filters[minPrice]"]) {
|
|
110
|
+
delete query["filters[minPrice]"];
|
|
111
|
+
}
|
|
112
|
+
return query;
|
|
113
|
+
};
|
|
114
|
+
export const getClearedFilterQueryByKey = (route, key) => {
|
|
115
|
+
if (key === "prices") {
|
|
116
|
+
return getClearedPriceQuery(route);
|
|
117
|
+
}
|
|
118
|
+
const query = { ...route.query };
|
|
119
|
+
const filterKey = `filters[${key}]`;
|
|
120
|
+
if (query[filterKey]) {
|
|
121
|
+
delete query[filterKey];
|
|
124
122
|
}
|
|
125
|
-
delete query["filters[minPrice]"];
|
|
126
|
-
delete query["filters[maxPrice]"];
|
|
127
123
|
return query;
|
|
128
124
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scayle/storefront-product-listing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.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,7 +45,7 @@
|
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
47
|
"@nuxt/kit": "^3.13.0",
|
|
48
|
-
"@scayle/storefront-nuxt": "^
|
|
48
|
+
"@scayle/storefront-nuxt": "^8.0.0",
|
|
49
49
|
"@vue/test-utils": "2.4.6",
|
|
50
50
|
"@vueuse/core": "12.0.0",
|
|
51
51
|
"fishery": "2.2.2",
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"@nuxt/kit": "3.13.2",
|
|
56
56
|
"@nuxt/module-builder": "0.8.4",
|
|
57
57
|
"@nuxt/schema": "3.13.2",
|
|
58
|
-
"@nuxt/test-utils": "3.
|
|
58
|
+
"@nuxt/test-utils": "3.15.1",
|
|
59
59
|
"@scayle/eslint-config-storefront": "4.3.2",
|
|
60
|
-
"@scayle/storefront-nuxt": "8.
|
|
61
|
-
"@types/node": "22.10.
|
|
60
|
+
"@scayle/storefront-nuxt": "8.1.3",
|
|
61
|
+
"@types/node": "22.10.2",
|
|
62
62
|
"@vue/test-utils": "2.4.6",
|
|
63
63
|
"@vueuse/core": "12.0.0",
|
|
64
64
|
"dprint": "0.47.6",
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { useFilters } from '@scayle/storefront-nuxt/composables';
|
|
2
|
-
import { type ComputedRef, type MaybeRefOrGetter } from 'vue';
|
|
3
|
-
import type { LocationQuery, RouteLocationNormalizedLoadedGeneric } from 'vue-router';
|
|
4
|
-
import type { FilterItemWithValues } from '../../types/filter.js';
|
|
5
|
-
export type ProductListFilterOptions = Partial<{
|
|
6
|
-
immediate: boolean;
|
|
7
|
-
keyPrefix: string;
|
|
8
|
-
}>;
|
|
9
|
-
export type UseProductListFilterReturn = Pick<Awaited<ReturnType<typeof useFilters>>, 'error' | 'status' | 'refresh'> & {
|
|
10
|
-
availableFilters: ComputedRef<FilterItemWithValues[]>;
|
|
11
|
-
clearedPriceQuery: ComputedRef<LocationQuery | undefined>;
|
|
12
|
-
unfilteredCount: ComputedRef<number>;
|
|
13
|
-
};
|
|
14
|
-
/**
|
|
15
|
-
* Composable to manage filters based on current category ID and route query parameters.
|
|
16
|
-
*
|
|
17
|
-
* @param {RouteLocationNormalizedLoadedGeneric} [route] - Route object to handle the queries.
|
|
18
|
-
* @param {number} [currentCategoryId] - current/active category ID
|
|
19
|
-
* @param {ProductListFilterOptions} options - Configuration options for filters.
|
|
20
|
-
* @param {string} options.immediate - Will enable "immediate" flag via "useFilters" composable in it.
|
|
21
|
-
* @param {string} options.keyPrefix - The prefix used to construct "key" via "useFilters" payload. Default is "base".
|
|
22
|
-
*
|
|
23
|
-
* @returns {UseProductListFilterReturn} - An object containing reactive data, computed properties and async RPC call for managing filters:
|
|
24
|
-
* - `fetch`: call for fetching the filters.
|
|
25
|
-
* - `error`: returns "useFilters" error.
|
|
26
|
-
* - `status`: returns "useFilters" status.
|
|
27
|
-
* - `fetching`: returns "useFilters" fetching flag.
|
|
28
|
-
* - `availableFilters` {ComputedRef<FilterItemWithValues[]>}: returns computed available filters.
|
|
29
|
-
* - `unfilteredCount` {ComputedRef<number>}: returns unfiltered filters count.
|
|
30
|
-
* - `clearedPriceQuery` {ComputedRef<LocationQuery | undefined>}: constructs an empty query object.
|
|
31
|
-
*/
|
|
32
|
-
export declare function useProductListFilter(route: RouteLocationNormalizedLoadedGeneric, currentCategoryId?: MaybeRefOrGetter<number | undefined>, options?: ProductListFilterOptions): UseProductListFilterReturn & Promise<UseProductListFilterReturn>;
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { type FetchProductsByCategoryParams, type Product, type ProductWith } from '@scayle/storefront-nuxt';
|
|
2
|
-
import { type MaybeRefOrGetter, type ComputedRef } from 'vue';
|
|
3
|
-
import { useProducts } from '@scayle/storefront-nuxt/composables';
|
|
4
|
-
import type { Pagination } from '@scayle/storefront-api';
|
|
5
|
-
import type { RouteLocationNormalizedLoadedGeneric } from 'vue-router';
|
|
6
|
-
export type UseProductsByCategoryReturn = Pick<Awaited<ReturnType<typeof useProducts>>, 'error' | 'status'> & {
|
|
7
|
-
products: ComputedRef<Product[]>;
|
|
8
|
-
pagination: ComputedRef<Pagination | undefined>;
|
|
9
|
-
totalProductsCount: ComputedRef<number>;
|
|
10
|
-
paginationOffset: ComputedRef<number>;
|
|
11
|
-
};
|
|
12
|
-
export interface ProductsByCategoryOptions {
|
|
13
|
-
params?: Omit<Partial<FetchProductsByCategoryParams>, 'category' | 'categoryId'>;
|
|
14
|
-
fetchingOptions?: Partial<{
|
|
15
|
-
lazy: boolean;
|
|
16
|
-
immediate: boolean;
|
|
17
|
-
}>;
|
|
18
|
-
productsPerPage?: number;
|
|
19
|
-
fetchProductsCacheTtl?: number;
|
|
20
|
-
cacheKeyPrefix?: string;
|
|
21
|
-
fetchingKey?: string;
|
|
22
|
-
withParams?: ProductWith;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Composable to fetch and manage products by category with configurable options.
|
|
26
|
-
*
|
|
27
|
-
* @param {MaybeRefOrGetter<number>} categoryId - The ID of the category to fetch products for. Accepts a ref, computed, or static number.
|
|
28
|
-
* @param {RouteLocationNormalizedLoadedGeneric} [route] - Route object to handle the queries.
|
|
29
|
-
* @param {ProductsByCategoryOptions} options - Configuration options for fetching products.
|
|
30
|
-
* @param {Partial<FetchProductsByCategoryParams>} options.params - Parameters to control product fetch behavior, excluding `category` and `categoryId`.
|
|
31
|
-
* @param {Partial<{ lazy: boolean; immediate: boolean }>} options.fetchingOptions - Options for fetch timing, such as lazy loading or immediate fetching.
|
|
32
|
-
* @param {number} options.productsPerPage - Number of products to fetch per page.
|
|
33
|
-
* @param {number} options.fetchProductsCacheTtl - Cache time-to-live for product data in milliseconds.
|
|
34
|
-
* @param {string} options.cacheKeyPrefix - Prefix for cache keys to uniquely identify cached data for this fetch.
|
|
35
|
-
* @param {string} [options.fetchingKey] - Optional unique key to control the fetching cache.
|
|
36
|
-
* @param {ProductWith} [options.withParams] - Additional fields to include with each product.
|
|
37
|
-
*
|
|
38
|
-
* @returns {UseProductsByCategoryReturn} - An object containing reactive data and computed properties for managing products by category.
|
|
39
|
-
* @property {ComputedRef<Product[]>} products - A computed array of products in the specified category.
|
|
40
|
-
* @property {ComputedRef<Pagination>} pagination - A computed object containing pagination details for the product list.
|
|
41
|
-
* @property {ComputedRef<number>} totalProductsCount - A computed total count of products in the category.
|
|
42
|
-
* @property {ComputedRef<number>} paginationOffset - A computed offset for the current page based on the pagination data.
|
|
43
|
-
* @property {Ref<boolean>} fetching - A reactive boolean indicating if products are currently being fetched.
|
|
44
|
-
* @property {Ref<Error | null>} error - A reactive error object, null if no error occurred.
|
|
45
|
-
*/
|
|
46
|
-
export declare function useProductsByCategory(categoryId: MaybeRefOrGetter<number>, route: RouteLocationNormalizedLoadedGeneric, { params, withParams, cacheKeyPrefix, fetchingKey, fetchingOptions, fetchProductsCacheTtl, productsPerPage, }?: Partial<ProductsByCategoryOptions>): UseProductsByCategoryReturn & Promise<UseProductsByCategoryReturn>;
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
extendPromise
|
|
3
|
-
} from "@scayle/storefront-nuxt";
|
|
4
|
-
import { computed, toValue } from "vue";
|
|
5
|
-
import { useProducts } from "@scayle/storefront-nuxt/composables";
|
|
6
|
-
import { useProductListSort } from "./useProductListSort.js";
|
|
7
|
-
import { useAppliedFilters } from "./useAppliedFilters.js";
|
|
8
|
-
const PRODUCTS_PER_PAGE = 24;
|
|
9
|
-
const DEFAULT_CACHE_TTL = 1e3;
|
|
10
|
-
const DEFAULT_CACHE_KEY_PREFIX = "PLP";
|
|
11
|
-
export function useProductsByCategory(categoryId, route, {
|
|
12
|
-
params = {
|
|
13
|
-
includeSoldOut: false,
|
|
14
|
-
includeSellableForFree: false,
|
|
15
|
-
pricePromotionKey: ""
|
|
16
|
-
},
|
|
17
|
-
withParams,
|
|
18
|
-
cacheKeyPrefix = DEFAULT_CACHE_KEY_PREFIX,
|
|
19
|
-
fetchingKey,
|
|
20
|
-
fetchingOptions = {},
|
|
21
|
-
fetchProductsCacheTtl = DEFAULT_CACHE_TTL,
|
|
22
|
-
productsPerPage = PRODUCTS_PER_PAGE
|
|
23
|
-
} = {}) {
|
|
24
|
-
const { selectedSort } = useProductListSort(route);
|
|
25
|
-
const { appliedFilter } = useAppliedFilters(route);
|
|
26
|
-
const productsData = useProducts({
|
|
27
|
-
params: () => ({
|
|
28
|
-
...route?.query.page && { page: +route?.query.page },
|
|
29
|
-
sort: selectedSort.value,
|
|
30
|
-
perPage: route?.query.products_per_page ? parseInt(route?.query.products_per_page, 10) : productsPerPage,
|
|
31
|
-
with: withParams,
|
|
32
|
-
categoryId: toValue(categoryId),
|
|
33
|
-
includeSoldOut: params?.includeSoldOut,
|
|
34
|
-
includeSellableForFree: params?.includeSellableForFree,
|
|
35
|
-
pricePromotionKey: params?.pricePromotionKey,
|
|
36
|
-
orFiltersOperator: params?.orFiltersOperator,
|
|
37
|
-
cache: {
|
|
38
|
-
ttl: fetchProductsCacheTtl,
|
|
39
|
-
cacheKeyPrefix: cacheKeyPrefix || `PLP:${toValue(categoryId)}`
|
|
40
|
-
},
|
|
41
|
-
where: appliedFilter.value,
|
|
42
|
-
// NOTE: We don't want to include trackSearchAnalyticsEvent parameter when paginating,
|
|
43
|
-
// as this logs the search term on every page request.
|
|
44
|
-
// Instead, we log the term only once, when the search is first performed.
|
|
45
|
-
// See: https://scayle.dev/en/developer-guide/products/search#scayle-search-analytics
|
|
46
|
-
trackSearchAnalyticsEvent: !!(params?.page === 1 && appliedFilter.value.term),
|
|
47
|
-
...params
|
|
48
|
-
}),
|
|
49
|
-
options: fetchingOptions
|
|
50
|
-
}, fetchingKey || `${toValue(categoryId)}-products`);
|
|
51
|
-
const products = computed(() => {
|
|
52
|
-
return productsData.data.value?.products ?? [];
|
|
53
|
-
});
|
|
54
|
-
const pagination = computed(() => {
|
|
55
|
-
return productsData.data.value?.pagination;
|
|
56
|
-
});
|
|
57
|
-
const totalProductsCount = computed(() => {
|
|
58
|
-
return productsData.data.value?.pagination?.total ?? 0;
|
|
59
|
-
});
|
|
60
|
-
const paginationOffset = computed(() => {
|
|
61
|
-
const page = pagination.value?.page ?? 1;
|
|
62
|
-
const perPage = pagination.value?.perPage ?? productsPerPage ?? PRODUCTS_PER_PAGE;
|
|
63
|
-
return (page - 1) * perPage;
|
|
64
|
-
});
|
|
65
|
-
return extendPromise(
|
|
66
|
-
productsData.then(() => ({})),
|
|
67
|
-
{
|
|
68
|
-
error: productsData.error,
|
|
69
|
-
status: productsData.status,
|
|
70
|
-
products,
|
|
71
|
-
pagination,
|
|
72
|
-
totalProductsCount,
|
|
73
|
-
paginationOffset
|
|
74
|
-
}
|
|
75
|
-
);
|
|
76
|
-
}
|