@primestyleai/tryon 5.5.26 → 5.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -218,6 +218,8 @@ const SIZE_CONVERSIONS = {
218
218
  };
219
219
  const TOTAL_STEPS = 3;
220
220
  const LS_PREFIX = "primestyle_";
221
+ const PROFILES_KEY = "profiles";
222
+ const ACTIVE_PROFILE_KEY = "active_profile_id";
221
223
  function lsGet(key, fallback) {
222
224
  if (typeof window === "undefined") return fallback;
223
225
  try {
@@ -233,11 +235,67 @@ function lsSet(key, value) {
233
235
  } catch {
234
236
  }
235
237
  }
236
- function isImperial(locale) {
237
- return ["US", "UK", "AU"].includes(locale);
238
+ function getProfiles() {
239
+ return lsGet(PROFILES_KEY, []);
238
240
  }
239
- function cx(base, override) {
240
- return override ? `${base} ${override}` : base;
241
+ function saveProfiles(profiles) {
242
+ lsSet(PROFILES_KEY, profiles);
243
+ }
244
+ function getActiveProfileId() {
245
+ return lsGet(ACTIVE_PROFILE_KEY, null);
246
+ }
247
+ function setActiveProfileId(id) {
248
+ lsSet(ACTIVE_PROFILE_KEY, id);
249
+ }
250
+ function getActiveProfile() {
251
+ const profiles = getProfiles();
252
+ if (profiles.length === 0) return null;
253
+ const activeId = getActiveProfileId();
254
+ if (activeId) {
255
+ const found = profiles.find((p) => p.id === activeId);
256
+ if (found) return found;
257
+ }
258
+ const sorted = [...profiles].sort(
259
+ (a, b) => (b.lastUsedAt || b.createdAt || 0) - (a.lastUsedAt || a.createdAt || 0)
260
+ );
261
+ return sorted[0] || null;
262
+ }
263
+ function updateProfile(id, patch) {
264
+ const profiles = getProfiles();
265
+ const idx = profiles.findIndex((p) => p.id === id);
266
+ if (idx < 0) return null;
267
+ const updated = { ...profiles[idx], ...patch, lastEditedAt: Date.now() };
268
+ profiles[idx] = updated;
269
+ saveProfiles(profiles);
270
+ return updated;
271
+ }
272
+ function updateProfileMeasurements(id, measurements, unit = "cm") {
273
+ return updateProfile(id, { measurements, measurementsUnit: unit });
274
+ }
275
+ function addSizeToHistory(profileId, entry) {
276
+ const profiles = getProfiles();
277
+ const idx = profiles.findIndex((p) => p.id === profileId);
278
+ if (idx < 0) return null;
279
+ const profile = profiles[idx];
280
+ const history = (profile.sizeHistory || []).filter(
281
+ (h) => h.productId !== entry.productId
282
+ );
283
+ history.unshift(entry);
284
+ const trimmed = history.slice(0, 50);
285
+ profiles[idx] = {
286
+ ...profile,
287
+ sizeHistory: trimmed,
288
+ lastUsedAt: Date.now()
289
+ };
290
+ saveProfiles(profiles);
291
+ return profiles[idx];
292
+ }
293
+ function getCachedSize(profile, productId) {
294
+ if (!profile.sizeHistory || profile.sizeHistory.length === 0) return null;
295
+ const entry = profile.sizeHistory.find((h) => h.productId === productId);
296
+ if (!entry) return null;
297
+ if (profile.lastEditedAt && profile.lastEditedAt > entry.savedAt) return null;
298
+ return entry;
241
299
  }
242
300
  function detectLocale() {
243
301
  if (typeof navigator === "undefined") return "US";
@@ -266,6 +324,159 @@ function getApiKey() {
266
324
  function getApiUrl(override) {
267
325
  return override || process.env.NEXT_PUBLIC_PRIMESTYLE_API_URL || "http://localhost:4000";
268
326
  }
327
+ async function recommendForProduct(input) {
328
+ const profile = input.profile ?? getActiveProfile();
329
+ if (!profile) return null;
330
+ if (!input.skipCache) {
331
+ const cached = getCachedSize(profile, input.productId);
332
+ if (cached) {
333
+ return {
334
+ recommendedSize: cached.recommendedSize,
335
+ confidence: cached.confidence,
336
+ sections: cached.sections,
337
+ profileId: profile.id,
338
+ fromCache: true
339
+ };
340
+ }
341
+ }
342
+ let apiKey;
343
+ try {
344
+ apiKey = input.apiKey ?? getApiKey();
345
+ } catch {
346
+ return null;
347
+ }
348
+ const apiUrl = (input.apiUrl ?? getApiUrl()).replace(/\/+$/, "");
349
+ if (!apiKey) return null;
350
+ let sizeGuide = null;
351
+ if (input.sizeGuideData != null) {
352
+ try {
353
+ const sgRes = await fetch(`${apiUrl}/api/v1/sizing/sizeguide`, {
354
+ method: "POST",
355
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
356
+ body: JSON.stringify({
357
+ product: { title: input.productTitle, productId: input.productId },
358
+ sizeGuideRaw: input.sizeGuideData
359
+ })
360
+ });
361
+ if (sgRes.ok) sizeGuide = await sgRes.json();
362
+ } catch {
363
+ }
364
+ }
365
+ const measurements = {
366
+ gender: profile.gender,
367
+ sizingUnit: profile.measurementsUnit || "cm"
368
+ };
369
+ if (profile.measurements) {
370
+ for (const [key, value] of Object.entries(profile.measurements)) {
371
+ if (value != null) measurements[key] = value;
372
+ }
373
+ }
374
+ if (profile.height != null) measurements.height = profile.height;
375
+ if (profile.weight != null) measurements.weight = profile.weight;
376
+ if (profile.heightUnit) measurements.heightUnit = profile.heightUnit;
377
+ if (profile.weightUnit) measurements.weightUnit = profile.weightUnit;
378
+ if (profile.age) measurements.age = profile.age;
379
+ if (profile.chestProfile) measurements.chestProfile = profile.chestProfile;
380
+ if (profile.midsectionProfile) measurements.midsectionProfile = profile.midsectionProfile;
381
+ if (profile.hipProfile) measurements.hipProfile = profile.hipProfile;
382
+ const payload = {
383
+ method: "exact",
384
+ locale: profile.country || "US",
385
+ sizingUnit: profile.measurementsUnit || profile.sizingUnit || "cm",
386
+ product: { title: input.productTitle, productId: input.productId, description: "", variants: [] },
387
+ measurements
388
+ };
389
+ if (sizeGuide && sizeGuide.found) {
390
+ payload.sizeGuide = sizeGuide;
391
+ }
392
+ let result = null;
393
+ try {
394
+ const res = await fetch(`${apiUrl}/api/v1/sizing/recommend`, {
395
+ method: "POST",
396
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
397
+ body: JSON.stringify(payload)
398
+ });
399
+ if (!res.ok) return null;
400
+ result = await res.json();
401
+ } catch {
402
+ return null;
403
+ }
404
+ if (!result || !result.recommendedSize) return null;
405
+ const sectionsMap = result.sections ? Object.fromEntries(
406
+ Object.entries(result.sections).map(([name, sec]) => [name, sec.recommendedSize])
407
+ ) : void 0;
408
+ addSizeToHistory(profile.id, {
409
+ productId: input.productId,
410
+ productTitle: input.productTitle,
411
+ productImage: input.productImage,
412
+ recommendedSize: result.recommendedSize,
413
+ confidence: result.confidence,
414
+ sections: sectionsMap,
415
+ savedAt: Date.now()
416
+ });
417
+ return {
418
+ recommendedSize: result.recommendedSize,
419
+ confidence: result.confidence,
420
+ sections: sectionsMap,
421
+ profileId: profile.id,
422
+ fromCache: false,
423
+ raw: result
424
+ };
425
+ }
426
+ async function estimateFullMeasurements(args) {
427
+ let apiKey;
428
+ try {
429
+ apiKey = args.apiKey ?? getApiKey();
430
+ } catch {
431
+ return null;
432
+ }
433
+ const apiUrl = (args.apiUrl ?? getApiUrl()).replace(/\/+$/, "");
434
+ if (!apiKey) return null;
435
+ const requiredFields = [
436
+ "chest",
437
+ "bust",
438
+ "waist",
439
+ "hips",
440
+ "shoulderWidth",
441
+ "sleeveLength",
442
+ "inseam",
443
+ "neckCircumference",
444
+ "thighCircumference",
445
+ "footLengthCm"
446
+ ];
447
+ const payload = {
448
+ height: args.height,
449
+ weight: args.weight,
450
+ heightUnit: args.heightUnit,
451
+ weightUnit: args.weightUnit,
452
+ gender: args.gender,
453
+ requiredFields
454
+ };
455
+ if (args.age) payload.age = args.age;
456
+ if (args.chestProfile) payload.chestProfile = args.chestProfile;
457
+ if (args.midsectionProfile) payload.midsectionProfile = args.midsectionProfile;
458
+ if (args.hipProfile) payload.hipProfile = args.hipProfile;
459
+ if (args.bodyImage) payload.bodyImage = args.bodyImage;
460
+ try {
461
+ const res = await fetch(`${apiUrl}/api/v1/sizing/estimate`, {
462
+ method: "POST",
463
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}` },
464
+ body: JSON.stringify(payload)
465
+ });
466
+ if (!res.ok) return null;
467
+ const data = await res.json();
468
+ if (!data?.estimates) return null;
469
+ return { estimates: data.estimates, unit: data.unit || "cm" };
470
+ } catch {
471
+ return null;
472
+ }
473
+ }
474
+ function isImperial(locale) {
475
+ return ["US", "UK", "AU"].includes(locale);
476
+ }
477
+ function cx(base, override) {
478
+ return override ? `${base} ${override}` : base;
479
+ }
269
480
  const STYLES = `
270
481
  /* Variable defaults must live on BOTH the root (for the trigger button)
271
482
  and the overlay (which is React-portaled to <body> and therefore not
@@ -3557,6 +3768,292 @@ const STYLES = `
3557
3768
  margin: 14px 12px 0;
3558
3769
  }
3559
3770
 
3771
+ /* ════════════════════════════════════════════════════════════════
3772
+ MySizingProfilesView (.ps-msp-*) — full profile management screen
3773
+ that replaces the old profile drawer. Grid of profile cards
3774
+ matching the ATELIER reference design.
3775
+ ════════════════════════════════════════════════════════════════ */
3776
+ .ps-msp-root {
3777
+ display: flex; flex-direction: column;
3778
+ height: 100%; min-height: 0;
3779
+ margin: 0 -16px;
3780
+ }
3781
+ .ps-msp-topbar {
3782
+ display: flex; align-items: center; justify-content: space-between;
3783
+ padding: 8px 16px;
3784
+ border-bottom: 1px solid var(--ps-border-subtle);
3785
+ flex-shrink: 0;
3786
+ }
3787
+ .ps-msp-back {
3788
+ background: none; border: none;
3789
+ color: var(--ps-text-primary); cursor: pointer;
3790
+ padding: 6px;
3791
+ display: flex; align-items: center; justify-content: center;
3792
+ transition: opacity 0.15s;
3793
+ }
3794
+ .ps-msp-back:hover { opacity: 0.7; }
3795
+ .ps-msp-back svg { width: 18px; height: 18px; }
3796
+ .ps-msp-topbar-title {
3797
+ font-size: 12px; font-weight: 700;
3798
+ letter-spacing: 0.16em; text-transform: uppercase;
3799
+ color: var(--ps-text-primary);
3800
+ flex: 1; text-align: center;
3801
+ }
3802
+ .ps-msp-topbar-spacer { width: 30px; flex-shrink: 0; }
3803
+
3804
+ .ps-msp-scroll {
3805
+ flex: 1; min-height: 0;
3806
+ overflow-y: auto; -webkit-overflow-scrolling: touch;
3807
+ padding: 18px 16px 32px;
3808
+ }
3809
+ .ps-msp-header { margin-bottom: 18px; }
3810
+ .ps-msp-title {
3811
+ font-size: 26px; font-weight: 700;
3812
+ color: var(--ps-text-primary);
3813
+ margin: 0 0 6px;
3814
+ letter-spacing: -0.01em;
3815
+ }
3816
+ .ps-msp-subtitle {
3817
+ font-size: 13px; color: var(--ps-text-muted);
3818
+ margin: 0; line-height: 1.5;
3819
+ }
3820
+
3821
+ /* Card grid */
3822
+ .ps-msp-grid {
3823
+ display: grid;
3824
+ grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
3825
+ gap: 14px;
3826
+ margin-bottom: 28px;
3827
+ }
3828
+ .ps-msp-card {
3829
+ background: var(--ps-bg-primary);
3830
+ border: 1px solid var(--ps-border-subtle);
3831
+ border-radius: 12px;
3832
+ padding: 14px;
3833
+ display: flex; flex-direction: column;
3834
+ transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
3835
+ box-shadow: 0 1px 3px rgba(0,0,0,0.04);
3836
+ position: relative;
3837
+ }
3838
+ .ps-msp-card:hover {
3839
+ border-color: var(--ps-text-primary);
3840
+ box-shadow: 0 4px 12px rgba(0,0,0,0.06);
3841
+ }
3842
+ .ps-msp-card.ps-active {
3843
+ border-color: var(--ps-accent);
3844
+ box-shadow: 0 4px 16px rgba(33,84,239,0.12);
3845
+ }
3846
+
3847
+ .ps-msp-card-header {
3848
+ display: flex; align-items: center; justify-content: flex-start;
3849
+ margin-bottom: 8px;
3850
+ }
3851
+ .ps-msp-card-tag {
3852
+ font-size: 9px; font-weight: 700;
3853
+ letter-spacing: 0.12em; text-transform: uppercase;
3854
+ background: var(--ps-bg-secondary);
3855
+ color: var(--ps-text-muted);
3856
+ padding: 4px 8px; border-radius: 4px;
3857
+ border: 1px solid var(--ps-border-subtle);
3858
+ }
3859
+ .ps-msp-card.ps-active .ps-msp-card-tag {
3860
+ background: var(--ps-accent); color: #FFFFFF;
3861
+ border-color: var(--ps-accent);
3862
+ }
3863
+
3864
+ .ps-msp-card-thumb {
3865
+ height: 90px;
3866
+ background: var(--ps-bg-secondary);
3867
+ border-radius: 8px;
3868
+ display: flex; align-items: center; justify-content: center;
3869
+ margin-bottom: 12px;
3870
+ color: var(--ps-text-secondary);
3871
+ }
3872
+ .ps-msp-avatar {
3873
+ position: relative;
3874
+ display: flex; align-items: center; justify-content: center;
3875
+ width: 56px; height: 56px;
3876
+ border-radius: 50%;
3877
+ background: var(--ps-bg-primary);
3878
+ color: var(--ps-text-secondary);
3879
+ border: 1.5px solid var(--ps-border-subtle);
3880
+ }
3881
+ .ps-msp-avatar-tag {
3882
+ position: absolute; bottom: -2px; right: -2px;
3883
+ width: 18px; height: 18px; border-radius: 50%;
3884
+ background: var(--ps-accent); color: #FFFFFF;
3885
+ font-size: 10px; font-weight: 700;
3886
+ display: flex; align-items: center; justify-content: center;
3887
+ border: 2px solid var(--ps-bg-primary);
3888
+ }
3889
+
3890
+ .ps-msp-card-name {
3891
+ font-size: 16px; font-weight: 700;
3892
+ color: var(--ps-text-primary);
3893
+ margin-bottom: 8px;
3894
+ }
3895
+ .ps-msp-card-meta {
3896
+ display: flex; flex-direction: column;
3897
+ gap: 4px;
3898
+ margin-bottom: 12px;
3899
+ }
3900
+ .ps-msp-meta-row {
3901
+ display: flex; align-items: center; justify-content: space-between;
3902
+ padding: 4px 0;
3903
+ border-bottom: 1px solid var(--ps-border-subtle);
3904
+ }
3905
+ .ps-msp-meta-row:last-child { border-bottom: none; }
3906
+ .ps-msp-meta-label {
3907
+ font-size: 9px; font-weight: 600;
3908
+ letter-spacing: 0.1em; text-transform: uppercase;
3909
+ color: var(--ps-text-muted);
3910
+ }
3911
+ .ps-msp-meta-value {
3912
+ font-size: 12px; font-weight: 600;
3913
+ color: var(--ps-text-primary);
3914
+ font-feature-settings: "tnum" 1;
3915
+ }
3916
+
3917
+ .ps-msp-card-actions {
3918
+ display: flex; gap: 8px;
3919
+ margin-top: auto;
3920
+ }
3921
+ .ps-msp-card-select {
3922
+ flex: 1;
3923
+ background: var(--ps-text-primary); color: #FFFFFF;
3924
+ border: none; border-radius: 6px;
3925
+ padding: 10px;
3926
+ font-family: inherit; font-size: 11px; font-weight: 700;
3927
+ letter-spacing: 0.12em; text-transform: uppercase;
3928
+ cursor: pointer;
3929
+ transition: opacity 0.15s, transform 0.15s;
3930
+ }
3931
+ .ps-msp-card-select:hover { opacity: 0.85; }
3932
+ .ps-msp-card-select:active { transform: scale(0.97); }
3933
+ .ps-msp-card-select.ps-active {
3934
+ background: var(--ps-accent);
3935
+ }
3936
+ .ps-msp-card-edit {
3937
+ width: 36px; height: 36px;
3938
+ background: var(--ps-bg-primary);
3939
+ border: 1px solid var(--ps-border-subtle);
3940
+ border-radius: 6px;
3941
+ display: flex; align-items: center; justify-content: center;
3942
+ color: var(--ps-text-secondary); cursor: pointer;
3943
+ transition: border-color 0.15s, color 0.15s;
3944
+ }
3945
+ .ps-msp-card-edit:hover {
3946
+ border-color: var(--ps-accent);
3947
+ color: var(--ps-accent);
3948
+ }
3949
+
3950
+ /* "Create New Profile" empty card */
3951
+ .ps-msp-card-create {
3952
+ background: var(--ps-bg-secondary);
3953
+ border: 2px dashed var(--ps-border-color);
3954
+ align-items: center; justify-content: center;
3955
+ text-align: center;
3956
+ cursor: pointer;
3957
+ min-height: 280px;
3958
+ transition: border-color 0.15s, background 0.15s;
3959
+ }
3960
+ .ps-msp-card-create:hover {
3961
+ border-color: var(--ps-accent);
3962
+ background: rgba(33,84,239,0.04);
3963
+ }
3964
+ .ps-msp-create-icon {
3965
+ width: 50px; height: 50px;
3966
+ background: var(--ps-text-primary); color: #FFFFFF;
3967
+ border-radius: 8px;
3968
+ display: flex; align-items: center; justify-content: center;
3969
+ margin-bottom: 12px;
3970
+ }
3971
+ .ps-msp-create-title {
3972
+ font-size: 15px; font-weight: 700;
3973
+ color: var(--ps-text-primary);
3974
+ margin-bottom: 4px;
3975
+ }
3976
+ .ps-msp-create-sub {
3977
+ font-size: 9px; font-weight: 700;
3978
+ letter-spacing: 0.14em; text-transform: uppercase;
3979
+ color: var(--ps-text-muted);
3980
+ }
3981
+
3982
+ /* Recent size calculations section */
3983
+ .ps-msp-history-section {
3984
+ margin-top: 20px;
3985
+ padding-top: 20px;
3986
+ border-top: 1px solid var(--ps-border-subtle);
3987
+ }
3988
+ .ps-msp-history-title {
3989
+ font-size: 13px; font-weight: 700;
3990
+ letter-spacing: 0.1em; text-transform: uppercase;
3991
+ color: var(--ps-text-primary);
3992
+ margin: 0 0 14px;
3993
+ }
3994
+ .ps-msp-history-list {
3995
+ display: flex; flex-direction: column; gap: 8px;
3996
+ }
3997
+ .ps-msp-history-card {
3998
+ display: flex; align-items: center; gap: 12px;
3999
+ padding: 12px;
4000
+ background: var(--ps-bg-primary);
4001
+ border: 1px solid var(--ps-border-subtle);
4002
+ border-radius: 8px;
4003
+ }
4004
+ .ps-msp-history-thumb {
4005
+ width: 48px; height: 48px;
4006
+ border-radius: 6px;
4007
+ background: var(--ps-bg-secondary);
4008
+ overflow: hidden;
4009
+ flex-shrink: 0;
4010
+ display: flex; align-items: center; justify-content: center;
4011
+ }
4012
+ .ps-msp-history-thumb img {
4013
+ max-width: 100%; max-height: 100%; object-fit: contain;
4014
+ }
4015
+ .ps-msp-history-info {
4016
+ flex: 1; min-width: 0;
4017
+ display: flex; flex-direction: column; gap: 2px;
4018
+ }
4019
+ .ps-msp-history-name {
4020
+ font-size: 13px; font-weight: 600;
4021
+ color: var(--ps-text-primary);
4022
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
4023
+ }
4024
+ .ps-msp-history-profile {
4025
+ font-size: 10px;
4026
+ color: var(--ps-text-muted);
4027
+ }
4028
+ .ps-msp-history-meta {
4029
+ font-size: 10px;
4030
+ color: var(--ps-text-muted);
4031
+ display: flex; align-items: center; gap: 4px;
4032
+ }
4033
+ .ps-msp-history-meta svg { color: var(--ps-text-muted); }
4034
+ .ps-msp-history-size {
4035
+ display: flex; flex-direction: column; align-items: flex-end;
4036
+ flex-shrink: 0;
4037
+ }
4038
+ .ps-msp-history-size-label {
4039
+ font-size: 9px; font-weight: 600;
4040
+ letter-spacing: 0.1em; text-transform: uppercase;
4041
+ color: var(--ps-text-muted);
4042
+ }
4043
+ .ps-msp-history-size-value {
4044
+ font-size: 22px; font-weight: 700;
4045
+ color: var(--ps-text-primary);
4046
+ font-feature-settings: "tnum" 1;
4047
+ line-height: 1;
4048
+ }
4049
+
4050
+ @media (max-width: 768px) {
4051
+ .ps-msp-grid { grid-template-columns: 1fr; }
4052
+ .ps-msp-card-create { min-height: 200px; }
4053
+ .ps-msp-title { font-size: 22px; }
4054
+ .ps-msp-subtitle { font-size: 12px; }
4055
+ }
4056
+
3560
4057
  /* Big product image */
3561
4058
  .ps-msd-image {
3562
4059
  width: 100%; height: 240px;
@@ -4550,7 +5047,7 @@ function ProfileDetailModal({
4550
5047
  setProfileDetail,
4551
5048
  setProfiles,
4552
5049
  activeProfileId,
4553
- setActiveProfileId,
5050
+ setActiveProfileId: setActiveProfileId2,
4554
5051
  t
4555
5052
  }) {
4556
5053
  if (!profileDetail) return null;
@@ -4598,7 +5095,7 @@ function ProfileDetailModal({
4598
5095
  ] }),
4599
5096
  /* @__PURE__ */ jsxs("button", { className: "ps-tryon-detail-delete", onClick: () => {
4600
5097
  setProfiles((prev) => prev.filter((x) => x.id !== p.id));
4601
- if (activeProfileId === p.id) setActiveProfileId(null);
5098
+ if (activeProfileId === p.id) setActiveProfileId2(null);
4602
5099
  setProfileDetail(null);
4603
5100
  }, children: [
4604
5101
  /* @__PURE__ */ jsx(TrashIcon, {}),
@@ -5715,6 +6212,7 @@ function SizeResultView({
5715
6212
  handleTryOnSubmit,
5716
6213
  tryOnProcessing,
5717
6214
  bodyLandmarks,
6215
+ estimationDone = false,
5718
6216
  activeSection,
5719
6217
  setActiveSection,
5720
6218
  t
@@ -5791,15 +6289,7 @@ function SizeResultView({
5791
6289
  const [poseLines, setPoseLines] = useState(null);
5792
6290
  const [poseReady, setPoseReady] = useState(false);
5793
6291
  const [imgDims, setImgDims] = useState({ w: 800, h: 1200 });
5794
- const [analyzingDone, setAnalyzingDone] = useState(false);
5795
- useEffect(() => {
5796
- if (!bodyLandmarks) {
5797
- setAnalyzingDone(false);
5798
- return;
5799
- }
5800
- const id = setTimeout(() => setAnalyzingDone(true), 1800);
5801
- return () => clearTimeout(id);
5802
- }, [bodyLandmarks]);
6292
+ const analyzingDone = estimationDone;
5803
6293
  const handleImgLoad = useCallback((e) => {
5804
6294
  const el = e.currentTarget;
5805
6295
  if (el.naturalWidth && el.naturalHeight) {
@@ -6574,6 +7064,154 @@ function ErrorView({
6574
7064
  /* @__PURE__ */ jsx("button", { onClick: handleRetry, className: cx("ps-tryon-submit", cn.submitButton), children: t("Try Again") })
6575
7065
  ] });
6576
7066
  }
7067
+ function ProfileAvatar({ gender }) {
7068
+ return /* @__PURE__ */ jsxs("div", { className: "ps-msp-avatar", children: [
7069
+ /* @__PURE__ */ jsx(UserIcon, { size: 28 }),
7070
+ gender && /* @__PURE__ */ jsx("span", { className: `ps-msp-avatar-tag ps-${gender}`, children: gender === "female" ? "♀" : "♂" })
7071
+ ] });
7072
+ }
7073
+ function ProfileCard({
7074
+ profile,
7075
+ isActive,
7076
+ onSelect,
7077
+ onEdit,
7078
+ t
7079
+ }) {
7080
+ const heightDisplay = (() => {
7081
+ const h = profile.height ?? profile.heightCm;
7082
+ if (!h) return null;
7083
+ if (profile.heightUnit === "in" || profile.heightUnit === "ft") {
7084
+ const ft = Math.floor(h / 12);
7085
+ const inches = Math.round(h % 12);
7086
+ return `${ft}'${inches}"`;
7087
+ }
7088
+ return `${Math.round(h)} cm`;
7089
+ })();
7090
+ const weightDisplay = (() => {
7091
+ const w = profile.weight ?? profile.weightKg;
7092
+ if (!w) return null;
7093
+ return `${Math.round(w)} ${profile.weightUnit || "kg"}`;
7094
+ })();
7095
+ const updatedDisplay = (() => {
7096
+ const ts = profile.lastEditedAt || profile.lastUsedAt || profile.createdAt;
7097
+ if (!ts) return null;
7098
+ return new Date(ts).toLocaleDateString(void 0, { month: "short", day: "numeric" });
7099
+ })();
7100
+ return /* @__PURE__ */ jsxs("div", { className: `ps-msp-card${isActive ? " ps-active" : ""}`, children: [
7101
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-card-header", children: /* @__PURE__ */ jsx("span", { className: "ps-msp-card-tag", children: isActive ? t("DEFAULT PROFILE") : profile.gender === "female" ? t("WOMEN'S FIT") : t("MEN'S FIT") }) }),
7102
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-card-thumb", children: /* @__PURE__ */ jsx(ProfileAvatar, { gender: profile.gender }) }),
7103
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-card-name", children: profile.name }),
7104
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-card-meta", children: [
7105
+ heightDisplay && /* @__PURE__ */ jsxs("div", { className: "ps-msp-meta-row", children: [
7106
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-label", children: t("HEIGHT") }),
7107
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-value", children: heightDisplay })
7108
+ ] }),
7109
+ weightDisplay && /* @__PURE__ */ jsxs("div", { className: "ps-msp-meta-row", children: [
7110
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-label", children: t("WEIGHT") }),
7111
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-value", children: weightDisplay })
7112
+ ] }),
7113
+ updatedDisplay && /* @__PURE__ */ jsxs("div", { className: "ps-msp-meta-row", children: [
7114
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-label", children: t("LAST UPDATE") }),
7115
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-value", children: updatedDisplay })
7116
+ ] })
7117
+ ] }),
7118
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-card-actions", children: [
7119
+ /* @__PURE__ */ jsx(
7120
+ "button",
7121
+ {
7122
+ type: "button",
7123
+ className: `ps-msp-card-select${isActive ? " ps-active" : ""}`,
7124
+ onClick: onSelect,
7125
+ children: isActive ? t("SELECTED") : t("SELECT")
7126
+ }
7127
+ ),
7128
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-msp-card-edit", onClick: onEdit, "aria-label": t("Edit"), children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", width: "14", height: "14", children: [
7129
+ /* @__PURE__ */ jsx("path", { d: "M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" }),
7130
+ /* @__PURE__ */ jsx("path", { d: "M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" })
7131
+ ] }) })
7132
+ ] })
7133
+ ] });
7134
+ }
7135
+ function CreateProfileCard({ onClick, t }) {
7136
+ return /* @__PURE__ */ jsxs("button", { type: "button", className: "ps-msp-card ps-msp-card-create", onClick, children: [
7137
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-create-icon", children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", width: "22", height: "22", children: [
7138
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
7139
+ /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
7140
+ ] }) }),
7141
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-create-title", children: t("Create New Profile") }),
7142
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-create-sub", children: t("ADD MEASUREMENTS & PHOTO") })
7143
+ ] });
7144
+ }
7145
+ function SizeHistoryCard({ entry, profileName, t }) {
7146
+ const date = new Date(entry.savedAt).toLocaleDateString(void 0, { month: "short", day: "numeric" });
7147
+ return /* @__PURE__ */ jsxs("div", { className: "ps-msp-history-card", children: [
7148
+ entry.productImage && /* @__PURE__ */ jsx("div", { className: "ps-msp-history-thumb", children: /* @__PURE__ */ jsx("img", { src: entry.productImage, alt: entry.productTitle }) }),
7149
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-history-info", children: [
7150
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-history-name", children: entry.productTitle }),
7151
+ profileName && /* @__PURE__ */ jsx("div", { className: "ps-msp-history-profile", children: profileName }),
7152
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-history-meta", children: [
7153
+ /* @__PURE__ */ jsx(ClockIcon, { size: 11 }),
7154
+ " ",
7155
+ date
7156
+ ] })
7157
+ ] }),
7158
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-history-size", children: [
7159
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-history-size-label", children: t("SIZE") }),
7160
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-history-size-value", children: entry.recommendedSize })
7161
+ ] })
7162
+ ] });
7163
+ }
7164
+ function MySizingProfilesView({
7165
+ profiles,
7166
+ activeProfileId,
7167
+ onSelectProfile,
7168
+ onEditProfile,
7169
+ onCreateProfile,
7170
+ onDeleteProfile,
7171
+ onClose,
7172
+ t
7173
+ }) {
7174
+ const allHistory = useMemo(() => {
7175
+ const items = [];
7176
+ for (const p of profiles) {
7177
+ for (const h of p.sizeHistory || []) {
7178
+ items.push({ entry: h, profileName: p.name });
7179
+ }
7180
+ }
7181
+ return items.sort((a, b) => b.entry.savedAt - a.entry.savedAt).slice(0, 12);
7182
+ }, [profiles]);
7183
+ return /* @__PURE__ */ jsxs("div", { className: "ps-msp-root", children: [
7184
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-topbar", children: [
7185
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-msp-back", onClick: onClose, "aria-label": t("Back"), children: /* @__PURE__ */ jsx(ArrowLeftIcon, {}) }),
7186
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-topbar-title", children: t("MY SIZING PROFILES") }),
7187
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-topbar-spacer" })
7188
+ ] }),
7189
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-scroll", children: [
7190
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-header", children: [
7191
+ /* @__PURE__ */ jsx("h2", { className: "ps-msp-title", children: t("My Sizing Profiles") }),
7192
+ /* @__PURE__ */ jsx("p", { className: "ps-msp-subtitle", children: t("Manage your bespoke silhouettes. Switch between profiles for different fits or create a new one for specific garment types.") })
7193
+ ] }),
7194
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-grid", children: [
7195
+ /* @__PURE__ */ jsx(CreateProfileCard, { onClick: onCreateProfile, t }),
7196
+ profiles.map((p) => /* @__PURE__ */ jsx(
7197
+ ProfileCard,
7198
+ {
7199
+ profile: p,
7200
+ isActive: p.id === activeProfileId,
7201
+ onSelect: () => onSelectProfile(p.id),
7202
+ onEdit: () => onEditProfile(p),
7203
+ t
7204
+ },
7205
+ p.id
7206
+ ))
7207
+ ] }),
7208
+ allHistory.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-msp-history-section", children: [
7209
+ /* @__PURE__ */ jsx("h3", { className: "ps-msp-history-title", children: t("Recent Size Calculations") }),
7210
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-history-list", children: allHistory.map(({ entry, profileName }) => /* @__PURE__ */ jsx(SizeHistoryCard, { entry, profileName, t }, `${entry.productId}-${entry.savedAt}`)) })
7211
+ ] })
7212
+ ] })
7213
+ ] });
7214
+ }
6577
7215
  function ResultView({ setView }) {
6578
7216
  useEffect(() => {
6579
7217
  setView("size-result");
@@ -7696,6 +8334,7 @@ if (typeof document !== "undefined") {
7696
8334
  function PrimeStyleTryonInner({
7697
8335
  productImage,
7698
8336
  productTitle = "Product",
8337
+ productId,
7699
8338
  buttonText,
7700
8339
  apiUrl,
7701
8340
  showPoweredBy = true,
@@ -7715,6 +8354,7 @@ function PrimeStyleTryonInner({
7715
8354
  onError,
7716
8355
  sizeGuideData
7717
8356
  }) {
8357
+ const effectiveProductId = productId || productImage;
7718
8358
  const [activeLocale, setActiveLocale] = useState(() => locale || "");
7719
8359
  useEffect(() => {
7720
8360
  if (locale !== void 0) setActiveLocale(locale);
@@ -7732,6 +8372,7 @@ function PrimeStyleTryonInner({
7732
8372
  const [sizingMethod, setSizingMethod] = useState(null);
7733
8373
  const [sizingResult, setSizingResult] = useState(null);
7734
8374
  const [sizingLoading, setSizingLoading] = useState(false);
8375
+ const [estimationDone, setEstimationDone] = useState(false);
7735
8376
  const [tryOnProcessing, setTryOnProcessing] = useState(false);
7736
8377
  const [sizeGuide, setSizeGuide] = useState(null);
7737
8378
  const [sizeGuideFetching, setSizeGuideFetching] = useState(false);
@@ -7748,7 +8389,11 @@ function PrimeStyleTryonInner({
7748
8389
  const [estimationLoading, setEstimationLoading] = useState(false);
7749
8390
  const [profiles, setProfiles] = useState(() => lsGet("profiles", []));
7750
8391
  const [history, setHistory] = useState(() => lsGet("history", []));
7751
- const [activeProfileId, setActiveProfileId] = useState(null);
8392
+ const [activeProfileId, setActiveProfileIdState] = useState(() => getActiveProfileId());
8393
+ const setActiveProfileId$1 = useCallback((id) => {
8394
+ setActiveProfileIdState(id);
8395
+ setActiveProfileId(id);
8396
+ }, []);
7752
8397
  const [profileSaved, setProfileSaved] = useState(false);
7753
8398
  const [drawer, setDrawer] = useState(null);
7754
8399
  const [profileDetail, setProfileDetail] = useState(null);
@@ -7887,6 +8532,69 @@ function PrimeStyleTryonInner({
7887
8532
  return 1;
7888
8533
  }
7889
8534
  }, [view]);
8535
+ const persistResultToProfile = useCallback(
8536
+ (formData, recommendation) => {
8537
+ let targetId = activeProfileId;
8538
+ let target = profiles.find((p) => p.id === targetId);
8539
+ if (!target) {
8540
+ const newProfile = {
8541
+ id: Date.now().toString(36) + Math.random().toString(36).slice(2, 6),
8542
+ name: formData.gender === "female" ? "My Profile" : "My Profile",
8543
+ gender: formData.gender,
8544
+ height: formData.height,
8545
+ weight: formData.weight,
8546
+ age: formData.age,
8547
+ heightUnit: formData.heightUnit,
8548
+ weightUnit: formData.weightUnit,
8549
+ chestProfile: formData.chestProfile,
8550
+ midsectionProfile: formData.midsectionProfile,
8551
+ hipProfile: formData.hipProfile,
8552
+ bandSize: formData.bandSize,
8553
+ cupSize: formData.cupSize,
8554
+ createdAt: Date.now(),
8555
+ lastUsedAt: Date.now()
8556
+ };
8557
+ setProfiles((prev) => [newProfile, ...prev]);
8558
+ setActiveProfileId$1(newProfile.id);
8559
+ targetId = newProfile.id;
8560
+ target = newProfile;
8561
+ }
8562
+ estimateFullMeasurements({
8563
+ apiUrl,
8564
+ height: formData.height,
8565
+ weight: formData.weight,
8566
+ heightUnit: formData.heightUnit,
8567
+ weightUnit: formData.weightUnit,
8568
+ gender: formData.gender,
8569
+ age: formData.age,
8570
+ chestProfile: formData.chestProfile,
8571
+ midsectionProfile: formData.midsectionProfile,
8572
+ hipProfile: formData.hipProfile,
8573
+ bodyImage: formData.bodyImage
8574
+ }).then((est) => {
8575
+ if (!est || !targetId) return;
8576
+ updateProfileMeasurements(targetId, est.estimates, est.unit);
8577
+ setProfiles(lsGet("profiles", []));
8578
+ }).catch(() => {
8579
+ }).finally(() => setEstimationDone(true));
8580
+ if (recommendation?.recommendedSize && targetId) {
8581
+ const sectionsMap = recommendation.sections ? Object.fromEntries(
8582
+ Object.entries(recommendation.sections).map(([name, sec]) => [name, sec.recommendedSize])
8583
+ ) : void 0;
8584
+ addSizeToHistory(targetId, {
8585
+ productId: effectiveProductId,
8586
+ productTitle,
8587
+ productImage,
8588
+ recommendedSize: recommendation.recommendedSize,
8589
+ confidence: recommendation.confidence,
8590
+ sections: sectionsMap,
8591
+ savedAt: Date.now()
8592
+ });
8593
+ setProfiles(lsGet("profiles", []));
8594
+ }
8595
+ },
8596
+ [activeProfileId, profiles, apiUrl, productImage, productTitle, effectiveProductId, setActiveProfileId$1]
8597
+ );
7890
8598
  const applyProfileRef = useRef(() => {
7891
8599
  });
7892
8600
  const handleOpen = useCallback(() => {
@@ -8093,6 +8801,7 @@ function PrimeStyleTryonInner({
8093
8801
  if (formRef.current.hipProfile) qe.hipProfile = formRef.current.hipProfile;
8094
8802
  payload.quickEstimate = qe;
8095
8803
  }
8804
+ setEstimationDone(false);
8096
8805
  try {
8097
8806
  const res = await fetch(`${baseUrl}/api/v1/sizing/recommend`, {
8098
8807
  method: "POST",
@@ -8104,20 +8813,39 @@ function PrimeStyleTryonInner({
8104
8813
  console.log("[PS-SDK] Sizing recommend RESULT:", JSON.stringify(data));
8105
8814
  setSizingResult(data);
8106
8815
  onComplete?.(data);
8816
+ const m = payload.measurements || {};
8817
+ const qe = payload.quickEstimate || {};
8818
+ const src = method === "exact" ? m : qe;
8819
+ persistResultToProfile(
8820
+ {
8821
+ gender: src.gender || "male",
8822
+ height: Number(src.height || src.heightCm || 0),
8823
+ weight: Number(src.weight || src.weightKg || 0),
8824
+ heightUnit: src.heightUnit || "cm",
8825
+ weightUnit: src.weightUnit || "kg",
8826
+ age: src.age != null ? Number(src.age) : void 0,
8827
+ chestProfile: src.chestProfile,
8828
+ midsectionProfile: src.midsectionProfile,
8829
+ hipProfile: src.hipProfile
8830
+ },
8831
+ data
8832
+ );
8107
8833
  } else {
8108
8834
  const errBody = await res.text().catch(() => "");
8109
8835
  console.error("[PS-SDK] Sizing recommend failed:", res.status, errBody);
8110
8836
  setErrorMessage(t("Unable to get size recommendation. Please try again."));
8111
8837
  setView("error");
8838
+ setEstimationDone(true);
8112
8839
  }
8113
8840
  } catch (err) {
8114
8841
  console.error("[PS-SDK] Sizing recommend network error:", err);
8115
8842
  setErrorMessage(t("Unable to connect to sizing service. Please try again."));
8116
8843
  setView("error");
8844
+ setEstimationDone(true);
8117
8845
  } finally {
8118
8846
  setSizingLoading(false);
8119
8847
  }
8120
- }, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productTitle, dynamicFields]);
8848
+ }, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productTitle, dynamicFields, persistResultToProfile]);
8121
8849
  const handleQuickEstimate = useCallback(async (height, weight, heightUnit2, weightUnit2, gender, age, bodyType, chestProfile, midsectionProfile, hipProfile, bodyImage) => {
8122
8850
  if (!apiRef.current) return;
8123
8851
  getApiUrl(apiUrl);
@@ -8182,6 +8910,7 @@ function PrimeStyleTryonInner({
8182
8910
  setSizingResult(null);
8183
8911
  setResultImageUrl(null);
8184
8912
  setSizingLoading(true);
8913
+ setEstimationDone(false);
8185
8914
  setView("size-result");
8186
8915
  modelPoseRef.current = null;
8187
8916
  setBodyLandmarks(null);
@@ -8220,11 +8949,26 @@ function PrimeStyleTryonInner({
8220
8949
  const recData = await recRes.json();
8221
8950
  setSizingResult(recData);
8222
8951
  onComplete?.(recData);
8952
+ persistResultToProfile(
8953
+ {
8954
+ gender: data.gender,
8955
+ height: data.height,
8956
+ weight: data.weight,
8957
+ heightUnit: data.heightUnit,
8958
+ weightUnit: data.weightUnit,
8959
+ age: data.age,
8960
+ bodyImage: data.photoBase64
8961
+ },
8962
+ recData
8963
+ );
8964
+ } else {
8965
+ setEstimationDone(true);
8223
8966
  }
8224
8967
  } catch {
8968
+ setEstimationDone(true);
8225
8969
  }
8226
8970
  setSizingLoading(false);
8227
- }, [apiUrl, productImage, productTitle, sizingUnit, weightUnit, sizingCountry, sizeGuide, dynamicFields]);
8971
+ }, [apiUrl, productImage, productTitle, sizingUnit, weightUnit, sizingCountry, sizeGuide, dynamicFields, persistResultToProfile]);
8228
8972
  const handleTryOnSubmit = useCallback(async () => {
8229
8973
  const file = selectedFile || selectedFileRef.current;
8230
8974
  if (!file || !apiRef.current || !sseRef.current) {
@@ -8416,7 +9160,7 @@ function PrimeStyleTryonInner({
8416
9160
  const applyProfile = useCallback((id) => {
8417
9161
  const p = profiles.find((pr) => pr.id === id);
8418
9162
  if (!p) return;
8419
- setActiveProfileId(id);
9163
+ setActiveProfileId$1(id);
8420
9164
  setProfiles((prev) => prev.map((pr) => pr.id === id ? { ...pr, lastUsedAt: Date.now() } : pr));
8421
9165
  const fd = { gender: p.gender || "male" };
8422
9166
  if (p.height ?? p.heightCm) fd.height = String(p.height ?? p.heightCm);
@@ -8511,7 +9255,7 @@ function PrimeStyleTryonInner({
8511
9255
  }
8512
9256
  return [...prev, p].slice(-50);
8513
9257
  });
8514
- setActiveProfileId(id);
9258
+ setActiveProfileId$1(id);
8515
9259
  setProfileSaved(true);
8516
9260
  }, [activeProfileId, sizingCountry, sizingUnit, heightUnit, weightUnit]);
8517
9261
  const saveHistoryEntry = useCallback(() => {
@@ -8726,6 +9470,7 @@ function PrimeStyleTryonInner({
8726
9470
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(
8727
9471
  SizeResultView,
8728
9472
  {
9473
+ estimationDone,
8729
9474
  sizingLoading,
8730
9475
  sizingResult,
8731
9476
  sizeGuide,
@@ -8780,6 +9525,28 @@ function PrimeStyleTryonInner({
8780
9525
  ) }, "v-proc");
8781
9526
  case "result":
8782
9527
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(ResultView, { setView }) }, "v-result");
9528
+ case "profiles":
9529
+ return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(
9530
+ MySizingProfilesView,
9531
+ {
9532
+ profiles,
9533
+ activeProfileId,
9534
+ onSelectProfile: (id) => {
9535
+ setActiveProfileId$1(id);
9536
+ setView("body-profile");
9537
+ },
9538
+ onEditProfile: (p) => {
9539
+ setProfileDetail(p);
9540
+ },
9541
+ onCreateProfile: () => {
9542
+ setActiveProfileId$1(null);
9543
+ setView("body-profile");
9544
+ },
9545
+ onDeleteProfile: (id) => setProfiles((prev) => prev.filter((p) => p.id !== id)),
9546
+ onClose: () => setView("body-profile"),
9547
+ t
9548
+ }
9549
+ ) }, "v-profiles");
8783
9550
  case "error":
8784
9551
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(
8785
9552
  ErrorView,
@@ -8803,7 +9570,7 @@ function PrimeStyleTryonInner({
8803
9570
  /* @__PURE__ */ jsx("div", { className: cx("ps-tryon-overlay", cn.overlay), style: cssVars, "data-ps-tryon-portal": true, children: /* @__PURE__ */ jsxs("div", { className: cx(`ps-tryon-modal${view === "result" && resultImageUrl && sizingResult || view === "size-result" || view === "estimation-review" || view === "body-profile" ? " ps-tryon-modal-wide" : ""}`, cn.modal), onClick: (e) => e.stopPropagation(), children: [
8804
9571
  /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-header ps-tryon-header-minimal", cn.header), children: [
8805
9572
  /* @__PURE__ */ jsx(LangSwitcher, { activeLocale, onSelect: setActiveLocale }),
8806
- /* @__PURE__ */ jsx("button", { className: "ps-tryon-header-icon", title: t("Profiles"), onClick: () => setDrawer(drawer === "profiles" ? null : "profiles"), children: /* @__PURE__ */ jsx(UserIcon, {}) }),
9573
+ /* @__PURE__ */ jsx("button", { className: "ps-tryon-header-icon", title: t("Profiles"), onClick: () => setView(view === "profiles" ? "body-profile" : "profiles"), children: /* @__PURE__ */ jsx(UserIcon, {}) }),
8807
9574
  /* @__PURE__ */ jsx("button", { className: "ps-tryon-header-icon", title: t("History"), onClick: () => setDrawer(drawer === "history" ? null : "history"), children: /* @__PURE__ */ jsx(ClockIcon, {}) }),
8808
9575
  /* @__PURE__ */ jsx("button", { onClick: handleClose, className: cx("ps-tryon-close", cn.closeButton), children: /* @__PURE__ */ jsx(XIcon, {}) })
8809
9576
  ] }),
@@ -8842,7 +9609,7 @@ function PrimeStyleTryonInner({
8842
9609
  setProfileDetail,
8843
9610
  setProfiles,
8844
9611
  activeProfileId,
8845
- setActiveProfileId,
9612
+ setActiveProfileId: setActiveProfileId$1,
8846
9613
  t
8847
9614
  }
8848
9615
  )
@@ -8851,6 +9618,53 @@ function PrimeStyleTryonInner({
8851
9618
  function PrimeStyleTryon(props) {
8852
9619
  return /* @__PURE__ */ jsx(PrimeStyleTryonInner, { ...props });
8853
9620
  }
9621
+ function usePrimeStyleSize(input) {
9622
+ const [result, setResult] = useState(null);
9623
+ const [loading, setLoading] = useState(true);
9624
+ const [noProfile, setNoProfile] = useState(false);
9625
+ const [tick, setTick] = useState(0);
9626
+ useEffect(() => {
9627
+ let cancelled = false;
9628
+ setLoading(true);
9629
+ setNoProfile(false);
9630
+ recommendForProduct(input).then((res) => {
9631
+ if (cancelled) return;
9632
+ if (res === null) {
9633
+ setNoProfile(true);
9634
+ setResult(null);
9635
+ } else {
9636
+ setResult(res);
9637
+ }
9638
+ }).catch(() => {
9639
+ if (!cancelled) setResult(null);
9640
+ }).finally(() => {
9641
+ if (!cancelled) setLoading(false);
9642
+ });
9643
+ return () => {
9644
+ cancelled = true;
9645
+ };
9646
+ }, [input.productId, input.apiUrl, input.apiKey, tick]);
9647
+ return {
9648
+ recommendedSize: result?.recommendedSize ?? null,
9649
+ sections: result?.sections ?? null,
9650
+ loading,
9651
+ noProfile,
9652
+ result,
9653
+ refetch: () => setTick((n) => n + 1)
9654
+ };
9655
+ }
8854
9656
  export {
8855
- PrimeStyleTryon
9657
+ PrimeStyleTryon,
9658
+ addSizeToHistory,
9659
+ estimateFullMeasurements,
9660
+ getActiveProfile,
9661
+ getActiveProfileId,
9662
+ getCachedSize,
9663
+ getProfiles,
9664
+ recommendForProduct,
9665
+ saveProfiles,
9666
+ setActiveProfileId,
9667
+ updateProfile,
9668
+ updateProfileMeasurements,
9669
+ usePrimeStyleSize
8856
9670
  };