cloudcommerce 0.39.0 → 0.40.1
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 +67 -0
- package/ecomplus-stores/barra-doce/functions/many/package.json +3 -3
- package/ecomplus-stores/barra-doce/functions/ssr/package.json +6 -6
- package/ecomplus-stores/barra-doce/functions/with-apps/package.json +3 -3
- package/ecomplus-stores/barra-doce/package.json +2 -2
- package/package.json +6 -6
- package/packages/api/lib/api.d.ts +2 -2
- package/packages/api/package.json +1 -1
- package/packages/api/types/applications.d.ts +15 -0
- package/packages/api/types/authentications.d.ts +14 -0
- package/packages/api/types/brands.d.ts +17 -0
- package/packages/api/types/carts.d.ts +12 -0
- package/packages/api/types/categories.d.ts +17 -0
- package/packages/api/types/collections.d.ts +15 -0
- package/packages/api/types/customers.d.ts +12 -0
- package/packages/api/types/grids.d.ts +15 -0
- package/packages/api/types/orders.d.ts +15 -0
- package/packages/api/types/products.d.ts +17 -0
- package/packages/api/types/stores.d.ts +15 -0
- package/packages/api/types.d.ts +34 -8
- package/packages/apps/affilate-program/package.json +1 -1
- package/packages/apps/correios/package.json +2 -2
- package/packages/apps/custom-payment/package.json +1 -1
- package/packages/apps/custom-shipping/package.json +1 -1
- package/packages/apps/datafrete/package.json +2 -2
- package/packages/apps/discounts/package.json +2 -2
- package/packages/apps/emails/package.json +1 -1
- package/packages/apps/fb-conversions/package.json +1 -1
- package/packages/apps/flash-courier/package.json +1 -1
- package/packages/apps/frenet/package.json +1 -1
- package/packages/apps/galaxpay/package.json +1 -1
- package/packages/apps/google-analytics/package.json +1 -1
- package/packages/apps/jadlog/package.json +1 -1
- package/packages/apps/loyalty-points/package.json +2 -2
- package/packages/apps/mandae/package.json +2 -2
- package/packages/apps/melhor-envio/package.json +1 -1
- package/packages/apps/mercadopago/package.json +1 -1
- package/packages/apps/pagarme/package.json +1 -1
- package/packages/apps/pagarme-v5/package.json +2 -2
- package/packages/apps/paghiper/package.json +1 -1
- package/packages/apps/pix/package.json +1 -1
- package/packages/apps/tiny-erp/package.json +2 -2
- package/packages/apps/webhooks/package.json +1 -1
- package/packages/cli/config/firebase.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/config/package.json +1 -1
- package/packages/emails/package.json +1 -1
- package/packages/eslint/package.json +5 -5
- package/packages/eslint/storefront.eslintrc.cjs +1 -0
- package/packages/events/package.json +1 -1
- package/packages/feeds/package.json +1 -1
- package/packages/firebase/package.json +2 -2
- package/packages/i18n/lib/en_us/i19anyPrice.txt +1 -0
- package/packages/i18n/lib/en_us/i19filterOut.txt +1 -0
- package/packages/i18n/lib/en_us/i19loadMoreProducts.txt +1 -0
- package/packages/i18n/lib/en_us/i19noProductsFound.txt +1 -0
- package/packages/i18n/lib/en_us/i19noProductsFoundFor$1.txt +1 -0
- package/packages/i18n/lib/en_us/i19noProductsInBrandMsg.txt +1 -0
- package/packages/i18n/lib/en_us/i19noProductsInCategoryMsg.txt +1 -0
- package/packages/i18n/lib/en_us.d.ts +8 -3
- package/packages/i18n/lib/en_us.js +8 -3
- package/packages/i18n/lib/en_us.js.map +1 -1
- package/packages/i18n/lib/pt_br/i19anyPrice.txt +1 -0
- package/packages/i18n/lib/pt_br/i19filterOut.txt +1 -0
- package/packages/i18n/lib/pt_br/i19loadMoreProducts.txt +1 -0
- package/packages/i18n/lib/pt_br/i19noItemSelected.txt +1 -1
- package/packages/i18n/lib/pt_br/i19noProductsFoundFor$1.txt +1 -0
- package/packages/i18n/lib/pt_br/i19noProductsInBrandMsg.txt +1 -0
- package/packages/i18n/lib/pt_br/i19noProductsInCategoryMsg.txt +1 -0
- package/packages/i18n/lib/pt_br.d.ts +9 -4
- package/packages/i18n/lib/pt_br.js +9 -4
- package/packages/i18n/lib/pt_br.js.map +1 -1
- package/packages/i18n/package.json +1 -1
- package/packages/i18n/src/en_us.ts +8 -3
- package/packages/i18n/src/pt_br.ts +9 -4
- package/packages/modules/package.json +2 -2
- package/packages/passport/package.json +1 -1
- package/packages/ssr/events.js +0 -0
- package/packages/ssr/package.json +6 -6
- package/packages/storefront/dist/client/_astro/AccountPage.Osc6ffV0.js +1 -0
- package/packages/storefront/dist/client/_astro/{CartSidebar.1kUFk9Xn.js → CartSidebar.LrfpXG2B.js} +1 -1
- package/packages/storefront/dist/client/_astro/HeroSlider.Zf6kCaqD.js +1 -0
- package/packages/storefront/dist/client/_astro/PitchBar.N4d9fV8H.js +1 -0
- package/packages/storefront/dist/client/_astro/{Prices.PuQc6C7F.js → Prices.eQ9Vd255.js} +1 -1
- package/packages/storefront/dist/client/_astro/ProductDetails.Ln_jf57U.js +7 -0
- package/packages/storefront/dist/client/_astro/ProductShelf.X389bv9S.js +1 -0
- package/packages/storefront/dist/client/_astro/ProductShelf.vj6lVDCr.js +1 -0
- package/packages/storefront/dist/client/_astro/{QuantitySelector.YNmWjN8y.js → QuantitySelector.qSJQlvTe.js} +1 -1
- package/packages/storefront/dist/client/_astro/SearchModal.BrVoDBvg.js +1 -0
- package/packages/storefront/dist/client/_astro/SearchShowcase.KAz3nwco.js +1 -0
- package/packages/storefront/dist/client/_astro/ShopHeader.mFKGzhIu.js +7 -0
- package/packages/storefront/dist/client/_astro/_plugin-vue_export-helper._suIQ7WC.js +1 -0
- package/packages/storefront/dist/client/_astro/_slug_.cfRx-rdA.css +1 -0
- package/packages/storefront/dist/client/_astro/client.PdegUP6S.js +1 -0
- package/packages/storefront/dist/client/_astro/{customer-session._VkzXnXT.js → customer-session.KkTHFOXl.js} +1 -1
- package/packages/storefront/dist/client/_astro/ecom-icon_12falx.png +0 -0
- package/packages/storefront/dist/client/_astro/ecom-icon_15pqnO.png +0 -0
- package/packages/storefront/dist/client/_astro/ecom-icon_t3guw.png +0 -0
- package/packages/storefront/dist/client/_astro/ecom-utils.Ld2zf-Ve.js +1 -0
- package/packages/storefront/dist/client/_astro/{format-money.FMQXgKHB.js → format-money.Axn0YFLJ.js} +1 -1
- package/packages/storefront/dist/client/_astro/grid-title.GntHOijE.js +1 -0
- package/packages/storefront/dist/client/_astro/headphone_T2Jjc.avif +0 -0
- package/packages/storefront/dist/client/_astro/headphone_Z1CG18r.webp +0 -0
- package/packages/storefront/dist/client/_astro/{hoisted._FbzheVm.js → hoisted.3ec9NcvP.js} +1 -1
- package/packages/storefront/dist/client/_astro/{hoisted.B6fKrLPR.js → hoisted.UnTlypMd.js} +1 -1
- package/packages/storefront/dist/client/_astro/{i18n.m7SpISxy.js → i18n.3-NUtxYq.js} +1 -1
- package/packages/storefront/dist/client/_astro/{img.zh-Drf-O.js → img.pozlYdd3.js} +1 -1
- package/packages/storefront/dist/client/_astro/{index.XrHFaN2F.js → index.TkCbiY_p.js} +1 -1
- package/packages/storefront/dist/client/_astro/{index.5PN-EYMS.js → index.m6fK0JXC.js} +1 -1
- package/packages/storefront/dist/client/_astro/logo_1UBsBq.webp +0 -0
- package/packages/storefront/dist/client/_astro/logo_Z1K5PE9.png +0 -0
- package/packages/storefront/dist/client/_astro/logo_Z1KIIl1.avif +0 -0
- package/packages/storefront/dist/client/_astro/{modules-info.sD0tdb2b.js → modules-info.mmwB1qIJ.js} +1 -1
- package/packages/storefront/dist/client/_astro/name.49dZlpDx.js +1 -0
- package/packages/storefront/dist/client/_astro/passion_LHbe9.webp +0 -0
- package/packages/storefront/dist/client/_astro/passion_Z23MeUb.avif +0 -0
- package/packages/storefront/dist/client/_astro/rect8589_1TtOHY.png +0 -0
- package/packages/storefront/dist/client/_astro/rect8589_1f5opX.webp +0 -0
- package/packages/storefront/dist/client/_astro/rect8589_IUskt.webp +0 -0
- package/packages/storefront/dist/client/_astro/rect8589_Uxfdf.png +0 -0
- package/packages/storefront/dist/client/_astro/rect8589_Z15uApA.png +0 -0
- package/packages/storefront/dist/client/_astro/rect8589_Z1Ap1Im.avif +0 -0
- package/packages/storefront/dist/client/_astro/rect8589_Z1JT1HB.webp +0 -0
- package/packages/storefront/dist/client/_astro/rect8589_ZY9mtN.avif +0 -0
- package/packages/storefront/dist/client/_astro/rect8589_tMFW0.avif +0 -0
- package/packages/storefront/dist/client/_astro/rect859_1TgQXS.avif +0 -0
- package/packages/storefront/dist/client/_astro/rect859_2Nm1z.avif +0 -0
- package/packages/storefront/dist/client/_astro/rect859_DIqwR.png +0 -0
- package/packages/storefront/dist/client/_astro/rect859_Z1IKDb2.png +0 -0
- package/packages/storefront/dist/client/_astro/rect859_Z29FI4V.webp +0 -0
- package/packages/storefront/dist/client/_astro/rect859_Z2kFHGk.avif +0 -0
- package/packages/storefront/dist/client/_astro/rect859_ZkpPFI.webp +0 -0
- package/packages/storefront/dist/client/_astro/rect859_jXzBi.png +0 -0
- package/packages/storefront/dist/client/_astro/rect859_x1l16.webp +0 -0
- package/packages/storefront/dist/client/_astro/rect89_1TSfW7.avif +0 -0
- package/packages/storefront/dist/client/_astro/rect89_Z1re32x.webp +0 -0
- package/packages/storefront/dist/client/_astro/sf-utils.yjuG8NjM.js +1 -0
- package/packages/storefront/dist/client/_astro/{shopping-cart.A-1jhlKi.js → shopping-cart.Ean2uW2R.js} +1 -1
- package/packages/storefront/dist/client/_astro/use-analytics.Y7amTmnr.js +1 -0
- package/packages/storefront/dist/client/_astro/{use-product-card.erbOV6Fv.js → use-product-card.zB4z32bC.js} +1 -1
- package/packages/storefront/dist/client/_astro/use-text-value.f9pDzruv.js +4 -0
- package/packages/storefront/dist/client/app/account/index.html +56 -0
- package/packages/storefront/dist/client/app/index.html +96 -0
- package/packages/storefront/dist/client/headset-gamer-corsair-hs40-raptor-ca-9011122-naap-vinho/index.html +107 -0
- package/packages/storefront/dist/client/index.html +120 -0
- package/packages/storefront/dist/client/macbook-apple-pro-15.4-intel-core-i7-2.6ghz-ram-16gb-ssd-512gb-mr972ll/a-prata/index.html +107 -0
- package/packages/storefront/dist/client/mouse-gamer-corsair-optico-harpoon-rgb-ch-9301011-na/index.html +107 -0
- package/packages/storefront/dist/client/teclado-gamer-fortrek-mecanico-k5-rgb-outemu-blue-preto/index.html +107 -0
- package/packages/storefront/dist/client/~fallback/index.html +74 -0
- package/packages/storefront/dist/server/chunks/{CartSidebar_hAgJQJgm.mjs → CartSidebar_gCUGFy65.mjs} +1 -1
- package/packages/storefront/dist/server/chunks/{SearchModal_eWb5SdQM.mjs → SearchModal_2uYZ9tHy.mjs} +4 -5
- package/packages/storefront/dist/server/chunks/{_.._S7DDBn_b.mjs → _.._FnNLvTNv.mjs} +1 -1
- package/packages/storefront/dist/server/chunks/{account_3ySmGzMc.mjs → account_iZ2QmK5E.mjs} +1 -1
- package/packages/storefront/dist/server/chunks/astro/{assets-service_QlOZG8ov.mjs → assets-service_TpUb271h.mjs} +58 -136
- package/packages/storefront/dist/server/chunks/{astro_zcC1GStV.mjs → astro_PpArQAsY.mjs} +4 -4
- package/packages/storefront/dist/server/chunks/{index_nIwq11oA.mjs → index_1q5IpD39.mjs} +1 -1
- package/packages/storefront/dist/server/chunks/{index_uAR5ZV4d.mjs → index_JEU6B2DI.mjs} +1 -1
- package/packages/storefront/dist/server/chunks/{node_2VvC7trl.mjs → node_wOa5hJmt.mjs} +1 -1
- package/packages/storefront/dist/server/chunks/pages/{__MSibDuuV.mjs → __cEcxuEWe.mjs} +1674 -422
- package/packages/storefront/dist/server/chunks/pages/{account_iG-YqJ5q.mjs → account_WliDuQOB.mjs} +2 -2
- package/packages/storefront/dist/server/chunks/pages/{index_BtDyKPh_.mjs → index_2bQLkQf-.mjs} +3 -3
- package/packages/storefront/dist/server/chunks/pages/{node_bKqL47eZ.mjs → node_ZaY4t9qW.mjs} +21 -2
- package/packages/storefront/dist/server/chunks/pages/{~fallback_73R5VA6j.mjs → ~fallback_TL5hPXF_.mjs} +2 -2
- package/packages/storefront/dist/server/chunks/{~fallback_7q1dqY4e.mjs → ~fallback_wxuqpDXG.mjs} +1 -1
- package/packages/storefront/dist/server/entry.mjs +34 -16
- package/packages/storefront/dist/server/{manifest_dSwvaOdW.mjs → manifest_YgAgEwvF.mjs} +17 -16
- package/packages/storefront/dist/server/renderers.mjs +14 -3
- package/packages/storefront/package.json +12 -12
- package/packages/storefront/src/helpers/sf-utils.ts +11 -0
- package/packages/storefront/src/lib/$storefront.d.ts +7 -1
- package/packages/storefront/src/lib/components/Drawer.vue +13 -8
- package/packages/storefront/src/lib/components/globals/ALink.vue +1 -1
- package/packages/storefront/src/lib/composables/use-pagination.ts +61 -0
- package/packages/storefront/src/lib/composables/use-product-shelf.ts +29 -19
- package/packages/storefront/src/lib/composables/use-search-filters.ts +271 -0
- package/packages/storefront/src/lib/composables/use-search-modal.ts +2 -11
- package/packages/storefront/src/lib/composables/use-search-showcase.ts +168 -22
- package/packages/storefront/src/lib/composables/use-sku-selector.ts +3 -8
- package/packages/storefront/src/lib/layouts/use-page-main.ts +20 -8
- package/packages/storefront/src/lib/state/search-engine.ts +19 -6
- package/packages/storefront/tsconfig.json +1 -1
- package/packages/test-base/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/pnpm-workspace.yaml +0 -2
- package/packages/i18n/lib/en_us/i19noProduct.txt +0 -1
- package/packages/i18n/lib/en_us/i19noResultsFor.txt +0 -1
- package/packages/i18n/lib/pt_br/i19noResultsFor.txt +0 -1
- package/packages/storefront/dist/client/_astro/AccountPage.j0C5JBLY.js +0 -1
- package/packages/storefront/dist/client/_astro/HeroSlider.tR1dVXyu.js +0 -1
- package/packages/storefront/dist/client/_astro/PitchBar.FelC04wE.js +0 -1
- package/packages/storefront/dist/client/_astro/ProductCard.ephJafAE.js +0 -1
- package/packages/storefront/dist/client/_astro/ProductDetails.B6Ih5MGf.js +0 -7
- package/packages/storefront/dist/client/_astro/ProductShelf.GESxuPZ_.js +0 -1
- package/packages/storefront/dist/client/_astro/SearchContainer.BzixfU3R.js +0 -1
- package/packages/storefront/dist/client/_astro/SearchModal.F7vbwxIv.js +0 -1
- package/packages/storefront/dist/client/_astro/ShopHeader.5vR1LgSW.js +0 -10
- package/packages/storefront/dist/client/_astro/_plugin-vue_export-helper.sk5AFsEV.js +0 -1
- package/packages/storefront/dist/client/_astro/_slug_.r8QHNfdw.css +0 -1
- package/packages/storefront/dist/client/_astro/client.RF8UxjZd.js +0 -1
- package/packages/storefront/dist/client/_astro/ecom-utils.gJYgRPRz.js +0 -1
- package/packages/storefront/dist/client/_astro/name.HU5l7TJo.js +0 -1
- package/packages/storefront/dist/client/_astro/sf-utils.5t7r9A2G.js +0 -1
- package/packages/storefront/dist/client/_astro/use-analytics.1EVxbrS7.js +0 -1
- /package/packages/i18n/lib/en_us/{i19relatedProduct.txt → i19relatedProducts.txt} +0 -0
- /package/packages/i18n/lib/pt_br/{i19noProduct.txt → i19noProductsFound.txt} +0 -0
- /package/packages/i18n/lib/pt_br/{i19relatedProduct.txt → i19relatedProducts.txt} +0 -0
|
@@ -2,6 +2,7 @@ import type { ResourceId, Collections, SearchItem } from '@cloudcommerce/types';
|
|
|
2
2
|
import { ref, shallowReactive } from 'vue';
|
|
3
3
|
import api from '@cloudcommerce/api';
|
|
4
4
|
import { inStock as checkInStock } from '@ecomplus/utils';
|
|
5
|
+
import { i19relatedProducts } from '@@i18n';
|
|
5
6
|
|
|
6
7
|
export interface Props {
|
|
7
8
|
collectionId?: ResourceId | null;
|
|
@@ -13,6 +14,7 @@ export interface Props {
|
|
|
13
14
|
limit?: number;
|
|
14
15
|
page?: number;
|
|
15
16
|
products?: SearchItem[];
|
|
17
|
+
isRelatedProducts?: boolean;
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
const useProductShelf = (props: Props) => {
|
|
@@ -26,31 +28,39 @@ const useProductShelf = (props: Props) => {
|
|
|
26
28
|
if (!props.products) {
|
|
27
29
|
isFetching.value = true;
|
|
28
30
|
fetching = (async () => {
|
|
29
|
-
let searchQuery = props.searchQuery || '';
|
|
30
|
-
let collection: Collections | undefined;
|
|
31
|
-
if (props.collectionId) {
|
|
32
|
-
try {
|
|
33
|
-
const { data } = await api.get(`collections/${props.collectionId}`);
|
|
34
|
-
collection = data;
|
|
35
|
-
} catch (err: any) {
|
|
36
|
-
console.error(err);
|
|
37
|
-
fetchError.value = err;
|
|
38
|
-
}
|
|
39
|
-
const productIds = collection?.products;
|
|
40
|
-
if (Array.isArray(productIds) && productIds.length) {
|
|
41
|
-
searchQuery += `&_id=${productIds.slice(0, 60).join(',')}`;
|
|
42
|
-
}
|
|
43
|
-
if (!title.value && title.value !== null && collection?.name) {
|
|
44
|
-
title.value = collection?.name;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
31
|
const limit = props.limit || 24;
|
|
48
32
|
const offset = props.page ? (props.page - 1) * limit : 0;
|
|
49
33
|
let endpointQuery = `offset=${offset}&limit=${limit}`;
|
|
50
34
|
if (props.sort) {
|
|
51
35
|
endpointQuery += `&sort=${props.sort}`;
|
|
52
36
|
}
|
|
53
|
-
|
|
37
|
+
if (props.isRelatedProducts) {
|
|
38
|
+
const { apiContext } = globalThis.$storefront;
|
|
39
|
+
if (apiContext?.resource === 'products') {
|
|
40
|
+
endpointQuery = `like=${apiContext.doc._id}`;
|
|
41
|
+
title.value = i19relatedProducts;
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
let searchQuery = props.searchQuery || '';
|
|
45
|
+
let collection: Collections | undefined;
|
|
46
|
+
if (props.collectionId) {
|
|
47
|
+
try {
|
|
48
|
+
const { data } = await api.get(`collections/${props.collectionId}`);
|
|
49
|
+
collection = data;
|
|
50
|
+
} catch (err: any) {
|
|
51
|
+
console.error(err);
|
|
52
|
+
fetchError.value = err;
|
|
53
|
+
}
|
|
54
|
+
const productIds = collection?.products;
|
|
55
|
+
if (Array.isArray(productIds) && productIds.length) {
|
|
56
|
+
searchQuery += `&_id=${productIds.slice(0, 60).join(',')}`;
|
|
57
|
+
}
|
|
58
|
+
if (!title.value && title.value !== null && collection?.name) {
|
|
59
|
+
title.value = collection?.name;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
endpointQuery += searchQuery;
|
|
63
|
+
}
|
|
54
64
|
try {
|
|
55
65
|
const { data } = await api.get(`search/v1?${endpointQuery}`);
|
|
56
66
|
if (props.isShuffle) {
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import type SearchEngineInstance from '@@sf/state/search-engine';
|
|
2
|
+
import { ref, computed, watch } from 'vue';
|
|
3
|
+
import { useDebounceFn } from '@vueuse/core';
|
|
4
|
+
import { formatMoney, gridTitle as getGridTitle } from '@ecomplus/utils';
|
|
5
|
+
import {
|
|
6
|
+
i19aboveOf,
|
|
7
|
+
i19brands,
|
|
8
|
+
i19categories,
|
|
9
|
+
i19upTo,
|
|
10
|
+
} from '@@i18n';
|
|
11
|
+
|
|
12
|
+
export interface Props {
|
|
13
|
+
searchEngine: SearchEngineInstance;
|
|
14
|
+
fixedParams?: SearchEngineInstance['params'];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type PriceRange = Exclude<
|
|
18
|
+
Exclude<SearchEngineInstance['meta']['buckets'], undefined>['prices'],
|
|
19
|
+
undefined
|
|
20
|
+
>[number];
|
|
21
|
+
|
|
22
|
+
const useSearchActiveFilters = ({ searchEngine, fixedParams }: Props) => {
|
|
23
|
+
const activeFilters = computed<SearchEngineInstance['params']>(() => {
|
|
24
|
+
const filters = {};
|
|
25
|
+
Object.keys(searchEngine.params).forEach((param) => {
|
|
26
|
+
if (fixedParams?.[param]) return;
|
|
27
|
+
const val = searchEngine.params[param];
|
|
28
|
+
if (val === undefined) return;
|
|
29
|
+
switch (param) {
|
|
30
|
+
case 'sort':
|
|
31
|
+
case 'term':
|
|
32
|
+
case 'limit':
|
|
33
|
+
case 'offset':
|
|
34
|
+
case 'count':
|
|
35
|
+
case 'buckets':
|
|
36
|
+
case 'fields':
|
|
37
|
+
return;
|
|
38
|
+
default:
|
|
39
|
+
}
|
|
40
|
+
filters[param] = val;
|
|
41
|
+
});
|
|
42
|
+
return filters;
|
|
43
|
+
});
|
|
44
|
+
const filtersCount = computed(() => {
|
|
45
|
+
const paramKeys = Object.keys(activeFilters.value);
|
|
46
|
+
const fields: string[] = [];
|
|
47
|
+
paramKeys.forEach((key) => {
|
|
48
|
+
const field = key.replace(/[^\w.]/g, '');
|
|
49
|
+
if (field === 'specs' && Array.isArray(activeFilters.value[key])) {
|
|
50
|
+
(activeFilters.value[key] as string[]).forEach((specAndVal) => {
|
|
51
|
+
const [spec] = specAndVal.split(':');
|
|
52
|
+
const specField = `specs.${spec}`;
|
|
53
|
+
if (!fields.includes(specField)) {
|
|
54
|
+
fields.push(specField);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!fields.includes(field)) {
|
|
60
|
+
fields.push(field);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
return fields.length;
|
|
64
|
+
});
|
|
65
|
+
return { activeFilters, filtersCount };
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const useSearchFilters = (props: Props) => {
|
|
69
|
+
const { searchEngine, fixedParams } = props;
|
|
70
|
+
const resultMeta = computed(() => searchEngine.meta);
|
|
71
|
+
const resultBuckets = computed(() => searchEngine.meta.buckets);
|
|
72
|
+
const { activeFilters, filtersCount } = useSearchActiveFilters(props);
|
|
73
|
+
watch(searchEngine.params, () => {
|
|
74
|
+
searchEngine.fetch();
|
|
75
|
+
});
|
|
76
|
+
let _lastParamChanged: null | string = null;
|
|
77
|
+
const clearFilters = () => {
|
|
78
|
+
Object.keys(searchEngine.params).forEach((param) => {
|
|
79
|
+
if (fixedParams?.[param]) return;
|
|
80
|
+
delete searchEngine.params[param];
|
|
81
|
+
});
|
|
82
|
+
_lastParamChanged = null;
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const getPriceRangeKey = ({ min, max }: Partial<PriceRange>) => {
|
|
86
|
+
return `${min || null}/${max || null}`;
|
|
87
|
+
};
|
|
88
|
+
const currentPriceRange = computed(() => {
|
|
89
|
+
const { params } = searchEngine;
|
|
90
|
+
return {
|
|
91
|
+
min: Number(params['price>']),
|
|
92
|
+
max: Number(params['price<']),
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
const priceRanges = ref<Array<{ range: PriceRange, key: string }>>([]);
|
|
96
|
+
const _updatePriceRanges = useDebounceFn(() => {
|
|
97
|
+
priceRanges.value.splice(0);
|
|
98
|
+
resultBuckets.value?.prices?.forEach((priceRange) => {
|
|
99
|
+
if (priceRange.min) priceRange.min = Math.round(priceRange.min * 100) / 100;
|
|
100
|
+
if (priceRange.max) priceRange.max = Math.round(priceRange.max * 100) / 100;
|
|
101
|
+
priceRanges.value.push({
|
|
102
|
+
range: priceRange,
|
|
103
|
+
key: getPriceRangeKey(priceRange),
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
if (!Number.isNaN(currentPriceRange.value.min)) {
|
|
107
|
+
const checkedPriceRange = priceRanges.value.find(({ range }) => {
|
|
108
|
+
return range.min === currentPriceRange.value.min
|
|
109
|
+
&& range.max === currentPriceRange.value.max;
|
|
110
|
+
});
|
|
111
|
+
if (!checkedPriceRange) {
|
|
112
|
+
priceRanges.value.unshift({
|
|
113
|
+
range: {
|
|
114
|
+
...currentPriceRange.value,
|
|
115
|
+
count: resultMeta.value.count || 0,
|
|
116
|
+
avg: null,
|
|
117
|
+
},
|
|
118
|
+
key: getPriceRangeKey(currentPriceRange.value),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}, 50);
|
|
123
|
+
_updatePriceRanges();
|
|
124
|
+
const priceRangeKey = ref<string | null>(getPriceRangeKey(currentPriceRange.value));
|
|
125
|
+
watch(priceRangeKey, () => {
|
|
126
|
+
_lastParamChanged = 'price';
|
|
127
|
+
const priceRange = priceRanges.value.find(({ range }) => {
|
|
128
|
+
return getPriceRangeKey(range) === priceRangeKey.value;
|
|
129
|
+
});
|
|
130
|
+
if (priceRange) {
|
|
131
|
+
const { min, max } = priceRange.range;
|
|
132
|
+
if (min) {
|
|
133
|
+
searchEngine.params['price>'] = min;
|
|
134
|
+
} else {
|
|
135
|
+
delete searchEngine.params['price>'];
|
|
136
|
+
}
|
|
137
|
+
if (max) {
|
|
138
|
+
searchEngine.params['price<'] = max;
|
|
139
|
+
} else {
|
|
140
|
+
delete searchEngine.params['price<'];
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
delete searchEngine.params['price>'];
|
|
145
|
+
delete searchEngine.params['price<'];
|
|
146
|
+
});
|
|
147
|
+
const getPriceRangeLabel = ({ min, max }: PriceRange) => {
|
|
148
|
+
if (min && max) {
|
|
149
|
+
if (max === min) {
|
|
150
|
+
return formatMoney(max);
|
|
151
|
+
}
|
|
152
|
+
return `${formatMoney(min)} ${i19upTo.toLowerCase()} ${formatMoney(max)}`;
|
|
153
|
+
}
|
|
154
|
+
if (!min && max) {
|
|
155
|
+
return `${i19upTo} ${formatMoney(max)}`;
|
|
156
|
+
}
|
|
157
|
+
return `${i19aboveOf} ${formatMoney(min || 0)}`;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const filterOptions = ref<Array<{
|
|
161
|
+
title: string,
|
|
162
|
+
options: { [value: string]: number },
|
|
163
|
+
field: string,
|
|
164
|
+
}>>([]);
|
|
165
|
+
const _updateFilterOptions = useDebounceFn(() => {
|
|
166
|
+
for (let i = 0; i < filterOptions.value.length; i++) {
|
|
167
|
+
const { field } = filterOptions.value[i];
|
|
168
|
+
if (field !== _lastParamChanged) {
|
|
169
|
+
filterOptions.value.splice(i, 1);
|
|
170
|
+
i -= 1;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const buckets = resultBuckets.value;
|
|
174
|
+
if (buckets) {
|
|
175
|
+
[['brands', i19brands], ['categories', i19categories]]
|
|
176
|
+
.forEach(([resource, title]) => {
|
|
177
|
+
const field = `${resource}.name`;
|
|
178
|
+
if (buckets[field] && _lastParamChanged !== field) {
|
|
179
|
+
filterOptions.value.push({
|
|
180
|
+
title,
|
|
181
|
+
options: buckets[field],
|
|
182
|
+
field,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
if (buckets.specs) {
|
|
187
|
+
const { grids } = globalThis.$storefront.data;
|
|
188
|
+
Object.keys(buckets.specs).forEach((specAndVal) => {
|
|
189
|
+
const [spec, value] = specAndVal.split(':');
|
|
190
|
+
if (value) {
|
|
191
|
+
const field = `specs.${spec}`;
|
|
192
|
+
if (_lastParamChanged === field) return;
|
|
193
|
+
const title = getGridTitle(spec, grids || []);
|
|
194
|
+
let filterOption = filterOptions.value.find((_filterOption) => {
|
|
195
|
+
return _filterOption.field === field;
|
|
196
|
+
});
|
|
197
|
+
if (!filterOption) {
|
|
198
|
+
filterOption = { title, options: {}, field };
|
|
199
|
+
filterOptions.value.push(filterOption);
|
|
200
|
+
}
|
|
201
|
+
filterOption.options[value] = buckets.specs![specAndVal];
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}, 50);
|
|
207
|
+
_updateFilterOptions();
|
|
208
|
+
const parseSpecsField = (field: string, value: string | number) => {
|
|
209
|
+
const [, spec] = field.split('.');
|
|
210
|
+
return ['specs,', `${spec}:${value}`];
|
|
211
|
+
};
|
|
212
|
+
const checkFilterOption = (field: string, value: string | number) => {
|
|
213
|
+
if (field.startsWith('specs.')) {
|
|
214
|
+
[field, value] = parseSpecsField(field, value);
|
|
215
|
+
}
|
|
216
|
+
const fieldParams = activeFilters.value[field];
|
|
217
|
+
if (fieldParams === value) return true;
|
|
218
|
+
// @ts-ignore
|
|
219
|
+
if (Array.isArray(fieldParams) && fieldParams.includes(value)) return true;
|
|
220
|
+
return false;
|
|
221
|
+
};
|
|
222
|
+
const toggleFilterOption = (field: string, value: string | number) => {
|
|
223
|
+
_lastParamChanged = field;
|
|
224
|
+
console.log({ _lastParamChanged });
|
|
225
|
+
if (field.startsWith('specs.')) {
|
|
226
|
+
[field, value] = parseSpecsField(field, value);
|
|
227
|
+
}
|
|
228
|
+
const isToActivate = !checkFilterOption(field, value);
|
|
229
|
+
let fieldParams = searchEngine.params[field];
|
|
230
|
+
if (!Array.isArray(fieldParams)) {
|
|
231
|
+
fieldParams = [];
|
|
232
|
+
searchEngine.params[field] = fieldParams;
|
|
233
|
+
}
|
|
234
|
+
if (isToActivate) {
|
|
235
|
+
// @ts-ignore
|
|
236
|
+
fieldParams.push(value);
|
|
237
|
+
} else {
|
|
238
|
+
for (let i = 0; i < fieldParams.length; i++) {
|
|
239
|
+
if (fieldParams[i] === value) {
|
|
240
|
+
fieldParams.splice(i, 1);
|
|
241
|
+
break;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
watch(resultBuckets, () => {
|
|
247
|
+
if (_lastParamChanged !== 'price') {
|
|
248
|
+
_updatePriceRanges();
|
|
249
|
+
}
|
|
250
|
+
_updateFilterOptions();
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
resultMeta,
|
|
255
|
+
resultBuckets,
|
|
256
|
+
activeFilters,
|
|
257
|
+
filtersCount,
|
|
258
|
+
clearFilters,
|
|
259
|
+
getPriceRangeKey,
|
|
260
|
+
priceRanges,
|
|
261
|
+
priceRangeKey,
|
|
262
|
+
getPriceRangeLabel,
|
|
263
|
+
filterOptions,
|
|
264
|
+
checkFilterOption,
|
|
265
|
+
toggleFilterOption,
|
|
266
|
+
};
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export default useSearchFilters;
|
|
270
|
+
|
|
271
|
+
export { useSearchFilters, useSearchActiveFilters };
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Categories,
|
|
3
|
-
Brands,
|
|
4
|
-
Collections,
|
|
5
|
-
} from '@cloudcommerce/api/types';
|
|
1
|
+
import type { Categories } from '@cloudcommerce/api/types';
|
|
6
2
|
import { ref, watch, toRef } from 'vue';
|
|
7
3
|
import Wade from 'wade';
|
|
8
4
|
import { clearAccents } from '@@sf/sf-lib';
|
|
@@ -14,18 +10,13 @@ export interface Props {
|
|
|
14
10
|
productsLimit?: number;
|
|
15
11
|
}
|
|
16
12
|
|
|
17
|
-
const storefrontData = globalThis.$storefront.data as {
|
|
18
|
-
categories?: Array<Partial<Categories>>,
|
|
19
|
-
brands?: Array<Partial<Brands>>,
|
|
20
|
-
collections?: Array<Partial<Collections>>,
|
|
21
|
-
};
|
|
22
13
|
const wadeDocs: Array<{
|
|
23
14
|
text: string,
|
|
24
15
|
type: 'categories' | 'brands' | 'collections' | 'blog',
|
|
25
16
|
data: Record<string, any> & { name: string, slug: string },
|
|
26
17
|
}> = [];
|
|
27
18
|
(['categories', 'brands', 'collections'] as const).forEach((resource) => {
|
|
28
|
-
const docsList =
|
|
19
|
+
const docsList = globalThis.$storefront.data[resource];
|
|
29
20
|
if (docsList) {
|
|
30
21
|
for (let i = 0; i < docsList.length; i++) {
|
|
31
22
|
const doc = docsList[i];
|
|
@@ -1,18 +1,40 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
1
2
|
import type { SearchItem } from '@cloudcommerce/types';
|
|
2
|
-
import {
|
|
3
|
+
import type { SearchEngineInstance } from '@@sf/state/search-engine';
|
|
4
|
+
import {
|
|
5
|
+
ref,
|
|
6
|
+
computed,
|
|
7
|
+
watch,
|
|
8
|
+
shallowReactive,
|
|
9
|
+
} from 'vue';
|
|
10
|
+
import { useUrlSearchParams, watchOnce } from '@vueuse/core';
|
|
11
|
+
import { isScreenLg, scrollToEl } from '@@sf/sf-lib';
|
|
12
|
+
import {
|
|
13
|
+
i19discount,
|
|
14
|
+
i19highestPrice,
|
|
15
|
+
i19lowestPrice,
|
|
16
|
+
i19name,
|
|
17
|
+
i19releases,
|
|
18
|
+
i19relevance,
|
|
19
|
+
i19sales,
|
|
20
|
+
} from '@@i18n';
|
|
3
21
|
import { SearchEngine } from '@@sf/state/search-engine';
|
|
22
|
+
import { useSearchActiveFilters } from '@@sf/composables/use-search-filters';
|
|
4
23
|
|
|
5
24
|
export interface Props {
|
|
6
|
-
searchEngine?: InstanceType<typeof SearchEngine>;
|
|
7
25
|
term?: string | null;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
26
|
+
fixedParams?: SearchEngineInstance['params'];
|
|
27
|
+
products?: SearchItem<null>[];
|
|
28
|
+
resultMeta?: SearchEngineInstance['meta'];
|
|
11
29
|
ssrError?: string | null;
|
|
30
|
+
canUseUrlParams?: boolean;
|
|
31
|
+
showcase?: Ref<HTMLElement | null>;
|
|
12
32
|
}
|
|
13
33
|
|
|
14
34
|
const useSearchShowcase = (props: Props) => {
|
|
15
|
-
let { term
|
|
35
|
+
let { term } = props;
|
|
36
|
+
const canUseUrlParams = props.canUseUrlParams !== false;
|
|
37
|
+
const urlParams = canUseUrlParams ? useUrlSearchParams('history') : null;
|
|
16
38
|
if (props.ssrError && !import.meta.env.SSR) {
|
|
17
39
|
console.error(new Error(`SSR search error: ${props.ssrError}`));
|
|
18
40
|
if (window.location.pathname.startsWith('/s/')) {
|
|
@@ -20,33 +42,157 @@ const useSearchShowcase = (props: Props) => {
|
|
|
20
42
|
}
|
|
21
43
|
}
|
|
22
44
|
const products = shallowReactive<SearchItem[]>(props.products || []);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
45
|
+
const searchEngine = new SearchEngine({ debounce: 50 });
|
|
46
|
+
if (term === undefined && !import.meta.env.SSR) {
|
|
47
|
+
term = new URLSearchParams(window.location.search).get('q') || null;
|
|
48
|
+
}
|
|
49
|
+
if (term !== undefined) {
|
|
50
|
+
searchEngine.term.value = term;
|
|
51
|
+
}
|
|
52
|
+
Object.assign(searchEngine.params, props.fixedParams);
|
|
53
|
+
if (urlParams) {
|
|
54
|
+
Object.keys(urlParams).forEach((param) => {
|
|
55
|
+
if (param === 'sort') {
|
|
56
|
+
searchEngine.params.sort = urlParams.sort;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (param === 'p') {
|
|
60
|
+
const pageNumber = parseInt(String(urlParams.p), 10);
|
|
61
|
+
if (pageNumber >= 1) searchEngine.pageNumber.value = pageNumber;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (param.startsWith('f\\')) {
|
|
65
|
+
const field = param.substring(2);
|
|
66
|
+
searchEngine.params[field] = urlParams[param];
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (!searchEngine.wasFetched.value) {
|
|
71
|
+
if (props.products || props.resultMeta) {
|
|
72
|
+
searchEngine.setResult({
|
|
73
|
+
result: props.products,
|
|
74
|
+
meta: props.resultMeta,
|
|
75
|
+
});
|
|
33
76
|
}
|
|
34
|
-
if (props.
|
|
35
|
-
searchEngine.
|
|
77
|
+
if (!props.products) {
|
|
78
|
+
searchEngine.fetch().catch(console.error);
|
|
36
79
|
}
|
|
37
80
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
81
|
+
searchEngine.isWithCount.value = true;
|
|
82
|
+
searchEngine.isWithBuckets.value = true;
|
|
83
|
+
const resultMeta = ref({
|
|
84
|
+
count: 0,
|
|
85
|
+
...(props.resultMeta || searchEngine.meta),
|
|
86
|
+
});
|
|
41
87
|
watch(searchEngine.products, () => {
|
|
42
88
|
products.splice(0);
|
|
43
|
-
searchEngine
|
|
89
|
+
searchEngine.products.forEach((item) => products.push(item));
|
|
90
|
+
resultMeta.value = {
|
|
91
|
+
count: 0,
|
|
92
|
+
...searchEngine.meta,
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const totalPages = computed(() => {
|
|
97
|
+
const { count } = searchEngine.meta;
|
|
98
|
+
if (!count || products.length < 2) return 1;
|
|
99
|
+
return Math.ceil(count / searchEngine.pageSize.value);
|
|
100
|
+
});
|
|
101
|
+
watch(searchEngine.pageNumber, (pageNumber) => {
|
|
102
|
+
if (urlParams) {
|
|
103
|
+
urlParams.p = `${pageNumber}`;
|
|
104
|
+
}
|
|
105
|
+
searchEngine.fetch();
|
|
44
106
|
});
|
|
107
|
+
const startWatchingFetch = () => {
|
|
108
|
+
watch(searchEngine.isFetching, (isFetching) => {
|
|
109
|
+
const el = props.showcase?.value;
|
|
110
|
+
if (!isFetching && el) {
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
scrollToEl(el, isScreenLg ? -25 : 0);
|
|
113
|
+
}, 50);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
if (searchEngine.wasFetched.value) {
|
|
118
|
+
startWatchingFetch();
|
|
119
|
+
} else {
|
|
120
|
+
watchOnce(searchEngine.wasFetched, startWatchingFetch);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const { activeFilters, filtersCount } = useSearchActiveFilters({
|
|
124
|
+
searchEngine,
|
|
125
|
+
fixedParams: props.fixedParams,
|
|
126
|
+
});
|
|
127
|
+
if (urlParams) {
|
|
128
|
+
watch(activeFilters, (params) => {
|
|
129
|
+
if (urlParams) {
|
|
130
|
+
Object.keys(urlParams).forEach((param) => {
|
|
131
|
+
if (param.startsWith('f\\')) delete urlParams[param];
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
Object.keys(params).forEach((param) => {
|
|
135
|
+
const val = params[param];
|
|
136
|
+
if (typeof val === 'string' || typeof val === 'number') {
|
|
137
|
+
urlParams[`f\\${param}`] = `${val}`;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (Array.isArray(val) && typeof val[0] === 'string') {
|
|
141
|
+
urlParams[`f\\${param}`] = val as string[];
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
const sortOptions = [
|
|
147
|
+
{
|
|
148
|
+
value: null,
|
|
149
|
+
label: i19relevance,
|
|
150
|
+
}, {
|
|
151
|
+
value: '-sales',
|
|
152
|
+
label: i19sales,
|
|
153
|
+
}, {
|
|
154
|
+
value: 'price',
|
|
155
|
+
label: i19lowestPrice,
|
|
156
|
+
}, {
|
|
157
|
+
value: '-price',
|
|
158
|
+
label: i19highestPrice,
|
|
159
|
+
}, {
|
|
160
|
+
value: '-price_discount',
|
|
161
|
+
label: i19discount,
|
|
162
|
+
}, {
|
|
163
|
+
value: '-created_at',
|
|
164
|
+
label: i19releases,
|
|
165
|
+
}, {
|
|
166
|
+
value: 'name',
|
|
167
|
+
label: i19name,
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
const sortOption = ref<string | null>(null);
|
|
171
|
+
watch(sortOption, () => {
|
|
172
|
+
searchEngine.params.sort = sortOption.value || undefined;
|
|
173
|
+
searchEngine.fetch();
|
|
174
|
+
});
|
|
175
|
+
if (urlParams) {
|
|
176
|
+
if (typeof urlParams.sort === 'string' && urlParams.sort) {
|
|
177
|
+
sortOption.value = urlParams.sort;
|
|
178
|
+
}
|
|
179
|
+
watch(searchEngine.params, (params) => {
|
|
180
|
+
delete urlParams.sort;
|
|
181
|
+
if (params.sort) urlParams.sort = String(params.sort);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
45
185
|
return {
|
|
46
186
|
searchEngine,
|
|
47
187
|
fetching: searchEngine.fetching.value,
|
|
48
188
|
isFetching: searchEngine.isFetching,
|
|
49
189
|
products,
|
|
190
|
+
resultMeta,
|
|
191
|
+
totalPages,
|
|
192
|
+
activeFilters,
|
|
193
|
+
filtersCount,
|
|
194
|
+
sortOptions,
|
|
195
|
+
sortOption,
|
|
50
196
|
};
|
|
51
197
|
};
|
|
52
198
|
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ResourceId,
|
|
3
|
-
Products,
|
|
4
|
-
GridsList,
|
|
5
|
-
} from '@cloudcommerce/api/types';
|
|
1
|
+
import type { ResourceId, Products } from '@cloudcommerce/api/types';
|
|
6
2
|
import {
|
|
7
3
|
ref,
|
|
8
4
|
computed,
|
|
@@ -25,9 +21,8 @@ export interface Props {
|
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
const useSkuSelector = (props: Props) => {
|
|
28
|
-
|
|
29
|
-
if (!grids) {
|
|
30
|
-
grids = shallowReactive([]);
|
|
24
|
+
const grids = shallowReactive(globalThis.$storefront.data.grids || []);
|
|
25
|
+
if (!grids.length) {
|
|
31
26
|
api.get('grids').then(({ data: { result } }) => {
|
|
32
27
|
result.forEach((grid) => grids.push(grid));
|
|
33
28
|
});
|
|
@@ -56,10 +56,13 @@ export const usePageSections = async <T extends CustomSection = CustomSection>
|
|
|
56
56
|
| { type: 'banners-grid', props: { banners: UseBannerProps[] } }
|
|
57
57
|
| { type: 'product-details', props: ProductDetailsProps }
|
|
58
58
|
| { type: 'breadcrumbs', props: {} }
|
|
59
|
-
| { type: 'related-products', props:
|
|
59
|
+
| { type: 'related-products', props: UseProductShelfProps }
|
|
60
60
|
| { type: 'doc-description', props: {} }
|
|
61
|
+
| { type: 'doc-banners', props: {} }
|
|
61
62
|
| { type: 'product-specifications', props: {} }
|
|
62
63
|
| { type: 'search-showcase' | 'context-showcase', props: UseSearchShowcaseProps }
|
|
64
|
+
| { type: 'page-title', props: {} }
|
|
65
|
+
| { type: 'custom-html', props: { html: string } }
|
|
63
66
|
> = [];
|
|
64
67
|
if (sectionsContent) {
|
|
65
68
|
await Promise.all(sectionsContent.map(async ({ type, ...sectionContent }, index) => {
|
|
@@ -134,32 +137,33 @@ export const usePageSections = async <T extends CustomSection = CustomSection>
|
|
|
134
137
|
}
|
|
135
138
|
const { resource, doc } = routeContext.apiContext;
|
|
136
139
|
if (resource === 'categories' || resource === 'brands') {
|
|
137
|
-
const params = { [`${resource}.
|
|
140
|
+
const params = { [`${resource}.name`]: [doc!.name] };
|
|
138
141
|
if (resource === 'categories') {
|
|
139
142
|
const { value: categories } = await useSharedData({ field: 'categories' });
|
|
140
|
-
categories?.forEach(({
|
|
143
|
+
categories?.forEach(({ name, parent }) => {
|
|
141
144
|
if (
|
|
142
|
-
|
|
145
|
+
name && parent
|
|
143
146
|
&& (parent._id === doc!._id || parent.slug === doc!.slug)
|
|
144
147
|
) {
|
|
145
|
-
params[`categories.
|
|
148
|
+
params[`categories.name`].push(name);
|
|
146
149
|
}
|
|
147
150
|
});
|
|
148
151
|
}
|
|
149
|
-
props.
|
|
152
|
+
props.fixedParams = params;
|
|
150
153
|
} else if (resource === 'collections') {
|
|
151
154
|
const { products } = (doc as Collections);
|
|
152
155
|
if (products?.length) {
|
|
153
|
-
props.
|
|
156
|
+
props.fixedParams = { _id: products };
|
|
154
157
|
}
|
|
155
158
|
}
|
|
156
159
|
} else if (routeContext.searchPageTerm !== undefined) {
|
|
157
160
|
props.term = routeContext.searchPageTerm || null;
|
|
158
161
|
}
|
|
159
|
-
if (props.term !== undefined || props.
|
|
162
|
+
if (props.term !== undefined || props.fixedParams) {
|
|
160
163
|
const { searchEngine, fetching } = useSearchShowcase(props);
|
|
161
164
|
await fetching;
|
|
162
165
|
props.products = searchEngine.products;
|
|
166
|
+
props.resultMeta = searchEngine.meta;
|
|
163
167
|
props.ssrError = searchEngine.fetchError.value?.message;
|
|
164
168
|
}
|
|
165
169
|
sections[index] = { type, props };
|
|
@@ -180,13 +184,21 @@ export const usePageSections = async <T extends CustomSection = CustomSection>
|
|
|
180
184
|
case 'product-details':
|
|
181
185
|
case 'related-products':
|
|
182
186
|
case 'doc-description':
|
|
187
|
+
case 'doc-banners':
|
|
183
188
|
case 'product-specifications':
|
|
189
|
+
case 'page-title':
|
|
184
190
|
// Bypassed sections
|
|
185
191
|
sections[index] = {
|
|
186
192
|
type,
|
|
187
193
|
props: sectionContent,
|
|
188
194
|
};
|
|
189
195
|
return;
|
|
196
|
+
case 'custom-html':
|
|
197
|
+
sections[index] = {
|
|
198
|
+
type,
|
|
199
|
+
props: { html: sectionContent.html || '' },
|
|
200
|
+
};
|
|
201
|
+
return;
|
|
190
202
|
default:
|
|
191
203
|
}
|
|
192
204
|
if (typeof handleCustomSection === 'function') {
|