@primestyleai/tryon 5.5.26 → 5.6.1

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,295 @@ 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-accent);
3840
+ box-shadow: 0 4px 12px rgba(33, 84, 239, 0.08);
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
+ .ps-msp-avatar { color: var(--ps-accent); border-color: var(--ps-accent); }
3864
+ .ps-msp-avatar-tag { background: var(--ps-accent); }
3865
+
3866
+ .ps-msp-card-thumb {
3867
+ height: 90px;
3868
+ background: var(--ps-bg-secondary);
3869
+ border-radius: 8px;
3870
+ display: flex; align-items: center; justify-content: center;
3871
+ margin-bottom: 12px;
3872
+ color: var(--ps-text-secondary);
3873
+ }
3874
+ .ps-msp-avatar {
3875
+ position: relative;
3876
+ display: flex; align-items: center; justify-content: center;
3877
+ width: 56px; height: 56px;
3878
+ border-radius: 50%;
3879
+ background: var(--ps-bg-primary);
3880
+ color: var(--ps-text-secondary);
3881
+ border: 1.5px solid var(--ps-border-subtle);
3882
+ }
3883
+ .ps-msp-avatar-tag {
3884
+ position: absolute; bottom: -2px; right: -2px;
3885
+ width: 18px; height: 18px; border-radius: 50%;
3886
+ background: var(--ps-accent); color: #FFFFFF;
3887
+ font-size: 10px; font-weight: 700;
3888
+ display: flex; align-items: center; justify-content: center;
3889
+ border: 2px solid var(--ps-bg-primary);
3890
+ }
3891
+
3892
+ .ps-msp-card-name {
3893
+ font-size: 16px; font-weight: 700;
3894
+ color: var(--ps-text-primary);
3895
+ margin-bottom: 8px;
3896
+ }
3897
+ .ps-msp-card-meta {
3898
+ display: flex; flex-direction: column;
3899
+ gap: 4px;
3900
+ margin-bottom: 12px;
3901
+ }
3902
+ .ps-msp-meta-row {
3903
+ display: flex; align-items: center; justify-content: space-between;
3904
+ padding: 4px 0;
3905
+ border-bottom: 1px solid var(--ps-border-subtle);
3906
+ }
3907
+ .ps-msp-meta-row:last-child { border-bottom: none; }
3908
+ .ps-msp-meta-label {
3909
+ font-size: 9px; font-weight: 600;
3910
+ letter-spacing: 0.1em; text-transform: uppercase;
3911
+ color: var(--ps-text-muted);
3912
+ }
3913
+ .ps-msp-meta-value {
3914
+ font-size: 12px; font-weight: 600;
3915
+ color: var(--ps-text-primary);
3916
+ font-feature-settings: "tnum" 1;
3917
+ }
3918
+
3919
+ .ps-msp-card-actions {
3920
+ display: flex; gap: 8px;
3921
+ margin-top: auto;
3922
+ }
3923
+ .ps-msp-card-select {
3924
+ flex: 1;
3925
+ background: var(--ps-accent); color: #FFFFFF;
3926
+ border: none; border-radius: 6px;
3927
+ padding: 10px;
3928
+ font-family: inherit; font-size: 11px; font-weight: 700;
3929
+ letter-spacing: 0.12em; text-transform: uppercase;
3930
+ cursor: pointer;
3931
+ transition: opacity 0.15s, transform 0.15s;
3932
+ }
3933
+ .ps-msp-card-select:hover { opacity: 0.85; }
3934
+ .ps-msp-card-select:active { transform: scale(0.97); }
3935
+ .ps-msp-card-select.ps-active {
3936
+ background: var(--ps-accent);
3937
+ box-shadow: 0 0 0 2px rgba(33, 84, 239, 0.18);
3938
+ }
3939
+ .ps-msp-card-edit {
3940
+ width: 36px; height: 36px;
3941
+ background: var(--ps-bg-primary);
3942
+ border: 1px solid var(--ps-border-subtle);
3943
+ border-radius: 6px;
3944
+ display: flex; align-items: center; justify-content: center;
3945
+ color: var(--ps-text-secondary); cursor: pointer;
3946
+ transition: border-color 0.15s, color 0.15s;
3947
+ }
3948
+ .ps-msp-card-edit:hover {
3949
+ border-color: var(--ps-accent);
3950
+ color: var(--ps-accent);
3951
+ }
3952
+
3953
+ /* "Create New Profile" empty card */
3954
+ .ps-msp-card-create {
3955
+ background: var(--ps-bg-secondary);
3956
+ border: 2px dashed var(--ps-border-color);
3957
+ align-items: center; justify-content: center;
3958
+ text-align: center;
3959
+ cursor: pointer;
3960
+ min-height: 280px;
3961
+ transition: border-color 0.15s, background 0.15s;
3962
+ }
3963
+ .ps-msp-card-create:hover {
3964
+ border-color: var(--ps-accent);
3965
+ background: rgba(33,84,239,0.04);
3966
+ }
3967
+ .ps-msp-create-icon {
3968
+ width: 50px; height: 50px;
3969
+ background: var(--ps-accent); color: #FFFFFF;
3970
+ border-radius: 8px;
3971
+ display: flex; align-items: center; justify-content: center;
3972
+ margin-bottom: 12px;
3973
+ }
3974
+ .ps-msp-create-title {
3975
+ font-size: 15px; font-weight: 700;
3976
+ color: var(--ps-text-primary);
3977
+ margin-bottom: 4px;
3978
+ }
3979
+ .ps-msp-create-sub {
3980
+ font-size: 9px; font-weight: 700;
3981
+ letter-spacing: 0.14em; text-transform: uppercase;
3982
+ color: var(--ps-text-muted);
3983
+ }
3984
+
3985
+ /* Recent size calculations section */
3986
+ .ps-msp-history-section {
3987
+ margin-top: 20px;
3988
+ padding-top: 20px;
3989
+ border-top: 1px solid var(--ps-border-subtle);
3990
+ }
3991
+ .ps-msp-history-title {
3992
+ font-size: 13px; font-weight: 700;
3993
+ letter-spacing: 0.1em; text-transform: uppercase;
3994
+ color: var(--ps-text-primary);
3995
+ margin: 0 0 14px;
3996
+ }
3997
+ .ps-msp-history-list {
3998
+ display: flex; flex-direction: column; gap: 8px;
3999
+ }
4000
+ .ps-msp-history-card {
4001
+ display: flex; align-items: center; gap: 12px;
4002
+ padding: 12px;
4003
+ background: var(--ps-bg-primary);
4004
+ border: 1px solid var(--ps-border-subtle);
4005
+ border-radius: 8px;
4006
+ }
4007
+ .ps-msp-history-thumb {
4008
+ width: 48px; height: 48px;
4009
+ border-radius: 6px;
4010
+ background: var(--ps-bg-secondary);
4011
+ overflow: hidden;
4012
+ flex-shrink: 0;
4013
+ display: flex; align-items: center; justify-content: center;
4014
+ }
4015
+ .ps-msp-history-thumb img {
4016
+ max-width: 100%; max-height: 100%; object-fit: contain;
4017
+ }
4018
+ .ps-msp-history-info {
4019
+ flex: 1; min-width: 0;
4020
+ display: flex; flex-direction: column; gap: 2px;
4021
+ }
4022
+ .ps-msp-history-name {
4023
+ font-size: 13px; font-weight: 600;
4024
+ color: var(--ps-text-primary);
4025
+ overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
4026
+ }
4027
+ .ps-msp-history-profile {
4028
+ font-size: 10px;
4029
+ color: var(--ps-text-muted);
4030
+ }
4031
+ .ps-msp-history-meta {
4032
+ font-size: 10px;
4033
+ color: var(--ps-text-muted);
4034
+ display: flex; align-items: center; gap: 4px;
4035
+ }
4036
+ .ps-msp-history-meta svg { color: var(--ps-text-muted); }
4037
+ .ps-msp-history-size {
4038
+ display: flex; flex-direction: column; align-items: flex-end;
4039
+ flex-shrink: 0;
4040
+ }
4041
+ .ps-msp-history-size-label {
4042
+ font-size: 9px; font-weight: 600;
4043
+ letter-spacing: 0.1em; text-transform: uppercase;
4044
+ color: var(--ps-text-muted);
4045
+ }
4046
+ .ps-msp-history-size-value {
4047
+ font-size: 22px; font-weight: 700;
4048
+ color: var(--ps-text-primary);
4049
+ font-feature-settings: "tnum" 1;
4050
+ line-height: 1;
4051
+ }
4052
+
4053
+ @media (max-width: 768px) {
4054
+ .ps-msp-grid { grid-template-columns: 1fr; }
4055
+ .ps-msp-card-create { min-height: 200px; }
4056
+ .ps-msp-title { font-size: 22px; }
4057
+ .ps-msp-subtitle { font-size: 12px; }
4058
+ }
4059
+
3560
4060
  /* Big product image */
3561
4061
  .ps-msd-image {
3562
4062
  width: 100%; height: 240px;
@@ -4550,7 +5050,7 @@ function ProfileDetailModal({
4550
5050
  setProfileDetail,
4551
5051
  setProfiles,
4552
5052
  activeProfileId,
4553
- setActiveProfileId,
5053
+ setActiveProfileId: setActiveProfileId2,
4554
5054
  t
4555
5055
  }) {
4556
5056
  if (!profileDetail) return null;
@@ -4598,7 +5098,7 @@ function ProfileDetailModal({
4598
5098
  ] }),
4599
5099
  /* @__PURE__ */ jsxs("button", { className: "ps-tryon-detail-delete", onClick: () => {
4600
5100
  setProfiles((prev) => prev.filter((x) => x.id !== p.id));
4601
- if (activeProfileId === p.id) setActiveProfileId(null);
5101
+ if (activeProfileId === p.id) setActiveProfileId2(null);
4602
5102
  setProfileDetail(null);
4603
5103
  }, children: [
4604
5104
  /* @__PURE__ */ jsx(TrashIcon, {}),
@@ -5715,6 +6215,7 @@ function SizeResultView({
5715
6215
  handleTryOnSubmit,
5716
6216
  tryOnProcessing,
5717
6217
  bodyLandmarks,
6218
+ estimationDone = false,
5718
6219
  activeSection,
5719
6220
  setActiveSection,
5720
6221
  t
@@ -5791,15 +6292,7 @@ function SizeResultView({
5791
6292
  const [poseLines, setPoseLines] = useState(null);
5792
6293
  const [poseReady, setPoseReady] = useState(false);
5793
6294
  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]);
6295
+ const analyzingDone = estimationDone;
5803
6296
  const handleImgLoad = useCallback((e) => {
5804
6297
  const el = e.currentTarget;
5805
6298
  if (el.naturalWidth && el.naturalHeight) {
@@ -6574,6 +7067,154 @@ function ErrorView({
6574
7067
  /* @__PURE__ */ jsx("button", { onClick: handleRetry, className: cx("ps-tryon-submit", cn.submitButton), children: t("Try Again") })
6575
7068
  ] });
6576
7069
  }
7070
+ function ProfileAvatar({ gender }) {
7071
+ return /* @__PURE__ */ jsxs("div", { className: "ps-msp-avatar", children: [
7072
+ /* @__PURE__ */ jsx(UserIcon, { size: 28 }),
7073
+ gender && /* @__PURE__ */ jsx("span", { className: `ps-msp-avatar-tag ps-${gender}`, children: gender === "female" ? "♀" : "♂" })
7074
+ ] });
7075
+ }
7076
+ function ProfileCard({
7077
+ profile,
7078
+ isActive,
7079
+ onSelect,
7080
+ onEdit,
7081
+ t
7082
+ }) {
7083
+ const heightDisplay = (() => {
7084
+ const h = profile.height ?? profile.heightCm;
7085
+ if (!h) return null;
7086
+ if (profile.heightUnit === "in" || profile.heightUnit === "ft") {
7087
+ const ft = Math.floor(h / 12);
7088
+ const inches = Math.round(h % 12);
7089
+ return `${ft}'${inches}"`;
7090
+ }
7091
+ return `${Math.round(h)} cm`;
7092
+ })();
7093
+ const weightDisplay = (() => {
7094
+ const w = profile.weight ?? profile.weightKg;
7095
+ if (!w) return null;
7096
+ return `${Math.round(w)} ${profile.weightUnit || "kg"}`;
7097
+ })();
7098
+ const updatedDisplay = (() => {
7099
+ const ts = profile.lastEditedAt || profile.lastUsedAt || profile.createdAt;
7100
+ if (!ts) return null;
7101
+ return new Date(ts).toLocaleDateString(void 0, { month: "short", day: "numeric" });
7102
+ })();
7103
+ return /* @__PURE__ */ jsxs("div", { className: `ps-msp-card${isActive ? " ps-active" : ""}`, children: [
7104
+ /* @__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") }) }),
7105
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-card-thumb", children: /* @__PURE__ */ jsx(ProfileAvatar, { gender: profile.gender }) }),
7106
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-card-name", children: profile.name }),
7107
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-card-meta", children: [
7108
+ heightDisplay && /* @__PURE__ */ jsxs("div", { className: "ps-msp-meta-row", children: [
7109
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-label", children: t("HEIGHT") }),
7110
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-value", children: heightDisplay })
7111
+ ] }),
7112
+ weightDisplay && /* @__PURE__ */ jsxs("div", { className: "ps-msp-meta-row", children: [
7113
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-label", children: t("WEIGHT") }),
7114
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-value", children: weightDisplay })
7115
+ ] }),
7116
+ updatedDisplay && /* @__PURE__ */ jsxs("div", { className: "ps-msp-meta-row", children: [
7117
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-label", children: t("LAST UPDATE") }),
7118
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-meta-value", children: updatedDisplay })
7119
+ ] })
7120
+ ] }),
7121
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-card-actions", children: [
7122
+ /* @__PURE__ */ jsx(
7123
+ "button",
7124
+ {
7125
+ type: "button",
7126
+ className: `ps-msp-card-select${isActive ? " ps-active" : ""}`,
7127
+ onClick: onSelect,
7128
+ children: isActive ? t("SELECTED") : t("SELECT")
7129
+ }
7130
+ ),
7131
+ /* @__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: [
7132
+ /* @__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" }),
7133
+ /* @__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" })
7134
+ ] }) })
7135
+ ] })
7136
+ ] });
7137
+ }
7138
+ function CreateProfileCard({ onClick, t }) {
7139
+ return /* @__PURE__ */ jsxs("button", { type: "button", className: "ps-msp-card ps-msp-card-create", onClick, children: [
7140
+ /* @__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: [
7141
+ /* @__PURE__ */ jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
7142
+ /* @__PURE__ */ jsx("line", { x1: "5", y1: "12", x2: "19", y2: "12" })
7143
+ ] }) }),
7144
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-create-title", children: t("Create New Profile") }),
7145
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-create-sub", children: t("ADD MEASUREMENTS & PHOTO") })
7146
+ ] });
7147
+ }
7148
+ function SizeHistoryCard({ entry, profileName, t }) {
7149
+ const date = new Date(entry.savedAt).toLocaleDateString(void 0, { month: "short", day: "numeric" });
7150
+ return /* @__PURE__ */ jsxs("div", { className: "ps-msp-history-card", children: [
7151
+ entry.productImage && /* @__PURE__ */ jsx("div", { className: "ps-msp-history-thumb", children: /* @__PURE__ */ jsx("img", { src: entry.productImage, alt: entry.productTitle }) }),
7152
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-history-info", children: [
7153
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-history-name", children: entry.productTitle }),
7154
+ profileName && /* @__PURE__ */ jsx("div", { className: "ps-msp-history-profile", children: profileName }),
7155
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-history-meta", children: [
7156
+ /* @__PURE__ */ jsx(ClockIcon, { size: 11 }),
7157
+ " ",
7158
+ date
7159
+ ] })
7160
+ ] }),
7161
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-history-size", children: [
7162
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-history-size-label", children: t("SIZE") }),
7163
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-history-size-value", children: entry.recommendedSize })
7164
+ ] })
7165
+ ] });
7166
+ }
7167
+ function MySizingProfilesView({
7168
+ profiles,
7169
+ activeProfileId,
7170
+ onSelectProfile,
7171
+ onEditProfile,
7172
+ onCreateProfile,
7173
+ onDeleteProfile,
7174
+ onClose,
7175
+ t
7176
+ }) {
7177
+ const allHistory = useMemo(() => {
7178
+ const items = [];
7179
+ for (const p of profiles) {
7180
+ for (const h of p.sizeHistory || []) {
7181
+ items.push({ entry: h, profileName: p.name });
7182
+ }
7183
+ }
7184
+ return items.sort((a, b) => b.entry.savedAt - a.entry.savedAt).slice(0, 12);
7185
+ }, [profiles]);
7186
+ return /* @__PURE__ */ jsxs("div", { className: "ps-msp-root", children: [
7187
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-topbar", children: [
7188
+ /* @__PURE__ */ jsx("button", { type: "button", className: "ps-msp-back", onClick: onClose, "aria-label": t("Back"), children: /* @__PURE__ */ jsx(ArrowLeftIcon, {}) }),
7189
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-topbar-title", children: t("MY SIZING PROFILES") }),
7190
+ /* @__PURE__ */ jsx("span", { className: "ps-msp-topbar-spacer" })
7191
+ ] }),
7192
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-scroll", children: [
7193
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-header", children: [
7194
+ /* @__PURE__ */ jsx("h2", { className: "ps-msp-title", children: t("My Sizing Profiles") }),
7195
+ /* @__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.") })
7196
+ ] }),
7197
+ /* @__PURE__ */ jsxs("div", { className: "ps-msp-grid", children: [
7198
+ /* @__PURE__ */ jsx(CreateProfileCard, { onClick: onCreateProfile, t }),
7199
+ profiles.map((p) => /* @__PURE__ */ jsx(
7200
+ ProfileCard,
7201
+ {
7202
+ profile: p,
7203
+ isActive: p.id === activeProfileId,
7204
+ onSelect: () => onSelectProfile(p.id),
7205
+ onEdit: () => onEditProfile(p),
7206
+ t
7207
+ },
7208
+ p.id
7209
+ ))
7210
+ ] }),
7211
+ allHistory.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ps-msp-history-section", children: [
7212
+ /* @__PURE__ */ jsx("h3", { className: "ps-msp-history-title", children: t("Recent Size Calculations") }),
7213
+ /* @__PURE__ */ jsx("div", { className: "ps-msp-history-list", children: allHistory.map(({ entry, profileName }) => /* @__PURE__ */ jsx(SizeHistoryCard, { entry, profileName, t }, `${entry.productId}-${entry.savedAt}`)) })
7214
+ ] })
7215
+ ] })
7216
+ ] });
7217
+ }
6577
7218
  function ResultView({ setView }) {
6578
7219
  useEffect(() => {
6579
7220
  setView("size-result");
@@ -7696,6 +8337,7 @@ if (typeof document !== "undefined") {
7696
8337
  function PrimeStyleTryonInner({
7697
8338
  productImage,
7698
8339
  productTitle = "Product",
8340
+ productId,
7699
8341
  buttonText,
7700
8342
  apiUrl,
7701
8343
  showPoweredBy = true,
@@ -7715,6 +8357,7 @@ function PrimeStyleTryonInner({
7715
8357
  onError,
7716
8358
  sizeGuideData
7717
8359
  }) {
8360
+ const effectiveProductId = productId || productImage;
7718
8361
  const [activeLocale, setActiveLocale] = useState(() => locale || "");
7719
8362
  useEffect(() => {
7720
8363
  if (locale !== void 0) setActiveLocale(locale);
@@ -7732,6 +8375,7 @@ function PrimeStyleTryonInner({
7732
8375
  const [sizingMethod, setSizingMethod] = useState(null);
7733
8376
  const [sizingResult, setSizingResult] = useState(null);
7734
8377
  const [sizingLoading, setSizingLoading] = useState(false);
8378
+ const [estimationDone, setEstimationDone] = useState(false);
7735
8379
  const [tryOnProcessing, setTryOnProcessing] = useState(false);
7736
8380
  const [sizeGuide, setSizeGuide] = useState(null);
7737
8381
  const [sizeGuideFetching, setSizeGuideFetching] = useState(false);
@@ -7748,7 +8392,11 @@ function PrimeStyleTryonInner({
7748
8392
  const [estimationLoading, setEstimationLoading] = useState(false);
7749
8393
  const [profiles, setProfiles] = useState(() => lsGet("profiles", []));
7750
8394
  const [history, setHistory] = useState(() => lsGet("history", []));
7751
- const [activeProfileId, setActiveProfileId] = useState(null);
8395
+ const [activeProfileId, setActiveProfileIdState] = useState(() => getActiveProfileId());
8396
+ const setActiveProfileId$1 = useCallback((id) => {
8397
+ setActiveProfileIdState(id);
8398
+ setActiveProfileId(id);
8399
+ }, []);
7752
8400
  const [profileSaved, setProfileSaved] = useState(false);
7753
8401
  const [drawer, setDrawer] = useState(null);
7754
8402
  const [profileDetail, setProfileDetail] = useState(null);
@@ -7887,6 +8535,69 @@ function PrimeStyleTryonInner({
7887
8535
  return 1;
7888
8536
  }
7889
8537
  }, [view]);
8538
+ const persistResultToProfile = useCallback(
8539
+ (formData, recommendation) => {
8540
+ let targetId = activeProfileId;
8541
+ let target = profiles.find((p) => p.id === targetId);
8542
+ if (!target) {
8543
+ const newProfile = {
8544
+ id: Date.now().toString(36) + Math.random().toString(36).slice(2, 6),
8545
+ name: formData.gender === "female" ? "My Profile" : "My Profile",
8546
+ gender: formData.gender,
8547
+ height: formData.height,
8548
+ weight: formData.weight,
8549
+ age: formData.age,
8550
+ heightUnit: formData.heightUnit,
8551
+ weightUnit: formData.weightUnit,
8552
+ chestProfile: formData.chestProfile,
8553
+ midsectionProfile: formData.midsectionProfile,
8554
+ hipProfile: formData.hipProfile,
8555
+ bandSize: formData.bandSize,
8556
+ cupSize: formData.cupSize,
8557
+ createdAt: Date.now(),
8558
+ lastUsedAt: Date.now()
8559
+ };
8560
+ setProfiles((prev) => [newProfile, ...prev]);
8561
+ setActiveProfileId$1(newProfile.id);
8562
+ targetId = newProfile.id;
8563
+ target = newProfile;
8564
+ }
8565
+ estimateFullMeasurements({
8566
+ apiUrl,
8567
+ height: formData.height,
8568
+ weight: formData.weight,
8569
+ heightUnit: formData.heightUnit,
8570
+ weightUnit: formData.weightUnit,
8571
+ gender: formData.gender,
8572
+ age: formData.age,
8573
+ chestProfile: formData.chestProfile,
8574
+ midsectionProfile: formData.midsectionProfile,
8575
+ hipProfile: formData.hipProfile,
8576
+ bodyImage: formData.bodyImage
8577
+ }).then((est) => {
8578
+ if (!est || !targetId) return;
8579
+ updateProfileMeasurements(targetId, est.estimates, est.unit);
8580
+ setProfiles(lsGet("profiles", []));
8581
+ }).catch(() => {
8582
+ }).finally(() => setEstimationDone(true));
8583
+ if (recommendation?.recommendedSize && targetId) {
8584
+ const sectionsMap = recommendation.sections ? Object.fromEntries(
8585
+ Object.entries(recommendation.sections).map(([name, sec]) => [name, sec.recommendedSize])
8586
+ ) : void 0;
8587
+ addSizeToHistory(targetId, {
8588
+ productId: effectiveProductId,
8589
+ productTitle,
8590
+ productImage,
8591
+ recommendedSize: recommendation.recommendedSize,
8592
+ confidence: recommendation.confidence,
8593
+ sections: sectionsMap,
8594
+ savedAt: Date.now()
8595
+ });
8596
+ setProfiles(lsGet("profiles", []));
8597
+ }
8598
+ },
8599
+ [activeProfileId, profiles, apiUrl, productImage, productTitle, effectiveProductId, setActiveProfileId$1]
8600
+ );
7890
8601
  const applyProfileRef = useRef(() => {
7891
8602
  });
7892
8603
  const handleOpen = useCallback(() => {
@@ -8093,6 +8804,7 @@ function PrimeStyleTryonInner({
8093
8804
  if (formRef.current.hipProfile) qe.hipProfile = formRef.current.hipProfile;
8094
8805
  payload.quickEstimate = qe;
8095
8806
  }
8807
+ setEstimationDone(false);
8096
8808
  try {
8097
8809
  const res = await fetch(`${baseUrl}/api/v1/sizing/recommend`, {
8098
8810
  method: "POST",
@@ -8104,20 +8816,39 @@ function PrimeStyleTryonInner({
8104
8816
  console.log("[PS-SDK] Sizing recommend RESULT:", JSON.stringify(data));
8105
8817
  setSizingResult(data);
8106
8818
  onComplete?.(data);
8819
+ const m = payload.measurements || {};
8820
+ const qe = payload.quickEstimate || {};
8821
+ const src = method === "exact" ? m : qe;
8822
+ persistResultToProfile(
8823
+ {
8824
+ gender: src.gender || "male",
8825
+ height: Number(src.height || src.heightCm || 0),
8826
+ weight: Number(src.weight || src.weightKg || 0),
8827
+ heightUnit: src.heightUnit || "cm",
8828
+ weightUnit: src.weightUnit || "kg",
8829
+ age: src.age != null ? Number(src.age) : void 0,
8830
+ chestProfile: src.chestProfile,
8831
+ midsectionProfile: src.midsectionProfile,
8832
+ hipProfile: src.hipProfile
8833
+ },
8834
+ data
8835
+ );
8107
8836
  } else {
8108
8837
  const errBody = await res.text().catch(() => "");
8109
8838
  console.error("[PS-SDK] Sizing recommend failed:", res.status, errBody);
8110
8839
  setErrorMessage(t("Unable to get size recommendation. Please try again."));
8111
8840
  setView("error");
8841
+ setEstimationDone(true);
8112
8842
  }
8113
8843
  } catch (err) {
8114
8844
  console.error("[PS-SDK] Sizing recommend network error:", err);
8115
8845
  setErrorMessage(t("Unable to connect to sizing service. Please try again."));
8116
8846
  setView("error");
8847
+ setEstimationDone(true);
8117
8848
  } finally {
8118
8849
  setSizingLoading(false);
8119
8850
  }
8120
- }, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productTitle, dynamicFields]);
8851
+ }, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productTitle, dynamicFields, persistResultToProfile]);
8121
8852
  const handleQuickEstimate = useCallback(async (height, weight, heightUnit2, weightUnit2, gender, age, bodyType, chestProfile, midsectionProfile, hipProfile, bodyImage) => {
8122
8853
  if (!apiRef.current) return;
8123
8854
  getApiUrl(apiUrl);
@@ -8182,6 +8913,7 @@ function PrimeStyleTryonInner({
8182
8913
  setSizingResult(null);
8183
8914
  setResultImageUrl(null);
8184
8915
  setSizingLoading(true);
8916
+ setEstimationDone(false);
8185
8917
  setView("size-result");
8186
8918
  modelPoseRef.current = null;
8187
8919
  setBodyLandmarks(null);
@@ -8220,11 +8952,26 @@ function PrimeStyleTryonInner({
8220
8952
  const recData = await recRes.json();
8221
8953
  setSizingResult(recData);
8222
8954
  onComplete?.(recData);
8955
+ persistResultToProfile(
8956
+ {
8957
+ gender: data.gender,
8958
+ height: data.height,
8959
+ weight: data.weight,
8960
+ heightUnit: data.heightUnit,
8961
+ weightUnit: data.weightUnit,
8962
+ age: data.age,
8963
+ bodyImage: data.photoBase64
8964
+ },
8965
+ recData
8966
+ );
8967
+ } else {
8968
+ setEstimationDone(true);
8223
8969
  }
8224
8970
  } catch {
8971
+ setEstimationDone(true);
8225
8972
  }
8226
8973
  setSizingLoading(false);
8227
- }, [apiUrl, productImage, productTitle, sizingUnit, weightUnit, sizingCountry, sizeGuide, dynamicFields]);
8974
+ }, [apiUrl, productImage, productTitle, sizingUnit, weightUnit, sizingCountry, sizeGuide, dynamicFields, persistResultToProfile]);
8228
8975
  const handleTryOnSubmit = useCallback(async () => {
8229
8976
  const file = selectedFile || selectedFileRef.current;
8230
8977
  if (!file || !apiRef.current || !sseRef.current) {
@@ -8416,7 +9163,7 @@ function PrimeStyleTryonInner({
8416
9163
  const applyProfile = useCallback((id) => {
8417
9164
  const p = profiles.find((pr) => pr.id === id);
8418
9165
  if (!p) return;
8419
- setActiveProfileId(id);
9166
+ setActiveProfileId$1(id);
8420
9167
  setProfiles((prev) => prev.map((pr) => pr.id === id ? { ...pr, lastUsedAt: Date.now() } : pr));
8421
9168
  const fd = { gender: p.gender || "male" };
8422
9169
  if (p.height ?? p.heightCm) fd.height = String(p.height ?? p.heightCm);
@@ -8511,7 +9258,7 @@ function PrimeStyleTryonInner({
8511
9258
  }
8512
9259
  return [...prev, p].slice(-50);
8513
9260
  });
8514
- setActiveProfileId(id);
9261
+ setActiveProfileId$1(id);
8515
9262
  setProfileSaved(true);
8516
9263
  }, [activeProfileId, sizingCountry, sizingUnit, heightUnit, weightUnit]);
8517
9264
  const saveHistoryEntry = useCallback(() => {
@@ -8726,6 +9473,7 @@ function PrimeStyleTryonInner({
8726
9473
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(
8727
9474
  SizeResultView,
8728
9475
  {
9476
+ estimationDone,
8729
9477
  sizingLoading,
8730
9478
  sizingResult,
8731
9479
  sizeGuide,
@@ -8780,6 +9528,31 @@ function PrimeStyleTryonInner({
8780
9528
  ) }, "v-proc");
8781
9529
  case "result":
8782
9530
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(ResultView, { setView }) }, "v-result");
9531
+ case "profiles":
9532
+ return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(
9533
+ MySizingProfilesView,
9534
+ {
9535
+ profiles,
9536
+ activeProfileId,
9537
+ onSelectProfile: (id) => {
9538
+ setActiveProfileId$1(id);
9539
+ setView("body-profile");
9540
+ },
9541
+ onEditProfile: (p) => {
9542
+ setProfileDetail(p);
9543
+ },
9544
+ onCreateProfile: () => {
9545
+ setActiveProfileId$1(null);
9546
+ formRef.current = {};
9547
+ setFormGender("male");
9548
+ setFormKey((k) => k + 1);
9549
+ setView("body-profile");
9550
+ },
9551
+ onDeleteProfile: (id) => setProfiles((prev) => prev.filter((p) => p.id !== id)),
9552
+ onClose: () => setView("body-profile"),
9553
+ t
9554
+ }
9555
+ ) }, "v-profiles");
8783
9556
  case "error":
8784
9557
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(
8785
9558
  ErrorView,
@@ -8800,10 +9573,10 @@ function PrimeStyleTryonInner({
8800
9573
  /* @__PURE__ */ jsx("span", { children: resolvedButtonText })
8801
9574
  ] }),
8802
9575
  view !== "idle" && typeof document !== "undefined" && createPortal(
8803
- /* @__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: [
9576
+ /* @__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" || view === "profiles" ? " ps-tryon-modal-wide" : ""}`, cn.modal), onClick: (e) => e.stopPropagation(), children: [
8804
9577
  /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-header ps-tryon-header-minimal", cn.header), children: [
8805
9578
  /* @__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, {}) }),
9579
+ /* @__PURE__ */ jsx("button", { className: "ps-tryon-header-icon", title: t("Profiles"), onClick: () => setView(view === "profiles" ? "body-profile" : "profiles"), children: /* @__PURE__ */ jsx(UserIcon, {}) }),
8807
9580
  /* @__PURE__ */ jsx("button", { className: "ps-tryon-header-icon", title: t("History"), onClick: () => setDrawer(drawer === "history" ? null : "history"), children: /* @__PURE__ */ jsx(ClockIcon, {}) }),
8808
9581
  /* @__PURE__ */ jsx("button", { onClick: handleClose, className: cx("ps-tryon-close", cn.closeButton), children: /* @__PURE__ */ jsx(XIcon, {}) })
8809
9582
  ] }),
@@ -8842,7 +9615,7 @@ function PrimeStyleTryonInner({
8842
9615
  setProfileDetail,
8843
9616
  setProfiles,
8844
9617
  activeProfileId,
8845
- setActiveProfileId,
9618
+ setActiveProfileId: setActiveProfileId$1,
8846
9619
  t
8847
9620
  }
8848
9621
  )
@@ -8851,6 +9624,53 @@ function PrimeStyleTryonInner({
8851
9624
  function PrimeStyleTryon(props) {
8852
9625
  return /* @__PURE__ */ jsx(PrimeStyleTryonInner, { ...props });
8853
9626
  }
9627
+ function usePrimeStyleSize(input) {
9628
+ const [result, setResult] = useState(null);
9629
+ const [loading, setLoading] = useState(true);
9630
+ const [noProfile, setNoProfile] = useState(false);
9631
+ const [tick, setTick] = useState(0);
9632
+ useEffect(() => {
9633
+ let cancelled = false;
9634
+ setLoading(true);
9635
+ setNoProfile(false);
9636
+ recommendForProduct(input).then((res) => {
9637
+ if (cancelled) return;
9638
+ if (res === null) {
9639
+ setNoProfile(true);
9640
+ setResult(null);
9641
+ } else {
9642
+ setResult(res);
9643
+ }
9644
+ }).catch(() => {
9645
+ if (!cancelled) setResult(null);
9646
+ }).finally(() => {
9647
+ if (!cancelled) setLoading(false);
9648
+ });
9649
+ return () => {
9650
+ cancelled = true;
9651
+ };
9652
+ }, [input.productId, input.apiUrl, input.apiKey, tick]);
9653
+ return {
9654
+ recommendedSize: result?.recommendedSize ?? null,
9655
+ sections: result?.sections ?? null,
9656
+ loading,
9657
+ noProfile,
9658
+ result,
9659
+ refetch: () => setTick((n) => n + 1)
9660
+ };
9661
+ }
8854
9662
  export {
8855
- PrimeStyleTryon
9663
+ PrimeStyleTryon,
9664
+ addSizeToHistory,
9665
+ estimateFullMeasurements,
9666
+ getActiveProfile,
9667
+ getActiveProfileId,
9668
+ getCachedSize,
9669
+ getProfiles,
9670
+ recommendForProduct,
9671
+ saveProfiles,
9672
+ setActiveProfileId,
9673
+ updateProfile,
9674
+ updateProfileMeasurements,
9675
+ usePrimeStyleSize
8856
9676
  };