@gfed-medusa/sf-lib-products 1.9.4 → 1.10.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/components/behavior-tracker/index.d.ts.map +1 -1
- package/dist/components/behavior-tracker/index.js +46 -33
- package/dist/components/behavior-tracker/index.js.map +1 -1
- package/dist/components/browse-product-preview/index.d.ts +2 -4
- package/dist/components/browse-product-preview/index.d.ts.map +1 -1
- package/dist/components/browse-product-preview/index.js +26 -3
- package/dist/components/browse-product-preview/index.js.map +1 -1
- package/dist/components/image-gallery/index.d.ts +3 -1
- package/dist/components/image-gallery/index.d.ts.map +1 -1
- package/dist/components/image-gallery/index.js +12 -2
- package/dist/components/image-gallery/index.js.map +1 -1
- package/dist/components/pagination/index.d.ts +2 -2
- package/dist/components/product-actions/index.d.ts +2 -2
- package/dist/components/product-actions/index.js +1 -1
- package/dist/components/product-onboarding-cta/index.d.ts +2 -2
- package/dist/components/product-onboarding-cta/index.d.ts.map +1 -1
- package/dist/components/product-price/index.d.ts +2 -2
- package/dist/components/product-tabs/index.d.ts +2 -2
- package/dist/components/product-tabs/index.d.ts.map +1 -1
- package/dist/components/product-tabs/index.js +29 -7
- package/dist/components/product-tabs/index.js.map +1 -1
- package/dist/components/refinement-list/index.d.ts +2 -2
- package/dist/components/refinement-list/index.d.ts.map +1 -1
- package/dist/components/refinement-list/index.js +7 -1
- package/dist/components/refinement-list/index.js.map +1 -1
- package/dist/components/refinement-list/sort-products/index.d.ts.map +1 -1
- package/dist/components/refinement-list/sort-products/index.js +3 -0
- package/dist/components/refinement-list/sort-products/index.js.map +1 -1
- package/dist/components/related-products/index.d.ts +2 -2
- package/dist/components/skeleton-product-grid/index.d.ts +2 -2
- package/dist/components/skeleton-product-preview/index.d.ts +2 -2
- package/dist/components/skeleton-product-preview/index.d.ts.map +1 -1
- package/dist/lib/data/cart.d.ts +1 -1
- package/dist/lib/data/cart.d.ts.map +1 -1
- package/dist/lib/data/cart.js +15 -5
- package/dist/lib/data/cart.js.map +1 -1
- package/dist/lib/gql/fragments/cart.d.ts +9 -9
- package/dist/lib/gql/fragments/cart.d.ts.map +1 -1
- package/dist/lib/gql/fragments/product.d.ts +16 -16
- package/dist/lib/gql/fragments/product.d.ts.map +1 -1
- package/dist/lib/gql/fragments/product.js +1 -0
- package/dist/lib/gql/fragments/product.js.map +1 -1
- package/dist/lib/gql/mutations/cart.d.ts +10 -10
- package/dist/lib/gql/queries/cart.d.ts +2 -2
- package/dist/lib/gql/queries/cart.d.ts.map +1 -1
- package/dist/lib/gql/queries/cart.js +1 -1
- package/dist/lib/gql/queries/cart.js.map +1 -1
- package/dist/lib/gql/queries/product.d.ts +13 -13
- package/dist/templates/paginated-products/client.js +0 -1
- package/dist/templates/paginated-products/client.js.map +1 -1
- package/dist/templates/paginated-products/index.d.ts +2 -2
- package/dist/templates/product-actions-wrapper/index.d.ts +2 -2
- package/dist/templates/product-info/index.d.ts +2 -2
- package/dist/templates/product-template/index.js +5 -2
- package/dist/templates/product-template/index.js.map +1 -1
- package/dist/templates/store-template/index.d.ts +2 -2
- package/dist/types/graphql.d.ts +160 -3
- package/dist/types/graphql.d.ts.map +1 -1
- package/dist/types/graphql.js +56 -2
- package/dist/types/graphql.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/behavior-tracker/index.tsx"],"sourcesContent":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/behavior-tracker/index.tsx"],"sourcesContent":[],"mappings":";;;UAuHiB,oBAAA;WACN;AADX;AAIgB,iBAAA,eAAA,CAAkB;EAAA;AAA+B,CAApB,EAAA,oBAAoB,CAAA,EAAA,IAAA"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useEffect, useRef } from "react";
|
|
4
|
+
import { sendClientSignal } from "@gfed-medusa/sf-lib-common/lib/personalization/client-signal";
|
|
5
|
+
import { SignalType } from "@gfed-medusa/sf-lib-common/types/graphql";
|
|
4
6
|
import { PERSONALIZATION_CONFIG, getSegmentIdFromCollection } from "@gfed-medusa/sf-lib-common/lib/personalization/config";
|
|
7
|
+
import { getSegmentCookie, setSegmentCookie } from "@gfed-medusa/sf-lib-common/lib/personalization/behavior-tracker";
|
|
5
8
|
import { useStorefrontContext } from "@gfed-medusa/sf-lib-common/lib/data/context";
|
|
9
|
+
import { useTimeOnPage } from "@gfed-medusa/sf-lib-common/lib/hooks/use-time-on-page";
|
|
6
10
|
|
|
7
11
|
//#region src/components/behavior-tracker/index.tsx
|
|
8
|
-
function buildCookieAttrs() {
|
|
9
|
-
return `path=/;max-age=${3600 * 24 * 7};SameSite=none;secure;domain=.justgood.win`;
|
|
10
|
-
}
|
|
11
12
|
const PDP_HESITATION_MS = PERSONALIZATION_CONFIG.pdpHesitationMs;
|
|
12
13
|
const HIGH_SCROLL_THRESHOLD = PERSONALIZATION_CONFIG.highScrollThreshold;
|
|
13
|
-
const
|
|
14
|
+
const PRICE_THRESHOLD = PERSONALIZATION_CONFIG.priceThreshold;
|
|
14
15
|
function getScrollPercentage() {
|
|
15
16
|
const scrollTop = window.scrollY;
|
|
16
17
|
const docHeight = document.documentElement.scrollHeight - window.innerHeight;
|
|
@@ -39,27 +40,15 @@ function throttle(fn, limit) {
|
|
|
39
40
|
});
|
|
40
41
|
}
|
|
41
42
|
function emitSignal(type, payload) {
|
|
42
|
-
const
|
|
43
|
-
let data = {};
|
|
44
|
-
if (match) try {
|
|
45
|
-
data = JSON.parse(decodeURIComponent(match[1]));
|
|
46
|
-
} catch {
|
|
47
|
-
data = {};
|
|
48
|
-
}
|
|
43
|
+
const data = getSegmentCookie();
|
|
49
44
|
if (!data.signals || typeof data.signals !== "object") data.signals = {};
|
|
50
45
|
data.signals[type] = payload ?? true;
|
|
51
|
-
|
|
46
|
+
setSegmentCookie(data);
|
|
52
47
|
}
|
|
53
48
|
const REPEAT_CATEGORY_THRESHOLD = 3;
|
|
54
49
|
function trackRepeatedCategoryView(segment) {
|
|
55
50
|
try {
|
|
56
|
-
const
|
|
57
|
-
let data = { signals: {} };
|
|
58
|
-
if (match) try {
|
|
59
|
-
data = JSON.parse(decodeURIComponent(match[1]));
|
|
60
|
-
} catch {
|
|
61
|
-
data = {};
|
|
62
|
-
}
|
|
51
|
+
const data = getSegmentCookie();
|
|
63
52
|
if (!data.signals || typeof data.signals !== "object") data.signals = {};
|
|
64
53
|
const categoryCounts = data.signals["repeated-category-view"] ?? {};
|
|
65
54
|
const newCount = (categoryCounts[segment] ?? 0) + 1;
|
|
@@ -69,22 +58,15 @@ function trackRepeatedCategoryView(segment) {
|
|
|
69
58
|
segment,
|
|
70
59
|
count: newCount
|
|
71
60
|
});
|
|
72
|
-
|
|
61
|
+
setSegmentCookie(data);
|
|
73
62
|
} catch {}
|
|
74
63
|
}
|
|
75
64
|
function addHistoryToCookie(segment) {
|
|
76
65
|
try {
|
|
77
|
-
const
|
|
78
|
-
let data = { history: [] };
|
|
79
|
-
if (match) try {
|
|
80
|
-
data = JSON.parse(decodeURIComponent(match[1]));
|
|
81
|
-
} catch {
|
|
82
|
-
data = {};
|
|
83
|
-
}
|
|
66
|
+
const data = getSegmentCookie();
|
|
84
67
|
if (!data.history || !Array.isArray(data.history)) data.history = [];
|
|
85
|
-
|
|
86
|
-
data
|
|
87
|
-
document.cookie = `_jg_segment=${encodeURIComponent(JSON.stringify(data))};${buildCookieAttrs()}`;
|
|
68
|
+
data.history = [...data.history, segment].slice(-PERSONALIZATION_CONFIG.historyMaxLength);
|
|
69
|
+
setSegmentCookie(data);
|
|
88
70
|
} catch {}
|
|
89
71
|
}
|
|
90
72
|
function BehaviorTracker({ product }) {
|
|
@@ -93,6 +75,9 @@ function BehaviorTracker({ product }) {
|
|
|
93
75
|
const scrollHandlerRef = useRef(null);
|
|
94
76
|
const scrollTrackedRef = useRef(false);
|
|
95
77
|
useRef(false);
|
|
78
|
+
const firedDepthRef = useRef(/* @__PURE__ */ new Set());
|
|
79
|
+
const exitIntentFiredRef = useRef(false);
|
|
80
|
+
useTimeOnPage("pdp", Boolean(product?.id));
|
|
96
81
|
useEffect(() => {
|
|
97
82
|
if (!product?.id) return;
|
|
98
83
|
const collectionHandle = product.collection?.handle;
|
|
@@ -102,16 +87,34 @@ function BehaviorTracker({ product }) {
|
|
|
102
87
|
trackRepeatedCategoryView(segment);
|
|
103
88
|
}
|
|
104
89
|
const productPrice = getCheapestVariantPrice(product);
|
|
90
|
+
sendClientSignal(SignalType.ProductView, {
|
|
91
|
+
productId: product.id,
|
|
92
|
+
productHandle: product.handle,
|
|
93
|
+
category: collectionHandle,
|
|
94
|
+
price: productPrice
|
|
95
|
+
});
|
|
105
96
|
const hasCart = Boolean(cartId);
|
|
106
|
-
if (productPrice && productPrice >=
|
|
97
|
+
if (productPrice && productPrice >= PRICE_THRESHOLD && !hasCart) hesitationTimeoutRef.current = setTimeout(() => {
|
|
107
98
|
emitSignal("pdp-hesitation", {
|
|
108
99
|
productId: product.id,
|
|
109
100
|
price: productPrice
|
|
110
101
|
});
|
|
111
102
|
}, PDP_HESITATION_MS);
|
|
112
103
|
const handleScroll = throttle(() => {
|
|
113
|
-
|
|
114
|
-
|
|
104
|
+
const scrollPct = Math.round(getScrollPercentage() * 100);
|
|
105
|
+
for (const threshold of [
|
|
106
|
+
25,
|
|
107
|
+
50,
|
|
108
|
+
75,
|
|
109
|
+
90
|
|
110
|
+
]) if (scrollPct >= threshold && !firedDepthRef.current.has(threshold)) {
|
|
111
|
+
firedDepthRef.current.add(threshold);
|
|
112
|
+
sendClientSignal(SignalType.ScrollDepth, {
|
|
113
|
+
depth: threshold,
|
|
114
|
+
page: window.location.pathname
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (getScrollPercentage() >= HIGH_SCROLL_THRESHOLD && !hasCart && !scrollTrackedRef.current) {
|
|
115
118
|
scrollTrackedRef.current = true;
|
|
116
119
|
emitSignal("high-scroll-no-action", {
|
|
117
120
|
productId: product.id,
|
|
@@ -133,6 +136,16 @@ function BehaviorTracker({ product }) {
|
|
|
133
136
|
scrollTrackedRef.current = false;
|
|
134
137
|
};
|
|
135
138
|
}, [product, cartId]);
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
const handleMouseLeave = (e) => {
|
|
141
|
+
if (e.clientY <= 0 && !exitIntentFiredRef.current) {
|
|
142
|
+
exitIntentFiredRef.current = true;
|
|
143
|
+
sendClientSignal(SignalType.ExitIntent, { page: window.location.pathname });
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
document.documentElement.addEventListener("mouseleave", handleMouseLeave);
|
|
147
|
+
return () => document.documentElement.removeEventListener("mouseleave", handleMouseLeave);
|
|
148
|
+
}, []);
|
|
136
149
|
return null;
|
|
137
150
|
}
|
|
138
151
|
var behavior_tracker_default = BehaviorTracker;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["cheapest: number | null"
|
|
1
|
+
{"version":3,"file":"index.js","names":["cheapest: number | null"],"sources":["../../../src/components/behavior-tracker/index.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef } from 'react';\n\nimport { sendClientSignal } from '@gfed-medusa/sf-lib-common/lib/personalization/client-signal';\nimport { SignalType } from '@gfed-medusa/sf-lib-common/types/graphql';\n\nimport {\n PERSONALIZATION_CONFIG,\n getSegmentIdFromCollection,\n} from '@gfed-medusa/sf-lib-common/lib/personalization/config';\nimport {\n getSegmentCookie,\n setSegmentCookie,\n} from '@gfed-medusa/sf-lib-common/lib/personalization/behavior-tracker';\nimport { useStorefrontContext } from '@gfed-medusa/sf-lib-common/lib/data/context';\nimport { useTimeOnPage } from '@gfed-medusa/sf-lib-common/lib/hooks/use-time-on-page';\nimport { Product } from '@/types/graphql';\n\nconst PDP_HESITATION_MS = PERSONALIZATION_CONFIG.pdpHesitationMs;\nconst HIGH_SCROLL_THRESHOLD = PERSONALIZATION_CONFIG.highScrollThreshold;\nconst PRICE_THRESHOLD = PERSONALIZATION_CONFIG.priceThreshold;\n\nfunction getScrollPercentage(): number {\n const scrollTop = window.scrollY;\n const docHeight =\n document.documentElement.scrollHeight - window.innerHeight;\n return docHeight > 0 ? scrollTop / docHeight : 0;\n}\n\nfunction getCheapestVariantPrice(product: Product): number | null {\n const variants = product.variants;\n if (!variants || variants.length === 0) return null;\n\n let cheapest: number | null = null;\n\n for (const variant of variants) {\n const priceObj = variant.price;\n if (priceObj && typeof priceObj.amount === 'number') {\n if (cheapest === null || priceObj.amount < cheapest) {\n cheapest = priceObj.amount;\n }\n }\n }\n\n return cheapest;\n}\n\nfunction throttle<T extends (...args: unknown[]) => void>(\n fn: T,\n limit: number\n): T {\n let lastCall = 0;\n return ((...args: unknown[]) => {\n const now = Date.now();\n if (now - lastCall >= limit) {\n lastCall = now;\n fn(...args);\n }\n }) as T;\n}\n\nfunction emitSignal(type: string, payload?: unknown) {\n const data = getSegmentCookie();\n\n if (!data.signals || typeof data.signals !== 'object') {\n data.signals = {};\n }\n\n (data.signals as Record<string, unknown>)[type] = payload ?? true;\n\n setSegmentCookie(data);\n}\n\nconst REPEAT_CATEGORY_THRESHOLD = 3;\n\nfunction trackRepeatedCategoryView(segment: string) {\n try {\n const data = getSegmentCookie();\n\n if (!data.signals || typeof data.signals !== 'object') {\n data.signals = {};\n }\n\n const categoryCounts = (data.signals as Record<string, unknown>)['repeated-category-view'] as Record<string, number> ?? {};\n const currentCount = categoryCounts[segment] ?? 0;\n const newCount = currentCount + 1;\n\n categoryCounts[segment] = newCount;\n (data.signals as Record<string, unknown>)['repeated-category-view'] = categoryCounts;\n\n if (newCount >= REPEAT_CATEGORY_THRESHOLD) {\n emitSignal('repeated-category-view', { segment, count: newCount });\n }\n\n setSegmentCookie(data);\n } catch {\n // Ignore\n }\n}\n\nfunction addHistoryToCookie(segment: string): void {\n try {\n const data = getSegmentCookie();\n\n if (!data.history || !Array.isArray(data.history)) {\n data.history = [];\n }\n\n const history = [...(data.history as string[]), segment].slice(\n -PERSONALIZATION_CONFIG.historyMaxLength\n );\n data.history = history;\n\n setSegmentCookie(data);\n } catch {\n }\n}\n\nexport interface BehaviorTrackerProps {\n product: Product;\n}\n\nexport function BehaviorTracker({ product }: BehaviorTrackerProps) {\n const { cartId } = useStorefrontContext();\n const hesitationTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(\n null\n );\n const scrollHandlerRef = useRef<(() => void) | null>(null);\n const scrollTrackedRef = useRef(false);\n const historyTrackedRef = useRef(false);\n const firedDepthRef = useRef<Set<number>>(new Set());\n const exitIntentFiredRef = useRef(false);\n\n useTimeOnPage('pdp', Boolean(product?.id));\n\n useEffect(() => {\n if (!product?.id) return;\n\n const collectionHandle = product.collection?.handle;\n const segment = getSegmentIdFromCollection(collectionHandle);\n\n if (segment) {\n addHistoryToCookie(segment);\n trackRepeatedCategoryView(segment);\n }\n\n const productPrice = getCheapestVariantPrice(product);\n void sendClientSignal(SignalType.ProductView, {\n productId: product.id,\n productHandle: product.handle,\n category: collectionHandle,\n price: productPrice,\n });\n\n const hasCart = Boolean(cartId);\n\n if (productPrice && productPrice >= PRICE_THRESHOLD && !hasCart) {\n hesitationTimeoutRef.current = setTimeout(() => {\n emitSignal('pdp-hesitation', {\n productId: product.id,\n price: productPrice,\n });\n }, PDP_HESITATION_MS);\n }\n\n const handleScroll = throttle(() => {\n // SCROLL_DEPTH analytics signal — always runs independently\n const scrollPct = Math.round(getScrollPercentage() * 100);\n const depthThresholds = [25, 50, 75, 90];\n for (const threshold of depthThresholds) {\n if (scrollPct >= threshold && !firedDepthRef.current.has(threshold)) {\n firedDepthRef.current.add(threshold);\n void sendClientSignal(SignalType.ScrollDepth, {\n depth: threshold,\n page: window.location.pathname,\n });\n }\n }\n\n if (getScrollPercentage() >= HIGH_SCROLL_THRESHOLD && !hasCart && !scrollTrackedRef.current) {\n scrollTrackedRef.current = true;\n emitSignal('high-scroll-no-action', {\n productId: product.id,\n scrollDepth: HIGH_SCROLL_THRESHOLD,\n });\n }\n }, 500);\n\n scrollHandlerRef.current = handleScroll;\n window.addEventListener('scroll', handleScroll, { passive: true });\n\n return () => {\n if (hesitationTimeoutRef.current !== null) {\n clearTimeout(hesitationTimeoutRef.current);\n hesitationTimeoutRef.current = null;\n }\n if (scrollHandlerRef.current !== null) {\n window.removeEventListener('scroll', scrollHandlerRef.current);\n scrollHandlerRef.current = null;\n }\n scrollTrackedRef.current = false;\n };\n }, [product, cartId]);\n\n useEffect(() => {\n const handleMouseLeave = (e: MouseEvent) => {\n if (e.clientY <= 0 && !exitIntentFiredRef.current) {\n exitIntentFiredRef.current = true;\n void sendClientSignal(SignalType.ExitIntent, {\n page: window.location.pathname,\n });\n }\n };\n document.documentElement.addEventListener('mouseleave', handleMouseLeave);\n return () => document.documentElement.removeEventListener('mouseleave', handleMouseLeave);\n }, []);\n\n return null;\n}\n\nexport default BehaviorTracker;\n"],"mappings":"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"}
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { BrowseProductHitFragment } from "../../types/graphql.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/browse-product-preview/index.d.ts
|
|
5
5
|
type BrowseProductPreviewProps = {
|
|
6
6
|
product: BrowseProductHitFragment;
|
|
7
7
|
isFeatured?: boolean;
|
|
8
|
-
imagePriority?: boolean;
|
|
9
8
|
imageFetchPriority?: 'auto' | 'high' | 'low';
|
|
10
9
|
};
|
|
11
10
|
declare const BrowseProductPreview: ({
|
|
12
11
|
product,
|
|
13
12
|
isFeatured,
|
|
14
|
-
imagePriority,
|
|
15
13
|
imageFetchPriority
|
|
16
|
-
}: BrowseProductPreviewProps) =>
|
|
14
|
+
}: BrowseProductPreviewProps) => react_jsx_runtime0.JSX.Element;
|
|
17
15
|
//#endregion
|
|
18
16
|
export { BrowseProductPreview };
|
|
19
17
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/browse-product-preview/index.tsx"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/browse-product-preview/index.tsx"],"sourcesContent":[],"mappings":";;;;KAkBK,yBAAA;WACM;;EADN,kBAAA,CAAA,EAAA,MAAA,GAAyB,MAAA,GAAA,KACnB;AAAwB,CAAA;cAwC7B,oBAAwB,EAAA,CAAA;EAAA,OAAA;EAAA,UAAA;EAAA;AAAA,CAAA,EAI3B,yBAJ2B,EAAA,GAIF,kBAAA,CAAA,GAAA,CAAA,OAJE"}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useRef } from "react";
|
|
4
|
+
import { sendClientSignal } from "@gfed-medusa/sf-lib-common/lib/personalization/client-signal";
|
|
5
|
+
import { SignalType } from "@gfed-medusa/sf-lib-common/types/graphql";
|
|
6
|
+
import { useSearchParams } from "next/navigation";
|
|
1
7
|
import { LocalizedClientLink } from "@gfed-medusa/sf-lib-common/components/localized-client-link";
|
|
2
8
|
import { PreviewPrice } from "@gfed-medusa/sf-lib-common/components/preview-price";
|
|
3
9
|
import { Thumbnail } from "@gfed-medusa/sf-lib-common/components/thumbnail";
|
|
@@ -27,19 +33,36 @@ const getBrowseProductPrice = (product) => {
|
|
|
27
33
|
percentage_diff: isSale && originalPrice > 0 ? getPercentageDiff(originalPrice, product.priceAmount) : "0"
|
|
28
34
|
};
|
|
29
35
|
};
|
|
30
|
-
const BrowseProductPreview = ({ product, isFeatured,
|
|
36
|
+
const BrowseProductPreview = ({ product, isFeatured, imageFetchPriority }) => {
|
|
31
37
|
const price = getBrowseProductPrice(product);
|
|
38
|
+
const hoveredRef = useRef(false);
|
|
39
|
+
const query = useSearchParams()?.get("q") ?? "";
|
|
32
40
|
return /* @__PURE__ */ jsx(LocalizedClientLink, {
|
|
33
|
-
href: `/products/${product.handle}`,
|
|
41
|
+
href: `/products/${product.handle ?? ""}`,
|
|
34
42
|
className: "group",
|
|
43
|
+
onClick: () => {
|
|
44
|
+
sendClientSignal(SignalType.SearchResultClick, {
|
|
45
|
+
productId: product.id ?? "",
|
|
46
|
+
productHandle: product.handle ?? "",
|
|
47
|
+
query
|
|
48
|
+
});
|
|
49
|
+
},
|
|
35
50
|
children: /* @__PURE__ */ jsxs("div", {
|
|
36
51
|
"data-testid": "product-wrapper",
|
|
52
|
+
onMouseEnter: () => {
|
|
53
|
+
if (!hoveredRef.current) {
|
|
54
|
+
hoveredRef.current = true;
|
|
55
|
+
sendClientSignal(SignalType.ProductHover, {
|
|
56
|
+
productId: product.id ?? "",
|
|
57
|
+
productHandle: product.handle ?? ""
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
},
|
|
37
61
|
children: [/* @__PURE__ */ jsx(Thumbnail, {
|
|
38
62
|
thumbnail: product.thumbnail,
|
|
39
63
|
images: [],
|
|
40
64
|
size: "full",
|
|
41
65
|
isFeatured,
|
|
42
|
-
imagePriority,
|
|
43
66
|
imageFetchPriority
|
|
44
67
|
}), /* @__PURE__ */ jsxs("div", {
|
|
45
68
|
className: "txt-compact-medium mt-4 flex min-w-0 flex-col items-start gap-y-1 text-left",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/browse-product-preview/index.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/browse-product-preview/index.tsx"],"sourcesContent":["'use client';\n\nimport { useRef } from 'react';\n\nimport { useSearchParams } from 'next/navigation';\n\nimport { LocalizedClientLink } from '@gfed-medusa/sf-lib-common/components/localized-client-link';\nimport { PreviewPrice } from '@gfed-medusa/sf-lib-common/components/preview-price';\nimport { Thumbnail } from '@gfed-medusa/sf-lib-common/components/thumbnail';\nimport { getPercentageDiff } from '@gfed-medusa/sf-lib-common/lib/utils/get-percentage-diff';\nimport { convertToLocale } from '@gfed-medusa/sf-lib-common/lib/utils/money';\nimport { sendClientSignal } from '@gfed-medusa/sf-lib-common/lib/personalization/client-signal';\nimport { SignalType } from '@gfed-medusa/sf-lib-common/types/graphql';\nimport type { VariantPrice } from '@gfed-medusa/sf-lib-common/types/prices';\nimport { Text } from '@medusajs/ui';\n\nimport type { BrowseProductHitFragment } from '@/types/graphql';\n\ntype BrowseProductPreviewProps = {\n product: BrowseProductHitFragment;\n isFeatured?: boolean;\n imageFetchPriority?: 'auto' | 'high' | 'low';\n};\n\nconst getBrowseProductPrice = (\n product: BrowseProductHitFragment\n): VariantPrice | null => {\n if (\n typeof product.priceAmount !== 'number' ||\n !product.currencyCode ||\n !product.currencyCode.trim()\n ) {\n return null;\n }\n\n const originalPrice = product.originalPriceAmount ?? product.priceAmount;\n const isSale =\n typeof originalPrice === 'number' && originalPrice > product.priceAmount;\n\n return {\n calculated_price_number: product.priceAmount,\n calculated_price: convertToLocale({\n amount: product.priceAmount,\n currency_code: product.currencyCode,\n }),\n original_price_number: originalPrice,\n original_price: convertToLocale({\n amount: originalPrice,\n currency_code: product.currencyCode,\n }),\n currency_code: product.currencyCode,\n price_type: isSale ? 'sale' : 'default',\n percentage_diff:\n isSale && originalPrice > 0\n ? getPercentageDiff(originalPrice, product.priceAmount)\n : '0',\n };\n};\n\nconst BrowseProductPreview = ({\n product,\n isFeatured,\n imageFetchPriority,\n}: BrowseProductPreviewProps) => {\n const price = getBrowseProductPrice(product);\n const hoveredRef = useRef(false);\n const searchParams = useSearchParams();\n const query = searchParams?.get('q') ?? '';\n\n return (\n <LocalizedClientLink\n href={`/products/${product.handle ?? ''}`}\n className=\"group\"\n onClick={() => {\n void sendClientSignal(SignalType.SearchResultClick, {\n productId: product.id ?? '',\n productHandle: product.handle ?? '',\n query,\n });\n }}\n >\n <div\n data-testid=\"product-wrapper\"\n onMouseEnter={() => {\n if (!hoveredRef.current) {\n hoveredRef.current = true;\n void sendClientSignal(SignalType.ProductHover, {\n productId: product.id ?? '',\n productHandle: product.handle ?? '',\n });\n }\n }}\n >\n <Thumbnail\n thumbnail={product.thumbnail}\n images={[]}\n size=\"full\"\n isFeatured={isFeatured}\n imageFetchPriority={imageFetchPriority}\n />\n <div className=\"txt-compact-medium mt-4 flex min-w-0 flex-col items-start gap-y-1 text-left\">\n <Text\n className=\"text-ui-fg-subtle w-full min-w-0 overflow-hidden break-words whitespace-normal [display:-webkit-box] [-webkit-box-orient:vertical] [-webkit-line-clamp:2]\"\n data-testid=\"product-title\"\n >\n {product.title}\n </Text>\n <div className=\"flex w-full min-w-0 flex-wrap items-baseline gap-x-2 gap-y-1 text-left\">\n {price && <PreviewPrice price={price} />}\n </div>\n </div>\n </div>\n </LocalizedClientLink>\n );\n};\n\nexport { BrowseProductPreview };\n"],"mappings":";;;;;;;;;;;;;;;AAwBA,MAAM,yBACJ,YACwB;AACxB,KACE,OAAO,QAAQ,gBAAgB,YAC/B,CAAC,QAAQ,gBACT,CAAC,QAAQ,aAAa,MAAM,CAE5B,QAAO;CAGT,MAAM,gBAAgB,QAAQ,uBAAuB,QAAQ;CAC7D,MAAM,SACJ,OAAO,kBAAkB,YAAY,gBAAgB,QAAQ;AAE/D,QAAO;EACL,yBAAyB,QAAQ;EACjC,kBAAkB,gBAAgB;GAChC,QAAQ,QAAQ;GAChB,eAAe,QAAQ;GACxB,CAAC;EACF,uBAAuB;EACvB,gBAAgB,gBAAgB;GAC9B,QAAQ;GACR,eAAe,QAAQ;GACxB,CAAC;EACF,eAAe,QAAQ;EACvB,YAAY,SAAS,SAAS;EAC9B,iBACE,UAAU,gBAAgB,IACtB,kBAAkB,eAAe,QAAQ,YAAY,GACrD;EACP;;AAGH,MAAM,wBAAwB,EAC5B,SACA,YACA,yBAC+B;CAC/B,MAAM,QAAQ,sBAAsB,QAAQ;CAC5C,MAAM,aAAa,OAAO,MAAM;CAEhC,MAAM,QADe,iBAAiB,EACV,IAAI,IAAI,IAAI;AAExC,QACE,oBAAC;EACC,MAAM,aAAa,QAAQ,UAAU;EACrC,WAAU;EACV,eAAe;AACb,GAAK,iBAAiB,WAAW,mBAAmB;IAClD,WAAW,QAAQ,MAAM;IACzB,eAAe,QAAQ,UAAU;IACjC;IACD,CAAC;;YAGJ,qBAAC;GACC,eAAY;GACZ,oBAAoB;AAClB,QAAI,CAAC,WAAW,SAAS;AACvB,gBAAW,UAAU;AACrB,KAAK,iBAAiB,WAAW,cAAc;MAC7C,WAAW,QAAQ,MAAM;MACzB,eAAe,QAAQ,UAAU;MAClC,CAAC;;;cAIN,oBAAC;IACC,WAAW,QAAQ;IACnB,QAAQ,EAAE;IACV,MAAK;IACO;IACQ;KACpB,EACF,qBAAC;IAAI,WAAU;eACb,oBAAC;KACC,WAAU;KACV,eAAY;eAEX,QAAQ;MACJ,EACP,oBAAC;KAAI,WAAU;eACZ,SAAS,oBAAC,gBAAoB,QAAS;MACpC;KACF;IACF;GACc"}
|
|
@@ -4,9 +4,11 @@ import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
|
4
4
|
//#region src/components/image-gallery/index.d.ts
|
|
5
5
|
type ImageGalleryProps = {
|
|
6
6
|
images: ProductImage[];
|
|
7
|
+
productId: string;
|
|
7
8
|
};
|
|
8
9
|
declare const ImageGallery: ({
|
|
9
|
-
images
|
|
10
|
+
images,
|
|
11
|
+
productId
|
|
10
12
|
}: ImageGalleryProps) => react_jsx_runtime0.JSX.Element;
|
|
11
13
|
//#endregion
|
|
12
14
|
export { ImageGallery as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/image-gallery/index.tsx"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/image-gallery/index.tsx"],"sourcesContent":[],"mappings":";;;;KAUK,iBAAA;UACK;;AAHqC,CAAA;AAGzB,cAIhB,YAsCL,EAAA,CAAA;EAAA,MAAA;EAAA;AAAA,CAAA,EAtC4C,iBAsC5C,EAAA,GAtC6D,kBAAA,CAAA,GAAA,CAAA,OAsC7D"}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { sendClientSignal } from "@gfed-medusa/sf-lib-common/lib/personalization/client-signal";
|
|
4
|
+
import { SignalType } from "@gfed-medusa/sf-lib-common/types/graphql";
|
|
1
5
|
import { Container } from "@medusajs/ui";
|
|
2
6
|
import { jsx } from "react/jsx-runtime";
|
|
3
7
|
import Image from "next/image";
|
|
4
8
|
|
|
5
9
|
//#region src/components/image-gallery/index.tsx
|
|
6
|
-
const ImageGallery = ({ images }) => {
|
|
10
|
+
const ImageGallery = ({ images, productId }) => {
|
|
7
11
|
return /* @__PURE__ */ jsx("div", {
|
|
8
12
|
className: "relative flex items-start",
|
|
9
13
|
children: /* @__PURE__ */ jsx("div", {
|
|
@@ -21,7 +25,13 @@ const ImageGallery = ({ images }) => {
|
|
|
21
25
|
quality: 60,
|
|
22
26
|
sizes: "(max-width: 576px) 280px, (max-width: 768px) 360px, (max-width: 992px) 480px, 800px",
|
|
23
27
|
style: { objectFit: "cover" },
|
|
24
|
-
...index === 0 ? { fetchPriority: "high" } : {}
|
|
28
|
+
...index === 0 ? { fetchPriority: "high" } : {},
|
|
29
|
+
onClick: () => {
|
|
30
|
+
sendClientSignal(SignalType.ImageZoom, {
|
|
31
|
+
productId,
|
|
32
|
+
imageUrl: image.url
|
|
33
|
+
});
|
|
34
|
+
}
|
|
25
35
|
})
|
|
26
36
|
}, image.id);
|
|
27
37
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/image-gallery/index.tsx"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/components/image-gallery/index.tsx"],"sourcesContent":["'use client';\n\nimport Image from 'next/image';\n\nimport { Container } from '@medusajs/ui';\n\nimport { sendClientSignal } from '@gfed-medusa/sf-lib-common/lib/personalization/client-signal';\nimport { SignalType } from '@gfed-medusa/sf-lib-common/types/graphql';\nimport { ProductImage } from '@/types/graphql';\n\ntype ImageGalleryProps = {\n images: ProductImage[];\n productId: string;\n};\n\nconst ImageGallery = ({ images, productId }: ImageGalleryProps) => {\n return (\n <div className=\"relative flex items-start\">\n <div className=\"small:mx-16 flex flex-1 flex-col gap-y-4\">\n {images.map((image, index) => {\n return (\n <Container\n key={image.id}\n className=\"bg-ui-bg-subtle relative aspect-[29/34] w-full overflow-hidden\"\n id={image.id}\n >\n {!!image.url && (\n <Image\n src={image.url}\n priority={index <= 2 ? true : false}\n className=\"rounded-rounded absolute inset-0\"\n alt={`Product image ${index + 1}`}\n fill\n quality={60}\n sizes=\"(max-width: 576px) 280px, (max-width: 768px) 360px, (max-width: 992px) 480px, 800px\"\n style={{\n objectFit: 'cover',\n }}\n {...(index === 0 ? { fetchPriority: 'high' } : {})}\n onClick={() => {\n void sendClientSignal(SignalType.ImageZoom, {\n productId,\n imageUrl: image.url,\n });\n }}\n />\n )}\n </Container>\n );\n })}\n </div>\n </div>\n );\n};\n\nexport default ImageGallery;\n"],"mappings":";;;;;;;;;AAeA,MAAM,gBAAgB,EAAE,QAAQ,gBAAmC;AACjE,QACE,oBAAC;EAAI,WAAU;YACb,oBAAC;GAAI,WAAU;aACZ,OAAO,KAAK,OAAO,UAAU;AAC5B,WACE,oBAAC;KAEC,WAAU;KACV,IAAI,MAAM;eAET,CAAC,CAAC,MAAM,OACP,oBAAC;MACC,KAAK,MAAM;MACX,UAAU,SAAS,IAAI,OAAO;MAC9B,WAAU;MACV,KAAK,iBAAiB,QAAQ;MAC9B;MACA,SAAS;MACT,OAAM;MACN,OAAO,EACL,WAAW,SACZ;MACD,GAAK,UAAU,IAAI,EAAE,eAAe,QAAQ,GAAG,EAAE;MACjD,eAAe;AACb,OAAK,iBAAiB,WAAW,WAAW;QAC1C;QACA,UAAU,MAAM;QACjB,CAAC;;OAEJ;OAvBC,MAAM,GAyBD;KAEd;IACE;GACF;;AAIV,4BAAe"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime2 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/components/pagination/index.d.ts
|
|
4
4
|
declare function Pagination({
|
|
@@ -19,7 +19,7 @@ declare function Pagination({
|
|
|
19
19
|
isLoading?: boolean;
|
|
20
20
|
onLoadMore: () => void;
|
|
21
21
|
'data-testid'?: string;
|
|
22
|
-
}):
|
|
22
|
+
}): react_jsx_runtime2.JSX.Element;
|
|
23
23
|
//#endregion
|
|
24
24
|
export { Pagination };
|
|
25
25
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ProductActionsProduct } from "../../types/index.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime4 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/product-actions/index.d.ts
|
|
5
5
|
type ProductActionsProps = {
|
|
@@ -13,7 +13,7 @@ declare function ProductActions({
|
|
|
13
13
|
regionId,
|
|
14
14
|
disabled,
|
|
15
15
|
enableMobileActions
|
|
16
|
-
}: ProductActionsProps):
|
|
16
|
+
}: ProductActionsProps): react_jsx_runtime4.JSX.Element;
|
|
17
17
|
//#endregion
|
|
18
18
|
export { ProductActionsProps, ProductActions as default };
|
|
19
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -7,9 +7,9 @@ import { useProductPrice } from "../../lib/hooks/use-product-price.js";
|
|
|
7
7
|
import { mergeProductPricing } from "../../lib/utils/merge-product-pricing.js";
|
|
8
8
|
import mobile_actions_default from "./mobile-actions.js";
|
|
9
9
|
import { useEffect, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { useParams } from "next/navigation";
|
|
10
11
|
import { Button } from "@medusajs/ui";
|
|
11
12
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
12
|
-
import { useParams } from "next/navigation";
|
|
13
13
|
import { isEqual } from "lodash";
|
|
14
14
|
import { ErrorMessage } from "@gfed-medusa/sf-lib-common/components/error-message";
|
|
15
15
|
import { WebComponent } from "@gfed-medusa/sf-lib-common/components/web-component";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime1 from "react/jsx-runtime";
|
|
2
2
|
|
|
3
3
|
//#region src/components/product-onboarding-cta/index.d.ts
|
|
4
|
-
declare function ProductOnboardingCta(): Promise<
|
|
4
|
+
declare function ProductOnboardingCta(): Promise<react_jsx_runtime1.JSX.Element | null>;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { ProductOnboardingCta as default };
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/product-onboarding-cta/index.tsx"],"sourcesContent":[],"mappings":";;;iBAIe,oBAAA,CAAA,GAAoB,QAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/product-onboarding-cta/index.tsx"],"sourcesContent":[],"mappings":";;;iBAIe,oBAAA,CAAA,GAAoB,QAAA,kBAAA,CAAA,GAAA,CAAA,OAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ProductVariant } from "../../types/graphql.js";
|
|
2
2
|
import { ProductActionsProduct } from "../../types/index.js";
|
|
3
|
-
import * as
|
|
3
|
+
import * as react_jsx_runtime3 from "react/jsx-runtime";
|
|
4
4
|
|
|
5
5
|
//#region src/components/product-price/index.d.ts
|
|
6
6
|
declare function ProductPrice({
|
|
@@ -9,7 +9,7 @@ declare function ProductPrice({
|
|
|
9
9
|
}: {
|
|
10
10
|
product: ProductActionsProduct;
|
|
11
11
|
variant?: ProductVariant;
|
|
12
|
-
}):
|
|
12
|
+
}): react_jsx_runtime3.JSX.Element;
|
|
13
13
|
//#endregion
|
|
14
14
|
export { ProductPrice as default };
|
|
15
15
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Product } from "../../types/graphql.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime5 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/product-tabs/index.d.ts
|
|
5
5
|
type ProductTabsProps = {
|
|
@@ -7,7 +7,7 @@ type ProductTabsProps = {
|
|
|
7
7
|
};
|
|
8
8
|
declare const ProductTabs: ({
|
|
9
9
|
product
|
|
10
|
-
}: ProductTabsProps) =>
|
|
10
|
+
}: ProductTabsProps) => react_jsx_runtime5.JSX.Element;
|
|
11
11
|
//#endregion
|
|
12
12
|
export { ProductTabs as default };
|
|
13
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/product-tabs/index.tsx"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/product-tabs/index.tsx"],"sourcesContent":[],"mappings":";;;;KAcK,gBAAA;WACM;;AAL+B,cAQpC,WAJe,EAAA,CAAA;EAAA;AACH,CAAP,EAGuB,gBAHhB,EAAA,GAGgC,kBAAA,CAAA,GAAA,CAAA,OAHhC"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import accordion_default from "./accordion.js";
|
|
4
|
+
import { useEffect, useRef, useState } from "react";
|
|
5
|
+
import { sendClientSignal } from "@gfed-medusa/sf-lib-common/lib/personalization/client-signal";
|
|
6
|
+
import { SignalType } from "@gfed-medusa/sf-lib-common/types/graphql";
|
|
4
7
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
8
|
import { Back } from "@gfed-medusa/sf-lib-ui/icons/back";
|
|
6
9
|
import { FastDelivery } from "@gfed-medusa/sf-lib-ui/icons/fast-delivery";
|
|
@@ -8,17 +11,36 @@ import { Refresh } from "@gfed-medusa/sf-lib-ui/icons/refresh";
|
|
|
8
11
|
|
|
9
12
|
//#region src/components/product-tabs/index.tsx
|
|
10
13
|
const ProductTabs = ({ product }) => {
|
|
14
|
+
const hasSentReviewsViewRef = useRef(false);
|
|
15
|
+
const productId = product.id;
|
|
16
|
+
const [openTabValues, setOpenTabValues] = useState([]);
|
|
17
|
+
const tabs = [{
|
|
18
|
+
label: "Product Information",
|
|
19
|
+
component: /* @__PURE__ */ jsx(ProductInfoTab, { product })
|
|
20
|
+
}, {
|
|
21
|
+
label: "Shipping & Returns",
|
|
22
|
+
component: /* @__PURE__ */ jsx(ShippingInfoTab, {})
|
|
23
|
+
}];
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (openTabValues.includes("Shipping & Returns") && !hasSentReviewsViewRef.current) {
|
|
26
|
+
hasSentReviewsViewRef.current = true;
|
|
27
|
+
sendClientSignal(SignalType.ReviewsView, { productId });
|
|
28
|
+
sendClientSignal(SignalType.ReturnPolicyView, { productId });
|
|
29
|
+
}
|
|
30
|
+
}, [openTabValues, productId]);
|
|
11
31
|
return /* @__PURE__ */ jsx("div", {
|
|
12
32
|
className: "w-full",
|
|
13
33
|
children: /* @__PURE__ */ jsx(accordion_default, {
|
|
14
34
|
type: "multiple",
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
35
|
+
value: openTabValues,
|
|
36
|
+
onValueChange: (values) => {
|
|
37
|
+
setOpenTabValues(values);
|
|
38
|
+
sendClientSignal(SignalType.TabSwitch, {
|
|
39
|
+
activeTabs: values,
|
|
40
|
+
productId
|
|
41
|
+
});
|
|
42
|
+
},
|
|
43
|
+
children: tabs.map((tab, i) => /* @__PURE__ */ jsx(accordion_default.Item, {
|
|
22
44
|
title: tab.label,
|
|
23
45
|
headingSize: "medium",
|
|
24
46
|
value: tab.label,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["Accordion"],"sources":["../../../src/components/product-tabs/index.tsx"],"sourcesContent":["'use client';\n\nimport { Back } from '@gfed-medusa/sf-lib-ui/icons/back';\nimport { FastDelivery } from '@gfed-medusa/sf-lib-ui/icons/fast-delivery';\nimport { Refresh } from '@gfed-medusa/sf-lib-ui/icons/refresh';\n\nimport { Product } from '@/types/graphql';\n\nimport Accordion from './accordion';\n\ntype ProductTabsProps = {\n product: Product;\n};\n\nconst ProductTabs = ({ product }: ProductTabsProps) => {\n const tabs = [\n {\n label: 'Product Information',\n component: <ProductInfoTab product={product} />,\n },\n {\n label: 'Shipping & Returns',\n component: <ShippingInfoTab />,\n },\n ];\n\n return (\n <div className=\"w-full\">\n <Accordion
|
|
1
|
+
{"version":3,"file":"index.js","names":["Accordion"],"sources":["../../../src/components/product-tabs/index.tsx"],"sourcesContent":["'use client';\n\nimport { useEffect, useRef, useState } from 'react';\n\nimport { Back } from '@gfed-medusa/sf-lib-ui/icons/back';\nimport { FastDelivery } from '@gfed-medusa/sf-lib-ui/icons/fast-delivery';\nimport { Refresh } from '@gfed-medusa/sf-lib-ui/icons/refresh';\n\nimport { sendClientSignal } from '@gfed-medusa/sf-lib-common/lib/personalization/client-signal';\nimport { SignalType } from '@gfed-medusa/sf-lib-common/types/graphql';\nimport { Product } from '@/types/graphql';\n\nimport Accordion from './accordion';\n\ntype ProductTabsProps = {\n product: Product;\n};\n\nconst ProductTabs = ({ product }: ProductTabsProps) => {\n const hasSentReviewsViewRef = useRef(false);\n const productId = product.id;\n const [openTabValues, setOpenTabValues] = useState<string[]>([]);\n\n const tabs = [\n {\n label: 'Product Information',\n component: <ProductInfoTab product={product} />,\n },\n {\n label: 'Shipping & Returns',\n component: <ShippingInfoTab />,\n },\n ];\n\n // Fire REVIEWS_VIEW and RETURN_POLICY_VIEW when the\n // \"Shipping & Returns\" tab is open — whether initially\n // (via defaultValue) or via user interaction.\n useEffect(() => {\n if (\n openTabValues.includes('Shipping & Returns') &&\n !hasSentReviewsViewRef.current\n ) {\n hasSentReviewsViewRef.current = true;\n void sendClientSignal(SignalType.ReviewsView, { productId });\n void sendClientSignal(SignalType.ReturnPolicyView, { productId });\n }\n }, [openTabValues, productId]);\n\n return (\n <div className=\"w-full\">\n <Accordion\n type=\"multiple\"\n value={openTabValues}\n onValueChange={(values: string[]) => {\n setOpenTabValues(values);\n void sendClientSignal(SignalType.TabSwitch, {\n activeTabs: values,\n productId,\n });\n }}\n >\n {tabs.map((tab, i) => (\n <Accordion.Item\n key={i}\n title={tab.label}\n headingSize=\"medium\"\n value={tab.label}\n >\n {tab.component}\n </Accordion.Item>\n ))}\n </Accordion>\n </div>\n );\n};\n\nconst ProductInfoTab = ({ product }: ProductTabsProps) => {\n return (\n <div className=\"text-small-regular py-8\">\n <div className=\"grid grid-cols-2 gap-x-8\">\n <div className=\"flex flex-col gap-y-4\">\n <div>\n <span className=\"font-semibold\">Material</span>\n <p>{product.material ? product.material : '-'}</p>\n </div>\n <div>\n <span className=\"font-semibold\">Country of origin</span>\n <p>{product.originCountry ? product.originCountry : '-'}</p>\n </div>\n <div>\n <span className=\"font-semibold\">Type</span>\n <p>{product.type || '-'}</p>\n </div>\n </div>\n <div className=\"flex flex-col gap-y-4\">\n <div>\n <span className=\"font-semibold\">Weight</span>\n <p>{product.weight ? `${product.weight} g` : '-'}</p>\n </div>\n <div>\n <span className=\"font-semibold\">Dimensions</span>\n <p>\n {product.length && product.width && product.height\n ? `${product.length}L x ${product.width}W x ${product.height}H`\n : '-'}\n </p>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nconst ShippingInfoTab = () => {\n return (\n <div className=\"text-small-regular py-8\">\n <div className=\"grid grid-cols-1 gap-y-8\">\n <div className=\"flex items-start gap-x-2\">\n <FastDelivery />\n <div>\n <span className=\"font-semibold\">Fast delivery</span>\n <p className=\"max-w-sm\">\n Your package will arrive in 3-5 business days at your pick up\n location or in the comfort of your home.\n </p>\n </div>\n </div>\n <div className=\"flex items-start gap-x-2\">\n <Refresh />\n <div>\n <span className=\"font-semibold\">Simple exchanges</span>\n <p className=\"max-w-sm\">\n Is the fit not quite right? No worries - we'll exchange your\n product for a new one.\n </p>\n </div>\n </div>\n <div className=\"flex items-start gap-x-2\">\n <Back />\n <div>\n <span className=\"font-semibold\">Easy returns</span>\n <p className=\"max-w-sm\">\n Just return your product and we'll refund your money. No\n questions asked – we'll do our best to make sure your return\n is hassle-free.\n </p>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default ProductTabs;\n"],"mappings":";;;;;;;;;;;;AAkBA,MAAM,eAAe,EAAE,cAAgC;CACrD,MAAM,wBAAwB,OAAO,MAAM;CAC3C,MAAM,YAAY,QAAQ;CAC1B,MAAM,CAAC,eAAe,oBAAoB,SAAmB,EAAE,CAAC;CAEhE,MAAM,OAAO,CACX;EACE,OAAO;EACP,WAAW,oBAAC,kBAAwB,UAAW;EAChD,EACD;EACE,OAAO;EACP,WAAW,oBAAC,oBAAkB;EAC/B,CACF;AAKD,iBAAgB;AACd,MACE,cAAc,SAAS,qBAAqB,IAC5C,CAAC,sBAAsB,SACvB;AACA,yBAAsB,UAAU;AAChC,GAAK,iBAAiB,WAAW,aAAa,EAAE,WAAW,CAAC;AAC5D,GAAK,iBAAiB,WAAW,kBAAkB,EAAE,WAAW,CAAC;;IAElE,CAAC,eAAe,UAAU,CAAC;AAE9B,QACE,oBAAC;EAAI,WAAU;YACb,oBAACA;GACC,MAAK;GACL,OAAO;GACP,gBAAgB,WAAqB;AACnC,qBAAiB,OAAO;AACxB,IAAK,iBAAiB,WAAW,WAAW;KAC1C,YAAY;KACZ;KACD,CAAC;;aAGH,KAAK,KAAK,KAAK,MACd,oBAACA,kBAAU;IAET,OAAO,IAAI;IACX,aAAY;IACZ,OAAO,IAAI;cAEV,IAAI;MALA,EAMU,CACjB;IACQ;GACR;;AAIV,MAAM,kBAAkB,EAAE,cAAgC;AACxD,QACE,oBAAC;EAAI,WAAU;YACb,qBAAC;GAAI,WAAU;cACb,qBAAC;IAAI,WAAU;;KACb,qBAAC,oBACC,oBAAC;MAAK,WAAU;gBAAgB;OAAe,EAC/C,oBAAC,iBAAG,QAAQ,WAAW,QAAQ,WAAW,MAAQ,IAC9C;KACN,qBAAC,oBACC,oBAAC;MAAK,WAAU;gBAAgB;OAAwB,EACxD,oBAAC,iBAAG,QAAQ,gBAAgB,QAAQ,gBAAgB,MAAQ,IACxD;KACN,qBAAC,oBACC,oBAAC;MAAK,WAAU;gBAAgB;OAAW,EAC3C,oBAAC,iBAAG,QAAQ,QAAQ,MAAQ,IACxB;;KACF,EACN,qBAAC;IAAI,WAAU;eACb,qBAAC,oBACC,oBAAC;KAAK,WAAU;eAAgB;MAAa,EAC7C,oBAAC,iBAAG,QAAQ,SAAS,GAAG,QAAQ,OAAO,MAAM,MAAQ,IACjD,EACN,qBAAC,oBACC,oBAAC;KAAK,WAAU;eAAgB;MAAiB,EACjD,oBAAC,iBACE,QAAQ,UAAU,QAAQ,SAAS,QAAQ,SACxC,GAAG,QAAQ,OAAO,MAAM,QAAQ,MAAM,MAAM,QAAQ,OAAO,KAC3D,MACF,IACA;KACF;IACF;GACF;;AAIV,MAAM,wBAAwB;AAC5B,QACE,oBAAC;EAAI,WAAU;YACb,qBAAC;GAAI,WAAU;;IACb,qBAAC;KAAI,WAAU;gBACb,oBAAC,iBAAe,EAChB,qBAAC,oBACC,oBAAC;MAAK,WAAU;gBAAgB;OAAoB,EACpD,oBAAC;MAAE,WAAU;gBAAW;OAGpB,IACA;MACF;IACN,qBAAC;KAAI,WAAU;gBACb,oBAAC,YAAU,EACX,qBAAC,oBACC,oBAAC;MAAK,WAAU;gBAAgB;OAAuB,EACvD,oBAAC;MAAE,WAAU;gBAAW;OAGpB,IACA;MACF;IACN,qBAAC;KAAI,WAAU;gBACb,oBAAC,SAAO,EACR,qBAAC,oBACC,oBAAC;MAAK,WAAU;gBAAgB;OAAmB,EACnD,oBAAC;MAAE,WAAU;gBAAW;OAIpB,IACA;MACF;;IACF;GACF;;AAIV,2BAAe"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SortOptions } from "./sort-products/index.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime6 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/components/refinement-list/index.d.ts
|
|
5
5
|
type RefinementListProps = {
|
|
@@ -12,7 +12,7 @@ declare const RefinementList: ({
|
|
|
12
12
|
sortBy,
|
|
13
13
|
"data-testid": dataTestId,
|
|
14
14
|
className
|
|
15
|
-
}: RefinementListProps) =>
|
|
15
|
+
}: RefinementListProps) => react_jsx_runtime6.JSX.Element;
|
|
16
16
|
//#endregion
|
|
17
17
|
export { RefinementList as default };
|
|
18
18
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/refinement-list/index.tsx"],"sourcesContent":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/components/refinement-list/index.tsx"],"sourcesContent":[],"mappings":";;;;KAaK,mBAAA;UACK;;EADL,aAAA,CAAA,EAAA,MAAmB;EAOlB,SAAA,CAAA,EAAA,MAmDL;CAnDuB;cAAlB,cAAkB,EAAA,CAAA;EAAA,MAAA;EAAA,aAAA,EAAA,UAAA;EAAA;AAAA,CAAA,EAIrB,mBAJqB,EAAA,GAIF,kBAAA,CAAA,GAAA,CAAA,OAJE"}
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import sort_products_default from "./sort-products/index.js";
|
|
4
4
|
import { useCallback } from "react";
|
|
5
|
+
import { sendClientSignal } from "@gfed-medusa/sf-lib-common/lib/personalization/client-signal";
|
|
6
|
+
import { SignalType } from "@gfed-medusa/sf-lib-common/types/graphql";
|
|
7
|
+
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
5
8
|
import { clx } from "@medusajs/ui";
|
|
6
9
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
-
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
8
10
|
|
|
9
11
|
//#region src/components/refinement-list/index.tsx
|
|
10
12
|
const RefinementList = ({ sortBy, "data-testid": dataTestId, className }) => {
|
|
@@ -19,6 +21,10 @@ const RefinementList = ({ sortBy, "data-testid": dataTestId, className }) => {
|
|
|
19
21
|
}, [searchParams]);
|
|
20
22
|
const setQueryParams = (name, value) => {
|
|
21
23
|
const query = createQueryString(name, value);
|
|
24
|
+
if (name !== "sortBy") sendClientSignal(SignalType.FilterApplied, {
|
|
25
|
+
filterName: name,
|
|
26
|
+
filterValue: value
|
|
27
|
+
});
|
|
22
28
|
router.push(`${pathname}?${query}`);
|
|
23
29
|
};
|
|
24
30
|
return /* @__PURE__ */ jsxs("div", {
|