@primestyleai/tryon 5.5.25 → 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,6 +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 });
6292
+ const analyzingDone = estimationDone;
5794
6293
  const handleImgLoad = useCallback((e) => {
5795
6294
  const el = e.currentTarget;
5796
6295
  if (el.naturalWidth && el.naturalHeight) {
@@ -5960,12 +6459,12 @@ function SizeResultView({
5960
6459
  /* @__PURE__ */ jsx("span", { children: t("Detecting body pose") })
5961
6460
  ] }),
5962
6461
  !sizingDone && /* @__PURE__ */ jsxs(Fragment, { children: [
5963
- /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${bodyLandmarks ? " ps-active" : ""}`, children: [
5964
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: bodyLandmarks ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) : /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "2" }) }),
6462
+ /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-done" : bodyLandmarks ? " ps-active" : ""}`, children: [
6463
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: !bodyLandmarks ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "2" }) : !analyzingDone ? /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) : /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-check", children: "" }) }),
5965
6464
  /* @__PURE__ */ jsx("span", { children: t("Analyzing your size") })
5966
6465
  ] }),
5967
- /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step`, children: [
5968
- /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "3" }) }),
6466
+ /* @__PURE__ */ jsxs("div", { className: `ps-tryon-snap-step${analyzingDone ? " ps-active" : ""}`, children: [
6467
+ /* @__PURE__ */ jsx("div", { className: "ps-tryon-snap-step-icon", children: !analyzingDone ? /* @__PURE__ */ jsx("span", { className: "ps-tryon-snap-num", children: "3" }) : /* @__PURE__ */ jsx("div", { className: "ps-tryon-size-loading-spinner", style: { width: "1vw", height: "1vw", borderWidth: "1.5px" } }) }),
5969
6468
  /* @__PURE__ */ jsx("span", { children: t("Finding best fit for you") })
5970
6469
  ] })
5971
6470
  ] }),
@@ -6565,6 +7064,154 @@ function ErrorView({
6565
7064
  /* @__PURE__ */ jsx("button", { onClick: handleRetry, className: cx("ps-tryon-submit", cn.submitButton), children: t("Try Again") })
6566
7065
  ] });
6567
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
+ }
6568
7215
  function ResultView({ setView }) {
6569
7216
  useEffect(() => {
6570
7217
  setView("size-result");
@@ -7687,6 +8334,7 @@ if (typeof document !== "undefined") {
7687
8334
  function PrimeStyleTryonInner({
7688
8335
  productImage,
7689
8336
  productTitle = "Product",
8337
+ productId,
7690
8338
  buttonText,
7691
8339
  apiUrl,
7692
8340
  showPoweredBy = true,
@@ -7706,6 +8354,7 @@ function PrimeStyleTryonInner({
7706
8354
  onError,
7707
8355
  sizeGuideData
7708
8356
  }) {
8357
+ const effectiveProductId = productId || productImage;
7709
8358
  const [activeLocale, setActiveLocale] = useState(() => locale || "");
7710
8359
  useEffect(() => {
7711
8360
  if (locale !== void 0) setActiveLocale(locale);
@@ -7723,6 +8372,7 @@ function PrimeStyleTryonInner({
7723
8372
  const [sizingMethod, setSizingMethod] = useState(null);
7724
8373
  const [sizingResult, setSizingResult] = useState(null);
7725
8374
  const [sizingLoading, setSizingLoading] = useState(false);
8375
+ const [estimationDone, setEstimationDone] = useState(false);
7726
8376
  const [tryOnProcessing, setTryOnProcessing] = useState(false);
7727
8377
  const [sizeGuide, setSizeGuide] = useState(null);
7728
8378
  const [sizeGuideFetching, setSizeGuideFetching] = useState(false);
@@ -7739,7 +8389,11 @@ function PrimeStyleTryonInner({
7739
8389
  const [estimationLoading, setEstimationLoading] = useState(false);
7740
8390
  const [profiles, setProfiles] = useState(() => lsGet("profiles", []));
7741
8391
  const [history, setHistory] = useState(() => lsGet("history", []));
7742
- const [activeProfileId, setActiveProfileId] = useState(null);
8392
+ const [activeProfileId, setActiveProfileIdState] = useState(() => getActiveProfileId());
8393
+ const setActiveProfileId$1 = useCallback((id) => {
8394
+ setActiveProfileIdState(id);
8395
+ setActiveProfileId(id);
8396
+ }, []);
7743
8397
  const [profileSaved, setProfileSaved] = useState(false);
7744
8398
  const [drawer, setDrawer] = useState(null);
7745
8399
  const [profileDetail, setProfileDetail] = useState(null);
@@ -7878,6 +8532,69 @@ function PrimeStyleTryonInner({
7878
8532
  return 1;
7879
8533
  }
7880
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
+ );
7881
8598
  const applyProfileRef = useRef(() => {
7882
8599
  });
7883
8600
  const handleOpen = useCallback(() => {
@@ -8084,6 +8801,7 @@ function PrimeStyleTryonInner({
8084
8801
  if (formRef.current.hipProfile) qe.hipProfile = formRef.current.hipProfile;
8085
8802
  payload.quickEstimate = qe;
8086
8803
  }
8804
+ setEstimationDone(false);
8087
8805
  try {
8088
8806
  const res = await fetch(`${baseUrl}/api/v1/sizing/recommend`, {
8089
8807
  method: "POST",
@@ -8095,20 +8813,39 @@ function PrimeStyleTryonInner({
8095
8813
  console.log("[PS-SDK] Sizing recommend RESULT:", JSON.stringify(data));
8096
8814
  setSizingResult(data);
8097
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
+ );
8098
8833
  } else {
8099
8834
  const errBody = await res.text().catch(() => "");
8100
8835
  console.error("[PS-SDK] Sizing recommend failed:", res.status, errBody);
8101
8836
  setErrorMessage(t("Unable to get size recommendation. Please try again."));
8102
8837
  setView("error");
8838
+ setEstimationDone(true);
8103
8839
  }
8104
8840
  } catch (err) {
8105
8841
  console.error("[PS-SDK] Sizing recommend network error:", err);
8106
8842
  setErrorMessage(t("Unable to connect to sizing service. Please try again."));
8107
8843
  setView("error");
8844
+ setEstimationDone(true);
8108
8845
  } finally {
8109
8846
  setSizingLoading(false);
8110
8847
  }
8111
- }, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productTitle, dynamicFields]);
8848
+ }, [apiUrl, sizingMethod, sizingCountry, heightUnit, weightUnit, sizingUnit, sizeGuide, productTitle, dynamicFields, persistResultToProfile]);
8112
8849
  const handleQuickEstimate = useCallback(async (height, weight, heightUnit2, weightUnit2, gender, age, bodyType, chestProfile, midsectionProfile, hipProfile, bodyImage) => {
8113
8850
  if (!apiRef.current) return;
8114
8851
  getApiUrl(apiUrl);
@@ -8173,6 +8910,7 @@ function PrimeStyleTryonInner({
8173
8910
  setSizingResult(null);
8174
8911
  setResultImageUrl(null);
8175
8912
  setSizingLoading(true);
8913
+ setEstimationDone(false);
8176
8914
  setView("size-result");
8177
8915
  modelPoseRef.current = null;
8178
8916
  setBodyLandmarks(null);
@@ -8211,11 +8949,26 @@ function PrimeStyleTryonInner({
8211
8949
  const recData = await recRes.json();
8212
8950
  setSizingResult(recData);
8213
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);
8214
8966
  }
8215
8967
  } catch {
8968
+ setEstimationDone(true);
8216
8969
  }
8217
8970
  setSizingLoading(false);
8218
- }, [apiUrl, productImage, productTitle, sizingUnit, weightUnit, sizingCountry, sizeGuide, dynamicFields]);
8971
+ }, [apiUrl, productImage, productTitle, sizingUnit, weightUnit, sizingCountry, sizeGuide, dynamicFields, persistResultToProfile]);
8219
8972
  const handleTryOnSubmit = useCallback(async () => {
8220
8973
  const file = selectedFile || selectedFileRef.current;
8221
8974
  if (!file || !apiRef.current || !sseRef.current) {
@@ -8407,7 +9160,7 @@ function PrimeStyleTryonInner({
8407
9160
  const applyProfile = useCallback((id) => {
8408
9161
  const p = profiles.find((pr) => pr.id === id);
8409
9162
  if (!p) return;
8410
- setActiveProfileId(id);
9163
+ setActiveProfileId$1(id);
8411
9164
  setProfiles((prev) => prev.map((pr) => pr.id === id ? { ...pr, lastUsedAt: Date.now() } : pr));
8412
9165
  const fd = { gender: p.gender || "male" };
8413
9166
  if (p.height ?? p.heightCm) fd.height = String(p.height ?? p.heightCm);
@@ -8502,7 +9255,7 @@ function PrimeStyleTryonInner({
8502
9255
  }
8503
9256
  return [...prev, p].slice(-50);
8504
9257
  });
8505
- setActiveProfileId(id);
9258
+ setActiveProfileId$1(id);
8506
9259
  setProfileSaved(true);
8507
9260
  }, [activeProfileId, sizingCountry, sizingUnit, heightUnit, weightUnit]);
8508
9261
  const saveHistoryEntry = useCallback(() => {
@@ -8717,6 +9470,7 @@ function PrimeStyleTryonInner({
8717
9470
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(
8718
9471
  SizeResultView,
8719
9472
  {
9473
+ estimationDone,
8720
9474
  sizingLoading,
8721
9475
  sizingResult,
8722
9476
  sizeGuide,
@@ -8771,6 +9525,28 @@ function PrimeStyleTryonInner({
8771
9525
  ) }, "v-proc");
8772
9526
  case "result":
8773
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");
8774
9550
  case "error":
8775
9551
  return /* @__PURE__ */ jsx("div", { className: "ps-tryon-view-enter", children: /* @__PURE__ */ jsx(
8776
9552
  ErrorView,
@@ -8794,7 +9570,7 @@ function PrimeStyleTryonInner({
8794
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: [
8795
9571
  /* @__PURE__ */ jsxs("div", { className: cx("ps-tryon-header ps-tryon-header-minimal", cn.header), children: [
8796
9572
  /* @__PURE__ */ jsx(LangSwitcher, { activeLocale, onSelect: setActiveLocale }),
8797
- /* @__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, {}) }),
8798
9574
  /* @__PURE__ */ jsx("button", { className: "ps-tryon-header-icon", title: t("History"), onClick: () => setDrawer(drawer === "history" ? null : "history"), children: /* @__PURE__ */ jsx(ClockIcon, {}) }),
8799
9575
  /* @__PURE__ */ jsx("button", { onClick: handleClose, className: cx("ps-tryon-close", cn.closeButton), children: /* @__PURE__ */ jsx(XIcon, {}) })
8800
9576
  ] }),
@@ -8833,7 +9609,7 @@ function PrimeStyleTryonInner({
8833
9609
  setProfileDetail,
8834
9610
  setProfiles,
8835
9611
  activeProfileId,
8836
- setActiveProfileId,
9612
+ setActiveProfileId: setActiveProfileId$1,
8837
9613
  t
8838
9614
  }
8839
9615
  )
@@ -8842,6 +9618,53 @@ function PrimeStyleTryonInner({
8842
9618
  function PrimeStyleTryon(props) {
8843
9619
  return /* @__PURE__ */ jsx(PrimeStyleTryonInner, { ...props });
8844
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
+ }
8845
9656
  export {
8846
- 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
8847
9670
  };