@scayle/storefront-product-detail 1.5.2 → 1.5.4

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,17 @@
1
1
  # @scayle/storefront-product-detail
2
2
 
3
+ ## 1.5.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated SCAYLE Resource Center references
8
+
9
+ ## 1.5.3
10
+
11
+ ### Patch Changes
12
+
13
+ - **\[FIX\]** Added logic to prevent simultaneously loading the same products when `loadMissingProducts` from `useRecentlyViewedProducts` is called multiple times concurrently. This ensures that products are not added to the recently viewed list more than once.
14
+
3
15
  ## 1.5.2
4
16
 
5
17
  ### Patch Changes
@@ -173,7 +185,7 @@
173
185
  - This release introduces the `@scayle/storefront-product-detail` package, decoupling composables and utilities of the Product Detail Page (PDP) functionality from the SCAYLE Storefront Boilerplate for enhanced modularity and integration.
174
186
  This separation empowers developers with greater control over PDP updates and simplifies its integration into existing Storefront-based projects.
175
187
 
176
- - [Discover more about the Product Detail Page for SCAYLE Storefront in our SCAYLE Resource Center.](https://scayle.dev/en/storefront-guide/developer-guide/features/pages/product-detail-page)
188
+ - [Discover more about the Product Detail Page for SCAYLE Storefront in our SCAYLE Resource Center.](https://scayle.dev/en/core-documentation/storefront-guide/storefront-application/features/product-detail-page)
177
189
 
178
190
  - This release requires `@scayle/storefront-nuxt@8.x` or higher. Support for `@scayle/storefront-nuxt@7.x` has been discontinued. Please update your dependencies accordingly. The `peerDependency` range has been updated to `^8.0.0`.
179
191
 
package/README.md CHANGED
@@ -55,7 +55,7 @@ Licensed under the [MIT License](https://opensource.org/license/mit/)
55
55
  [SCAYLE](https://scayle.com) is a full-featured e-commerce software solution that comes with flexible APIs.
56
56
  Within SCAYLE, you can manage all aspects of your shop, such as products, stocks, customers, and transactions.
57
57
 
58
- Learn more about [SCAYLE’s architecture](https://scayle.dev/en/getting-started) and commerce modules in the Docs.
58
+ Learn more about [SCAYLE’s architecture](https://scayle.dev/en/core-documentation/welcome-to-scayle/getting-started) and commerce modules in the Docs.
59
59
 
60
60
  ## Other channels
61
61
 
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@scayle/storefront-product-detail",
3
3
  "configKey": "product-detail",
4
- "version": "1.5.2",
4
+ "version": "1.5.4",
5
5
  "compatibility": {
6
6
  "bridge": false,
7
7
  "nuxt": ">=3.13"
package/dist/module.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { defineNuxtModule, createResolver, addImportsDir } from '@nuxt/kit';
2
2
 
3
3
  const PACKAGE_NAME = "@scayle/storefront-product-detail";
4
- const PACKAGE_VERSION = "1.5.2";
4
+ const PACKAGE_VERSION = "1.5.4";
5
5
  const module = defineNuxtModule({
6
6
  meta: {
7
7
  name: PACKAGE_NAME,
@@ -16,6 +16,10 @@ export function useRecentlyViewedProducts(options) {
16
16
  () => "idle"
17
17
  );
18
18
  const products = useState("recently-viewed-products", () => []);
19
+ const loadingPromise = useState(
20
+ "recently-viewed-products-loading-promise",
21
+ () => /* @__PURE__ */ new Map()
22
+ );
19
23
  const addProductId = (productId) => {
20
24
  if (import.meta.server) {
21
25
  throw new Error(
@@ -38,46 +42,56 @@ export function useRecentlyViewedProducts(options) {
38
42
  "useRecentlyViewedProducts uses local storage. fetchProducts is therefore not available on the server."
39
43
  );
40
44
  }
41
- loading.value = true;
42
- status.value = "pending";
43
- try {
44
- const loadedProductIds = new Set(
45
- products.value.map((product) => product.id)
46
- );
47
- const missingProductIds = recentlyViewedProductsIds.value.filter(
48
- (id) => !loadedProductIds.has(id)
49
- );
50
- if (missingProductIds.length > 0) {
51
- const result = await fetchProductsRpc({
52
- ids: missingProductIds,
53
- with: options?.with,
54
- pricePromotionKey: options?.pricePromotionKey
55
- });
56
- products.value.push(...result);
57
- }
58
- const sortOrderMap = new Map(
59
- recentlyViewedProductsIds.value.map(
60
- (id, index) => [id, index]
61
- )
62
- );
63
- products.value = products.value.sort((a, b) => {
64
- const aIndex = sortOrderMap.get(a.id);
65
- const bIndex = sortOrderMap.get(b.id);
66
- if (aIndex === void 0) {
67
- return 1;
68
- }
69
- if (bIndex === void 0) {
70
- return -1;
71
- }
72
- return aIndex - bIndex;
73
- }).slice(0, maxRecentlyViewedProducts);
74
- status.value = "success";
75
- } catch (e) {
76
- error.value = e;
77
- status.value = "error";
78
- } finally {
79
- loading.value = false;
45
+ const loadedProductIds = new Set(
46
+ products.value.map((product) => product.id)
47
+ );
48
+ const missingProductIds = recentlyViewedProductsIds.value.filter(
49
+ (id) => !loadedProductIds.has(id)
50
+ );
51
+ const promiseKey = missingProductIds.join(",");
52
+ if (loadingPromise.value.has(promiseKey)) {
53
+ return loadingPromise.value.get(promiseKey);
80
54
  }
55
+ const load = async () => {
56
+ loading.value = true;
57
+ status.value = "pending";
58
+ try {
59
+ if (missingProductIds.length > 0) {
60
+ const result = await fetchProductsRpc({
61
+ ids: missingProductIds,
62
+ with: options?.with,
63
+ pricePromotionKey: options?.pricePromotionKey
64
+ });
65
+ products.value.push(...result);
66
+ }
67
+ const sortOrderMap = new Map(
68
+ recentlyViewedProductsIds.value.map(
69
+ (id, index) => [id, index]
70
+ )
71
+ );
72
+ products.value = products.value.sort((a, b) => {
73
+ const aIndex = sortOrderMap.get(a.id);
74
+ const bIndex = sortOrderMap.get(b.id);
75
+ if (aIndex === void 0) {
76
+ return 1;
77
+ }
78
+ if (bIndex === void 0) {
79
+ return -1;
80
+ }
81
+ return aIndex - bIndex;
82
+ }).slice(0, maxRecentlyViewedProducts);
83
+ status.value = "success";
84
+ } catch (e) {
85
+ error.value = e;
86
+ status.value = "error";
87
+ } finally {
88
+ loading.value = false;
89
+ loadingPromise.value.delete(promiseKey);
90
+ }
91
+ };
92
+ const promise = load();
93
+ loadingPromise.value.set(promiseKey, promise);
94
+ return promise;
81
95
  };
82
96
  return {
83
97
  addProductId,
@@ -7,8 +7,8 @@ import type { AdvancedAttribute } from '@scayle/storefront-nuxt';
7
7
  * commonly used to handle product recommendations.
8
8
  *
9
9
  * More information about recommended products and attributes groups please visit our SCAYLE Resource Center:
10
- * @see https://scayle.dev/en/storefront-guide/developer-guide/features/product-recommendation
11
- * @see https://scayle.dev/en/user-guide/settings/product-structure/attribute-groups
10
+ * @see https://scayle.dev/en/core-documentation/storefront-guide/storefront-application/features/product-detail-page#recommendations
11
+ * @see https://scayle.dev/en/core-documentation/the-basics/products/attribute-groups
12
12
  *
13
13
  * @param attribute The advanced attribute containing values to extract product IDs from. This attribute is sourced from a product's advanced attributes.
14
14
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scayle/storefront-product-detail",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "Collection of essential composables and utilities to work with product detail",
5
5
  "author": "SCAYLE Commerce Engine",
6
6
  "license": "MIT",
@@ -37,29 +37,29 @@
37
37
  },
38
38
  "devDependencies": {
39
39
  "@arethetypeswrong/cli": "0.18.2",
40
- "@nuxt/kit": "3.19.2",
40
+ "@nuxt/kit": "3.19.3",
41
41
  "@nuxt/module-builder": "1.0.2",
42
- "@nuxt/schema": "3.19.2",
42
+ "@nuxt/schema": "3.19.3",
43
43
  "@nuxt/test-utils": "3.19.2",
44
- "@types/node": "22.18.3",
44
+ "@types/node": "22.18.11",
45
45
  "@vitest/coverage-v8": "3.2.4",
46
46
  "@vueuse/core": "13.9.0",
47
47
  "dprint": "0.50.2",
48
48
  "eslint-formatter-gitlab": "6.0.1",
49
- "eslint": "9.35.0",
50
- "happy-dom": "18.0.1",
51
- "nuxt": "3.19.2",
52
- "publint": "0.3.12",
49
+ "eslint": "9.37.0",
50
+ "happy-dom": "20.0.7",
51
+ "nuxt": "3.19.3",
52
+ "publint": "0.3.14",
53
53
  "schema-dts": "1.1.5",
54
- "typescript": "5.9.2",
54
+ "typescript": "5.9.3",
55
55
  "unbuild": "3.6.1",
56
56
  "vitest": "3.2.4",
57
- "vue-router": "4.5.1",
58
- "vue-tsc": "3.0.7",
59
- "vue": "3.5.21",
60
- "@scayle/eslint-config-storefront": "4.7.8",
61
- "@scayle/storefront-nuxt": "8.44.1",
62
- "@scayle/vitest-config-storefront": "1.0.0"
57
+ "vue-router": "4.6.3",
58
+ "vue-tsc": "3.1.1",
59
+ "vue": "3.5.22",
60
+ "@scayle/eslint-config-storefront": "4.7.10",
61
+ "@scayle/vitest-config-storefront": "1.0.0",
62
+ "@scayle/storefront-nuxt": "8.45.1"
63
63
  },
64
64
  "scripts": {
65
65
  "build": "nuxt-module-build build",