@primestyleai/tryon 5.10.102 → 5.10.104
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 +4919 -4940
- package/dist/react/index.js.map +1 -1
- package/dist/react/styles.d.ts +1 -1
- package/dist/react/types.d.ts +15 -0
- package/dist/react/utils/pickBestGarmentImage.d.ts +1 -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 +651 -752
- 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
|
|
@@ -10586,6 +10588,45 @@ function getUnitLabel(unit) {
|
|
|
10586
10588
|
if (unit === "mm") return "mm";
|
|
10587
10589
|
return "";
|
|
10588
10590
|
}
|
|
10591
|
+
const cache = /* @__PURE__ */ new Map();
|
|
10592
|
+
function scoreLandmarks(lm) {
|
|
10593
|
+
if (!lm) return 0;
|
|
10594
|
+
let joints = 0;
|
|
10595
|
+
for (const [k2, v2] of Object.entries(lm)) {
|
|
10596
|
+
if (k2 === "imageWidth" || k2 === "imageHeight") continue;
|
|
10597
|
+
if (v2 && typeof v2 === "object" && typeof v2.x === "number") joints++;
|
|
10598
|
+
}
|
|
10599
|
+
let score = joints * 10;
|
|
10600
|
+
if (lm.nose) score += 50;
|
|
10601
|
+
if (lm.leftAnkle && lm.rightAnkle) score += 5;
|
|
10602
|
+
return score;
|
|
10603
|
+
}
|
|
10604
|
+
async function scoreImage(url) {
|
|
10605
|
+
try {
|
|
10606
|
+
const lm = await detectBodyLandmarks(url);
|
|
10607
|
+
return scoreLandmarks(lm);
|
|
10608
|
+
} catch {
|
|
10609
|
+
return 0;
|
|
10610
|
+
}
|
|
10611
|
+
}
|
|
10612
|
+
async function pickBestGarmentImage(images) {
|
|
10613
|
+
if (!images || !images.length) return null;
|
|
10614
|
+
if (images.length === 1) return images[0];
|
|
10615
|
+
const cacheKey = images.join("|");
|
|
10616
|
+
const cached = cache.get(cacheKey);
|
|
10617
|
+
if (cached) return cached;
|
|
10618
|
+
const t0 = Date.now();
|
|
10619
|
+
const scored = await Promise.all(images.map(async (url) => ({
|
|
10620
|
+
url,
|
|
10621
|
+
score: await scoreImage(url)
|
|
10622
|
+
})));
|
|
10623
|
+
scored.sort((a, b) => b.score - a.score);
|
|
10624
|
+
const best = (scored[0]?.score ?? 0) > 0 ? scored[0].url : images[0];
|
|
10625
|
+
cache.set(cacheKey, best);
|
|
10626
|
+
console.log(`[ps-sdk:garment-pick] ${Date.now() - t0}ms — chose ${images.indexOf(best)}/${images.length}`);
|
|
10627
|
+
for (const s of scored) console.log(`[ps-sdk:garment-pick] ${s.score.toString().padStart(4, " ")} ${s.url}`);
|
|
10628
|
+
return best;
|
|
10629
|
+
}
|
|
10589
10630
|
function cx(base, override) {
|
|
10590
10631
|
return override ? `${base} ${override}` : base;
|
|
10591
10632
|
}
|
|
@@ -11328,6 +11369,37 @@ const STYLES$1 = `
|
|
|
11328
11369
|
border: 1px solid rgba(33,84,239,0.25); border-radius: 2vw;
|
|
11329
11370
|
padding: 0.1vw 0.5vw;
|
|
11330
11371
|
}
|
|
11372
|
+
.ps-tryon-sr-card-v2-rec-pill {
|
|
11373
|
+
align-self: flex-start;
|
|
11374
|
+
font-size: 0.55vw; font-weight: 700; color: var(--ps-accent);
|
|
11375
|
+
text-transform: uppercase; letter-spacing: 0.08em;
|
|
11376
|
+
background: rgba(33, 84, 239, 0.10);
|
|
11377
|
+
border: 1px solid rgba(33, 84, 239, 0.18);
|
|
11378
|
+
border-radius: 2vw;
|
|
11379
|
+
padding: 0.18vw 0.6vw;
|
|
11380
|
+
margin-top: 0.3vw;
|
|
11381
|
+
}
|
|
11382
|
+
.ps-tryon-sr-card-v2-rec-pill.is-overridden {
|
|
11383
|
+
color: #b45309;
|
|
11384
|
+
background: rgba(180, 83, 9, 0.10);
|
|
11385
|
+
border-color: rgba(180, 83, 9, 0.25);
|
|
11386
|
+
}
|
|
11387
|
+
.ps-tryon-sr-card-v2-view {
|
|
11388
|
+
align-self: center;
|
|
11389
|
+
margin-top: 0.4vw;
|
|
11390
|
+
font-size: 0.62vw; font-weight: 600;
|
|
11391
|
+
color: var(--ps-accent);
|
|
11392
|
+
text-transform: uppercase; letter-spacing: 0.06em;
|
|
11393
|
+
display: inline-flex; align-items: center; justify-content: center; gap: 0.2vw;
|
|
11394
|
+
transition: gap 0.2s ease;
|
|
11395
|
+
}
|
|
11396
|
+
.ps-tryon-sr-card-v2:hover .ps-tryon-sr-card-v2-view {
|
|
11397
|
+
gap: 0.4vw;
|
|
11398
|
+
}
|
|
11399
|
+
.ps-tryon-sr-card-v2-view > span {
|
|
11400
|
+
font-size: 0.85vw; line-height: 1; color: var(--ps-accent);
|
|
11401
|
+
transform: translateY(-0.05vw);
|
|
11402
|
+
}
|
|
11331
11403
|
.ps-tryon-sr-card-v2-img { display: none; }
|
|
11332
11404
|
.ps-tryon-sr-card-v2-icon {
|
|
11333
11405
|
position: absolute; bottom: 0.35vw; right: 0.45vw;
|
|
@@ -11391,24 +11463,165 @@ const STYLES$1 = `
|
|
|
11391
11463
|
filter: blur(8px) brightness(0.5); transform: scale(1.05);
|
|
11392
11464
|
transition: filter 0.5s ease, transform 0.5s ease;
|
|
11393
11465
|
}
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
background:
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
|
|
11402
|
-
box-shadow: 0
|
|
11466
|
+
/* ── Try-on generation badge (left-side overlay during VTO) ── */
|
|
11467
|
+
.ps-tryon-badge {
|
|
11468
|
+
position: absolute; bottom: 16px; left: 16px; right: 16px;
|
|
11469
|
+
z-index: 5;
|
|
11470
|
+
background: #ffffff;
|
|
11471
|
+
border-radius: 14px;
|
|
11472
|
+
padding: 14px 18px;
|
|
11473
|
+
max-width: 420px;
|
|
11474
|
+
box-shadow: 0 8px 28px rgba(20, 30, 60, 0.14), 0 2px 6px rgba(20, 30, 60, 0.08);
|
|
11475
|
+
display: flex; flex-direction: column; gap: 10px;
|
|
11476
|
+
font-family: inherit;
|
|
11477
|
+
pointer-events: none;
|
|
11478
|
+
}
|
|
11479
|
+
.ps-tryon-badge-row {
|
|
11480
|
+
display: flex; align-items: center; gap: 12px;
|
|
11403
11481
|
}
|
|
11404
|
-
.ps-tryon-
|
|
11405
|
-
|
|
11482
|
+
.ps-tryon-badge-spinner {
|
|
11483
|
+
display: inline-flex; flex-shrink: 0;
|
|
11484
|
+
animation: ps-tryon-badge-spin 1s linear infinite;
|
|
11485
|
+
}
|
|
11486
|
+
.ps-tryon-badge-title {
|
|
11487
|
+
flex: 1; min-width: 0;
|
|
11488
|
+
font-size: 15px; font-weight: 600; color: #0f172a;
|
|
11489
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
11490
|
+
}
|
|
11491
|
+
.ps-tryon-badge-pct {
|
|
11492
|
+
flex-shrink: 0;
|
|
11493
|
+
background: linear-gradient(135deg, var(--ps-accent) 0%, var(--ps-accent-hover) 100%);
|
|
11494
|
+
color: #fff; font-size: 12px; font-weight: 700;
|
|
11495
|
+
padding: 4px 11px; border-radius: 999px;
|
|
11496
|
+
letter-spacing: 0.02em;
|
|
11497
|
+
}
|
|
11498
|
+
.ps-tryon-badge-bar {
|
|
11499
|
+
height: 5px;
|
|
11500
|
+
background: #eef2f8;
|
|
11501
|
+
border-radius: 999px; overflow: hidden;
|
|
11502
|
+
}
|
|
11503
|
+
.ps-tryon-badge-bar-fill {
|
|
11504
|
+
height: 100%;
|
|
11505
|
+
background: linear-gradient(90deg, var(--ps-accent) 0%, var(--ps-accent-hover) 100%);
|
|
11506
|
+
border-radius: 999px;
|
|
11507
|
+
transition: width 0.3s ease;
|
|
11508
|
+
}
|
|
11509
|
+
.ps-tryon-badge-foot {
|
|
11510
|
+
display: flex; align-items: center; justify-content: space-between; gap: 10px;
|
|
11511
|
+
font-size: 12px; color: #6b7280;
|
|
11512
|
+
}
|
|
11513
|
+
.ps-tryon-badge-status {
|
|
11514
|
+
display: inline-flex; align-items: center; gap: 6px;
|
|
11515
|
+
font-weight: 500;
|
|
11516
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
11517
|
+
}
|
|
11518
|
+
.ps-tryon-badge-status-icon {
|
|
11519
|
+
display: inline-flex; flex-shrink: 0; color: var(--ps-accent);
|
|
11520
|
+
}
|
|
11521
|
+
.ps-tryon-badge-eta {
|
|
11522
|
+
display: inline-flex; align-items: center; gap: 5px;
|
|
11523
|
+
font-weight: 500; flex-shrink: 0;
|
|
11524
|
+
}
|
|
11525
|
+
@keyframes ps-tryon-badge-spin {
|
|
11526
|
+
to { transform: rotate(360deg); }
|
|
11527
|
+
}
|
|
11528
|
+
|
|
11529
|
+
/* ── Product photo strip (single-garment, below the size card) ──
|
|
11530
|
+
Three thumbnails per slide, evenly spaced, auto-advances. Lives at
|
|
11531
|
+
the bottom of the right panel as decoration / entertainment. */
|
|
11532
|
+
.ps-tryon-photo-strip {
|
|
11533
|
+
margin-top: 1vw;
|
|
11534
|
+
display: flex; flex-direction: column; gap: 0.6vw;
|
|
11535
|
+
}
|
|
11536
|
+
.ps-tryon-photo-strip-head {
|
|
11537
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
11538
|
+
}
|
|
11539
|
+
.ps-tryon-photo-strip-badge {
|
|
11540
|
+
color: var(--ps-accent);
|
|
11541
|
+
font-size: 0.7vw; font-weight: 600;
|
|
11542
|
+
display: inline-flex; align-items: center; gap: 0.3vw;
|
|
11543
|
+
letter-spacing: 0.04em; text-transform: uppercase;
|
|
11544
|
+
}
|
|
11545
|
+
.ps-tryon-photo-strip-row {
|
|
11546
|
+
display: grid;
|
|
11547
|
+
grid-template-columns: repeat(3, 1fr);
|
|
11548
|
+
gap: 0.6vw;
|
|
11549
|
+
animation: ps-tryon-photo-strip-fade 0.5s ease;
|
|
11550
|
+
}
|
|
11551
|
+
.ps-tryon-photo-strip-cell {
|
|
11552
|
+
position: relative;
|
|
11553
|
+
aspect-ratio: 3 / 4;
|
|
11554
|
+
overflow: hidden;
|
|
11555
|
+
border-radius: 0.5vw;
|
|
11556
|
+
background: #f3f5f9;
|
|
11557
|
+
box-shadow: 0 0.15vw 0.5vw rgba(20, 30, 60, 0.08);
|
|
11558
|
+
transition: transform 0.25s ease;
|
|
11559
|
+
}
|
|
11560
|
+
.ps-tryon-photo-strip-cell:hover {
|
|
11561
|
+
transform: translateY(-0.15vw);
|
|
11562
|
+
}
|
|
11563
|
+
.ps-tryon-photo-strip-cell > img {
|
|
11564
|
+
width: 100%; height: 100%;
|
|
11565
|
+
object-fit: cover;
|
|
11566
|
+
user-select: none;
|
|
11567
|
+
pointer-events: none;
|
|
11568
|
+
}
|
|
11569
|
+
.ps-tryon-photo-strip-dots {
|
|
11570
|
+
display: flex; justify-content: center; align-items: center; gap: 0.3vw;
|
|
11571
|
+
padding-top: 0.2vw;
|
|
11572
|
+
}
|
|
11573
|
+
.ps-tryon-photo-strip-dot {
|
|
11574
|
+
width: 0.3vw; height: 0.3vw; min-width: 4px; min-height: 4px;
|
|
11575
|
+
border-radius: 999px;
|
|
11576
|
+
background: #d6dbe4;
|
|
11577
|
+
transition: background-color 0.3s ease, width 0.3s ease;
|
|
11578
|
+
}
|
|
11579
|
+
.ps-tryon-photo-strip-dot.is-active {
|
|
11580
|
+
background: var(--ps-accent);
|
|
11581
|
+
width: 0.9vw; min-width: 14px;
|
|
11582
|
+
}
|
|
11583
|
+
@keyframes ps-tryon-photo-strip-fade {
|
|
11584
|
+
from { opacity: 0; transform: translateY(0.3vw); }
|
|
11585
|
+
to { opacity: 1; transform: translateY(0); }
|
|
11586
|
+
}
|
|
11587
|
+
|
|
11588
|
+
/* ── No-fit empty state (single-garment, sizing match% < 50%) ── */
|
|
11589
|
+
.ps-tryon-nofit {
|
|
11590
|
+
background: #ffffff;
|
|
11591
|
+
border: 1px solid #eef2f8;
|
|
11592
|
+
border-radius: 1vw;
|
|
11593
|
+
padding: 3vw 2.4vw 2.6vw;
|
|
11594
|
+
text-align: center;
|
|
11595
|
+
display: flex; flex-direction: column; align-items: center;
|
|
11596
|
+
box-shadow: 0 0.4vw 1.2vw rgba(20, 30, 60, 0.05);
|
|
11597
|
+
}
|
|
11598
|
+
.ps-tryon-nofit-icon {
|
|
11599
|
+
width: 4.4vw; height: 4.4vw; min-width: 56px; min-height: 56px;
|
|
11600
|
+
border-radius: 50%;
|
|
11601
|
+
background: #fef2f2;
|
|
11602
|
+
color: #dc2626;
|
|
11603
|
+
display: flex; align-items: center; justify-content: center;
|
|
11604
|
+
margin-bottom: 1.2vw;
|
|
11605
|
+
}
|
|
11606
|
+
.ps-tryon-nofit-icon svg { width: 50%; height: 50%; }
|
|
11607
|
+
.ps-tryon-nofit-title {
|
|
11608
|
+
font-size: 1.15vw; font-weight: 700; color: #0f172a;
|
|
11609
|
+
margin: 0 0 0.7vw;
|
|
11610
|
+
line-height: 1.3;
|
|
11611
|
+
letter-spacing: -0.01em;
|
|
11612
|
+
}
|
|
11613
|
+
.ps-tryon-nofit-sub {
|
|
11614
|
+
font-size: 0.78vw; color: #6b7280;
|
|
11615
|
+
margin: 0 0 2vw;
|
|
11616
|
+
max-width: 22vw;
|
|
11617
|
+
line-height: 1.6;
|
|
11618
|
+
}
|
|
11619
|
+
.ps-tryon-nofit-actions {
|
|
11620
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
11621
|
+
width: 100%; gap: 1vw;
|
|
11622
|
+
padding-top: 1.2vw;
|
|
11623
|
+
border-top: 1px solid #f1f4fa;
|
|
11406
11624
|
}
|
|
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
11625
|
|
|
11413
11626
|
/* "I don't know" link */
|
|
11414
11627
|
.ps-tryon-v2-dontknow {
|
|
@@ -18741,133 +18954,6 @@ function MobileBottomTabs({ mode, onSwitchToManual, onSwitchToScan, t: t2 }) {
|
|
|
18741
18954
|
)
|
|
18742
18955
|
] });
|
|
18743
18956
|
}
|
|
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
18957
|
const SKELETON_CONNECTIONS$1 = [
|
|
18872
18958
|
["leftShoulder", "rightShoulder"],
|
|
18873
18959
|
["leftShoulder", "leftElbow"],
|
|
@@ -18953,30 +19039,6 @@ function MobileScanningView({
|
|
|
18953
19039
|
onSwitchToManual,
|
|
18954
19040
|
t: t2
|
|
18955
19041
|
}) {
|
|
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
19042
|
const displayImage = previewUrl || productImage || "";
|
|
18981
19043
|
const isPhotoMode = !!previewUrl;
|
|
18982
19044
|
const stages = isPhotoMode ? [
|
|
@@ -18996,11 +19058,18 @@ function MobileScanningView({
|
|
|
18996
19058
|
const img = e.currentTarget;
|
|
18997
19059
|
setDims({ w: img.naturalWidth || img.offsetWidth, h: img.naturalHeight || img.offsetHeight });
|
|
18998
19060
|
};
|
|
19061
|
+
const TOTAL_MS = 6e3;
|
|
19062
|
+
const LAST_HOLD_MS = 1e3;
|
|
19063
|
+
const startRef = reactExports.useRef(Date.now());
|
|
18999
19064
|
const [stageIdx, setStageIdx] = reactExports.useState(0);
|
|
19000
19065
|
reactExports.useEffect(() => {
|
|
19066
|
+
const stepMs = (TOTAL_MS - LAST_HOLD_MS) / Math.max(1, stages.length - 1);
|
|
19001
19067
|
const id2 = setInterval(() => {
|
|
19002
|
-
|
|
19003
|
-
|
|
19068
|
+
const elapsed = Date.now() - startRef.current;
|
|
19069
|
+
const idx = Math.min(stages.length - 1, Math.floor(elapsed / stepMs));
|
|
19070
|
+
setStageIdx((prev) => prev === idx ? prev : idx);
|
|
19071
|
+
if (idx >= stages.length - 1) clearInterval(id2);
|
|
19072
|
+
}, 100);
|
|
19004
19073
|
return () => clearInterval(id2);
|
|
19005
19074
|
}, [stages.length]);
|
|
19006
19075
|
reactExports.useEffect(() => {
|
|
@@ -19235,6 +19304,132 @@ function MultiSectionMobile({
|
|
|
19235
19304
|
sizeGuide ? null : null
|
|
19236
19305
|
] });
|
|
19237
19306
|
}
|
|
19307
|
+
const TARGET_SECONDS = 22;
|
|
19308
|
+
function TryOnGenerationBadge({
|
|
19309
|
+
tryOnStartedAt,
|
|
19310
|
+
t: t2
|
|
19311
|
+
}) {
|
|
19312
|
+
const [, force] = reactExports.useState(0);
|
|
19313
|
+
reactExports.useEffect(() => {
|
|
19314
|
+
if (tryOnStartedAt == null) return;
|
|
19315
|
+
const id2 = setInterval(() => force((v2) => v2 + 1), 200);
|
|
19316
|
+
return () => clearInterval(id2);
|
|
19317
|
+
}, [tryOnStartedAt]);
|
|
19318
|
+
if (tryOnStartedAt == null) return null;
|
|
19319
|
+
const elapsed = (Date.now() - tryOnStartedAt) / 1e3;
|
|
19320
|
+
const pct = Math.min(95, elapsed / TARGET_SECONDS * 100);
|
|
19321
|
+
const pctRounded = Math.round(pct);
|
|
19322
|
+
const remaining = Math.max(0, TARGET_SECONDS - Math.floor(elapsed));
|
|
19323
|
+
const etaText = elapsed >= TARGET_SECONDS ? t2("almost done") : `~${remaining}s ${t2("left")}`;
|
|
19324
|
+
const statuses = [
|
|
19325
|
+
t2("Preparing your image"),
|
|
19326
|
+
t2("Analyzing body proportions"),
|
|
19327
|
+
t2("Mapping garment to body"),
|
|
19328
|
+
t2("Refining drape and shadows"),
|
|
19329
|
+
t2("Almost done")
|
|
19330
|
+
];
|
|
19331
|
+
const stepIdx = Math.min(
|
|
19332
|
+
statuses.length - 1,
|
|
19333
|
+
Math.floor(elapsed / TARGET_SECONDS * statuses.length)
|
|
19334
|
+
);
|
|
19335
|
+
const status = statuses[stepIdx];
|
|
19336
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge", role: "status", "aria-live": "polite", children: [
|
|
19337
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-row", children: [
|
|
19338
|
+
/* @__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: [
|
|
19339
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("defs", { children: /* @__PURE__ */ jsxRuntimeExports.jsxs("linearGradient", { id: "ps-tryon-badge-grad", x1: "0", y1: "0", x2: "1", y2: "1", children: [
|
|
19340
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "0%", stopColor: "#3B82F6" }),
|
|
19341
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("stop", { offset: "100%", stopColor: "#2563EB" })
|
|
19342
|
+
] }) }),
|
|
19343
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "9", fill: "none", stroke: "rgba(59,130,246,0.18)", strokeWidth: "2.4" }),
|
|
19344
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
19345
|
+
"circle",
|
|
19346
|
+
{
|
|
19347
|
+
cx: "12",
|
|
19348
|
+
cy: "12",
|
|
19349
|
+
r: "9",
|
|
19350
|
+
fill: "none",
|
|
19351
|
+
stroke: "url(#ps-tryon-badge-grad)",
|
|
19352
|
+
strokeWidth: "2.4",
|
|
19353
|
+
strokeLinecap: "round",
|
|
19354
|
+
strokeDasharray: "56.5",
|
|
19355
|
+
strokeDashoffset: "38"
|
|
19356
|
+
}
|
|
19357
|
+
)
|
|
19358
|
+
] }) }),
|
|
19359
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-badge-title", children: t2("Generating your look...") }),
|
|
19360
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-pct", children: [
|
|
19361
|
+
pctRounded,
|
|
19362
|
+
"%"
|
|
19363
|
+
] })
|
|
19364
|
+
] }),
|
|
19365
|
+
/* @__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}%` } }) }),
|
|
19366
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-badge-foot", children: [
|
|
19367
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-status", children: [
|
|
19368
|
+
/* @__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: [
|
|
19369
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "6", y1: "10", x2: "6", y2: "14" }),
|
|
19370
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "10", y1: "6", x2: "10", y2: "18" }),
|
|
19371
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "14", y1: "9", x2: "14", y2: "15" }),
|
|
19372
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "18", y1: "11", x2: "18", y2: "13" })
|
|
19373
|
+
] }) }),
|
|
19374
|
+
status
|
|
19375
|
+
] }),
|
|
19376
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-badge-eta", children: [
|
|
19377
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
19378
|
+
"svg",
|
|
19379
|
+
{
|
|
19380
|
+
width: "11",
|
|
19381
|
+
height: "11",
|
|
19382
|
+
viewBox: "0 0 24 24",
|
|
19383
|
+
fill: "none",
|
|
19384
|
+
stroke: "currentColor",
|
|
19385
|
+
strokeWidth: "2",
|
|
19386
|
+
strokeLinecap: "round",
|
|
19387
|
+
strokeLinejoin: "round",
|
|
19388
|
+
"aria-hidden": "true",
|
|
19389
|
+
children: [
|
|
19390
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
19391
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("polyline", { points: "12 6 12 12 16 14" })
|
|
19392
|
+
]
|
|
19393
|
+
}
|
|
19394
|
+
),
|
|
19395
|
+
etaText
|
|
19396
|
+
] })
|
|
19397
|
+
] })
|
|
19398
|
+
] });
|
|
19399
|
+
}
|
|
19400
|
+
const PER_SLIDE = 3;
|
|
19401
|
+
const CYCLE_MS = 4e3;
|
|
19402
|
+
function ProductPhotoCarouselCard({
|
|
19403
|
+
photos,
|
|
19404
|
+
productTitle,
|
|
19405
|
+
t: t2
|
|
19406
|
+
}) {
|
|
19407
|
+
const [groupIdx, setGroupIdx] = reactExports.useState(0);
|
|
19408
|
+
const totalGroups = Math.max(1, Math.ceil(photos.length / PER_SLIDE));
|
|
19409
|
+
reactExports.useEffect(() => {
|
|
19410
|
+
if (totalGroups < 2) return;
|
|
19411
|
+
const id2 = setInterval(() => setGroupIdx((v2) => (v2 + 1) % totalGroups), CYCLE_MS);
|
|
19412
|
+
return () => clearInterval(id2);
|
|
19413
|
+
}, [totalGroups]);
|
|
19414
|
+
if (!photos || photos.length === 0) return null;
|
|
19415
|
+
const start = groupIdx * PER_SLIDE;
|
|
19416
|
+
const slide = photos.slice(start, start + PER_SLIDE);
|
|
19417
|
+
while (slide.length < PER_SLIDE && photos.length >= PER_SLIDE) {
|
|
19418
|
+
slide.push(photos[(start + slide.length) % photos.length]);
|
|
19419
|
+
}
|
|
19420
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-photo-strip", role: "group", "aria-label": t2("Product photos"), children: [
|
|
19421
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-photo-strip-head", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-photo-strip-badge", children: [
|
|
19422
|
+
/* @__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: [
|
|
19423
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2" }),
|
|
19424
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "9", cy: "9", r: "2" }),
|
|
19425
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21" })
|
|
19426
|
+
] }),
|
|
19427
|
+
t2("Gallery")
|
|
19428
|
+
] }) }),
|
|
19429
|
+
/* @__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),
|
|
19430
|
+
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)) })
|
|
19431
|
+
] });
|
|
19432
|
+
}
|
|
19238
19433
|
function garmentIconForSection(name) {
|
|
19239
19434
|
const n2 = name.toLowerCase();
|
|
19240
19435
|
if (n2.includes("jacket") || n2.includes("blazer") || n2.includes("coat")) return garmentJacketImg;
|
|
@@ -19258,62 +19453,6 @@ const SKELETON_CONNECTIONS = [
|
|
|
19258
19453
|
["rightHip", "rightKnee"],
|
|
19259
19454
|
["rightKnee", "rightAnkle"]
|
|
19260
19455
|
];
|
|
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
19456
|
function FaceOverlay({
|
|
19318
19457
|
landmarks,
|
|
19319
19458
|
imgWidth,
|
|
@@ -19440,14 +19579,20 @@ function StageCycler({
|
|
|
19440
19579
|
{ title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the size guide.") },
|
|
19441
19580
|
{ title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
|
|
19442
19581
|
];
|
|
19582
|
+
const TOTAL_MS = 6e3;
|
|
19583
|
+
const LAST_HOLD_MS = 1e3;
|
|
19584
|
+
const startRef = reactExports.useRef(Date.now());
|
|
19443
19585
|
const [idx, setIdx] = reactExports.useState(0);
|
|
19444
19586
|
reactExports.useEffect(() => {
|
|
19445
|
-
|
|
19587
|
+
const stepMs = (TOTAL_MS - LAST_HOLD_MS) / Math.max(1, sizingStages.length - 1);
|
|
19446
19588
|
const id2 = setInterval(() => {
|
|
19447
|
-
|
|
19448
|
-
|
|
19589
|
+
const elapsed = Date.now() - startRef.current;
|
|
19590
|
+
const next = Math.min(sizingStages.length - 1, Math.floor(elapsed / stepMs));
|
|
19591
|
+
setIdx((prev) => prev === next ? prev : next);
|
|
19592
|
+
if (next >= sizingStages.length - 1) clearInterval(id2);
|
|
19593
|
+
}, 100);
|
|
19449
19594
|
return () => clearInterval(id2);
|
|
19450
|
-
}, [
|
|
19595
|
+
}, [sizingStages.length]);
|
|
19451
19596
|
const current = sizingStages[idx] ?? sizingStages[0];
|
|
19452
19597
|
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
19598
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msc-stage-title", children: current.title }),
|
|
@@ -19721,19 +19866,11 @@ function SectionDetailView({
|
|
|
19721
19866
|
internationalSizes,
|
|
19722
19867
|
continueLabel,
|
|
19723
19868
|
renderRaw = false,
|
|
19724
|
-
sectionFound
|
|
19725
|
-
onSelectForTryOn,
|
|
19726
|
-
onRegenerateTryOn,
|
|
19727
|
-
pendingOverride,
|
|
19728
|
-
retryLoading,
|
|
19729
|
-
retryStartedAt
|
|
19869
|
+
sectionFound
|
|
19730
19870
|
}) {
|
|
19731
19871
|
const recSize = sectionResult?.recommendedSize || "";
|
|
19732
|
-
const [selectedSize, setSelectedSize] = reactExports.useState(
|
|
19733
|
-
pendingOverride?.selectedSize && pendingOverride.selectedSize !== (sectionResult?.recommendedSize || "") ? pendingOverride.selectedSize : null
|
|
19734
|
-
);
|
|
19872
|
+
const [selectedSize, setSelectedSize] = reactExports.useState(null);
|
|
19735
19873
|
const tryOnElapsedS = useElapsedSeconds(tryOnStartedAt ?? null);
|
|
19736
|
-
const retryElapsedS = useElapsedSeconds(retryStartedAt ?? null);
|
|
19737
19874
|
const unitLblLower = unitLbl.toLowerCase();
|
|
19738
19875
|
const displayUnitId = unitLblLower.includes("mm") ? "mm" : unitLblLower.includes("cm") ? "cm" : "in";
|
|
19739
19876
|
const fromUnit = chartUnit || displayUnitId;
|
|
@@ -19746,9 +19883,7 @@ function SectionDetailView({
|
|
|
19746
19883
|
const countryOptions = internationalSizes ? Object.keys(internationalSizes) : [];
|
|
19747
19884
|
const [selectedCountry, setSelectedCountry] = reactExports.useState(null);
|
|
19748
19885
|
const recLength = lengthEntry?.secResult?.recommendedSize || "";
|
|
19749
|
-
const [selectedLength, setSelectedLength] = reactExports.useState(
|
|
19750
|
-
pendingOverride?.selectedLength && pendingOverride.selectedLength !== recLength ? pendingOverride.selectedLength : null
|
|
19751
|
-
);
|
|
19886
|
+
const [selectedLength, setSelectedLength] = reactExports.useState(null);
|
|
19752
19887
|
const lengthSizes = reactExports.useMemo(() => {
|
|
19753
19888
|
if (!lengthEntry) return [];
|
|
19754
19889
|
const sec = lengthEntry.section;
|
|
@@ -19975,8 +20110,8 @@ function SectionDetailView({
|
|
|
19975
20110
|
const userInColUnit = colIsCm && userIsInches ? +(userNum2 * 2.54).toFixed(1) : !colIsCm && !userIsInches ? +(userNum2 * 2.54).toFixed(1) : userNum2;
|
|
19976
20111
|
const range2 = rMaxRaw - rMinRaw;
|
|
19977
20112
|
const threshold2 = range2 > 0 ? range2 * 0.5 : rMinRaw * 0.05 || 3;
|
|
19978
|
-
const
|
|
19979
|
-
if (userInColUnit
|
|
20113
|
+
const tol = colIsCm ? 2.54 : 1;
|
|
20114
|
+
if (userInColUnit > rMinRaw - tol && userInColUnit < rMaxRaw + tol) fit2 = "good";
|
|
19980
20115
|
else if (userInColUnit < rMinRaw) {
|
|
19981
20116
|
const diff = rMinRaw - userInColUnit;
|
|
19982
20117
|
fit2 = diff > threshold2 * 2 ? "too-long" : diff > threshold2 ? "long" : "a-bit-long";
|
|
@@ -20009,8 +20144,10 @@ function SectionDetailView({
|
|
|
20009
20144
|
const measLower = m2.measurement.toLowerCase();
|
|
20010
20145
|
const isDirectional = /length|inseam|sleeve|hem|rise/.test(measLower);
|
|
20011
20146
|
let fit;
|
|
20012
|
-
const
|
|
20013
|
-
|
|
20147
|
+
const perfectTol = chartUnit === "cm" ? 2.54 : chartUnit === "mm" ? 25.4 : 1;
|
|
20148
|
+
const lowBound = rMin - perfectTol;
|
|
20149
|
+
const highBound = rMax + perfectTol;
|
|
20150
|
+
if (userNum > lowBound && userNum < highBound) {
|
|
20014
20151
|
fit = "good";
|
|
20015
20152
|
} else if (isDirectional) {
|
|
20016
20153
|
const diff = userNum > rMax ? userNum - rMax : rMin - userNum;
|
|
@@ -20057,65 +20194,6 @@ function SectionDetailView({
|
|
|
20057
20194
|
const start = Math.max(0, Math.min(lengthOptions.length - 3, idx - 1));
|
|
20058
20195
|
return lengthOptions.slice(start, start + 3);
|
|
20059
20196
|
})();
|
|
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
20197
|
if (isMobileProp) {
|
|
20120
20198
|
const cleanSectionName = sectionName.replace(/\s*[—–-]\s*.*/g, "");
|
|
20121
20199
|
const measurementDesc = (area) => {
|
|
@@ -20599,169 +20677,7 @@ function SectionDetailView({
|
|
|
20599
20677
|
s
|
|
20600
20678
|
);
|
|
20601
20679
|
}) })
|
|
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
|
-
})() })
|
|
20680
|
+
] })
|
|
20765
20681
|
] }) }),
|
|
20766
20682
|
/* @__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
20683
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-bp-back-btn", onClick: onBack, type: "button", style: { fontSize: "0.7vw" }, children: [
|
|
@@ -20837,15 +20753,13 @@ function SizeResultView({
|
|
|
20837
20753
|
sizeGuide,
|
|
20838
20754
|
resultImageUrl,
|
|
20839
20755
|
productImage,
|
|
20756
|
+
productImages,
|
|
20840
20757
|
productTitle,
|
|
20841
20758
|
productMaterial,
|
|
20842
20759
|
productDescription,
|
|
20843
20760
|
sizingUnit,
|
|
20844
20761
|
setView,
|
|
20845
20762
|
handleDownload,
|
|
20846
|
-
onRetryWithFit,
|
|
20847
|
-
retryLoading,
|
|
20848
|
-
retryStartedAt,
|
|
20849
20763
|
selectedFile,
|
|
20850
20764
|
previewUrl,
|
|
20851
20765
|
handleFileSelect,
|
|
@@ -20864,7 +20778,6 @@ function SizeResultView({
|
|
|
20864
20778
|
userHeightCm,
|
|
20865
20779
|
pendingCustomSizes: pendingCustomSizesProp,
|
|
20866
20780
|
onPendingCustomSizeChange,
|
|
20867
|
-
onRegenerateTryOn,
|
|
20868
20781
|
t: t2
|
|
20869
20782
|
}) {
|
|
20870
20783
|
const resultUnitRaw = (sizingResult?.unit || sizingUnit || "").toString().toLowerCase();
|
|
@@ -20970,9 +20883,6 @@ function SizeResultView({
|
|
|
20970
20883
|
const [poseReady, setPoseReady] = reactExports.useState(false);
|
|
20971
20884
|
const [imgDims, setImgDims] = reactExports.useState({ w: 800, h: 1200 });
|
|
20972
20885
|
const pendingCustomSizes = pendingCustomSizesProp ?? {};
|
|
20973
|
-
const setPendingCustomSize = (sectionName, override) => {
|
|
20974
|
-
onPendingCustomSizeChange?.(sectionName, override);
|
|
20975
|
-
};
|
|
20976
20886
|
const handleImgLoad = reactExports.useCallback((e) => {
|
|
20977
20887
|
const el2 = e.currentTarget;
|
|
20978
20888
|
if (el2.naturalWidth && el2.naturalHeight) {
|
|
@@ -21141,7 +21051,7 @@ function SizeResultView({
|
|
|
21141
21051
|
const prettyLength = lengthRec.replace(/\s+/g, " ").trim();
|
|
21142
21052
|
return `${baseSize} / ${prettyLength}`;
|
|
21143
21053
|
}, [lengthEntries, allSectionEntries]);
|
|
21144
|
-
|
|
21054
|
+
reactExports.useMemo(() => {
|
|
21145
21055
|
const cm = userHeightCm || 0;
|
|
21146
21056
|
if (!cm) return "";
|
|
21147
21057
|
if (unitLbl === "in") {
|
|
@@ -21153,8 +21063,8 @@ function SizeResultView({
|
|
|
21153
21063
|
return `${Math.round(cm)} cm`;
|
|
21154
21064
|
}, [userHeightCm, unitLbl]);
|
|
21155
21065
|
const hasPhoto = !!previewUrl;
|
|
21156
|
-
const isSnapProcessing = hasPhoto &&
|
|
21157
|
-
const isSizingOnly = !hasPhoto && sizingLoading
|
|
21066
|
+
const isSnapProcessing = hasPhoto && sizingLoading;
|
|
21067
|
+
const isSizingOnly = !hasPhoto && sizingLoading;
|
|
21158
21068
|
const sizingDone = !!sizingResult;
|
|
21159
21069
|
const tryOnDone = !!resultImageUrl && !tryOnProcessing;
|
|
21160
21070
|
const allDone = hasPhoto ? sizingDone && tryOnDone : sizingDone;
|
|
@@ -21221,20 +21131,12 @@ function SizeResultView({
|
|
|
21221
21131
|
onLoad: handleImgLoad
|
|
21222
21132
|
}
|
|
21223
21133
|
),
|
|
21224
|
-
|
|
21134
|
+
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
21135
|
] }),
|
|
21226
21136
|
(() => {
|
|
21227
21137
|
const isFaceCategory = measurementType === "face" || measurementType === "head";
|
|
21228
21138
|
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(
|
|
21139
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-right-col", style: { display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21238
21140
|
StageCycler,
|
|
21239
21141
|
{
|
|
21240
21142
|
category: isFaceCategory ? measurementType : "body",
|
|
@@ -21272,11 +21174,6 @@ function SizeResultView({
|
|
|
21272
21174
|
})(),
|
|
21273
21175
|
onBack: () => setActiveSection(null),
|
|
21274
21176
|
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
21177
|
productImage: resultImageUrl || productImage,
|
|
21281
21178
|
productTitle,
|
|
21282
21179
|
isMobile: true,
|
|
@@ -21314,10 +21211,7 @@ function SizeResultView({
|
|
|
21314
21211
|
] });
|
|
21315
21212
|
}
|
|
21316
21213
|
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
|
-
] }),
|
|
21214
|
+
/* @__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
21215
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel", children: [
|
|
21322
21216
|
mismatchNotice,
|
|
21323
21217
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -21339,11 +21233,6 @@ function SizeResultView({
|
|
|
21339
21233
|
})(),
|
|
21340
21234
|
onBack: () => setActiveSection(null),
|
|
21341
21235
|
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
21236
|
t: t2
|
|
21348
21237
|
}
|
|
21349
21238
|
)
|
|
@@ -21413,11 +21302,8 @@ function SizeResultView({
|
|
|
21413
21302
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2", children: [
|
|
21414
21303
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
|
|
21415
21304
|
/* @__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 }),
|
|
21305
|
+
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
|
|
21306
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing }),
|
|
21421
21307
|
resultImageUrl && !tryOnProcessing && poseReady && poseLines && /* @__PURE__ */ jsxRuntimeExports.jsx(MeasurementOverlay, { lines: poseLines, fitRows: (() => {
|
|
21422
21308
|
const all = [...sizingResult?.matchDetails || []];
|
|
21423
21309
|
if (sizingResult?.sections) {
|
|
@@ -21483,11 +21369,15 @@ function SizeResultView({
|
|
|
21483
21369
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21484
21370
|
"span",
|
|
21485
21371
|
{
|
|
21486
|
-
className:
|
|
21487
|
-
|
|
21488
|
-
children: isOverridden ? t2("your selection · not recommended") : heightLineLabel ? `${t2("recommended")} · ${heightLineLabel}` : t2("recommended")
|
|
21372
|
+
className: `ps-tryon-sr-card-v2-rec-pill${isOverridden ? " is-overridden" : ""}`,
|
|
21373
|
+
children: isOverridden ? t2("YOUR SELECTION") : t2("RECOMMENDED")
|
|
21489
21374
|
}
|
|
21490
|
-
)
|
|
21375
|
+
),
|
|
21376
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-sr-card-v2-view", children: [
|
|
21377
|
+
t2("VIEW DETAILS"),
|
|
21378
|
+
" ",
|
|
21379
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: "›" })
|
|
21380
|
+
] })
|
|
21491
21381
|
] }),
|
|
21492
21382
|
sectionImg && /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: sectionImg, alt: name, className: "ps-tryon-sr-card-v2-img" })
|
|
21493
21383
|
] }, name);
|
|
@@ -21578,11 +21468,6 @@ function SizeResultView({
|
|
|
21578
21468
|
},
|
|
21579
21469
|
backLabel: t2("Back"),
|
|
21580
21470
|
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
21471
|
onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
|
|
21587
21472
|
continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
|
|
21588
21473
|
tryOnProcessing,
|
|
@@ -21612,50 +21497,158 @@ function SizeResultView({
|
|
|
21612
21497
|
}
|
|
21613
21498
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2", children: [
|
|
21614
21499
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-bg", style: { position: "relative" }, children: [
|
|
21615
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21616
|
-
|
|
21500
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21501
|
+
"img",
|
|
21502
|
+
{
|
|
21503
|
+
src: tryOnProcessing && previewUrl ? previewUrl : resultImageUrl || productImage,
|
|
21504
|
+
alt: productTitle,
|
|
21505
|
+
className: "ps-tryon-v2-bg-img",
|
|
21506
|
+
onLoad: handleImgLoad
|
|
21507
|
+
}
|
|
21508
|
+
),
|
|
21509
|
+
tryOnProcessing && /* @__PURE__ */ jsxRuntimeExports.jsx(TryOnGenerationBadge, { tryOnStartedAt: tryOnStartedAt ?? null, t: t2 }),
|
|
21510
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(RegenScanOverlay, { active: !!tryOnProcessing }),
|
|
21511
|
+
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
21512
|
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
21513
|
!isAccessory && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "ps-tryon-sr-glass-btn", onClick: () => setShowLines(!showLines), children: showLines ? t2("Hide Fit") : t2("Show Fit") }),
|
|
21619
21514
|
/* @__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 })
|
|
21515
|
+
] })
|
|
21622
21516
|
] }),
|
|
21623
21517
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel", children: [
|
|
21624
21518
|
mismatchNotice,
|
|
21625
|
-
|
|
21626
|
-
|
|
21627
|
-
|
|
21628
|
-
|
|
21629
|
-
|
|
21630
|
-
|
|
21631
|
-
|
|
21632
|
-
|
|
21633
|
-
|
|
21634
|
-
|
|
21635
|
-
|
|
21636
|
-
|
|
21637
|
-
|
|
21638
|
-
|
|
21639
|
-
|
|
21640
|
-
|
|
21519
|
+
activeSection === sectionName ? (
|
|
21520
|
+
/* DETAIL VIEW — full size table, same as multi-garment */
|
|
21521
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21522
|
+
SectionDetailView,
|
|
21523
|
+
{
|
|
21524
|
+
sectionName,
|
|
21525
|
+
section: singleSection,
|
|
21526
|
+
sectionResult: singleResult,
|
|
21527
|
+
sectionFound: sizingResult?.found,
|
|
21528
|
+
userMeasurements: singleUserMeasurements,
|
|
21529
|
+
unitLbl,
|
|
21530
|
+
chartUnit: resultUnit,
|
|
21531
|
+
lengthEntry: null,
|
|
21532
|
+
onBack: () => setActiveSection(null),
|
|
21533
|
+
backLabel: t2("Back"),
|
|
21534
|
+
internationalSizes: sizingResult?.internationalSizes,
|
|
21535
|
+
onTryOn: resultImageUrl || vtoExcluded ? void 0 : handleSingleTryOn,
|
|
21536
|
+
continueLabel: resultImageUrl ? t2("Continue Shopping") : void 0,
|
|
21537
|
+
tryOnProcessing,
|
|
21538
|
+
tryOnStartedAt,
|
|
21539
|
+
t: t2,
|
|
21540
|
+
renderRaw: isAccessory
|
|
21541
|
+
}
|
|
21542
|
+
)
|
|
21543
|
+
) : sizingResult?.found === false ? (
|
|
21544
|
+
/* NO-FIT EMPTY STATE — match% < 50% or backend reports
|
|
21545
|
+
no valid size. Skip the card + gallery + try-on
|
|
21546
|
+
entirely so the user gets immediate feedback that
|
|
21547
|
+
this product doesn't carry their size. */
|
|
21548
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-nofit", children: [
|
|
21549
|
+
/* @__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: [
|
|
21550
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
21551
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "15", y1: "9", x2: "9", y2: "15" }),
|
|
21552
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("line", { x1: "9", y1: "9", x2: "15", y2: "15" })
|
|
21553
|
+
] }) }),
|
|
21554
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-nofit-title", children: t2("No size matches your measurements") }),
|
|
21555
|
+
/* @__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.") }),
|
|
21556
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-nofit-actions", children: [
|
|
21557
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21558
|
+
"button",
|
|
21559
|
+
{
|
|
21560
|
+
className: "ps-bp-back-btn",
|
|
21561
|
+
onClick: () => {
|
|
21562
|
+
if (resultImageUrl) onResetTryOn?.();
|
|
21563
|
+
else setView("body-profile");
|
|
21564
|
+
},
|
|
21565
|
+
type: "button",
|
|
21566
|
+
children: [
|
|
21567
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
|
|
21568
|
+
" ",
|
|
21569
|
+
t2("Back")
|
|
21570
|
+
]
|
|
21571
|
+
}
|
|
21572
|
+
),
|
|
21573
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-v2-cta", style: { marginTop: 0 }, onClick: onClose, type: "button", children: [
|
|
21574
|
+
t2("Continue Shopping"),
|
|
21575
|
+
" →"
|
|
21576
|
+
] })
|
|
21577
|
+
] })
|
|
21578
|
+
] })
|
|
21579
|
+
) : (
|
|
21580
|
+
/* CARD VIEW — clickable summary card + gallery strip */
|
|
21581
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
21582
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: t2("Your Perfect Fit") }),
|
|
21583
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-v2-subtitle", children: t2("Tap the card for detailed breakdown") }),
|
|
21584
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-sep" }),
|
|
21585
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-sr-cards-v2", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21586
|
+
"button",
|
|
21587
|
+
{
|
|
21588
|
+
className: `ps-tryon-sr-card-v2 ps-full${pendingCustomSizes[sectionName] ? " ps-overridden" : ""}`,
|
|
21589
|
+
onClick: () => setActiveSection(sectionName),
|
|
21590
|
+
type: "button",
|
|
21591
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-sr-card-v2-text", children: [
|
|
21592
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-sr-card-v2-label", children: sectionName }),
|
|
21593
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-tryon-sr-card-v2-value", children: pendingCustomSizes[sectionName]?.displayLabel || singleResult.recommendedSize || "—" }),
|
|
21594
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
21595
|
+
"span",
|
|
21596
|
+
{
|
|
21597
|
+
className: `ps-tryon-sr-card-v2-rec-pill${pendingCustomSizes[sectionName] ? " is-overridden" : ""}`,
|
|
21598
|
+
children: pendingCustomSizes[sectionName] ? t2("YOUR SELECTION") : t2("RECOMMENDED")
|
|
21599
|
+
}
|
|
21600
|
+
),
|
|
21601
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ps-tryon-sr-card-v2-view", children: [
|
|
21602
|
+
t2("VIEW DETAILS"),
|
|
21603
|
+
" ",
|
|
21604
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { "aria-hidden": "true", children: "›" })
|
|
21605
|
+
] })
|
|
21606
|
+
] })
|
|
21641
21607
|
}
|
|
21642
|
-
},
|
|
21643
|
-
|
|
21644
|
-
|
|
21645
|
-
|
|
21646
|
-
|
|
21647
|
-
|
|
21648
|
-
|
|
21649
|
-
|
|
21650
|
-
|
|
21651
|
-
|
|
21652
|
-
|
|
21653
|
-
|
|
21654
|
-
|
|
21655
|
-
|
|
21656
|
-
|
|
21608
|
+
) }),
|
|
21609
|
+
productImages && productImages.length >= 2 && /* @__PURE__ */ jsxRuntimeExports.jsx(ProductPhotoCarouselCard, { photos: productImages, productTitle, t: t2 }),
|
|
21610
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginTop: "0.5vw", gap: "0.5vw" }, children: [
|
|
21611
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21612
|
+
"button",
|
|
21613
|
+
{
|
|
21614
|
+
className: "ps-bp-back-btn",
|
|
21615
|
+
onClick: () => {
|
|
21616
|
+
if (resultImageUrl) onResetTryOn?.();
|
|
21617
|
+
else setView("body-profile");
|
|
21618
|
+
},
|
|
21619
|
+
type: "button",
|
|
21620
|
+
children: [
|
|
21621
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-back-arrow", children: "←" }),
|
|
21622
|
+
" ",
|
|
21623
|
+
t2("Back")
|
|
21624
|
+
]
|
|
21625
|
+
}
|
|
21626
|
+
),
|
|
21627
|
+
resultImageUrl && !tryOnProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-v2-cta", style: { marginTop: 0 }, onClick: onClose, children: [
|
|
21628
|
+
t2("Continue Shopping"),
|
|
21629
|
+
" →"
|
|
21630
|
+
] }) : vtoExcluded ? /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { className: "ps-tryon-v2-cta", style: { marginTop: 0 }, onClick: onClose, children: [
|
|
21631
|
+
t2("Continue Shopping"),
|
|
21632
|
+
" →"
|
|
21633
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
21634
|
+
"button",
|
|
21635
|
+
{
|
|
21636
|
+
className: "ps-tryon-v2-cta",
|
|
21637
|
+
style: { marginTop: 0 },
|
|
21638
|
+
disabled: tryOnProcessing,
|
|
21639
|
+
onClick: handleSingleTryOn,
|
|
21640
|
+
type: "button",
|
|
21641
|
+
children: [
|
|
21642
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(CameraIcon$1, { size: 14 }),
|
|
21643
|
+
" ",
|
|
21644
|
+
tryOnProcessing ? t2("Processing...") : t2("Try It On")
|
|
21645
|
+
]
|
|
21646
|
+
}
|
|
21647
|
+
)
|
|
21648
|
+
] })
|
|
21649
|
+
] })
|
|
21657
21650
|
)
|
|
21658
|
-
] },
|
|
21651
|
+
] }, `panel-single-${activeSection ? "detail" : "card"}`)
|
|
21659
21652
|
] });
|
|
21660
21653
|
})()
|
|
21661
21654
|
),
|
|
@@ -27696,6 +27689,19 @@ function detectMeasurementType(title) {
|
|
|
27696
27689
|
if (/\b(sunglass|sunglasses|eyewear|eyeglasses|glasses|spectacles|optical|goggles|frames|aviator|wayfarer|lens)\b/.test(t2)) return "face";
|
|
27697
27690
|
return "body";
|
|
27698
27691
|
}
|
|
27692
|
+
function computeMatchScore(recData) {
|
|
27693
|
+
if (!recData) return null;
|
|
27694
|
+
const all = [];
|
|
27695
|
+
for (const m2 of recData.matchDetails ?? []) all.push(m2);
|
|
27696
|
+
if (recData.sections) {
|
|
27697
|
+
for (const sec of Object.values(recData.sections)) {
|
|
27698
|
+
for (const m2 of sec?.matchDetails ?? []) all.push(m2);
|
|
27699
|
+
}
|
|
27700
|
+
}
|
|
27701
|
+
if (all.length === 0) return null;
|
|
27702
|
+
const good = all.filter((r2) => r2.fit === "good" || r2.fit === "a-bit-tight" || r2.fit === "a-bit-loose").length;
|
|
27703
|
+
return Math.round(good / all.length * 100);
|
|
27704
|
+
}
|
|
27699
27705
|
function measurementTypeToVtoCategory(type) {
|
|
27700
27706
|
if (type === "face") return "sunglasses";
|
|
27701
27707
|
if (type === "head") return "hat";
|
|
@@ -27704,6 +27710,8 @@ function measurementTypeToVtoCategory(type) {
|
|
|
27704
27710
|
}
|
|
27705
27711
|
function PrimeStyleTryonInner({
|
|
27706
27712
|
productImage,
|
|
27713
|
+
productImages,
|
|
27714
|
+
garmentReferenceImage,
|
|
27707
27715
|
productTitle = "Product",
|
|
27708
27716
|
productId,
|
|
27709
27717
|
productDescription,
|
|
@@ -27744,9 +27752,7 @@ function PrimeStyleTryonInner({
|
|
|
27744
27752
|
const [resultImageUrl, setResultImageUrl] = reactExports.useState(null);
|
|
27745
27753
|
const [errorMessage, setErrorMessage] = reactExports.useState(null);
|
|
27746
27754
|
const [dragOver, setDragOver] = reactExports.useState(false);
|
|
27747
|
-
const [retryLoading, setRetryLoading] = reactExports.useState(false);
|
|
27748
27755
|
const [tryOnStartedAt, setTryOnStartedAt] = reactExports.useState(null);
|
|
27749
|
-
const [retryStartedAt, setRetryStartedAt] = reactExports.useState(null);
|
|
27750
27756
|
const [activeSection, setActiveSection] = reactExports.useState(null);
|
|
27751
27757
|
const [pendingCustomSizes, setPendingCustomSizes] = reactExports.useState({});
|
|
27752
27758
|
const pendingCustomSizesRef = reactExports.useRef({});
|
|
@@ -27756,7 +27762,7 @@ function PrimeStyleTryonInner({
|
|
|
27756
27762
|
const sizingResultRef = reactExports.useRef(null);
|
|
27757
27763
|
const sizeGuideRef = reactExports.useRef(null);
|
|
27758
27764
|
const resultImageUrlRef = reactExports.useRef(null);
|
|
27759
|
-
|
|
27765
|
+
reactExports.useCallback((sectionName, override) => {
|
|
27760
27766
|
setPendingCustomSizes((prev) => {
|
|
27761
27767
|
const next = { ...prev };
|
|
27762
27768
|
if (override === null) delete next[sectionName];
|
|
@@ -27778,6 +27784,7 @@ function PrimeStyleTryonInner({
|
|
|
27778
27784
|
const [estimationDone, setEstimationDone] = reactExports.useState(false);
|
|
27779
27785
|
const [tryOnProcessing, setTryOnProcessing] = reactExports.useState(false);
|
|
27780
27786
|
const [sizeGuide, setSizeGuide] = reactExports.useState(null);
|
|
27787
|
+
const noFitFoundRef = reactExports.useRef(false);
|
|
27781
27788
|
reactExports.useEffect(() => {
|
|
27782
27789
|
sizingResultRef.current = sizingResult;
|
|
27783
27790
|
}, [sizingResult]);
|
|
@@ -27836,6 +27843,7 @@ function PrimeStyleTryonInner({
|
|
|
27836
27843
|
const [faceLandmarks, setFaceLandmarks] = reactExports.useState(null);
|
|
27837
27844
|
const selectedFileRef = reactExports.useRef(null);
|
|
27838
27845
|
const modelImageIdRef = reactExports.useRef(null);
|
|
27846
|
+
const autoTryOnFiredRef = reactExports.useRef(false);
|
|
27839
27847
|
reactExports.useEffect(() => {
|
|
27840
27848
|
try {
|
|
27841
27849
|
const key = getApiKey();
|
|
@@ -28243,6 +28251,15 @@ function PrimeStyleTryonInner({
|
|
|
28243
28251
|
unsubRef.current = null;
|
|
28244
28252
|
}, []);
|
|
28245
28253
|
const handleVtoUpdate = reactExports.useCallback((update) => {
|
|
28254
|
+
if (noFitFoundRef.current) {
|
|
28255
|
+
if (update.status === "completed" || update.status === "failed") {
|
|
28256
|
+
completedRef.current = true;
|
|
28257
|
+
cleanupJob();
|
|
28258
|
+
setTryOnProcessing(false);
|
|
28259
|
+
setTryOnStartedAt(null);
|
|
28260
|
+
}
|
|
28261
|
+
return;
|
|
28262
|
+
}
|
|
28246
28263
|
if (update.status === "completed" && update.imageUrl) {
|
|
28247
28264
|
setResultImageUrl((prev) => {
|
|
28248
28265
|
if (!prev || prev.startsWith("data:")) return update.imageUrl;
|
|
@@ -28425,11 +28442,15 @@ function PrimeStyleTryonInner({
|
|
|
28425
28442
|
}
|
|
28426
28443
|
setEstimationDone(false);
|
|
28427
28444
|
try {
|
|
28445
|
+
const tReq = Date.now();
|
|
28446
|
+
const payloadBytes = JSON.stringify(payload).length;
|
|
28447
|
+
console.log(`[ps-sdk:T] ▶ POST /sizing/recommend (quick) payload=${Math.round(payloadBytes / 1024)}KB bodyImage=${!!payload.bodyImage}`);
|
|
28428
28448
|
const res = await fetch(`${baseUrl}/api/v1/sizing/recommend`, {
|
|
28429
28449
|
method: "POST",
|
|
28430
28450
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
|
|
28431
28451
|
body: JSON.stringify(payload)
|
|
28432
28452
|
});
|
|
28453
|
+
console.log(`[ps-sdk:T] ◀ /sizing/recommend (quick) status=${res.status} roundTrip=${Date.now() - tReq}ms`);
|
|
28433
28454
|
if (res.ok) {
|
|
28434
28455
|
const data = await res.json();
|
|
28435
28456
|
console.log("[PS-SDK] Sizing recommend RESULT:", JSON.stringify(data));
|
|
@@ -28565,6 +28586,8 @@ function PrimeStyleTryonInner({
|
|
|
28565
28586
|
const objUrl = data.photoFile ? URL.createObjectURL(data.photoFile) : data.photoBase64.startsWith("data:") ? data.photoBase64 : `data:image/jpeg;base64,${data.photoBase64}`;
|
|
28566
28587
|
setPreviewUrl(objUrl);
|
|
28567
28588
|
completedRef.current = false;
|
|
28589
|
+
modelImageIdRef.current = null;
|
|
28590
|
+
noFitFoundRef.current = false;
|
|
28568
28591
|
setTryOnProcessing(false);
|
|
28569
28592
|
setTryOnStartedAt(null);
|
|
28570
28593
|
setSizingResult(null);
|
|
@@ -28575,12 +28598,12 @@ function PrimeStyleTryonInner({
|
|
|
28575
28598
|
const measurementType = detectMeasurementType(productTitle);
|
|
28576
28599
|
if (measurementType === "face" || measurementType === "head") {
|
|
28577
28600
|
setFaceLandmarks(null);
|
|
28578
|
-
const
|
|
28601
|
+
const minVisible2 = new Promise((r2) => setTimeout(r2, 4500));
|
|
28579
28602
|
try {
|
|
28580
28603
|
const faceResult = await detectFaceMeasurements(objUrl);
|
|
28581
28604
|
if (!faceResult) {
|
|
28582
28605
|
console.warn("[ps-sdk] face detection returned no result — likely a full-body photo for a face/head product");
|
|
28583
|
-
await
|
|
28606
|
+
await minVisible2;
|
|
28584
28607
|
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
28608
|
setErrorMessage(msg);
|
|
28586
28609
|
setView("error");
|
|
@@ -28608,7 +28631,7 @@ function PrimeStyleTryonInner({
|
|
|
28608
28631
|
});
|
|
28609
28632
|
if (recRes.ok) {
|
|
28610
28633
|
const recData = await recRes.json();
|
|
28611
|
-
await
|
|
28634
|
+
await minVisible2;
|
|
28612
28635
|
setSizingResult(recData);
|
|
28613
28636
|
onComplete?.(recData);
|
|
28614
28637
|
persistResultToProfile(
|
|
@@ -28625,12 +28648,12 @@ function PrimeStyleTryonInner({
|
|
|
28625
28648
|
{ skipBodyEstimate: true }
|
|
28626
28649
|
);
|
|
28627
28650
|
} else {
|
|
28628
|
-
await
|
|
28651
|
+
await minVisible2;
|
|
28629
28652
|
setEstimationDone(true);
|
|
28630
28653
|
}
|
|
28631
28654
|
} catch (err) {
|
|
28632
28655
|
console.error("[ps-sdk] face-recommend failed:", err);
|
|
28633
|
-
await
|
|
28656
|
+
await minVisible2;
|
|
28634
28657
|
setEstimationDone(true);
|
|
28635
28658
|
}
|
|
28636
28659
|
setSizingLoading(false);
|
|
@@ -28700,12 +28723,17 @@ function PrimeStyleTryonInner({
|
|
|
28700
28723
|
const jointCount = lmObj ? Object.keys(lmObj).filter((k2) => k2 !== "imageWidth" && k2 !== "imageHeight" && lmObj[k2]).length : 0;
|
|
28701
28724
|
console.log(`[ps-sdk:debug] payload → bodyLandmarks=${!!lmObj}(${jointCount} joints)`);
|
|
28702
28725
|
}
|
|
28726
|
+
const minVisible = new Promise((r2) => setTimeout(r2, 6e3));
|
|
28703
28727
|
try {
|
|
28728
|
+
const tReq = Date.now();
|
|
28729
|
+
const payloadBytes = JSON.stringify(payload).length;
|
|
28730
|
+
console.log(`[ps-sdk:T] ▶ POST /sizing/recommend payload=${Math.round(payloadBytes / 1024)}KB bodyImage=${!!payload.bodyImage} landmarks=${!!payload.bodyLandmarks}`);
|
|
28704
28731
|
const recRes = await fetch(`${baseUrl}/api/v1/sizing/recommend`, {
|
|
28705
28732
|
method: "POST",
|
|
28706
28733
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${key}` },
|
|
28707
28734
|
body: JSON.stringify(payload)
|
|
28708
28735
|
});
|
|
28736
|
+
console.log(`[ps-sdk:T] ◀ /sizing/recommend status=${recRes.status} roundTrip=${Date.now() - tReq}ms`);
|
|
28709
28737
|
if (recRes.ok) {
|
|
28710
28738
|
const recData = await recRes.json();
|
|
28711
28739
|
if (recData?.found === false && recData?.reasoning === "NO_SIZE_CHART") {
|
|
@@ -28714,26 +28742,38 @@ function PrimeStyleTryonInner({
|
|
|
28714
28742
|
setSizingLoading(false);
|
|
28715
28743
|
return;
|
|
28716
28744
|
}
|
|
28717
|
-
|
|
28718
|
-
|
|
28719
|
-
|
|
28720
|
-
{
|
|
28721
|
-
|
|
28722
|
-
|
|
28723
|
-
|
|
28724
|
-
|
|
28725
|
-
|
|
28726
|
-
|
|
28727
|
-
|
|
28728
|
-
|
|
28729
|
-
|
|
28730
|
-
|
|
28745
|
+
const matchScore = computeMatchScore(recData);
|
|
28746
|
+
const isLowFit = recData?.found === false || matchScore != null && matchScore < 50;
|
|
28747
|
+
if (isLowFit) {
|
|
28748
|
+
console.log(`[ps-sdk:gate] LOW FIT (match=${matchScore ?? "?"}%, found=${recData?.found}) — suppressing try-on`);
|
|
28749
|
+
noFitFoundRef.current = true;
|
|
28750
|
+
setTryOnProcessing(false);
|
|
28751
|
+
setTryOnStartedAt(null);
|
|
28752
|
+
setSizingResult({ ...recData, found: false });
|
|
28753
|
+
onComplete?.({ ...recData, found: false });
|
|
28754
|
+
} else {
|
|
28755
|
+
setSizingResult(recData);
|
|
28756
|
+
onComplete?.(recData);
|
|
28757
|
+
persistResultToProfile(
|
|
28758
|
+
{
|
|
28759
|
+
gender: data.gender,
|
|
28760
|
+
height: data.height,
|
|
28761
|
+
weight: data.weight,
|
|
28762
|
+
heightUnit: data.heightUnit,
|
|
28763
|
+
weightUnit: data.weightUnit,
|
|
28764
|
+
age: data.age,
|
|
28765
|
+
bodyImage: data.photoBase64
|
|
28766
|
+
},
|
|
28767
|
+
recData
|
|
28768
|
+
);
|
|
28769
|
+
}
|
|
28731
28770
|
} else {
|
|
28732
28771
|
setEstimationDone(true);
|
|
28733
28772
|
}
|
|
28734
28773
|
} catch {
|
|
28735
28774
|
setEstimationDone(true);
|
|
28736
28775
|
}
|
|
28776
|
+
await minVisible;
|
|
28737
28777
|
setSizingLoading(false);
|
|
28738
28778
|
}, [apiUrl, productImage, productTitle, sizingUnit, weightUnit, sizingCountry, sizeGuide, dynamicFields, persistResultToProfile]);
|
|
28739
28779
|
snapSubmitRef.current = handleSnapSubmit;
|
|
@@ -28757,9 +28797,9 @@ function PrimeStyleTryonInner({
|
|
|
28757
28797
|
const isApparel = vtoCategory === "apparel";
|
|
28758
28798
|
const previewObjUrl = (overrideFile ? null : previewUrl) || URL.createObjectURL(file);
|
|
28759
28799
|
if (overrideFile || !previewUrl) setPreviewUrl(previewObjUrl);
|
|
28760
|
-
modelPoseRef.current
|
|
28761
|
-
|
|
28762
|
-
|
|
28800
|
+
if (isApparel && (!modelPoseRef.current || !bodyLandmarks)) {
|
|
28801
|
+
modelPoseRef.current = null;
|
|
28802
|
+
setBodyLandmarks(null);
|
|
28763
28803
|
detectMeasurementLines(previewObjUrl).then((lines) => {
|
|
28764
28804
|
modelPoseRef.current = lines;
|
|
28765
28805
|
}).catch(() => {
|
|
@@ -28810,20 +28850,20 @@ function PrimeStyleTryonInner({
|
|
|
28810
28850
|
console.log("[ps-sdk:flatten] sizingResult keys:", Object.keys(sizingResult || {}));
|
|
28811
28851
|
console.log("[ps-sdk:flatten] root matchDetails:", (sizingResult?.matchDetails || []).map((m2) => m2.measurement));
|
|
28812
28852
|
console.log("[ps-sdk:flatten] sections:", sizingResult?.sections ? Object.keys(sizingResult.sections) : "none");
|
|
28813
|
-
const push = (md2, src) => {
|
|
28853
|
+
const push = (md2, src, section) => {
|
|
28814
28854
|
if (!md2) return;
|
|
28815
28855
|
console.log(`[ps-sdk:flatten] ${src} →`, md2.map((m2) => m2.measurement));
|
|
28816
28856
|
for (const m2 of md2) {
|
|
28817
28857
|
const k2 = m2.measurement.toLowerCase().replace(/\s*\(.*?\)\s*/g, "").trim();
|
|
28818
28858
|
if (seen.has(k2)) continue;
|
|
28819
28859
|
seen.add(k2);
|
|
28820
|
-
out.push(m2);
|
|
28860
|
+
out.push({ ...m2, section });
|
|
28821
28861
|
}
|
|
28822
28862
|
};
|
|
28823
|
-
push(sizingResult?.matchDetails, "root");
|
|
28863
|
+
push(sizingResult?.matchDetails, "root", void 0);
|
|
28824
28864
|
if (sizingResult?.sections) {
|
|
28825
28865
|
for (const [secName, sec] of Object.entries(sizingResult.sections)) {
|
|
28826
|
-
push(sec?.matchDetails, `section:${secName}
|
|
28866
|
+
push(sec?.matchDetails, `section:${secName}`, secName);
|
|
28827
28867
|
}
|
|
28828
28868
|
}
|
|
28829
28869
|
console.log("[ps-sdk:flatten] final unique:", out.map((m2) => m2.measurement));
|
|
@@ -28832,12 +28872,24 @@ function PrimeStyleTryonInner({
|
|
|
28832
28872
|
const effectiveMatchDetails = override?.matchDetails && override.matchDetails.length ? override.matchDetails : flattenAllMatchDetails();
|
|
28833
28873
|
let fitInfo;
|
|
28834
28874
|
if (isApparel && effectiveMatchDetails.length) {
|
|
28835
|
-
|
|
28875
|
+
const unitRaw = (sizingResult?.unit || sizingUnit || "in").toString().toLowerCase();
|
|
28876
|
+
const unit = unitRaw === "cm" ? "cm" : unitRaw === "mm" ? "mm" : "in";
|
|
28877
|
+
fitInfo = buildFitInfo(effectiveMatchDetails, modelPoseRef.current, unit);
|
|
28836
28878
|
}
|
|
28837
28879
|
console.log("[ps-sdk:tryon] fitInfo built", { count: fitInfo?.length || 0, areas: fitInfo?.map((f2) => `${f2.area}(${f2.fit})`) });
|
|
28880
|
+
let garmentImage = productImage;
|
|
28881
|
+
if (garmentReferenceImage) {
|
|
28882
|
+
garmentImage = garmentReferenceImage;
|
|
28883
|
+
} else if (productImages && productImages.length > 1) {
|
|
28884
|
+
const best = await pickBestGarmentImage(productImages);
|
|
28885
|
+
if (best && best !== productImage) {
|
|
28886
|
+
console.log(`[ps-sdk:tryon] auto-picked garment reference: ${best}`);
|
|
28887
|
+
garmentImage = best;
|
|
28888
|
+
}
|
|
28889
|
+
}
|
|
28838
28890
|
const response = await apiRef.current.submitTryOn(
|
|
28839
28891
|
modelImage,
|
|
28840
|
-
|
|
28892
|
+
garmentImage,
|
|
28841
28893
|
fitInfo,
|
|
28842
28894
|
vtoCategory ?? "apparel",
|
|
28843
28895
|
{
|
|
@@ -28881,167 +28933,19 @@ function PrimeStyleTryonInner({
|
|
|
28881
28933
|
onError?.({ message, code });
|
|
28882
28934
|
}
|
|
28883
28935
|
}, [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");
|
|
28936
|
+
reactExports.useEffect(() => {
|
|
28937
|
+
if (!sizingResult) {
|
|
28938
|
+
autoTryOnFiredRef.current = false;
|
|
29035
28939
|
return;
|
|
29036
28940
|
}
|
|
29037
|
-
|
|
29038
|
-
|
|
29039
|
-
|
|
29040
|
-
|
|
29041
|
-
|
|
29042
|
-
|
|
29043
|
-
|
|
29044
|
-
}, [
|
|
28941
|
+
if (sizingResult.found === false) return;
|
|
28942
|
+
if (noFitFoundRef.current) return;
|
|
28943
|
+
if (autoTryOnFiredRef.current) return;
|
|
28944
|
+
if (tryOnProcessing || resultImageUrl) return;
|
|
28945
|
+
if (!selectedFile && !selectedFileRef.current) return;
|
|
28946
|
+
autoTryOnFiredRef.current = true;
|
|
28947
|
+
handleTryOnSubmit();
|
|
28948
|
+
}, [sizingResult, tryOnProcessing, resultImageUrl, selectedFile, handleTryOnSubmit]);
|
|
29045
28949
|
const handleDownload = reactExports.useCallback(() => {
|
|
29046
28950
|
if (!resultImageUrl) return;
|
|
29047
28951
|
if (resultImageUrl.startsWith("data:")) {
|
|
@@ -29483,15 +29387,13 @@ function PrimeStyleTryonInner({
|
|
|
29483
29387
|
sizeGuide,
|
|
29484
29388
|
resultImageUrl,
|
|
29485
29389
|
productImage,
|
|
29390
|
+
productImages,
|
|
29486
29391
|
productTitle,
|
|
29487
29392
|
productMaterial,
|
|
29488
29393
|
productDescription,
|
|
29489
29394
|
sizingUnit,
|
|
29490
29395
|
setView,
|
|
29491
29396
|
handleDownload,
|
|
29492
|
-
onRetryWithFit: handleRetryWithFit,
|
|
29493
|
-
retryLoading,
|
|
29494
|
-
retryStartedAt,
|
|
29495
29397
|
selectedFile,
|
|
29496
29398
|
previewUrl,
|
|
29497
29399
|
handleFileSelect,
|
|
@@ -29504,9 +29406,6 @@ function PrimeStyleTryonInner({
|
|
|
29504
29406
|
measurementType: detectMeasurementType(productTitle),
|
|
29505
29407
|
activeSection,
|
|
29506
29408
|
setActiveSection,
|
|
29507
|
-
pendingCustomSizes,
|
|
29508
|
-
onPendingCustomSizeChange: setPendingCustomSizeBySection,
|
|
29509
|
-
onRegenerateTryOn: handleRegenerateTryOn,
|
|
29510
29409
|
onResetTryOn: () => {
|
|
29511
29410
|
setSelectedFile(null);
|
|
29512
29411
|
if (previewUrl) URL.revokeObjectURL(previewUrl);
|