@primestyleai/tryon 5.10.102 → 5.10.103
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/PrimeStyleTryonInner.d.ts +1 -1
- package/dist/react/index.js +4903 -4964
- package/dist/react/index.js.map +1 -1
- package/dist/react/styles.d.ts +1 -1
- package/dist/react/types.d.ts +4 -0
- package/dist/react/views/ProductPhotoCarouselCard.d.ts +12 -0
- package/dist/react/views/SizeResultView.d.ts +5 -19
- package/dist/react/views/TryOnGenerationBadge.d.ts +5 -0
- package/dist/sizing/fit-compute.d.ts +8 -3
- package/dist/storefront/primestyle-tryon.js +600 -751
- package/dist/types.d.ts +5 -0
- package/package.json +1 -1
|
@@ -10078,12 +10078,13 @@ function parseNum(s) {
|
|
|
10078
10078
|
const n2 = parseFloat(s.replace(/[^\d.]/g, ""));
|
|
10079
10079
|
return isNaN(n2) ? 0 : n2;
|
|
10080
10080
|
}
|
|
10081
|
-
function computeFit(userValue, chartRange) {
|
|
10081
|
+
function computeFit(userValue, chartRange, unit) {
|
|
10082
10082
|
const { min: rMin, max: rMax } = parseRange(chartRange);
|
|
10083
10083
|
if (rMin === 0 && rMax === 0) return "good";
|
|
10084
10084
|
const range = rMax - rMin;
|
|
10085
10085
|
const threshold = range > 0 ? range * 0.5 : rMin * 0.05 || 3;
|
|
10086
|
-
|
|
10086
|
+
const perfectTol = unit === "cm" ? 2.54 : unit === "mm" ? 25.4 : 1;
|
|
10087
|
+
if (userValue > rMin - perfectTol && userValue < rMax + perfectTol) return "good";
|
|
10087
10088
|
if (userValue < rMin) {
|
|
10088
10089
|
const diff2 = rMin - userValue;
|
|
10089
10090
|
if (diff2 > threshold * 2) return "too-loose";
|
|
@@ -10107,12 +10108,13 @@ const SKIP_AREAS_FOR_FIT = /* @__PURE__ */ new Set([
|
|
|
10107
10108
|
"altezza",
|
|
10108
10109
|
"estatura"
|
|
10109
10110
|
]);
|
|
10110
|
-
function buildFitInfo(matchDetails, poseLines) {
|
|
10111
|
+
function buildFitInfo(matchDetails, poseLines, unit) {
|
|
10111
10112
|
return matchDetails.filter((m2) => !SKIP_AREAS_FOR_FIT.has(m2.measurement.toLowerCase().replace(/\s*\(.*?\)\s*/g, "").trim())).map((m2) => {
|
|
10112
10113
|
const userNum = parseNum(m2.userValue);
|
|
10113
|
-
const fit = computeFit(userNum, m2.chartRange);
|
|
10114
|
+
const fit = computeFit(userNum, m2.chartRange, unit);
|
|
10114
10115
|
const info = {
|
|
10115
10116
|
area: m2.measurement,
|
|
10117
|
+
section: m2.section || void 0,
|
|
10116
10118
|
fit,
|
|
10117
10119
|
userValue: userNum || void 0,
|
|
10118
10120
|
garmentRange: m2.chartRange || void 0
|
|
@@ -11328,6 +11330,37 @@ const STYLES$1 = `
|
|
|
11328
11330
|
border: 1px solid rgba(33,84,239,0.25); border-radius: 2vw;
|
|
11329
11331
|
padding: 0.1vw 0.5vw;
|
|
11330
11332
|
}
|
|
11333
|
+
.ps-tryon-sr-card-v2-rec-pill {
|
|
11334
|
+
align-self: flex-start;
|
|
11335
|
+
font-size: 0.55vw; font-weight: 700; color: var(--ps-accent);
|
|
11336
|
+
text-transform: uppercase; letter-spacing: 0.08em;
|
|
11337
|
+
background: rgba(33, 84, 239, 0.10);
|
|
11338
|
+
border: 1px solid rgba(33, 84, 239, 0.18);
|
|
11339
|
+
border-radius: 2vw;
|
|
11340
|
+
padding: 0.18vw 0.6vw;
|
|
11341
|
+
margin-top: 0.3vw;
|
|
11342
|
+
}
|
|
11343
|
+
.ps-tryon-sr-card-v2-rec-pill.is-overridden {
|
|
11344
|
+
color: #b45309;
|
|
11345
|
+
background: rgba(180, 83, 9, 0.10);
|
|
11346
|
+
border-color: rgba(180, 83, 9, 0.25);
|
|
11347
|
+
}
|
|
11348
|
+
.ps-tryon-sr-card-v2-view {
|
|
11349
|
+
align-self: center;
|
|
11350
|
+
margin-top: 0.4vw;
|
|
11351
|
+
font-size: 0.62vw; font-weight: 600;
|
|
11352
|
+
color: var(--ps-accent);
|
|
11353
|
+
text-transform: uppercase; letter-spacing: 0.06em;
|
|
11354
|
+
display: inline-flex; align-items: center; justify-content: center; gap: 0.2vw;
|
|
11355
|
+
transition: gap 0.2s ease;
|
|
11356
|
+
}
|
|
11357
|
+
.ps-tryon-sr-card-v2:hover .ps-tryon-sr-card-v2-view {
|
|
11358
|
+
gap: 0.4vw;
|
|
11359
|
+
}
|
|
11360
|
+
.ps-tryon-sr-card-v2-view > span {
|
|
11361
|
+
font-size: 0.85vw; line-height: 1; color: var(--ps-accent);
|
|
11362
|
+
transform: translateY(-0.05vw);
|
|
11363
|
+
}
|
|
11331
11364
|
.ps-tryon-sr-card-v2-img { display: none; }
|
|
11332
11365
|
.ps-tryon-sr-card-v2-icon {
|
|
11333
11366
|
position: absolute; bottom: 0.35vw; right: 0.45vw;
|
|
@@ -11391,24 +11424,165 @@ const STYLES$1 = `
|
|
|
11391
11424
|
filter: blur(8px) brightness(0.5); transform: scale(1.05);
|
|
11392
11425
|
transition: filter 0.5s ease, transform 0.5s ease;
|
|
11393
11426
|
}
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
background:
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
|
|
11402
|
-
box-shadow: 0
|
|
11427
|
+
/* ── Try-on generation badge (left-side overlay during VTO) ── */
|
|
11428
|
+
.ps-tryon-badge {
|
|
11429
|
+
position: absolute; bottom: 16px; left: 16px; right: 16px;
|
|
11430
|
+
z-index: 5;
|
|
11431
|
+
background: #ffffff;
|
|
11432
|
+
border-radius: 14px;
|
|
11433
|
+
padding: 14px 18px;
|
|
11434
|
+
max-width: 420px;
|
|
11435
|
+
box-shadow: 0 8px 28px rgba(20, 30, 60, 0.14), 0 2px 6px rgba(20, 30, 60, 0.08);
|
|
11436
|
+
display: flex; flex-direction: column; gap: 10px;
|
|
11437
|
+
font-family: inherit;
|
|
11438
|
+
pointer-events: none;
|
|
11439
|
+
}
|
|
11440
|
+
.ps-tryon-badge-row {
|
|
11441
|
+
display: flex; align-items: center; gap: 12px;
|
|
11403
11442
|
}
|
|
11404
|
-
.ps-tryon-
|
|
11405
|
-
|
|
11443
|
+
.ps-tryon-badge-spinner {
|
|
11444
|
+
display: inline-flex; flex-shrink: 0;
|
|
11445
|
+
animation: ps-tryon-badge-spin 1s linear infinite;
|
|
11446
|
+
}
|
|
11447
|
+
.ps-tryon-badge-title {
|
|
11448
|
+
flex: 1; min-width: 0;
|
|
11449
|
+
font-size: 15px; font-weight: 600; color: #0f172a;
|
|
11450
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
11451
|
+
}
|
|
11452
|
+
.ps-tryon-badge-pct {
|
|
11453
|
+
flex-shrink: 0;
|
|
11454
|
+
background: linear-gradient(135deg, var(--ps-accent) 0%, var(--ps-accent-hover) 100%);
|
|
11455
|
+
color: #fff; font-size: 12px; font-weight: 700;
|
|
11456
|
+
padding: 4px 11px; border-radius: 999px;
|
|
11457
|
+
letter-spacing: 0.02em;
|
|
11458
|
+
}
|
|
11459
|
+
.ps-tryon-badge-bar {
|
|
11460
|
+
height: 5px;
|
|
11461
|
+
background: #eef2f8;
|
|
11462
|
+
border-radius: 999px; overflow: hidden;
|
|
11463
|
+
}
|
|
11464
|
+
.ps-tryon-badge-bar-fill {
|
|
11465
|
+
height: 100%;
|
|
11466
|
+
background: linear-gradient(90deg, var(--ps-accent) 0%, var(--ps-accent-hover) 100%);
|
|
11467
|
+
border-radius: 999px;
|
|
11468
|
+
transition: width 0.3s ease;
|
|
11469
|
+
}
|
|
11470
|
+
.ps-tryon-badge-foot {
|
|
11471
|
+
display: flex; align-items: center; justify-content: space-between; gap: 10px;
|
|
11472
|
+
font-size: 12px; color: #6b7280;
|
|
11473
|
+
}
|
|
11474
|
+
.ps-tryon-badge-status {
|
|
11475
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
11476
|
+
font-weight: 500;
|
|
11477
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
11478
|
+
}
|
|
11479
|
+
.ps-tryon-badge-status-icon {
|
|
11480
|
+
display: inline-flex; flex-shrink: 0; color: var(--ps-accent);
|
|
11481
|
+
}
|
|
11482
|
+
.ps-tryon-badge-eta {
|
|
11483
|
+
display: inline-flex; align-items: center; gap: 5px;
|
|
11484
|
+
font-weight: 500; flex-shrink: 0;
|
|
11485
|
+
}
|
|
11486
|
+
@keyframes ps-tryon-badge-spin {
|
|
11487
|
+
to { transform: rotate(360deg); }
|
|
11488
|
+
}
|
|
11489
|
+
|
|
11490
|
+
/* ── Product photo strip (single-garment, below the size card) ──
|
|
11491
|
+
Three thumbnails per slide, evenly spaced, auto-advances. Lives at
|
|
11492
|
+
the bottom of the right panel as decoration / entertainment. */
|
|
11493
|
+
.ps-tryon-photo-strip {
|
|
11494
|
+
margin-top: 1vw;
|
|
11495
|
+
display: flex; flex-direction: column; gap: 0.6vw;
|
|
11496
|
+
}
|
|
11497
|
+
.ps-tryon-photo-strip-head {
|
|
11498
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
11499
|
+
}
|
|
11500
|
+
.ps-tryon-photo-strip-badge {
|
|
11501
|
+
color: var(--ps-accent);
|
|
11502
|
+
font-size: 0.7vw; font-weight: 600;
|
|
11503
|
+
display: inline-flex; align-items: center; gap: 0.3vw;
|
|
11504
|
+
letter-spacing: 0.04em; text-transform: uppercase;
|
|
11505
|
+
}
|
|
11506
|
+
.ps-tryon-photo-strip-row {
|
|
11507
|
+
display: grid;
|
|
11508
|
+
grid-template-columns: repeat(3, 1fr);
|
|
11509
|
+
gap: 0.6vw;
|
|
11510
|
+
animation: ps-tryon-photo-strip-fade 0.5s ease;
|
|
11511
|
+
}
|
|
11512
|
+
.ps-tryon-photo-strip-cell {
|
|
11513
|
+
position: relative;
|
|
11514
|
+
aspect-ratio: 3 / 4;
|
|
11515
|
+
overflow: hidden;
|
|
11516
|
+
border-radius: 0.5vw;
|
|
11517
|
+
background: #f3f5f9;
|
|
11518
|
+
box-shadow: 0 0.15vw 0.5vw rgba(20, 30, 60, 0.08);
|
|
11519
|
+
transition: transform 0.25s ease;
|
|
11520
|
+
}
|
|
11521
|
+
.ps-tryon-photo-strip-cell:hover {
|
|
11522
|
+
transform: translateY(-0.15vw);
|
|
11523
|
+
}
|
|
11524
|
+
.ps-tryon-photo-strip-cell > img {
|
|
11525
|
+
width: 100%; height: 100%;
|
|
11526
|
+
object-fit: cover;
|
|
11527
|
+
user-select: none;
|
|
11528
|
+
pointer-events: none;
|
|
11529
|
+
}
|
|
11530
|
+
.ps-tryon-photo-strip-dots {
|
|
11531
|
+
display: flex; justify-content: center; align-items: center; gap: 0.3vw;
|
|
11532
|
+
padding-top: 0.2vw;
|
|
11533
|
+
}
|
|
11534
|
+
.ps-tryon-photo-strip-dot {
|
|
11535
|
+
width: 0.3vw; height: 0.3vw; min-width: 4px; min-height: 4px;
|
|
11536
|
+
border-radius: 999px;
|
|
11537
|
+
background: #d6dbe4;
|
|
11538
|
+
transition: background-color 0.3s ease, width 0.3s ease;
|
|
11539
|
+
}
|
|
11540
|
+
.ps-tryon-photo-strip-dot.is-active {
|
|
11541
|
+
background: var(--ps-accent);
|
|
11542
|
+
width: 0.9vw; min-width: 14px;
|
|
11543
|
+
}
|
|
11544
|
+
@keyframes ps-tryon-photo-strip-fade {
|
|
11545
|
+
from { opacity: 0; transform: translateY(0.3vw); }
|
|
11546
|
+
to { opacity: 1; transform: translateY(0); }
|
|
11547
|
+
}
|
|
11548
|
+
|
|
11549
|
+
/* ── No-fit empty state (single-garment, sizing match% < 50%) ── */
|
|
11550
|
+
.ps-tryon-nofit {
|
|
11551
|
+
background: #ffffff;
|
|
11552
|
+
border: 1px solid #eef2f8;
|
|
11553
|
+
border-radius: 1vw;
|
|
11554
|
+
padding: 3vw 2.4vw 2.6vw;
|
|
11555
|
+
text-align: center;
|
|
11556
|
+
display: flex; flex-direction: column; align-items: center;
|
|
11557
|
+
box-shadow: 0 0.4vw 1.2vw rgba(20, 30, 60, 0.05);
|
|
11558
|
+
}
|
|
11559
|
+
.ps-tryon-nofit-icon {
|
|
11560
|
+
width: 4.4vw; height: 4.4vw; min-width: 56px; min-height: 56px;
|
|
11561
|
+
border-radius: 50%;
|
|
11562
|
+
background: #fef2f2;
|
|
11563
|
+
color: #dc2626;
|
|
11564
|
+
display: flex; align-items: center; justify-content: center;
|
|
11565
|
+
margin-bottom: 1.2vw;
|
|
11566
|
+
}
|
|
11567
|
+
.ps-tryon-nofit-icon svg { width: 50%; height: 50%; }
|
|
11568
|
+
.ps-tryon-nofit-title {
|
|
11569
|
+
font-size: 1.15vw; font-weight: 700; color: #0f172a;
|
|
11570
|
+
margin: 0 0 0.7vw;
|
|
11571
|
+
line-height: 1.3;
|
|
11572
|
+
letter-spacing: -0.01em;
|
|
11573
|
+
}
|
|
11574
|
+
.ps-tryon-nofit-sub {
|
|
11575
|
+
font-size: 0.78vw; color: #6b7280;
|
|
11576
|
+
margin: 0 0 2vw;
|
|
11577
|
+
max-width: 22vw;
|
|
11578
|
+
line-height: 1.6;
|
|
11579
|
+
}
|
|
11580
|
+
.ps-tryon-nofit-actions {
|
|
11581
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
11582
|
+
width: 100%; gap: 1vw;
|
|
11583
|
+
padding-top: 1.2vw;
|
|
11584
|
+
border-top: 1px solid #f1f4fa;
|
|
11406
11585
|
}
|
|
11407
|
-
.ps-tryon-v2-processing-label .ps-tryon-progress-ring-track { stroke: rgba(255,255,255,0.18); }
|
|
11408
|
-
.ps-tryon-v2-processing-label .ps-tryon-progress-ring-fill { stroke: var(--ps-accent-light); }
|
|
11409
|
-
.ps-tryon-v2-processing-label .ps-tryon-progress-eta { color: #fff; }
|
|
11410
|
-
.ps-tryon-v2-processing-label .ps-tryon-progress-bar-wrap { background: rgba(255,255,255,0.18); }
|
|
11411
|
-
.ps-tryon-v2-processing-label .ps-tryon-progress-pct { color: var(--ps-accent-light); }
|
|
11412
11586
|
|
|
11413
11587
|
/* "I don't know" link */
|
|
11414
11588
|
.ps-tryon-v2-dontknow {
|
|
@@ -18741,133 +18915,6 @@ function MobileBottomTabs({ mode, onSwitchToManual, onSwitchToScan, t: t2 }) {
|
|
|
18741
18915
|
)
|
|
18742
18916
|
] });
|
|
18743
18917
|
}
|
|
18744
|
-
const TARGET_SECONDS = 22;
|
|
18745
|
-
const RING_RADIUS$1 = 38;
|
|
18746
|
-
const RING_CIRC = 2 * Math.PI * RING_RADIUS$1;
|
|
18747
|
-
function EngagingTryOnView({
|
|
18748
|
-
previewUrl,
|
|
18749
|
-
productMaterial,
|
|
18750
|
-
productDescription,
|
|
18751
|
-
onCancel,
|
|
18752
|
-
variant = "split",
|
|
18753
|
-
t: t2
|
|
18754
|
-
}) {
|
|
18755
|
-
const startRef = reactExports.useRef(Date.now());
|
|
18756
|
-
const ringRef = reactExports.useRef(null);
|
|
18757
|
-
const pctRef = reactExports.useRef(null);
|
|
18758
|
-
const statusRef = reactExports.useRef(null);
|
|
18759
|
-
const statuses = [
|
|
18760
|
-
t2("Preparing your image…"),
|
|
18761
|
-
t2("Mapping body landmarks…"),
|
|
18762
|
-
t2("Rendering the garment…"),
|
|
18763
|
-
t2("Refining drape and shadows…"),
|
|
18764
|
-
t2("Almost done — finalizing…")
|
|
18765
|
-
];
|
|
18766
|
-
reactExports.useEffect(() => {
|
|
18767
|
-
startRef.current = Date.now();
|
|
18768
|
-
const id2 = setInterval(() => {
|
|
18769
|
-
const elapsed = (Date.now() - startRef.current) / 1e3;
|
|
18770
|
-
const pct = Math.min(95, elapsed / TARGET_SECONDS * 100);
|
|
18771
|
-
const val = Math.round(pct);
|
|
18772
|
-
if (pctRef.current) pctRef.current.textContent = `${val}%`;
|
|
18773
|
-
if (ringRef.current) ringRef.current.style.strokeDashoffset = String(RING_CIRC * (1 - pct / 100));
|
|
18774
|
-
if (statusRef.current) {
|
|
18775
|
-
const stepIdx = Math.min(statuses.length - 1, Math.floor(elapsed / TARGET_SECONDS * statuses.length));
|
|
18776
|
-
const desired = statuses[stepIdx];
|
|
18777
|
-
if (statusRef.current.textContent !== desired) statusRef.current.textContent = desired;
|
|
18778
|
-
}
|
|
18779
|
-
}, 200);
|
|
18780
|
-
return () => clearInterval(id2);
|
|
18781
|
-
}, []);
|
|
18782
|
-
const aiFact = t2("Our model is analyzing 150+ body landmarks for the perfect fit");
|
|
18783
|
-
const styleTips = [
|
|
18784
|
-
t2("Match your belt to your shoes — never your pants"),
|
|
18785
|
-
t2("Leave the bottom button of a suit jacket undone"),
|
|
18786
|
-
t2("Cuff a pocket square so it peeks 1–2 cm above the pocket"),
|
|
18787
|
-
t2("Roll sleeves twice for a relaxed, intentional finish"),
|
|
18788
|
-
t2("A tie tip should land at the middle of your belt buckle"),
|
|
18789
|
-
t2("Cufflinks should sit half an inch past the jacket sleeve")
|
|
18790
|
-
];
|
|
18791
|
-
const [tipIdx, setTipIdx] = reactExports.useState(0);
|
|
18792
|
-
reactExports.useEffect(() => {
|
|
18793
|
-
const s = setInterval(() => setTipIdx((i) => (i + 1) % styleTips.length), 5e3);
|
|
18794
|
-
return () => clearInterval(s);
|
|
18795
|
-
}, []);
|
|
18796
|
-
const garmentLine = productMaterial?.trim() || (productDescription?.trim() ? productDescription.trim().slice(0, 90) + (productDescription.trim().length > 90 ? "…" : "") : null) || t2("Crafted with quality materials for everyday comfort");
|
|
18797
|
-
const Panel = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-panel", children: [
|
|
18798
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-head", children: [
|
|
18799
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-processing-v2-title", children: t2("Generating Your Look") }),
|
|
18800
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-processing-v2-sub", children: t2("Our AI is precisely mapping the garment to your unique proportions.") })
|
|
18801
|
-
] }),
|
|
18802
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-ring-wrap", children: [
|
|
18803
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 96 96", width: "120", height: "120", "aria-hidden": "true", children: [
|
|
18804
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "48", cy: "48", r: RING_RADIUS$1, className: "ps-tryon-progress-ring-track" }),
|
|
18805
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18806
|
-
"circle",
|
|
18807
|
-
{
|
|
18808
|
-
ref: ringRef,
|
|
18809
|
-
cx: "48",
|
|
18810
|
-
cy: "48",
|
|
18811
|
-
r: RING_RADIUS$1,
|
|
18812
|
-
className: "ps-tryon-progress-ring-fill",
|
|
18813
|
-
strokeDasharray: RING_CIRC,
|
|
18814
|
-
strokeDashoffset: RING_CIRC
|
|
18815
|
-
}
|
|
18816
|
-
)
|
|
18817
|
-
] }),
|
|
18818
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-ring-text", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { ref: pctRef, className: "ps-tryon-processing-v2-pct", children: "0%" }) })
|
|
18819
|
-
] }),
|
|
18820
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { ref: statusRef, className: "ps-tryon-processing-v2-status", children: statuses[0] }),
|
|
18821
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-sep" }),
|
|
18822
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
18823
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-section-label", children: t2("WHILE YOU WAIT") }),
|
|
18824
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-cards", children: [
|
|
18825
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-card", children: [
|
|
18826
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-card-icon ps-style", children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M9 18h6M10 22h4M12 2a7 7 0 0 0-4 12.7c1 .9 1 1.8 1 2.3v1h6v-1c0-.5 0-1.4 1-2.3A7 7 0 0 0 12 2z" }) }) }),
|
|
18827
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-card-text", children: [
|
|
18828
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-card-head", children: t2("Style Tip") }),
|
|
18829
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-card-body", children: styleTips[tipIdx] }, tipIdx)
|
|
18830
|
-
] })
|
|
18831
|
-
] }),
|
|
18832
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-card", children: [
|
|
18833
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-card-icon ps-spotlight", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
18834
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
18835
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
|
|
18836
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
|
|
18837
|
-
] }) }),
|
|
18838
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-card-text", children: [
|
|
18839
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-card-head", children: t2("Garment Spotlight") }),
|
|
18840
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-card-body", children: garmentLine })
|
|
18841
|
-
] })
|
|
18842
|
-
] }),
|
|
18843
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-card", children: [
|
|
18844
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-card-icon ps-fact", children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M12 2v6M12 16v6M4.93 4.93l4.24 4.24M14.83 14.83l4.24 4.24M2 12h6M16 12h6M4.93 19.07l4.24-4.24M14.83 9.17l4.24-4.24" }) }) }),
|
|
18845
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-card-text", children: [
|
|
18846
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-card-head", children: t2("AI Fact") }),
|
|
18847
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-v2-card-body", children: aiFact })
|
|
18848
|
-
] })
|
|
18849
|
-
] })
|
|
18850
|
-
] })
|
|
18851
|
-
] }),
|
|
18852
|
-
onCancel && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-tryon-processing-v2-cancel", onClick: onCancel, children: t2("Cancel Generation") })
|
|
18853
|
-
] });
|
|
18854
|
-
if (variant === "panel-only") return Panel;
|
|
18855
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2", children: [
|
|
18856
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-image", children: [
|
|
18857
|
-
previewUrl && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
18858
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-processing-blur", style: { backgroundImage: `url(${previewUrl})` } }),
|
|
18859
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: previewUrl, alt: t2("Your photo"), className: "ps-tryon-processing-model" })
|
|
18860
|
-
] }),
|
|
18861
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-scan-line" }),
|
|
18862
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-scan-overlay" }),
|
|
18863
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-processing-v2-badge", children: [
|
|
18864
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-processing-v2-badge-dot", "aria-hidden": "true" }),
|
|
18865
|
-
t2("ANALYZING BODY MAP")
|
|
18866
|
-
] })
|
|
18867
|
-
] }),
|
|
18868
|
-
Panel
|
|
18869
|
-
] });
|
|
18870
|
-
}
|
|
18871
18918
|
const SKELETON_CONNECTIONS$1 = [
|
|
18872
18919
|
["leftShoulder", "rightShoulder"],
|
|
18873
18920
|
["leftShoulder", "leftElbow"],
|
|
@@ -18953,30 +19000,6 @@ function MobileScanningView({
|
|
|
18953
19000
|
onSwitchToManual,
|
|
18954
19001
|
t: t2
|
|
18955
19002
|
}) {
|
|
18956
|
-
if (tryOnProcessing) {
|
|
18957
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msc-root", children: [
|
|
18958
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18959
|
-
EngagingTryOnView,
|
|
18960
|
-
{
|
|
18961
|
-
previewUrl,
|
|
18962
|
-
productMaterial,
|
|
18963
|
-
productDescription,
|
|
18964
|
-
onCancel: onCancelTryOn,
|
|
18965
|
-
t: t2
|
|
18966
|
-
}
|
|
18967
|
-
),
|
|
18968
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-bpm-bottom", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
18969
|
-
MobileBottomTabs,
|
|
18970
|
-
{
|
|
18971
|
-
mode: "scan",
|
|
18972
|
-
onSwitchToManual,
|
|
18973
|
-
onSwitchToScan: () => {
|
|
18974
|
-
},
|
|
18975
|
-
t: t2
|
|
18976
|
-
}
|
|
18977
|
-
) })
|
|
18978
|
-
] });
|
|
18979
|
-
}
|
|
18980
19003
|
const displayImage = previewUrl || productImage || "";
|
|
18981
19004
|
const isPhotoMode = !!previewUrl;
|
|
18982
19005
|
const stages = isPhotoMode ? [
|
|
@@ -18996,11 +19019,18 @@ function MobileScanningView({
|
|
|
18996
19019
|
const img = e.currentTarget;
|
|
18997
19020
|
setDims({ w: img.naturalWidth || img.offsetWidth, h: img.naturalHeight || img.offsetHeight });
|
|
18998
19021
|
};
|
|
19022
|
+
const TOTAL_MS = 6e3;
|
|
19023
|
+
const LAST_HOLD_MS = 1e3;
|
|
19024
|
+
const startRef = reactExports.useRef(Date.now());
|
|
18999
19025
|
const [stageIdx, setStageIdx] = reactExports.useState(0);
|
|
19000
19026
|
reactExports.useEffect(() => {
|
|
19027
|
+
const stepMs = (TOTAL_MS - LAST_HOLD_MS) / Math.max(1, stages.length - 1);
|
|
19001
19028
|
const id2 = setInterval(() => {
|
|
19002
|
-
|
|
19003
|
-
|
|
19029
|
+
const elapsed = Date.now() - startRef.current;
|
|
19030
|
+
const idx = Math.min(stages.length - 1, Math.floor(elapsed / stepMs));
|
|
19031
|
+
setStageIdx((prev) => prev === idx ? prev : idx);
|
|
19032
|
+
if (idx >= stages.length - 1) clearInterval(id2);
|
|
19033
|
+
}, 100);
|
|
19004
19034
|
return () => clearInterval(id2);
|
|
19005
19035
|
}, [stages.length]);
|
|
19006
19036
|
reactExports.useEffect(() => {
|
|
@@ -19235,6 +19265,132 @@ function MultiSectionMobile({
|
|
|
19235
19265
|
sizeGuide ? null : null
|
|
19236
19266
|
] });
|
|
19237
19267
|
}
|
|
19268
|
+
const TARGET_SECONDS = 22;
|
|
19269
|
+
function TryOnGenerationBadge({
|
|
19270
|
+
tryOnStartedAt,
|
|
19271
|
+
t: t2
|
|
19272
|
+
}) {
|
|
19273
|
+
const [, force] = reactExports.useState(0);
|
|
19274
|
+
reactExports.useEffect(() => {
|
|
19275
|
+
if (tryOnStartedAt == null) return;
|
|
19276
|
+
const id2 = setInterval(() => force((v2) => v2 + 1), 200);
|
|
19277
|
+
return () => clearInterval(id2);
|
|
19278
|
+
}, [tryOnStartedAt]);
|
|
19279
|
+
if (tryOnStartedAt == null) return null;
|
|
19280
|
+
const elapsed = (Date.now() - tryOnStartedAt) / 1e3;
|
|
19281
|
+
const pct = Math.min(95, elapsed / TARGET_SECONDS * 100);
|
|
19282
|
+
const pctRounded = Math.round(pct);
|
|
19283
|
+
const remaining = Math.max(0, TARGET_SECONDS - Math.floor(elapsed));
|
|
19284
|
+
const etaText = elapsed >= TARGET_SECONDS ? t2("almost done") : `~${remaining}s ${t2("left")}`;
|
|
19285
|
+
const statuses = [
|
|
19286
|
+
t2("Preparing your image"),
|
|
19287
|
+
t2("Analyzing body proportions"),
|
|
19288
|
+
t2("Mapping garment to body"),
|
|
19289
|
+
t2("Refining drape and shadows"),
|
|
19290
|
+
t2("Almost done")
|
|
19291
|
+
];
|
|
19292
|
+
const stepIdx = Math.min(
|
|
19293
|
+
statuses.length - 1,
|
|
19294
|
+
Math.floor(elapsed / TARGET_SECONDS * statuses.length)
|
|
19295
|
+
);
|
|
19296
|
+
const status = statuses[stepIdx];
|
|
19297
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge", role: "status", "aria-live": "polite", children: [
|
|
19298
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-row", children: [
|
|
19299
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-spinner", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", width: "22", height: "22", children: [
|
|
19300
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: "ps-tryon-badge-grad", x1: "0", y1: "0", x2: "1", y2: "1", children: [
|
|
19301
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "0%", stopColor: "#3B82F6" }),
|
|
19302
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "100%", stopColor: "#2563EB" })
|
|
19303
|
+
] }) }),
|
|
19304
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "9", fill: "none", stroke: "rgba(59,130,246,0.18)", strokeWidth: "2.4" }),
|
|
19305
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19306
|
+
"circle",
|
|
19307
|
+
{
|
|
19308
|
+
cx: "12",
|
|
19309
|
+
cy: "12",
|
|
19310
|
+
r: "9",
|
|
19311
|
+
fill: "none",
|
|
19312
|
+
stroke: "url(#ps-tryon-badge-grad)",
|
|
19313
|
+
strokeWidth: "2.4",
|
|
19314
|
+
strokeLinecap: "round",
|
|
19315
|
+
strokeDasharray: "56.5",
|
|
19316
|
+
strokeDashoffset: "38"
|
|
19317
|
+
}
|
|
19318
|
+
)
|
|
19319
|
+
] }) }),
|
|
19320
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-title", children: t2("Generating your look...") }),
|
|
19321
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-pct", children: [
|
|
19322
|
+
pctRounded,
|
|
19323
|
+
"%"
|
|
19324
|
+
] })
|
|
19325
|
+
] }),
|
|
19326
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-badge-bar", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-badge-bar-fill", style: { width: `${pctRounded}%` } }) }),
|
|
19327
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-foot", children: [
|
|
19328
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-status", children: [
|
|
19329
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-status-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
19330
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "6", y1: "10", x2: "6", y2: "14" }),
|
|
19331
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "6", x2: "10", y2: "18" }),
|
|
19332
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "9", x2: "14", y2: "15" }),
|
|
19333
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "18", y1: "11", x2: "18", y2: "13" })
|
|
19334
|
+
] }) }),
|
|
19335
|
+
status
|
|
19336
|
+
] }),
|
|
19337
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-eta", children: [
|
|
19338
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
19339
|
+
"svg",
|
|
19340
|
+
{
|
|
19341
|
+
width: "11",
|
|
19342
|
+
height: "11",
|
|
19343
|
+
viewBox: "0 0 24 24",
|
|
19344
|
+
fill: "none",
|
|
19345
|
+
stroke: "currentColor",
|
|
19346
|
+
strokeWidth: "2",
|
|
19347
|
+
strokeLinecap: "round",
|
|
19348
|
+
strokeLinejoin: "round",
|
|
19349
|
+
"aria-hidden": "true",
|
|
19350
|
+
children: [
|
|
19351
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
19352
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("polyline", { points: "12 6 12 12 16 14" })
|
|
19353
|
+
]
|
|
19354
|
+
}
|
|
19355
|
+
),
|
|
19356
|
+
etaText
|
|
19357
|
+
] })
|
|
19358
|
+
] })
|
|
19359
|
+
] });
|
|
19360
|
+
}
|
|
19361
|
+
const PER_SLIDE = 3;
|
|
19362
|
+
const CYCLE_MS = 4e3;
|
|
19363
|
+
function ProductPhotoCarouselCard({
|
|
19364
|
+
photos,
|
|
19365
|
+
productTitle,
|
|
19366
|
+
t: t2
|
|
19367
|
+
}) {
|
|
19368
|
+
const [groupIdx, setGroupIdx] = reactExports.useState(0);
|
|
19369
|
+
const totalGroups = Math.max(1, Math.ceil(photos.length / PER_SLIDE));
|
|
19370
|
+
reactExports.useEffect(() => {
|
|
19371
|
+
if (totalGroups < 2) return;
|
|
19372
|
+
const id2 = setInterval(() => setGroupIdx((v2) => (v2 + 1) % totalGroups), CYCLE_MS);
|
|
19373
|
+
return () => clearInterval(id2);
|
|
19374
|
+
}, [totalGroups]);
|
|
19375
|
+
if (!photos || photos.length === 0) return null;
|
|
19376
|
+
const start = groupIdx * PER_SLIDE;
|
|
19377
|
+
const slide = photos.slice(start, start + PER_SLIDE);
|
|
19378
|
+
while (slide.length < PER_SLIDE && photos.length >= PER_SLIDE) {
|
|
19379
|
+
slide.push(photos[(start + slide.length) % photos.length]);
|
|
19380
|
+
}
|
|
19381
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-photo-strip", role: "group", "aria-label": t2("Product photos"), children: [
|
|
19382
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-photo-strip-head", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-photo-strip-badge", children: [
|
|
19383
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "11", height: "11", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
|
|
19384
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
19385
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9", cy: "9", r: "2" }),
|
|
19386
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
|
|
19387
|
+
] }),
|
|
19388
|
+
t2("Gallery")
|
|
19389
|
+
] }) }),
|
|
19390
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-photo-strip-row", children: slide.map((src, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-photo-strip-cell", children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src, alt: productTitle || "", draggable: false }) }, `${groupIdx}-${i}`)) }, groupIdx),
|
|
19391
|
+
totalGroups > 1 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-photo-strip-dots", "aria-hidden": "true", children: Array.from({ length: totalGroups }).map((_, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `ps-tryon-photo-strip-dot${i === groupIdx ? " is-active" : ""}` }, i)) })
|
|
19392
|
+
] });
|
|
19393
|
+
}
|
|
19238
19394
|
function garmentIconForSection(name) {
|
|
19239
19395
|
const n2 = name.toLowerCase();
|
|
19240
19396
|
if (n2.includes("jacket") || n2.includes("blazer") || n2.includes("coat")) return garmentJacketImg;
|
|
@@ -19258,62 +19414,6 @@ const SKELETON_CONNECTIONS = [
|
|
|
19258
19414
|
["rightHip", "rightKnee"],
|
|
19259
19415
|
["rightKnee", "rightAnkle"]
|
|
19260
19416
|
];
|
|
19261
|
-
const TRYON_TARGET_SECONDS = 22;
|
|
19262
|
-
const TRYON_RING_RADIUS = 27;
|
|
19263
|
-
const TRYON_RING_CIRC = 2 * Math.PI * TRYON_RING_RADIUS;
|
|
19264
|
-
function TryOnProgress({ t: t2, isActive }) {
|
|
19265
|
-
const startRef = reactExports.useRef(null);
|
|
19266
|
-
const ringRef = reactExports.useRef(null);
|
|
19267
|
-
const barRef = reactExports.useRef(null);
|
|
19268
|
-
const etaRef = reactExports.useRef(null);
|
|
19269
|
-
const pctRef = reactExports.useRef(null);
|
|
19270
|
-
reactExports.useEffect(() => {
|
|
19271
|
-
if (!isActive) {
|
|
19272
|
-
startRef.current = null;
|
|
19273
|
-
return;
|
|
19274
|
-
}
|
|
19275
|
-
startRef.current = Date.now();
|
|
19276
|
-
const id2 = setInterval(() => {
|
|
19277
|
-
const start = startRef.current || Date.now();
|
|
19278
|
-
const elapsed = (Date.now() - start) / 1e3;
|
|
19279
|
-
const pct = Math.min(95, elapsed / TRYON_TARGET_SECONDS * 100);
|
|
19280
|
-
const val = Math.round(pct);
|
|
19281
|
-
if (barRef.current) barRef.current.style.width = `${val}%`;
|
|
19282
|
-
if (pctRef.current) pctRef.current.textContent = `${val}%`;
|
|
19283
|
-
if (ringRef.current) {
|
|
19284
|
-
ringRef.current.style.strokeDashoffset = String(TRYON_RING_CIRC * (1 - pct / 100));
|
|
19285
|
-
}
|
|
19286
|
-
if (etaRef.current) {
|
|
19287
|
-
const remaining = Math.max(0, TRYON_TARGET_SECONDS - Math.floor(elapsed));
|
|
19288
|
-
etaRef.current.textContent = elapsed >= TRYON_TARGET_SECONDS ? "•••" : `~${remaining}s`;
|
|
19289
|
-
}
|
|
19290
|
-
}, 200);
|
|
19291
|
-
return () => clearInterval(id2);
|
|
19292
|
-
}, [isActive]);
|
|
19293
|
-
if (!isActive) return null;
|
|
19294
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-progress-wrap", children: [
|
|
19295
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-progress-ring", children: [
|
|
19296
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "64", height: "64", viewBox: "0 0 64 64", "aria-hidden": "true", children: [
|
|
19297
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "32", cy: "32", r: TRYON_RING_RADIUS, className: "ps-tryon-progress-ring-track" }),
|
|
19298
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19299
|
-
"circle",
|
|
19300
|
-
{
|
|
19301
|
-
ref: ringRef,
|
|
19302
|
-
cx: "32",
|
|
19303
|
-
cy: "32",
|
|
19304
|
-
r: TRYON_RING_RADIUS,
|
|
19305
|
-
className: "ps-tryon-progress-ring-fill",
|
|
19306
|
-
strokeDasharray: TRYON_RING_CIRC,
|
|
19307
|
-
strokeDashoffset: TRYON_RING_CIRC
|
|
19308
|
-
}
|
|
19309
|
-
)
|
|
19310
|
-
] }),
|
|
19311
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { ref: etaRef, className: "ps-tryon-progress-eta", children: `~${TRYON_TARGET_SECONDS}s` })
|
|
19312
|
-
] }),
|
|
19313
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-progress-bar-wrap", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: barRef, className: "ps-tryon-progress-bar-fill" }) }),
|
|
19314
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { ref: pctRef, className: "ps-tryon-progress-pct", children: "0%" })
|
|
19315
|
-
] });
|
|
19316
|
-
}
|
|
19317
19417
|
function FaceOverlay({
|
|
19318
19418
|
landmarks,
|
|
19319
19419
|
imgWidth,
|
|
@@ -19440,14 +19540,20 @@ function StageCycler({
|
|
|
19440
19540
|
{ title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the size guide.") },
|
|
19441
19541
|
{ title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
|
|
19442
19542
|
];
|
|
19543
|
+
const TOTAL_MS = 6e3;
|
|
19544
|
+
const LAST_HOLD_MS = 1e3;
|
|
19545
|
+
const startRef = reactExports.useRef(Date.now());
|
|
19443
19546
|
const [idx, setIdx] = reactExports.useState(0);
|
|
19444
19547
|
reactExports.useEffect(() => {
|
|
19445
|
-
|
|
19548
|
+
const stepMs = (TOTAL_MS - LAST_HOLD_MS) / Math.max(1, sizingStages.length - 1);
|
|
19446
19549
|
const id2 = setInterval(() => {
|
|
19447
|
-
|
|
19448
|
-
|
|
19550
|
+
const elapsed = Date.now() - startRef.current;
|
|
19551
|
+
const next = Math.min(sizingStages.length - 1, Math.floor(elapsed / stepMs));
|
|
19552
|
+
setIdx((prev) => prev === next ? prev : next);
|
|
19553
|
+
if (next >= sizingStages.length - 1) clearInterval(id2);
|
|
19554
|
+
}, 100);
|
|
19449
19555
|
return () => clearInterval(id2);
|
|
19450
|
-
}, [
|
|
19556
|
+
}, [sizingStages.length]);
|
|
19451
19557
|
const current = sizingStages[idx] ?? sizingStages[0];
|
|
19452
19558
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage", style: { alignSelf: "center", marginTop: "auto", marginBottom: "auto" }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-msc-stage-slot", children: [
|
|
19453
19559
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage-title", children: current.title }),
|
|
@@ -19721,19 +19827,11 @@ function SectionDetailView({
|
|
|
19721
19827
|
internationalSizes,
|
|
19722
19828
|
continueLabel,
|
|
19723
19829
|
renderRaw = false,
|
|
19724
|
-
sectionFound
|
|
19725
|
-
onSelectForTryOn,
|
|
19726
|
-
onRegenerateTryOn,
|
|
19727
|
-
pendingOverride,
|
|
19728
|
-
retryLoading,
|
|
19729
|
-
retryStartedAt
|
|
19830
|
+
sectionFound
|
|
19730
19831
|
}) {
|
|
19731
19832
|
const recSize = sectionResult?.recommendedSize || "";
|
|
19732
|
-
const [selectedSize, setSelectedSize] = reactExports.useState(
|
|
19733
|
-
pendingOverride?.selectedSize && pendingOverride.selectedSize !== (sectionResult?.recommendedSize || "") ? pendingOverride.selectedSize : null
|
|
19734
|
-
);
|
|
19833
|
+
const [selectedSize, setSelectedSize] = reactExports.useState(null);
|
|
19735
19834
|
const tryOnElapsedS = useElapsedSeconds(tryOnStartedAt ?? null);
|
|
19736
|
-
const retryElapsedS = useElapsedSeconds(retryStartedAt ?? null);
|
|
19737
19835
|
const unitLblLower = unitLbl.toLowerCase();
|
|
19738
19836
|
const displayUnitId = unitLblLower.includes("mm") ? "mm" : unitLblLower.includes("cm") ? "cm" : "in";
|
|
19739
19837
|
const fromUnit = chartUnit || displayUnitId;
|
|
@@ -19746,9 +19844,7 @@ function SectionDetailView({
|
|
|
19746
19844
|
const countryOptions = internationalSizes ? Object.keys(internationalSizes) : [];
|
|
19747
19845
|
const [selectedCountry, setSelectedCountry] = reactExports.useState(null);
|
|
19748
19846
|
const recLength = lengthEntry?.secResult?.recommendedSize || "";
|
|
19749
|
-
const [selectedLength, setSelectedLength] = reactExports.useState(
|
|
19750
|
-
pendingOverride?.selectedLength && pendingOverride.selectedLength !== recLength ? pendingOverride.selectedLength : null
|
|
19751
|
-
);
|
|
19847
|
+
const [selectedLength, setSelectedLength] = reactExports.useState(null);
|
|
19752
19848
|
const lengthSizes = reactExports.useMemo(() => {
|
|
19753
19849
|
if (!lengthEntry) return [];
|
|
19754
19850
|
const sec = lengthEntry.section;
|
|
@@ -19975,8 +20071,8 @@ function SectionDetailView({
|
|
|
19975
20071
|
const userInColUnit = colIsCm && userIsInches ? +(userNum2 * 2.54).toFixed(1) : !colIsCm && !userIsInches ? +(userNum2 * 2.54).toFixed(1) : userNum2;
|
|
19976
20072
|
const range2 = rMaxRaw - rMinRaw;
|
|
19977
20073
|
const threshold2 = range2 > 0 ? range2 * 0.5 : rMinRaw * 0.05 || 3;
|
|
19978
|
-
const
|
|
19979
|
-
if (userInColUnit
|
|
20074
|
+
const tol = colIsCm ? 2.54 : 1;
|
|
20075
|
+
if (userInColUnit > rMinRaw - tol && userInColUnit < rMaxRaw + tol) fit2 = "good";
|
|
19980
20076
|
else if (userInColUnit < rMinRaw) {
|
|
19981
20077
|
const diff = rMinRaw - userInColUnit;
|
|
19982
20078
|
fit2 = diff > threshold2 * 2 ? "too-long" : diff > threshold2 ? "long" : "a-bit-long";
|
|
@@ -20009,8 +20105,10 @@ function SectionDetailView({
|
|
|
20009
20105
|
const measLower = m2.measurement.toLowerCase();
|
|
20010
20106
|
const isDirectional = /length|inseam|sleeve|hem|rise/.test(measLower);
|
|
20011
20107
|
let fit;
|
|
20012
|
-
const
|
|
20013
|
-
|
|
20108
|
+
const perfectTol = chartUnit === "cm" ? 2.54 : chartUnit === "mm" ? 25.4 : 1;
|
|
20109
|
+
const lowBound = rMin - perfectTol;
|
|
20110
|
+
const highBound = rMax + perfectTol;
|
|
20111
|
+
if (userNum > lowBound && userNum < highBound) {
|
|
20014
20112
|
fit = "good";
|
|
20015
20113
|
} else if (isDirectional) {
|
|
20016
20114
|
const diff = userNum > rMax ? userNum - rMax : rMin - userNum;
|
|
@@ -20057,65 +20155,6 @@ function SectionDetailView({
|
|
|
20057
20155
|
const start = Math.max(0, Math.min(lengthOptions.length - 3, idx - 1));
|
|
20058
20156
|
return lengthOptions.slice(start, start + 3);
|
|
20059
20157
|
})();
|
|
20060
|
-
const autoCommitInitialMount = reactExports.useRef(true);
|
|
20061
|
-
reactExports.useLayoutEffect(() => {
|
|
20062
|
-
if (autoCommitInitialMount.current) {
|
|
20063
|
-
autoCommitInitialMount.current = false;
|
|
20064
|
-
return;
|
|
20065
|
-
}
|
|
20066
|
-
if (!onSelectForTryOn) return;
|
|
20067
|
-
const effSize = displaySize;
|
|
20068
|
-
const effLength = selectedLength || backendLength || "";
|
|
20069
|
-
const hasSizePick = !!selectedSize && selectedSize !== recSize;
|
|
20070
|
-
const hasLengthPick = !!selectedLength && selectedLength !== backendLength;
|
|
20071
|
-
if (!hasSizePick && !hasLengthPick) {
|
|
20072
|
-
onSelectForTryOn(sectionName, null);
|
|
20073
|
-
return;
|
|
20074
|
-
}
|
|
20075
|
-
const mainDetails = sectionResult?.matchDetails || [];
|
|
20076
|
-
const lengthMeasurements = new Set(
|
|
20077
|
-
(lengthEntry?.secResult?.matchDetails || []).map((m2) => m2.measurement.toLowerCase())
|
|
20078
|
-
);
|
|
20079
|
-
const overrideMd = mainDetails.length ? mainDetails.map((m2) => {
|
|
20080
|
-
const measLc = m2.measurement.toLowerCase();
|
|
20081
|
-
if (lengthMeasurements.has(measLc) && lengthEntry) {
|
|
20082
|
-
const sec = lengthEntry.section;
|
|
20083
|
-
const sizeCol = sec.headers.findIndex((h) => /size|length/i.test(h.trim()));
|
|
20084
|
-
const sIdx = sizeCol >= 0 ? sizeCol : 0;
|
|
20085
|
-
const targetCol = sec.headers.findIndex((h) => {
|
|
20086
|
-
const hLc = h.toLowerCase().replace(/\s*\(.*?\)\s*/g, "").trim();
|
|
20087
|
-
return !!hLc && (hLc === measLc || hLc.includes(measLc) || measLc.includes(hLc));
|
|
20088
|
-
});
|
|
20089
|
-
if (targetCol < 0) return m2;
|
|
20090
|
-
const row = sec.rows.find((r2) => cellValFn(r2, sIdx, sec.headers[sIdx]) === effLength);
|
|
20091
|
-
if (!row) return m2;
|
|
20092
|
-
const cell = cellValFn(row, targetCol, sec.headers[targetCol]);
|
|
20093
|
-
return cell ? { ...m2, chartRange: cell } : m2;
|
|
20094
|
-
}
|
|
20095
|
-
const alt = chartRangeFor(m2.measurement, effSize);
|
|
20096
|
-
if (alt?.range) return { ...m2, chartRange: alt.range };
|
|
20097
|
-
return m2;
|
|
20098
|
-
}) : void 0;
|
|
20099
|
-
const label = effLength ? `${effSize} / ${effLength}` : effSize;
|
|
20100
|
-
console.log(`[ps-sdk:auto-commit] section="${sectionName}" label="${label}"`, {
|
|
20101
|
-
selectedSize,
|
|
20102
|
-
selectedLength,
|
|
20103
|
-
recSize,
|
|
20104
|
-
backendLength,
|
|
20105
|
-
overrideMdPreview: overrideMd?.map((m2) => ({
|
|
20106
|
-
area: m2.measurement,
|
|
20107
|
-
userValue: m2.userValue,
|
|
20108
|
-
chartRange: m2.chartRange
|
|
20109
|
-
}))
|
|
20110
|
-
});
|
|
20111
|
-
onSelectForTryOn(sectionName, {
|
|
20112
|
-
sectionName,
|
|
20113
|
-
selectedSize: effSize,
|
|
20114
|
-
selectedLength: hasLengthPick ? effLength : void 0,
|
|
20115
|
-
displayLabel: label,
|
|
20116
|
-
matchDetails: overrideMd
|
|
20117
|
-
});
|
|
20118
|
-
}, [selectedSize, selectedLength]);
|
|
20119
20158
|
if (isMobileProp) {
|
|
20120
20159
|
const cleanSectionName = sectionName.replace(/\s*[—–-]\s*.*/g, "");
|
|
20121
20160
|
const measurementDesc = (area) => {
|
|
@@ -20599,169 +20638,7 @@ function SectionDetailView({
|
|
|
20599
20638
|
s
|
|
20600
20639
|
);
|
|
20601
20640
|
}) })
|
|
20602
|
-
] })
|
|
20603
|
-
(onRegenerateTryOn || onSelectForTryOn && (!isRecommended || selectedLength && selectedLength !== backendLength)) && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { marginTop: "0.6vw", marginBottom: "0.2vw" }, children: (() => {
|
|
20604
|
-
const effSize = displaySize;
|
|
20605
|
-
const effLength = selectedLength || backendLength || "";
|
|
20606
|
-
const hasLengthPick = !!(selectedLength && selectedLength !== backendLength);
|
|
20607
|
-
const label = effLength ? `${effSize} / ${effLength}` : effSize;
|
|
20608
|
-
const buildOverrideMatchDetails = () => {
|
|
20609
|
-
const mainDetails = sectionResult?.matchDetails || [];
|
|
20610
|
-
if (!mainDetails.length) return void 0;
|
|
20611
|
-
const lengthMeasurements = new Set(
|
|
20612
|
-
(lengthEntry?.secResult?.matchDetails || []).map((m2) => m2.measurement.toLowerCase())
|
|
20613
|
-
);
|
|
20614
|
-
const out = mainDetails.map((m2) => {
|
|
20615
|
-
const measLc = m2.measurement.toLowerCase();
|
|
20616
|
-
if (lengthMeasurements.has(measLc) && lengthEntry) {
|
|
20617
|
-
const numericPick = effLength && !Number.isNaN(parseFloat(effLength)) ? effLength : null;
|
|
20618
|
-
if (numericPick) {
|
|
20619
|
-
return { ...m2, chartRange: numericPick };
|
|
20620
|
-
}
|
|
20621
|
-
const sec = lengthEntry.section;
|
|
20622
|
-
const sizeCol = sec.headers.findIndex((h) => /size|length/i.test(h.trim()));
|
|
20623
|
-
const sIdx = sizeCol >= 0 ? sizeCol : 0;
|
|
20624
|
-
const targetCol = sec.headers.findIndex((h) => {
|
|
20625
|
-
const hLc = h.toLowerCase().replace(/\s*\(.*?\)\s*/g, "").trim();
|
|
20626
|
-
return !!hLc && (hLc === measLc || hLc.includes(measLc) || measLc.includes(hLc));
|
|
20627
|
-
});
|
|
20628
|
-
if (targetCol < 0) return m2;
|
|
20629
|
-
const row = sec.rows.find((r2) => cellValFn(r2, sIdx, sec.headers[sIdx]) === effLength);
|
|
20630
|
-
if (!row) return m2;
|
|
20631
|
-
const cell = cellValFn(row, targetCol, sec.headers[targetCol]);
|
|
20632
|
-
return cell ? { ...m2, chartRange: cell } : m2;
|
|
20633
|
-
}
|
|
20634
|
-
const alt = chartRangeFor(m2.measurement, effSize);
|
|
20635
|
-
if (alt?.range) return { ...m2, chartRange: alt.range };
|
|
20636
|
-
return m2;
|
|
20637
|
-
});
|
|
20638
|
-
if (effLength && Number.isNaN(parseFloat(effLength))) {
|
|
20639
|
-
out.push({
|
|
20640
|
-
measurement: "Length",
|
|
20641
|
-
userValue: "",
|
|
20642
|
-
chartRange: effLength,
|
|
20643
|
-
fit: "good"
|
|
20644
|
-
});
|
|
20645
|
-
}
|
|
20646
|
-
return out;
|
|
20647
|
-
};
|
|
20648
|
-
const isStored = pendingOverride?.selectedSize === effSize;
|
|
20649
|
-
if (onRegenerateTryOn) {
|
|
20650
|
-
const isRegenerating = !!retryLoading;
|
|
20651
|
-
const TARGET_S = 22;
|
|
20652
|
-
const countdownS = isRegenerating ? Math.max(0, TARGET_S - retryElapsedS) : TARGET_S;
|
|
20653
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
20654
|
-
"button",
|
|
20655
|
-
{
|
|
20656
|
-
type: "button",
|
|
20657
|
-
"data-ps-regen": "1",
|
|
20658
|
-
disabled: isRegenerating,
|
|
20659
|
-
onClick: () => {
|
|
20660
|
-
const md2 = buildOverrideMatchDetails();
|
|
20661
|
-
onRegenerateTryOn({
|
|
20662
|
-
sectionName,
|
|
20663
|
-
selectedSize: effSize,
|
|
20664
|
-
selectedLength: hasLengthPick ? effLength : void 0,
|
|
20665
|
-
displayLabel: label,
|
|
20666
|
-
matchDetails: md2
|
|
20667
|
-
});
|
|
20668
|
-
},
|
|
20669
|
-
style: {
|
|
20670
|
-
width: "100%",
|
|
20671
|
-
padding: "0.55vw 0.8vw",
|
|
20672
|
-
borderRadius: "0.45vw",
|
|
20673
|
-
fontSize: "0.7vw",
|
|
20674
|
-
fontWeight: 700,
|
|
20675
|
-
background: "var(--ps-accent)",
|
|
20676
|
-
color: "#FFFFFF",
|
|
20677
|
-
border: "1.5px solid var(--ps-accent)",
|
|
20678
|
-
cursor: isRegenerating ? "progress" : "pointer",
|
|
20679
|
-
fontFamily: "inherit",
|
|
20680
|
-
display: "flex",
|
|
20681
|
-
alignItems: "center",
|
|
20682
|
-
justifyContent: "center",
|
|
20683
|
-
gap: "0.4vw",
|
|
20684
|
-
position: "relative",
|
|
20685
|
-
overflow: "hidden"
|
|
20686
|
-
},
|
|
20687
|
-
children: [
|
|
20688
|
-
isRegenerating && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20689
|
-
"div",
|
|
20690
|
-
{
|
|
20691
|
-
className: "ps-tryon-regen-fill",
|
|
20692
|
-
"aria-hidden": "true"
|
|
20693
|
-
},
|
|
20694
|
-
retryStartedAt ?? "regen"
|
|
20695
|
-
),
|
|
20696
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { position: "relative", zIndex: 1 }, children: isRegenerating ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
20697
|
-
t2("Generating new try-on…"),
|
|
20698
|
-
" ",
|
|
20699
|
-
countdownS,
|
|
20700
|
-
"s"
|
|
20701
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
20702
|
-
t2("Try It On"),
|
|
20703
|
-
" ",
|
|
20704
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { style: { fontSize: "0.65vw", opacity: 0.9 }, children: [
|
|
20705
|
-
"(",
|
|
20706
|
-
label,
|
|
20707
|
-
")"
|
|
20708
|
-
] })
|
|
20709
|
-
] }) })
|
|
20710
|
-
]
|
|
20711
|
-
}
|
|
20712
|
-
);
|
|
20713
|
-
}
|
|
20714
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
20715
|
-
"button",
|
|
20716
|
-
{
|
|
20717
|
-
type: "button",
|
|
20718
|
-
onClick: () => {
|
|
20719
|
-
if (!onSelectForTryOn) return;
|
|
20720
|
-
onSelectForTryOn(sectionName, isStored ? null : {
|
|
20721
|
-
sectionName,
|
|
20722
|
-
selectedSize: effSize,
|
|
20723
|
-
selectedLength: hasLengthPick ? effLength : void 0,
|
|
20724
|
-
displayLabel: label,
|
|
20725
|
-
matchDetails: buildOverrideMatchDetails()
|
|
20726
|
-
});
|
|
20727
|
-
},
|
|
20728
|
-
style: {
|
|
20729
|
-
width: "100%",
|
|
20730
|
-
padding: "0.55vw 0.8vw",
|
|
20731
|
-
borderRadius: "0.45vw",
|
|
20732
|
-
fontSize: "0.7vw",
|
|
20733
|
-
fontWeight: 700,
|
|
20734
|
-
background: isStored ? "var(--ps-accent)" : "transparent",
|
|
20735
|
-
color: isStored ? "#FFFFFF" : "var(--ps-accent)",
|
|
20736
|
-
border: `1.5px ${isStored ? "solid" : "dashed"} var(--ps-accent)`,
|
|
20737
|
-
cursor: "pointer",
|
|
20738
|
-
fontFamily: "inherit",
|
|
20739
|
-
display: "flex",
|
|
20740
|
-
alignItems: "center",
|
|
20741
|
-
justifyContent: "center",
|
|
20742
|
-
gap: "0.4vw",
|
|
20743
|
-
transition: "background 0.15s, color 0.15s"
|
|
20744
|
-
},
|
|
20745
|
-
children: isStored ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
20746
|
-
t2("Will use this on Try On"),
|
|
20747
|
-
" ",
|
|
20748
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { style: { fontSize: "0.65vw", opacity: 0.9 }, children: [
|
|
20749
|
-
"(",
|
|
20750
|
-
label,
|
|
20751
|
-
") ✓"
|
|
20752
|
-
] })
|
|
20753
|
-
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
20754
|
-
t2("Use this for Try On"),
|
|
20755
|
-
" ",
|
|
20756
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { style: { fontSize: "0.65vw", opacity: 0.75 }, children: [
|
|
20757
|
-
"(",
|
|
20758
|
-
label,
|
|
20759
|
-
")"
|
|
20760
|
-
] })
|
|
20761
|
-
] })
|
|
20762
|
-
}
|
|
20763
|
-
);
|
|
20764
|
-
})() })
|
|
20641
|
+
] })
|
|
20765
20642
|
] }) }),
|
|
20766
20643
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", paddingTop: "0.6vw", borderTop: "1px solid rgba(0,0,0,0.06)", flexShrink: 0 }, children: [
|
|
20767
20644
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-bp-back-btn", onClick: onBack, type: "button", style: { fontSize: "0.7vw" }, children: [
|
|
@@ -20837,15 +20714,13 @@ function SizeResultView({
|
|
|
20837
20714
|
sizeGuide,
|
|
20838
20715
|
resultImageUrl,
|
|
20839
20716
|
productImage,
|
|
20717
|
+
productImages,
|
|
20840
20718
|
productTitle,
|
|
20841
20719
|
productMaterial,
|
|
20842
20720
|
productDescription,
|
|
20843
20721
|
sizingUnit,
|
|
20844
20722
|
setView,
|
|
20845
20723
|
handleDownload,
|
|
20846
|
-
onRetryWithFit,
|
|
20847
|
-
retryLoading,
|
|
20848
|
-
retryStartedAt,
|
|
20849
20724
|
selectedFile,
|
|
20850
20725
|
previewUrl,
|
|
20851
20726
|
handleFileSelect,
|
|
@@ -20864,7 +20739,6 @@ function SizeResultView({
|
|
|
20864
20739
|
userHeightCm,
|
|
20865
20740
|
pendingCustomSizes: pendingCustomSizesProp,
|
|
20866
20741
|
onPendingCustomSizeChange,
|
|
20867
|
-
onRegenerateTryOn,
|
|
20868
20742
|
t: t2
|
|
20869
20743
|
}) {
|
|
20870
20744
|
const resultUnitRaw = (sizingResult?.unit || sizingUnit || "").toString().toLowerCase();
|
|
@@ -20970,9 +20844,6 @@ function SizeResultView({
|
|
|
20970
20844
|
const [poseReady, setPoseReady] = reactExports.useState(false);
|
|
20971
20845
|
const [imgDims, setImgDims] = reactExports.useState({ w: 800, h: 1200 });
|
|
20972
20846
|
const pendingCustomSizes = pendingCustomSizesProp ?? {};
|
|
20973
|
-
const setPendingCustomSize = (sectionName, override) => {
|
|
20974
|
-
onPendingCustomSizeChange?.(sectionName, override);
|
|
20975
|
-
};
|
|
20976
20847
|
const handleImgLoad = reactExports.useCallback((e) => {
|
|
20977
20848
|
const el2 = e.currentTarget;
|
|
20978
20849
|
if (el2.naturalWidth && el2.naturalHeight) {
|
|
@@ -21141,7 +21012,7 @@ function SizeResultView({
|
|
|
21141
21012
|
const prettyLength = lengthRec.replace(/\s+/g, " ").trim();
|
|
21142
21013
|
return `${baseSize} / ${prettyLength}`;
|
|
21143
21014
|
}, [lengthEntries, allSectionEntries]);
|
|
21144
|
-
|
|
21015
|
+
reactExports.useMemo(() => {
|
|
21145
21016
|
const cm = userHeightCm || 0;
|
|
21146
21017
|
if (!cm) return "";
|
|
21147
21018
|
if (unitLbl === "in") {
|
|
@@ -21153,8 +21024,8 @@ function SizeResultView({
|
|
|
21153
21024
|
return `${Math.round(cm)} cm`;
|
|
21154
21025
|
}, [userHeightCm, unitLbl]);
|
|
21155
21026
|
const hasPhoto = !!previewUrl;
|
|
21156
|
-
const isSnapProcessing = hasPhoto &&
|
|
21157
|
-
const isSizingOnly = !hasPhoto && sizingLoading
|
|
21027
|
+
const isSnapProcessing = hasPhoto && sizingLoading;
|
|
21028
|
+
const isSizingOnly = !hasPhoto && sizingLoading;
|
|
21158
21029
|
const sizingDone = !!sizingResult;
|
|
21159
21030
|
const tryOnDone = !!resultImageUrl && !tryOnProcessing;
|
|
21160
21031
|
const allDone = hasPhoto ? sizingDone && tryOnDone : sizingDone;
|
|
@@ -21221,20 +21092,12 @@ function SizeResultView({
|
|
|
21221
21092
|
onLoad: handleImgLoad
|
|
21222
21093
|
}
|
|
21223
21094
|
),
|
|
21224
|
-
|
|
21095
|
+
measurementType === "face" || measurementType === "head" ? faceLandmarks && /* @__PURE__ */ jsxRuntimeExports.jsx(FaceOverlay, { landmarks: faceLandmarks, imgWidth: imgDims.w, imgHeight: imgDims.h }) : bodyLandmarks && /* @__PURE__ */ jsxRuntimeExports.jsx(SkeletonOverlay, { landmarks: bodyLandmarks, imgWidth: imgDims.w, imgHeight: imgDims.h })
|
|
21225
21096
|
] }),
|
|
21226
21097
|
(() => {
|
|
21227
21098
|
const isFaceCategory = measurementType === "face" || measurementType === "head";
|
|
21228
21099
|
isFaceCategory ? measurementType === "head" ? t2("Detecting head") : t2("Detecting face") : t2("Detecting body pose");
|
|
21229
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-right-col", style: { display: "flex", alignItems:
|
|
21230
|
-
EngagingTryOnView,
|
|
21231
|
-
{
|
|
21232
|
-
productMaterial,
|
|
21233
|
-
productDescription,
|
|
21234
|
-
variant: "panel-only",
|
|
21235
|
-
t: t2
|
|
21236
|
-
}
|
|
21237
|
-
) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21100
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-right-col", style: { display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21238
21101
|
StageCycler,
|
|
21239
21102
|
{
|
|
21240
21103
|
category: isFaceCategory ? measurementType : "body",
|
|
@@ -21272,11 +21135,6 @@ function SizeResultView({
|
|
|
21272
21135
|
})(),
|
|
21273
21136
|
onBack: () => setActiveSection(null),
|
|
21274
21137
|
internationalSizes: entry.secResult?.internationalSizes,
|
|
21275
|
-
onSelectForTryOn: setPendingCustomSize,
|
|
21276
|
-
onRegenerateTryOn: isAccessory ? void 0 : resultImageUrl && onRegenerateTryOn ? onRegenerateTryOn : void 0,
|
|
21277
|
-
retryLoading,
|
|
21278
|
-
retryStartedAt,
|
|
21279
|
-
pendingOverride: pendingCustomSizes[entry.name] ?? null,
|
|
21280
21138
|
productImage: resultImageUrl || productImage,
|
|
21281
21139
|
productTitle,
|
|
21282
21140
|
isMobile: true,
|
|
@@ -21314,10 +21172,7 @@ function SizeResultView({
|
|
|
21314
21172
|
] });
|
|
21315
21173
|
}
|
|
21316
21174
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2", children: [
|
|
21317
|
-
/* @__PURE__ */ jsxRuntimeExports.
|
|
21318
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: resultImageUrl || productImage, alt: productTitle, className: "ps-tryon-v2-bg-img" }),
|
|
21319
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!retryLoading && !!resultImageUrl })
|
|
21320
|
-
] }),
|
|
21175
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: resultImageUrl || productImage, alt: productTitle, className: "ps-tryon-v2-bg-img" }) }),
|
|
21321
21176
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel", children: [
|
|
21322
21177
|
mismatchNotice,
|
|
21323
21178
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -21339,11 +21194,6 @@ function SizeResultView({
|
|
|
21339
21194
|
})(),
|
|
21340
21195
|
onBack: () => setActiveSection(null),
|
|
21341
21196
|
internationalSizes: entry.secResult?.internationalSizes,
|
|
21342
|
-
onSelectForTryOn: setPendingCustomSize,
|
|
21343
|
-
onRegenerateTryOn: isAccessory ? void 0 : resultImageUrl && onRegenerateTryOn ? onRegenerateTryOn : void 0,
|
|
21344
|
-
retryLoading,
|
|
21345
|
-
retryStartedAt,
|
|
21346
|
-
pendingOverride: pendingCustomSizes[entry.name] ?? null,
|
|
21347
21197
|
t: t2
|
|
21348
21198
|
}
|
|
21349
21199
|
)
|
|
@@ -21413,11 +21263,8 @@ function SizeResultView({
|
|
|
21413
21263
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2", children: [
|
|
21414
21264
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
|
|
21415
21265
|
/* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage, alt: productTitle, className: "ps-tryon-v2-bg-img", onLoad: handleImgLoad }),
|
|
21416
|
-
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.
|
|
21417
|
-
|
|
21418
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TryOnProgress, { t: t2, isActive: true })
|
|
21419
|
-
] }),
|
|
21420
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!retryLoading && !!resultImageUrl && !tryOnProcessing || !!tryOnProcessing }),
|
|
21266
|
+
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
|
|
21267
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing }),
|
|
21421
21268
|
resultImageUrl && !tryOnProcessing && poseReady && poseLines && /* @__PURE__ */ jsxRuntimeExports.jsx(MeasurementOverlay, { lines: poseLines, fitRows: (() => {
|
|
21422
21269
|
const all = [...sizingResult?.matchDetails || []];
|
|
21423
21270
|
if (sizingResult?.sections) {
|
|
@@ -21483,11 +21330,15 @@ function SizeResultView({
|
|
|
21483
21330
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21484
21331
|
"span",
|
|
21485
21332
|
{
|
|
21486
|
-
className:
|
|
21487
|
-
|
|
21488
|
-
children: isOverridden ? t2("your selection · not recommended") : heightLineLabel ? `${t2("recommended")} · ${heightLineLabel}` : t2("recommended")
|
|
21333
|
+
className: `ps-tryon-sr-card-v2-rec-pill${isOverridden ? " is-overridden" : ""}`,
|
|
21334
|
+
children: isOverridden ? t2("YOUR SELECTION") : t2("RECOMMENDED")
|
|
21489
21335
|
}
|
|
21490
|
-
)
|
|
21336
|
+
),
|
|
21337
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-sr-card-v2-view", children: [
|
|
21338
|
+
t2("VIEW DETAILS"),
|
|
21339
|
+
" ",
|
|
21340
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: "›" })
|
|
21341
|
+
] })
|
|
21491
21342
|
] }),
|
|
21492
21343
|
sectionImg && /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: sectionImg, alt: name, className: "ps-tryon-sr-card-v2-img" })
|
|
21493
21344
|
] }, name);
|
|
@@ -21578,11 +21429,6 @@ function SizeResultView({
|
|
|
21578
21429
|
},
|
|
21579
21430
|
backLabel: t2("Back"),
|
|
21580
21431
|
internationalSizes: sizingResult?.internationalSizes,
|
|
21581
|
-
onSelectForTryOn: setPendingCustomSize,
|
|
21582
|
-
onRegenerateTryOn: isAccessory ? void 0 : resultImageUrl && onRegenerateTryOn ? onRegenerateTryOn : void 0,
|
|
21583
|
-
retryLoading,
|
|
21584
|
-
retryStartedAt,
|
|
21585
|
-
pendingOverride: pendingCustomSizes[sectionName] ?? null,
|
|
21586
21432
|
onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
|
|
21587
21433
|
continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
|
|
21588
21434
|
tryOnProcessing,
|
|
@@ -21612,50 +21458,158 @@ function SizeResultView({
|
|
|
21612
21458
|
}
|
|
21613
21459
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2", children: [
|
|
21614
21460
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
|
|
21615
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21616
|
-
|
|
21461
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21462
|
+
"img",
|
|
21463
|
+
{
|
|
21464
|
+
src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
|
|
21465
|
+
alt: productTitle,
|
|
21466
|
+
className: "ps-tryon-v2-bg-img",
|
|
21467
|
+
onLoad: handleImgLoad
|
|
21468
|
+
}
|
|
21469
|
+
),
|
|
21470
|
+
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
|
|
21471
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing }),
|
|
21472
|
+
resultImageUrl && !tryOnProcessing && poseReady && poseLines && /* @__PURE__ */ jsxRuntimeExports.jsx(MeasurementOverlay, { lines: poseLines, fitRows: (sizingResult?.matchDetails || []).map((m2) => ({ area: m2.measurement, userNum: parseFloat(m2.userValue) || 0, chartLabel: m2.chartRange || "", fit: m2.fit })), show: showLines, imgWidth: imgDims.w, imgHeight: imgDims.h }),
|
|
21617
21473
|
resultImageUrl && !tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { position: "absolute", bottom: "0.5vw", left: "0.5vw", zIndex: 3, display: "flex", flexDirection: "column", gap: "0.3vw" }, children: [
|
|
21618
21474
|
!isAccessory && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: showLines ? t2("Hide Fit") : t2("Show Fit") }),
|
|
21619
21475
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: handleDownload, children: t2("Download") })
|
|
21620
|
-
] })
|
|
21621
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!retryLoading && !!resultImageUrl && !tryOnProcessing })
|
|
21476
|
+
] })
|
|
21622
21477
|
] }),
|
|
21623
21478
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel", children: [
|
|
21624
21479
|
mismatchNotice,
|
|
21625
|
-
|
|
21626
|
-
|
|
21627
|
-
|
|
21628
|
-
|
|
21629
|
-
|
|
21630
|
-
|
|
21631
|
-
|
|
21632
|
-
|
|
21633
|
-
|
|
21634
|
-
|
|
21635
|
-
|
|
21636
|
-
|
|
21637
|
-
|
|
21638
|
-
|
|
21639
|
-
|
|
21640
|
-
|
|
21480
|
+
activeSection === sectionName ? (
|
|
21481
|
+
/* DETAIL VIEW — full size table, same as multi-garment */
|
|
21482
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21483
|
+
SectionDetailView,
|
|
21484
|
+
{
|
|
21485
|
+
sectionName,
|
|
21486
|
+
section: singleSection,
|
|
21487
|
+
sectionResult: singleResult,
|
|
21488
|
+
sectionFound: sizingResult?.found,
|
|
21489
|
+
userMeasurements: singleUserMeasurements,
|
|
21490
|
+
unitLbl,
|
|
21491
|
+
chartUnit: resultUnit,
|
|
21492
|
+
lengthEntry: null,
|
|
21493
|
+
onBack: () => setActiveSection(null),
|
|
21494
|
+
backLabel: t2("Back"),
|
|
21495
|
+
internationalSizes: sizingResult?.internationalSizes,
|
|
21496
|
+
onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
|
|
21497
|
+
continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
|
|
21498
|
+
tryOnProcessing,
|
|
21499
|
+
tryOnStartedAt,
|
|
21500
|
+
t: t2,
|
|
21501
|
+
renderRaw: isAccessory
|
|
21502
|
+
}
|
|
21503
|
+
)
|
|
21504
|
+
) : sizingResult?.found === false ? (
|
|
21505
|
+
/* NO-FIT EMPTY STATE — match% < 50% or backend reports
|
|
21506
|
+
no valid size. Skip the card + gallery + try-on
|
|
21507
|
+
entirely so the user gets immediate feedback that
|
|
21508
|
+
this product doesn't carry their size. */
|
|
21509
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-nofit", children: [
|
|
21510
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-nofit-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { width: "36", height: "36", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
21511
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
21512
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
|
|
21513
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
|
|
21514
|
+
] }) }),
|
|
21515
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-nofit-title", children: t2("No size matches your measurements") }),
|
|
21516
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-nofit-sub", children: t2("This product's size chart doesn't carry a fit close enough to your body. Try another product or update your profile.") }),
|
|
21517
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-nofit-actions", children: [
|
|
21518
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21519
|
+
"button",
|
|
21520
|
+
{
|
|
21521
|
+
className: "ps-bp-back-btn",
|
|
21522
|
+
onClick: () => {
|
|
21523
|
+
if (resultImageUrl) onResetTryOn?.();
|
|
21524
|
+
else setView("body-profile");
|
|
21525
|
+
},
|
|
21526
|
+
type: "button",
|
|
21527
|
+
children: [
|
|
21528
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
|
|
21529
|
+
" ",
|
|
21530
|
+
t2("Back")
|
|
21531
|
+
]
|
|
21532
|
+
}
|
|
21533
|
+
),
|
|
21534
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-v2-cta", style: { marginTop: 0 }, onClick: onClose, type: "button", children: [
|
|
21535
|
+
t2("Continue Shopping"),
|
|
21536
|
+
" →"
|
|
21537
|
+
] })
|
|
21538
|
+
] })
|
|
21539
|
+
] })
|
|
21540
|
+
) : (
|
|
21541
|
+
/* CARD VIEW — clickable summary card + gallery strip */
|
|
21542
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
21543
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: t2("Your Perfect Fit") }),
|
|
21544
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-v2-subtitle", children: t2("Tap the card for detailed breakdown") }),
|
|
21545
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-sep" }),
|
|
21546
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-cards-v2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21547
|
+
"button",
|
|
21548
|
+
{
|
|
21549
|
+
className: `ps-tryon-sr-card-v2 ps-full${pendingCustomSizes[sectionName] ? " ps-overridden" : ""}`,
|
|
21550
|
+
onClick: () => setActiveSection(sectionName),
|
|
21551
|
+
type: "button",
|
|
21552
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-card-v2-text", children: [
|
|
21553
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-sr-card-v2-label", children: sectionName }),
|
|
21554
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-sr-card-v2-value", children: pendingCustomSizes[sectionName]?.displayLabel || singleResult.recommendedSize || "—" }),
|
|
21555
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21556
|
+
"span",
|
|
21557
|
+
{
|
|
21558
|
+
className: `ps-tryon-sr-card-v2-rec-pill${pendingCustomSizes[sectionName] ? " is-overridden" : ""}`,
|
|
21559
|
+
children: pendingCustomSizes[sectionName] ? t2("YOUR SELECTION") : t2("RECOMMENDED")
|
|
21560
|
+
}
|
|
21561
|
+
),
|
|
21562
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-sr-card-v2-view", children: [
|
|
21563
|
+
t2("VIEW DETAILS"),
|
|
21564
|
+
" ",
|
|
21565
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: "›" })
|
|
21566
|
+
] })
|
|
21567
|
+
] })
|
|
21641
21568
|
}
|
|
21642
|
-
},
|
|
21643
|
-
|
|
21644
|
-
|
|
21645
|
-
|
|
21646
|
-
|
|
21647
|
-
|
|
21648
|
-
|
|
21649
|
-
|
|
21650
|
-
|
|
21651
|
-
|
|
21652
|
-
|
|
21653
|
-
|
|
21654
|
-
|
|
21655
|
-
|
|
21656
|
-
|
|
21569
|
+
) }),
|
|
21570
|
+
productImages && productImages.length >= 2 && /* @__PURE__ */ jsxRuntimeExports.jsx(ProductPhotoCarouselCard, { photos: productImages, productTitle, t: t2 }),
|
|
21571
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginTop: "0.5vw", gap: "0.5vw" }, children: [
|
|
21572
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21573
|
+
"button",
|
|
21574
|
+
{
|
|
21575
|
+
className: "ps-bp-back-btn",
|
|
21576
|
+
onClick: () => {
|
|
21577
|
+
if (resultImageUrl) onResetTryOn?.();
|
|
21578
|
+
else setView("body-profile");
|
|
21579
|
+
},
|
|
21580
|
+
type: "button",
|
|
21581
|
+
children: [
|
|
21582
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
|
|
21583
|
+
" ",
|
|
21584
|
+
t2("Back")
|
|
21585
|
+
]
|
|
21586
|
+
}
|
|
21587
|
+
),
|
|
21588
|
+
resultImageUrl && !tryOnProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-v2-cta", style: { marginTop: 0 }, onClick: onClose, children: [
|
|
21589
|
+
t2("Continue Shopping"),
|
|
21590
|
+
" →"
|
|
21591
|
+
] }) : vtoExcluded ? /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-v2-cta", style: { marginTop: 0 }, onClick: onClose, children: [
|
|
21592
|
+
t2("Continue Shopping"),
|
|
21593
|
+
" →"
|
|
21594
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21595
|
+
"button",
|
|
21596
|
+
{
|
|
21597
|
+
className: "ps-tryon-v2-cta",
|
|
21598
|
+
style: { marginTop: 0 },
|
|
21599
|
+
disabled: tryOnProcessing,
|
|
21600
|
+
onClick: handleSingleTryOn,
|
|
21601
|
+
type: "button",
|
|
21602
|
+
children: [
|
|
21603
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CameraIcon$1, { size: 14 }),
|
|
21604
|
+
" ",
|
|
21605
|
+
tryOnProcessing ? t2("Processing...") : t2("Try It On")
|
|
21606
|
+
]
|
|
21607
|
+
}
|
|
21608
|
+
)
|
|
21609
|
+
] })
|
|
21610
|
+
] })
|
|
21657
21611
|
)
|
|
21658
|
-
] },
|
|
21612
|
+
] }, `panel-single-${activeSection ? "detail" : "card"}`)
|
|
21659
21613
|
] });
|
|
21660
21614
|
})()
|
|
21661
21615
|
),
|
|
@@ -27696,6 +27650,19 @@ function detectMeasurementType(title) {
|
|
|
27696
27650
|
if (/\b(sunglass|sunglasses|eyewear|eyeglasses|glasses|spectacles|optical|goggles|frames|aviator|wayfarer|lens)\b/.test(t2)) return "face";
|
|
27697
27651
|
return "body";
|
|
27698
27652
|
}
|
|
27653
|
+
function computeMatchScore(recData) {
|
|
27654
|
+
if (!recData) return null;
|
|
27655
|
+
const all = [];
|
|
27656
|
+
for (const m2 of recData.matchDetails ?? []) all.push(m2);
|
|
27657
|
+
if (recData.sections) {
|
|
27658
|
+
for (const sec of Object.values(recData.sections)) {
|
|
27659
|
+
for (const m2 of sec?.matchDetails ?? []) all.push(m2);
|
|
27660
|
+
}
|
|
27661
|
+
}
|
|
27662
|
+
if (all.length === 0) return null;
|
|
27663
|
+
const good = all.filter((r2) => r2.fit === "good" || r2.fit === "a-bit-tight" || r2.fit === "a-bit-loose").length;
|
|
27664
|
+
return Math.round(good / all.length * 100);
|
|
27665
|
+
}
|
|
27699
27666
|
function measurementTypeToVtoCategory(type) {
|
|
27700
27667
|
if (type === "face") return "sunglasses";
|
|
27701
27668
|
if (type === "head") return "hat";
|
|
@@ -27704,6 +27671,7 @@ function measurementTypeToVtoCategory(type) {
|
|
|
27704
27671
|
}
|
|
27705
27672
|
function PrimeStyleTryonInner({
|
|
27706
27673
|
productImage,
|
|
27674
|
+
productImages,
|
|
27707
27675
|
productTitle = "Product",
|
|
27708
27676
|
productId,
|
|
27709
27677
|
productDescription,
|
|
@@ -27744,9 +27712,7 @@ function PrimeStyleTryonInner({
|
|
|
27744
27712
|
const [resultImageUrl, setResultImageUrl] = reactExports.useState(null);
|
|
27745
27713
|
const [errorMessage, setErrorMessage] = reactExports.useState(null);
|
|
27746
27714
|
const [dragOver, setDragOver] = reactExports.useState(false);
|
|
27747
|
-
const [retryLoading, setRetryLoading] = reactExports.useState(false);
|
|
27748
27715
|
const [tryOnStartedAt, setTryOnStartedAt] = reactExports.useState(null);
|
|
27749
|
-
const [retryStartedAt, setRetryStartedAt] = reactExports.useState(null);
|
|
27750
27716
|
const [activeSection, setActiveSection] = reactExports.useState(null);
|
|
27751
27717
|
const [pendingCustomSizes, setPendingCustomSizes] = reactExports.useState({});
|
|
27752
27718
|
const pendingCustomSizesRef = reactExports.useRef({});
|
|
@@ -27756,7 +27722,7 @@ function PrimeStyleTryonInner({
|
|
|
27756
27722
|
const sizingResultRef = reactExports.useRef(null);
|
|
27757
27723
|
const sizeGuideRef = reactExports.useRef(null);
|
|
27758
27724
|
const resultImageUrlRef = reactExports.useRef(null);
|
|
27759
|
-
|
|
27725
|
+
reactExports.useCallback((sectionName, override) => {
|
|
27760
27726
|
setPendingCustomSizes((prev) => {
|
|
27761
27727
|
const next = { ...prev };
|
|
27762
27728
|
if (override === null) delete next[sectionName];
|
|
@@ -27778,6 +27744,7 @@ function PrimeStyleTryonInner({
|
|
|
27778
27744
|
const [estimationDone, setEstimationDone] = reactExports.useState(false);
|
|
27779
27745
|
const [tryOnProcessing, setTryOnProcessing] = reactExports.useState(false);
|
|
27780
27746
|
const [sizeGuide, setSizeGuide] = reactExports.useState(null);
|
|
27747
|
+
const noFitFoundRef = reactExports.useRef(false);
|
|
27781
27748
|
reactExports.useEffect(() => {
|
|
27782
27749
|
sizingResultRef.current = sizingResult;
|
|
27783
27750
|
}, [sizingResult]);
|
|
@@ -27836,6 +27803,7 @@ function PrimeStyleTryonInner({
|
|
|
27836
27803
|
const [faceLandmarks, setFaceLandmarks] = reactExports.useState(null);
|
|
27837
27804
|
const selectedFileRef = reactExports.useRef(null);
|
|
27838
27805
|
const modelImageIdRef = reactExports.useRef(null);
|
|
27806
|
+
const autoTryOnFiredRef = reactExports.useRef(false);
|
|
27839
27807
|
reactExports.useEffect(() => {
|
|
27840
27808
|
try {
|
|
27841
27809
|
const key = getApiKey();
|
|
@@ -28243,6 +28211,15 @@ function PrimeStyleTryonInner({
|
|
|
28243
28211
|
unsubRef.current = null;
|
|
28244
28212
|
}, []);
|
|
28245
28213
|
const handleVtoUpdate = reactExports.useCallback((update) => {
|
|
28214
|
+
if (noFitFoundRef.current) {
|
|
28215
|
+
if (update.status === "completed" || update.status === "failed") {
|
|
28216
|
+
completedRef.current = true;
|
|
28217
|
+
cleanupJob();
|
|
28218
|
+
setTryOnProcessing(false);
|
|
28219
|
+
setTryOnStartedAt(null);
|
|
28220
|
+
}
|
|
28221
|
+
return;
|
|
28222
|
+
}
|
|
28246
28223
|
if (update.status === "completed" && update.imageUrl) {
|
|
28247
28224
|
setResultImageUrl((prev) => {
|
|
28248
28225
|
if (!prev || prev.startsWith("data:")) return update.imageUrl;
|
|
@@ -28425,11 +28402,15 @@ function PrimeStyleTryonInner({
|
|
|
28425
28402
|
}
|
|
28426
28403
|
setEstimationDone(false);
|
|
28427
28404
|
try {
|
|
28405
|
+
const tReq = Date.now();
|
|
28406
|
+
const payloadBytes = JSON.stringify(payload).length;
|
|
28407
|
+
console.log(`[ps-sdk:T] ▶ POST /sizing/recommend (quick) payload=${Math.round(payloadBytes / 1024)}KB bodyImage=${!!payload.bodyImage}`);
|
|
28428
28408
|
const res = await fetch(`${baseUrl}/api/v1/sizing/recommend`, {
|
|
28429
28409
|
method: "POST",
|
|
28430
28410
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
|
|
28431
28411
|
body: JSON.stringify(payload)
|
|
28432
28412
|
});
|
|
28413
|
+
console.log(`[ps-sdk:T] ◀ /sizing/recommend (quick) status=${res.status} roundTrip=${Date.now() - tReq}ms`);
|
|
28433
28414
|
if (res.ok) {
|
|
28434
28415
|
const data = await res.json();
|
|
28435
28416
|
console.log("[PS-SDK] Sizing recommend RESULT:", JSON.stringify(data));
|
|
@@ -28565,6 +28546,8 @@ function PrimeStyleTryonInner({
|
|
|
28565
28546
|
const objUrl = data.photoFile ? URL.createObjectURL(data.photoFile) : data.photoBase64.startsWith("data:") ? data.photoBase64 : `data:image/jpeg;base64,${data.photoBase64}`;
|
|
28566
28547
|
setPreviewUrl(objUrl);
|
|
28567
28548
|
completedRef.current = false;
|
|
28549
|
+
modelImageIdRef.current = null;
|
|
28550
|
+
noFitFoundRef.current = false;
|
|
28568
28551
|
setTryOnProcessing(false);
|
|
28569
28552
|
setTryOnStartedAt(null);
|
|
28570
28553
|
setSizingResult(null);
|
|
@@ -28575,12 +28558,12 @@ function PrimeStyleTryonInner({
|
|
|
28575
28558
|
const measurementType = detectMeasurementType(productTitle);
|
|
28576
28559
|
if (measurementType === "face" || measurementType === "head") {
|
|
28577
28560
|
setFaceLandmarks(null);
|
|
28578
|
-
const
|
|
28561
|
+
const minVisible2 = new Promise((r2) => setTimeout(r2, 4500));
|
|
28579
28562
|
try {
|
|
28580
28563
|
const faceResult = await detectFaceMeasurements(objUrl);
|
|
28581
28564
|
if (!faceResult) {
|
|
28582
28565
|
console.warn("[ps-sdk] face detection returned no result — likely a full-body photo for a face/head product");
|
|
28583
|
-
await
|
|
28566
|
+
await minVisible2;
|
|
28584
28567
|
const msg = measurementType === "head" ? t2("We couldn't detect your head clearly. Please upload a close-up photo that shows your full head and ears.") : t2("We couldn't detect your face clearly. Please upload a close-up selfie that shows both eyes.");
|
|
28585
28568
|
setErrorMessage(msg);
|
|
28586
28569
|
setView("error");
|
|
@@ -28608,7 +28591,7 @@ function PrimeStyleTryonInner({
|
|
|
28608
28591
|
});
|
|
28609
28592
|
if (recRes.ok) {
|
|
28610
28593
|
const recData = await recRes.json();
|
|
28611
|
-
await
|
|
28594
|
+
await minVisible2;
|
|
28612
28595
|
setSizingResult(recData);
|
|
28613
28596
|
onComplete?.(recData);
|
|
28614
28597
|
persistResultToProfile(
|
|
@@ -28625,12 +28608,12 @@ function PrimeStyleTryonInner({
|
|
|
28625
28608
|
{ skipBodyEstimate: true }
|
|
28626
28609
|
);
|
|
28627
28610
|
} else {
|
|
28628
|
-
await
|
|
28611
|
+
await minVisible2;
|
|
28629
28612
|
setEstimationDone(true);
|
|
28630
28613
|
}
|
|
28631
28614
|
} catch (err) {
|
|
28632
28615
|
console.error("[ps-sdk] face-recommend failed:", err);
|
|
28633
|
-
await
|
|
28616
|
+
await minVisible2;
|
|
28634
28617
|
setEstimationDone(true);
|
|
28635
28618
|
}
|
|
28636
28619
|
setSizingLoading(false);
|
|
@@ -28700,12 +28683,17 @@ function PrimeStyleTryonInner({
|
|
|
28700
28683
|
const jointCount = lmObj ? Object.keys(lmObj).filter((k2) => k2 !== "imageWidth" && k2 !== "imageHeight" && lmObj[k2]).length : 0;
|
|
28701
28684
|
console.log(`[ps-sdk:debug] payload → bodyLandmarks=${!!lmObj}(${jointCount} joints)`);
|
|
28702
28685
|
}
|
|
28686
|
+
const minVisible = new Promise((r2) => setTimeout(r2, 6e3));
|
|
28703
28687
|
try {
|
|
28688
|
+
const tReq = Date.now();
|
|
28689
|
+
const payloadBytes = JSON.stringify(payload).length;
|
|
28690
|
+
console.log(`[ps-sdk:T] ▶ POST /sizing/recommend payload=${Math.round(payloadBytes / 1024)}KB bodyImage=${!!payload.bodyImage} landmarks=${!!payload.bodyLandmarks}`);
|
|
28704
28691
|
const recRes = await fetch(`${baseUrl}/api/v1/sizing/recommend`, {
|
|
28705
28692
|
method: "POST",
|
|
28706
28693
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
|
|
28707
28694
|
body: JSON.stringify(payload)
|
|
28708
28695
|
});
|
|
28696
|
+
console.log(`[ps-sdk:T] ◀ /sizing/recommend status=${recRes.status} roundTrip=${Date.now() - tReq}ms`);
|
|
28709
28697
|
if (recRes.ok) {
|
|
28710
28698
|
const recData = await recRes.json();
|
|
28711
28699
|
if (recData?.found === false && recData?.reasoning === "NO_SIZE_CHART") {
|
|
@@ -28714,26 +28702,38 @@ function PrimeStyleTryonInner({
|
|
|
28714
28702
|
setSizingLoading(false);
|
|
28715
28703
|
return;
|
|
28716
28704
|
}
|
|
28717
|
-
|
|
28718
|
-
|
|
28719
|
-
|
|
28720
|
-
{
|
|
28721
|
-
|
|
28722
|
-
|
|
28723
|
-
|
|
28724
|
-
|
|
28725
|
-
|
|
28726
|
-
|
|
28727
|
-
|
|
28728
|
-
|
|
28729
|
-
|
|
28730
|
-
|
|
28705
|
+
const matchScore = computeMatchScore(recData);
|
|
28706
|
+
const isLowFit = recData?.found === false || matchScore != null && matchScore < 50;
|
|
28707
|
+
if (isLowFit) {
|
|
28708
|
+
console.log(`[ps-sdk:gate] LOW FIT (match=${matchScore ?? "?"}%, found=${recData?.found}) — suppressing try-on`);
|
|
28709
|
+
noFitFoundRef.current = true;
|
|
28710
|
+
setTryOnProcessing(false);
|
|
28711
|
+
setTryOnStartedAt(null);
|
|
28712
|
+
setSizingResult({ ...recData, found: false });
|
|
28713
|
+
onComplete?.({ ...recData, found: false });
|
|
28714
|
+
} else {
|
|
28715
|
+
setSizingResult(recData);
|
|
28716
|
+
onComplete?.(recData);
|
|
28717
|
+
persistResultToProfile(
|
|
28718
|
+
{
|
|
28719
|
+
gender: data.gender,
|
|
28720
|
+
height: data.height,
|
|
28721
|
+
weight: data.weight,
|
|
28722
|
+
heightUnit: data.heightUnit,
|
|
28723
|
+
weightUnit: data.weightUnit,
|
|
28724
|
+
age: data.age,
|
|
28725
|
+
bodyImage: data.photoBase64
|
|
28726
|
+
},
|
|
28727
|
+
recData
|
|
28728
|
+
);
|
|
28729
|
+
}
|
|
28731
28730
|
} else {
|
|
28732
28731
|
setEstimationDone(true);
|
|
28733
28732
|
}
|
|
28734
28733
|
} catch {
|
|
28735
28734
|
setEstimationDone(true);
|
|
28736
28735
|
}
|
|
28736
|
+
await minVisible;
|
|
28737
28737
|
setSizingLoading(false);
|
|
28738
28738
|
}, [apiUrl, productImage, productTitle, sizingUnit, weightUnit, sizingCountry, sizeGuide, dynamicFields, persistResultToProfile]);
|
|
28739
28739
|
snapSubmitRef.current = handleSnapSubmit;
|
|
@@ -28757,9 +28757,9 @@ function PrimeStyleTryonInner({
|
|
|
28757
28757
|
const isApparel = vtoCategory === "apparel";
|
|
28758
28758
|
const previewObjUrl = (overrideFile ? null : previewUrl) || URL.createObjectURL(file);
|
|
28759
28759
|
if (overrideFile || !previewUrl) setPreviewUrl(previewObjUrl);
|
|
28760
|
-
modelPoseRef.current
|
|
28761
|
-
|
|
28762
|
-
|
|
28760
|
+
if (isApparel && (!modelPoseRef.current || !bodyLandmarks)) {
|
|
28761
|
+
modelPoseRef.current = null;
|
|
28762
|
+
setBodyLandmarks(null);
|
|
28763
28763
|
detectMeasurementLines(previewObjUrl).then((lines) => {
|
|
28764
28764
|
modelPoseRef.current = lines;
|
|
28765
28765
|
}).catch(() => {
|
|
@@ -28810,20 +28810,20 @@ function PrimeStyleTryonInner({
|
|
|
28810
28810
|
console.log("[ps-sdk:flatten] sizingResult keys:", Object.keys(sizingResult || {}));
|
|
28811
28811
|
console.log("[ps-sdk:flatten] root matchDetails:", (sizingResult?.matchDetails || []).map((m2) => m2.measurement));
|
|
28812
28812
|
console.log("[ps-sdk:flatten] sections:", sizingResult?.sections ? Object.keys(sizingResult.sections) : "none");
|
|
28813
|
-
const push = (md2, src) => {
|
|
28813
|
+
const push = (md2, src, section) => {
|
|
28814
28814
|
if (!md2) return;
|
|
28815
28815
|
console.log(`[ps-sdk:flatten] ${src} →`, md2.map((m2) => m2.measurement));
|
|
28816
28816
|
for (const m2 of md2) {
|
|
28817
28817
|
const k2 = m2.measurement.toLowerCase().replace(/\s*\(.*?\)\s*/g, "").trim();
|
|
28818
28818
|
if (seen.has(k2)) continue;
|
|
28819
28819
|
seen.add(k2);
|
|
28820
|
-
out.push(m2);
|
|
28820
|
+
out.push({ ...m2, section });
|
|
28821
28821
|
}
|
|
28822
28822
|
};
|
|
28823
|
-
push(sizingResult?.matchDetails, "root");
|
|
28823
|
+
push(sizingResult?.matchDetails, "root", void 0);
|
|
28824
28824
|
if (sizingResult?.sections) {
|
|
28825
28825
|
for (const [secName, sec] of Object.entries(sizingResult.sections)) {
|
|
28826
|
-
push(sec?.matchDetails, `section:${secName}
|
|
28826
|
+
push(sec?.matchDetails, `section:${secName}`, secName);
|
|
28827
28827
|
}
|
|
28828
28828
|
}
|
|
28829
28829
|
console.log("[ps-sdk:flatten] final unique:", out.map((m2) => m2.measurement));
|
|
@@ -28832,7 +28832,9 @@ function PrimeStyleTryonInner({
|
|
|
28832
28832
|
const effectiveMatchDetails = override?.matchDetails && override.matchDetails.length ? override.matchDetails : flattenAllMatchDetails();
|
|
28833
28833
|
let fitInfo;
|
|
28834
28834
|
if (isApparel && effectiveMatchDetails.length) {
|
|
28835
|
-
|
|
28835
|
+
const unitRaw = (sizingResult?.unit || sizingUnit || "in").toString().toLowerCase();
|
|
28836
|
+
const unit = unitRaw === "cm" ? "cm" : unitRaw === "mm" ? "mm" : "in";
|
|
28837
|
+
fitInfo = buildFitInfo(effectiveMatchDetails, modelPoseRef.current, unit);
|
|
28836
28838
|
}
|
|
28837
28839
|
console.log("[ps-sdk:tryon] fitInfo built", { count: fitInfo?.length || 0, areas: fitInfo?.map((f2) => `${f2.area}(${f2.fit})`) });
|
|
28838
28840
|
const response = await apiRef.current.submitTryOn(
|
|
@@ -28881,167 +28883,19 @@ function PrimeStyleTryonInner({
|
|
|
28881
28883
|
onError?.({ message, code });
|
|
28882
28884
|
}
|
|
28883
28885
|
}, [selectedFile, productImage, productTitle, sizingResult, onProcessing, onError, handleVtoUpdate]);
|
|
28884
|
-
|
|
28885
|
-
|
|
28886
|
-
|
|
28887
|
-
console.warn("[ps-sdk:retry] skipping — no file/api/sse", {
|
|
28888
|
-
hasFile: !!file,
|
|
28889
|
-
hasApi: !!apiRef.current,
|
|
28890
|
-
hasSse: !!sseRef.current
|
|
28891
|
-
});
|
|
28892
|
-
return;
|
|
28893
|
-
}
|
|
28894
|
-
console.log("[ps-sdk:retry] starting", { fitInfoCount: fitInfo.length, selectedSizeOverride, fitInfo });
|
|
28895
|
-
setRetryLoading(true);
|
|
28896
|
-
setRetryStartedAt(Date.now());
|
|
28897
|
-
const vtoCategory = measurementTypeToVtoCategory(detectMeasurementType(productTitle));
|
|
28898
|
-
const isApparel = vtoCategory === "apparel";
|
|
28899
|
-
if (isApparel && modelPoseRef.current) {
|
|
28900
|
-
const AREA_MAP = {
|
|
28901
|
-
chest: "chest",
|
|
28902
|
-
bust: "chest",
|
|
28903
|
-
waist: "waist",
|
|
28904
|
-
hips: "hips",
|
|
28905
|
-
hip: "hips"
|
|
28906
|
-
};
|
|
28907
|
-
for (const area of fitInfo) {
|
|
28908
|
-
const key = AREA_MAP[area.area.toLowerCase()];
|
|
28909
|
-
if (key && modelPoseRef.current[key]) {
|
|
28910
|
-
const line = modelPoseRef.current[key];
|
|
28911
|
-
area.y = Math.round(line.y * 1e3) / 1e3;
|
|
28912
|
-
area.x1 = Math.round(line.x1 * 1e3) / 1e3;
|
|
28913
|
-
area.x2 = Math.round(line.x2 * 1e3) / 1e3;
|
|
28914
|
-
}
|
|
28915
|
-
}
|
|
28916
|
-
}
|
|
28917
|
-
try {
|
|
28918
|
-
completedRef.current = false;
|
|
28919
|
-
unsubRef.current?.();
|
|
28920
|
-
if (pollingRef.current) {
|
|
28921
|
-
clearInterval(pollingRef.current);
|
|
28922
|
-
pollingRef.current = null;
|
|
28923
|
-
}
|
|
28924
|
-
const useExistingResult = false;
|
|
28925
|
-
const modelImage = await compressImage(file, { maxDimension: 1024, quality: 0.85 });
|
|
28926
|
-
console.log("[ps-sdk:retry] modelImage source", {
|
|
28927
|
-
useExistingResult,
|
|
28928
|
-
bytes: modelImage.length,
|
|
28929
|
-
isPng: modelImage.startsWith("data:image/png")
|
|
28930
|
-
});
|
|
28931
|
-
const outboundFitInfo = isApparel ? fitInfo : void 0;
|
|
28932
|
-
const response = await apiRef.current.submitTryOn(
|
|
28933
|
-
modelImage,
|
|
28934
|
-
productImage,
|
|
28935
|
-
outboundFitInfo,
|
|
28936
|
-
vtoCategory ?? "apparel",
|
|
28937
|
-
{
|
|
28938
|
-
editFromPrevious: useExistingResult,
|
|
28939
|
-
productId: effectiveProductId,
|
|
28940
|
-
productTitle,
|
|
28941
|
-
productDescription,
|
|
28942
|
-
productMaterial,
|
|
28943
|
-
silhouetteContext: buildSilhouetteContext(sizingResultRef.current, sizeGuideRef.current, selectedSizeOverride),
|
|
28944
|
-
modelImageId: modelImageIdRef.current ?? void 0
|
|
28945
|
-
}
|
|
28946
|
-
);
|
|
28947
|
-
if (response.modelImageId) modelImageIdRef.current = response.modelImageId;
|
|
28948
|
-
unsubRef.current = sseRef.current.onJob(response.jobId, (update) => {
|
|
28949
|
-
if (update.status === "completed" && update.imageUrl) {
|
|
28950
|
-
setResultImageUrl(update.imageUrl);
|
|
28951
|
-
setRetryLoading(false);
|
|
28952
|
-
setRetryStartedAt(null);
|
|
28953
|
-
completedRef.current = true;
|
|
28954
|
-
unsubRef.current?.();
|
|
28955
|
-
unsubRef.current = null;
|
|
28956
|
-
if (pollingRef.current) {
|
|
28957
|
-
clearInterval(pollingRef.current);
|
|
28958
|
-
pollingRef.current = null;
|
|
28959
|
-
}
|
|
28960
|
-
} else if (update.status === "failed") {
|
|
28961
|
-
setRetryLoading(false);
|
|
28962
|
-
setRetryStartedAt(null);
|
|
28963
|
-
completedRef.current = true;
|
|
28964
|
-
unsubRef.current?.();
|
|
28965
|
-
unsubRef.current = null;
|
|
28966
|
-
if (pollingRef.current) {
|
|
28967
|
-
clearInterval(pollingRef.current);
|
|
28968
|
-
pollingRef.current = null;
|
|
28969
|
-
}
|
|
28970
|
-
}
|
|
28971
|
-
});
|
|
28972
|
-
let attempts = 0;
|
|
28973
|
-
pollingRef.current = setInterval(async () => {
|
|
28974
|
-
if (completedRef.current) {
|
|
28975
|
-
if (pollingRef.current) clearInterval(pollingRef.current);
|
|
28976
|
-
pollingRef.current = null;
|
|
28977
|
-
return;
|
|
28978
|
-
}
|
|
28979
|
-
attempts++;
|
|
28980
|
-
if (attempts > 60) {
|
|
28981
|
-
if (pollingRef.current) clearInterval(pollingRef.current);
|
|
28982
|
-
pollingRef.current = null;
|
|
28983
|
-
setRetryLoading(false);
|
|
28984
|
-
setRetryStartedAt(null);
|
|
28985
|
-
return;
|
|
28986
|
-
}
|
|
28987
|
-
try {
|
|
28988
|
-
const status = await apiRef.current.getStatus(response.jobId);
|
|
28989
|
-
if (status.status === "completed" && status.imageUrl) {
|
|
28990
|
-
if (!completedRef.current) {
|
|
28991
|
-
completedRef.current = true;
|
|
28992
|
-
setResultImageUrl(status.imageUrl);
|
|
28993
|
-
setRetryLoading(false);
|
|
28994
|
-
setRetryStartedAt(null);
|
|
28995
|
-
unsubRef.current?.();
|
|
28996
|
-
unsubRef.current = null;
|
|
28997
|
-
}
|
|
28998
|
-
if (pollingRef.current) {
|
|
28999
|
-
clearInterval(pollingRef.current);
|
|
29000
|
-
pollingRef.current = null;
|
|
29001
|
-
}
|
|
29002
|
-
} else if (status.status === "failed") {
|
|
29003
|
-
completedRef.current = true;
|
|
29004
|
-
setRetryLoading(false);
|
|
29005
|
-
setRetryStartedAt(null);
|
|
29006
|
-
if (pollingRef.current) {
|
|
29007
|
-
clearInterval(pollingRef.current);
|
|
29008
|
-
pollingRef.current = null;
|
|
29009
|
-
}
|
|
29010
|
-
}
|
|
29011
|
-
} catch {
|
|
29012
|
-
}
|
|
29013
|
-
}, 3e3);
|
|
29014
|
-
} catch {
|
|
29015
|
-
setRetryLoading(false);
|
|
29016
|
-
setRetryStartedAt(null);
|
|
29017
|
-
}
|
|
29018
|
-
}, [selectedFile, productImage, productTitle]);
|
|
29019
|
-
const handleRegenerateTryOn = reactExports.useCallback((override) => {
|
|
29020
|
-
console.log("[ps-sdk:regen] fired", { sectionName: override.sectionName, override, hasFile: !!selectedFile, hasRefFile: !!selectedFileRef.current });
|
|
29021
|
-
setPendingCustomSizeBySection(override.sectionName, override);
|
|
29022
|
-
const map = { ...pendingCustomSizesRef.current, [override.sectionName]: override };
|
|
29023
|
-
const seen = /* @__PURE__ */ new Set();
|
|
29024
|
-
const merged = [];
|
|
29025
|
-
for (const key of Object.keys(map)) {
|
|
29026
|
-
for (const m2 of map[key].matchDetails || []) {
|
|
29027
|
-
const k2 = m2.measurement.toLowerCase().trim();
|
|
29028
|
-
if (seen.has(k2)) continue;
|
|
29029
|
-
seen.add(k2);
|
|
29030
|
-
merged.push(m2);
|
|
29031
|
-
}
|
|
29032
|
-
}
|
|
29033
|
-
if (!merged.length) {
|
|
29034
|
-
console.warn("[ps-sdk:regen] no matchDetails across any section — cannot rebuild fitInfo");
|
|
28886
|
+
reactExports.useEffect(() => {
|
|
28887
|
+
if (!sizingResult) {
|
|
28888
|
+
autoTryOnFiredRef.current = false;
|
|
29035
28889
|
return;
|
|
29036
28890
|
}
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
|
|
29040
|
-
|
|
29041
|
-
|
|
29042
|
-
|
|
29043
|
-
|
|
29044
|
-
}, [
|
|
28891
|
+
if (sizingResult.found === false) return;
|
|
28892
|
+
if (noFitFoundRef.current) return;
|
|
28893
|
+
if (autoTryOnFiredRef.current) return;
|
|
28894
|
+
if (tryOnProcessing || resultImageUrl) return;
|
|
28895
|
+
if (!selectedFile && !selectedFileRef.current) return;
|
|
28896
|
+
autoTryOnFiredRef.current = true;
|
|
28897
|
+
handleTryOnSubmit();
|
|
28898
|
+
}, [sizingResult, tryOnProcessing, resultImageUrl, selectedFile, handleTryOnSubmit]);
|
|
29045
28899
|
const handleDownload = reactExports.useCallback(() => {
|
|
29046
28900
|
if (!resultImageUrl) return;
|
|
29047
28901
|
if (resultImageUrl.startsWith("data:")) {
|
|
@@ -29483,15 +29337,13 @@ function PrimeStyleTryonInner({
|
|
|
29483
29337
|
sizeGuide,
|
|
29484
29338
|
resultImageUrl,
|
|
29485
29339
|
productImage,
|
|
29340
|
+
productImages,
|
|
29486
29341
|
productTitle,
|
|
29487
29342
|
productMaterial,
|
|
29488
29343
|
productDescription,
|
|
29489
29344
|
sizingUnit,
|
|
29490
29345
|
setView,
|
|
29491
29346
|
handleDownload,
|
|
29492
|
-
onRetryWithFit: handleRetryWithFit,
|
|
29493
|
-
retryLoading,
|
|
29494
|
-
retryStartedAt,
|
|
29495
29347
|
selectedFile,
|
|
29496
29348
|
previewUrl,
|
|
29497
29349
|
handleFileSelect,
|
|
@@ -29504,9 +29356,6 @@ function PrimeStyleTryonInner({
|
|
|
29504
29356
|
measurementType: detectMeasurementType(productTitle),
|
|
29505
29357
|
activeSection,
|
|
29506
29358
|
setActiveSection,
|
|
29507
|
-
pendingCustomSizes,
|
|
29508
|
-
onPendingCustomSizeChange: setPendingCustomSizeBySection,
|
|
29509
|
-
onRegenerateTryOn: handleRegenerateTryOn,
|
|
29510
29359
|
onResetTryOn: () => {
|
|
29511
29360
|
setSelectedFile(null);
|
|
29512
29361
|
if (previewUrl) URL.revokeObjectURL(previewUrl);
|