@primestyleai/tryon 5.10.194 → 5.10.195
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/PrimeStyleTryon.d.ts +5 -0
- package/dist/api-client.d.ts +30 -1
- package/dist/{index-BiotPzcm.js → index-D_9-KLXy.js} +150 -102
- package/dist/index-D_9-KLXy.js.map +1 -0
- package/dist/primestyle-tryon.js +232 -164
- package/dist/primestyle-tryon.js.map +1 -1
- package/dist/react/index.js +4318 -4067
- package/dist/react/index.js.map +1 -1
- package/dist/storefront/primestyle-tryon.js +429 -99
- package/package.json +1 -1
- package/dist/index-BiotPzcm.js.map +0 -1
|
@@ -9321,53 +9321,6 @@ reactJsxRuntime_production_min.jsxs = q;
|
|
|
9321
9321
|
jsxRuntime.exports = reactJsxRuntime_production_min;
|
|
9322
9322
|
}
|
|
9323
9323
|
var jsxRuntimeExports = jsxRuntime.exports;
|
|
9324
|
-
function cx(base, override) {
|
|
9325
|
-
return override ? `${base} ${override}` : base;
|
|
9326
|
-
}
|
|
9327
|
-
const MOBILE_BREAKPOINT = 768;
|
|
9328
|
-
function useIsMobile() {
|
|
9329
|
-
const [isMobile, setIsMobile] = reactExports.useState(false);
|
|
9330
|
-
reactExports.useEffect(() => {
|
|
9331
|
-
if (typeof window === "undefined") return;
|
|
9332
|
-
const check = () => setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
9333
|
-
check();
|
|
9334
|
-
window.addEventListener("resize", check);
|
|
9335
|
-
return () => window.removeEventListener("resize", check);
|
|
9336
|
-
}, []);
|
|
9337
|
-
return isMobile;
|
|
9338
|
-
}
|
|
9339
|
-
function ErrorView({
|
|
9340
|
-
productImage,
|
|
9341
|
-
productTitle,
|
|
9342
|
-
onManualMeasurements,
|
|
9343
|
-
cn,
|
|
9344
|
-
t: t2
|
|
9345
|
-
}) {
|
|
9346
|
-
const isMobile = useIsMobile();
|
|
9347
|
-
const RightColumn = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cx("ps-tryon-no-chart-content ps-tryon-error-fallback", cn.error), children: [
|
|
9348
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-icon ps-tryon-error-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", width: "44", height: "44", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
9349
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 3l8.5 15H3.5L12 3z" }),
|
|
9350
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 9v4" }),
|
|
9351
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 17h.01" })
|
|
9352
|
-
] }) }),
|
|
9353
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-no-chart-title", children: t2("We couldn't find a matching size for you") }),
|
|
9354
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: cx("ps-tryon-no-chart-msg", cn.errorText), children: t2("Please try the manual measurement screen so we can calculate your fit from your measurements.") }),
|
|
9355
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-actions", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", onClick: onManualMeasurements, className: cx("ps-tryon-no-chart-cta", cn.submitButton), children: [
|
|
9356
|
-
t2("Try manual measurements"),
|
|
9357
|
-
" →"
|
|
9358
|
-
] }) })
|
|
9359
|
-
] });
|
|
9360
|
-
if (isMobile) {
|
|
9361
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr", children: [
|
|
9362
|
-
productImage && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-col", style: { flex: "0 0 auto", maxHeight: "38vh" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle || "", className: "ps-tryon-sr-product-img" }) }),
|
|
9363
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-right-col", children: RightColumn })
|
|
9364
|
-
] });
|
|
9365
|
-
}
|
|
9366
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-split", children: [
|
|
9367
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-col", children: productImage && /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle || "", className: "ps-tryon-sr-product-img" }) }),
|
|
9368
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-right-col ps-tryon-no-chart-right-col", children: RightColumn })
|
|
9369
|
-
] }) });
|
|
9370
|
-
}
|
|
9371
9324
|
const STORAGE_KEY = "ps_session";
|
|
9372
9325
|
const MAX_AGE_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
9373
9326
|
const FALLBACK_PREFIX = "ps_mem_";
|
|
@@ -9412,6 +9365,14 @@ function writeRecord(record) {
|
|
|
9412
9365
|
} catch {
|
|
9413
9366
|
}
|
|
9414
9367
|
}
|
|
9368
|
+
function attachReplaySession(sessionId) {
|
|
9369
|
+
if (typeof window === "undefined") return;
|
|
9370
|
+
try {
|
|
9371
|
+
const clarity = window.clarity;
|
|
9372
|
+
if (typeof clarity === "function") clarity("set", STORAGE_KEY, sessionId);
|
|
9373
|
+
} catch {
|
|
9374
|
+
}
|
|
9375
|
+
}
|
|
9415
9376
|
function getOrCreateSessionId() {
|
|
9416
9377
|
const now = Date.now();
|
|
9417
9378
|
const existing = readRecord();
|
|
@@ -9419,10 +9380,12 @@ function getOrCreateSessionId() {
|
|
|
9419
9380
|
if (now - existing.lastSeenAt > 5 * 60 * 1e3) {
|
|
9420
9381
|
writeRecord({ ...existing, lastSeenAt: now });
|
|
9421
9382
|
}
|
|
9383
|
+
attachReplaySession(existing.id);
|
|
9422
9384
|
return existing.id;
|
|
9423
9385
|
}
|
|
9424
9386
|
const fresh = { id: uuid(), issuedAt: now, lastSeenAt: now };
|
|
9425
9387
|
writeRecord(fresh);
|
|
9388
|
+
attachReplaySession(fresh.id);
|
|
9426
9389
|
return fresh.id;
|
|
9427
9390
|
}
|
|
9428
9391
|
function getDeviceHint() {
|
|
@@ -9544,8 +9507,49 @@ class ApiClient {
|
|
|
9544
9507
|
}
|
|
9545
9508
|
return res.json();
|
|
9546
9509
|
}
|
|
9547
|
-
|
|
9548
|
-
const
|
|
9510
|
+
async reportEvent(input) {
|
|
9511
|
+
const res = await fetch(`${this.baseUrl}/api/v1/tryon/event`, {
|
|
9512
|
+
method: "POST",
|
|
9513
|
+
headers: this.headers,
|
|
9514
|
+
keepalive: true,
|
|
9515
|
+
body: JSON.stringify({
|
|
9516
|
+
...input,
|
|
9517
|
+
sessionId: getOrCreateSessionId(),
|
|
9518
|
+
deviceHint: getDeviceHint()
|
|
9519
|
+
})
|
|
9520
|
+
});
|
|
9521
|
+
if (!res.ok) {
|
|
9522
|
+
const data = await res.json().catch(() => ({}));
|
|
9523
|
+
throw new PrimeStyleError(
|
|
9524
|
+
data.message || "Failed to report SDK event",
|
|
9525
|
+
"EVENT_REPORT_FAILED"
|
|
9526
|
+
);
|
|
9527
|
+
}
|
|
9528
|
+
return res.json();
|
|
9529
|
+
}
|
|
9530
|
+
async reportClientError(input) {
|
|
9531
|
+
const res = await fetch(`${this.baseUrl}/api/v1/tryon/client-error`, {
|
|
9532
|
+
method: "POST",
|
|
9533
|
+
headers: this.headers,
|
|
9534
|
+
keepalive: true,
|
|
9535
|
+
body: JSON.stringify({
|
|
9536
|
+
...input,
|
|
9537
|
+
sessionId: getOrCreateSessionId(),
|
|
9538
|
+
deviceHint: getDeviceHint()
|
|
9539
|
+
})
|
|
9540
|
+
});
|
|
9541
|
+
if (!res.ok) {
|
|
9542
|
+
const data = await res.json().catch(() => ({}));
|
|
9543
|
+
throw new PrimeStyleError(
|
|
9544
|
+
data.message || "Failed to report SDK client error",
|
|
9545
|
+
"CLIENT_ERROR_REPORT_FAILED"
|
|
9546
|
+
);
|
|
9547
|
+
}
|
|
9548
|
+
return res.json();
|
|
9549
|
+
}
|
|
9550
|
+
getStreamUrl(jobId) {
|
|
9551
|
+
const streamPath = jobId ? `/api/v1/tryon/stream/${encodeURIComponent(jobId)}` : "/api/v1/tryon/stream";
|
|
9552
|
+
const streamUrl = `${this.baseUrl}${streamPath}`;
|
|
9549
9553
|
return this.apiKey ? `${streamUrl}?key=${encodeURIComponent(this.apiKey)}` : streamUrl;
|
|
9550
9554
|
}
|
|
9551
9555
|
}
|
|
@@ -9561,6 +9565,89 @@ class PrimeStyleError extends Error {
|
|
|
9561
9565
|
this.code = code;
|
|
9562
9566
|
}
|
|
9563
9567
|
}
|
|
9568
|
+
function detectLocale() {
|
|
9569
|
+
if (typeof navigator === "undefined") return "US";
|
|
9570
|
+
const lang = navigator.language || "";
|
|
9571
|
+
const region = lang.split("-")[1]?.toUpperCase();
|
|
9572
|
+
if (region === "GB") return "UK";
|
|
9573
|
+
if (region) return region;
|
|
9574
|
+
const map = {
|
|
9575
|
+
en: "US",
|
|
9576
|
+
ja: "JP",
|
|
9577
|
+
ko: "KR",
|
|
9578
|
+
zh: "CN",
|
|
9579
|
+
fr: "FR",
|
|
9580
|
+
it: "IT",
|
|
9581
|
+
de: "DE",
|
|
9582
|
+
es: "ES",
|
|
9583
|
+
pt: "BR"
|
|
9584
|
+
};
|
|
9585
|
+
return map[lang.split("-")[0].toLowerCase()] || "US";
|
|
9586
|
+
}
|
|
9587
|
+
function getApiKey() {
|
|
9588
|
+
let key = "";
|
|
9589
|
+
try {
|
|
9590
|
+
key = "shopify-proxy";
|
|
9591
|
+
} catch {
|
|
9592
|
+
}
|
|
9593
|
+
return key;
|
|
9594
|
+
}
|
|
9595
|
+
function getApiUrl(override) {
|
|
9596
|
+
if (override) return override;
|
|
9597
|
+
let envUrl = "";
|
|
9598
|
+
try {
|
|
9599
|
+
envUrl = "";
|
|
9600
|
+
} catch {
|
|
9601
|
+
}
|
|
9602
|
+
return envUrl || "http://localhost:4000";
|
|
9603
|
+
}
|
|
9604
|
+
function cx(base, override) {
|
|
9605
|
+
return override ? `${base} ${override}` : base;
|
|
9606
|
+
}
|
|
9607
|
+
const MOBILE_BREAKPOINT = 768;
|
|
9608
|
+
function useIsMobile() {
|
|
9609
|
+
const [isMobile, setIsMobile] = reactExports.useState(false);
|
|
9610
|
+
reactExports.useEffect(() => {
|
|
9611
|
+
if (typeof window === "undefined") return;
|
|
9612
|
+
const check = () => setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
|
|
9613
|
+
check();
|
|
9614
|
+
window.addEventListener("resize", check);
|
|
9615
|
+
return () => window.removeEventListener("resize", check);
|
|
9616
|
+
}, []);
|
|
9617
|
+
return isMobile;
|
|
9618
|
+
}
|
|
9619
|
+
function ErrorView({
|
|
9620
|
+
productImage,
|
|
9621
|
+
productTitle,
|
|
9622
|
+
onManualMeasurements,
|
|
9623
|
+
cn,
|
|
9624
|
+
t: t2
|
|
9625
|
+
}) {
|
|
9626
|
+
const isMobile = useIsMobile();
|
|
9627
|
+
const RightColumn = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: cx("ps-tryon-no-chart-content ps-tryon-error-fallback", cn.error), children: [
|
|
9628
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-icon ps-tryon-error-fallback-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", width: "44", height: "44", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
9629
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 3l8.5 15H3.5L12 3z" }),
|
|
9630
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 9v4" }),
|
|
9631
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 17h.01" })
|
|
9632
|
+
] }) }),
|
|
9633
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-no-chart-title", children: t2("We couldn't find a matching size for you") }),
|
|
9634
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: cx("ps-tryon-no-chart-msg", cn.errorText), children: t2("Please try the manual measurement screen so we can calculate your fit from your measurements.") }),
|
|
9635
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-actions", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", onClick: onManualMeasurements, className: cx("ps-tryon-no-chart-cta", cn.submitButton), children: [
|
|
9636
|
+
t2("Try manual measurements"),
|
|
9637
|
+
" →"
|
|
9638
|
+
] }) })
|
|
9639
|
+
] });
|
|
9640
|
+
if (isMobile) {
|
|
9641
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr", children: [
|
|
9642
|
+
productImage && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-col", style: { flex: "0 0 auto", maxHeight: "38vh" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle || "", className: "ps-tryon-sr-product-img" }) }),
|
|
9643
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-right-col", children: RightColumn })
|
|
9644
|
+
] });
|
|
9645
|
+
}
|
|
9646
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-split", children: [
|
|
9647
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-img-col", children: productImage && /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: productImage, alt: productTitle || "", className: "ps-tryon-sr-product-img" }) }),
|
|
9648
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-right-col ps-tryon-no-chart-right-col", children: RightColumn })
|
|
9649
|
+
] }) });
|
|
9650
|
+
}
|
|
9564
9651
|
class SseClient {
|
|
9565
9652
|
constructor(streamUrl) {
|
|
9566
9653
|
this.eventSource = null;
|
|
@@ -10932,42 +11019,6 @@ function installCartHook() {
|
|
|
10932
11019
|
}
|
|
10933
11020
|
console.log(TAG$1, "attribution hook installed");
|
|
10934
11021
|
}
|
|
10935
|
-
function detectLocale() {
|
|
10936
|
-
if (typeof navigator === "undefined") return "US";
|
|
10937
|
-
const lang = navigator.language || "";
|
|
10938
|
-
const region = lang.split("-")[1]?.toUpperCase();
|
|
10939
|
-
if (region === "GB") return "UK";
|
|
10940
|
-
if (region) return region;
|
|
10941
|
-
const map = {
|
|
10942
|
-
en: "US",
|
|
10943
|
-
ja: "JP",
|
|
10944
|
-
ko: "KR",
|
|
10945
|
-
zh: "CN",
|
|
10946
|
-
fr: "FR",
|
|
10947
|
-
it: "IT",
|
|
10948
|
-
de: "DE",
|
|
10949
|
-
es: "ES",
|
|
10950
|
-
pt: "BR"
|
|
10951
|
-
};
|
|
10952
|
-
return map[lang.split("-")[0].toLowerCase()] || "US";
|
|
10953
|
-
}
|
|
10954
|
-
function getApiKey() {
|
|
10955
|
-
let key = "";
|
|
10956
|
-
try {
|
|
10957
|
-
key = "shopify-proxy";
|
|
10958
|
-
} catch {
|
|
10959
|
-
}
|
|
10960
|
-
return key;
|
|
10961
|
-
}
|
|
10962
|
-
function getApiUrl(override) {
|
|
10963
|
-
if (override) return override;
|
|
10964
|
-
let envUrl = "";
|
|
10965
|
-
try {
|
|
10966
|
-
envUrl = "";
|
|
10967
|
-
} catch {
|
|
10968
|
-
}
|
|
10969
|
-
return envUrl || "http://localhost:4000";
|
|
10970
|
-
}
|
|
10971
11022
|
const SESSION_KEY = "primestyle_profile_session";
|
|
10972
11023
|
const AUTH_MESSAGE_TYPE = "PRIMESTYLE_SDK_AUTH";
|
|
10973
11024
|
const POPUP_TIMEOUT_MS = 12e4;
|
|
@@ -11150,6 +11201,30 @@ async function saveRemoteProfiles(apiUrl, accessToken, profiles, activeProfileId
|
|
|
11150
11201
|
});
|
|
11151
11202
|
return normalizeStore(await parseResponse(response));
|
|
11152
11203
|
}
|
|
11204
|
+
function shouldUseShopifyProxy(apiUrl) {
|
|
11205
|
+
if (typeof window === "undefined") return false;
|
|
11206
|
+
try {
|
|
11207
|
+
const w2 = window;
|
|
11208
|
+
if (w2.Shopify?.shop) return true;
|
|
11209
|
+
return /\/apps\/primestyle\/?$/.test(apiUrl);
|
|
11210
|
+
} catch {
|
|
11211
|
+
return false;
|
|
11212
|
+
}
|
|
11213
|
+
}
|
|
11214
|
+
function reportDirectSdkEvent(apiUrl, apiKey, body) {
|
|
11215
|
+
if (!apiKey || shouldUseShopifyProxy(apiUrl)) return;
|
|
11216
|
+
void fetch(`${apiUrl}/api/v1/tryon/event`, {
|
|
11217
|
+
method: "POST",
|
|
11218
|
+
headers: jsonHeaders(apiKey),
|
|
11219
|
+
keepalive: true,
|
|
11220
|
+
body: JSON.stringify({
|
|
11221
|
+
...body,
|
|
11222
|
+
sessionId: getOrCreateSessionId(),
|
|
11223
|
+
deviceHint: getDeviceHint()
|
|
11224
|
+
})
|
|
11225
|
+
}).catch(() => {
|
|
11226
|
+
});
|
|
11227
|
+
}
|
|
11153
11228
|
let cachedMP = null;
|
|
11154
11229
|
const MP_CACHE_TTL_MS = 6e4;
|
|
11155
11230
|
function setCachedMediaPipe(landmarks) {
|
|
@@ -11223,6 +11298,13 @@ async function recommendForProduct(input) {
|
|
|
11223
11298
|
recommendedSize: cached.recommendedSize,
|
|
11224
11299
|
fromCache: true
|
|
11225
11300
|
});
|
|
11301
|
+
reportDirectSdkEvent(apiUrl, apiKey, {
|
|
11302
|
+
eventType: "SIZE_RECOMMENDATION_SHOWN",
|
|
11303
|
+
productId: input.productId,
|
|
11304
|
+
productTitle: input.productTitle,
|
|
11305
|
+
recommendedSize: cached.recommendedSize,
|
|
11306
|
+
metadata: { fromCache: true, profileId: profile.id }
|
|
11307
|
+
});
|
|
11226
11308
|
const reconstructedRaw = cached.sectionsFull ? {
|
|
11227
11309
|
recommendedSize: cached.recommendedSize,
|
|
11228
11310
|
confidence: cached.confidence || "high",
|
|
@@ -11434,6 +11516,19 @@ async function recommendForProduct(input) {
|
|
|
11434
11516
|
size: result.recommendedSize,
|
|
11435
11517
|
recommendedSize: result.recommendedSize
|
|
11436
11518
|
});
|
|
11519
|
+
logSizeShown({
|
|
11520
|
+
productId: input.productId,
|
|
11521
|
+
productTitle: input.productTitle,
|
|
11522
|
+
recommendedSize: result.recommendedSize,
|
|
11523
|
+
fromCache: false
|
|
11524
|
+
});
|
|
11525
|
+
reportDirectSdkEvent(apiUrl, apiKey, {
|
|
11526
|
+
eventType: "SIZE_RECOMMENDATION_SHOWN",
|
|
11527
|
+
productId: input.productId,
|
|
11528
|
+
productTitle: input.productTitle,
|
|
11529
|
+
recommendedSize: result.recommendedSize,
|
|
11530
|
+
metadata: { fromCache: false, profileId: profile.id, found: result.found }
|
|
11531
|
+
});
|
|
11437
11532
|
return {
|
|
11438
11533
|
recommendedSize: result.recommendedSize,
|
|
11439
11534
|
confidence: result.confidence,
|
|
@@ -35031,7 +35126,7 @@ function PrimeStyleTryonInner({
|
|
|
35031
35126
|
const key = getApiKey();
|
|
35032
35127
|
const url = getApiUrl(apiUrl);
|
|
35033
35128
|
apiRef.current = new ApiClient(key, url);
|
|
35034
|
-
sseRef.current =
|
|
35129
|
+
sseRef.current = null;
|
|
35035
35130
|
} catch {
|
|
35036
35131
|
}
|
|
35037
35132
|
return () => {
|
|
@@ -35040,6 +35135,52 @@ function PrimeStyleTryonInner({
|
|
|
35040
35135
|
if (pollingRef.current) clearInterval(pollingRef.current);
|
|
35041
35136
|
};
|
|
35042
35137
|
}, [apiUrl]);
|
|
35138
|
+
const reportSdkEvent = reactExports.useCallback((eventType, input = {}) => {
|
|
35139
|
+
if (shouldUseShopifyCartAttribution(apiUrl)) return;
|
|
35140
|
+
const client = apiRef.current;
|
|
35141
|
+
if (!client) return;
|
|
35142
|
+
void client.reportEvent({
|
|
35143
|
+
eventType,
|
|
35144
|
+
productId: effectiveProductId,
|
|
35145
|
+
productTitle: restoredProductTitle || productTitle,
|
|
35146
|
+
productUrl: restoredProductUrl || effectiveProductUrl,
|
|
35147
|
+
jobId: input.jobId ?? currentTryOnJobIdRef.current ?? void 0,
|
|
35148
|
+
recommendedSize: input.recommendedSize ?? sizingResultRef.current?.recommendedSize,
|
|
35149
|
+
metadata: input.metadata
|
|
35150
|
+
}).catch(() => {
|
|
35151
|
+
});
|
|
35152
|
+
}, [apiUrl, effectiveProductId, effectiveProductUrl, productTitle, restoredProductTitle, restoredProductUrl]);
|
|
35153
|
+
const reportSdkClientError = reactExports.useCallback((input) => {
|
|
35154
|
+
if (shouldUseShopifyCartAttribution(apiUrl)) return;
|
|
35155
|
+
const client = apiRef.current;
|
|
35156
|
+
if (!client) return;
|
|
35157
|
+
void client.reportClientError({
|
|
35158
|
+
...input,
|
|
35159
|
+
productId: effectiveProductId,
|
|
35160
|
+
productTitle: restoredProductTitle || productTitle,
|
|
35161
|
+
productUrl: restoredProductUrl || effectiveProductUrl,
|
|
35162
|
+
jobId: input.jobId ?? currentTryOnJobIdRef.current ?? void 0
|
|
35163
|
+
}).catch(() => {
|
|
35164
|
+
});
|
|
35165
|
+
}, [apiUrl, effectiveProductId, effectiveProductUrl, productTitle, restoredProductTitle, restoredProductUrl]);
|
|
35166
|
+
const productViewLoggedRef = reactExports.useRef(null);
|
|
35167
|
+
reactExports.useEffect(() => {
|
|
35168
|
+
const key = `${effectiveProductId || ""}|${effectiveProductUrl || ""}`;
|
|
35169
|
+
if (!key.trim() || productViewLoggedRef.current === key) return;
|
|
35170
|
+
productViewLoggedRef.current = key;
|
|
35171
|
+
if (shouldUseShopifyCartAttribution(apiUrl)) {
|
|
35172
|
+
logProductView({ productId: effectiveProductId, productTitle });
|
|
35173
|
+
return;
|
|
35174
|
+
}
|
|
35175
|
+
reportSdkEvent("PRODUCT_VIEW", {
|
|
35176
|
+
metadata: {
|
|
35177
|
+
productUrl: effectiveProductUrl,
|
|
35178
|
+
productFitType: resolvedProductFitType,
|
|
35179
|
+
productCategory,
|
|
35180
|
+
productSubcategory
|
|
35181
|
+
}
|
|
35182
|
+
});
|
|
35183
|
+
}, [apiUrl, effectiveProductId, effectiveProductUrl, productCategory, productSubcategory, productTitle, reportSdkEvent, resolvedProductFitType]);
|
|
35043
35184
|
const pickFireCountRef = reactExports.useRef(0);
|
|
35044
35185
|
const toBackendFetchableImageUrl = reactExports.useCallback((url) => {
|
|
35045
35186
|
const trimmed = String(url || "").trim();
|
|
@@ -35580,10 +35721,11 @@ function PrimeStyleTryonInner({
|
|
|
35580
35721
|
});
|
|
35581
35722
|
const handleOpen = reactExports.useCallback(() => {
|
|
35582
35723
|
console.log("[ps-sdk] handleOpen fired — opening modal");
|
|
35724
|
+
reportSdkEvent("SDK_OPENED", { metadata: { view: "body-profile" } });
|
|
35583
35725
|
setBodyProfileInitialStep(null);
|
|
35584
35726
|
setView("body-profile");
|
|
35585
35727
|
onOpen?.();
|
|
35586
|
-
}, [onOpen]);
|
|
35728
|
+
}, [onOpen, reportSdkEvent]);
|
|
35587
35729
|
const handleClose = reactExports.useCallback(() => {
|
|
35588
35730
|
const tryOnInFlight = tryOnProcessing;
|
|
35589
35731
|
setView("idle");
|
|
@@ -35673,12 +35815,28 @@ function PrimeStyleTryonInner({
|
|
|
35673
35815
|
if (!isValidImageFile(file)) {
|
|
35674
35816
|
setErrorMessage(t2("Please upload a JPEG, PNG, or WebP image."));
|
|
35675
35817
|
setView("error");
|
|
35818
|
+
reportSdkClientError({
|
|
35819
|
+
message: "Invalid image file type",
|
|
35820
|
+
code: "INVALID_FILE",
|
|
35821
|
+
component: "PhotoUpload",
|
|
35822
|
+
view,
|
|
35823
|
+
severity: "low",
|
|
35824
|
+
metadata: { fileType: file.type, fileSize: file.size }
|
|
35825
|
+
});
|
|
35676
35826
|
onError?.({ message: "Invalid file type", code: "INVALID_FILE" });
|
|
35677
35827
|
return;
|
|
35678
35828
|
}
|
|
35679
35829
|
if (file.size > 10 * 1024 * 1024) {
|
|
35680
35830
|
setErrorMessage(t2("Image must be under 10MB."));
|
|
35681
35831
|
setView("error");
|
|
35832
|
+
reportSdkClientError({
|
|
35833
|
+
message: "Image file too large",
|
|
35834
|
+
code: "FILE_TOO_LARGE",
|
|
35835
|
+
component: "PhotoUpload",
|
|
35836
|
+
view,
|
|
35837
|
+
severity: "low",
|
|
35838
|
+
metadata: { fileType: file.type, fileSize: file.size }
|
|
35839
|
+
});
|
|
35682
35840
|
onError?.({ message: "File too large", code: "FILE_TOO_LARGE" });
|
|
35683
35841
|
return;
|
|
35684
35842
|
}
|
|
@@ -35687,13 +35845,23 @@ function PrimeStyleTryonInner({
|
|
|
35687
35845
|
modelImageIdRef.current = null;
|
|
35688
35846
|
const objUrl = URL.createObjectURL(file);
|
|
35689
35847
|
setPreviewUrl(objUrl);
|
|
35848
|
+
reportSdkEvent("PHOTO_UPLOADED", {
|
|
35849
|
+
metadata: { fileType: file.type, fileSize: file.size, view }
|
|
35850
|
+
});
|
|
35690
35851
|
onUpload?.(file);
|
|
35691
35852
|
modelPoseRef.current = null;
|
|
35692
35853
|
detectMeasurementLines(objUrl).then((lines) => {
|
|
35693
35854
|
modelPoseRef.current = lines;
|
|
35694
|
-
}).catch(() => {
|
|
35855
|
+
}).catch((error) => {
|
|
35856
|
+
reportSdkClientError({
|
|
35857
|
+
message: error instanceof Error ? error.message : "Pose detection failed",
|
|
35858
|
+
code: "POSE_DETECTION_FAILED",
|
|
35859
|
+
component: "MediaPipe",
|
|
35860
|
+
view,
|
|
35861
|
+
severity: "low"
|
|
35862
|
+
});
|
|
35695
35863
|
});
|
|
35696
|
-
}, [onUpload, onError]);
|
|
35864
|
+
}, [onUpload, onError, reportSdkClientError, reportSdkEvent, t2, view]);
|
|
35697
35865
|
const handleRemovePreview = reactExports.useCallback(() => {
|
|
35698
35866
|
setSelectedFile(null);
|
|
35699
35867
|
if (previewUrl) URL.revokeObjectURL(previewUrl);
|
|
@@ -35762,12 +35930,21 @@ function PrimeStyleTryonInner({
|
|
|
35762
35930
|
setTryOnProcessing(false);
|
|
35763
35931
|
setTryOnStartedAt(null);
|
|
35764
35932
|
const msg = update.error || t2("Try-on generation failed");
|
|
35933
|
+
reportSdkClientError({
|
|
35934
|
+
message: msg,
|
|
35935
|
+
code: "TRYON_GENERATION_FAILED",
|
|
35936
|
+
component: "TryOn",
|
|
35937
|
+
view,
|
|
35938
|
+
severity: "medium",
|
|
35939
|
+
jobId: update.galleryId,
|
|
35940
|
+
metadata: { status: update.status }
|
|
35941
|
+
});
|
|
35765
35942
|
setErrorMessage(msg);
|
|
35766
35943
|
setView("error");
|
|
35767
35944
|
onError?.({ message: msg });
|
|
35768
35945
|
}
|
|
35769
35946
|
}
|
|
35770
|
-
}, [apiUrl, effectiveProductId, productTitle, onComplete, onError, cleanupJob]);
|
|
35947
|
+
}, [apiUrl, effectiveProductId, productTitle, onComplete, onError, cleanupJob, reportSdkClientError, t2, view]);
|
|
35771
35948
|
const dynamicFields = reactExports.useMemo(() => {
|
|
35772
35949
|
if (sizeGuide?.found && sizeGuide.requiredFields && sizeGuide.requiredFields.length > 0) {
|
|
35773
35950
|
return sizeGuide.requiredFields;
|
|
@@ -35781,6 +35958,14 @@ function PrimeStyleTryonInner({
|
|
|
35781
35958
|
const method = methodOverride || sizingMethod;
|
|
35782
35959
|
const baseUrl = getApiUrl(apiUrl);
|
|
35783
35960
|
const key = getApiKey();
|
|
35961
|
+
reportSdkEvent("SIZING_STARTED", {
|
|
35962
|
+
metadata: {
|
|
35963
|
+
method,
|
|
35964
|
+
measurementType,
|
|
35965
|
+
productFitType: resolvedProductFitType,
|
|
35966
|
+
hasSizeGuide: !!sizeGuide?.found
|
|
35967
|
+
}
|
|
35968
|
+
});
|
|
35784
35969
|
if (measurementType === "face" || measurementType === "head") {
|
|
35785
35970
|
const f2 = formRef.current;
|
|
35786
35971
|
const toNum = (v2) => {
|
|
@@ -35839,16 +36024,42 @@ function PrimeStyleTryonInner({
|
|
|
35839
36024
|
const data = await resp.json();
|
|
35840
36025
|
await minVisible;
|
|
35841
36026
|
if (data?.found === false) {
|
|
36027
|
+
reportSdkEvent("SIZING_FAILED", {
|
|
36028
|
+
metadata: {
|
|
36029
|
+
reason: data?.reasoning || "NO_MATCH",
|
|
36030
|
+
measurementType,
|
|
36031
|
+
found: false
|
|
36032
|
+
}
|
|
36033
|
+
});
|
|
35842
36034
|
setNoSizeReason(data?.reasoning === "NO_SIZE_CHART" ? "no-chart" : "no-match");
|
|
35843
36035
|
setView("no-chart");
|
|
35844
36036
|
setEstimationDone(true);
|
|
35845
36037
|
return;
|
|
35846
36038
|
}
|
|
35847
36039
|
setSizingResult(data);
|
|
36040
|
+
reportSdkEvent("SIZE_RECOMMENDATION_SHOWN", {
|
|
36041
|
+
recommendedSize: data?.recommendedSize,
|
|
36042
|
+
metadata: {
|
|
36043
|
+
confidence: data?.confidence,
|
|
36044
|
+
measurementType,
|
|
36045
|
+
source: "face-recommend"
|
|
36046
|
+
}
|
|
36047
|
+
});
|
|
35848
36048
|
onComplete?.(data);
|
|
35849
36049
|
} else {
|
|
35850
36050
|
const body = await resp.text().catch(() => "");
|
|
35851
36051
|
console.error("[PS-SDK] face-recommend failed:", resp.status, body);
|
|
36052
|
+
reportSdkEvent("SIZING_FAILED", {
|
|
36053
|
+
metadata: { status: resp.status, measurementType, source: "face-recommend" }
|
|
36054
|
+
});
|
|
36055
|
+
reportSdkClientError({
|
|
36056
|
+
message: body || "Face/head sizing request failed",
|
|
36057
|
+
code: "FACE_RECOMMEND_FAILED",
|
|
36058
|
+
component: "Sizing",
|
|
36059
|
+
view,
|
|
36060
|
+
severity: "medium",
|
|
36061
|
+
metadata: { status: resp.status, measurementType }
|
|
36062
|
+
});
|
|
35852
36063
|
await minVisible;
|
|
35853
36064
|
setErrorMessage(t2("Unable to get a size suggestion. Please try again."));
|
|
35854
36065
|
setView("error");
|
|
@@ -35856,6 +36067,18 @@ function PrimeStyleTryonInner({
|
|
|
35856
36067
|
}
|
|
35857
36068
|
} catch (err) {
|
|
35858
36069
|
console.error("[PS-SDK] face-recommend network error:", err);
|
|
36070
|
+
reportSdkEvent("SIZING_FAILED", {
|
|
36071
|
+
metadata: { measurementType, source: "face-recommend", network: true }
|
|
36072
|
+
});
|
|
36073
|
+
reportSdkClientError({
|
|
36074
|
+
message: err instanceof Error ? err.message : "Face/head sizing network error",
|
|
36075
|
+
code: "FACE_RECOMMEND_NETWORK_ERROR",
|
|
36076
|
+
stack: err instanceof Error ? err.stack : void 0,
|
|
36077
|
+
component: "Sizing",
|
|
36078
|
+
view,
|
|
36079
|
+
severity: "medium",
|
|
36080
|
+
metadata: { measurementType }
|
|
36081
|
+
});
|
|
35859
36082
|
await minVisible;
|
|
35860
36083
|
setErrorMessage(t2("Unable to connect to sizing service. Please try again."));
|
|
35861
36084
|
setView("error");
|
|
@@ -35916,6 +36139,17 @@ function PrimeStyleTryonInner({
|
|
|
35916
36139
|
const qWeight = parseFloat(formRef.current.weight || "0");
|
|
35917
36140
|
if (!qHeight || !qWeight) {
|
|
35918
36141
|
console.error("[PS-SDK] submitSizing ABORT — qHeight:", qHeight, "qWeight:", qWeight, "formRef:", JSON.stringify(formRef.current));
|
|
36142
|
+
reportSdkEvent("SIZING_FAILED", {
|
|
36143
|
+
metadata: { reason: "missing_height_or_weight", method, measurementType }
|
|
36144
|
+
});
|
|
36145
|
+
reportSdkClientError({
|
|
36146
|
+
message: "Sizing submitted without height or weight",
|
|
36147
|
+
code: "SIZING_INPUT_MISSING",
|
|
36148
|
+
component: "Sizing",
|
|
36149
|
+
view,
|
|
36150
|
+
severity: "low",
|
|
36151
|
+
metadata: { method, measurementType, qHeight, qWeight }
|
|
36152
|
+
});
|
|
35919
36153
|
setSizingLoading(false);
|
|
35920
36154
|
return;
|
|
35921
36155
|
}
|
|
@@ -35948,12 +36182,29 @@ function PrimeStyleTryonInner({
|
|
|
35948
36182
|
const data = await res.json();
|
|
35949
36183
|
console.log("[PS-SDK] Sizing recommend RESULT:", JSON.stringify(data));
|
|
35950
36184
|
if (data?.found === false) {
|
|
36185
|
+
reportSdkEvent("SIZING_FAILED", {
|
|
36186
|
+
metadata: {
|
|
36187
|
+
reason: data?.reasoning || "NO_MATCH",
|
|
36188
|
+
method,
|
|
36189
|
+
measurementType,
|
|
36190
|
+
found: false
|
|
36191
|
+
}
|
|
36192
|
+
});
|
|
35951
36193
|
setNoSizeReason(data?.reasoning === "NO_SIZE_CHART" ? "no-chart" : "no-match");
|
|
35952
36194
|
setView("no-chart");
|
|
35953
36195
|
setEstimationDone(true);
|
|
35954
36196
|
return;
|
|
35955
36197
|
}
|
|
35956
36198
|
setSizingResult(data);
|
|
36199
|
+
reportSdkEvent("SIZE_RECOMMENDATION_SHOWN", {
|
|
36200
|
+
recommendedSize: data?.recommendedSize,
|
|
36201
|
+
metadata: {
|
|
36202
|
+
confidence: data?.confidence,
|
|
36203
|
+
method,
|
|
36204
|
+
measurementType,
|
|
36205
|
+
found: data?.found
|
|
36206
|
+
}
|
|
36207
|
+
});
|
|
35957
36208
|
onComplete?.(data);
|
|
35958
36209
|
const m2 = payload.measurements || {};
|
|
35959
36210
|
const qe2 = payload.quickEstimate || {};
|
|
@@ -35981,26 +36232,49 @@ function PrimeStyleTryonInner({
|
|
|
35981
36232
|
} else {
|
|
35982
36233
|
const errBody = await res.text().catch(() => "");
|
|
35983
36234
|
console.error("[PS-SDK] Sizing recommend failed:", res.status, errBody);
|
|
36235
|
+
reportSdkEvent("SIZING_FAILED", {
|
|
36236
|
+
metadata: { status: res.status, method, measurementType, source: "sizing-recommend" }
|
|
36237
|
+
});
|
|
36238
|
+
reportSdkClientError({
|
|
36239
|
+
message: errBody || "Sizing request failed",
|
|
36240
|
+
code: "SIZING_RECOMMEND_FAILED",
|
|
36241
|
+
component: "Sizing",
|
|
36242
|
+
view,
|
|
36243
|
+
severity: "medium",
|
|
36244
|
+
metadata: { status: res.status, method, measurementType }
|
|
36245
|
+
});
|
|
35984
36246
|
setErrorMessage(t2("Unable to get a size suggestion. Please try again."));
|
|
35985
36247
|
setView("error");
|
|
35986
36248
|
setEstimationDone(true);
|
|
35987
36249
|
}
|
|
35988
36250
|
} catch (err) {
|
|
35989
36251
|
console.error("[PS-SDK] Sizing recommend network error:", err);
|
|
36252
|
+
reportSdkEvent("SIZING_FAILED", {
|
|
36253
|
+
metadata: { method, measurementType, source: "sizing-recommend", network: true }
|
|
36254
|
+
});
|
|
36255
|
+
reportSdkClientError({
|
|
36256
|
+
message: err instanceof Error ? err.message : "Sizing network error",
|
|
36257
|
+
code: "SIZING_RECOMMEND_NETWORK_ERROR",
|
|
36258
|
+
stack: err instanceof Error ? err.stack : void 0,
|
|
36259
|
+
component: "Sizing",
|
|
36260
|
+
view,
|
|
36261
|
+
severity: "medium",
|
|
36262
|
+
metadata: { method, measurementType }
|
|
36263
|
+
});
|
|
35990
36264
|
setErrorMessage(t2("Unable to connect to sizing service. Please try again."));
|
|
35991
36265
|
setView("error");
|
|
35992
36266
|
setEstimationDone(true);
|
|
35993
36267
|
} finally {
|
|
35994
36268
|
setSizingLoading(false);
|
|
35995
36269
|
}
|
|
35996
|
-
}, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productContext, measurementType, dynamicFields, persistResultToProfile]);
|
|
36270
|
+
}, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productContext, measurementType, resolvedProductFitType, dynamicFields, persistResultToProfile, reportSdkClientError, reportSdkEvent, t2, view]);
|
|
35997
36271
|
const handleQuickEstimate = reactExports.useCallback(async (height, weight, heightUnit2, weightUnit2, gender, age, bodyType, chestProfile, midsectionProfile, hipProfile, bodyImage) => {
|
|
35998
36272
|
if (!apiRef.current) {
|
|
35999
36273
|
const msg = t2("SDK not configured. Please refresh and try again.");
|
|
36000
36274
|
console.warn("[ps-sdk] handleQuickEstimate BAILED — apiRef is null. API key not loaded.");
|
|
36001
36275
|
setErrorMessage(msg);
|
|
36002
36276
|
setView("error");
|
|
36003
|
-
onError?.({ message: msg, code: "SDK_NOT_CONFIGURED" });
|
|
36277
|
+
onError?.({ message: msg, code: !apiRef.current ? "SDK_NOT_CONFIGURED" : "PHOTO_MISSING" });
|
|
36004
36278
|
return;
|
|
36005
36279
|
}
|
|
36006
36280
|
getApiUrl(apiUrl);
|
|
@@ -36379,6 +36653,13 @@ function PrimeStyleTryonInner({
|
|
|
36379
36653
|
const msg = !apiRef.current ? t2("SDK not configured. Please provide an API key.") : t2("Please upload a photo first.");
|
|
36380
36654
|
setErrorMessage(msg);
|
|
36381
36655
|
setView("error");
|
|
36656
|
+
reportSdkClientError({
|
|
36657
|
+
message: msg,
|
|
36658
|
+
code: !apiRef.current ? "SDK_NOT_CONFIGURED" : "PHOTO_MISSING",
|
|
36659
|
+
component: "TryOn",
|
|
36660
|
+
view,
|
|
36661
|
+
severity: !apiRef.current ? "high" : "low"
|
|
36662
|
+
});
|
|
36382
36663
|
onError?.({ message: msg, code: "SDK_NOT_CONFIGURED" });
|
|
36383
36664
|
return;
|
|
36384
36665
|
}
|
|
@@ -36536,9 +36817,9 @@ function PrimeStyleTryonInner({
|
|
|
36536
36817
|
if (response.modelImageId) modelImageIdRef.current = response.modelImageId;
|
|
36537
36818
|
onProcessing?.(response.jobId);
|
|
36538
36819
|
const usePollingOnly = shouldUseShopifyCartAttribution(apiUrl);
|
|
36539
|
-
if (!usePollingOnly
|
|
36820
|
+
if (!usePollingOnly) {
|
|
36540
36821
|
sseRef.current?.disconnect();
|
|
36541
|
-
sseRef.current = new SseClient(response.streamUrl);
|
|
36822
|
+
sseRef.current = new SseClient(response.streamUrl || apiRef.current.getStreamUrl(response.jobId));
|
|
36542
36823
|
}
|
|
36543
36824
|
unsubRef.current?.();
|
|
36544
36825
|
unsubRef.current = usePollingOnly ? null : sseRef.current?.onJob(response.jobId, handleVtoUpdate) ?? null;
|
|
@@ -36566,11 +36847,19 @@ function PrimeStyleTryonInner({
|
|
|
36566
36847
|
} catch (err) {
|
|
36567
36848
|
const message = err instanceof Error ? err.message : t2("Failed to start try-on");
|
|
36568
36849
|
const code = err instanceof PrimeStyleError ? err.code : void 0;
|
|
36850
|
+
reportSdkClientError({
|
|
36851
|
+
message,
|
|
36852
|
+
code: code || "TRYON_SUBMIT_FAILED",
|
|
36853
|
+
stack: err instanceof Error ? err.stack : void 0,
|
|
36854
|
+
component: "TryOn",
|
|
36855
|
+
view,
|
|
36856
|
+
severity: "medium"
|
|
36857
|
+
});
|
|
36569
36858
|
setErrorMessage(message);
|
|
36570
36859
|
setView("error");
|
|
36571
36860
|
onError?.({ message, code });
|
|
36572
36861
|
}
|
|
36573
|
-
}, [selectedFile, productImage, effectiveProductImages, garmentReferenceImage, garmentDetailImage, productTitle, productCategory, productSubcategory, resolvedProductFitType, productType, productTagsList, productDescription, productMaterial, measurementType, sizingResult, sizeGuide, apiUrl, onProcessing, onError, handleVtoUpdate]);
|
|
36862
|
+
}, [selectedFile, productImage, effectiveProductImages, garmentReferenceImage, garmentDetailImage, productTitle, productCategory, productSubcategory, resolvedProductFitType, productType, productTagsList, productDescription, productMaterial, measurementType, sizingResult, sizeGuide, apiUrl, onProcessing, onError, handleVtoUpdate, reportSdkClientError, t2, view]);
|
|
36574
36863
|
reactExports.useEffect(() => {
|
|
36575
36864
|
if (view !== "size-result") {
|
|
36576
36865
|
autoTryOnFiredRef.current = false;
|
|
@@ -36662,7 +36951,7 @@ function PrimeStyleTryonInner({
|
|
|
36662
36951
|
}, [sizingResult]);
|
|
36663
36952
|
const handleAddToBag = reactExports.useCallback(async () => {
|
|
36664
36953
|
if (!onAddToBag || !sizingResult) return;
|
|
36665
|
-
|
|
36954
|
+
const payload = {
|
|
36666
36955
|
productId,
|
|
36667
36956
|
productTitle: restoredProductTitle || productTitle,
|
|
36668
36957
|
productUrl: restoredProductUrl || effectiveProductUrl,
|
|
@@ -36671,7 +36960,33 @@ function PrimeStyleTryonInner({
|
|
|
36671
36960
|
resultImageUrl: resultImageUrlRef.current || resultImageUrl,
|
|
36672
36961
|
historyEntryId: currentHistoryEntryIdRef.current ?? void 0,
|
|
36673
36962
|
selectedSizes: buildAddToBagSelectedSizes()
|
|
36674
|
-
}
|
|
36963
|
+
};
|
|
36964
|
+
try {
|
|
36965
|
+
await onAddToBag(payload);
|
|
36966
|
+
reportSdkEvent("SIZE_RECOMMENDATION_ACCEPTED", {
|
|
36967
|
+
recommendedSize: sizingResult.recommendedSize,
|
|
36968
|
+
metadata: { selectedSizes: payload.selectedSizes }
|
|
36969
|
+
});
|
|
36970
|
+
reportSdkEvent("ADD_TO_CART_FROM_TRYON", {
|
|
36971
|
+
recommendedSize: sizingResult.recommendedSize,
|
|
36972
|
+
metadata: {
|
|
36973
|
+
selectedSizes: payload.selectedSizes,
|
|
36974
|
+
historyEntryId: payload.historyEntryId,
|
|
36975
|
+
hasResult: Boolean(payload.resultImageUrl)
|
|
36976
|
+
}
|
|
36977
|
+
});
|
|
36978
|
+
} catch (error) {
|
|
36979
|
+
reportSdkClientError({
|
|
36980
|
+
message: error instanceof Error ? error.message : "Add to bag failed",
|
|
36981
|
+
code: "ADD_TO_BAG_FAILED",
|
|
36982
|
+
stack: error instanceof Error ? error.stack : void 0,
|
|
36983
|
+
component: "ResultActions",
|
|
36984
|
+
view,
|
|
36985
|
+
severity: "medium",
|
|
36986
|
+
metadata: { selectedSizes: payload.selectedSizes }
|
|
36987
|
+
});
|
|
36988
|
+
throw error;
|
|
36989
|
+
}
|
|
36675
36990
|
}, [
|
|
36676
36991
|
buildAddToBagSelectedSizes,
|
|
36677
36992
|
effectiveProductUrl,
|
|
@@ -36681,7 +36996,10 @@ function PrimeStyleTryonInner({
|
|
|
36681
36996
|
restoredProductTitle,
|
|
36682
36997
|
restoredProductUrl,
|
|
36683
36998
|
resultImageUrl,
|
|
36684
|
-
|
|
36999
|
+
reportSdkClientError,
|
|
37000
|
+
reportSdkEvent,
|
|
37001
|
+
sizingResult,
|
|
37002
|
+
view
|
|
36685
37003
|
]);
|
|
36686
37004
|
const handleTryOnFeedbackSubmit = reactExports.useCallback(async ({ rating, note }) => {
|
|
36687
37005
|
const profileLoggedIn = Boolean(profileSession);
|
|
@@ -37891,8 +38209,20 @@ class PrimeStyleTryonErrorBoundary extends reactExports.Component {
|
|
|
37891
38209
|
}
|
|
37892
38210
|
componentDidCatch(error) {
|
|
37893
38211
|
console.error("[ps-sdk] PrimeStyleTryon render failed:", error);
|
|
38212
|
+
const message = error instanceof Error ? error.message : "PrimeStyleTryon render failed";
|
|
38213
|
+
void new ApiClient(getApiKey(), getApiUrl(this.props.apiUrl)).reportClientError({
|
|
38214
|
+
message,
|
|
38215
|
+
code: "RENDER_ERROR",
|
|
38216
|
+
stack: error instanceof Error ? error.stack : void 0,
|
|
38217
|
+
component: "PrimeStyleTryon",
|
|
38218
|
+
productId: this.props.productId || this.props.productImage,
|
|
38219
|
+
productTitle: this.props.productTitle,
|
|
38220
|
+
productUrl: this.props.productUrl,
|
|
38221
|
+
severity: "high"
|
|
38222
|
+
}).catch(() => {
|
|
38223
|
+
});
|
|
37894
38224
|
this.props.onError?.({
|
|
37895
|
-
message
|
|
38225
|
+
message,
|
|
37896
38226
|
code: "RENDER_ERROR"
|
|
37897
38227
|
});
|
|
37898
38228
|
}
|