@primestyleai/tryon 5.10.187 → 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.
@@ -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
- "Get the perfect fit, then try it on virtually": "Encuentra el ajuste perfecto y pruébatelo virtualmente",
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
- "perfect fit": "ajuste perfecto",
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
- "Get the perfect fit, then try it on virtually": "Trouvez la coupe parfaite, puis essayez-le virtuellement",
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
- "perfect fit": "coupe parfaite",
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
- "Get the perfect fit, then try it on virtually": "Finden Sie die perfekte Passform und probieren Sie es virtuell an",
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
- "perfect fit": "perfekte Passform",
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
- "Get the perfect fit, then try it on virtually": "Trova la vestibilità perfetta, poi provalo virtualmente",
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
- "perfect fit": "vestibilità perfetta",
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
- "Get the perfect fit, then try it on virtually": "Encontre o caimento perfeito e experimente virtualmente",
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
- "perfect fit": "caimento perfeito",
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
- "Get the perfect fit, then try it on virtually": "最適なフィットを見つけて、バーチャルで試着しましょう",
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
- "perfect fit": "ぴったり",
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
- "Get the perfect fit, then try it on virtually": "找到最佳合身度,然后虚拟试穿",
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
- "perfect fit": "完美合身",
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
- "Get the perfect fit, then try it on virtually": "완벽한 핏을 찾고 가상으로 입어보세요",
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
- "perfect fit": "완벽한 ",
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
- "Get the perfect fit, then try it on virtually": "اعثر على المقاس المثالي ثم جرّبه افتراضياً",
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
- "perfect fit": "مقاس مثالي",
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 || "").toString().trim();
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 ?? "").toString().trim();
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 profile = input.profile ?? getActiveProfile();
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 active profile — returning null");
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
- addSizeToHistory(profile.id, {
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
- /* Minimal "Using <profile> · start fresh" hint above the first input */
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-top: clamp(8px, 0.7vw, 14px);
20143
- padding-bottom: clamp(8px, 0.7vw, 14px);
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(10px, 0.9vw, 20px);
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(12px, 1vw, 22px);
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("Get the perfect fit, then try it on virtually") })
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 to calculate the perfect fit."), viewfinderText: t2("SCANNING FRAME") },
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("perfect fit") : 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");
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("perfect fit");
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 Perfect Fit") }),
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 Perfect Fit") }),
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 the perfect fit"),
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,7 +26486,7 @@ 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";
@@ -26383,6 +26521,7 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
26383
26521
  const [scanStageIdx, setScanStageIdx] = reactExports.useState(0);
26384
26522
  const [photoHelpOpen, setPhotoHelpOpen] = reactExports.useState(false);
26385
26523
  const [uploadHoverCpw, setUploadHoverCpw] = reactExports.useState(false);
26524
+ const directAutoStartedRef = reactExports.useRef(false);
26386
26525
  reactExports.useEffect(() => {
26387
26526
  if (imageStep !== "calculating" || !photoBase64) return;
26388
26527
  let cancelled = false;
@@ -26681,7 +26820,7 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
26681
26820
  return;
26682
26821
  }
26683
26822
  const a = parseFloat(ageVal);
26684
- if (isWomen && (!bandSize || !cupSize)) {
26823
+ if (isWomen && !directAnalysisFlow && (!bandSize || !cupSize)) {
26685
26824
  setError(t2("Please select your bra band and cup size"));
26686
26825
  return;
26687
26826
  }
@@ -26731,6 +26870,15 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
26731
26870
  }
26732
26871
  onSave(payload);
26733
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]);
26734
26882
  const goBackImage = () => {
26735
26883
  setError("");
26736
26884
  if (imageStep === "details") {
@@ -26772,9 +26920,12 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
26772
26920
  if (photoBase64) pct += 50;
26773
26921
  return pct;
26774
26922
  })();
26775
- const hideGlobalBack = mode === "image" && imageStep === "name-photo";
26776
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `ps-cpw-root${hideGlobalBack ? " ps-cpw-hide-global-back" : ""}`, children: [
26777
- !(mode === "image" && imageStep === "name-photo") && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-step-head", children: [
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: [
26778
26929
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-cpw-step-title", children: headerLabel }),
26779
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}%` } }) }) })
26780
26931
  ] }),
@@ -27702,7 +27853,7 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
27702
27853
  mode === "image" && imageStep === "calculating" && (() => {
27703
27854
  const stages = [
27704
27855
  { title: t2("DETECTING POSE"), desc: t2("Identifying body landmarks from your photo.") },
27705
- { title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions to calculate the perfect fit.") },
27856
+ { title: t2("SCANNING FRAME"), desc: t2("Our AI is mapping your proportions for a size recommendation.") },
27706
27857
  { title: t2("ANALYZING BODY"), desc: t2("Measuring shoulders, chest, waist and hips.") },
27707
27858
  { title: t2("MATCHING SIZE"), desc: t2("Comparing your measurements to the size guide.") },
27708
27859
  { title: t2("FINALIZING RESULT"), desc: t2("Almost done — preparing your recommendation.") }
@@ -27790,13 +27941,13 @@ function CreateProfileWizard({ onSave, onCancel, initialMode, initialDraft, apiU
27790
27941
  ] }) }, "image-calculating");
27791
27942
  })()
27792
27943
  ] }),
27793
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-cpw-footer", children: [
27794
- /* @__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")}` }),
27795
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") }),
27796
27947
  mode === "image" && imageStep === "name-photo" && (() => {
27797
27948
  const heightOk = unit === "in" ? parseFloat(heightFt) > 0 || parseFloat(heightInch) > 0 : parseFloat(heightVal) > 0;
27798
27949
  const weightOk = parseFloat(weightVal) > 0;
27799
- const braOk = !isWomen || !!bandSize && !!cupSize;
27950
+ const braOk = !isWomen || directAnalysisFlow || !!bandSize && !!cupSize;
27800
27951
  const nameOk = !!name.trim();
27801
27952
  const photoOk = !!photoBase64;
27802
27953
  const analyzing = photoUploading;
@@ -28252,6 +28403,7 @@ function MySizingProfilesView({
28252
28403
  apiKey,
28253
28404
  initialMode: initialCreateDraft ? "image" : void 0,
28254
28405
  initialDraft: initialCreateDraft,
28406
+ directAnalysisFlow: !!initialCreateDraft,
28255
28407
  onSave: (data) => {
28256
28408
  onSaveNewProfile(data);
28257
28409
  onProfileDraftConsumed?.();
@@ -28488,14 +28640,13 @@ function BasicsStepMobile({
28488
28640
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-bpm-title", children: t2("Body Measurements") }),
28489
28641
  /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ps-bpm-subtitle", children: t2("Enter your details for a bespoke size recommendation") })
28490
28642
  ] }),
28491
- activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "ps-bp-profile-hint", children: [
28492
- t2("Using"),
28493
- " ",
28494
- /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: activeProfileName }),
28495
- onStartFresh && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
28496
- " · ",
28497
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-bp-profile-hint-link", onClick: onStartFresh, children: t2("start fresh") })
28498
- ] })
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") })
28499
28650
  ] }),
28500
28651
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bpm-toggle", children: [
28501
28652
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -29555,6 +29706,9 @@ function BodyProfileView({
29555
29706
  formRef.current.weight = String(weightVal);
29556
29707
  formRef.current.gender = gender;
29557
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;
29558
29712
  if (bandSize) formRef.current.bandSize = bandSize;
29559
29713
  if (cupSize) formRef.current.cupSize = cupSize;
29560
29714
  if (braSizeRegion) formRef.current.braSizeRegion = braSizeRegion;
@@ -29611,6 +29765,9 @@ function BodyProfileView({
29611
29765
  weightUnit: isShoeReferenceMode ? "kg" : wUnit,
29612
29766
  gender,
29613
29767
  ...ageForSubmit ? { age: ageForSubmit } : {},
29768
+ ...chestProfile ? { chestProfile } : {},
29769
+ ...midsectionProfile ? { midsectionProfile } : {},
29770
+ ...hipProfile ? { hipProfile } : {},
29614
29771
  ...currentShoeReference ? {
29615
29772
  extraMeasurements: {
29616
29773
  referenceShoeBrandId: currentShoeReference.brandId,
@@ -30508,14 +30665,13 @@ function BodyProfileView({
30508
30665
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: `ps-bp-system-btn${isImperialMode ? " ps-bp-system-active" : ""}`, onClick: photoSwitchToImperial, type: "button", children: t2("Imperial") })
30509
30666
  ] }),
30510
30667
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { marginTop: "auto", marginBottom: "auto" }, children: [
30511
- activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "ps-bp-profile-hint", style: { textAlign: "center", margin: "0 0 0.5vw" }, children: [
30512
- t2("Using"),
30513
- " ",
30514
- /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: activeProfileName }),
30515
- onStartFresh && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
30516
- " · ",
30517
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-bp-profile-hint-link", onClick: handleClearFromProfile, children: t2("start fresh") })
30518
- ] })
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") })
30519
30675
  ] }),
30520
30676
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-fields", children: [
30521
30677
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-inline-row", children: [
@@ -30817,14 +30973,13 @@ function BodyProfileView({
30817
30973
  }
30818
30974
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-step ps-bp-step-enter", children: [
30819
30975
  /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "ps-bp-title", children: basicOnly || simplePhotoOnly ? t2("Your Details") : t2("Body Measurements") }),
30820
- activeProfileName && /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "ps-bp-profile-hint", style: { textAlign: "center", margin: "0 0 0.5vw" }, children: [
30821
- t2("Using"),
30822
- " ",
30823
- /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: activeProfileName }),
30824
- onStartFresh && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
30825
- " · ",
30826
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "ps-bp-profile-hint-link", onClick: handleClearFromProfile, children: t2("start fresh") })
30827
- ] })
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") })
30828
30983
  ] }),
30829
30984
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ps-bp-system-toggle", children: [
30830
30985
  /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: `ps-bp-system-btn${!isImperialMode ? " ps-bp-system-active" : ""}`, onClick: switchToMetric, type: "button", children: t2("Metric") }),
@@ -32600,6 +32755,7 @@ function PrimeStyleTryonInner({
32600
32755
  setCssReady(true);
32601
32756
  }, []);
32602
32757
  const [view, setView] = reactExports.useState(initialView ?? "idle");
32758
+ const [noSizeReason, setNoSizeReason] = reactExports.useState("no-chart");
32603
32759
  const [selectedFile, setSelectedFile] = reactExports.useState(null);
32604
32760
  const [previewUrl, setPreviewUrl] = reactExports.useState(null);
32605
32761
  const [resultImageUrl, setResultImageUrl] = reactExports.useState(null);
@@ -32679,7 +32835,9 @@ function PrimeStyleTryonInner({
32679
32835
  const [estimationLoading, setEstimationLoading] = reactExports.useState(false);
32680
32836
  const [profiles, setProfiles] = reactExports.useState(() => lsGet("profiles", []));
32681
32837
  const [profileSession, setProfileSession] = reactExports.useState(() => getStoredProfileSession());
32682
- const [profileCompletionDraft, setProfileCompletionDraft] = reactExports.useState(() => lsGet(PROFILE_COMPLETION_DRAFT_KEY, null));
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));
32683
32841
  const [profileAuthError, setProfileAuthError] = reactExports.useState(null);
32684
32842
  const [profileAuthLoadingProvider, setProfileAuthLoadingProvider] = reactExports.useState(null);
32685
32843
  const [history, setHistory] = reactExports.useState(() => lsGet("history", []).map(normalizeHistoryEntry));
@@ -32698,8 +32856,11 @@ function PrimeStyleTryonInner({
32698
32856
  const [deleteConfirmId, setDeleteConfirmId] = reactExports.useState(null);
32699
32857
  const setActiveProfileId$1 = reactExports.useCallback((id2) => {
32700
32858
  setActiveProfileIdState(id2);
32701
- setActiveProfileId(id2);
32859
+ if (!profileSessionRef.current) setActiveProfileId(id2);
32702
32860
  }, []);
32861
+ reactExports.useEffect(() => {
32862
+ profileSessionRef.current = profileSession;
32863
+ }, [profileSession]);
32703
32864
  const [profileSaved, setProfileSaved] = reactExports.useState(false);
32704
32865
  const [drawer, setDrawer] = reactExports.useState(null);
32705
32866
  const [profileDetail, setProfileDetail] = reactExports.useState(null);
@@ -32715,7 +32876,7 @@ function PrimeStyleTryonInner({
32715
32876
  profilesGoBackRef.current = goBack;
32716
32877
  }, []);
32717
32878
  const clearProfileCompletionDraft = reactExports.useCallback(() => {
32718
- lsSet(PROFILE_COMPLETION_DRAFT_KEY, null);
32879
+ lsRemove(PROFILE_COMPLETION_DRAFT_KEY);
32719
32880
  setProfileCompletionDraft(null);
32720
32881
  }, []);
32721
32882
  const handleCompleteProfileFromResult = reactExports.useCallback(() => {
@@ -32748,31 +32909,33 @@ function PrimeStyleTryonInner({
32748
32909
  ...normalizedProfilePhoto ? { photoBase64: normalizedProfilePhoto } : {},
32749
32910
  ...Object.keys(customMeasurements).length > 0 ? { customMeasurements } : {}
32750
32911
  };
32751
- lsSet(PROFILE_COMPLETION_DRAFT_KEY, draft);
32912
+ if (profileSessionRef.current) lsRemove(PROFILE_COMPLETION_DRAFT_KEY);
32913
+ else lsSet(PROFILE_COMPLETION_DRAFT_KEY, draft);
32752
32914
  setProfileCompletionDraft(draft);
32753
32915
  setProfileAuthError(null);
32754
32916
  setView("profiles");
32755
32917
  }, [activeProfileId, effectiveProductId, heightUnit, productTitle, profiles, sizingUnit, weightUnit]);
32756
- const applyProfileStore = reactExports.useCallback((nextProfiles, nextActiveProfileId) => {
32757
- saveProfiles(nextProfiles);
32918
+ const applyProfileStore = reactExports.useCallback((nextProfiles, nextActiveProfileId, persistLocal = !profileSessionRef.current) => {
32919
+ if (persistLocal) saveProfiles(nextProfiles);
32758
32920
  setProfiles(nextProfiles);
32759
- setActiveProfileId$1(nextActiveProfileId);
32921
+ setActiveProfileIdState(nextActiveProfileId);
32922
+ if (persistLocal) setActiveProfileId(nextActiveProfileId);
32760
32923
  profileSyncSnapshotRef.current = JSON.stringify({ profiles: nextProfiles, activeProfileId: nextActiveProfileId });
32761
- }, [setActiveProfileId$1]);
32924
+ }, []);
32762
32925
  const hydrateProfileStore = reactExports.useCallback(async (session, seedProfiles, seedActiveProfileId) => {
32763
32926
  profileSyncHydratingRef.current = true;
32764
32927
  try {
32765
32928
  const remoteStore = await fetchRemoteProfiles(apiUrl, session.accessToken);
32766
32929
  if (remoteStore.profiles.length > 0) {
32767
- applyProfileStore(remoteStore.profiles, remoteStore.activeProfileId);
32930
+ applyProfileStore(remoteStore.profiles, remoteStore.activeProfileId, false);
32768
32931
  return;
32769
32932
  }
32770
32933
  if (seedProfiles.length > 0) {
32771
32934
  const savedStore = await saveRemoteProfiles(apiUrl, session.accessToken, seedProfiles, seedActiveProfileId);
32772
- applyProfileStore(savedStore.profiles, savedStore.activeProfileId);
32935
+ applyProfileStore(savedStore.profiles, savedStore.activeProfileId, false);
32773
32936
  return;
32774
32937
  }
32775
- applyProfileStore([], null);
32938
+ applyProfileStore([], null, false);
32776
32939
  } finally {
32777
32940
  profileSyncHydratingRef.current = false;
32778
32941
  }
@@ -32783,6 +32946,7 @@ function PrimeStyleTryonInner({
32783
32946
  try {
32784
32947
  const session = await startSocialProfileLogin(provider, apiUrl);
32785
32948
  setStoredProfileSession(session);
32949
+ profileSessionRef.current = session;
32786
32950
  setProfileSession(session);
32787
32951
  await hydrateProfileStore(session, profiles, activeProfileId);
32788
32952
  } catch (error) {
@@ -32793,10 +32957,28 @@ function PrimeStyleTryonInner({
32793
32957
  }, [activeProfileId, apiUrl, hydrateProfileStore, profiles, t2]);
32794
32958
  const handleProfileLogout = reactExports.useCallback(() => {
32795
32959
  clearStoredProfileSession();
32960
+ clearProfileLocalStorage();
32961
+ suppressNextProfilePersistRef.current = true;
32962
+ profileSessionRef.current = null;
32796
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());
32797
32979
  setProfileAuthError(null);
32798
32980
  setProfileAuthLoadingProvider(null);
32799
- }, []);
32981
+ }, [previewUrl]);
32800
32982
  const fileInputRef = reactExports.useRef(null);
32801
32983
  const apiRef = reactExports.useRef(null);
32802
32984
  const sseRef = reactExports.useRef(null);
@@ -33079,6 +33261,11 @@ function PrimeStyleTryonInner({
33079
33261
  };
33080
33262
  }, [history]);
33081
33263
  reactExports.useEffect(() => {
33264
+ if (suppressNextProfilePersistRef.current) {
33265
+ suppressNextProfilePersistRef.current = false;
33266
+ return;
33267
+ }
33268
+ if (profileSessionRef.current) return;
33082
33269
  lsSet("profiles", profiles);
33083
33270
  }, [profiles]);
33084
33271
  reactExports.useEffect(() => {
@@ -33107,7 +33294,10 @@ function PrimeStyleTryonInner({
33107
33294
  };
33108
33295
  }, [activeProfileId, apiUrl, applyProfileStore, profileSession, profiles, t2]);
33109
33296
  reactExports.useEffect(() => {
33110
- const handler = () => setProfiles(lsGet("profiles", []));
33297
+ const handler = () => {
33298
+ if (profileSessionRef.current) return;
33299
+ setProfiles(lsGet("profiles", []));
33300
+ };
33111
33301
  window.addEventListener(PS_STORAGE_CHANGE_EVENT, handler);
33112
33302
  return () => window.removeEventListener(PS_STORAGE_CHANGE_EVENT, handler);
33113
33303
  }, []);
@@ -33155,6 +33345,14 @@ function PrimeStyleTryonInner({
33155
33345
  return 1;
33156
33346
  }
33157
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
+ }, []);
33158
33356
  const persistResultToProfile = reactExports.useCallback(
33159
33357
  (formData, recommendation, options) => {
33160
33358
  let targetId = activeProfileId;
@@ -33164,27 +33362,63 @@ function PrimeStyleTryonInner({
33164
33362
  return;
33165
33363
  }
33166
33364
  if (targetId && formData.gender === "female" && (formData.bandSize || formData.cupSize || formData.braSizeRegion)) {
33167
- updateProfile(targetId, {
33365
+ const patch = {
33168
33366
  ...formData.bandSize ? { bandSize: formData.bandSize } : {},
33169
33367
  ...formData.cupSize ? { cupSize: formData.cupSize } : {},
33170
33368
  ...formData.braSizeRegion ? { braSizeRegion: formData.braSizeRegion } : {}
33171
- });
33172
- setProfiles(lsGet("profiles", []));
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
+ }
33173
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
+ };
33174
33409
  if (options?.skipBodyEstimate) {
33175
33410
  console.log("[ps-sdk:persist] skipping body estimates — face/head flow (no body context)");
33176
33411
  } else if (targetId && recommendation?.estimates) {
33177
33412
  const est = recommendation.estimates;
33178
33413
  const unit = recommendation.estimatesUnit || "cm";
33179
- updateProfileMeasurements(targetId, est, unit);
33180
- setProfiles(lsGet("profiles", []));
33414
+ persistMeasurements(est, unit);
33181
33415
  }
33182
33416
  setEstimationDone(true);
33183
33417
  if (recommendation?.recommendedSize && targetId) {
33184
33418
  const sectionsMap = recommendation.sections ? Object.fromEntries(
33185
33419
  Object.entries(recommendation.sections).map(([name, sec]) => [name, sec.recommendedSize])
33186
33420
  ) : void 0;
33187
- addSizeToHistory(targetId, {
33421
+ persistSizeHistory({
33188
33422
  productId: effectiveProductId,
33189
33423
  productTitle,
33190
33424
  productImage,
@@ -33193,10 +33427,9 @@ function PrimeStyleTryonInner({
33193
33427
  sections: sectionsMap,
33194
33428
  savedAt: Date.now()
33195
33429
  });
33196
- setProfiles(lsGet("profiles", []));
33197
33430
  }
33198
33431
  },
33199
- [activeProfileId, profiles, productImage, productTitle, effectiveProductId]
33432
+ [activeProfileId, profiles, productImage, productTitle, effectiveProductId, updateProfilesForCurrentSession]
33200
33433
  );
33201
33434
  const snapSubmitRef = reactExports.useRef(null);
33202
33435
  const [confirmProfile, setConfirmProfile] = reactExports.useState(null);
@@ -33205,7 +33438,7 @@ function PrimeStyleTryonInner({
33205
33438
  const profileWeight = p2.weight ?? p2.weightKg ?? 0;
33206
33439
  const hasStored = !!p2.measurements && Object.keys(p2.measurements).length > 0;
33207
33440
  const storedPhoto = p2.photoUrl || p2.photoBase64;
33208
- if (!hasStored && storedPhoto && profileHeight > 0 && snapSubmitRef.current) {
33441
+ if (storedPhoto && profileHeight > 0 && snapSubmitRef.current) {
33209
33442
  try {
33210
33443
  const dataUrl = await profilePhotoToDataUrl(storedPhoto);
33211
33444
  const blob = await fetch(dataUrl).then((r2) => r2.blob());
@@ -33219,6 +33452,7 @@ function PrimeStyleTryonInner({
33219
33452
  weightUnit: p2.weightUnit || "kg",
33220
33453
  gender: p2.gender,
33221
33454
  age: p2.age,
33455
+ ...hasStored && p2.measurements ? { knownMeasurements: p2.measurements } : {},
33222
33456
  ...snapBraFields({
33223
33457
  gender: p2.gender,
33224
33458
  bandSize: p2.bandSize,
@@ -33262,6 +33496,7 @@ function PrimeStyleTryonInner({
33262
33496
  }
33263
33497
  }
33264
33498
  setView("size-result");
33499
+ const minVisible = new Promise((resolve) => setTimeout(resolve, 6e3));
33265
33500
  recommendForProduct({
33266
33501
  productId: effectiveProductId,
33267
33502
  productTitle,
@@ -33280,7 +33515,9 @@ function PrimeStyleTryonInner({
33280
33515
  if (res?.raw) setSizingResult(res.raw);
33281
33516
  setEstimationDone(true);
33282
33517
  }).catch(() => {
33283
- }).finally(() => setSizingLoading(false));
33518
+ }).finally(() => {
33519
+ void minVisible.then(() => setSizingLoading(false));
33520
+ });
33284
33521
  }, [effectiveProductId, productTitle, productImage, productCategory, productSubcategory, resolvedProductFitType, productType, productTagsList, productDescription, sizeGuideData, apiUrl, previewUrl]);
33285
33522
  const handleUseActiveProfile = reactExports.useCallback(async () => {
33286
33523
  const p2 = profiles.find((x2) => x2.id === activeProfileId);
@@ -33502,6 +33739,8 @@ function PrimeStyleTryonInner({
33502
33739
  }, [sizeGuide, formGender]);
33503
33740
  const submitSizing = reactExports.useCallback(async (methodOverride) => {
33504
33741
  if (!apiRef.current) return;
33742
+ setActiveSection(null);
33743
+ noFitFoundRef.current = false;
33505
33744
  const method = methodOverride || sizingMethod;
33506
33745
  const baseUrl = getApiUrl(apiUrl);
33507
33746
  const key = getApiKey();
@@ -33562,6 +33801,12 @@ function PrimeStyleTryonInner({
33562
33801
  if (resp.ok) {
33563
33802
  const data = await resp.json();
33564
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
+ }
33565
33810
  setSizingResult(data);
33566
33811
  onComplete?.(data);
33567
33812
  } else {
@@ -33623,6 +33868,10 @@ function PrimeStyleTryonInner({
33623
33868
  if (formRef.current.shoeUS) m2.shoeUS = formRef.current.shoeUS;
33624
33869
  if (formRef.current.shoeUK) m2.shoeUK = formRef.current.shoeUK;
33625
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;
33626
33875
  payload.measurements = m2;
33627
33876
  console.log("[PS-SDK] FINAL measurements:", JSON.stringify(m2));
33628
33877
  } else {
@@ -33661,7 +33910,8 @@ function PrimeStyleTryonInner({
33661
33910
  if (res.ok) {
33662
33911
  const data = await res.json();
33663
33912
  console.log("[PS-SDK] Sizing recommend RESULT:", JSON.stringify(data));
33664
- if (data?.found === false && data?.reasoning === "NO_SIZE_CHART") {
33913
+ if (data?.found === false) {
33914
+ setNoSizeReason(data?.reasoning === "NO_SIZE_CHART" ? "no-chart" : "no-match");
33665
33915
  setView("no-chart");
33666
33916
  setEstimationDone(true);
33667
33917
  return;
@@ -33750,6 +34000,7 @@ function PrimeStyleTryonInner({
33750
34000
  setFaceLandmarks(null);
33751
34001
  setSizingMethod("quick");
33752
34002
  setSizingLoading(true);
34003
+ setActiveSection(null);
33753
34004
  setView("size-result");
33754
34005
  submitSizing("quick");
33755
34006
  return;
@@ -33768,6 +34019,7 @@ function PrimeStyleTryonInner({
33768
34019
  setResultImageUrl(null);
33769
34020
  currentHistoryEntryIdRef.current = null;
33770
34021
  currentTryOnJobIdRef.current = null;
34022
+ setActiveSection(null);
33771
34023
  setRestoredProductImage(null);
33772
34024
  setRestoredProductImages(null);
33773
34025
  setRestoredProductCarouselItems(null);
@@ -33845,6 +34097,7 @@ function PrimeStyleTryonInner({
33845
34097
  historyTryonSavedRef.current = false;
33846
34098
  currentHistoryEntryIdRef.current = null;
33847
34099
  currentTryOnJobIdRef.current = null;
34100
+ setActiveSection(null);
33848
34101
  setSizingLoading(true);
33849
34102
  setEstimationDone(false);
33850
34103
  setView("size-result");
@@ -33891,6 +34144,14 @@ function PrimeStyleTryonInner({
33891
34144
  });
33892
34145
  if (recRes.ok) {
33893
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
+ }
33894
34155
  setSizingResult(recData);
33895
34156
  onComplete?.(recData);
33896
34157
  persistResultToProfile(
@@ -34010,6 +34271,7 @@ function PrimeStyleTryonInner({
34010
34271
  if (recRes.ok) {
34011
34272
  const recData = await recRes.json();
34012
34273
  if (recData?.found === false && recData?.reasoning === "NO_SIZE_CHART") {
34274
+ setNoSizeReason("no-chart");
34013
34275
  setView("no-chart");
34014
34276
  setEstimationDone(true);
34015
34277
  setSizingLoading(false);
@@ -34023,8 +34285,13 @@ function PrimeStyleTryonInner({
34023
34285
  noFitFoundRef.current = true;
34024
34286
  setTryOnProcessing(false);
34025
34287
  setTryOnStartedAt(null);
34288
+ setNoSizeReason("no-match");
34026
34289
  setSizingResult({ ...recData, found: false });
34027
34290
  onComplete?.({ ...recData, found: false });
34291
+ setView("no-chart");
34292
+ setEstimationDone(true);
34293
+ setSizingLoading(false);
34294
+ return;
34028
34295
  } else {
34029
34296
  setSizingResult(recData);
34030
34297
  onComplete?.(recData);
@@ -34185,6 +34452,8 @@ function PrimeStyleTryonInner({
34185
34452
  {
34186
34453
  productId: effectiveProductId,
34187
34454
  productTitle,
34455
+ productCategory,
34456
+ productSubcategory,
34188
34457
  productFitType: resolvedProductFitType,
34189
34458
  productType,
34190
34459
  productTags: productTagsList,
@@ -34253,7 +34522,7 @@ function PrimeStyleTryonInner({
34253
34522
  setView("error");
34254
34523
  onError?.({ message, code });
34255
34524
  }
34256
- }, [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]);
34257
34526
  reactExports.useEffect(() => {
34258
34527
  if (view !== "size-result") {
34259
34528
  autoTryOnFiredRef.current = false;
@@ -35000,12 +35269,31 @@ function PrimeStyleTryonInner({
35000
35269
  setView("body-profile");
35001
35270
  },
35002
35271
  onSaveProfileMeasurements: (id2, measurements, unit) => {
35003
- updateProfileMeasurements(id2, measurements, unit ?? profiles.find((x2) => x2.id === id2)?.measurementsUnit ?? "cm");
35004
- setProfiles(lsGet("profiles", []));
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
+ }
35005
35284
  },
35006
35285
  onSaveBraSize: (id2, bandSize, cupSize) => {
35007
- updateProfile(id2, { bandSize, cupSize });
35008
- setProfiles(lsGet("profiles", []));
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
+ }
35009
35297
  },
35010
35298
  onEditProfile: (p2) => {
35011
35299
  setProfileDetail(p2);
@@ -35078,13 +35366,24 @@ function PrimeStyleTryonInner({
35078
35366
  bodyLandmarks: landmarks ?? void 0
35079
35367
  })).then((est) => {
35080
35368
  if (est) {
35081
- updateProfileMeasurements(newProfile.id, est.estimates, est.unit);
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
+ }
35082
35379
  if (est.userEstimates) {
35083
- const all = lsGet("profiles", []);
35084
- const idx = all.findIndex((p2) => p2.id === newProfile.id);
35085
- if (idx >= 0) {
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];
35086
35385
  const target = all[idx];
35087
- const u2 = est.userEstimates;
35386
+ const u2 = userEstimates;
35088
35387
  const patched = { ...target };
35089
35388
  if (u2.height && !(target.height || target.heightCm)) {
35090
35389
  patched.height = u2.height;
@@ -35100,10 +35399,10 @@ function PrimeStyleTryonInner({
35100
35399
  patched.age = u2.age;
35101
35400
  }
35102
35401
  all[idx] = patched;
35103
- lsSet("profiles", all);
35104
- }
35402
+ return all;
35403
+ });
35105
35404
  }
35106
- setProfiles(lsGet("profiles", []));
35405
+ if (!profileSessionRef.current) setProfiles(lsGet("profiles", []));
35107
35406
  }
35108
35407
  }).catch(() => {
35109
35408
  }).finally(() => {
@@ -35116,9 +35415,8 @@ function PrimeStyleTryonInner({
35116
35415
  }
35117
35416
  },
35118
35417
  onDeleteProfile: (id2) => {
35119
- setProfiles((prev) => prev.filter((p2) => p2.id !== id2));
35418
+ updateProfilesForCurrentSession((prev) => prev.filter((p2) => p2.id !== id2));
35120
35419
  if (activeProfileId === id2) setActiveProfileId$1(null);
35121
- lsSet("profiles", lsGet("profiles", []).filter((p2) => p2.id !== id2));
35122
35420
  },
35123
35421
  onRequestDelete: (id2) => setDeleteConfirmId(id2),
35124
35422
  onLogout: handleProfileLogout,
@@ -35152,6 +35450,7 @@ function PrimeStyleTryonInner({
35152
35450
  {
35153
35451
  productImage,
35154
35452
  productTitle,
35453
+ reason: noSizeReason,
35155
35454
  onTryOn: () => setView("photo-guide"),
35156
35455
  onClose: onClose ?? (() => {
35157
35456
  }),
@@ -35378,9 +35677,7 @@ function PrimeStyleTryonInner({
35378
35677
  {
35379
35678
  onConfirm: () => {
35380
35679
  const id2 = deleteConfirmId;
35381
- const updated = lsGet("profiles", []).filter((p2) => p2.id !== id2);
35382
- lsSet("profiles", updated);
35383
- setProfiles(updated);
35680
+ updateProfilesForCurrentSession((prev) => prev.filter((p2) => p2.id !== id2));
35384
35681
  if (activeProfileId === id2) setActiveProfileId$1(null);
35385
35682
  setDeleteConfirmId(null);
35386
35683
  },