@primestyleai/tryon 5.9.0 → 5.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/react/components/ConfirmMeasurementsModal.d.ts +22 -0
- package/dist/react/index.js +350 -55
- package/dist/react/recommendForProduct.d.ts +4 -0
- package/dist/react/styles.d.ts +1 -1
- package/dist/react/utils/units.d.ts +6 -0
- package/dist/react/views/MobileScanningView.d.ts +4 -1
- package/dist/storefront/primestyle-tryon.js +350 -55
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
package/dist/react/index.js
CHANGED
|
@@ -655,7 +655,8 @@ async function recommendForProduct(input) {
|
|
|
655
655
|
sections: sectionsMap,
|
|
656
656
|
profileId: profile.id,
|
|
657
657
|
fromCache: false,
|
|
658
|
-
raw: result
|
|
658
|
+
raw: result,
|
|
659
|
+
found: result.found
|
|
659
660
|
};
|
|
660
661
|
}
|
|
661
662
|
async function estimateFullMeasurements(args) {
|
|
@@ -714,6 +715,12 @@ async function estimateFullMeasurements(args) {
|
|
|
714
715
|
function isImperial(locale) {
|
|
715
716
|
return ["US", "UK", "AU"].includes(locale);
|
|
716
717
|
}
|
|
718
|
+
function getUnitLabel(unit) {
|
|
719
|
+
if (unit === "in" || unit === "inches" || unit === "lbs") return "Imperial";
|
|
720
|
+
if (unit === "cm" || unit === "kg") return "Metric";
|
|
721
|
+
if (unit === "mm") return "mm";
|
|
722
|
+
return "";
|
|
723
|
+
}
|
|
717
724
|
function cx(base, override) {
|
|
718
725
|
return override ? `${base} ${override}` : base;
|
|
719
726
|
}
|
|
@@ -1488,12 +1495,22 @@ const STYLES = `
|
|
|
1488
1495
|
}
|
|
1489
1496
|
.ps-tryon-v2-processing-label {
|
|
1490
1497
|
position: absolute; bottom: 1vw; left: 50%; transform: translateX(-50%);
|
|
1491
|
-
z-index: 5; font-size: 0.
|
|
1492
|
-
color:
|
|
1493
|
-
background: rgba(0,0,0,0.
|
|
1494
|
-
padding: 0.
|
|
1498
|
+
z-index: 5; font-size: 0.7vw; font-weight: 600;
|
|
1499
|
+
color: #fff; letter-spacing: 0.05em;
|
|
1500
|
+
background: rgba(0,0,0,0.72); backdrop-filter: blur(10px);
|
|
1501
|
+
padding: 0.6vw 0.9vw; border-radius: 0.6vw;
|
|
1502
|
+
display: flex; flex-direction: column; align-items: center; gap: 0.5vw;
|
|
1503
|
+
min-width: 14vw;
|
|
1504
|
+
box-shadow: 0 0.4vw 1.5vw rgba(0,0,0,0.35);
|
|
1505
|
+
}
|
|
1506
|
+
.ps-tryon-v2-processing-label > span:first-child {
|
|
1495
1507
|
animation: ps-loading-pulse 2s ease-in-out infinite;
|
|
1496
1508
|
}
|
|
1509
|
+
.ps-tryon-v2-processing-label .ps-tryon-progress-ring-track { stroke: rgba(255,255,255,0.18); }
|
|
1510
|
+
.ps-tryon-v2-processing-label .ps-tryon-progress-ring-fill { stroke: var(--ps-accent-light); }
|
|
1511
|
+
.ps-tryon-v2-processing-label .ps-tryon-progress-eta { color: #fff; }
|
|
1512
|
+
.ps-tryon-v2-processing-label .ps-tryon-progress-bar-wrap { background: rgba(255,255,255,0.18); }
|
|
1513
|
+
.ps-tryon-v2-processing-label .ps-tryon-progress-pct { color: var(--ps-accent-light); }
|
|
1497
1514
|
|
|
1498
1515
|
/* "I don't know" link */
|
|
1499
1516
|
.ps-tryon-v2-dontknow {
|
|
@@ -2086,6 +2103,26 @@ const STYLES = `
|
|
|
2086
2103
|
.ps-tryon-progress-section {
|
|
2087
2104
|
display: flex; align-items: center; gap: 0.63vw; width: 100%; max-width: 18vw; margin-bottom: 0.83vw;
|
|
2088
2105
|
}
|
|
2106
|
+
/* Shared progress layout used inside StageCycler (desktop) and
|
|
2107
|
+
MobileScanningView — row of ring + bar + percent, same tokens. */
|
|
2108
|
+
.ps-tryon-progress-wrap {
|
|
2109
|
+
display: flex; align-items: center; gap: 12px;
|
|
2110
|
+
width: 100%; max-width: 360px; margin-top: 18px;
|
|
2111
|
+
}
|
|
2112
|
+
.ps-tryon-progress-wrap .ps-tryon-progress-bar-wrap {
|
|
2113
|
+
flex: 1; height: 6px; border-radius: 4px; overflow: hidden;
|
|
2114
|
+
position: relative; background: var(--ps-border-color);
|
|
2115
|
+
}
|
|
2116
|
+
.ps-tryon-progress-wrap .ps-tryon-progress-bar-fill {
|
|
2117
|
+
height: 100%; width: 0%;
|
|
2118
|
+
background: linear-gradient(90deg, var(--ps-accent), var(--ps-accent-light));
|
|
2119
|
+
border-radius: 4px; transition: width 0.3s ease;
|
|
2120
|
+
}
|
|
2121
|
+
.ps-tryon-progress-wrap .ps-tryon-progress-pct {
|
|
2122
|
+
font-size: 13px; font-weight: 700; color: var(--ps-accent);
|
|
2123
|
+
min-width: 36px; text-align: right;
|
|
2124
|
+
font-variant-numeric: tabular-nums;
|
|
2125
|
+
}
|
|
2089
2126
|
.ps-tryon-progress-bar-wrap {
|
|
2090
2127
|
flex: 1; height: 0.31vw; background: var(--ps-border-color); border-radius: 3px; overflow: hidden;
|
|
2091
2128
|
position: relative;
|
|
@@ -2111,25 +2148,25 @@ const STYLES = `
|
|
|
2111
2148
|
font-variant-numeric: tabular-nums;
|
|
2112
2149
|
}
|
|
2113
2150
|
|
|
2114
|
-
/* Circular ETA ring —
|
|
2151
|
+
/* Circular ETA ring — 64×64 px SVG with a track + progress circle; ETA
|
|
2115
2152
|
text centered. strokeDashoffset is driven by the ticker in
|
|
2116
2153
|
PrimeStyleTryonInner, so CSS only styles the appearance. */
|
|
2117
2154
|
.ps-tryon-progress-ring {
|
|
2118
|
-
position: relative; width:
|
|
2155
|
+
position: relative; width: 64px; height: 64px; flex: 0 0 64px;
|
|
2119
2156
|
display: flex; align-items: center; justify-content: center;
|
|
2120
2157
|
}
|
|
2121
2158
|
.ps-tryon-progress-ring svg { transform: rotate(-90deg); }
|
|
2122
2159
|
.ps-tryon-progress-ring-track {
|
|
2123
|
-
fill: none; stroke: var(--ps-border-color); stroke-width:
|
|
2160
|
+
fill: none; stroke: var(--ps-border-color); stroke-width: 5;
|
|
2124
2161
|
}
|
|
2125
2162
|
.ps-tryon-progress-ring-fill {
|
|
2126
|
-
fill: none; stroke: var(--ps-accent); stroke-width:
|
|
2163
|
+
fill: none; stroke: var(--ps-accent); stroke-width: 5;
|
|
2127
2164
|
stroke-linecap: round;
|
|
2128
2165
|
transition: stroke-dashoffset 0.3s ease;
|
|
2129
2166
|
}
|
|
2130
2167
|
.ps-tryon-progress-eta {
|
|
2131
2168
|
position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
|
|
2132
|
-
font-size:
|
|
2169
|
+
font-size: 13px; font-weight: 700; color: var(--ps-accent);
|
|
2133
2170
|
font-variant-numeric: tabular-nums; letter-spacing: 0.01em;
|
|
2134
2171
|
pointer-events: none;
|
|
2135
2172
|
}
|
|
@@ -7216,6 +7253,92 @@ function ProfileDetailModal({
|
|
|
7216
7253
|
document.body
|
|
7217
7254
|
);
|
|
7218
7255
|
}
|
|
7256
|
+
function ConfirmMeasurementsModal({
|
|
7257
|
+
profile,
|
|
7258
|
+
onProceed,
|
|
7259
|
+
onEdit,
|
|
7260
|
+
t
|
|
7261
|
+
}) {
|
|
7262
|
+
const heightUnit = profile.heightUnit === "in" || profile.heightUnit === "ft" ? "in" : "cm";
|
|
7263
|
+
const weightUnit = profile.weightUnit === "lbs" ? "lbs" : "kg";
|
|
7264
|
+
const systemLabel = getUnitLabel(heightUnit);
|
|
7265
|
+
const formatHeight = (h) => {
|
|
7266
|
+
if (!h) return "—";
|
|
7267
|
+
if (heightUnit === "in") {
|
|
7268
|
+
const ft = Math.floor(h / 12);
|
|
7269
|
+
const inches = Math.round(h % 12);
|
|
7270
|
+
return `${ft}'${inches}"`;
|
|
7271
|
+
}
|
|
7272
|
+
return `${Math.round(h)} cm`;
|
|
7273
|
+
};
|
|
7274
|
+
const formatWeight = (w) => {
|
|
7275
|
+
if (!w) return "—";
|
|
7276
|
+
return `${Math.round(w)} ${weightUnit}`;
|
|
7277
|
+
};
|
|
7278
|
+
const height = profile.height ?? profile.heightCm;
|
|
7279
|
+
const weight = profile.weight ?? profile.weightKg;
|
|
7280
|
+
return /* @__PURE__ */ jsx("div", { className: "ps-confirm-overlay", onClick: onEdit, children: /* @__PURE__ */ jsxs("div", { className: "ps-confirm-modal", onClick: (e) => e.stopPropagation(), children: [
|
|
7281
|
+
/* @__PURE__ */ jsx(
|
|
7282
|
+
"button",
|
|
7283
|
+
{
|
|
7284
|
+
type: "button",
|
|
7285
|
+
"aria-label": t("Close"),
|
|
7286
|
+
onClick: onEdit,
|
|
7287
|
+
style: {
|
|
7288
|
+
position: "absolute",
|
|
7289
|
+
top: "0.75vw",
|
|
7290
|
+
right: "0.75vw",
|
|
7291
|
+
width: "1.8vw",
|
|
7292
|
+
height: "1.8vw",
|
|
7293
|
+
borderRadius: "50%",
|
|
7294
|
+
background: "transparent",
|
|
7295
|
+
border: "none",
|
|
7296
|
+
cursor: "pointer",
|
|
7297
|
+
display: "flex",
|
|
7298
|
+
alignItems: "center",
|
|
7299
|
+
justifyContent: "center",
|
|
7300
|
+
color: "var(--ps-text-muted)"
|
|
7301
|
+
},
|
|
7302
|
+
children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", width: "16", height: "16", children: [
|
|
7303
|
+
/* @__PURE__ */ jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
7304
|
+
/* @__PURE__ */ jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
7305
|
+
] })
|
|
7306
|
+
}
|
|
7307
|
+
),
|
|
7308
|
+
/* @__PURE__ */ jsx("p", { style: { fontWeight: 700, marginBottom: "0.4vw" }, children: t("Confirm your measurements") }),
|
|
7309
|
+
/* @__PURE__ */ jsx("small", { style: { color: "var(--ps-text-muted)" }, children: systemLabel ? t("You chose") + " " + systemLabel + ". " + t("Review before continuing.") : t("Review before continuing.") }),
|
|
7310
|
+
/* @__PURE__ */ jsxs("ul", { style: {
|
|
7311
|
+
listStyle: "none",
|
|
7312
|
+
padding: 0,
|
|
7313
|
+
margin: "0.8vw 0 0.2vw 0",
|
|
7314
|
+
width: "100%",
|
|
7315
|
+
textAlign: "left",
|
|
7316
|
+
fontSize: "0.78vw",
|
|
7317
|
+
lineHeight: 1.6
|
|
7318
|
+
}, children: [
|
|
7319
|
+
/* @__PURE__ */ jsxs("li", { style: { display: "flex", justifyContent: "space-between", gap: "1vw" }, children: [
|
|
7320
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--ps-text-muted)" }, children: t("Height") }),
|
|
7321
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 600 }, children: formatHeight(height) })
|
|
7322
|
+
] }),
|
|
7323
|
+
/* @__PURE__ */ jsxs("li", { style: { display: "flex", justifyContent: "space-between", gap: "1vw" }, children: [
|
|
7324
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--ps-text-muted)" }, children: t("Weight") }),
|
|
7325
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 600 }, children: formatWeight(weight) })
|
|
7326
|
+
] }),
|
|
7327
|
+
profile.age ? /* @__PURE__ */ jsxs("li", { style: { display: "flex", justifyContent: "space-between", gap: "1vw" }, children: [
|
|
7328
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--ps-text-muted)" }, children: t("Age") }),
|
|
7329
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 600 }, children: profile.age })
|
|
7330
|
+
] }) : null,
|
|
7331
|
+
/* @__PURE__ */ jsxs("li", { style: { display: "flex", justifyContent: "space-between", gap: "1vw" }, children: [
|
|
7332
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--ps-text-muted)" }, children: t("Gender") }),
|
|
7333
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 600 }, children: profile.gender === "female" ? t("Female") : t("Male") })
|
|
7334
|
+
] })
|
|
7335
|
+
] }),
|
|
7336
|
+
/* @__PURE__ */ jsxs("div", { className: "ps-confirm-actions", children: [
|
|
7337
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "ps-confirm-cancel", onClick: onEdit, children: t("Edit") }),
|
|
7338
|
+
/* @__PURE__ */ jsx("button", { type: "button", className: "ps-confirm-delete", onClick: onProceed, children: t("Proceed") })
|
|
7339
|
+
] })
|
|
7340
|
+
] }) });
|
|
7341
|
+
}
|
|
7219
7342
|
function WelcomeView({
|
|
7220
7343
|
productImage,
|
|
7221
7344
|
setView,
|
|
@@ -7451,17 +7574,71 @@ function MobileSkeleton({ landmarks, w, h }) {
|
|
|
7451
7574
|
}
|
|
7452
7575
|
);
|
|
7453
7576
|
}
|
|
7577
|
+
const MSC_TRYON_TARGET_SECONDS = 22;
|
|
7578
|
+
const MSC_RING_RADIUS = 27;
|
|
7579
|
+
const MSC_RING_CIRC = 2 * Math.PI * MSC_RING_RADIUS;
|
|
7580
|
+
function MscTryOnProgress({ t }) {
|
|
7581
|
+
const startRef = useRef(Date.now());
|
|
7582
|
+
const ringRef = useRef(null);
|
|
7583
|
+
const barRef = useRef(null);
|
|
7584
|
+
const etaRef = useRef(null);
|
|
7585
|
+
const pctRef = useRef(null);
|
|
7586
|
+
useEffect(() => {
|
|
7587
|
+
startRef.current = Date.now();
|
|
7588
|
+
const id = setInterval(() => {
|
|
7589
|
+
const elapsed = (Date.now() - startRef.current) / 1e3;
|
|
7590
|
+
const pct = Math.min(95, elapsed / MSC_TRYON_TARGET_SECONDS * 100);
|
|
7591
|
+
const val = Math.round(pct);
|
|
7592
|
+
if (barRef.current) barRef.current.style.width = `${val}%`;
|
|
7593
|
+
if (pctRef.current) pctRef.current.textContent = `${val}%`;
|
|
7594
|
+
if (ringRef.current) ringRef.current.style.strokeDashoffset = String(MSC_RING_CIRC * (1 - pct / 100));
|
|
7595
|
+
if (etaRef.current) {
|
|
7596
|
+
const remaining = Math.max(0, MSC_TRYON_TARGET_SECONDS - Math.floor(elapsed));
|
|
7597
|
+
etaRef.current.textContent = elapsed >= MSC_TRYON_TARGET_SECONDS ? t("Finalizing...") : `~${remaining}s`;
|
|
7598
|
+
}
|
|
7599
|
+
}, 200);
|
|
7600
|
+
return () => clearInterval(id);
|
|
7601
|
+
}, []);
|
|
7602
|
+
return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-progress-wrap", children: [
|
|
7603
|
+
/* @__PURE__ */ jsxs("div", { className: "ps-tryon-progress-ring", children: [
|
|
7604
|
+
/* @__PURE__ */ jsxs("svg", { width: "64", height: "64", viewBox: "0 0 64 64", "aria-hidden": "true", children: [
|
|
7605
|
+
/* @__PURE__ */ jsx("circle", { cx: "32", cy: "32", r: MSC_RING_RADIUS, className: "ps-tryon-progress-ring-track" }),
|
|
7606
|
+
/* @__PURE__ */ jsx(
|
|
7607
|
+
"circle",
|
|
7608
|
+
{
|
|
7609
|
+
ref: ringRef,
|
|
7610
|
+
cx: "32",
|
|
7611
|
+
cy: "32",
|
|
7612
|
+
r: MSC_RING_RADIUS,
|
|
7613
|
+
className: "ps-tryon-progress-ring-fill",
|
|
7614
|
+
strokeDasharray: MSC_RING_CIRC,
|
|
7615
|
+
strokeDashoffset: MSC_RING_CIRC
|
|
7616
|
+
}
|
|
7617
|
+
)
|
|
7618
|
+
] }),
|
|
7619
|
+
/* @__PURE__ */ jsx("span", { ref: etaRef, className: "ps-tryon-progress-eta", children: `~${MSC_TRYON_TARGET_SECONDS}s` })
|
|
7620
|
+
] }),
|
|
7621
|
+
/* @__PURE__ */ jsx("div", { className: "ps-tryon-progress-bar-wrap", children: /* @__PURE__ */ jsx("div", { ref: barRef, className: "ps-tryon-progress-bar-fill" }) }),
|
|
7622
|
+
/* @__PURE__ */ jsx("span", { ref: pctRef, className: "ps-tryon-progress-pct", children: "0%" })
|
|
7623
|
+
] });
|
|
7624
|
+
}
|
|
7454
7625
|
function MobileScanningView({
|
|
7455
7626
|
previewUrl,
|
|
7456
7627
|
productImage,
|
|
7457
7628
|
bodyLandmarks,
|
|
7458
7629
|
sizingDone,
|
|
7630
|
+
tryOnProcessing,
|
|
7459
7631
|
onSwitchToManual,
|
|
7460
7632
|
t
|
|
7461
7633
|
}) {
|
|
7462
7634
|
const displayImage = previewUrl || productImage || "";
|
|
7463
7635
|
const isPhotoMode = !!previewUrl;
|
|
7464
|
-
const stages =
|
|
7636
|
+
const stages = tryOnProcessing ? [
|
|
7637
|
+
{ title: t("GENERATING TRY-ON"), desc: t("Rendering the garment on your photo."), viewfinderText: t("GENERATING") },
|
|
7638
|
+
{ title: t("REFINING DETAILS"), desc: t("Fine-tuning fit, drape and shadows."), viewfinderText: t("REFINING") },
|
|
7639
|
+
{ title: t("ALMOST THERE"), desc: t("Final compositing in progress."), viewfinderText: t("COMPOSITING") },
|
|
7640
|
+
{ title: t("FINISHING TOUCHES"), desc: t("Polishing the result."), viewfinderText: t("FINISHING") }
|
|
7641
|
+
] : isPhotoMode ? [
|
|
7465
7642
|
{ title: t("DETECTING POSE"), desc: t("Identifying body landmarks from your photo."), viewfinderText: t("DETECTING POSE") },
|
|
7466
7643
|
{ title: t("SCANNING FRAME"), desc: t("Our AI is mapping your proportions to calculate the perfect fit."), viewfinderText: t("SCANNING FRAME") },
|
|
7467
7644
|
{ title: t("ANALYZING BODY"), desc: t("Measuring shoulders, chest, waist and hips."), viewfinderText: t("ANALYZING") },
|
|
@@ -7480,11 +7657,12 @@ function MobileScanningView({
|
|
|
7480
7657
|
};
|
|
7481
7658
|
const [stageIdx, setStageIdx] = useState(0);
|
|
7482
7659
|
useEffect(() => {
|
|
7660
|
+
const intervalMs = tryOnProcessing ? 2200 : 1500;
|
|
7483
7661
|
const id = setInterval(() => {
|
|
7484
7662
|
setStageIdx((i) => (i + 1) % stages.length);
|
|
7485
|
-
},
|
|
7663
|
+
}, intervalMs);
|
|
7486
7664
|
return () => clearInterval(id);
|
|
7487
|
-
}, [stages.length]);
|
|
7665
|
+
}, [stages.length, tryOnProcessing]);
|
|
7488
7666
|
useEffect(() => {
|
|
7489
7667
|
if (isPhotoMode && bodyLandmarks && stageIdx === 0) {
|
|
7490
7668
|
setStageIdx(1);
|
|
@@ -7504,10 +7682,13 @@ function MobileScanningView({
|
|
|
7504
7682
|
),
|
|
7505
7683
|
isPhotoMode && bodyLandmarks && /* @__PURE__ */ jsx("div", { className: "ps-msc-pose-wrap", children: /* @__PURE__ */ jsx(MobileSkeleton, { landmarks: bodyLandmarks, w: dims.w, h: dims.h }) })
|
|
7506
7684
|
] }),
|
|
7507
|
-
/* @__PURE__ */
|
|
7508
|
-
/* @__PURE__ */
|
|
7509
|
-
|
|
7510
|
-
|
|
7685
|
+
/* @__PURE__ */ jsxs("div", { className: "ps-msc-stage", children: [
|
|
7686
|
+
/* @__PURE__ */ jsxs("div", { className: "ps-msc-stage-slot", children: [
|
|
7687
|
+
/* @__PURE__ */ jsx("div", { className: "ps-msc-stage-title", children: current.title }),
|
|
7688
|
+
/* @__PURE__ */ jsx("div", { className: "ps-msc-stage-desc", children: current.desc })
|
|
7689
|
+
] }, stageIdx),
|
|
7690
|
+
tryOnProcessing && /* @__PURE__ */ jsx(MscTryOnProgress, { t })
|
|
7691
|
+
] }),
|
|
7511
7692
|
/* @__PURE__ */ jsx("div", { className: "ps-bpm-spacer" }),
|
|
7512
7693
|
/* @__PURE__ */ jsx("div", { className: "ps-bpm-bottom", children: /* @__PURE__ */ jsx(
|
|
7513
7694
|
MobileBottomTabs,
|
|
@@ -7638,7 +7819,7 @@ function MultiSectionMobile({
|
|
|
7638
7819
|
/* @__PURE__ */ jsx("div", { className: "ps-msr-sections", children: sectionEntries.map(({ name, secResult }) => {
|
|
7639
7820
|
const cleanName = name.replace(/\s*[—–-]\s*.*/g, "");
|
|
7640
7821
|
const sec = secResult;
|
|
7641
|
-
const sizeValue = sec.size || secResult.recommendedSize;
|
|
7822
|
+
const sizeValue = sec.found === false ? t("No fit") : sec.size || secResult.recommendedSize;
|
|
7642
7823
|
return /* @__PURE__ */ jsxs(
|
|
7643
7824
|
"button",
|
|
7644
7825
|
{
|
|
@@ -7673,7 +7854,19 @@ function MultiSectionMobile({
|
|
|
7673
7854
|
children: t("Continue Shopping")
|
|
7674
7855
|
}
|
|
7675
7856
|
)
|
|
7676
|
-
] }) :
|
|
7857
|
+
] }) : sizingResult?.found === false ? (
|
|
7858
|
+
// Backend couldn't find a size that fits — Try-On is meaningless
|
|
7859
|
+
// without a recommendation, so surface a clear terminal action.
|
|
7860
|
+
/* @__PURE__ */ jsx(
|
|
7861
|
+
"button",
|
|
7862
|
+
{
|
|
7863
|
+
type: "button",
|
|
7864
|
+
className: "ps-msr-tryon-cta",
|
|
7865
|
+
onClick: onClose,
|
|
7866
|
+
children: t("Continue Shopping")
|
|
7867
|
+
}
|
|
7868
|
+
)
|
|
7869
|
+
) : /* @__PURE__ */ jsxs(
|
|
7677
7870
|
"button",
|
|
7678
7871
|
{
|
|
7679
7872
|
type: "button",
|
|
@@ -7705,6 +7898,62 @@ const SKELETON_CONNECTIONS = [
|
|
|
7705
7898
|
["rightHip", "rightKnee"],
|
|
7706
7899
|
["rightKnee", "rightAnkle"]
|
|
7707
7900
|
];
|
|
7901
|
+
const TRYON_TARGET_SECONDS = 22;
|
|
7902
|
+
const TRYON_RING_RADIUS = 27;
|
|
7903
|
+
const TRYON_RING_CIRC = 2 * Math.PI * TRYON_RING_RADIUS;
|
|
7904
|
+
function TryOnProgress({ t, isActive }) {
|
|
7905
|
+
const startRef = useRef(null);
|
|
7906
|
+
const ringRef = useRef(null);
|
|
7907
|
+
const barRef = useRef(null);
|
|
7908
|
+
const etaRef = useRef(null);
|
|
7909
|
+
const pctRef = useRef(null);
|
|
7910
|
+
useEffect(() => {
|
|
7911
|
+
if (!isActive) {
|
|
7912
|
+
startRef.current = null;
|
|
7913
|
+
return;
|
|
7914
|
+
}
|
|
7915
|
+
startRef.current = Date.now();
|
|
7916
|
+
const id = setInterval(() => {
|
|
7917
|
+
const start = startRef.current || Date.now();
|
|
7918
|
+
const elapsed = (Date.now() - start) / 1e3;
|
|
7919
|
+
const pct = Math.min(95, elapsed / TRYON_TARGET_SECONDS * 100);
|
|
7920
|
+
const val = Math.round(pct);
|
|
7921
|
+
if (barRef.current) barRef.current.style.width = `${val}%`;
|
|
7922
|
+
if (pctRef.current) pctRef.current.textContent = `${val}%`;
|
|
7923
|
+
if (ringRef.current) {
|
|
7924
|
+
ringRef.current.style.strokeDashoffset = String(TRYON_RING_CIRC * (1 - pct / 100));
|
|
7925
|
+
}
|
|
7926
|
+
if (etaRef.current) {
|
|
7927
|
+
const remaining = Math.max(0, TRYON_TARGET_SECONDS - Math.floor(elapsed));
|
|
7928
|
+
etaRef.current.textContent = elapsed >= TRYON_TARGET_SECONDS ? t("Finalizing...") : `~${remaining}s`;
|
|
7929
|
+
}
|
|
7930
|
+
}, 200);
|
|
7931
|
+
return () => clearInterval(id);
|
|
7932
|
+
}, [isActive]);
|
|
7933
|
+
if (!isActive) return null;
|
|
7934
|
+
return /* @__PURE__ */ jsxs("div", { className: "ps-tryon-progress-wrap", children: [
|
|
7935
|
+
/* @__PURE__ */ jsxs("div", { className: "ps-tryon-progress-ring", children: [
|
|
7936
|
+
/* @__PURE__ */ jsxs("svg", { width: "64", height: "64", viewBox: "0 0 64 64", "aria-hidden": "true", children: [
|
|
7937
|
+
/* @__PURE__ */ jsx("circle", { cx: "32", cy: "32", r: TRYON_RING_RADIUS, className: "ps-tryon-progress-ring-track" }),
|
|
7938
|
+
/* @__PURE__ */ jsx(
|
|
7939
|
+
"circle",
|
|
7940
|
+
{
|
|
7941
|
+
ref: ringRef,
|
|
7942
|
+
cx: "32",
|
|
7943
|
+
cy: "32",
|
|
7944
|
+
r: TRYON_RING_RADIUS,
|
|
7945
|
+
className: "ps-tryon-progress-ring-fill",
|
|
7946
|
+
strokeDasharray: TRYON_RING_CIRC,
|
|
7947
|
+
strokeDashoffset: TRYON_RING_CIRC
|
|
7948
|
+
}
|
|
7949
|
+
)
|
|
7950
|
+
] }),
|
|
7951
|
+
/* @__PURE__ */ jsx("span", { ref: etaRef, className: "ps-tryon-progress-eta", children: `~${TRYON_TARGET_SECONDS}s` })
|
|
7952
|
+
] }),
|
|
7953
|
+
/* @__PURE__ */ jsx("div", { className: "ps-tryon-progress-bar-wrap", children: /* @__PURE__ */ jsx("div", { ref: barRef, className: "ps-tryon-progress-bar-fill" }) }),
|
|
7954
|
+
/* @__PURE__ */ jsx("span", { ref: pctRef, className: "ps-tryon-progress-pct", children: "0%" })
|
|
7955
|
+
] });
|
|
7956
|
+
}
|
|
7708
7957
|
function FaceOverlay({
|
|
7709
7958
|
landmarks,
|
|
7710
7959
|
imgWidth,
|
|
@@ -7842,16 +8091,20 @@ function StageCycler({
|
|
|
7842
8091
|
}, [tryOnProcessing]);
|
|
7843
8092
|
useEffect(() => {
|
|
7844
8093
|
if (isDone) return;
|
|
8094
|
+
const intervalMs = tryOnProcessing ? 2200 : 900;
|
|
7845
8095
|
const id = setInterval(() => {
|
|
7846
8096
|
setIdx((i) => Math.min(i + 1, active.length - 1));
|
|
7847
|
-
},
|
|
8097
|
+
}, intervalMs);
|
|
7848
8098
|
return () => clearInterval(id);
|
|
7849
|
-
}, [isDone, active.length]);
|
|
8099
|
+
}, [isDone, active.length, tryOnProcessing]);
|
|
7850
8100
|
const current = active[idx] ?? active[0];
|
|
7851
|
-
return /* @__PURE__ */
|
|
7852
|
-
/* @__PURE__ */
|
|
7853
|
-
|
|
7854
|
-
|
|
8101
|
+
return /* @__PURE__ */ jsxs("div", { className: "ps-msc-stage", style: { alignSelf: "center", marginTop: "auto", marginBottom: "auto" }, children: [
|
|
8102
|
+
/* @__PURE__ */ jsxs("div", { className: "ps-msc-stage-slot", children: [
|
|
8103
|
+
/* @__PURE__ */ jsx("div", { className: "ps-msc-stage-title", children: current.title }),
|
|
8104
|
+
/* @__PURE__ */ jsx("div", { className: "ps-msc-stage-desc", children: current.desc })
|
|
8105
|
+
] }, `${tryOnProcessing ? "t" : "s"}-${idx}`),
|
|
8106
|
+
tryOnProcessing && /* @__PURE__ */ jsx(TryOnProgress, { t, isActive: !!tryOnProcessing })
|
|
8107
|
+
] });
|
|
7855
8108
|
}
|
|
7856
8109
|
function SkeletonOverlay({ landmarks, imgWidth, imgHeight }) {
|
|
7857
8110
|
const W = imgWidth;
|
|
@@ -8090,7 +8343,8 @@ function SectionDetailView({
|
|
|
8090
8343
|
backLabel,
|
|
8091
8344
|
internationalSizes,
|
|
8092
8345
|
continueLabel,
|
|
8093
|
-
renderRaw = false
|
|
8346
|
+
renderRaw = false,
|
|
8347
|
+
sectionFound
|
|
8094
8348
|
}) {
|
|
8095
8349
|
const recSize = sectionResult?.recommendedSize || "";
|
|
8096
8350
|
const [selectedSize, setSelectedSize] = useState(null);
|
|
@@ -8135,7 +8389,8 @@ function SectionDetailView({
|
|
|
8135
8389
|
const hasBadFit = details.some((d) => BAD_FIT.test(d.fit || ""));
|
|
8136
8390
|
return hasBadFit ? t("Not Recommended") : t("Your Selection");
|
|
8137
8391
|
}, [isRecommended, sectionResult, t]);
|
|
8138
|
-
const
|
|
8392
|
+
const noFitMessage = t("We couldn't find a size that fits for this product");
|
|
8393
|
+
const displaySizeLabel = sectionFound === false ? noFitMessage : selectedCountry && isRecommended && internationalSizes && internationalSizes[selectedCountry] ? internationalSizes[selectedCountry] : displaySize;
|
|
8139
8394
|
const columnUnits = useMemo(() => {
|
|
8140
8395
|
const units = [];
|
|
8141
8396
|
for (let i = 0; i < section.headers.length; i++) {
|
|
@@ -8989,6 +9244,7 @@ function SizeResultView({
|
|
|
8989
9244
|
const allDone = hasPhoto ? sizingDone && tryOnDone : sizingDone;
|
|
8990
9245
|
const isMobile = useIsMobile();
|
|
8991
9246
|
const isAccessory = measurementType === "face" || measurementType === "head";
|
|
9247
|
+
const noFit = sizingResult?.found === false;
|
|
8992
9248
|
const vtoExcluded = measurementType === "foot";
|
|
8993
9249
|
console.log("[PS-SDK] SizeResultView render:", {
|
|
8994
9250
|
hasPhoto,
|
|
@@ -9027,6 +9283,7 @@ function SizeResultView({
|
|
|
9027
9283
|
previewUrl,
|
|
9028
9284
|
bodyLandmarks: bodyLandmarks ?? null,
|
|
9029
9285
|
sizingDone,
|
|
9286
|
+
tryOnProcessing,
|
|
9030
9287
|
onSwitchToManual: () => setView("body-profile"),
|
|
9031
9288
|
t
|
|
9032
9289
|
}
|
|
@@ -9072,6 +9329,7 @@ function SizeResultView({
|
|
|
9072
9329
|
sectionName: entry.name,
|
|
9073
9330
|
section: entry.section,
|
|
9074
9331
|
sectionResult: entry.secResult,
|
|
9332
|
+
sectionFound: entry.secResult?.found,
|
|
9075
9333
|
userMeasurements: entry.userMeasurements,
|
|
9076
9334
|
unitLbl,
|
|
9077
9335
|
chartUnit: resultUnit,
|
|
@@ -9083,7 +9341,7 @@ function SizeResultView({
|
|
|
9083
9341
|
isMobile: true,
|
|
9084
9342
|
isTryOnImage: !!resultImageUrl,
|
|
9085
9343
|
showLines,
|
|
9086
|
-
onToggleLines: () => setShowLines(!showLines),
|
|
9344
|
+
onToggleLines: isAccessory ? void 0 : () => setShowLines(!showLines),
|
|
9087
9345
|
onImageLoad: handleImgLoad,
|
|
9088
9346
|
overlayNode: resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsx(
|
|
9089
9347
|
MeasurementOverlay,
|
|
@@ -9121,6 +9379,7 @@ function SizeResultView({
|
|
|
9121
9379
|
sectionName: entry.name,
|
|
9122
9380
|
section: entry.section,
|
|
9123
9381
|
sectionResult: entry.secResult,
|
|
9382
|
+
sectionFound: entry.secResult?.found,
|
|
9124
9383
|
userMeasurements: entry.userMeasurements,
|
|
9125
9384
|
unitLbl,
|
|
9126
9385
|
chartUnit: resultUnit,
|
|
@@ -9157,7 +9416,7 @@ function SizeResultView({
|
|
|
9157
9416
|
},
|
|
9158
9417
|
onClose,
|
|
9159
9418
|
showLines,
|
|
9160
|
-
onToggleLines: () => setShowLines(!showLines),
|
|
9419
|
+
onToggleLines: isAccessory ? void 0 : () => setShowLines(!showLines),
|
|
9161
9420
|
onImageLoad: handleImgLoad,
|
|
9162
9421
|
overlayNode: resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsx(
|
|
9163
9422
|
MeasurementOverlay,
|
|
@@ -9192,7 +9451,10 @@ function SizeResultView({
|
|
|
9192
9451
|
/* @__PURE__ */ jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
|
|
9193
9452
|
/* @__PURE__ */ jsx("img", { src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage, alt: productTitle, className: "ps-tryon-v2-bg-img", onLoad: handleImgLoad }),
|
|
9194
9453
|
tryOnProcessing && bodyLandmarks && /* @__PURE__ */ jsx(SkeletonOverlay, { landmarks: bodyLandmarks, imgWidth: imgDims.w, imgHeight: imgDims.h }),
|
|
9195
|
-
tryOnProcessing && /* @__PURE__ */
|
|
9454
|
+
tryOnProcessing && /* @__PURE__ */ jsxs("div", { className: "ps-tryon-v2-processing-label", children: [
|
|
9455
|
+
/* @__PURE__ */ jsx("span", { children: t("Generating try-on...") }),
|
|
9456
|
+
/* @__PURE__ */ jsx(TryOnProgress, { t, isActive: true })
|
|
9457
|
+
] }),
|
|
9196
9458
|
resultImageUrl && !tryOnProcessing && poseReady && poseLines && /* @__PURE__ */ jsx(MeasurementOverlay, { lines: poseLines, fitRows: (() => {
|
|
9197
9459
|
const all = [...sizingResult?.matchDetails || []];
|
|
9198
9460
|
if (sizingResult?.sections) {
|
|
@@ -9209,7 +9471,7 @@ function SizeResultView({
|
|
|
9209
9471
|
}).map((m) => ({ area: m.measurement, userNum: parseFloat(m.userValue) || 0, chartLabel: m.chartRange || "", fit: m.fit }));
|
|
9210
9472
|
})(), show: showLines, imgWidth: imgDims.w, imgHeight: imgDims.h }),
|
|
9211
9473
|
resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxs("div", { style: { position: "absolute", bottom: "0.5vw", left: "0.5vw", zIndex: 3, display: "flex", flexDirection: "column", gap: "0.3vw" }, children: [
|
|
9212
|
-
/* @__PURE__ */ jsxs("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: [
|
|
9474
|
+
!isAccessory && /* @__PURE__ */ jsxs("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: [
|
|
9213
9475
|
/* @__PURE__ */ jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", style: { marginRight: "0.3vw" }, children: [
|
|
9214
9476
|
/* @__PURE__ */ jsx("line", { x1: "4", y1: "9", x2: "20", y2: "9" }),
|
|
9215
9477
|
/* @__PURE__ */ jsx("line", { x1: "4", y1: "15", x2: "20", y2: "15" }),
|
|
@@ -9239,7 +9501,7 @@ function SizeResultView({
|
|
|
9239
9501
|
return /* @__PURE__ */ jsxs("button", { className: `ps-tryon-sr-card-v2${isLast ? " ps-full" : ""}`, onClick: () => setActiveSection(name), style: { animationDelay: `${idx * 0.07}s` }, children: [
|
|
9240
9502
|
/* @__PURE__ */ jsxs("div", { className: "ps-tryon-sr-card-v2-text", children: [
|
|
9241
9503
|
/* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-card-v2-label", children: name.replace(/\s*[—–-]\s*.*/g, "") }),
|
|
9242
|
-
/* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-card-v2-value", children: sec.size || secResult.recommendedSize }),
|
|
9504
|
+
/* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-card-v2-value", children: sec.found === false ? t("No fit") : sec.size || secResult.recommendedSize }),
|
|
9243
9505
|
/* @__PURE__ */ jsx("span", { className: "ps-tryon-sr-card-v2-rec", children: t("recommended") })
|
|
9244
9506
|
] }),
|
|
9245
9507
|
sectionImg && /* @__PURE__ */ jsx("img", { src: sectionImg, alt: name, className: "ps-tryon-sr-card-v2-img" }),
|
|
@@ -9263,7 +9525,7 @@ function SizeResultView({
|
|
|
9263
9525
|
" →"
|
|
9264
9526
|
]
|
|
9265
9527
|
}
|
|
9266
|
-
) : vtoExcluded ? /* @__PURE__ */ jsxs(
|
|
9528
|
+
) : vtoExcluded || noFit ? /* @__PURE__ */ jsxs(
|
|
9267
9529
|
"button",
|
|
9268
9530
|
{
|
|
9269
9531
|
className: "ps-tryon-v2-cta",
|
|
@@ -9316,6 +9578,7 @@ function SizeResultView({
|
|
|
9316
9578
|
sectionName,
|
|
9317
9579
|
section: singleSection,
|
|
9318
9580
|
sectionResult: singleResult,
|
|
9581
|
+
sectionFound: sizingResult?.found,
|
|
9319
9582
|
userMeasurements: singleUserMeasurements,
|
|
9320
9583
|
unitLbl,
|
|
9321
9584
|
chartUnit: resultUnit,
|
|
@@ -9323,7 +9586,7 @@ function SizeResultView({
|
|
|
9323
9586
|
onBack: resultImageUrl ? onClose || (() => setView("body-profile")) : () => setView("body-profile"),
|
|
9324
9587
|
backLabel: t("Back"),
|
|
9325
9588
|
internationalSizes: sizingResult?.internationalSizes,
|
|
9326
|
-
onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
|
|
9589
|
+
onTryOn: resultImageUrl || vtoExcluded || noFit ? void 0 : handleSingleTryOn,
|
|
9327
9590
|
continueLabel: resultImageUrl ? t("Continue Shopping") : void 0,
|
|
9328
9591
|
tryOnProcessing,
|
|
9329
9592
|
productImage: resultImageUrl || productImage,
|
|
@@ -9332,7 +9595,7 @@ function SizeResultView({
|
|
|
9332
9595
|
renderRaw: isAccessory,
|
|
9333
9596
|
isTryOnImage: !!resultImageUrl,
|
|
9334
9597
|
showLines,
|
|
9335
|
-
onToggleLines: () => setShowLines(!showLines),
|
|
9598
|
+
onToggleLines: isAccessory ? void 0 : () => setShowLines(!showLines),
|
|
9336
9599
|
onImageLoad: handleImgLoad,
|
|
9337
9600
|
overlayNode: resultImageUrl && poseReady && poseLines ? /* @__PURE__ */ jsx(
|
|
9338
9601
|
MeasurementOverlay,
|
|
@@ -9353,7 +9616,7 @@ function SizeResultView({
|
|
|
9353
9616
|
/* @__PURE__ */ jsx("img", { src: resultImageUrl || productImage, alt: productTitle, className: "ps-tryon-v2-bg-img", onLoad: handleImgLoad }),
|
|
9354
9617
|
resultImageUrl && poseReady && poseLines && /* @__PURE__ */ jsx(MeasurementOverlay, { lines: poseLines, fitRows: (sizingResult?.matchDetails || []).map((m) => ({ area: m.measurement, userNum: parseFloat(m.userValue) || 0, chartLabel: m.chartRange || "", fit: m.fit })), show: showLines, imgWidth: imgDims.w, imgHeight: imgDims.h }),
|
|
9355
9618
|
resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxs("div", { style: { position: "absolute", bottom: "0.5vw", left: "0.5vw", zIndex: 3, display: "flex", flexDirection: "column", gap: "0.3vw" }, children: [
|
|
9356
|
-
/* @__PURE__ */ jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: showLines ? t("Hide Fit") : t("Show Fit") }),
|
|
9619
|
+
!isAccessory && /* @__PURE__ */ jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: showLines ? t("Hide Fit") : t("Show Fit") }),
|
|
9357
9620
|
/* @__PURE__ */ jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: handleDownload, children: t("Download") })
|
|
9358
9621
|
] })
|
|
9359
9622
|
] }),
|
|
@@ -9363,6 +9626,7 @@ function SizeResultView({
|
|
|
9363
9626
|
sectionName,
|
|
9364
9627
|
section: singleSection,
|
|
9365
9628
|
sectionResult: singleResult,
|
|
9629
|
+
sectionFound: sizingResult?.found,
|
|
9366
9630
|
userMeasurements: singleUserMeasurements,
|
|
9367
9631
|
unitLbl,
|
|
9368
9632
|
chartUnit: resultUnit,
|
|
@@ -9370,7 +9634,7 @@ function SizeResultView({
|
|
|
9370
9634
|
onBack: resultImageUrl ? onClose || (() => setView("body-profile")) : () => setView("body-profile"),
|
|
9371
9635
|
backLabel: t("Back"),
|
|
9372
9636
|
internationalSizes: sizingResult?.internationalSizes,
|
|
9373
|
-
onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
|
|
9637
|
+
onTryOn: resultImageUrl || vtoExcluded || noFit ? void 0 : handleSingleTryOn,
|
|
9374
9638
|
continueLabel: resultImageUrl ? t("Continue Shopping") : void 0,
|
|
9375
9639
|
tryOnProcessing,
|
|
9376
9640
|
t,
|
|
@@ -9746,7 +10010,7 @@ function UploadView({
|
|
|
9746
10010
|
}
|
|
9747
10011
|
) });
|
|
9748
10012
|
}
|
|
9749
|
-
const RING_RADIUS =
|
|
10013
|
+
const RING_RADIUS = 27;
|
|
9750
10014
|
const RING_CIRCUMFERENCE = 2 * Math.PI * RING_RADIUS;
|
|
9751
10015
|
function ProcessingView({
|
|
9752
10016
|
previewUrl,
|
|
@@ -9791,12 +10055,12 @@ function ProcessingView({
|
|
|
9791
10055
|
] }),
|
|
9792
10056
|
/* @__PURE__ */ jsxs("div", { className: "ps-tryon-progress-section", children: [
|
|
9793
10057
|
/* @__PURE__ */ jsxs("div", { className: "ps-tryon-progress-ring", children: [
|
|
9794
|
-
/* @__PURE__ */ jsxs("svg", { viewBox: "0 0
|
|
10058
|
+
/* @__PURE__ */ jsxs("svg", { viewBox: "0 0 64 64", width: "64", height: "64", "aria-hidden": "true", children: [
|
|
9795
10059
|
/* @__PURE__ */ jsx(
|
|
9796
10060
|
"circle",
|
|
9797
10061
|
{
|
|
9798
|
-
cx: "
|
|
9799
|
-
cy: "
|
|
10062
|
+
cx: "32",
|
|
10063
|
+
cy: "32",
|
|
9800
10064
|
r: RING_RADIUS,
|
|
9801
10065
|
className: "ps-tryon-progress-ring-track"
|
|
9802
10066
|
}
|
|
@@ -9805,8 +10069,8 @@ function ProcessingView({
|
|
|
9805
10069
|
"circle",
|
|
9806
10070
|
{
|
|
9807
10071
|
ref: ringCb,
|
|
9808
|
-
cx: "
|
|
9809
|
-
cy: "
|
|
10072
|
+
cx: "32",
|
|
10073
|
+
cy: "32",
|
|
9810
10074
|
r: RING_RADIUS,
|
|
9811
10075
|
className: "ps-tryon-progress-ring-fill",
|
|
9812
10076
|
strokeDasharray: RING_CIRCUMFERENCE,
|
|
@@ -12376,7 +12640,7 @@ function BodyProfileView({
|
|
|
12376
12640
|
hidePhotoOptions: hasActiveProfileWithMeasurements,
|
|
12377
12641
|
onNext: hasActiveProfileWithMeasurements && onUseActiveProfile ? onUseActiveProfile : handleNext,
|
|
12378
12642
|
canProceed: true,
|
|
12379
|
-
fastPathLabel: hasActiveProfileWithMeasurements ? t("Find My Best Fit") : void 0,
|
|
12643
|
+
fastPathLabel: hasActiveProfileWithMeasurements ? t("Find My Best Fit") + (getUnitLabel(hUnit) ? ` (${getUnitLabel(hUnit)})` : "") : void 0,
|
|
12380
12644
|
activeProfileName: hasActiveProfileWithMeasurements ? activeProfileName : null,
|
|
12381
12645
|
onStartFresh,
|
|
12382
12646
|
error,
|
|
@@ -12631,7 +12895,8 @@ function BodyProfileView({
|
|
|
12631
12895
|
!(isMobile && step === "basics") && (() => {
|
|
12632
12896
|
const useProfileFast = step === "basics" && hasActiveProfileWithMeasurements && !!onUseActiveProfile;
|
|
12633
12897
|
const handleClick = useProfileFast ? onUseActiveProfile : handleNext;
|
|
12634
|
-
const
|
|
12898
|
+
const unitSuffix = getUnitLabel(hUnit) ? ` (${getUnitLabel(hUnit)})` : "";
|
|
12899
|
+
const label = useProfileFast ? t("Find My Best Fit") + unitSuffix : isLastStep ? t("Find My Size") + unitSuffix : t("Next");
|
|
12635
12900
|
return /* @__PURE__ */ jsxs("div", { className: "ps-bp-nav", children: [
|
|
12636
12901
|
step !== "basics" ? /* @__PURE__ */ jsxs("button", { className: "ps-bp-back-btn", onClick: handleBackStep, type: "button", children: [
|
|
12637
12902
|
/* @__PURE__ */ jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
|
|
@@ -12821,6 +13086,7 @@ function AccessorySizeView({
|
|
|
12821
13086
|
/* @__PURE__ */ jsxs("div", { className: "ps-bpm-bottom", children: [
|
|
12822
13087
|
/* @__PURE__ */ jsxs("button", { type: "button", className: "ps-bpm-next-btn", onClick: handleManualSubmit, children: [
|
|
12823
13088
|
t("Find My Size"),
|
|
13089
|
+
getUnitLabel(sizingUnit) ? ` (${getUnitLabel(sizingUnit)})` : "",
|
|
12824
13090
|
" ",
|
|
12825
13091
|
/* @__PURE__ */ jsx(ArrowRightIcon, {})
|
|
12826
13092
|
] }),
|
|
@@ -13155,6 +13421,7 @@ function AccessorySizeView({
|
|
|
13155
13421
|
/* @__PURE__ */ jsx("div", {}),
|
|
13156
13422
|
/* @__PURE__ */ jsxs("button", { className: "ps-bp-next-btn", onClick: handleManualSubmit, type: "button", children: [
|
|
13157
13423
|
t("Find My Size"),
|
|
13424
|
+
getUnitLabel(sizingUnit) ? ` (${getUnitLabel(sizingUnit)})` : "",
|
|
13158
13425
|
" ",
|
|
13159
13426
|
/* @__PURE__ */ jsx(ArrowRightIcon, {})
|
|
13160
13427
|
] })
|
|
@@ -13388,6 +13655,9 @@ function PrimeStyleTryonInner({
|
|
|
13388
13655
|
const [sizingUnit, setSizingUnit] = useState(imperial ? "in" : "cm");
|
|
13389
13656
|
const [heightUnit, setHeightUnit] = useState(imperial ? "in" : "cm");
|
|
13390
13657
|
const [weightUnit, setWeightUnit] = useState(imperial ? "lbs" : "kg");
|
|
13658
|
+
useEffect(() => {
|
|
13659
|
+
if (detectMeasurementType(productTitle) === "foot") setSizingUnit("cm");
|
|
13660
|
+
}, [productTitle]);
|
|
13391
13661
|
const formRef = useRef({});
|
|
13392
13662
|
const [formGender, setFormGender] = useState("male");
|
|
13393
13663
|
const [formKey, setFormKey] = useState(0);
|
|
@@ -13462,7 +13732,7 @@ function PrimeStyleTryonInner({
|
|
|
13462
13732
|
{ at: 75, text: t("Refining details...") },
|
|
13463
13733
|
{ at: 90, text: t("Almost there...") }
|
|
13464
13734
|
];
|
|
13465
|
-
const RING_CIRCUMFERENCE2 = 2 * Math.PI *
|
|
13735
|
+
const RING_CIRCUMFERENCE2 = 2 * Math.PI * 27;
|
|
13466
13736
|
progressIntervalRef.current = setInterval(() => {
|
|
13467
13737
|
if (completedRef.current) return;
|
|
13468
13738
|
const startTs = progressStartTsRef.current || Date.now();
|
|
@@ -13640,13 +13910,10 @@ function PrimeStyleTryonInner({
|
|
|
13640
13910
|
[activeProfileId, profiles, apiUrl, productImage, productTitle, effectiveProductId, setActiveProfileId$1]
|
|
13641
13911
|
);
|
|
13642
13912
|
const snapSubmitRef = useRef(null);
|
|
13643
|
-
const
|
|
13644
|
-
|
|
13645
|
-
if (!p) return;
|
|
13913
|
+
const [confirmProfile, setConfirmProfile] = useState(null);
|
|
13914
|
+
const runRecommendWithProfile = useCallback(async (p) => {
|
|
13646
13915
|
const profileHeight = p.height ?? p.heightCm ?? 0;
|
|
13647
13916
|
const profileWeight = p.weight ?? p.weightKg ?? 0;
|
|
13648
|
-
const hasIdentity = profileHeight > 0 && profileWeight > 0;
|
|
13649
|
-
if (!hasIdentity) return;
|
|
13650
13917
|
const hasStored = !!p.measurements && Object.keys(p.measurements).length > 0;
|
|
13651
13918
|
const storedPhoto = p.photoBase64;
|
|
13652
13919
|
if (!hasStored && storedPhoto && profileHeight > 0 && snapSubmitRef.current) {
|
|
@@ -13670,9 +13937,8 @@ function PrimeStyleTryonInner({
|
|
|
13670
13937
|
}
|
|
13671
13938
|
setSizingResult(null);
|
|
13672
13939
|
setSizingLoading(true);
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
if (hasStoredMeasurements) {
|
|
13940
|
+
setEstimationDone(hasStored);
|
|
13941
|
+
if (hasStored) {
|
|
13676
13942
|
setPreviewUrl(null);
|
|
13677
13943
|
setBodyLandmarks(null);
|
|
13678
13944
|
}
|
|
@@ -13705,7 +13971,27 @@ function PrimeStyleTryonInner({
|
|
|
13705
13971
|
setEstimationDone(true);
|
|
13706
13972
|
}).catch(() => {
|
|
13707
13973
|
}).finally(() => setSizingLoading(false));
|
|
13708
|
-
}, [
|
|
13974
|
+
}, [effectiveProductId, productTitle, productImage, sizeGuideData, apiUrl, previewUrl]);
|
|
13975
|
+
const handleUseActiveProfile = useCallback(async () => {
|
|
13976
|
+
const p = profiles.find((x) => x.id === activeProfileId);
|
|
13977
|
+
if (!p) return;
|
|
13978
|
+
const profileHeight = p.height ?? p.heightCm ?? 0;
|
|
13979
|
+
const profileWeight = p.weight ?? p.weightKg ?? 0;
|
|
13980
|
+
const hasIdentity = profileHeight > 0 && profileWeight > 0;
|
|
13981
|
+
if (!hasIdentity) return;
|
|
13982
|
+
setConfirmProfile(p);
|
|
13983
|
+
}, [profiles, activeProfileId]);
|
|
13984
|
+
const proceedFromConfirmProfile = useCallback(() => {
|
|
13985
|
+
if (!confirmProfile) return;
|
|
13986
|
+
const p = confirmProfile;
|
|
13987
|
+
setConfirmProfile(null);
|
|
13988
|
+
void runRecommendWithProfile(p);
|
|
13989
|
+
}, [confirmProfile, runRecommendWithProfile]);
|
|
13990
|
+
const cancelFromConfirmProfile = useCallback(() => {
|
|
13991
|
+
setConfirmProfile(null);
|
|
13992
|
+
setFormKey((k) => k + 1);
|
|
13993
|
+
setView("body-profile");
|
|
13994
|
+
}, []);
|
|
13709
13995
|
const applyProfileRef = useRef(() => {
|
|
13710
13996
|
});
|
|
13711
13997
|
const handleOpen = useCallback(() => {
|
|
@@ -15080,6 +15366,15 @@ function PrimeStyleTryonInner({
|
|
|
15080
15366
|
onCancel: () => setDeleteConfirmId(null),
|
|
15081
15367
|
t
|
|
15082
15368
|
}
|
|
15369
|
+
),
|
|
15370
|
+
confirmProfile && /* @__PURE__ */ jsx(
|
|
15371
|
+
ConfirmMeasurementsModal,
|
|
15372
|
+
{
|
|
15373
|
+
profile: confirmProfile,
|
|
15374
|
+
onProceed: proceedFromConfirmProfile,
|
|
15375
|
+
onEdit: cancelFromConfirmProfile,
|
|
15376
|
+
t
|
|
15377
|
+
}
|
|
15083
15378
|
)
|
|
15084
15379
|
] }) }),
|
|
15085
15380
|
document.body
|