@primestyleai/tryon 5.10.186 → 5.10.188
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/api-client.d.ts +2 -0
- package/dist/{index-CYT0nGWX.js → index-BduSFARG.js} +60 -51
- package/dist/index-BduSFARG.js.map +1 -0
- package/dist/primestyle-tryon.js +2 -2
- package/dist/react/index.js +6178 -5975
- package/dist/react/index.js.map +1 -1
- package/dist/react/styles.d.ts +1 -1
- package/dist/react/types.d.ts +2 -0
- package/dist/react/utils/storage.d.ts +2 -0
- package/dist/react/views/BodyProfileView.d.ts +3 -0
- package/dist/react/views/CreateProfileWizard.d.ts +3 -1
- package/dist/react/views/NoChartView.d.ts +2 -1
- package/dist/storefront/primestyle-tryon.js +613 -305
- package/package.json +1 -1
- package/dist/index-CYT0nGWX.js.map +0 -1
|
@@ -6979,7 +6979,7 @@ const es = {
|
|
|
6979
6979
|
"Virtual Try-On": "Probador Virtual",
|
|
6980
6980
|
"Find Your Size & See It On You": "Encuentra tu talla y pruébatelo",
|
|
6981
6981
|
"See Your Fit": "Ver tu ajuste",
|
|
6982
|
-
"
|
|
6982
|
+
"Check your size, then try it on virtually": "Comprueba tu talla y pruébatelo virtualmente",
|
|
6983
6983
|
"Get Your Size": "Tu talla",
|
|
6984
6984
|
"Instant fit recommendation": "Recomendación de ajuste instantánea",
|
|
6985
6985
|
"Try It On": "Pruébatelo",
|
|
@@ -7014,8 +7014,9 @@ const es = {
|
|
|
7014
7014
|
"Edit measurements": "Editar medidas",
|
|
7015
7015
|
"Size guide": "Guía de tallas",
|
|
7016
7016
|
"Your fit": "Tu ajuste",
|
|
7017
|
+
"Your Size Recommendation": "Tu recomendación de talla",
|
|
7017
7018
|
"Your measure": "Tu medida",
|
|
7018
|
-
"
|
|
7019
|
+
"within range": "dentro del rango",
|
|
7019
7020
|
"too tight": "demasiado ajustado",
|
|
7020
7021
|
"tight": "ajustado",
|
|
7021
7022
|
"a bit tight": "un poco ajustado",
|
|
@@ -7236,7 +7237,7 @@ const fr = {
|
|
|
7236
7237
|
"Virtual Try-On": "Essayage Virtuel",
|
|
7237
7238
|
"Find Your Size & See It On You": "Trouvez votre taille et essayez-le",
|
|
7238
7239
|
"See Your Fit": "Voir votre ajustement",
|
|
7239
|
-
"
|
|
7240
|
+
"Check your size, then try it on virtually": "Vérifiez votre taille, puis essayez-le virtuellement",
|
|
7240
7241
|
"Get Your Size": "Votre taille",
|
|
7241
7242
|
"Instant fit recommendation": "Recommandation de coupe instantanée",
|
|
7242
7243
|
"Try It On": "Essayer",
|
|
@@ -7271,8 +7272,9 @@ const fr = {
|
|
|
7271
7272
|
"Edit measurements": "Modifier les mesures",
|
|
7272
7273
|
"Size guide": "Guide des tailles",
|
|
7273
7274
|
"Your fit": "Votre coupe",
|
|
7275
|
+
"Your Size Recommendation": "Votre recommandation de taille",
|
|
7274
7276
|
"Your measure": "Votre mesure",
|
|
7275
|
-
"
|
|
7277
|
+
"within range": "dans la plage",
|
|
7276
7278
|
"too tight": "trop serré",
|
|
7277
7279
|
"tight": "serré",
|
|
7278
7280
|
"a bit tight": "un peu serré",
|
|
@@ -7493,7 +7495,7 @@ const de = {
|
|
|
7493
7495
|
"Virtual Try-On": "Virtuelle Anprobe",
|
|
7494
7496
|
"Find Your Size & See It On You": "Finden Sie Ihre Größe und probieren Sie es an",
|
|
7495
7497
|
"See Your Fit": "Ihre Passform ansehen",
|
|
7496
|
-
"
|
|
7498
|
+
"Check your size, then try it on virtually": "Prüfen Sie Ihre Größe und probieren Sie es virtuell an",
|
|
7497
7499
|
"Get Your Size": "Ihre Größe",
|
|
7498
7500
|
"Instant fit recommendation": "Sofortige Passformempfehlung",
|
|
7499
7501
|
"Try It On": "Anprobieren",
|
|
@@ -7528,8 +7530,9 @@ const de = {
|
|
|
7528
7530
|
"Edit measurements": "Maße bearbeiten",
|
|
7529
7531
|
"Size guide": "Größentabelle",
|
|
7530
7532
|
"Your fit": "Ihre Passform",
|
|
7533
|
+
"Your Size Recommendation": "Ihre Größenempfehlung",
|
|
7531
7534
|
"Your measure": "Ihr Maß",
|
|
7532
|
-
"
|
|
7535
|
+
"within range": "im Bereich",
|
|
7533
7536
|
"too tight": "zu eng",
|
|
7534
7537
|
"tight": "eng",
|
|
7535
7538
|
"a bit tight": "etwas eng",
|
|
@@ -7750,7 +7753,7 @@ const it = {
|
|
|
7750
7753
|
"Virtual Try-On": "Prova Virtuale",
|
|
7751
7754
|
"Find Your Size & See It On You": "Trova la tua taglia e provalo",
|
|
7752
7755
|
"See Your Fit": "Vedi la vestibilità",
|
|
7753
|
-
"
|
|
7756
|
+
"Check your size, then try it on virtually": "Controlla la tua taglia, poi provalo virtualmente",
|
|
7754
7757
|
"Get Your Size": "La tua taglia",
|
|
7755
7758
|
"Instant fit recommendation": "Raccomandazione vestibilità istantanea",
|
|
7756
7759
|
"Try It On": "Provalo",
|
|
@@ -7785,8 +7788,9 @@ const it = {
|
|
|
7785
7788
|
"Edit measurements": "Modifica misure",
|
|
7786
7789
|
"Size guide": "Guida alle taglie",
|
|
7787
7790
|
"Your fit": "La tua vestibilità",
|
|
7791
|
+
"Your Size Recommendation": "La tua taglia consigliata",
|
|
7788
7792
|
"Your measure": "La tua misura",
|
|
7789
|
-
"
|
|
7793
|
+
"within range": "entro l'intervallo",
|
|
7790
7794
|
"too tight": "troppo stretto",
|
|
7791
7795
|
"tight": "stretto",
|
|
7792
7796
|
"a bit tight": "un po' stretto",
|
|
@@ -8007,7 +8011,7 @@ const pt$1 = {
|
|
|
8007
8011
|
"Virtual Try-On": "Provador Virtual",
|
|
8008
8012
|
"Find Your Size & See It On You": "Encontre seu tamanho e experimente",
|
|
8009
8013
|
"See Your Fit": "Veja seu ajuste",
|
|
8010
|
-
"
|
|
8014
|
+
"Check your size, then try it on virtually": "Confira seu tamanho e experimente virtualmente",
|
|
8011
8015
|
"Get Your Size": "Seu tamanho",
|
|
8012
8016
|
"Instant fit recommendation": "Recomendação de caimento instantânea",
|
|
8013
8017
|
"Try It On": "Experimentar",
|
|
@@ -8042,8 +8046,9 @@ const pt$1 = {
|
|
|
8042
8046
|
"Edit measurements": "Editar medidas",
|
|
8043
8047
|
"Size guide": "Guia de tamanhos",
|
|
8044
8048
|
"Your fit": "Seu caimento",
|
|
8049
|
+
"Your Size Recommendation": "Sua recomendação de tamanho",
|
|
8045
8050
|
"Your measure": "Sua medida",
|
|
8046
|
-
"
|
|
8051
|
+
"within range": "dentro da faixa",
|
|
8047
8052
|
"too tight": "muito apertado",
|
|
8048
8053
|
"tight": "apertado",
|
|
8049
8054
|
"a bit tight": "um pouco apertado",
|
|
@@ -8264,7 +8269,7 @@ const ja = {
|
|
|
8264
8269
|
"Virtual Try-On": "バーチャル試着",
|
|
8265
8270
|
"Find Your Size & See It On You": "あなたのサイズを見つけて試着",
|
|
8266
8271
|
"See Your Fit": "フィット感を見る",
|
|
8267
|
-
"
|
|
8272
|
+
"Check your size, then try it on virtually": "サイズを確認して、バーチャルで試着しましょう",
|
|
8268
8273
|
"Get Your Size": "サイズを確認",
|
|
8269
8274
|
"Instant fit recommendation": "瞬時にフィット提案",
|
|
8270
8275
|
"Try It On": "試着する",
|
|
@@ -8299,8 +8304,9 @@ const ja = {
|
|
|
8299
8304
|
"Edit measurements": "寸法を編集",
|
|
8300
8305
|
"Size guide": "サイズガイド",
|
|
8301
8306
|
"Your fit": "あなたのフィット",
|
|
8307
|
+
"Your Size Recommendation": "サイズのおすすめ",
|
|
8302
8308
|
"Your measure": "あなたの寸法",
|
|
8303
|
-
"
|
|
8309
|
+
"within range": "範囲内",
|
|
8304
8310
|
"too tight": "きつすぎる",
|
|
8305
8311
|
"tight": "きつい",
|
|
8306
8312
|
"a bit tight": "少しきつい",
|
|
@@ -8521,7 +8527,7 @@ const zh = {
|
|
|
8521
8527
|
"Virtual Try-On": "虚拟试穿",
|
|
8522
8528
|
"Find Your Size & See It On You": "找到你的尺码并试穿",
|
|
8523
8529
|
"See Your Fit": "查看合身效果",
|
|
8524
|
-
"
|
|
8530
|
+
"Check your size, then try it on virtually": "确认尺码,然后虚拟试穿",
|
|
8525
8531
|
"Get Your Size": "获取尺码",
|
|
8526
8532
|
"Instant fit recommendation": "即时合身推荐",
|
|
8527
8533
|
"Try It On": "试穿",
|
|
@@ -8556,8 +8562,9 @@ const zh = {
|
|
|
8556
8562
|
"Edit measurements": "编辑尺寸",
|
|
8557
8563
|
"Size guide": "尺码指南",
|
|
8558
8564
|
"Your fit": "你的合身度",
|
|
8565
|
+
"Your Size Recommendation": "你的尺码建议",
|
|
8559
8566
|
"Your measure": "你的尺寸",
|
|
8560
|
-
"
|
|
8567
|
+
"within range": "在范围内",
|
|
8561
8568
|
"too tight": "太紧",
|
|
8562
8569
|
"tight": "偏紧",
|
|
8563
8570
|
"a bit tight": "略紧",
|
|
@@ -8778,7 +8785,7 @@ const ko = {
|
|
|
8778
8785
|
"Virtual Try-On": "가상 피팅",
|
|
8779
8786
|
"Find Your Size & See It On You": "사이즈를 찾고 입어보세요",
|
|
8780
8787
|
"See Your Fit": "핏 확인하기",
|
|
8781
|
-
"
|
|
8788
|
+
"Check your size, then try it on virtually": "사이즈를 확인하고 가상으로 입어보세요",
|
|
8782
8789
|
"Get Your Size": "사이즈 확인",
|
|
8783
8790
|
"Instant fit recommendation": "즉시 핏 추천",
|
|
8784
8791
|
"Try It On": "입어보기",
|
|
@@ -8813,8 +8820,9 @@ const ko = {
|
|
|
8813
8820
|
"Edit measurements": "치수 수정",
|
|
8814
8821
|
"Size guide": "사이즈 가이드",
|
|
8815
8822
|
"Your fit": "나의 핏",
|
|
8823
|
+
"Your Size Recommendation": "사이즈 추천",
|
|
8816
8824
|
"Your measure": "내 치수",
|
|
8817
|
-
"
|
|
8825
|
+
"within range": "범위 내",
|
|
8818
8826
|
"too tight": "너무 타이트",
|
|
8819
8827
|
"tight": "타이트",
|
|
8820
8828
|
"a bit tight": "약간 타이트",
|
|
@@ -9035,7 +9043,7 @@ const ar = {
|
|
|
9035
9043
|
"Virtual Try-On": "تجربة افتراضية",
|
|
9036
9044
|
"Find Your Size & See It On You": "اعثر على مقاسك وجرّبه",
|
|
9037
9045
|
"See Your Fit": "شاهد الملاءمة",
|
|
9038
|
-
"
|
|
9046
|
+
"Check your size, then try it on virtually": "تحقق من مقاسك ثم جرّبه افتراضياً",
|
|
9039
9047
|
"Get Your Size": "مقاسك",
|
|
9040
9048
|
"Instant fit recommendation": "توصية فورية بالمقاس",
|
|
9041
9049
|
"Try It On": "جرّبه",
|
|
@@ -9070,8 +9078,9 @@ const ar = {
|
|
|
9070
9078
|
"Edit measurements": "تعديل القياسات",
|
|
9071
9079
|
"Size guide": "دليل المقاسات",
|
|
9072
9080
|
"Your fit": "ملاءمتك",
|
|
9081
|
+
"Your Size Recommendation": "توصية المقاس",
|
|
9073
9082
|
"Your measure": "قياسك",
|
|
9074
|
-
"
|
|
9083
|
+
"within range": "ضمن النطاق",
|
|
9075
9084
|
"too tight": "ضيق جداً",
|
|
9076
9085
|
"tight": "ضيق",
|
|
9077
9086
|
"a bit tight": "ضيق قليلاً",
|
|
@@ -9465,6 +9474,8 @@ class ApiClient {
|
|
|
9465
9474
|
if (category && category !== "apparel") body.category = category;
|
|
9466
9475
|
if (context?.productId) body.productId = context.productId;
|
|
9467
9476
|
if (context?.productTitle) body.productTitle = context.productTitle;
|
|
9477
|
+
if (context?.productCategory) body.productCategory = context.productCategory;
|
|
9478
|
+
if (context?.productSubcategory) body.productSubcategory = context.productSubcategory;
|
|
9468
9479
|
if (context?.productFitType) body.productFitType = context.productFitType;
|
|
9469
9480
|
if (context?.productType) body.productType = context.productType;
|
|
9470
9481
|
if (context?.productTags?.length) body.productTags = context.productTags;
|
|
@@ -10280,6 +10291,9 @@ function formatUserMeasurementValue(measurement, value) {
|
|
|
10280
10291
|
if (!isUnitlessShoeSizeMeasurement(measurement)) return value;
|
|
10281
10292
|
return value.replace(/\s*(cm|mm|in|inch|inches)\b/ig, "").trim();
|
|
10282
10293
|
}
|
|
10294
|
+
function normalizePromptSizeLabel(size) {
|
|
10295
|
+
return String(size || "").trim().replace(/\s+[–—-]\s+(?:UK|US|EU|IT|FR|DE|ES|JP|CN|KR|AU|BR)\s+.+$/i, "").replace(/\s*\((?:UK|US|EU|IT|FR|DE|ES|JP|CN|KR|AU|BR)\s+[^)]*\)\s*$/i, "").trim();
|
|
10296
|
+
}
|
|
10283
10297
|
function computeFit(userValue, chartRange, unit) {
|
|
10284
10298
|
const targetUnit = normalizeUnit(unit) || detectUnitFromText(chartRange) || "in";
|
|
10285
10299
|
const chartUnit = detectUnitFromText(chartRange);
|
|
@@ -10340,7 +10354,7 @@ function buildSilhouetteContext(sizingResult, sizeGuide, selectedSizeOverride, u
|
|
|
10340
10354
|
if (!sizingResult && !sizeGuide && !userHeight && !userWeight) return void 0;
|
|
10341
10355
|
const out = {};
|
|
10342
10356
|
const promptUnit = normalizeUnit(sizingResult?.unit) || detectUnitFromText(sizingResult?.matchDetails?.[0]?.userValue) || detectUnitFromText(Object.values(sizingResult?.sections || {})[0]?.matchDetails?.[0]?.userValue) || "in";
|
|
10343
|
-
const baseSize = (selectedSizeOverride || sizingResult?.recommendedSize || "")
|
|
10357
|
+
const baseSize = normalizePromptSizeLabel(selectedSizeOverride || sizingResult?.recommendedSize || "");
|
|
10344
10358
|
if (userHeight) out.userHeight = userHeight;
|
|
10345
10359
|
if (userWeight) out.userWeight = userWeight;
|
|
10346
10360
|
let chartRowLength = null;
|
|
@@ -10390,7 +10404,7 @@ function buildSilhouetteContext(sizingResult, sizeGuide, selectedSizeOverride, u
|
|
|
10390
10404
|
const labelParts = [];
|
|
10391
10405
|
const measurementParts = [];
|
|
10392
10406
|
for (const [secName, secResult] of sectionEntries) {
|
|
10393
|
-
const secSize = (secResult?.recommendedSize ?? "")
|
|
10407
|
+
const secSize = normalizePromptSizeLabel(secResult?.recommendedSize ?? "");
|
|
10394
10408
|
if (!secSize) continue;
|
|
10395
10409
|
const cleanSec = /\bsize\s*$/i.test(secName) ? secName.replace(/\s*\bsize\s*$/i, "").trim() : secName;
|
|
10396
10410
|
labelParts.push(`${cleanSec} ${secSize}`);
|
|
@@ -10496,6 +10510,24 @@ function lsSet(key, value) {
|
|
|
10496
10510
|
} catch {
|
|
10497
10511
|
}
|
|
10498
10512
|
}
|
|
10513
|
+
function lsRemove(key) {
|
|
10514
|
+
try {
|
|
10515
|
+
localStorage.removeItem(LS_PREFIX + key);
|
|
10516
|
+
} catch {
|
|
10517
|
+
}
|
|
10518
|
+
}
|
|
10519
|
+
function clearProfileLocalStorage() {
|
|
10520
|
+
lsRemove(PROFILES_KEY);
|
|
10521
|
+
lsRemove(ACTIVE_PROFILE_KEY);
|
|
10522
|
+
lsRemove("profile_completion_draft");
|
|
10523
|
+
try {
|
|
10524
|
+
localStorage.removeItem(PROFILES_KEY);
|
|
10525
|
+
localStorage.removeItem(ACTIVE_PROFILE_KEY);
|
|
10526
|
+
localStorage.removeItem("profile_completion_draft");
|
|
10527
|
+
} catch {
|
|
10528
|
+
}
|
|
10529
|
+
emitStorageChange("profile-clear");
|
|
10530
|
+
}
|
|
10499
10531
|
function getProfiles() {
|
|
10500
10532
|
return lsGet(PROFILES_KEY, []);
|
|
10501
10533
|
}
|
|
@@ -10510,19 +10542,6 @@ function setActiveProfileId(id2) {
|
|
|
10510
10542
|
lsSet(ACTIVE_PROFILE_KEY, id2);
|
|
10511
10543
|
emitStorageChange("active-profile");
|
|
10512
10544
|
}
|
|
10513
|
-
function getActiveProfile() {
|
|
10514
|
-
const profiles = getProfiles();
|
|
10515
|
-
if (profiles.length === 0) return null;
|
|
10516
|
-
const activeId = getActiveProfileId();
|
|
10517
|
-
if (activeId) {
|
|
10518
|
-
const found = profiles.find((p2) => p2.id === activeId);
|
|
10519
|
-
if (found) return found;
|
|
10520
|
-
}
|
|
10521
|
-
const sorted = [...profiles].sort(
|
|
10522
|
-
(a, b) => (b.lastUsedAt || b.createdAt || 0) - (a.lastUsedAt || a.createdAt || 0)
|
|
10523
|
-
);
|
|
10524
|
-
return sorted[0] || null;
|
|
10525
|
-
}
|
|
10526
10545
|
function updateProfile(id2, patch) {
|
|
10527
10546
|
const profiles = getProfiles();
|
|
10528
10547
|
const idx = profiles.findIndex((p2) => p2.id === id2);
|
|
@@ -10937,6 +10956,179 @@ function getApiUrl(override) {
|
|
|
10937
10956
|
}
|
|
10938
10957
|
return envUrl || "http://localhost:4000";
|
|
10939
10958
|
}
|
|
10959
|
+
const SESSION_KEY = "primestyle_profile_session";
|
|
10960
|
+
const AUTH_MESSAGE_TYPE = "PRIMESTYLE_SDK_AUTH";
|
|
10961
|
+
const POPUP_TIMEOUT_MS = 12e4;
|
|
10962
|
+
const POLL_INTERVAL_MS = 900;
|
|
10963
|
+
function isTrustedAuthOrigin(eventOrigin, expectedOrigin) {
|
|
10964
|
+
if (eventOrigin === expectedOrigin) return true;
|
|
10965
|
+
try {
|
|
10966
|
+
const host = new URL(eventOrigin).hostname;
|
|
10967
|
+
return host === "localhost" || host === "127.0.0.1" || host.endsWith(".primestyleai.com") || host.endsWith(".myaifitting.com");
|
|
10968
|
+
} catch {
|
|
10969
|
+
return false;
|
|
10970
|
+
}
|
|
10971
|
+
}
|
|
10972
|
+
function readStorage() {
|
|
10973
|
+
if (typeof window === "undefined") return null;
|
|
10974
|
+
try {
|
|
10975
|
+
return window.localStorage;
|
|
10976
|
+
} catch {
|
|
10977
|
+
return null;
|
|
10978
|
+
}
|
|
10979
|
+
}
|
|
10980
|
+
function createAuthRequestId() {
|
|
10981
|
+
try {
|
|
10982
|
+
const randomId = window.crypto?.randomUUID?.();
|
|
10983
|
+
if (randomId) return randomId;
|
|
10984
|
+
} catch {
|
|
10985
|
+
}
|
|
10986
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
|
|
10987
|
+
}
|
|
10988
|
+
async function readAuthStatus(statusUrl) {
|
|
10989
|
+
const response = await fetch(statusUrl.toString(), {
|
|
10990
|
+
method: "GET",
|
|
10991
|
+
credentials: "omit",
|
|
10992
|
+
cache: "no-store"
|
|
10993
|
+
});
|
|
10994
|
+
if (!response.ok) return null;
|
|
10995
|
+
const data = await response.json();
|
|
10996
|
+
return data.status === "done" ? data : null;
|
|
10997
|
+
}
|
|
10998
|
+
function getStoredProfileSession() {
|
|
10999
|
+
const storage = readStorage();
|
|
11000
|
+
if (!storage) return null;
|
|
11001
|
+
try {
|
|
11002
|
+
const raw = storage.getItem(SESSION_KEY);
|
|
11003
|
+
if (!raw) return null;
|
|
11004
|
+
const parsed = JSON.parse(raw);
|
|
11005
|
+
return parsed?.accessToken ? parsed : null;
|
|
11006
|
+
} catch {
|
|
11007
|
+
return null;
|
|
11008
|
+
}
|
|
11009
|
+
}
|
|
11010
|
+
function setStoredProfileSession(session) {
|
|
11011
|
+
const storage = readStorage();
|
|
11012
|
+
if (!storage) return;
|
|
11013
|
+
try {
|
|
11014
|
+
storage.setItem(SESSION_KEY, JSON.stringify(session));
|
|
11015
|
+
} catch {
|
|
11016
|
+
}
|
|
11017
|
+
}
|
|
11018
|
+
function clearStoredProfileSession() {
|
|
11019
|
+
const storage = readStorage();
|
|
11020
|
+
if (!storage) return;
|
|
11021
|
+
try {
|
|
11022
|
+
storage.removeItem(SESSION_KEY);
|
|
11023
|
+
} catch {
|
|
11024
|
+
}
|
|
11025
|
+
}
|
|
11026
|
+
function startSocialProfileLogin(provider, apiUrl) {
|
|
11027
|
+
if (typeof window === "undefined") {
|
|
11028
|
+
return Promise.reject(new Error("Social login must run in the browser."));
|
|
11029
|
+
}
|
|
11030
|
+
const baseUrl = getApiUrl(apiUrl);
|
|
11031
|
+
const backendOrigin = new URL(baseUrl).origin;
|
|
11032
|
+
const authRequestId = createAuthRequestId();
|
|
11033
|
+
const startUrl = new URL(`${baseUrl.replace(/\/$/, "")}/api/sdk/v1/auth/${provider}/start`);
|
|
11034
|
+
startUrl.searchParams.set("origin", window.location.origin);
|
|
11035
|
+
startUrl.searchParams.set("requestId", authRequestId);
|
|
11036
|
+
const statusUrl = new URL(`${baseUrl.replace(/\/$/, "")}/api/sdk/v1/auth/${provider}/status`);
|
|
11037
|
+
statusUrl.searchParams.set("origin", window.location.origin);
|
|
11038
|
+
statusUrl.searchParams.set("requestId", authRequestId);
|
|
11039
|
+
const popup = window.open(
|
|
11040
|
+
startUrl.toString(),
|
|
11041
|
+
"primestyle-profile-login",
|
|
11042
|
+
"width=520,height=720"
|
|
11043
|
+
);
|
|
11044
|
+
if (!popup) {
|
|
11045
|
+
return Promise.reject(new Error("Popup was blocked. Please allow popups and try again."));
|
|
11046
|
+
}
|
|
11047
|
+
return new Promise((resolve, reject) => {
|
|
11048
|
+
let settled = false;
|
|
11049
|
+
const cleanup = () => {
|
|
11050
|
+
window.removeEventListener("message", onMessage);
|
|
11051
|
+
window.clearInterval(statusTimer);
|
|
11052
|
+
window.clearTimeout(timeout);
|
|
11053
|
+
};
|
|
11054
|
+
const finish = (fn) => {
|
|
11055
|
+
if (settled) return;
|
|
11056
|
+
settled = true;
|
|
11057
|
+
cleanup();
|
|
11058
|
+
fn();
|
|
11059
|
+
};
|
|
11060
|
+
const onMessage = (event) => {
|
|
11061
|
+
if (!isTrustedAuthOrigin(event.origin, backendOrigin)) return;
|
|
11062
|
+
const data = event.data;
|
|
11063
|
+
if (!data || data.type !== AUTH_MESSAGE_TYPE) return;
|
|
11064
|
+
if (!data.ok || !data.accessToken) {
|
|
11065
|
+
finish(() => reject(new Error(data.error || "Social login failed.")));
|
|
11066
|
+
return;
|
|
11067
|
+
}
|
|
11068
|
+
finish(() => resolve({
|
|
11069
|
+
accessToken: data.accessToken,
|
|
11070
|
+
isNewUser: Boolean(data.isNewUser),
|
|
11071
|
+
signedInAt: Date.now()
|
|
11072
|
+
}));
|
|
11073
|
+
};
|
|
11074
|
+
const handleAuthPayload = (data) => {
|
|
11075
|
+
if (!data.ok || !data.accessToken) {
|
|
11076
|
+
finish(() => reject(new Error(data.error || "Social login failed.")));
|
|
11077
|
+
return;
|
|
11078
|
+
}
|
|
11079
|
+
finish(() => resolve({
|
|
11080
|
+
accessToken: data.accessToken,
|
|
11081
|
+
isNewUser: Boolean(data.isNewUser),
|
|
11082
|
+
signedInAt: Date.now()
|
|
11083
|
+
}));
|
|
11084
|
+
};
|
|
11085
|
+
const statusTimer = window.setInterval(() => {
|
|
11086
|
+
readAuthStatus(statusUrl).then((data) => {
|
|
11087
|
+
if (data) handleAuthPayload(data);
|
|
11088
|
+
}).catch(() => {
|
|
11089
|
+
});
|
|
11090
|
+
}, POLL_INTERVAL_MS);
|
|
11091
|
+
const timeout = window.setTimeout(() => {
|
|
11092
|
+
finish(() => reject(new Error("Login did not finish. Please close the sign-in window and try again.")));
|
|
11093
|
+
}, POPUP_TIMEOUT_MS);
|
|
11094
|
+
window.addEventListener("message", onMessage);
|
|
11095
|
+
});
|
|
11096
|
+
}
|
|
11097
|
+
function endpoint(apiUrl) {
|
|
11098
|
+
return `${getApiUrl(apiUrl).replace(/\/$/, "")}/api/sdk/v1/profiles`;
|
|
11099
|
+
}
|
|
11100
|
+
function normalizeStore(data) {
|
|
11101
|
+
return {
|
|
11102
|
+
profiles: Array.isArray(data.profiles) ? data.profiles : [],
|
|
11103
|
+
activeProfileId: data.activeProfileId ?? null
|
|
11104
|
+
};
|
|
11105
|
+
}
|
|
11106
|
+
async function parseResponse(response) {
|
|
11107
|
+
const data = await response.json().catch(() => ({}));
|
|
11108
|
+
if (!response.ok) {
|
|
11109
|
+
const message = typeof data.message === "string" ? data.message : "Profile sync failed.";
|
|
11110
|
+
throw new Error(message);
|
|
11111
|
+
}
|
|
11112
|
+
return data;
|
|
11113
|
+
}
|
|
11114
|
+
async function fetchRemoteProfiles(apiUrl, accessToken) {
|
|
11115
|
+
const response = await fetch(endpoint(apiUrl), {
|
|
11116
|
+
method: "GET",
|
|
11117
|
+
headers: { Authorization: `Bearer ${accessToken}` }
|
|
11118
|
+
});
|
|
11119
|
+
return normalizeStore(await parseResponse(response));
|
|
11120
|
+
}
|
|
11121
|
+
async function saveRemoteProfiles(apiUrl, accessToken, profiles, activeProfileId) {
|
|
11122
|
+
const response = await fetch(endpoint(apiUrl), {
|
|
11123
|
+
method: "PUT",
|
|
11124
|
+
headers: {
|
|
11125
|
+
Authorization: `Bearer ${accessToken}`,
|
|
11126
|
+
"Content-Type": "application/json"
|
|
11127
|
+
},
|
|
11128
|
+
body: JSON.stringify({ profiles, activeProfileId })
|
|
11129
|
+
});
|
|
11130
|
+
return normalizeStore(await parseResponse(response));
|
|
11131
|
+
}
|
|
10940
11132
|
let cachedMP = null;
|
|
10941
11133
|
const MP_CACHE_TTL_MS = 6e4;
|
|
10942
11134
|
function setCachedMediaPipe(landmarks) {
|
|
@@ -10962,9 +11154,26 @@ async function recommendForProduct(input) {
|
|
|
10962
11154
|
const t0 = Date.now();
|
|
10963
11155
|
log("ENTER", { productId: input.productId, apiUrl: input.apiUrl, skipCache: !!input.skipCache });
|
|
10964
11156
|
const sessionId = getOrCreateSessionId();
|
|
10965
|
-
const
|
|
11157
|
+
const apiKey = input.apiKey ?? getApiKey();
|
|
11158
|
+
const apiUrl = (input.apiUrl ?? getApiUrl()).replace(/\/+$/, "");
|
|
11159
|
+
const session = getStoredProfileSession();
|
|
11160
|
+
if (!session) {
|
|
11161
|
+
log("no signed-in profile session — returning null");
|
|
11162
|
+
return null;
|
|
11163
|
+
}
|
|
11164
|
+
let remoteProfiles = [];
|
|
11165
|
+
let activeProfileId = null;
|
|
11166
|
+
try {
|
|
11167
|
+
const remoteStore = await fetchRemoteProfiles(apiUrl, session.accessToken);
|
|
11168
|
+
remoteProfiles = remoteStore.profiles;
|
|
11169
|
+
activeProfileId = remoteStore.activeProfileId;
|
|
11170
|
+
} catch (error) {
|
|
11171
|
+
log("remote profile fetch failed — returning null", error);
|
|
11172
|
+
return null;
|
|
11173
|
+
}
|
|
11174
|
+
const profile = input.profile && input.profile.id === activeProfileId ? input.profile : activeProfileId ? remoteProfiles.find((p2) => p2.id === activeProfileId) ?? null : null;
|
|
10966
11175
|
if (!profile) {
|
|
10967
|
-
log("no
|
|
11176
|
+
log("no selected backend profile — returning null");
|
|
10968
11177
|
return null;
|
|
10969
11178
|
}
|
|
10970
11179
|
log("profile resolved", {
|
|
@@ -11017,8 +11226,6 @@ async function recommendForProduct(input) {
|
|
|
11017
11226
|
}
|
|
11018
11227
|
}
|
|
11019
11228
|
log(`cache MISS — calling backend (elapsed in pre-flight: ${Date.now() - t0}ms)`);
|
|
11020
|
-
const apiKey = input.apiKey ?? getApiKey();
|
|
11021
|
-
const apiUrl = (input.apiUrl ?? getApiUrl()).replace(/\/+$/, "");
|
|
11022
11229
|
let sizeGuide = null;
|
|
11023
11230
|
if (input.sizeGuideData != null) {
|
|
11024
11231
|
const tSg = Date.now();
|
|
@@ -11063,6 +11270,34 @@ async function recommendForProduct(input) {
|
|
|
11063
11270
|
if (value != null) measurements[key] = value;
|
|
11064
11271
|
}
|
|
11065
11272
|
}
|
|
11273
|
+
const legacyKnownMeasurements = {};
|
|
11274
|
+
for (const key of [
|
|
11275
|
+
"chest",
|
|
11276
|
+
"bust",
|
|
11277
|
+
"waist",
|
|
11278
|
+
"hips",
|
|
11279
|
+
"shoulderWidth",
|
|
11280
|
+
"sleeveLength",
|
|
11281
|
+
"inseam",
|
|
11282
|
+
"neckCircumference",
|
|
11283
|
+
"thighCircumference",
|
|
11284
|
+
"wristCircumference",
|
|
11285
|
+
"footLengthCm"
|
|
11286
|
+
]) {
|
|
11287
|
+
const value = profile[key];
|
|
11288
|
+
if (typeof value === "number" && value > 0) {
|
|
11289
|
+
measurements[key] = value;
|
|
11290
|
+
legacyKnownMeasurements[key] = value;
|
|
11291
|
+
}
|
|
11292
|
+
}
|
|
11293
|
+
if (profile.customMeasurements) {
|
|
11294
|
+
for (const [key, value] of Object.entries(profile.customMeasurements)) {
|
|
11295
|
+
if (typeof value === "number" && value > 0) {
|
|
11296
|
+
measurements[key] = value;
|
|
11297
|
+
legacyKnownMeasurements[key] = value;
|
|
11298
|
+
}
|
|
11299
|
+
}
|
|
11300
|
+
}
|
|
11066
11301
|
if (profile.height != null) measurements.height = profile.height;
|
|
11067
11302
|
if (profile.weight != null) measurements.weight = profile.weight;
|
|
11068
11303
|
if (profile.heightUnit) measurements.heightUnit = profile.heightUnit;
|
|
@@ -11099,6 +11334,8 @@ async function recommendForProduct(input) {
|
|
|
11099
11334
|
}
|
|
11100
11335
|
if (profile.knownMeasurements) {
|
|
11101
11336
|
payload.knownMeasurements = profile.knownMeasurements;
|
|
11337
|
+
} else if (Object.keys(legacyKnownMeasurements).length > 0) {
|
|
11338
|
+
payload.knownMeasurements = legacyKnownMeasurements;
|
|
11102
11339
|
}
|
|
11103
11340
|
if (sizeGuide && sizeGuide.found) {
|
|
11104
11341
|
payload.sizeGuide = sizeGuide;
|
|
@@ -11146,7 +11383,7 @@ async function recommendForProduct(input) {
|
|
|
11146
11383
|
}
|
|
11147
11384
|
])
|
|
11148
11385
|
) : void 0;
|
|
11149
|
-
|
|
11386
|
+
const newHistoryEntry = {
|
|
11150
11387
|
productId: input.productId,
|
|
11151
11388
|
productTitle: input.productTitle,
|
|
11152
11389
|
productImage: input.productImage,
|
|
@@ -11156,6 +11393,15 @@ async function recommendForProduct(input) {
|
|
|
11156
11393
|
sectionsFull,
|
|
11157
11394
|
recommendedLength: result.recommendedLength || void 0,
|
|
11158
11395
|
savedAt: Date.now()
|
|
11396
|
+
};
|
|
11397
|
+
const updatedProfiles = remoteProfiles.map((p2) => {
|
|
11398
|
+
if (p2.id !== profile.id) return p2;
|
|
11399
|
+
const history = (p2.sizeHistory || []).filter((h) => h.productId !== input.productId);
|
|
11400
|
+
history.unshift(newHistoryEntry);
|
|
11401
|
+
return { ...p2, sizeHistory: history.slice(0, 50), lastUsedAt: Date.now() };
|
|
11402
|
+
});
|
|
11403
|
+
void saveRemoteProfiles(apiUrl, session.accessToken, updatedProfiles, activeProfileId).catch((error) => {
|
|
11404
|
+
log("remote size-history save failed", error);
|
|
11159
11405
|
});
|
|
11160
11406
|
setLastSizeSelection({
|
|
11161
11407
|
productId: input.productId,
|
|
@@ -11345,179 +11591,6 @@ async function pickBestGarmentImage(images) {
|
|
|
11345
11591
|
for (const s of scored) console.log(`[ps-sdk:garment-pick] ${s.score.toString().padStart(4, " ")} ${s.url}`);
|
|
11346
11592
|
return best;
|
|
11347
11593
|
}
|
|
11348
|
-
const SESSION_KEY = "primestyle_profile_session";
|
|
11349
|
-
const AUTH_MESSAGE_TYPE = "PRIMESTYLE_SDK_AUTH";
|
|
11350
|
-
const POPUP_TIMEOUT_MS = 12e4;
|
|
11351
|
-
const POLL_INTERVAL_MS = 900;
|
|
11352
|
-
function isTrustedAuthOrigin(eventOrigin, expectedOrigin) {
|
|
11353
|
-
if (eventOrigin === expectedOrigin) return true;
|
|
11354
|
-
try {
|
|
11355
|
-
const host = new URL(eventOrigin).hostname;
|
|
11356
|
-
return host === "localhost" || host === "127.0.0.1" || host.endsWith(".primestyleai.com") || host.endsWith(".myaifitting.com");
|
|
11357
|
-
} catch {
|
|
11358
|
-
return false;
|
|
11359
|
-
}
|
|
11360
|
-
}
|
|
11361
|
-
function readStorage() {
|
|
11362
|
-
if (typeof window === "undefined") return null;
|
|
11363
|
-
try {
|
|
11364
|
-
return window.localStorage;
|
|
11365
|
-
} catch {
|
|
11366
|
-
return null;
|
|
11367
|
-
}
|
|
11368
|
-
}
|
|
11369
|
-
function createAuthRequestId() {
|
|
11370
|
-
try {
|
|
11371
|
-
const randomId = window.crypto?.randomUUID?.();
|
|
11372
|
-
if (randomId) return randomId;
|
|
11373
|
-
} catch {
|
|
11374
|
-
}
|
|
11375
|
-
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`;
|
|
11376
|
-
}
|
|
11377
|
-
async function readAuthStatus(statusUrl) {
|
|
11378
|
-
const response = await fetch(statusUrl.toString(), {
|
|
11379
|
-
method: "GET",
|
|
11380
|
-
credentials: "omit",
|
|
11381
|
-
cache: "no-store"
|
|
11382
|
-
});
|
|
11383
|
-
if (!response.ok) return null;
|
|
11384
|
-
const data = await response.json();
|
|
11385
|
-
return data.status === "done" ? data : null;
|
|
11386
|
-
}
|
|
11387
|
-
function getStoredProfileSession() {
|
|
11388
|
-
const storage = readStorage();
|
|
11389
|
-
if (!storage) return null;
|
|
11390
|
-
try {
|
|
11391
|
-
const raw = storage.getItem(SESSION_KEY);
|
|
11392
|
-
if (!raw) return null;
|
|
11393
|
-
const parsed = JSON.parse(raw);
|
|
11394
|
-
return parsed?.accessToken ? parsed : null;
|
|
11395
|
-
} catch {
|
|
11396
|
-
return null;
|
|
11397
|
-
}
|
|
11398
|
-
}
|
|
11399
|
-
function setStoredProfileSession(session) {
|
|
11400
|
-
const storage = readStorage();
|
|
11401
|
-
if (!storage) return;
|
|
11402
|
-
try {
|
|
11403
|
-
storage.setItem(SESSION_KEY, JSON.stringify(session));
|
|
11404
|
-
} catch {
|
|
11405
|
-
}
|
|
11406
|
-
}
|
|
11407
|
-
function clearStoredProfileSession() {
|
|
11408
|
-
const storage = readStorage();
|
|
11409
|
-
if (!storage) return;
|
|
11410
|
-
try {
|
|
11411
|
-
storage.removeItem(SESSION_KEY);
|
|
11412
|
-
} catch {
|
|
11413
|
-
}
|
|
11414
|
-
}
|
|
11415
|
-
function startSocialProfileLogin(provider, apiUrl) {
|
|
11416
|
-
if (typeof window === "undefined") {
|
|
11417
|
-
return Promise.reject(new Error("Social login must run in the browser."));
|
|
11418
|
-
}
|
|
11419
|
-
const baseUrl = getApiUrl(apiUrl);
|
|
11420
|
-
const backendOrigin = new URL(baseUrl).origin;
|
|
11421
|
-
const authRequestId = createAuthRequestId();
|
|
11422
|
-
const startUrl = new URL(`${baseUrl.replace(/\/$/, "")}/api/sdk/v1/auth/${provider}/start`);
|
|
11423
|
-
startUrl.searchParams.set("origin", window.location.origin);
|
|
11424
|
-
startUrl.searchParams.set("requestId", authRequestId);
|
|
11425
|
-
const statusUrl = new URL(`${baseUrl.replace(/\/$/, "")}/api/sdk/v1/auth/${provider}/status`);
|
|
11426
|
-
statusUrl.searchParams.set("origin", window.location.origin);
|
|
11427
|
-
statusUrl.searchParams.set("requestId", authRequestId);
|
|
11428
|
-
const popup = window.open(
|
|
11429
|
-
startUrl.toString(),
|
|
11430
|
-
"primestyle-profile-login",
|
|
11431
|
-
"width=520,height=720"
|
|
11432
|
-
);
|
|
11433
|
-
if (!popup) {
|
|
11434
|
-
return Promise.reject(new Error("Popup was blocked. Please allow popups and try again."));
|
|
11435
|
-
}
|
|
11436
|
-
return new Promise((resolve, reject) => {
|
|
11437
|
-
let settled = false;
|
|
11438
|
-
const cleanup = () => {
|
|
11439
|
-
window.removeEventListener("message", onMessage);
|
|
11440
|
-
window.clearInterval(statusTimer);
|
|
11441
|
-
window.clearTimeout(timeout);
|
|
11442
|
-
};
|
|
11443
|
-
const finish = (fn) => {
|
|
11444
|
-
if (settled) return;
|
|
11445
|
-
settled = true;
|
|
11446
|
-
cleanup();
|
|
11447
|
-
fn();
|
|
11448
|
-
};
|
|
11449
|
-
const onMessage = (event) => {
|
|
11450
|
-
if (!isTrustedAuthOrigin(event.origin, backendOrigin)) return;
|
|
11451
|
-
const data = event.data;
|
|
11452
|
-
if (!data || data.type !== AUTH_MESSAGE_TYPE) return;
|
|
11453
|
-
if (!data.ok || !data.accessToken) {
|
|
11454
|
-
finish(() => reject(new Error(data.error || "Social login failed.")));
|
|
11455
|
-
return;
|
|
11456
|
-
}
|
|
11457
|
-
finish(() => resolve({
|
|
11458
|
-
accessToken: data.accessToken,
|
|
11459
|
-
isNewUser: Boolean(data.isNewUser),
|
|
11460
|
-
signedInAt: Date.now()
|
|
11461
|
-
}));
|
|
11462
|
-
};
|
|
11463
|
-
const handleAuthPayload = (data) => {
|
|
11464
|
-
if (!data.ok || !data.accessToken) {
|
|
11465
|
-
finish(() => reject(new Error(data.error || "Social login failed.")));
|
|
11466
|
-
return;
|
|
11467
|
-
}
|
|
11468
|
-
finish(() => resolve({
|
|
11469
|
-
accessToken: data.accessToken,
|
|
11470
|
-
isNewUser: Boolean(data.isNewUser),
|
|
11471
|
-
signedInAt: Date.now()
|
|
11472
|
-
}));
|
|
11473
|
-
};
|
|
11474
|
-
const statusTimer = window.setInterval(() => {
|
|
11475
|
-
readAuthStatus(statusUrl).then((data) => {
|
|
11476
|
-
if (data) handleAuthPayload(data);
|
|
11477
|
-
}).catch(() => {
|
|
11478
|
-
});
|
|
11479
|
-
}, POLL_INTERVAL_MS);
|
|
11480
|
-
const timeout = window.setTimeout(() => {
|
|
11481
|
-
finish(() => reject(new Error("Login did not finish. Please close the sign-in window and try again.")));
|
|
11482
|
-
}, POPUP_TIMEOUT_MS);
|
|
11483
|
-
window.addEventListener("message", onMessage);
|
|
11484
|
-
});
|
|
11485
|
-
}
|
|
11486
|
-
function endpoint(apiUrl) {
|
|
11487
|
-
return `${getApiUrl(apiUrl).replace(/\/$/, "")}/api/sdk/v1/profiles`;
|
|
11488
|
-
}
|
|
11489
|
-
function normalizeStore(data) {
|
|
11490
|
-
return {
|
|
11491
|
-
profiles: Array.isArray(data.profiles) ? data.profiles : [],
|
|
11492
|
-
activeProfileId: data.activeProfileId ?? null
|
|
11493
|
-
};
|
|
11494
|
-
}
|
|
11495
|
-
async function parseResponse(response) {
|
|
11496
|
-
const data = await response.json().catch(() => ({}));
|
|
11497
|
-
if (!response.ok) {
|
|
11498
|
-
const message = typeof data.message === "string" ? data.message : "Profile sync failed.";
|
|
11499
|
-
throw new Error(message);
|
|
11500
|
-
}
|
|
11501
|
-
return data;
|
|
11502
|
-
}
|
|
11503
|
-
async function fetchRemoteProfiles(apiUrl, accessToken) {
|
|
11504
|
-
const response = await fetch(endpoint(apiUrl), {
|
|
11505
|
-
method: "GET",
|
|
11506
|
-
headers: { Authorization: `Bearer ${accessToken}` }
|
|
11507
|
-
});
|
|
11508
|
-
return normalizeStore(await parseResponse(response));
|
|
11509
|
-
}
|
|
11510
|
-
async function saveRemoteProfiles(apiUrl, accessToken, profiles, activeProfileId) {
|
|
11511
|
-
const response = await fetch(endpoint(apiUrl), {
|
|
11512
|
-
method: "PUT",
|
|
11513
|
-
headers: {
|
|
11514
|
-
Authorization: `Bearer ${accessToken}`,
|
|
11515
|
-
"Content-Type": "application/json"
|
|
11516
|
-
},
|
|
11517
|
-
body: JSON.stringify({ profiles, activeProfileId })
|
|
11518
|
-
});
|
|
11519
|
-
return normalizeStore(await parseResponse(response));
|
|
11520
|
-
}
|
|
11521
11594
|
function normalizeProfilePhotoSource(value) {
|
|
11522
11595
|
if (!value) return null;
|
|
11523
11596
|
if (/^https?:\/\//i.test(value)) return value;
|
|
@@ -16611,7 +16684,7 @@ const STYLES = `
|
|
|
16611
16684
|
to { opacity: 1; }
|
|
16612
16685
|
}
|
|
16613
16686
|
|
|
16614
|
-
/*
|
|
16687
|
+
/* Active profile status above body details */
|
|
16615
16688
|
.ps-bp-profile-hint {
|
|
16616
16689
|
margin: 0; padding: 0;
|
|
16617
16690
|
text-align: center;
|
|
@@ -16631,6 +16704,65 @@ const STYLES = `
|
|
|
16631
16704
|
cursor: pointer; padding: 0;
|
|
16632
16705
|
}
|
|
16633
16706
|
.ps-bp-profile-hint-link:hover { color: var(--ps-text-secondary); }
|
|
16707
|
+
.ps-bp-profile-card {
|
|
16708
|
+
display: flex;
|
|
16709
|
+
align-items: center;
|
|
16710
|
+
justify-content: space-between;
|
|
16711
|
+
gap: clamp(10px, 0.9vw, 18px);
|
|
16712
|
+
width: min(100%, 520px);
|
|
16713
|
+
margin: 0 auto clamp(10px, 0.9vw, 18px);
|
|
16714
|
+
padding: clamp(10px, 0.85vw, 16px) clamp(12px, 1vw, 20px);
|
|
16715
|
+
border: 1px solid rgba(33, 84, 239, 0.18);
|
|
16716
|
+
border-radius: clamp(8px, 0.7vw, 12px);
|
|
16717
|
+
background: linear-gradient(135deg, rgba(33, 84, 239, 0.08), rgba(255, 255, 255, 0.96));
|
|
16718
|
+
box-shadow: 0 10px 28px -24px rgba(33, 84, 239, 0.55);
|
|
16719
|
+
}
|
|
16720
|
+
.ps-bp-profile-card-copy {
|
|
16721
|
+
display: flex;
|
|
16722
|
+
flex-direction: column;
|
|
16723
|
+
gap: clamp(2px, 0.18vw, 4px);
|
|
16724
|
+
min-width: 0;
|
|
16725
|
+
}
|
|
16726
|
+
.ps-bp-profile-card-eyebrow {
|
|
16727
|
+
font-size: clamp(8px, 0.55vw, 10px);
|
|
16728
|
+
font-weight: 800;
|
|
16729
|
+
letter-spacing: 0.14em;
|
|
16730
|
+
text-transform: uppercase;
|
|
16731
|
+
color: var(--ps-accent);
|
|
16732
|
+
}
|
|
16733
|
+
.ps-bp-profile-card-copy strong {
|
|
16734
|
+
font-size: clamp(13px, 0.95vw, 17px);
|
|
16735
|
+
line-height: 1.1;
|
|
16736
|
+
color: var(--ps-text-primary);
|
|
16737
|
+
overflow: hidden;
|
|
16738
|
+
text-overflow: ellipsis;
|
|
16739
|
+
white-space: nowrap;
|
|
16740
|
+
}
|
|
16741
|
+
.ps-bp-profile-card-copy span:last-child {
|
|
16742
|
+
font-size: clamp(10px, 0.68vw, 12px);
|
|
16743
|
+
line-height: 1.35;
|
|
16744
|
+
color: var(--ps-text-secondary);
|
|
16745
|
+
}
|
|
16746
|
+
.ps-bp-profile-card-action {
|
|
16747
|
+
flex-shrink: 0;
|
|
16748
|
+
border: 1px solid rgba(33, 84, 239, 0.22);
|
|
16749
|
+
background: #FFFFFF;
|
|
16750
|
+
color: var(--ps-accent);
|
|
16751
|
+
border-radius: 999px;
|
|
16752
|
+
padding: clamp(7px, 0.55vw, 10px) clamp(10px, 0.8vw, 16px);
|
|
16753
|
+
font-family: inherit;
|
|
16754
|
+
font-size: clamp(9px, 0.62vw, 11px);
|
|
16755
|
+
font-weight: 800;
|
|
16756
|
+
letter-spacing: 0.08em;
|
|
16757
|
+
text-transform: uppercase;
|
|
16758
|
+
cursor: pointer;
|
|
16759
|
+
transition: border-color 0.15s, background 0.15s, transform 0.15s;
|
|
16760
|
+
}
|
|
16761
|
+
.ps-bp-profile-card-action:hover {
|
|
16762
|
+
border-color: var(--ps-accent);
|
|
16763
|
+
background: rgba(33, 84, 239, 0.06);
|
|
16764
|
+
}
|
|
16765
|
+
.ps-bp-profile-card-action:active { transform: scale(0.98); }
|
|
16634
16766
|
|
|
16635
16767
|
/* Typography */
|
|
16636
16768
|
.ps-bp-title {
|
|
@@ -19259,6 +19391,9 @@ const STYLES = `
|
|
|
19259
19391
|
background: var(--ps-bg-primary);
|
|
19260
19392
|
flex-shrink: 0;
|
|
19261
19393
|
}
|
|
19394
|
+
.ps-cpw-footer-no-back {
|
|
19395
|
+
justify-content: flex-end;
|
|
19396
|
+
}
|
|
19262
19397
|
.ps-cpw-back-btn {
|
|
19263
19398
|
background: none; border: none;
|
|
19264
19399
|
color: var(--ps-text-secondary);
|
|
@@ -19902,6 +20037,7 @@ const STYLES = `
|
|
|
19902
20037
|
display: flex; flex-direction: column;
|
|
19903
20038
|
gap: max(14px, 1.2vw);
|
|
19904
20039
|
min-width: 0; width: 100%;
|
|
20040
|
+
padding-bottom: clamp(78px, 5.4vw, 104px);
|
|
19905
20041
|
}
|
|
19906
20042
|
|
|
19907
20043
|
/* Basics list — height / weight / age, inline icon + label + value */
|
|
@@ -20137,12 +20273,12 @@ const STYLES = `
|
|
|
20137
20273
|
gap: clamp(8px, 0.7vw, 14px);
|
|
20138
20274
|
position: sticky;
|
|
20139
20275
|
bottom: 0;
|
|
20140
|
-
background: var(--ps-bg-primary);
|
|
20276
|
+
background: color-mix(in srgb, var(--ps-bg-primary) 96%, #FFFFFF);
|
|
20141
20277
|
border-top: 1px solid var(--ps-border-subtle);
|
|
20142
|
-
padding
|
|
20143
|
-
|
|
20144
|
-
z-index: 2;
|
|
20278
|
+
padding: clamp(10px, 0.8vw, 16px) clamp(4px, 0.35vw, 8px) calc(clamp(10px, 0.8vw, 16px) + env(safe-area-inset-bottom, 0px));
|
|
20279
|
+
z-index: 5;
|
|
20145
20280
|
margin-top: auto;
|
|
20281
|
+
box-shadow: 0 -14px 30px -28px rgba(17, 24, 39, 0.35);
|
|
20146
20282
|
}
|
|
20147
20283
|
.ps-pmv-actions-right {
|
|
20148
20284
|
display: flex; align-items: center;
|
|
@@ -20154,7 +20290,7 @@ const STYLES = `
|
|
|
20154
20290
|
background: none;
|
|
20155
20291
|
border: 1px solid var(--ps-border-color);
|
|
20156
20292
|
border-radius: clamp(4px, 0.35vw, 8px);
|
|
20157
|
-
padding: clamp(6px, 0.55vw, 12px) clamp(
|
|
20293
|
+
padding: clamp(6px, 0.55vw, 12px) clamp(13px, 1.05vw, 24px);
|
|
20158
20294
|
font-family: inherit;
|
|
20159
20295
|
font-size: clamp(9px, 0.65vw, 12px);
|
|
20160
20296
|
font-weight: 600;
|
|
@@ -20176,7 +20312,7 @@ const STYLES = `
|
|
|
20176
20312
|
background: var(--ps-accent); color: #FFFFFF;
|
|
20177
20313
|
border: none;
|
|
20178
20314
|
border-radius: clamp(4px, 0.35vw, 8px);
|
|
20179
|
-
padding: clamp(7px, 0.65vw, 14px) clamp(
|
|
20315
|
+
padding: clamp(7px, 0.65vw, 14px) clamp(15px, 1.15vw, 26px);
|
|
20180
20316
|
font-family: inherit;
|
|
20181
20317
|
font-size: clamp(9px, 0.65vw, 12px);
|
|
20182
20318
|
font-weight: 700;
|
|
@@ -21824,7 +21960,7 @@ function WelcomeView({
|
|
|
21824
21960
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-welcome-sparkle", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SparkleIcon, { size: 20 }) })
|
|
21825
21961
|
] }),
|
|
21826
21962
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-tryon-welcome-title", children: t2("See Your Fit") }),
|
|
21827
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-welcome-sub", children: t2("
|
|
21963
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-welcome-sub", children: t2("Check your size, then try it on virtually") })
|
|
21828
21964
|
] }),
|
|
21829
21965
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-features", children: [
|
|
21830
21966
|
{ icon: /* @__PURE__ */ jsxRuntimeExports.jsx(RulerIcon$1, { size: 22 }), title: t2("Get Your Size"), desc: t2("Instant fit recommendation") },
|
|
@@ -22155,7 +22291,7 @@ function MobileScanningView({
|
|
|
22155
22291
|
{ title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation."), viewfinderText: t2("FINALIZING") }
|
|
22156
22292
|
] : [
|
|
22157
22293
|
{ title: t2("DETECTING POSE"), desc: t2("Identifying body landmarks from your photo."), viewfinderText: t2("DETECTING POSE") },
|
|
22158
|
-
{ title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions
|
|
22294
|
+
{ title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions for a size recommendation."), viewfinderText: t2("SCANNING FRAME") },
|
|
22159
22295
|
{ title: t2("ANALYZING BODY"), desc: t2("Measuring shoulders, chest, waist and hips."), viewfinderText: t2("ANALYZING") },
|
|
22160
22296
|
{ title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the size guide."), viewfinderText: t2("MATCHING SIZE") },
|
|
22161
22297
|
{ title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation."), viewfinderText: t2("FINALIZING") }
|
|
@@ -23168,10 +23304,10 @@ const cellValFn = (row, colIdx, header) => {
|
|
|
23168
23304
|
}
|
|
23169
23305
|
return "";
|
|
23170
23306
|
};
|
|
23171
|
-
const fitLabelFn = (fit, t2) => fit === "good" ? t2("
|
|
23307
|
+
const fitLabelFn = (fit, t2) => fit === "good" ? t2("within range") : fit === "too-tight" ? t2("too tight") : fit === "tight" ? t2("tight") : fit === "a-bit-tight" ? t2("a bit tight") : fit === "too-loose" ? t2("too loose") : fit === "loose" ? t2("loose") : t2("a bit loose");
|
|
23172
23308
|
const accessoryFitLabelFn = (fit, t2) => fit === "good" ? t2("within range") : fitLabelFn(fit, t2);
|
|
23173
23309
|
const lengthFitLabelFn = (fit, t2) => {
|
|
23174
|
-
if (fit === "good") return t2("
|
|
23310
|
+
if (fit === "good") return t2("within range");
|
|
23175
23311
|
if (fit === "too-short" || fit === "too-tight") return t2("too short");
|
|
23176
23312
|
if (fit === "short" || fit === "tight") return t2("short");
|
|
23177
23313
|
if (fit === "a-bit-short" || fit === "a-bit-tight") return t2("a bit short");
|
|
@@ -24929,7 +25065,7 @@ function SizeResultView({
|
|
|
24929
25065
|
] }),
|
|
24930
25066
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-panel ps-tryon-v2-result-panel", children: [
|
|
24931
25067
|
profileCompletionCta ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-profile-head ps-expanded", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProfileCompletionCta, { onClick: profileCompletionCta.onClick, placement: "header", t: t2 }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-result-copy", children: [
|
|
24932
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: t2("Your
|
|
25068
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: t2("Your Size Recommendation") }),
|
|
24933
25069
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-v2-subtitle", children: t2("Tap any section for detailed breakdown") })
|
|
24934
25070
|
] }),
|
|
24935
25071
|
mismatchNotice,
|
|
@@ -25186,7 +25322,7 @@ function SizeResultView({
|
|
|
25186
25322
|
/* CARD VIEW — clickable summary card + gallery strip */
|
|
25187
25323
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
25188
25324
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-result-head", children: profileCompletionCta ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-profile-head ps-expanded", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ProfileCompletionCta, { onClick: profileCompletionCta.onClick, placement: "header", t: t2 }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-v2-result-copy", children: [
|
|
25189
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: guideOnlyResult ? t2("Product Size Guide") : t2("Your
|
|
25325
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-v2-title", children: guideOnlyResult ? t2("Product Size Guide") : t2("Your Size Recommendation") }),
|
|
25190
25326
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-v2-subtitle", children: guideOnlyResult ? t2("Tap the card to view product measurements") : t2("Tap the card for detailed breakdown") })
|
|
25191
25327
|
] }) }),
|
|
25192
25328
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-v2-sep" }),
|
|
@@ -26048,7 +26184,7 @@ function ProcessingView({
|
|
|
26048
26184
|
}
|
|
26049
26185
|
}, []);
|
|
26050
26186
|
const aiFacts = [
|
|
26051
|
-
t2("Our model is analyzing 150+ body landmarks for
|
|
26187
|
+
t2("Our model is analyzing 150+ body landmarks for your size recommendation"),
|
|
26052
26188
|
t2("Calibrating fabric drape against your body proportions"),
|
|
26053
26189
|
t2("Cross-checking fit against millions of garment patterns"),
|
|
26054
26190
|
t2("Rendering shadows and highlights to match your photo's lighting")
|
|
@@ -26151,20 +26287,22 @@ function ProcessingView({
|
|
|
26151
26287
|
function NoChartView({
|
|
26152
26288
|
productImage,
|
|
26153
26289
|
productTitle,
|
|
26290
|
+
reason = "no-chart",
|
|
26154
26291
|
onTryOn,
|
|
26155
26292
|
onClose,
|
|
26156
26293
|
t: t2
|
|
26157
26294
|
}) {
|
|
26158
26295
|
const isMobile = useIsMobile();
|
|
26296
|
+
const isNoMatch = reason === "no-match";
|
|
26159
26297
|
const RightColumn = /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-no-chart-content", children: [
|
|
26160
26298
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-tryon-no-chart-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("svg", { viewBox: "0 0 24 24", width: "44", height: "44", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
26161
26299
|
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M3 17l6 6 12-12-6-6L3 17z" }),
|
|
26162
26300
|
/* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M14 4l-3 3M16 6l-2 2M18 8l-2 2M11 7l-2 2M13 9l-2 2M15 11l-2 2" })
|
|
26163
26301
|
] }) }),
|
|
26164
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-no-chart-title", children: t2("No size chart available") }),
|
|
26165
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-no-chart-msg", children: t2("The merchant hasn't uploaded sizing data for this product yet. You can still see how it looks on you with a virtual try-on.") }),
|
|
26302
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "ps-tryon-no-chart-title", children: isNoMatch ? t2("No matching size available") : t2("No size chart available") }),
|
|
26303
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-tryon-no-chart-msg", children: isNoMatch ? t2("This product's size chart doesn't include a reliable fit for your measurements.") : t2("The merchant hasn't uploaded sizing data for this product yet. You can still see how it looks on you with a virtual try-on.") }),
|
|
26166
26304
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-tryon-no-chart-actions", children: [
|
|
26167
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-tryon-no-chart-cta", onClick: onTryOn, children: [
|
|
26305
|
+
!isNoMatch && /* @__PURE__ */ jsxRuntimeExports.jsxs("button", { type: "button", className: "ps-tryon-no-chart-cta", onClick: onTryOn, children: [
|
|
26168
26306
|
t2("See how it looks on you"),
|
|
26169
26307
|
" →"
|
|
26170
26308
|
] }),
|
|
@@ -26348,10 +26486,11 @@ function ProgressiveStep({
|
|
|
26348
26486
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-card-row", children })
|
|
26349
26487
|
] }, stepKey);
|
|
26350
26488
|
}
|
|
26351
|
-
function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiUrl, apiKey, onPhotoPreview, onEstimate, t: t2 }) {
|
|
26489
|
+
function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, directAnalysisFlow = false, apiUrl, apiKey, onPhotoPreview, onEstimate, t: t2 }) {
|
|
26352
26490
|
const seededUnit = draftUnit(initialDraft);
|
|
26353
26491
|
const seededHeight = draftHeightParts(initialDraft, seededUnit);
|
|
26354
26492
|
const seededGender = initialDraft?.gender === "female" ? "female" : "male";
|
|
26493
|
+
const seededPhotoRef = reactExports.useRef(initialDraft?.photoBase64 || initialDraft?.photoUrl || null);
|
|
26355
26494
|
const [mode, setMode] = reactExports.useState(initialMode ?? null);
|
|
26356
26495
|
const [manualStep, setManualStep] = reactExports.useState("identity");
|
|
26357
26496
|
const [imageStep, setImageStep] = reactExports.useState("name-photo");
|
|
@@ -26370,15 +26509,19 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
|
|
|
26370
26509
|
const [weightVal, setWeightVal] = reactExports.useState(draftDisplayNumber(initialDraft?.weight));
|
|
26371
26510
|
const [ageVal, setAgeVal] = reactExports.useState(draftDisplayNumber(initialDraft?.age));
|
|
26372
26511
|
const [error, setError] = reactExports.useState("");
|
|
26373
|
-
const [photoBase64, setPhotoBase64] = reactExports.useState(
|
|
26512
|
+
const [photoBase64, setPhotoBase64] = reactExports.useState(() => seededPhotoRef.current);
|
|
26374
26513
|
const [photoUploading, setPhotoUploading] = reactExports.useState(false);
|
|
26375
26514
|
const [photoStatus, setPhotoStatus] = reactExports.useState("");
|
|
26376
26515
|
const [photoRejection, setPhotoRejection] = reactExports.useState(null);
|
|
26516
|
+
reactExports.useEffect(() => {
|
|
26517
|
+
if (seededPhotoRef.current) onPhotoPreview?.(seededPhotoRef.current);
|
|
26518
|
+
}, []);
|
|
26377
26519
|
const [scanLandmarks, setScanLandmarks] = reactExports.useState(null);
|
|
26378
26520
|
const [scanImgDims, setScanImgDims] = reactExports.useState({ w: 800, h: 1200 });
|
|
26379
26521
|
const [scanStageIdx, setScanStageIdx] = reactExports.useState(0);
|
|
26380
26522
|
const [photoHelpOpen, setPhotoHelpOpen] = reactExports.useState(false);
|
|
26381
26523
|
const [uploadHoverCpw, setUploadHoverCpw] = reactExports.useState(false);
|
|
26524
|
+
const directAutoStartedRef = reactExports.useRef(false);
|
|
26382
26525
|
reactExports.useEffect(() => {
|
|
26383
26526
|
if (imageStep !== "calculating" || !photoBase64) return;
|
|
26384
26527
|
let cancelled = false;
|
|
@@ -26677,7 +26820,7 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
|
|
|
26677
26820
|
return;
|
|
26678
26821
|
}
|
|
26679
26822
|
const a = parseFloat(ageVal);
|
|
26680
|
-
if (isWomen && (!bandSize || !cupSize)) {
|
|
26823
|
+
if (isWomen && !directAnalysisFlow && (!bandSize || !cupSize)) {
|
|
26681
26824
|
setError(t2("Please select your bra band and cup size"));
|
|
26682
26825
|
return;
|
|
26683
26826
|
}
|
|
@@ -26727,6 +26870,15 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
|
|
|
26727
26870
|
}
|
|
26728
26871
|
onSave(payload);
|
|
26729
26872
|
};
|
|
26873
|
+
reactExports.useEffect(() => {
|
|
26874
|
+
if (!directAnalysisFlow || directAutoStartedRef.current) return;
|
|
26875
|
+
if (mode !== "image" || imageStep !== "name-photo") return;
|
|
26876
|
+
const hasHeight = unit === "in" ? parseFloat(heightFt) > 0 || parseFloat(heightInch) > 0 : parseFloat(heightVal) > 0;
|
|
26877
|
+
const hasWeight = parseFloat(weightVal) > 0;
|
|
26878
|
+
if (!photoBase64 || !name.trim() || !hasHeight || !hasWeight) return;
|
|
26879
|
+
directAutoStartedRef.current = true;
|
|
26880
|
+
void advanceImage();
|
|
26881
|
+
}, [directAnalysisFlow, mode, imageStep, photoBase64, name, heightFt, heightInch, heightVal, weightVal, unit]);
|
|
26730
26882
|
const goBackImage = () => {
|
|
26731
26883
|
setError("");
|
|
26732
26884
|
if (imageStep === "details") {
|
|
@@ -26768,9 +26920,12 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
|
|
|
26768
26920
|
if (photoBase64) pct += 50;
|
|
26769
26921
|
return pct;
|
|
26770
26922
|
})();
|
|
26771
|
-
const hideGlobalBack = mode === "image" && imageStep === "name-photo";
|
|
26772
|
-
|
|
26773
|
-
|
|
26923
|
+
const hideGlobalBack = mode === "image" && imageStep === "name-photo" && !directAnalysisFlow;
|
|
26924
|
+
const hideStepHeader = directAnalysisFlow && mode === "image";
|
|
26925
|
+
const hideFooter = directAnalysisFlow && mode === "image" && imageStep === "calculating" && estimating;
|
|
26926
|
+
const hideFooterBack = directAnalysisFlow && mode === "image";
|
|
26927
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-cpw-root${hideGlobalBack ? " ps-cpw-hide-global-back" : ""}${directAnalysisFlow ? " ps-cpw-direct-flow" : ""}`, children: [
|
|
26928
|
+
!hideStepHeader && !(mode === "image" && imageStep === "name-photo") && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-step-head", children: [
|
|
26774
26929
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-cpw-step-title", children: headerLabel }),
|
|
26775
26930
|
mode != null && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-progress", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-progress-track", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-cpw-progress-fill", style: { width: `${progressPct}%` } }) }) })
|
|
26776
26931
|
] }),
|
|
@@ -27698,7 +27853,7 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
|
|
|
27698
27853
|
mode === "image" && imageStep === "calculating" && (() => {
|
|
27699
27854
|
const stages = [
|
|
27700
27855
|
{ title: t2("DETECTING POSE"), desc: t2("Identifying body landmarks from your photo.") },
|
|
27701
|
-
{ title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions
|
|
27856
|
+
{ title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions for a size recommendation.") },
|
|
27702
27857
|
{ title: t2("ANALYZING BODY"), desc: t2("Measuring shoulders, chest, waist and hips.") },
|
|
27703
27858
|
{ title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the size guide.") },
|
|
27704
27859
|
{ title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
|
|
@@ -27786,13 +27941,13 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
|
|
|
27786
27941
|
] }) }, "image-calculating");
|
|
27787
27942
|
})()
|
|
27788
27943
|
] }),
|
|
27789
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-footer"
|
|
27790
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-cpw-back-btn", onClick: handleBack, children: mode == null ? t2("Cancel") : `← ${t2("Back")}` }),
|
|
27944
|
+
!hideFooter && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-cpw-footer${hideFooterBack ? " ps-cpw-footer-no-back" : ""}`, children: [
|
|
27945
|
+
!hideFooterBack && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-cpw-back-btn", onClick: handleBack, children: mode == null ? t2("Cancel") : `← ${t2("Back")}` }),
|
|
27791
27946
|
mode === "manual" && !isAutoAdvanceStep && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-cpw-next-btn", onClick: advanceManual, children: isLastManualStep ? t2("CALCULATE MY FIT") : t2("Continue") }),
|
|
27792
27947
|
mode === "image" && imageStep === "name-photo" && (() => {
|
|
27793
27948
|
const heightOk = unit === "in" ? parseFloat(heightFt) > 0 || parseFloat(heightInch) > 0 : parseFloat(heightVal) > 0;
|
|
27794
27949
|
const weightOk = parseFloat(weightVal) > 0;
|
|
27795
|
-
const braOk = !isWomen || !!bandSize && !!cupSize;
|
|
27950
|
+
const braOk = !isWomen || directAnalysisFlow || !!bandSize && !!cupSize;
|
|
27796
27951
|
const nameOk = !!name.trim();
|
|
27797
27952
|
const photoOk = !!photoBase64;
|
|
27798
27953
|
const analyzing = photoUploading;
|
|
@@ -28213,6 +28368,8 @@ function MySizingProfilesView({
|
|
|
28213
28368
|
const goBack = () => {
|
|
28214
28369
|
if (creating) {
|
|
28215
28370
|
setCreating(false);
|
|
28371
|
+
onProfileDraftConsumed?.();
|
|
28372
|
+
onPhotoPreview?.(null);
|
|
28216
28373
|
return;
|
|
28217
28374
|
}
|
|
28218
28375
|
if (viewingId !== null) {
|
|
@@ -28221,7 +28378,7 @@ function MySizingProfilesView({
|
|
|
28221
28378
|
}
|
|
28222
28379
|
};
|
|
28223
28380
|
onRegisterBackInterceptor(canGoBack, goBack);
|
|
28224
|
-
}, [creating, viewingId, onRegisterBackInterceptor]);
|
|
28381
|
+
}, [creating, viewingId, onRegisterBackInterceptor, onProfileDraftConsumed, onPhotoPreview]);
|
|
28225
28382
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msp-root", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ps-msp-scroll", children: viewingProfile ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
28226
28383
|
ProfileMeasurementsView,
|
|
28227
28384
|
{
|
|
@@ -28246,6 +28403,7 @@ function MySizingProfilesView({
|
|
|
28246
28403
|
apiKey,
|
|
28247
28404
|
initialMode: initialCreateDraft ? "image" : void 0,
|
|
28248
28405
|
initialDraft: initialCreateDraft,
|
|
28406
|
+
directAnalysisFlow: !!initialCreateDraft,
|
|
28249
28407
|
onSave: (data) => {
|
|
28250
28408
|
onSaveNewProfile(data);
|
|
28251
28409
|
onProfileDraftConsumed?.();
|
|
@@ -28482,14 +28640,13 @@ function BasicsStepMobile({
|
|
|
28482
28640
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-bpm-title", children: t2("Body Measurements") }),
|
|
28483
28641
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-bpm-subtitle", children: t2("Enter your details for a bespoke size recommendation") })
|
|
28484
28642
|
] }),
|
|
28485
|
-
activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("
|
|
28486
|
-
|
|
28487
|
-
|
|
28488
|
-
|
|
28489
|
-
|
|
28490
|
-
|
|
28491
|
-
|
|
28492
|
-
] })
|
|
28643
|
+
activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-profile-card", children: [
|
|
28644
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-profile-card-copy", children: [
|
|
28645
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-profile-card-eyebrow", children: t2("Active Profile") }),
|
|
28646
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: activeProfileName }),
|
|
28647
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Using saved measurements for this fit.") })
|
|
28648
|
+
] }),
|
|
28649
|
+
onStartFresh && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-bp-profile-card-action", onClick: onStartFresh, children: t2("Start Fresh") })
|
|
28493
28650
|
] }),
|
|
28494
28651
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bpm-toggle", children: [
|
|
28495
28652
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -29549,6 +29706,9 @@ function BodyProfileView({
|
|
|
29549
29706
|
formRef.current.weight = String(weightVal);
|
|
29550
29707
|
formRef.current.gender = gender;
|
|
29551
29708
|
if (age) formRef.current.age = age;
|
|
29709
|
+
if (chestProfile) formRef.current.chestProfile = chestProfile;
|
|
29710
|
+
if (midsectionProfile) formRef.current.midsectionProfile = midsectionProfile;
|
|
29711
|
+
if (hipProfile) formRef.current.hipProfile = hipProfile;
|
|
29552
29712
|
if (bandSize) formRef.current.bandSize = bandSize;
|
|
29553
29713
|
if (cupSize) formRef.current.cupSize = cupSize;
|
|
29554
29714
|
if (braSizeRegion) formRef.current.braSizeRegion = braSizeRegion;
|
|
@@ -29605,6 +29765,9 @@ function BodyProfileView({
|
|
|
29605
29765
|
weightUnit: isShoeReferenceMode ? "kg" : wUnit,
|
|
29606
29766
|
gender,
|
|
29607
29767
|
...ageForSubmit ? { age: ageForSubmit } : {},
|
|
29768
|
+
...chestProfile ? { chestProfile } : {},
|
|
29769
|
+
...midsectionProfile ? { midsectionProfile } : {},
|
|
29770
|
+
...hipProfile ? { hipProfile } : {},
|
|
29608
29771
|
...currentShoeReference ? {
|
|
29609
29772
|
extraMeasurements: {
|
|
29610
29773
|
referenceShoeBrandId: currentShoeReference.brandId,
|
|
@@ -30502,14 +30665,13 @@ function BodyProfileView({
|
|
|
30502
30665
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: `ps-bp-system-btn${isImperialMode ? " ps-bp-system-active" : ""}`, onClick: photoSwitchToImperial, type: "button", children: t2("Imperial") })
|
|
30503
30666
|
] }),
|
|
30504
30667
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { marginTop: "auto", marginBottom: "auto" }, children: [
|
|
30505
|
-
activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("
|
|
30506
|
-
|
|
30507
|
-
|
|
30508
|
-
|
|
30509
|
-
|
|
30510
|
-
|
|
30511
|
-
|
|
30512
|
-
] })
|
|
30668
|
+
activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-profile-card", children: [
|
|
30669
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-profile-card-copy", children: [
|
|
30670
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-profile-card-eyebrow", children: t2("Active Profile") }),
|
|
30671
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: activeProfileName }),
|
|
30672
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Using saved measurements for this fit.") })
|
|
30673
|
+
] }),
|
|
30674
|
+
onStartFresh && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-bp-profile-card-action", onClick: handleClearFromProfile, children: t2("Start Fresh") })
|
|
30513
30675
|
] }),
|
|
30514
30676
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-fields", children: [
|
|
30515
30677
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
|
|
@@ -30811,14 +30973,13 @@ function BodyProfileView({
|
|
|
30811
30973
|
}
|
|
30812
30974
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-step ps-bp-step-enter", children: [
|
|
30813
30975
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-bp-title", children: basicOnly || simplePhotoOnly ? t2("Your Details") : t2("Body Measurements") }),
|
|
30814
|
-
activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("
|
|
30815
|
-
|
|
30816
|
-
|
|
30817
|
-
|
|
30818
|
-
|
|
30819
|
-
|
|
30820
|
-
|
|
30821
|
-
] })
|
|
30976
|
+
activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-profile-card", children: [
|
|
30977
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-profile-card-copy", children: [
|
|
30978
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ps-bp-profile-card-eyebrow", children: t2("Active Profile") }),
|
|
30979
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: activeProfileName }),
|
|
30980
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: t2("Using saved measurements for this fit.") })
|
|
30981
|
+
] }),
|
|
30982
|
+
onStartFresh && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-bp-profile-card-action", onClick: handleClearFromProfile, children: t2("Start Fresh") })
|
|
30822
30983
|
] }),
|
|
30823
30984
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-system-toggle", children: [
|
|
30824
30985
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: `ps-bp-system-btn${!isImperialMode ? " ps-bp-system-active" : ""}`, onClick: switchToMetric, type: "button", children: t2("Metric") }),
|
|
@@ -32594,6 +32755,7 @@ function PrimeStyleTryonInner({
|
|
|
32594
32755
|
setCssReady(true);
|
|
32595
32756
|
}, []);
|
|
32596
32757
|
const [view, setView] = reactExports.useState(initialView ?? "idle");
|
|
32758
|
+
const [noSizeReason, setNoSizeReason] = reactExports.useState("no-chart");
|
|
32597
32759
|
const [selectedFile, setSelectedFile] = reactExports.useState(null);
|
|
32598
32760
|
const [previewUrl, setPreviewUrl] = reactExports.useState(null);
|
|
32599
32761
|
const [resultImageUrl, setResultImageUrl] = reactExports.useState(null);
|
|
@@ -32673,7 +32835,9 @@ function PrimeStyleTryonInner({
|
|
|
32673
32835
|
const [estimationLoading, setEstimationLoading] = reactExports.useState(false);
|
|
32674
32836
|
const [profiles, setProfiles] = reactExports.useState(() => lsGet("profiles", []));
|
|
32675
32837
|
const [profileSession, setProfileSession] = reactExports.useState(() => getStoredProfileSession());
|
|
32676
|
-
const
|
|
32838
|
+
const profileSessionRef = reactExports.useRef(profileSession);
|
|
32839
|
+
const suppressNextProfilePersistRef = reactExports.useRef(false);
|
|
32840
|
+
const [profileCompletionDraft, setProfileCompletionDraft] = reactExports.useState(() => getStoredProfileSession() ? null : lsGet(PROFILE_COMPLETION_DRAFT_KEY, null));
|
|
32677
32841
|
const [profileAuthError, setProfileAuthError] = reactExports.useState(null);
|
|
32678
32842
|
const [profileAuthLoadingProvider, setProfileAuthLoadingProvider] = reactExports.useState(null);
|
|
32679
32843
|
const [history, setHistory] = reactExports.useState(() => lsGet("history", []).map(normalizeHistoryEntry));
|
|
@@ -32692,8 +32856,11 @@ function PrimeStyleTryonInner({
|
|
|
32692
32856
|
const [deleteConfirmId, setDeleteConfirmId] = reactExports.useState(null);
|
|
32693
32857
|
const setActiveProfileId$1 = reactExports.useCallback((id2) => {
|
|
32694
32858
|
setActiveProfileIdState(id2);
|
|
32695
|
-
setActiveProfileId(id2);
|
|
32859
|
+
if (!profileSessionRef.current) setActiveProfileId(id2);
|
|
32696
32860
|
}, []);
|
|
32861
|
+
reactExports.useEffect(() => {
|
|
32862
|
+
profileSessionRef.current = profileSession;
|
|
32863
|
+
}, [profileSession]);
|
|
32697
32864
|
const [profileSaved, setProfileSaved] = reactExports.useState(false);
|
|
32698
32865
|
const [drawer, setDrawer] = reactExports.useState(null);
|
|
32699
32866
|
const [profileDetail, setProfileDetail] = reactExports.useState(null);
|
|
@@ -32709,13 +32876,15 @@ function PrimeStyleTryonInner({
|
|
|
32709
32876
|
profilesGoBackRef.current = goBack;
|
|
32710
32877
|
}, []);
|
|
32711
32878
|
const clearProfileCompletionDraft = reactExports.useCallback(() => {
|
|
32712
|
-
|
|
32879
|
+
lsRemove(PROFILE_COMPLETION_DRAFT_KEY);
|
|
32713
32880
|
setProfileCompletionDraft(null);
|
|
32714
32881
|
}, []);
|
|
32715
32882
|
const handleCompleteProfileFromResult = reactExports.useCallback(() => {
|
|
32716
32883
|
const f2 = formRef.current || {};
|
|
32717
32884
|
const active = profiles.find((p2) => p2.id === activeProfileId) || null;
|
|
32718
32885
|
const gender = f2.gender === "female" || active?.gender === "female" ? "female" : "male";
|
|
32886
|
+
const profilePhoto = f2.photoBase64 || f2.bodyImage || active?.photoBase64 || active?.photoUrl;
|
|
32887
|
+
const normalizedProfilePhoto = profilePhoto ? normalizeProfilePhotoSource(profilePhoto) : null;
|
|
32719
32888
|
const customMeasurements = {};
|
|
32720
32889
|
const wristCircumference = positiveNumber(f2.wristCircumference);
|
|
32721
32890
|
if (wristCircumference != null) customMeasurements.wristCircumference = wristCircumference;
|
|
@@ -32737,33 +32906,36 @@ function PrimeStyleTryonInner({
|
|
|
32737
32906
|
bandSize: f2.bandSize || active?.bandSize,
|
|
32738
32907
|
cupSize: f2.cupSize || active?.cupSize,
|
|
32739
32908
|
braSizeRegion: f2.braSizeRegion || active?.braSizeRegion || "US",
|
|
32909
|
+
...normalizedProfilePhoto ? { photoBase64: normalizedProfilePhoto } : {},
|
|
32740
32910
|
...Object.keys(customMeasurements).length > 0 ? { customMeasurements } : {}
|
|
32741
32911
|
};
|
|
32742
|
-
|
|
32912
|
+
if (profileSessionRef.current) lsRemove(PROFILE_COMPLETION_DRAFT_KEY);
|
|
32913
|
+
else lsSet(PROFILE_COMPLETION_DRAFT_KEY, draft);
|
|
32743
32914
|
setProfileCompletionDraft(draft);
|
|
32744
32915
|
setProfileAuthError(null);
|
|
32745
32916
|
setView("profiles");
|
|
32746
32917
|
}, [activeProfileId, effectiveProductId, heightUnit, productTitle, profiles, sizingUnit, weightUnit]);
|
|
32747
|
-
const applyProfileStore = reactExports.useCallback((nextProfiles, nextActiveProfileId) => {
|
|
32748
|
-
saveProfiles(nextProfiles);
|
|
32918
|
+
const applyProfileStore = reactExports.useCallback((nextProfiles, nextActiveProfileId, persistLocal = !profileSessionRef.current) => {
|
|
32919
|
+
if (persistLocal) saveProfiles(nextProfiles);
|
|
32749
32920
|
setProfiles(nextProfiles);
|
|
32750
|
-
|
|
32921
|
+
setActiveProfileIdState(nextActiveProfileId);
|
|
32922
|
+
if (persistLocal) setActiveProfileId(nextActiveProfileId);
|
|
32751
32923
|
profileSyncSnapshotRef.current = JSON.stringify({ profiles: nextProfiles, activeProfileId: nextActiveProfileId });
|
|
32752
|
-
}, [
|
|
32924
|
+
}, []);
|
|
32753
32925
|
const hydrateProfileStore = reactExports.useCallback(async (session, seedProfiles, seedActiveProfileId) => {
|
|
32754
32926
|
profileSyncHydratingRef.current = true;
|
|
32755
32927
|
try {
|
|
32756
32928
|
const remoteStore = await fetchRemoteProfiles(apiUrl, session.accessToken);
|
|
32757
32929
|
if (remoteStore.profiles.length > 0) {
|
|
32758
|
-
applyProfileStore(remoteStore.profiles, remoteStore.activeProfileId);
|
|
32930
|
+
applyProfileStore(remoteStore.profiles, remoteStore.activeProfileId, false);
|
|
32759
32931
|
return;
|
|
32760
32932
|
}
|
|
32761
32933
|
if (seedProfiles.length > 0) {
|
|
32762
32934
|
const savedStore = await saveRemoteProfiles(apiUrl, session.accessToken, seedProfiles, seedActiveProfileId);
|
|
32763
|
-
applyProfileStore(savedStore.profiles, savedStore.activeProfileId);
|
|
32935
|
+
applyProfileStore(savedStore.profiles, savedStore.activeProfileId, false);
|
|
32764
32936
|
return;
|
|
32765
32937
|
}
|
|
32766
|
-
applyProfileStore([], null);
|
|
32938
|
+
applyProfileStore([], null, false);
|
|
32767
32939
|
} finally {
|
|
32768
32940
|
profileSyncHydratingRef.current = false;
|
|
32769
32941
|
}
|
|
@@ -32774,6 +32946,7 @@ function PrimeStyleTryonInner({
|
|
|
32774
32946
|
try {
|
|
32775
32947
|
const session = await startSocialProfileLogin(provider, apiUrl);
|
|
32776
32948
|
setStoredProfileSession(session);
|
|
32949
|
+
profileSessionRef.current = session;
|
|
32777
32950
|
setProfileSession(session);
|
|
32778
32951
|
await hydrateProfileStore(session, profiles, activeProfileId);
|
|
32779
32952
|
} catch (error) {
|
|
@@ -32784,10 +32957,28 @@ function PrimeStyleTryonInner({
|
|
|
32784
32957
|
}, [activeProfileId, apiUrl, hydrateProfileStore, profiles, t2]);
|
|
32785
32958
|
const handleProfileLogout = reactExports.useCallback(() => {
|
|
32786
32959
|
clearStoredProfileSession();
|
|
32960
|
+
clearProfileLocalStorage();
|
|
32961
|
+
suppressNextProfilePersistRef.current = true;
|
|
32962
|
+
profileSessionRef.current = null;
|
|
32787
32963
|
setProfileSession(null);
|
|
32964
|
+
setProfiles([]);
|
|
32965
|
+
setActiveProfileIdState(null);
|
|
32966
|
+
setProfileCompletionDraft(null);
|
|
32967
|
+
setProfileSaved(false);
|
|
32968
|
+
setProfileDetail(null);
|
|
32969
|
+
formRef.current = {};
|
|
32970
|
+
setFormKey((k2) => k2 + 1);
|
|
32971
|
+
if (previewUrl) URL.revokeObjectURL(previewUrl);
|
|
32972
|
+
setSelectedFile(null);
|
|
32973
|
+
selectedFileRef.current = null;
|
|
32974
|
+
setPreviewUrl(null);
|
|
32975
|
+
setBodyLandmarks(null);
|
|
32976
|
+
setFaceLandmarks(null);
|
|
32977
|
+
setEstimatedValues(null);
|
|
32978
|
+
setEstimatingProfileIds(/* @__PURE__ */ new Set());
|
|
32788
32979
|
setProfileAuthError(null);
|
|
32789
32980
|
setProfileAuthLoadingProvider(null);
|
|
32790
|
-
}, []);
|
|
32981
|
+
}, [previewUrl]);
|
|
32791
32982
|
const fileInputRef = reactExports.useRef(null);
|
|
32792
32983
|
const apiRef = reactExports.useRef(null);
|
|
32793
32984
|
const sseRef = reactExports.useRef(null);
|
|
@@ -33070,6 +33261,11 @@ function PrimeStyleTryonInner({
|
|
|
33070
33261
|
};
|
|
33071
33262
|
}, [history]);
|
|
33072
33263
|
reactExports.useEffect(() => {
|
|
33264
|
+
if (suppressNextProfilePersistRef.current) {
|
|
33265
|
+
suppressNextProfilePersistRef.current = false;
|
|
33266
|
+
return;
|
|
33267
|
+
}
|
|
33268
|
+
if (profileSessionRef.current) return;
|
|
33073
33269
|
lsSet("profiles", profiles);
|
|
33074
33270
|
}, [profiles]);
|
|
33075
33271
|
reactExports.useEffect(() => {
|
|
@@ -33098,7 +33294,10 @@ function PrimeStyleTryonInner({
|
|
|
33098
33294
|
};
|
|
33099
33295
|
}, [activeProfileId, apiUrl, applyProfileStore, profileSession, profiles, t2]);
|
|
33100
33296
|
reactExports.useEffect(() => {
|
|
33101
|
-
const handler = () =>
|
|
33297
|
+
const handler = () => {
|
|
33298
|
+
if (profileSessionRef.current) return;
|
|
33299
|
+
setProfiles(lsGet("profiles", []));
|
|
33300
|
+
};
|
|
33102
33301
|
window.addEventListener(PS_STORAGE_CHANGE_EVENT, handler);
|
|
33103
33302
|
return () => window.removeEventListener(PS_STORAGE_CHANGE_EVENT, handler);
|
|
33104
33303
|
}, []);
|
|
@@ -33146,6 +33345,14 @@ function PrimeStyleTryonInner({
|
|
|
33146
33345
|
return 1;
|
|
33147
33346
|
}
|
|
33148
33347
|
}, [view]);
|
|
33348
|
+
const updateProfilesForCurrentSession = reactExports.useCallback((updater) => {
|
|
33349
|
+
setProfiles((prev) => {
|
|
33350
|
+
const source = profileSessionRef.current ? prev : lsGet("profiles", prev);
|
|
33351
|
+
const next = updater(source);
|
|
33352
|
+
if (!profileSessionRef.current) saveProfiles(next);
|
|
33353
|
+
return next;
|
|
33354
|
+
});
|
|
33355
|
+
}, []);
|
|
33149
33356
|
const persistResultToProfile = reactExports.useCallback(
|
|
33150
33357
|
(formData, recommendation, options) => {
|
|
33151
33358
|
let targetId = activeProfileId;
|
|
@@ -33155,27 +33362,63 @@ function PrimeStyleTryonInner({
|
|
|
33155
33362
|
return;
|
|
33156
33363
|
}
|
|
33157
33364
|
if (targetId && formData.gender === "female" && (formData.bandSize || formData.cupSize || formData.braSizeRegion)) {
|
|
33158
|
-
|
|
33365
|
+
const patch = {
|
|
33159
33366
|
...formData.bandSize ? { bandSize: formData.bandSize } : {},
|
|
33160
33367
|
...formData.cupSize ? { cupSize: formData.cupSize } : {},
|
|
33161
33368
|
...formData.braSizeRegion ? { braSizeRegion: formData.braSizeRegion } : {}
|
|
33162
|
-
}
|
|
33163
|
-
|
|
33369
|
+
};
|
|
33370
|
+
if (profileSessionRef.current) {
|
|
33371
|
+
updateProfilesForCurrentSession((list) => list.map((p2) => p2.id === targetId ? { ...p2, ...patch, lastEditedAt: Date.now() } : p2));
|
|
33372
|
+
} else {
|
|
33373
|
+
updateProfile(targetId, patch);
|
|
33374
|
+
setProfiles(lsGet("profiles", []));
|
|
33375
|
+
}
|
|
33164
33376
|
}
|
|
33377
|
+
const persistMeasurements = (est, unit) => {
|
|
33378
|
+
if (!targetId) return;
|
|
33379
|
+
if (profileSessionRef.current) {
|
|
33380
|
+
updateProfilesForCurrentSession((list) => list.map((p2) => p2.id === targetId ? {
|
|
33381
|
+
...p2,
|
|
33382
|
+
measurements: est,
|
|
33383
|
+
measurementsUnit: unit,
|
|
33384
|
+
lastEditedAt: Date.now()
|
|
33385
|
+
} : p2));
|
|
33386
|
+
} else {
|
|
33387
|
+
updateProfileMeasurements(targetId, est, unit);
|
|
33388
|
+
setProfiles(lsGet("profiles", []));
|
|
33389
|
+
}
|
|
33390
|
+
};
|
|
33391
|
+
const persistSizeHistory = (entry) => {
|
|
33392
|
+
if (!targetId) return;
|
|
33393
|
+
if (profileSessionRef.current) {
|
|
33394
|
+
updateProfilesForCurrentSession((list) => list.map((p2) => {
|
|
33395
|
+
if (p2.id !== targetId) return p2;
|
|
33396
|
+
const sizeHistory = (p2.sizeHistory || []).filter((h) => h.productId !== entry.productId);
|
|
33397
|
+
sizeHistory.unshift(entry);
|
|
33398
|
+
return {
|
|
33399
|
+
...p2,
|
|
33400
|
+
sizeHistory: sizeHistory.slice(0, 50),
|
|
33401
|
+
lastUsedAt: Date.now()
|
|
33402
|
+
};
|
|
33403
|
+
}));
|
|
33404
|
+
} else {
|
|
33405
|
+
addSizeToHistory(targetId, entry);
|
|
33406
|
+
setProfiles(lsGet("profiles", []));
|
|
33407
|
+
}
|
|
33408
|
+
};
|
|
33165
33409
|
if (options?.skipBodyEstimate) {
|
|
33166
33410
|
console.log("[ps-sdk:persist] skipping body estimates — face/head flow (no body context)");
|
|
33167
33411
|
} else if (targetId && recommendation?.estimates) {
|
|
33168
33412
|
const est = recommendation.estimates;
|
|
33169
33413
|
const unit = recommendation.estimatesUnit || "cm";
|
|
33170
|
-
|
|
33171
|
-
setProfiles(lsGet("profiles", []));
|
|
33414
|
+
persistMeasurements(est, unit);
|
|
33172
33415
|
}
|
|
33173
33416
|
setEstimationDone(true);
|
|
33174
33417
|
if (recommendation?.recommendedSize && targetId) {
|
|
33175
33418
|
const sectionsMap = recommendation.sections ? Object.fromEntries(
|
|
33176
33419
|
Object.entries(recommendation.sections).map(([name, sec]) => [name, sec.recommendedSize])
|
|
33177
33420
|
) : void 0;
|
|
33178
|
-
|
|
33421
|
+
persistSizeHistory({
|
|
33179
33422
|
productId: effectiveProductId,
|
|
33180
33423
|
productTitle,
|
|
33181
33424
|
productImage,
|
|
@@ -33184,10 +33427,9 @@ function PrimeStyleTryonInner({
|
|
|
33184
33427
|
sections: sectionsMap,
|
|
33185
33428
|
savedAt: Date.now()
|
|
33186
33429
|
});
|
|
33187
|
-
setProfiles(lsGet("profiles", []));
|
|
33188
33430
|
}
|
|
33189
33431
|
},
|
|
33190
|
-
[activeProfileId, profiles, productImage, productTitle, effectiveProductId]
|
|
33432
|
+
[activeProfileId, profiles, productImage, productTitle, effectiveProductId, updateProfilesForCurrentSession]
|
|
33191
33433
|
);
|
|
33192
33434
|
const snapSubmitRef = reactExports.useRef(null);
|
|
33193
33435
|
const [confirmProfile, setConfirmProfile] = reactExports.useState(null);
|
|
@@ -33196,7 +33438,7 @@ function PrimeStyleTryonInner({
|
|
|
33196
33438
|
const profileWeight = p2.weight ?? p2.weightKg ?? 0;
|
|
33197
33439
|
const hasStored = !!p2.measurements && Object.keys(p2.measurements).length > 0;
|
|
33198
33440
|
const storedPhoto = p2.photoUrl || p2.photoBase64;
|
|
33199
|
-
if (
|
|
33441
|
+
if (storedPhoto && profileHeight > 0 && snapSubmitRef.current) {
|
|
33200
33442
|
try {
|
|
33201
33443
|
const dataUrl = await profilePhotoToDataUrl(storedPhoto);
|
|
33202
33444
|
const blob = await fetch(dataUrl).then((r2) => r2.blob());
|
|
@@ -33210,6 +33452,7 @@ function PrimeStyleTryonInner({
|
|
|
33210
33452
|
weightUnit: p2.weightUnit || "kg",
|
|
33211
33453
|
gender: p2.gender,
|
|
33212
33454
|
age: p2.age,
|
|
33455
|
+
...hasStored && p2.measurements ? { knownMeasurements: p2.measurements } : {},
|
|
33213
33456
|
...snapBraFields({
|
|
33214
33457
|
gender: p2.gender,
|
|
33215
33458
|
bandSize: p2.bandSize,
|
|
@@ -33253,6 +33496,7 @@ function PrimeStyleTryonInner({
|
|
|
33253
33496
|
}
|
|
33254
33497
|
}
|
|
33255
33498
|
setView("size-result");
|
|
33499
|
+
const minVisible = new Promise((resolve) => setTimeout(resolve, 6e3));
|
|
33256
33500
|
recommendForProduct({
|
|
33257
33501
|
productId: effectiveProductId,
|
|
33258
33502
|
productTitle,
|
|
@@ -33271,7 +33515,9 @@ function PrimeStyleTryonInner({
|
|
|
33271
33515
|
if (res?.raw) setSizingResult(res.raw);
|
|
33272
33516
|
setEstimationDone(true);
|
|
33273
33517
|
}).catch(() => {
|
|
33274
|
-
}).finally(() =>
|
|
33518
|
+
}).finally(() => {
|
|
33519
|
+
void minVisible.then(() => setSizingLoading(false));
|
|
33520
|
+
});
|
|
33275
33521
|
}, [effectiveProductId, productTitle, productImage, productCategory, productSubcategory, resolvedProductFitType, productType, productTagsList, productDescription, sizeGuideData, apiUrl, previewUrl]);
|
|
33276
33522
|
const handleUseActiveProfile = reactExports.useCallback(async () => {
|
|
33277
33523
|
const p2 = profiles.find((x2) => x2.id === activeProfileId);
|
|
@@ -33493,6 +33739,8 @@ function PrimeStyleTryonInner({
|
|
|
33493
33739
|
}, [sizeGuide, formGender]);
|
|
33494
33740
|
const submitSizing = reactExports.useCallback(async (methodOverride) => {
|
|
33495
33741
|
if (!apiRef.current) return;
|
|
33742
|
+
setActiveSection(null);
|
|
33743
|
+
noFitFoundRef.current = false;
|
|
33496
33744
|
const method = methodOverride || sizingMethod;
|
|
33497
33745
|
const baseUrl = getApiUrl(apiUrl);
|
|
33498
33746
|
const key = getApiKey();
|
|
@@ -33553,6 +33801,12 @@ function PrimeStyleTryonInner({
|
|
|
33553
33801
|
if (resp.ok) {
|
|
33554
33802
|
const data = await resp.json();
|
|
33555
33803
|
await minVisible;
|
|
33804
|
+
if (data?.found === false) {
|
|
33805
|
+
setNoSizeReason(data?.reasoning === "NO_SIZE_CHART" ? "no-chart" : "no-match");
|
|
33806
|
+
setView("no-chart");
|
|
33807
|
+
setEstimationDone(true);
|
|
33808
|
+
return;
|
|
33809
|
+
}
|
|
33556
33810
|
setSizingResult(data);
|
|
33557
33811
|
onComplete?.(data);
|
|
33558
33812
|
} else {
|
|
@@ -33614,6 +33868,10 @@ function PrimeStyleTryonInner({
|
|
|
33614
33868
|
if (formRef.current.shoeUS) m2.shoeUS = formRef.current.shoeUS;
|
|
33615
33869
|
if (formRef.current.shoeUK) m2.shoeUK = formRef.current.shoeUK;
|
|
33616
33870
|
if (formRef.current.fitPreference) m2.fitPreference = formRef.current.fitPreference;
|
|
33871
|
+
if (formRef.current.bodyType) m2.bodyType = formRef.current.bodyType;
|
|
33872
|
+
if (formRef.current.chestProfile) m2.chestProfile = formRef.current.chestProfile;
|
|
33873
|
+
if (formRef.current.midsectionProfile) m2.midsectionProfile = formRef.current.midsectionProfile;
|
|
33874
|
+
if (formRef.current.hipProfile) m2.hipProfile = formRef.current.hipProfile;
|
|
33617
33875
|
payload.measurements = m2;
|
|
33618
33876
|
console.log("[PS-SDK] FINAL measurements:", JSON.stringify(m2));
|
|
33619
33877
|
} else {
|
|
@@ -33652,7 +33910,8 @@ function PrimeStyleTryonInner({
|
|
|
33652
33910
|
if (res.ok) {
|
|
33653
33911
|
const data = await res.json();
|
|
33654
33912
|
console.log("[PS-SDK] Sizing recommend RESULT:", JSON.stringify(data));
|
|
33655
|
-
if (data?.found === false
|
|
33913
|
+
if (data?.found === false) {
|
|
33914
|
+
setNoSizeReason(data?.reasoning === "NO_SIZE_CHART" ? "no-chart" : "no-match");
|
|
33656
33915
|
setView("no-chart");
|
|
33657
33916
|
setEstimationDone(true);
|
|
33658
33917
|
return;
|
|
@@ -33741,6 +34000,7 @@ function PrimeStyleTryonInner({
|
|
|
33741
34000
|
setFaceLandmarks(null);
|
|
33742
34001
|
setSizingMethod("quick");
|
|
33743
34002
|
setSizingLoading(true);
|
|
34003
|
+
setActiveSection(null);
|
|
33744
34004
|
setView("size-result");
|
|
33745
34005
|
submitSizing("quick");
|
|
33746
34006
|
return;
|
|
@@ -33759,6 +34019,7 @@ function PrimeStyleTryonInner({
|
|
|
33759
34019
|
setResultImageUrl(null);
|
|
33760
34020
|
currentHistoryEntryIdRef.current = null;
|
|
33761
34021
|
currentTryOnJobIdRef.current = null;
|
|
34022
|
+
setActiveSection(null);
|
|
33762
34023
|
setRestoredProductImage(null);
|
|
33763
34024
|
setRestoredProductImages(null);
|
|
33764
34025
|
setRestoredProductCarouselItems(null);
|
|
@@ -33810,6 +34071,8 @@ function PrimeStyleTryonInner({
|
|
|
33810
34071
|
formRef.current.weightUnit = data.weightUnit;
|
|
33811
34072
|
formRef.current.gender = data.gender;
|
|
33812
34073
|
if (data.age != null) formRef.current.age = String(data.age);
|
|
34074
|
+
formRef.current.bodyImage = data.photoBase64;
|
|
34075
|
+
formRef.current.photoBase64 = data.photoBase64;
|
|
33813
34076
|
const braFields = snapBraFields(data);
|
|
33814
34077
|
if (braFields.bandSize) formRef.current.bandSize = braFields.bandSize;
|
|
33815
34078
|
if (braFields.cupSize) formRef.current.cupSize = braFields.cupSize;
|
|
@@ -33834,6 +34097,7 @@ function PrimeStyleTryonInner({
|
|
|
33834
34097
|
historyTryonSavedRef.current = false;
|
|
33835
34098
|
currentHistoryEntryIdRef.current = null;
|
|
33836
34099
|
currentTryOnJobIdRef.current = null;
|
|
34100
|
+
setActiveSection(null);
|
|
33837
34101
|
setSizingLoading(true);
|
|
33838
34102
|
setEstimationDone(false);
|
|
33839
34103
|
setView("size-result");
|
|
@@ -33880,6 +34144,14 @@ function PrimeStyleTryonInner({
|
|
|
33880
34144
|
});
|
|
33881
34145
|
if (recRes.ok) {
|
|
33882
34146
|
const recData = await recRes.json();
|
|
34147
|
+
if (recData?.found === false) {
|
|
34148
|
+
await minVisible2;
|
|
34149
|
+
setNoSizeReason(recData?.reasoning === "NO_SIZE_CHART" ? "no-chart" : "no-match");
|
|
34150
|
+
setView("no-chart");
|
|
34151
|
+
setEstimationDone(true);
|
|
34152
|
+
setSizingLoading(false);
|
|
34153
|
+
return;
|
|
34154
|
+
}
|
|
33883
34155
|
setSizingResult(recData);
|
|
33884
34156
|
onComplete?.(recData);
|
|
33885
34157
|
persistResultToProfile(
|
|
@@ -33999,6 +34271,7 @@ function PrimeStyleTryonInner({
|
|
|
33999
34271
|
if (recRes.ok) {
|
|
34000
34272
|
const recData = await recRes.json();
|
|
34001
34273
|
if (recData?.found === false && recData?.reasoning === "NO_SIZE_CHART") {
|
|
34274
|
+
setNoSizeReason("no-chart");
|
|
34002
34275
|
setView("no-chart");
|
|
34003
34276
|
setEstimationDone(true);
|
|
34004
34277
|
setSizingLoading(false);
|
|
@@ -34012,8 +34285,13 @@ function PrimeStyleTryonInner({
|
|
|
34012
34285
|
noFitFoundRef.current = true;
|
|
34013
34286
|
setTryOnProcessing(false);
|
|
34014
34287
|
setTryOnStartedAt(null);
|
|
34288
|
+
setNoSizeReason("no-match");
|
|
34015
34289
|
setSizingResult({ ...recData, found: false });
|
|
34016
34290
|
onComplete?.({ ...recData, found: false });
|
|
34291
|
+
setView("no-chart");
|
|
34292
|
+
setEstimationDone(true);
|
|
34293
|
+
setSizingLoading(false);
|
|
34294
|
+
return;
|
|
34017
34295
|
} else {
|
|
34018
34296
|
setSizingResult(recData);
|
|
34019
34297
|
onComplete?.(recData);
|
|
@@ -34174,6 +34452,8 @@ function PrimeStyleTryonInner({
|
|
|
34174
34452
|
{
|
|
34175
34453
|
productId: effectiveProductId,
|
|
34176
34454
|
productTitle,
|
|
34455
|
+
productCategory,
|
|
34456
|
+
productSubcategory,
|
|
34177
34457
|
productFitType: resolvedProductFitType,
|
|
34178
34458
|
productType,
|
|
34179
34459
|
productTags: productTagsList,
|
|
@@ -34242,7 +34522,7 @@ function PrimeStyleTryonInner({
|
|
|
34242
34522
|
setView("error");
|
|
34243
34523
|
onError?.({ message, code });
|
|
34244
34524
|
}
|
|
34245
|
-
}, [selectedFile, productImage, effectiveProductImages, garmentReferenceImage, productTitle, resolvedProductFitType, productType, productTagsList, productDescription, productMaterial, measurementType, sizingResult, sizeGuide, apiUrl, onProcessing, onError, handleVtoUpdate]);
|
|
34525
|
+
}, [selectedFile, productImage, effectiveProductImages, garmentReferenceImage, productTitle, productCategory, productSubcategory, resolvedProductFitType, productType, productTagsList, productDescription, productMaterial, measurementType, sizingResult, sizeGuide, apiUrl, onProcessing, onError, handleVtoUpdate]);
|
|
34246
34526
|
reactExports.useEffect(() => {
|
|
34247
34527
|
if (view !== "size-result") {
|
|
34248
34528
|
autoTryOnFiredRef.current = false;
|
|
@@ -34989,12 +35269,31 @@ function PrimeStyleTryonInner({
|
|
|
34989
35269
|
setView("body-profile");
|
|
34990
35270
|
},
|
|
34991
35271
|
onSaveProfileMeasurements: (id2, measurements, unit) => {
|
|
34992
|
-
|
|
34993
|
-
|
|
35272
|
+
const nextUnit = unit ?? profiles.find((x2) => x2.id === id2)?.measurementsUnit ?? "cm";
|
|
35273
|
+
if (profileSessionRef.current) {
|
|
35274
|
+
updateProfilesForCurrentSession((list) => list.map((p2) => p2.id === id2 ? {
|
|
35275
|
+
...p2,
|
|
35276
|
+
measurements,
|
|
35277
|
+
measurementsUnit: nextUnit,
|
|
35278
|
+
lastEditedAt: Date.now()
|
|
35279
|
+
} : p2));
|
|
35280
|
+
} else {
|
|
35281
|
+
updateProfileMeasurements(id2, measurements, nextUnit);
|
|
35282
|
+
setProfiles(lsGet("profiles", []));
|
|
35283
|
+
}
|
|
34994
35284
|
},
|
|
34995
35285
|
onSaveBraSize: (id2, bandSize, cupSize) => {
|
|
34996
|
-
|
|
34997
|
-
|
|
35286
|
+
if (profileSessionRef.current) {
|
|
35287
|
+
updateProfilesForCurrentSession((list) => list.map((p2) => p2.id === id2 ? {
|
|
35288
|
+
...p2,
|
|
35289
|
+
bandSize,
|
|
35290
|
+
cupSize,
|
|
35291
|
+
lastEditedAt: Date.now()
|
|
35292
|
+
} : p2));
|
|
35293
|
+
} else {
|
|
35294
|
+
updateProfile(id2, { bandSize, cupSize });
|
|
35295
|
+
setProfiles(lsGet("profiles", []));
|
|
35296
|
+
}
|
|
34998
35297
|
},
|
|
34999
35298
|
onEditProfile: (p2) => {
|
|
35000
35299
|
setProfileDetail(p2);
|
|
@@ -35067,13 +35366,24 @@ function PrimeStyleTryonInner({
|
|
|
35067
35366
|
bodyLandmarks: landmarks ?? void 0
|
|
35068
35367
|
})).then((est) => {
|
|
35069
35368
|
if (est) {
|
|
35070
|
-
|
|
35369
|
+
if (profileSessionRef.current) {
|
|
35370
|
+
updateProfilesForCurrentSession((list) => list.map((p2) => p2.id === newProfile.id ? {
|
|
35371
|
+
...p2,
|
|
35372
|
+
measurements: est.estimates,
|
|
35373
|
+
measurementsUnit: est.unit,
|
|
35374
|
+
lastEditedAt: Date.now()
|
|
35375
|
+
} : p2));
|
|
35376
|
+
} else {
|
|
35377
|
+
updateProfileMeasurements(newProfile.id, est.estimates, est.unit);
|
|
35378
|
+
}
|
|
35071
35379
|
if (est.userEstimates) {
|
|
35072
|
-
const
|
|
35073
|
-
|
|
35074
|
-
|
|
35380
|
+
const userEstimates = est.userEstimates;
|
|
35381
|
+
updateProfilesForCurrentSession((list) => {
|
|
35382
|
+
const idx = list.findIndex((p2) => p2.id === newProfile.id);
|
|
35383
|
+
if (idx < 0) return list;
|
|
35384
|
+
const all = [...list];
|
|
35075
35385
|
const target = all[idx];
|
|
35076
|
-
const u2 =
|
|
35386
|
+
const u2 = userEstimates;
|
|
35077
35387
|
const patched = { ...target };
|
|
35078
35388
|
if (u2.height && !(target.height || target.heightCm)) {
|
|
35079
35389
|
patched.height = u2.height;
|
|
@@ -35089,10 +35399,10 @@ function PrimeStyleTryonInner({
|
|
|
35089
35399
|
patched.age = u2.age;
|
|
35090
35400
|
}
|
|
35091
35401
|
all[idx] = patched;
|
|
35092
|
-
|
|
35093
|
-
}
|
|
35402
|
+
return all;
|
|
35403
|
+
});
|
|
35094
35404
|
}
|
|
35095
|
-
setProfiles(lsGet("profiles", []));
|
|
35405
|
+
if (!profileSessionRef.current) setProfiles(lsGet("profiles", []));
|
|
35096
35406
|
}
|
|
35097
35407
|
}).catch(() => {
|
|
35098
35408
|
}).finally(() => {
|
|
@@ -35105,9 +35415,8 @@ function PrimeStyleTryonInner({
|
|
|
35105
35415
|
}
|
|
35106
35416
|
},
|
|
35107
35417
|
onDeleteProfile: (id2) => {
|
|
35108
|
-
|
|
35418
|
+
updateProfilesForCurrentSession((prev) => prev.filter((p2) => p2.id !== id2));
|
|
35109
35419
|
if (activeProfileId === id2) setActiveProfileId$1(null);
|
|
35110
|
-
lsSet("profiles", lsGet("profiles", []).filter((p2) => p2.id !== id2));
|
|
35111
35420
|
},
|
|
35112
35421
|
onRequestDelete: (id2) => setDeleteConfirmId(id2),
|
|
35113
35422
|
onLogout: handleProfileLogout,
|
|
@@ -35141,6 +35450,7 @@ function PrimeStyleTryonInner({
|
|
|
35141
35450
|
{
|
|
35142
35451
|
productImage,
|
|
35143
35452
|
productTitle,
|
|
35453
|
+
reason: noSizeReason,
|
|
35144
35454
|
onTryOn: () => setView("photo-guide"),
|
|
35145
35455
|
onClose: onClose ?? (() => {
|
|
35146
35456
|
}),
|
|
@@ -35367,9 +35677,7 @@ function PrimeStyleTryonInner({
|
|
|
35367
35677
|
{
|
|
35368
35678
|
onConfirm: () => {
|
|
35369
35679
|
const id2 = deleteConfirmId;
|
|
35370
|
-
|
|
35371
|
-
lsSet("profiles", updated);
|
|
35372
|
-
setProfiles(updated);
|
|
35680
|
+
updateProfilesForCurrentSession((prev) => prev.filter((p2) => p2.id !== id2));
|
|
35373
35681
|
if (activeProfileId === id2) setActiveProfileId$1(null);
|
|
35374
35682
|
setDeleteConfirmId(null);
|
|
35375
35683
|
},
|