@thefittingroom/shop-ui 5.0.8 → 5.0.10

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.
Files changed (2) hide show
  1. package/dist/index.js +327 -158
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -19034,7 +19034,7 @@ const en$1 = {
19034
19034
  "get-app": { "create_avatar": "Create your avatar" },
19035
19035
  "sign-in": { "email": "Email", "password": "Password", "forgot_password": "Forgot password?", "sign_in": "Sign in", "no_account": "Don’t have an account?", "download_app": "Download the app.", "invalid_email": "Please enter a valid email address.", "missing_password": "Please enter your password.", "login_failed": "Incorrect email or password." },
19036
19036
  "forgot-password": { "title": "Forgot password", "description": "We’ll send you an email with a link to reset your password.", "send_link": "Send link", "link_sent": "Link sent! Please check your email.", "need_help": "Need help?", "contact_us": "Contact us." },
19037
- "vto-single": { "avatar_loading": "Finding your perfect fit...", "slide_to_rotate": "Slide to rotate", "sign_out": "Sign out", "color_label": "Color:", "add_to_cart": "Add to cart", "view_product_details": "View product details", "hide_product_details": "Hide product details" },
19037
+ "vto-single": { "avatar_loading": "Finding your perfect fit...", "slide_to_rotate": "Slide to rotate", "sign_out": "Sign out", "color_label": "Color:", "add_to_cart": "Add to cart", "view_product_details": "View product details", "hide_product_details": "Hide product details", "no_recommendation": "There are currently no well fitting sizes available for this item." },
19038
19038
  "size-rec": { "recommended_size": "Recommended Size: {{size}}", "item_fit": "This item is {{fit}}", "select_size": "Select a size to see how it fits", "fitClassification": { "form_fitting": "Form Fitting", "slim_fit": "Slim Fit", "regular_fit": "Regular Fit", "relaxed_fit": "Relaxed Fit", "oversized_fit": "Oversized Fit" }, "measurementLocation": { "neck_base": "Neck", "across_shoulder": "Shoulders", "cb_neck_to_wrist": "Neck to Wrist", "sleeve_length_from_shoulder_point": "Sleeve", "bust": "Bust", "waist": "Waist", "low_waist": "Low Waist", "high_hip": "High Hip", "low_hip": "Low Hip", "thigh": "Thigh", "inseam": "Inseam", "hsp_to_low_hip": "HSP to Low Hip", "hsp_to_crotch": "HSP to Crotch", "low_hip_bottoms": "Low Hip (Bottoms)", "high_hip_bottoms": "High Hip (Bottoms)" }, "fit": { "too_tight": "Too Tight", "tight": "Tight", "slightly_tight": "Slightly Tight", "perfect_fit": "Perfect Fit", "slightly_loose": "Slightly Loose", "loose": "Loose", "oversized": "Oversized", "too_short": "Too Short", "short": "Short", "slightly_short": "Slightly Short", "slightly_long": "Slightly Long", "long": "Long", "too_long": "Too Long" } },
19039
19039
  "fit-chart": { "fit_scale": "Fit Scale", "fit": { "poor_fit": "Poor Fit", "acceptable_fit": "Acceptable Fit", "too_tight": "Too Tight", "tight": "Tight or More Fitted", "slightly_tight": "Slightly Tight or Fitted", "perfect_fit": "Perfect Fit", "slightly_loose": "Slightly Loose or Less Fitted", "loose": "Loose or Not Fitted", "oversized": "Oversized" }, "measurement_points": "Measurement Points", "point": { "bust": "Chest/Bust", "waist": "Natural Waist", "pant_waist": "Pant Waist", "high_hip": "High Hip", "low_hip": "Low Hip", "thigh": "Thigh" } }
19040
19040
  };
@@ -19050,7 +19050,7 @@ const fr = {
19050
19050
  "get-app": { "create_avatar": "Créez votre avatar" },
19051
19051
  "sign-in": { "email": "Email", "password": "Mot de passe", "forgot_password": "Mot de passe oublié ?", "sign_in": "Se connecter", "no_account": "Vous n'avez pas de compte ?", "download_app": "Téléchargez l'application.", "invalid_email": "Veuillez entrer une adresse e-mail valide.", "missing_password": "Veuillez entrer votre mot de passe.", "login_failed": "Email ou mot de passe incorrect." },
19052
19052
  "forgot-password": { "title": "Mot de passe oublié", "description": "Nous vous enverrons un e-mail avec un lien pour réinitialiser votre mot de passe.", "send_link": "Envoyer le lien", "link_sent": "Lien envoyé ! Veuillez vérifier votre e-mail.", "need_help": "Besoin d'aide ?", "contact_us": "Contactez-nous." },
19053
- "vto-single": { "avatar_loading": "Trouver votre ajustement parfait...", "slide_to_rotate": "Faites glisser pour faire pivoter", "sign_out": "Se déconnecter", "color_label": "Couleur :", "add_to_cart": "Ajouter au panier", "view_product_details": "Voir les détails du produit", "hide_product_details": "Masquer les détails du produit" },
19053
+ "vto-single": { "avatar_loading": "Trouver votre ajustement parfait...", "slide_to_rotate": "Faites glisser pour faire pivoter", "sign_out": "Se déconnecter", "color_label": "Couleur :", "add_to_cart": "Ajouter au panier", "view_product_details": "Voir les détails du produit", "hide_product_details": "Masquer les détails du produit", "no_recommendation": "Il n'y a actuellement pas de tailles bien ajustées disponibles pour cet article." },
19054
19054
  "size-rec": { "recommended_size": "Taille recommandée : {{size}}", "item_fit": "Cet article est {{fit}}", "select_size": "Sélectionnez une taille pour voir comment elle s'adapte", "fitClassification": { "form_fitting": "Ajusté", "slim_fit": "Coupe slim", "regular_fit": "Coupe régulière", "relaxed_fit": "Coupe décontractée", "oversized_fit": "Coupe oversize" }, "measurementLocation": { "neck_base": "Cou", "across_shoulder": "Épaules", "cb_neck_to_wrist": "Cou jusqu'au poignet", "sleeve_length_from_shoulder_point": "Manche", "bust": "Buste", "waist": "Taille", "low_waist": "Bas de la taille", "high_hip": "Haut des hanches", "low_hip": "Bas des hanches", "thigh": "Cuisse", "inseam": "Entrejambe", "hsp_to_low_hip": "HSP au bas des hanches", "hsp_to_crotch": "HSP à l'entrejambe", "low_hip_bottoms": "Bas des hanches (bas)", "high_hip_bottoms": "Haut des hanches (bas)" }, "fit": { "too_tight": "Trop serré", "tight": "Serré", "slightly_tight": "Légèrement serré", "perfect_fit": "Parfait", "slightly_loose": "Légèrement ample", "loose": "Ample", "oversized": "Oversize", "too_short": "Trop court", "short": "Court", "slightly_short": "Légèrement court", "slightly_long": "Légèrement long", "long": "Long", "too_long": "Trop long" } },
19055
19055
  "fit-chart": { "fit_scale": "Échelle d'ajustement", "fit": { "poor_fit": "Mauvais ajustement", "acceptable_fit": "Ajustement acceptable", "too_tight": "Trop serré", "tight": "Serré ou plus ajusté", "slightly_tight": "Légèrement serré ou ajusté", "perfect_fit": "Parfait", "slightly_loose": "Légèrement ample ou moins ajusté", "loose": "Ample ou non ajusté", "oversized": "Oversize" }, "measurement_points": "Points de mesure", "point": { "bust": "Poitrine/Buste", "waist": "Taille naturelle", "pant_waist": "Taille du pantalon", "high_hip": "Haut des hanches", "low_hip": "Bas des hanches", "thigh": "Cuisse" } }
19056
19056
  };
@@ -22677,7 +22677,7 @@ function isVersionServiceProvider(provider) {
22677
22677
  }
22678
22678
  const name$q = "@firebase/app";
22679
22679
  const version$1$1 = "0.14.5";
22680
- const logger$5 = new Logger$1("@firebase/app");
22680
+ const logger$6 = new Logger$1("@firebase/app");
22681
22681
  const name$p = "@firebase/app-compat";
22682
22682
  const name$o = "@firebase/analytics-compat";
22683
22683
  const name$n = "@firebase/analytics";
@@ -22744,13 +22744,13 @@ function _addComponent(app, component) {
22744
22744
  try {
22745
22745
  app.container.addComponent(component);
22746
22746
  } catch (e) {
22747
- logger$5.debug(`Component ${component.name} failed to register with FirebaseApp ${app.name}`, e);
22747
+ logger$6.debug(`Component ${component.name} failed to register with FirebaseApp ${app.name}`, e);
22748
22748
  }
22749
22749
  }
22750
22750
  function _registerComponent(component) {
22751
22751
  const componentName = component.name;
22752
22752
  if (_components.has(componentName)) {
22753
- logger$5.debug(`There were multiple attempts to register component ${componentName}.`);
22753
+ logger$6.debug(`There were multiple attempts to register component ${componentName}.`);
22754
22754
  return false;
22755
22755
  }
22756
22756
  _components.set(componentName, component);
@@ -22959,7 +22959,7 @@ function registerVersion(libraryKeyOrName, version2, variant) {
22959
22959
  if (versionMismatch) {
22960
22960
  warning.push(`version name "${version2}" contains illegal characters (whitespace or "/")`);
22961
22961
  }
22962
- logger$5.warn(warning.join(" "));
22962
+ logger$6.warn(warning.join(" "));
22963
22963
  return;
22964
22964
  }
22965
22965
  _registerComponent(new Component(
@@ -23003,12 +23003,12 @@ async function readHeartbeatsFromIndexedDB(app) {
23003
23003
  return result;
23004
23004
  } catch (e) {
23005
23005
  if (e instanceof FirebaseError) {
23006
- logger$5.warn(e.message);
23006
+ logger$6.warn(e.message);
23007
23007
  } else {
23008
23008
  const idbGetError = ERROR_FACTORY.create("idb-get", {
23009
23009
  originalErrorMessage: e?.message
23010
23010
  });
23011
- logger$5.warn(idbGetError.message);
23011
+ logger$6.warn(idbGetError.message);
23012
23012
  }
23013
23013
  }
23014
23014
  }
@@ -23021,12 +23021,12 @@ async function writeHeartbeatsToIndexedDB(app, heartbeatObject) {
23021
23021
  await tx.done;
23022
23022
  } catch (e) {
23023
23023
  if (e instanceof FirebaseError) {
23024
- logger$5.warn(e.message);
23024
+ logger$6.warn(e.message);
23025
23025
  } else {
23026
23026
  const idbGetError = ERROR_FACTORY.create("idb-set", {
23027
23027
  originalErrorMessage: e?.message
23028
23028
  });
23029
- logger$5.warn(idbGetError.message);
23029
+ logger$6.warn(idbGetError.message);
23030
23030
  }
23031
23031
  }
23032
23032
  }
@@ -23075,7 +23075,7 @@ class HeartbeatServiceImpl {
23075
23075
  }
23076
23076
  return this._storage.overwrite(this._heartbeatsCache);
23077
23077
  } catch (e) {
23078
- logger$5.warn(e);
23078
+ logger$6.warn(e);
23079
23079
  }
23080
23080
  }
23081
23081
  /**
@@ -23106,7 +23106,7 @@ class HeartbeatServiceImpl {
23106
23106
  }
23107
23107
  return headerString;
23108
23108
  } catch (e) {
23109
- logger$5.warn(e);
23109
+ logger$6.warn(e);
23110
23110
  return "";
23111
23111
  }
23112
23112
  }
@@ -40670,103 +40670,144 @@ registerAuth(
40670
40670
  "Browser"
40671
40671
  /* ClientPlatform.BROWSER */
40672
40672
  );
40673
- let sourceRegExp = false;
40673
+ let debugSource = false;
40674
40674
  function _init$4(debug) {
40675
40675
  if (debug) {
40676
40676
  let escapeRegExp = function(string) {
40677
- return string.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
40677
+ return "^" + string.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".") + "$";
40678
40678
  };
40679
40679
  if (debug === true) {
40680
- sourceRegExp = /.*/;
40680
+ debugSource = true;
40681
40681
  } else if (debug instanceof RegExp) {
40682
- sourceRegExp = debug;
40682
+ debugSource = debug;
40683
40683
  } else if (Array.isArray(debug)) {
40684
- sourceRegExp = new RegExp(debug.map((s) => escapeRegExp(s)).join("|"));
40684
+ debugSource = new RegExp(debug.map((s) => escapeRegExp(s)).join("|"));
40685
40685
  } else if (typeof debug === "string") {
40686
- sourceRegExp = new RegExp(escapeRegExp(debug));
40686
+ debugSource = new RegExp(escapeRegExp(debug));
40687
40687
  }
40688
40688
  }
40689
40689
  }
40690
40690
  function isDebugSource(source) {
40691
- if (!sourceRegExp) {
40692
- return false;
40691
+ if (typeof debugSource === "boolean") {
40692
+ return debugSource;
40693
40693
  }
40694
- return sourceRegExp.test(source);
40694
+ return debugSource.test(source);
40695
40695
  }
40696
40696
  function log(entry) {
40697
40697
  const {
40698
40698
  source,
40699
40699
  level,
40700
40700
  message,
40701
- data
40701
+ data,
40702
+ duration
40702
40703
  } = entry;
40703
- const logMessage = `[TFR ${source}][${level.toUpperCase()}] ${message}`;
40704
+ if (level === "debug" && !isDebugSource(source)) {
40705
+ return;
40706
+ }
40707
+ let finalMessage = message;
40708
+ if (finalMessage.includes("{{")) {
40709
+ finalMessage = finalMessage.replace(/{{ts}}/g, (/* @__PURE__ */ new Date()).toISOString());
40710
+ }
40711
+ finalMessage = `[TFR ${source}][${level.toUpperCase()}] ${finalMessage}`;
40712
+ const logData = [finalMessage];
40713
+ if (duration !== void 0) {
40714
+ logData.push(`${duration.toFixed(2)} ms`);
40715
+ }
40716
+ if (data) {
40717
+ logData.push(data);
40718
+ }
40704
40719
  switch (level) {
40705
40720
  case "error":
40706
- console.error(logMessage, ...data);
40721
+ console.error(...logData);
40707
40722
  break;
40708
40723
  case "warn":
40709
- console.warn(logMessage, ...data);
40724
+ console.warn(...logData);
40710
40725
  break;
40711
40726
  case "info":
40712
- console.info(logMessage, ...data);
40727
+ console.info(...logData);
40713
40728
  break;
40714
40729
  case "debug":
40715
- if (isDebugSource(source)) {
40716
- console.debug(logMessage, ...data);
40717
- }
40730
+ console.debug(...logData);
40718
40731
  break;
40719
40732
  default:
40720
- console.log(logMessage, ...data);
40733
+ console.log(...logData);
40721
40734
  }
40722
40735
  }
40723
- function logError(source, message, ...data) {
40724
- log({
40725
- source,
40726
- level: "error",
40727
- message,
40728
- data
40729
- });
40730
- }
40731
- function logWarn(source, message, ...data) {
40732
- log({
40733
- source,
40734
- level: "warn",
40735
- message,
40736
- data
40737
- });
40738
- }
40739
- function logInfo(source, message, ...data) {
40740
- log({
40741
- source,
40742
- level: "info",
40743
- message,
40744
- data
40745
- });
40746
- }
40747
- function logDebug(source, message, ...data) {
40748
- log({
40749
- source,
40750
- level: "debug",
40751
- message,
40752
- data
40753
- });
40754
- }
40755
40736
  class Logger3 {
40756
40737
  constructor(source) {
40738
+ this.timers = {};
40757
40739
  this.source = source;
40758
40740
  }
40759
- logError(message, ...data) {
40760
- logError(this.source, message, ...data);
40741
+ logError(message, data = null) {
40742
+ log({
40743
+ source: this.source,
40744
+ level: "error",
40745
+ message,
40746
+ data
40747
+ });
40748
+ }
40749
+ logWarn(message, data = null) {
40750
+ log({
40751
+ source: this.source,
40752
+ level: "warn",
40753
+ message,
40754
+ data
40755
+ });
40756
+ }
40757
+ logInfo(message, data = null) {
40758
+ log({
40759
+ source: this.source,
40760
+ level: "info",
40761
+ message,
40762
+ data
40763
+ });
40764
+ }
40765
+ logDebug(message, data = null) {
40766
+ log({
40767
+ source: this.source,
40768
+ level: "debug",
40769
+ message,
40770
+ data
40771
+ });
40761
40772
  }
40762
- logWarn(message, ...data) {
40763
- logWarn(this.source, message, ...data);
40773
+ logTimer(timerName, message, data = null) {
40774
+ const duration = this.getTimerDuration(timerName);
40775
+ log({
40776
+ source: this.source,
40777
+ level: "debug",
40778
+ message,
40779
+ data,
40780
+ duration: duration ?? void 0
40781
+ });
40764
40782
  }
40765
- logInfo(message, ...data) {
40766
- logInfo(this.source, message, ...data);
40783
+ clearTimers() {
40784
+ this.timers = {};
40767
40785
  }
40768
- logDebug(message, ...data) {
40769
- logDebug(this.source, message, ...data);
40786
+ timerStart(name2) {
40787
+ this.timers[name2] = [performance.now(), null];
40788
+ }
40789
+ timerEnd(name2) {
40790
+ const timer = this.timers[name2];
40791
+ if (timer && timer[1] === null) {
40792
+ timer[1] = performance.now();
40793
+ }
40794
+ }
40795
+ getTimers() {
40796
+ const result = {};
40797
+ for (const name2 in this.timers) {
40798
+ result[name2] = this.getTimerDuration(name2);
40799
+ }
40800
+ return result;
40801
+ }
40802
+ getTimerDuration(name2) {
40803
+ const timer = this.timers[name2];
40804
+ if (timer && timer[1] !== null) {
40805
+ return timer[1] - timer[0];
40806
+ }
40807
+ return null;
40808
+ }
40809
+ isDebugEnabled() {
40810
+ return isDebugSource(this.source);
40770
40811
  }
40771
40812
  }
40772
40813
  function getLogger(source) {
@@ -40776,7 +40817,7 @@ const firebaseDateToDayjs = (date) => {
40776
40817
  return dayjs(date.seconds * 1e3);
40777
40818
  };
40778
40819
  const LOGIN_TRACKING_PERIOD_SECONDS = 1800;
40779
- const logger$4 = getLogger("firebase");
40820
+ const logger$5 = getLogger("firebase");
40780
40821
  let firebaseApp = null;
40781
40822
  class FirestoreManager {
40782
40823
  constructor(firestore) {
@@ -40904,6 +40945,9 @@ class AuthManager {
40904
40945
  this.listenToUserProfileUnsub = null;
40905
40946
  }
40906
40947
  if (authUser) {
40948
+ logger$5.logDebug("User logged in:", {
40949
+ uid: authUser.uid
40950
+ });
40907
40951
  this.listenToUserProfileUnsub = getFirestoreManager().listenToDoc("users", authUser.uid, (doc2) => {
40908
40952
  this.userProfile = doc2;
40909
40953
  this.userProfileChangeListeners.forEach((callback) => callback(this.userProfile));
@@ -40935,7 +40979,9 @@ class AuthManager {
40935
40979
  await firestore.mergeDocData("user_logging", userLoggingDocId, userLoggingData);
40936
40980
  }
40937
40981
  } catch (error) {
40938
- logger$4.logError("Error logging user login activity:", error);
40982
+ logger$5.logError("Error logging user login activity:", {
40983
+ error
40984
+ });
40939
40985
  }
40940
40986
  })();
40941
40987
  } else {
@@ -40982,7 +41028,7 @@ async function _init$3() {
40982
41028
  }
40983
41029
  }
40984
41030
  const CONTACT_US_LINK = "mailto:info@thefittingroom.tech?subject=Forgot%20Password%20Assistance";
40985
- const logger$3 = getLogger("forgot-password");
41031
+ const logger$4 = getLogger("forgot-password");
40986
41032
  function ForgotPasswordOverlay({
40987
41033
  returnToOverlay
40988
41034
  }) {
@@ -41048,7 +41094,9 @@ function ForgotPasswordOverlay({
41048
41094
  await authManager2.sendPasswordResetEmail(email2);
41049
41095
  setLinkSent(true);
41050
41096
  } catch (error) {
41051
- logger$3.logError("Error sending password reset email:", error);
41097
+ logger$4.logError("Error sending password reset email:", {
41098
+ error
41099
+ });
41052
41100
  }
41053
41101
  }
41054
41102
  event.preventDefault();
@@ -41265,7 +41313,7 @@ function TfrTitle() {
41265
41313
  }));
41266
41314
  return /* @__PURE__ */ jsx$1("div", { css: css2.container, children: /* @__PURE__ */ jsx$1(SvgTfrName, { css: css2.nameIcon }) });
41267
41315
  }
41268
- const logger$2 = getLogger("sign-in");
41316
+ const logger$3 = getLogger("sign-in");
41269
41317
  function SignInOverlay({
41270
41318
  returnToOverlay
41271
41319
  }) {
@@ -41339,7 +41387,9 @@ function SignInOverlay({
41339
41387
  closeOverlay();
41340
41388
  }
41341
41389
  } catch (error) {
41342
- logger$2.logError("Login failed:", error);
41390
+ logger$3.logError("Login failed:", {
41391
+ error
41392
+ });
41343
41393
  setEmailError(" ");
41344
41394
  setPasswordError(t("sign-in.login_failed"));
41345
41395
  passwordEl.focus();
@@ -41801,12 +41851,6 @@ async function getSizeRecommendation(styleId) {
41801
41851
  endpoint: `/v1/styles/${styleId}/recommendation`
41802
41852
  });
41803
41853
  }
41804
- function getSizeLabelFromSize(size) {
41805
- if (size.label) {
41806
- return size.label;
41807
- }
41808
- return size.size_value?.name ?? null;
41809
- }
41810
41854
  async function requestVtoSingle(colorwaySizeAssetId) {
41811
41855
  await execApiRequest({
41812
41856
  useCache: true,
@@ -41844,10 +41888,16 @@ async function getStyleGarmentCategoryById(styleGarmentCategoryId) {
41844
41888
  recordCache[cacheKey] = record;
41845
41889
  return record;
41846
41890
  }
41891
+ function getSizeLabelFromSize(size) {
41892
+ if (size.label) {
41893
+ return size.label;
41894
+ }
41895
+ return size.size_value?.name ?? null;
41896
+ }
41847
41897
  const AVATAR_IMAGE_ASPECT_RATIO = 2 / 3;
41848
41898
  const AVATAR_GUTTER_HEIGHT_PX = 100;
41849
41899
  const CONTENT_AREA_WIDTH_PX = 550;
41850
- const logger$1 = getLogger("vto-single");
41900
+ const logger$2 = getLogger("overlays/vto-single");
41851
41901
  function VtoSingleOverlay() {
41852
41902
  const {
41853
41903
  brandId
@@ -41862,6 +41912,8 @@ function VtoSingleOverlay() {
41862
41912
  const [selectedSizeLabel, setSelectedSizeLabel] = reactExports.useState(null);
41863
41913
  const [selectedColorLabel, setSelectedColorLabel] = reactExports.useState(null);
41864
41914
  const [modalStyle, setModalStyle] = reactExports.useState({});
41915
+ const fetchedVtoSkus = reactExports.useRef(/* @__PURE__ */ new Set());
41916
+ const readyVtoSkus = reactExports.useRef(/* @__PURE__ */ new Set());
41865
41917
  reactExports.useEffect(() => {
41866
41918
  if (!userIsLoggedIn) {
41867
41919
  openOverlay(OverlayName.LANDING, {
@@ -41880,6 +41932,10 @@ function VtoSingleOverlay() {
41880
41932
  reactExports.useEffect(() => {
41881
41933
  async function fetchInitialData() {
41882
41934
  try {
41935
+ logger$2.clearTimers();
41936
+ logger$2.timerStart("fetchInitialData");
41937
+ logger$2.logDebug("{{ts}} - Starting fetch of initial data");
41938
+ logger$2.timerStart("fetchInitialData_1_getProductData");
41883
41939
  const {
41884
41940
  currentProduct
41885
41941
  } = getStaticData();
@@ -41891,82 +41947,112 @@ function VtoSingleOverlay() {
41891
41947
  const {
41892
41948
  color: selectedColor
41893
41949
  } = await currentProduct.getSelectedOptions();
41950
+ logger$2.timerEnd("fetchInitialData_1_getProductData");
41951
+ logger$2.timerStart("fetchInitialData_2_getStyleData");
41894
41952
  const styleRec = await getStyleByExternalId(brandId, currentProduct.externalId);
41895
41953
  if (!styleRec) {
41896
- logger$1.logError("Style not found for externalId:", currentProduct.externalId);
41954
+ logger$2.logError(`Style not found for externalId: ${currentProduct.externalId}`);
41897
41955
  return;
41898
41956
  }
41899
41957
  const styleGarmentCategoryRec = await getStyleGarmentCategoryById(styleRec.style_garment_category_id);
41900
41958
  const styleCategoryLabel = styleGarmentCategoryRec?.style_category_label ?? null;
41959
+ logger$2.timerEnd("fetchInitialData_2_getStyleData");
41960
+ logger$2.timerStart("fetchInitialData_3_getSizeRecommendation");
41901
41961
  const sizeRecommendationRecord = await getSizeRecommendation(styleRec.id);
41902
- let productData;
41903
- const recommendedSizeLabel = getSizeLabelFromSize(sizeRecommendationRecord.recommended_size) ?? "(unknown)";
41962
+ logger$2.timerEnd("fetchInitialData_3_getSizeRecommendation");
41963
+ logger$2.timerStart("fetchInitialData_4_assembleLoadedData");
41904
41964
  {
41905
- const fitClassification = sizeRecommendationRecord.fit_classification;
41906
- const recommendedSizeId = sizeRecommendationRecord.recommended_size.id;
41907
- const sizes = [];
41908
- for (const sizeRec of sizeRecommendationRecord.available_sizes) {
41909
- const sizeId = sizeRec.id;
41910
- const sizeLabel = getSizeLabelFromSize(sizeRec) ?? "(unknown)";
41911
- const isRecommended = sizeRec.id === recommendedSizeId;
41912
- const fit = sizeRecommendationRecord.fits.find((f) => f.size_id === sizeRec.id);
41913
- if (!fit) {
41914
- continue;
41965
+ const recommendedSizeId = sizeRecommendationRecord.recommended_size.id || null;
41966
+ const recommendedSizeLabel = getSizeLabelFromSize(sizeRecommendationRecord.recommended_size);
41967
+ if (recommendedSizeId != null && recommendedSizeLabel != null) {
41968
+ let productData;
41969
+ {
41970
+ const fitClassification = sizeRecommendationRecord.fit_classification;
41971
+ const sizes = [];
41972
+ for (const sizeRec of sizeRecommendationRecord.available_sizes) {
41973
+ const sizeId = sizeRec.id;
41974
+ const sizeLabel = getSizeLabelFromSize(sizeRec) || null;
41975
+ if (!sizeLabel) {
41976
+ continue;
41977
+ }
41978
+ const isRecommended = sizeRec.id === recommendedSizeId;
41979
+ const fit = sizeRecommendationRecord.fits.find((f) => f.size_id === sizeRec.id);
41980
+ if (!fit) {
41981
+ continue;
41982
+ }
41983
+ const colors = [];
41984
+ for (const csaRec of sizeRec.colorway_size_assets) {
41985
+ const colorwaySizeAssetId = csaRec.id;
41986
+ const sku = csaRec.sku;
41987
+ const variant = variants.find((v) => v.sku === sku);
41988
+ if (!variant) {
41989
+ continue;
41990
+ }
41991
+ const colorLabel = variant.color || null;
41992
+ if (!colorLabel) {
41993
+ continue;
41994
+ }
41995
+ const priceFormatted = variant.priceFormatted;
41996
+ colors.push({
41997
+ colorwaySizeAssetId,
41998
+ colorLabel,
41999
+ sku,
42000
+ priceFormatted
42001
+ });
42002
+ }
42003
+ sizes.push({
42004
+ sizeId,
42005
+ sizeLabel,
42006
+ isRecommended,
42007
+ fit,
42008
+ colors
42009
+ });
42010
+ }
42011
+ productData = {
42012
+ productName,
42013
+ productDescriptionHtml,
42014
+ fitClassification,
42015
+ recommendedSizeId,
42016
+ recommendedSizeLabel,
42017
+ sizes,
42018
+ styleCategoryLabel
42019
+ };
41915
42020
  }
41916
- const colors = [];
41917
- for (const csaRec of sizeRec.colorway_size_assets) {
41918
- const colorwaySizeAssetId = csaRec.id;
41919
- const sku = csaRec.sku;
41920
- const variant = variants.find((v) => v.sku === sku);
41921
- if (!variant) {
41922
- continue;
42021
+ let recommendedColorLabel;
42022
+ {
42023
+ const recommendedSizeRecord = productData.sizes.find((s) => s.isRecommended);
42024
+ if (!recommendedSizeRecord) {
42025
+ throw new Error("Recommended size record not found");
41923
42026
  }
41924
- const colorLabel = variant.color;
41925
- const priceFormatted = variant.priceFormatted;
41926
- colors.push({
41927
- colorwaySizeAssetId,
41928
- colorLabel,
41929
- sku,
41930
- priceFormatted
41931
- });
42027
+ const recommendedSizeColorRecord = recommendedSizeRecord.colors.find((c) => {
42028
+ return c.colorLabel === selectedColor;
42029
+ }) || recommendedSizeRecord.colors[0];
42030
+ recommendedColorLabel = recommendedSizeColorRecord.colorLabel;
41932
42031
  }
41933
- sizes.push({
41934
- sizeId,
41935
- sizeLabel,
41936
- isRecommended,
41937
- fit,
41938
- colors
41939
- });
42032
+ setLoadedProductData(productData);
42033
+ setSelectedSizeLabel(recommendedSizeLabel);
42034
+ setSelectedColorLabel(recommendedColorLabel);
42035
+ } else {
42036
+ setLoadedProductData(false);
41940
42037
  }
41941
- productData = {
41942
- productName,
41943
- productDescriptionHtml,
41944
- fitClassification,
41945
- recommendedSizeId,
41946
- recommendedSizeLabel,
41947
- sizes,
41948
- styleCategoryLabel
41949
- };
41950
42038
  }
41951
- let recommendedColorLabel;
41952
- {
41953
- const recommendedSizeRecord = productData.sizes.find((s) => s.isRecommended);
41954
- const recommendedSizeColorRecord = recommendedSizeRecord.colors.find((c) => {
41955
- return c.colorLabel === selectedColor;
41956
- }) || recommendedSizeRecord.colors[0];
41957
- recommendedColorLabel = recommendedSizeColorRecord.colorLabel;
41958
- }
41959
- setLoadedProductData(productData);
41960
- setSelectedSizeLabel(recommendedSizeLabel);
41961
- setSelectedColorLabel(recommendedColorLabel);
42039
+ for (const sku in userProfile?.vto?.[brandId] ?? {}) {
42040
+ fetchedVtoSkus.current.add(sku);
42041
+ readyVtoSkus.current.add(sku);
42042
+ }
42043
+ logger$2.timerEnd("fetchInitialData_4_assembleLoadedData");
42044
+ logger$2.timerEnd("fetchInitialData");
42045
+ logger$2.logTimer("total", "{{ts}} - Completed fetch of initial data", logger$2.getTimers());
41962
42046
  } catch (error) {
41963
- logger$1.logError("Error fetching VTO data:", error);
42047
+ logger$2.logError("Error fetching initial data:", {
42048
+ error
42049
+ });
41964
42050
  }
41965
42051
  }
41966
- if (userIsLoggedIn && userHasAvatar) {
42052
+ if (userIsLoggedIn && userHasAvatar && userProfile && loadedProductData == null) {
41967
42053
  fetchInitialData();
41968
42054
  }
41969
- }, [userIsLoggedIn, userHasAvatar]);
42055
+ }, [userIsLoggedIn, userHasAvatar, userProfile, loadedProductData]);
41970
42056
  const {
41971
42057
  sizeColorRecord: selectedColorSizeRecord,
41972
42058
  availableColorLabels
@@ -41978,7 +42064,7 @@ function VtoSingleOverlay() {
41978
42064
  };
41979
42065
  }
41980
42066
  const sizeRecord = loadedProductData.sizes.find((s) => s.sizeLabel === selectedSizeLabel);
41981
- if (!sizeRecord) {
42067
+ if (!sizeRecord || !sizeRecord.colors.length) {
41982
42068
  return {
41983
42069
  sizeColorRecord: null,
41984
42070
  availableColorLabels: []
@@ -41991,25 +42077,54 @@ function VtoSingleOverlay() {
41991
42077
  availableColorLabels: availableColorLabels2
41992
42078
  };
41993
42079
  }, [loadedProductData, selectedSizeLabel, selectedColorLabel]);
42080
+ const requestVto = reactExports.useCallback((sizeColorRecord) => {
42081
+ if (fetchedVtoSkus.current.has(sizeColorRecord.sku)) {
42082
+ return;
42083
+ }
42084
+ logger$2.timerStart(`requestVto_${sizeColorRecord.sku}`);
42085
+ logger$2.logDebug(`{{ts}} - Requesting VTO for sku: ${sizeColorRecord.sku}`, {
42086
+ sizeColorRecord
42087
+ });
42088
+ fetchedVtoSkus.current.add(sizeColorRecord.sku);
42089
+ requestVtoSingle(sizeColorRecord.colorwaySizeAssetId).catch((error) => {
42090
+ logger$2.logError("Error requesting VTO:", {
42091
+ error,
42092
+ sizeColorRecord
42093
+ });
42094
+ });
42095
+ }, []);
41994
42096
  reactExports.useEffect(() => {
41995
42097
  if (selectedColorSizeRecord) {
41996
- requestVtoSingle(selectedColorSizeRecord.colorwaySizeAssetId);
42098
+ requestVto(selectedColorSizeRecord);
41997
42099
  }
41998
- }, [selectedColorSizeRecord]);
42100
+ }, [requestVto, selectedColorSizeRecord]);
41999
42101
  reactExports.useEffect(() => {
42000
42102
  if (!loadedProductData) {
42001
42103
  return;
42002
42104
  }
42003
42105
  for (const sizeRecord of loadedProductData.sizes) {
42004
42106
  const sizeColorRecord = sizeRecord.colors.find((c) => c.colorLabel === selectedColorLabel) ?? sizeRecord.colors[0];
42005
- requestVtoSingle(sizeColorRecord.colorwaySizeAssetId);
42107
+ requestVto(sizeColorRecord);
42006
42108
  }
42007
- }, [loadedProductData, selectedColorLabel]);
42109
+ }, [requestVto, loadedProductData, selectedColorLabel]);
42008
42110
  const vtoData = reactExports.useMemo(() => {
42009
42111
  if (!userProfile || !selectedColorSizeRecord) {
42010
42112
  return null;
42011
42113
  }
42012
- const vtoData2 = userProfile.vto?.[brandId]?.[selectedColorSizeRecord.sku];
42114
+ const availableSkuData = userProfile.vto?.[brandId];
42115
+ if (!availableSkuData) {
42116
+ return null;
42117
+ }
42118
+ if (logger$2.isDebugEnabled()) {
42119
+ for (const sku of fetchedVtoSkus.current) {
42120
+ if (!readyVtoSkus.current.has(sku) && availableSkuData[sku]) {
42121
+ readyVtoSkus.current.add(sku);
42122
+ logger$2.timerEnd(`requestVto_${sku}`);
42123
+ logger$2.logTimer(`requestVto_${sku}`, `{{ts}} - VTO data is loaded for sku: ${sku}`);
42124
+ }
42125
+ }
42126
+ }
42127
+ const vtoData2 = availableSkuData[selectedColorSizeRecord.sku];
42013
42128
  if (!vtoData2) {
42014
42129
  return null;
42015
42130
  }
@@ -42026,7 +42141,9 @@ function VtoSingleOverlay() {
42026
42141
  closeOverlay();
42027
42142
  const authManager2 = getAuthManager();
42028
42143
  authManager2.logout().catch((error) => {
42029
- logger$1.logError("Error during logout:", error);
42144
+ logger$2.logError("Error during logout:", {
42145
+ error
42146
+ });
42030
42147
  });
42031
42148
  }, [closeOverlay, openOverlay]);
42032
42149
  const handleAddToCartClick = reactExports.useCallback(async () => {
@@ -42043,10 +42160,15 @@ function VtoSingleOverlay() {
42043
42160
  color: selectedColorLabel
42044
42161
  });
42045
42162
  } catch (error) {
42046
- logger$1.logError("Error adding to cart:", error);
42163
+ logger$2.logError("Error adding to cart:", {
42164
+ error
42165
+ });
42047
42166
  }
42048
42167
  }, [selectedColorLabel, selectedSizeLabel]);
42049
- if (!userIsLoggedIn || !userHasAvatar || !loadedProductData || !selectedColorSizeRecord) {
42168
+ if (loadedProductData === false) {
42169
+ return /* @__PURE__ */ jsx$1(SidecarModalFrame, { onRequestClose: closeOverlay, children: /* @__PURE__ */ jsx$1(NoFitLayout, { onClose: closeOverlay, onSignOut: handleSignOutClick }) });
42170
+ }
42171
+ if (!userIsLoggedIn || !userHasAvatar || loadedProductData == null || !selectedColorSizeRecord) {
42050
42172
  return /* @__PURE__ */ jsx$1(SidecarModalFrame, { onRequestClose: closeOverlay, children: /* @__PURE__ */ jsx$1(Loading, {}) });
42051
42173
  }
42052
42174
  let Layout;
@@ -42057,6 +42179,44 @@ function VtoSingleOverlay() {
42057
42179
  }
42058
42180
  return /* @__PURE__ */ jsx$1(SidecarModalFrame, { onRequestClose: closeOverlay, contentStyle: modalStyle, children: /* @__PURE__ */ jsx$1(Layout, { loadedProductData, selectedColorSizeRecord, availableColorLabels, selectedColorLabel, selectedSizeLabel, frameUrls, setModalStyle, onClose: closeOverlay, onChangeColor: setSelectedColorLabel, onChangeSize: setSelectedSizeLabel, onAddToCart: handleAddToCartClick, onSignOut: handleSignOutClick }) });
42059
42181
  }
42182
+ function NoFitLayout({
42183
+ onClose,
42184
+ onSignOut
42185
+ }) {
42186
+ const {
42187
+ t
42188
+ } = useTranslation();
42189
+ const css2 = useCss((_theme) => ({
42190
+ mainContainer: {
42191
+ width: "100%",
42192
+ height: "100%",
42193
+ padding: "16px"
42194
+ },
42195
+ titlebarContainer: {},
42196
+ contentContainer: {
42197
+ height: "100%",
42198
+ display: "flex",
42199
+ flexDirection: "column",
42200
+ alignItems: "center",
42201
+ justifyContent: "center"
42202
+ },
42203
+ messageContainer: {
42204
+ marginTop: "32px",
42205
+ textAlign: "center"
42206
+ },
42207
+ footerContainer: {
42208
+ marginTop: "32px"
42209
+ }
42210
+ }));
42211
+ return /* @__PURE__ */ jsxs("div", { css: css2.mainContainer, children: [
42212
+ /* @__PURE__ */ jsx$1("div", { css: css2.titlebarContainer, children: /* @__PURE__ */ jsx$1(ModalTitlebar, { title: t("try_it_on"), onCloseClick: onClose }) }),
42213
+ /* @__PURE__ */ jsxs("div", { css: css2.contentContainer, children: [
42214
+ /* @__PURE__ */ jsx$1("div", { children: " " }),
42215
+ /* @__PURE__ */ jsx$1("div", { css: css2.messageContainer, children: /* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "vto-single.no_recommendation" }) }),
42216
+ /* @__PURE__ */ jsx$1("div", { css: css2.footerContainer, children: /* @__PURE__ */ jsx$1(Footer, { onSignOutClick: onSignOut }) })
42217
+ ] })
42218
+ ] });
42219
+ }
42060
42220
  function MobileLayout({
42061
42221
  loadedProductData,
42062
42222
  selectedColorSizeRecord,
@@ -43014,7 +43174,7 @@ function useSizeRecommendation(load) {
43014
43174
  error
43015
43175
  };
43016
43176
  }
43017
- const logger = getLogger("size-rec");
43177
+ const logger$1 = getLogger("size-rec");
43018
43178
  function SizeRecWidget({}) {
43019
43179
  const openOverlay = useMainStore((state) => state.openOverlay);
43020
43180
  const openedOverlays = useMainStore((state) => state.openedOverlays);
@@ -43025,7 +43185,9 @@ function SizeRecWidget({}) {
43025
43185
  } = useSizeRecommendation(hasOpenedVtoSingleOverlay);
43026
43186
  reactExports.useEffect(() => {
43027
43187
  if (sizeRecommendationError) {
43028
- logger.logError("Error loading size recommendation:", sizeRecommendationError);
43188
+ logger$1.logError("Error loading size recommendation:", {
43189
+ error: sizeRecommendationError
43190
+ });
43029
43191
  }
43030
43192
  }, [sizeRecommendationError]);
43031
43193
  const handleLinkClick = reactExports.useCallback(() => {
@@ -43042,6 +43204,7 @@ function SizeRecWidget({}) {
43042
43204
  size: sizeLabel
43043
43205
  } });
43044
43206
  }
43207
+ const logger = getLogger("widgets/vto-button");
43045
43208
  function VtoButtonWidget({}) {
43046
43209
  const openOverlay = useMainStore((state) => state.openOverlay);
43047
43210
  const css2 = useCss((theme) => ({
@@ -43071,6 +43234,7 @@ function VtoButtonWidget({}) {
43071
43234
  }
43072
43235
  }));
43073
43236
  const openVto = () => {
43237
+ logger.logDebug("{{ts}} - Opening VTO overlay");
43074
43238
  openOverlay(OverlayName.VTO_SINGLE);
43075
43239
  };
43076
43240
  return /* @__PURE__ */ jsxs("button", { type: "button", onClick: openVto, css: css2.button, children: [
@@ -43271,9 +43435,9 @@ const SHARED_CONFIG = {
43271
43435
  appGooglePlayUrl: "https://play.google.com/store/apps/details?id=com.thefittingroom.marketplace"
43272
43436
  },
43273
43437
  build: {
43274
- version: `${"5.0.8"}`,
43275
- commitHash: `${"d1d0462"}`,
43276
- date: `${"2026-01-18T23:29:10.022Z"}`
43438
+ version: `${"5.0.10"}`,
43439
+ commitHash: `${"0058a65"}`,
43440
+ date: `${"2026-02-01T18:44:35.278Z"}`
43277
43441
  }
43278
43442
  };
43279
43443
  const CONFIGS = {
@@ -43355,7 +43519,9 @@ async function init(initParams) {
43355
43519
  throw new Error(`Invalid environment "${environment}"`);
43356
43520
  }
43357
43521
  _init$4(debug);
43358
- logger2.logDebug("Received initParams:", initParams);
43522
+ logger2.logDebug("Starting SDK initialization:", {
43523
+ initParams
43524
+ });
43359
43525
  const config = getConfig(environment);
43360
43526
  if (lang) {
43361
43527
  await instance.changeLanguage(lang);
@@ -43393,14 +43559,17 @@ async function init(initParams) {
43393
43559
  logger2.logDebug("SDK initialized", config.build);
43394
43560
  return true;
43395
43561
  } catch (error) {
43396
- logger2.logError("SDK initialization failed:", error);
43562
+ logger2.logError("SDK initialization failed:", {
43563
+ error
43564
+ });
43397
43565
  return false;
43398
43566
  }
43399
43567
  }
43400
43568
  async function logout() {
43401
43569
  const authManager2 = getAuthManager();
43402
43570
  await authManager2.logout();
43403
- logInfo("logout", "User logged out");
43571
+ const logger2 = getLogger("logout");
43572
+ logger2.logInfo("User logged out");
43404
43573
  }
43405
43574
  const TFR = {
43406
43575
  init,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thefittingroom/shop-ui",
3
- "version": "5.0.8",
3
+ "version": "5.0.10",
4
4
  "description": "the fitting room UI library",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",