@thefittingroom/shop-ui 5.0.22 → 5.0.24
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.
- package/dist/index.js +1040 -484
- package/package.json +14 -3
package/dist/index.js
CHANGED
|
@@ -14054,7 +14054,7 @@ function applyFrameBaseUrl(url, baseUrl2) {
|
|
|
14054
14054
|
return `${cleanBase}${url.startsWith("/") ? "" : "/"}${url}`;
|
|
14055
14055
|
}
|
|
14056
14056
|
const STORAGE_KEY = "tfr:fitting-room:v1";
|
|
14057
|
-
const logger$
|
|
14057
|
+
const logger$f = getLogger("fitting-room-storage");
|
|
14058
14058
|
function readAll() {
|
|
14059
14059
|
try {
|
|
14060
14060
|
const raw = window.localStorage.getItem(STORAGE_KEY);
|
|
@@ -14067,7 +14067,7 @@ function readAll() {
|
|
|
14067
14067
|
}
|
|
14068
14068
|
return parsed;
|
|
14069
14069
|
} catch (error) {
|
|
14070
|
-
logger$
|
|
14070
|
+
logger$f.logWarn("Failed to read fitting room from localStorage", {
|
|
14071
14071
|
error
|
|
14072
14072
|
});
|
|
14073
14073
|
return {};
|
|
@@ -14077,7 +14077,7 @@ function writeAll(all) {
|
|
|
14077
14077
|
try {
|
|
14078
14078
|
window.localStorage.setItem(STORAGE_KEY, JSON.stringify(all));
|
|
14079
14079
|
} catch (error) {
|
|
14080
|
-
logger$
|
|
14080
|
+
logger$f.logWarn("Failed to write fitting room to localStorage", {
|
|
14081
14081
|
error
|
|
14082
14082
|
});
|
|
14083
14083
|
}
|
|
@@ -14101,17 +14101,9 @@ function _init$7() {
|
|
|
14101
14101
|
fittingRoom: items
|
|
14102
14102
|
});
|
|
14103
14103
|
}
|
|
14104
|
-
async function
|
|
14104
|
+
async function addFittingRoomItem(productId, handle, isPdp) {
|
|
14105
14105
|
const state = useMainStore.getState();
|
|
14106
|
-
|
|
14107
|
-
if (isInFittingRoom) {
|
|
14108
|
-
logger$h.logDebug("{{ts}} - Removing from fitting room", {
|
|
14109
|
-
productId
|
|
14110
|
-
});
|
|
14111
|
-
state.removeFromFittingRoom(productId);
|
|
14112
|
-
return;
|
|
14113
|
-
}
|
|
14114
|
-
logger$h.logDebug("{{ts}} - Adding to fitting room", {
|
|
14106
|
+
logger$f.logDebug("{{ts}} - Adding to fitting room", {
|
|
14115
14107
|
productId,
|
|
14116
14108
|
handle,
|
|
14117
14109
|
isPdp
|
|
@@ -14133,7 +14125,7 @@ async function toggleFittingRoomItem(productId, handle, isPdp) {
|
|
|
14133
14125
|
size = selection.size || null;
|
|
14134
14126
|
color = selection.color;
|
|
14135
14127
|
} catch (error) {
|
|
14136
|
-
logger$
|
|
14128
|
+
logger$f.logWarn("Failed to read selected options from currentProduct", {
|
|
14137
14129
|
error
|
|
14138
14130
|
});
|
|
14139
14131
|
}
|
|
@@ -14161,6 +14153,25 @@ async function toggleFittingRoomItem(productId, handle, isPdp) {
|
|
|
14161
14153
|
addedAt: Date.now()
|
|
14162
14154
|
});
|
|
14163
14155
|
}
|
|
14156
|
+
async function toggleFittingRoomItem(productId, handle, isPdp) {
|
|
14157
|
+
const state = useMainStore.getState();
|
|
14158
|
+
const isInFittingRoom = state.fittingRoom.some((item) => item.externalId === productId);
|
|
14159
|
+
if (isInFittingRoom) {
|
|
14160
|
+
logger$f.logDebug("{{ts}} - Removing from fitting room", {
|
|
14161
|
+
productId
|
|
14162
|
+
});
|
|
14163
|
+
state.removeFromFittingRoom(productId);
|
|
14164
|
+
return;
|
|
14165
|
+
}
|
|
14166
|
+
await addFittingRoomItem(productId, handle, isPdp);
|
|
14167
|
+
}
|
|
14168
|
+
async function ensureFittingRoomItem(productId, handle, isPdp) {
|
|
14169
|
+
const state = useMainStore.getState();
|
|
14170
|
+
if (state.fittingRoom.some((item) => item.externalId === productId)) {
|
|
14171
|
+
return;
|
|
14172
|
+
}
|
|
14173
|
+
await addFittingRoomItem(productId, handle, isPdp);
|
|
14174
|
+
}
|
|
14164
14175
|
const BROWSER_ALIASES_MAP = {
|
|
14165
14176
|
AmazonBot: "amazonbot",
|
|
14166
14177
|
"Amazon Silk": "amazon_silk",
|
|
@@ -19307,7 +19318,7 @@ const en$1 = {
|
|
|
19307
19318
|
"get-app": { "create_avatar": "Create your avatar" },
|
|
19308
19319
|
"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." },
|
|
19309
19320
|
"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." },
|
|
19310
|
-
"
|
|
19321
|
+
"quick-view": { "title": "Quick View Try On", "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.", "vto_error": "Couldn't load the try-on. Please try again.", "zoom_in": "Zoom In" },
|
|
19311
19322
|
"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" } },
|
|
19312
19323
|
"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" } }
|
|
19313
19324
|
};
|
|
@@ -19331,11 +19342,11 @@ const fr = {
|
|
|
19331
19342
|
"get-app": { "create_avatar": "Créez votre avatar" },
|
|
19332
19343
|
"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." },
|
|
19333
19344
|
"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." },
|
|
19334
|
-
"
|
|
19345
|
+
"quick-view": { "title": "Essayage rapide", "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.", "vto_error": "Impossible de charger l'essayage. Veuillez réessayer.", "zoom_in": "Agrandir" },
|
|
19335
19346
|
"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" } },
|
|
19336
19347
|
"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" } }
|
|
19337
19348
|
};
|
|
19338
|
-
instance.use(initReactI18next).init({
|
|
19349
|
+
void instance.use(initReactI18next).init({
|
|
19339
19350
|
lng: "en",
|
|
19340
19351
|
fallbackLng: "en",
|
|
19341
19352
|
resources: {
|
|
@@ -19385,14 +19396,14 @@ function keyframes() {
|
|
|
19385
19396
|
};
|
|
19386
19397
|
}
|
|
19387
19398
|
const themeData = {
|
|
19388
|
-
brand_font_family: "
|
|
19399
|
+
brand_font_family: "'Inter', sans-serif",
|
|
19389
19400
|
brand_link_text_decoration: "underline",
|
|
19390
19401
|
brand_button_background_color: "#FFA273",
|
|
19391
19402
|
brand_button_text_color: "#21201F",
|
|
19392
19403
|
color_danger: "#900B09",
|
|
19393
19404
|
color_fg_text: "#21201F",
|
|
19394
19405
|
color_tfr_800: "#265A64",
|
|
19395
|
-
font_family: "sans-serif"
|
|
19406
|
+
font_family: "'Inter', sans-serif"
|
|
19396
19407
|
};
|
|
19397
19408
|
function _init$6(initThemeData) {
|
|
19398
19409
|
if (initThemeData) {
|
|
@@ -19487,7 +19498,7 @@ const Text = reactExports.forwardRef(({
|
|
|
19487
19498
|
const variantCss = useVariantCss(variant, (theme) => ({
|
|
19488
19499
|
base: {
|
|
19489
19500
|
color: theme.color_fg_text,
|
|
19490
|
-
fontFamily:
|
|
19501
|
+
fontFamily: theme.font_family,
|
|
19491
19502
|
fontSize: "14px"
|
|
19492
19503
|
},
|
|
19493
19504
|
brand: {
|
|
@@ -19497,6 +19508,7 @@ const Text = reactExports.forwardRef(({
|
|
|
19497
19508
|
},
|
|
19498
19509
|
error: {
|
|
19499
19510
|
color: theme.color_danger,
|
|
19511
|
+
fontFamily: theme.font_family,
|
|
19500
19512
|
fontSize: "14px"
|
|
19501
19513
|
}
|
|
19502
19514
|
}));
|
|
@@ -21244,6 +21256,45 @@ function SidecarModalFrame({
|
|
|
21244
21256
|
};
|
|
21245
21257
|
return /* @__PURE__ */ jsx$1(ModalFrame, { isOpen: true, onRequestClose, contentStyle: applyContentStyle, children });
|
|
21246
21258
|
}
|
|
21259
|
+
function Snackbar({
|
|
21260
|
+
messageKey,
|
|
21261
|
+
onDismiss
|
|
21262
|
+
}) {
|
|
21263
|
+
const css2 = useCss((theme) => ({
|
|
21264
|
+
container: {
|
|
21265
|
+
position: "absolute",
|
|
21266
|
+
left: "50%",
|
|
21267
|
+
bottom: "24px",
|
|
21268
|
+
transform: "translateX(-50%)",
|
|
21269
|
+
padding: "12px 20px",
|
|
21270
|
+
borderRadius: "24px",
|
|
21271
|
+
backgroundColor: theme.color_fg_text,
|
|
21272
|
+
fontSize: "13px",
|
|
21273
|
+
display: "flex",
|
|
21274
|
+
alignItems: "center",
|
|
21275
|
+
gap: "12px",
|
|
21276
|
+
zIndex: 10,
|
|
21277
|
+
maxWidth: "calc(100% - 32px)"
|
|
21278
|
+
},
|
|
21279
|
+
// The Text 'base' variant carries a dark color; override it so the copy
|
|
21280
|
+
// is readable on the dark snackbar background.
|
|
21281
|
+
text: {
|
|
21282
|
+
color: "#FFFFFF"
|
|
21283
|
+
},
|
|
21284
|
+
dismiss: {
|
|
21285
|
+
background: "none",
|
|
21286
|
+
border: "none",
|
|
21287
|
+
color: "#FFFFFF",
|
|
21288
|
+
fontSize: "16px",
|
|
21289
|
+
lineHeight: 1,
|
|
21290
|
+
cursor: "pointer"
|
|
21291
|
+
}
|
|
21292
|
+
}));
|
|
21293
|
+
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
21294
|
+
/* @__PURE__ */ jsx$1(TextT, { variant: "base", t: messageKey, css: css2.text }),
|
|
21295
|
+
/* @__PURE__ */ jsx$1("button", { css: css2.dismiss, onClick: onDismiss, "aria-label": "Dismiss", children: "×" })
|
|
21296
|
+
] });
|
|
21297
|
+
}
|
|
21247
21298
|
var dayjs_min$1 = { exports: {} };
|
|
21248
21299
|
var dayjs_min = dayjs_min$1.exports;
|
|
21249
21300
|
var hasRequiredDayjs_min;
|
|
@@ -23007,7 +23058,7 @@ function isVersionServiceProvider(provider) {
|
|
|
23007
23058
|
}
|
|
23008
23059
|
const name$q = "@firebase/app";
|
|
23009
23060
|
const version$1$1 = "0.14.5";
|
|
23010
|
-
const logger$
|
|
23061
|
+
const logger$e = new Logger3("@firebase/app");
|
|
23011
23062
|
const name$p = "@firebase/app-compat";
|
|
23012
23063
|
const name$o = "@firebase/analytics-compat";
|
|
23013
23064
|
const name$n = "@firebase/analytics";
|
|
@@ -23074,13 +23125,13 @@ function _addComponent(app, component) {
|
|
|
23074
23125
|
try {
|
|
23075
23126
|
app.container.addComponent(component);
|
|
23076
23127
|
} catch (e) {
|
|
23077
|
-
logger$
|
|
23128
|
+
logger$e.debug(`Component ${component.name} failed to register with FirebaseApp ${app.name}`, e);
|
|
23078
23129
|
}
|
|
23079
23130
|
}
|
|
23080
23131
|
function _registerComponent(component) {
|
|
23081
23132
|
const componentName = component.name;
|
|
23082
23133
|
if (_components.has(componentName)) {
|
|
23083
|
-
logger$
|
|
23134
|
+
logger$e.debug(`There were multiple attempts to register component ${componentName}.`);
|
|
23084
23135
|
return false;
|
|
23085
23136
|
}
|
|
23086
23137
|
_components.set(componentName, component);
|
|
@@ -23289,7 +23340,7 @@ function registerVersion(libraryKeyOrName, version2, variant) {
|
|
|
23289
23340
|
if (versionMismatch) {
|
|
23290
23341
|
warning.push(`version name "${version2}" contains illegal characters (whitespace or "/")`);
|
|
23291
23342
|
}
|
|
23292
|
-
logger$
|
|
23343
|
+
logger$e.warn(warning.join(" "));
|
|
23293
23344
|
return;
|
|
23294
23345
|
}
|
|
23295
23346
|
_registerComponent(new Component(
|
|
@@ -23333,12 +23384,12 @@ async function readHeartbeatsFromIndexedDB(app) {
|
|
|
23333
23384
|
return result;
|
|
23334
23385
|
} catch (e) {
|
|
23335
23386
|
if (e instanceof FirebaseError) {
|
|
23336
|
-
logger$
|
|
23387
|
+
logger$e.warn(e.message);
|
|
23337
23388
|
} else {
|
|
23338
23389
|
const idbGetError = ERROR_FACTORY.create("idb-get", {
|
|
23339
23390
|
originalErrorMessage: e?.message
|
|
23340
23391
|
});
|
|
23341
|
-
logger$
|
|
23392
|
+
logger$e.warn(idbGetError.message);
|
|
23342
23393
|
}
|
|
23343
23394
|
}
|
|
23344
23395
|
}
|
|
@@ -23351,12 +23402,12 @@ async function writeHeartbeatsToIndexedDB(app, heartbeatObject) {
|
|
|
23351
23402
|
await tx.done;
|
|
23352
23403
|
} catch (e) {
|
|
23353
23404
|
if (e instanceof FirebaseError) {
|
|
23354
|
-
logger$
|
|
23405
|
+
logger$e.warn(e.message);
|
|
23355
23406
|
} else {
|
|
23356
23407
|
const idbGetError = ERROR_FACTORY.create("idb-set", {
|
|
23357
23408
|
originalErrorMessage: e?.message
|
|
23358
23409
|
});
|
|
23359
|
-
logger$
|
|
23410
|
+
logger$e.warn(idbGetError.message);
|
|
23360
23411
|
}
|
|
23361
23412
|
}
|
|
23362
23413
|
}
|
|
@@ -23405,7 +23456,7 @@ class HeartbeatServiceImpl {
|
|
|
23405
23456
|
}
|
|
23406
23457
|
return this._storage.overwrite(this._heartbeatsCache);
|
|
23407
23458
|
} catch (e) {
|
|
23408
|
-
logger$
|
|
23459
|
+
logger$e.warn(e);
|
|
23409
23460
|
}
|
|
23410
23461
|
}
|
|
23411
23462
|
/**
|
|
@@ -23436,7 +23487,7 @@ class HeartbeatServiceImpl {
|
|
|
23436
23487
|
}
|
|
23437
23488
|
return headerString;
|
|
23438
23489
|
} catch (e) {
|
|
23439
|
-
logger$
|
|
23490
|
+
logger$e.warn(e);
|
|
23440
23491
|
return "";
|
|
23441
23492
|
}
|
|
23442
23493
|
}
|
|
@@ -41004,7 +41055,7 @@ const firebaseDateToDayjs = (date) => {
|
|
|
41004
41055
|
return dayjs(date.seconds * 1e3);
|
|
41005
41056
|
};
|
|
41006
41057
|
const LOGIN_TRACKING_PERIOD_SECONDS = 1800;
|
|
41007
|
-
const logger$
|
|
41058
|
+
const logger$d = getLogger("firebase");
|
|
41008
41059
|
let firebaseApp = null;
|
|
41009
41060
|
class FirestoreManager {
|
|
41010
41061
|
constructor(firestore) {
|
|
@@ -41132,14 +41183,14 @@ class AuthManager {
|
|
|
41132
41183
|
this.listenToUserProfileUnsub = null;
|
|
41133
41184
|
}
|
|
41134
41185
|
if (authUser) {
|
|
41135
|
-
logger$
|
|
41186
|
+
logger$d.logDebug("User logged in:", {
|
|
41136
41187
|
uid: authUser.uid
|
|
41137
41188
|
});
|
|
41138
41189
|
this.listenToUserProfileUnsub = getFirestoreManager().listenToDoc("users", authUser.uid, (doc2) => {
|
|
41139
41190
|
this.userProfile = doc2;
|
|
41140
41191
|
this.userProfileChangeListeners.forEach((callback) => callback(this.userProfile));
|
|
41141
41192
|
});
|
|
41142
|
-
(async () => {
|
|
41193
|
+
void (async () => {
|
|
41143
41194
|
try {
|
|
41144
41195
|
const firestore = getFirestoreManager();
|
|
41145
41196
|
const userLoggingDocId = authUser.uid;
|
|
@@ -41166,7 +41217,7 @@ class AuthManager {
|
|
|
41166
41217
|
await firestore.mergeDocData("user_logging", userLoggingDocId, userLoggingData);
|
|
41167
41218
|
}
|
|
41168
41219
|
} catch (error) {
|
|
41169
|
-
logger$
|
|
41220
|
+
logger$d.logError("Error logging user login activity:", {
|
|
41170
41221
|
error
|
|
41171
41222
|
});
|
|
41172
41223
|
}
|
|
@@ -41271,7 +41322,9 @@ async function execApiRequest(params) {
|
|
|
41271
41322
|
try {
|
|
41272
41323
|
response = await fetch(url, options);
|
|
41273
41324
|
} finally {
|
|
41274
|
-
if (timeoutHandle)
|
|
41325
|
+
if (timeoutHandle) {
|
|
41326
|
+
clearTimeout(timeoutHandle);
|
|
41327
|
+
}
|
|
41275
41328
|
}
|
|
41276
41329
|
if (!response.ok) {
|
|
41277
41330
|
let detail = "";
|
|
@@ -41364,7 +41417,7 @@ async function getStyleByExternalId(brandId, externalId) {
|
|
|
41364
41417
|
recordCache[cacheKey] = record;
|
|
41365
41418
|
return record;
|
|
41366
41419
|
}
|
|
41367
|
-
const logger$
|
|
41420
|
+
const logger$c = getLogger("product");
|
|
41368
41421
|
function _init$2() {
|
|
41369
41422
|
useMainStore.subscribe((state, prevState) => {
|
|
41370
41423
|
if (state.userHasAvatar && !prevState.userHasAvatar) {
|
|
@@ -41397,11 +41450,11 @@ function loadProductDataToStore(externalId) {
|
|
|
41397
41450
|
try {
|
|
41398
41451
|
const productData2 = await loadProductData(externalId);
|
|
41399
41452
|
useMainStore.getState().setProductData(productData2.externalId, productData2);
|
|
41400
|
-
logger$
|
|
41453
|
+
logger$c.logDebug(`Loaded product data for externalId: ${externalId}`, {
|
|
41401
41454
|
productData: productData2
|
|
41402
41455
|
});
|
|
41403
41456
|
} catch (error) {
|
|
41404
|
-
logger$
|
|
41457
|
+
logger$c.logError(`Error loading product data for externalId: ${externalId}`, {
|
|
41405
41458
|
error
|
|
41406
41459
|
});
|
|
41407
41460
|
}
|
|
@@ -41414,9 +41467,9 @@ function loadProductDataToStore(externalId) {
|
|
|
41414
41467
|
if (productData[externalId] || !userIsLoggedIn || userHasAvatar === false) {
|
|
41415
41468
|
return;
|
|
41416
41469
|
}
|
|
41417
|
-
loadAndStore();
|
|
41470
|
+
void loadAndStore();
|
|
41418
41471
|
}
|
|
41419
|
-
const logger$
|
|
41472
|
+
const logger$b = getLogger("style-categories");
|
|
41420
41473
|
let cached = null;
|
|
41421
41474
|
let inflight = null;
|
|
41422
41475
|
function buildIndex(categories, groups) {
|
|
@@ -41460,7 +41513,7 @@ async function loadStyleCategoryIndex() {
|
|
|
41460
41513
|
}
|
|
41461
41514
|
inflight = (async () => {
|
|
41462
41515
|
try {
|
|
41463
|
-
logger$
|
|
41516
|
+
logger$b.logDebug("{{ts}} - Loading style-category index");
|
|
41464
41517
|
const [categories, groups] = await Promise.all([getStyleCategories(), getStyleCategoryGroups()]);
|
|
41465
41518
|
cached = buildIndex(categories, groups);
|
|
41466
41519
|
return cached;
|
|
@@ -41473,12 +41526,12 @@ async function loadStyleCategoryIndex() {
|
|
|
41473
41526
|
function peekStyleCategoryIndex() {
|
|
41474
41527
|
return cached;
|
|
41475
41528
|
}
|
|
41476
|
-
const logger$
|
|
41529
|
+
const logger$a = getLogger("fitting-room-data");
|
|
41477
41530
|
async function loadFittingRoomData() {
|
|
41478
41531
|
const state = useMainStore.getState();
|
|
41479
41532
|
const items = state.fittingRoom;
|
|
41480
41533
|
loadStyleCategoryIndex().catch((error) => {
|
|
41481
|
-
logger$
|
|
41534
|
+
logger$a.logError("Failed to load style-category index", {
|
|
41482
41535
|
error
|
|
41483
41536
|
});
|
|
41484
41537
|
});
|
|
@@ -41490,7 +41543,9 @@ async function loadFittingRoomData() {
|
|
|
41490
41543
|
} = getStaticData();
|
|
41491
41544
|
if (!productLookup) {
|
|
41492
41545
|
for (const item of items) {
|
|
41493
|
-
if (state.merchantProductData[item.externalId])
|
|
41546
|
+
if (state.merchantProductData[item.externalId]) {
|
|
41547
|
+
continue;
|
|
41548
|
+
}
|
|
41494
41549
|
state.setMerchantProductData(item.externalId, {
|
|
41495
41550
|
error: new Error("No productLookup callback configured")
|
|
41496
41551
|
});
|
|
@@ -41526,7 +41581,7 @@ async function loadFittingRoomData() {
|
|
|
41526
41581
|
}
|
|
41527
41582
|
}
|
|
41528
41583
|
} catch (error) {
|
|
41529
|
-
logger$
|
|
41584
|
+
logger$a.logError("productLookup batch failed", {
|
|
41530
41585
|
error,
|
|
41531
41586
|
handles
|
|
41532
41587
|
});
|
|
@@ -41561,7 +41616,7 @@ function resolveItem(item, merchantSlot, loadedSlot, index) {
|
|
|
41561
41616
|
const found = loadedProduct.sizeFitRecommendation.available_sizes.some((sz) => sz.colorway_size_assets.some((csa) => csa.id === item.colorwaySizeAssetId));
|
|
41562
41617
|
if (!found) {
|
|
41563
41618
|
needsResize = true;
|
|
41564
|
-
logger$
|
|
41619
|
+
logger$a.logDebug("csa no longer in size rec, marking needsResize", {
|
|
41565
41620
|
externalId: item.externalId,
|
|
41566
41621
|
csa: item.colorwaySizeAssetId
|
|
41567
41622
|
});
|
|
@@ -41611,7 +41666,7 @@ function useResolvedFittingRoom() {
|
|
|
41611
41666
|
}, []);
|
|
41612
41667
|
reactExports.useEffect(() => {
|
|
41613
41668
|
loadFittingRoomData().catch((error) => {
|
|
41614
|
-
logger$
|
|
41669
|
+
logger$a.logError("loadFittingRoomData failed", {
|
|
41615
41670
|
error
|
|
41616
41671
|
});
|
|
41617
41672
|
});
|
|
@@ -41657,6 +41712,84 @@ function useResolvedFittingRoom() {
|
|
|
41657
41712
|
};
|
|
41658
41713
|
}, [fittingRoom, productData, merchantProductData, index, styleCategoryError]);
|
|
41659
41714
|
}
|
|
41715
|
+
function buildVtoProductDataFromResolved(item) {
|
|
41716
|
+
const {
|
|
41717
|
+
merchantProduct,
|
|
41718
|
+
loadedProduct
|
|
41719
|
+
} = item;
|
|
41720
|
+
if (!merchantProduct || !loadedProduct) {
|
|
41721
|
+
return null;
|
|
41722
|
+
}
|
|
41723
|
+
const sizeRec = loadedProduct.sizeFitRecommendation;
|
|
41724
|
+
const recommendedSizeId = sizeRec.recommended_size.id || null;
|
|
41725
|
+
const recommendedSizeLabel = getSizeLabelFromSize(sizeRec.recommended_size);
|
|
41726
|
+
if (recommendedSizeId == null || !recommendedSizeLabel) {
|
|
41727
|
+
logger$a.logWarn("Missing recommended size for item", {
|
|
41728
|
+
externalId: item.externalId
|
|
41729
|
+
});
|
|
41730
|
+
return null;
|
|
41731
|
+
}
|
|
41732
|
+
const sizes = [];
|
|
41733
|
+
for (const sizeRecord of sizeRec.available_sizes) {
|
|
41734
|
+
const sizeLabel = getSizeLabelFromSize(sizeRecord);
|
|
41735
|
+
if (!sizeLabel) {
|
|
41736
|
+
continue;
|
|
41737
|
+
}
|
|
41738
|
+
const fit = sizeRec.fits.find((f) => f.size_id === sizeRecord.id);
|
|
41739
|
+
if (!fit) {
|
|
41740
|
+
continue;
|
|
41741
|
+
}
|
|
41742
|
+
const colors = [];
|
|
41743
|
+
for (const csa of sizeRecord.colorway_size_assets) {
|
|
41744
|
+
const variant = merchantProduct.variants.find((v) => v.sku === csa.sku);
|
|
41745
|
+
if (!variant) {
|
|
41746
|
+
continue;
|
|
41747
|
+
}
|
|
41748
|
+
colors.push({
|
|
41749
|
+
colorwaySizeAssetId: csa.id,
|
|
41750
|
+
colorLabel: variant.color || null,
|
|
41751
|
+
sku: csa.sku,
|
|
41752
|
+
priceFormatted: variant.priceFormatted
|
|
41753
|
+
});
|
|
41754
|
+
}
|
|
41755
|
+
if (colors.length === 0) {
|
|
41756
|
+
continue;
|
|
41757
|
+
}
|
|
41758
|
+
sizes.push({
|
|
41759
|
+
sizeId: sizeRecord.id,
|
|
41760
|
+
sizeLabel,
|
|
41761
|
+
isRecommended: sizeRecord.id === recommendedSizeId,
|
|
41762
|
+
fit,
|
|
41763
|
+
colors
|
|
41764
|
+
});
|
|
41765
|
+
}
|
|
41766
|
+
if (sizes.length === 0) {
|
|
41767
|
+
return null;
|
|
41768
|
+
}
|
|
41769
|
+
return {
|
|
41770
|
+
productName: merchantProduct.productName,
|
|
41771
|
+
productDescriptionHtml: merchantProduct.productDescriptionHtml,
|
|
41772
|
+
fitClassification: sizeRec.fit_classification,
|
|
41773
|
+
recommendedSizeId,
|
|
41774
|
+
recommendedSizeLabel,
|
|
41775
|
+
sizes,
|
|
41776
|
+
styleCategoryLabel: item.styleCategory?.label_singular ?? loadedProduct.style.style_category_label ?? null
|
|
41777
|
+
};
|
|
41778
|
+
}
|
|
41779
|
+
function findRecommendedColorSize(data, preferredColor) {
|
|
41780
|
+
const recommended = data.sizes.find((s) => s.isRecommended);
|
|
41781
|
+
if (!recommended || recommended.colors.length === 0) {
|
|
41782
|
+
return null;
|
|
41783
|
+
}
|
|
41784
|
+
return recommended.colors.find((c) => c.colorLabel === preferredColor) ?? recommended.colors[0];
|
|
41785
|
+
}
|
|
41786
|
+
function findCsaByLabel(data, sizeLabel, preferredColor) {
|
|
41787
|
+
const sizeRecord = data.sizes.find((s) => s.sizeLabel === sizeLabel);
|
|
41788
|
+
if (!sizeRecord || sizeRecord.colors.length === 0) {
|
|
41789
|
+
return null;
|
|
41790
|
+
}
|
|
41791
|
+
return sizeRecord.colors.find((c) => c.colorLabel === preferredColor) ?? sizeRecord.colors[0];
|
|
41792
|
+
}
|
|
41660
41793
|
function useMobileSheetSnap(initial = "collapsed") {
|
|
41661
41794
|
const [snap, setSnap] = reactExports.useState(initial);
|
|
41662
41795
|
const handleTouchStart = reactExports.useCallback((e) => {
|
|
@@ -41664,7 +41797,9 @@ function useMobileSheetSnap(initial = "collapsed") {
|
|
|
41664
41797
|
const initialSnap = snap;
|
|
41665
41798
|
const onTouchMove = (moveEvent) => {
|
|
41666
41799
|
const deltaY = moveEvent.touches[0].clientY - startY;
|
|
41667
|
-
if (Math.abs(deltaY) < 30)
|
|
41800
|
+
if (Math.abs(deltaY) < 30) {
|
|
41801
|
+
return;
|
|
41802
|
+
}
|
|
41668
41803
|
if (deltaY > 0) {
|
|
41669
41804
|
if (initialSnap === "full" || initialSnap === "expanded") {
|
|
41670
41805
|
setSnap("collapsed");
|
|
@@ -41693,11 +41828,16 @@ function useMobileSheetSnap(initial = "collapsed") {
|
|
|
41693
41828
|
}
|
|
41694
41829
|
const MAX_OUTFIT_ITEMS = 4;
|
|
41695
41830
|
function asStringList(value) {
|
|
41696
|
-
if (!Array.isArray(value))
|
|
41831
|
+
if (!Array.isArray(value)) {
|
|
41832
|
+
return [];
|
|
41833
|
+
}
|
|
41697
41834
|
const out = [];
|
|
41698
41835
|
for (const v of value) {
|
|
41699
|
-
if (typeof v === "string")
|
|
41700
|
-
|
|
41836
|
+
if (typeof v === "string") {
|
|
41837
|
+
out.push(v);
|
|
41838
|
+
} else if (v != null) {
|
|
41839
|
+
out.push(String(v));
|
|
41840
|
+
}
|
|
41701
41841
|
}
|
|
41702
41842
|
return out;
|
|
41703
41843
|
}
|
|
@@ -41738,8 +41878,12 @@ function computeAvailability(item, selectedExternalIds, resolved) {
|
|
|
41738
41878
|
}
|
|
41739
41879
|
const itemCat = item.styleCategory;
|
|
41740
41880
|
for (const sel of resolved.items) {
|
|
41741
|
-
if (!selectedExternalIds.has(sel.externalId))
|
|
41742
|
-
|
|
41881
|
+
if (!selectedExternalIds.has(sel.externalId)) {
|
|
41882
|
+
continue;
|
|
41883
|
+
}
|
|
41884
|
+
if (!sel.styleCategory) {
|
|
41885
|
+
continue;
|
|
41886
|
+
}
|
|
41743
41887
|
if (!pairCompatible(sel.styleCategory, itemCat, sel.styleCategoryGroup)) {
|
|
41744
41888
|
return "disabled";
|
|
41745
41889
|
}
|
|
@@ -41747,8 +41891,12 @@ function computeAvailability(item, selectedExternalIds, resolved) {
|
|
|
41747
41891
|
return "available";
|
|
41748
41892
|
}
|
|
41749
41893
|
function makeOutfitItem(r, forceUntuck) {
|
|
41750
|
-
if (!r.styleCategory)
|
|
41751
|
-
|
|
41894
|
+
if (!r.styleCategory) {
|
|
41895
|
+
return null;
|
|
41896
|
+
}
|
|
41897
|
+
if (r.storage.colorwaySizeAssetId == null) {
|
|
41898
|
+
return null;
|
|
41899
|
+
}
|
|
41752
41900
|
const tuckable = !!r.styleCategory.tuckable;
|
|
41753
41901
|
const untucked = forceUntuck && tuckable;
|
|
41754
41902
|
const layerOrder = untucked ? r.styleCategory.layer_order_untucked : r.styleCategory.layer_order;
|
|
@@ -41768,10 +41916,16 @@ function buildOutfit(selectedExternalIds, resolved, forceUntuck, lastAddedExtern
|
|
|
41768
41916
|
const entries = [];
|
|
41769
41917
|
let lastAddedResolved = null;
|
|
41770
41918
|
for (const r of resolved.items) {
|
|
41771
|
-
if (!selectedExternalIds.has(r.externalId))
|
|
41772
|
-
|
|
41919
|
+
if (!selectedExternalIds.has(r.externalId)) {
|
|
41920
|
+
continue;
|
|
41921
|
+
}
|
|
41922
|
+
if (r.externalId === lastAddedExternalId) {
|
|
41923
|
+
lastAddedResolved = r;
|
|
41924
|
+
}
|
|
41773
41925
|
const entry = makeOutfitItem(r, forceUntuck);
|
|
41774
|
-
if (entry)
|
|
41926
|
+
if (entry) {
|
|
41927
|
+
entries.push(entry);
|
|
41928
|
+
}
|
|
41775
41929
|
}
|
|
41776
41930
|
entries.sort((a, b) => a.layerOrder - b.layerOrder);
|
|
41777
41931
|
const items = entries.slice(0, MAX_OUTFIT_ITEMS).map((e) => e.outfitItem);
|
|
@@ -41782,10 +41936,16 @@ function buildOutfit(selectedExternalIds, resolved, forceUntuck, lastAddedExtern
|
|
|
41782
41936
|
};
|
|
41783
41937
|
}
|
|
41784
41938
|
function buildAlternateOutfits(primary, lastAddedResolved) {
|
|
41785
|
-
if (!lastAddedResolved || !lastAddedResolved.loadedProduct)
|
|
41939
|
+
if (!lastAddedResolved || !lastAddedResolved.loadedProduct) {
|
|
41940
|
+
return [];
|
|
41941
|
+
}
|
|
41786
41942
|
const currentCsaId = lastAddedResolved.storage.colorwaySizeAssetId;
|
|
41787
|
-
if (currentCsaId == null)
|
|
41788
|
-
|
|
41943
|
+
if (currentCsaId == null) {
|
|
41944
|
+
return [];
|
|
41945
|
+
}
|
|
41946
|
+
if (!primary.some((i) => i.externalId === lastAddedResolved.externalId)) {
|
|
41947
|
+
return [];
|
|
41948
|
+
}
|
|
41789
41949
|
const sizeRec = lastAddedResolved.loadedProduct.sizeFitRecommendation;
|
|
41790
41950
|
let currentColorwayId = null;
|
|
41791
41951
|
for (const sz of sizeRec.available_sizes) {
|
|
@@ -41798,7 +41958,9 @@ function buildAlternateOutfits(primary, lastAddedResolved) {
|
|
|
41798
41958
|
const out = [];
|
|
41799
41959
|
for (const sz of sizeRec.available_sizes) {
|
|
41800
41960
|
const altCsa = sz.colorway_size_assets.find((c) => c.id !== currentCsaId && (currentColorwayId == null || c.colorway_id === currentColorwayId));
|
|
41801
|
-
if (!altCsa)
|
|
41961
|
+
if (!altCsa) {
|
|
41962
|
+
continue;
|
|
41963
|
+
}
|
|
41802
41964
|
const alternate = primary.map((it) => it.externalId === lastAddedResolved.externalId ? {
|
|
41803
41965
|
...it,
|
|
41804
41966
|
colorwaySizeAssetId: altCsa.id
|
|
@@ -41807,6 +41969,24 @@ function buildAlternateOutfits(primary, lastAddedResolved) {
|
|
|
41807
41969
|
}
|
|
41808
41970
|
return out;
|
|
41809
41971
|
}
|
|
41972
|
+
function pillBaseStyle(theme) {
|
|
41973
|
+
return {
|
|
41974
|
+
display: "inline-flex",
|
|
41975
|
+
alignItems: "center",
|
|
41976
|
+
gap: "8px",
|
|
41977
|
+
padding: "8px 16px",
|
|
41978
|
+
borderRadius: "24px",
|
|
41979
|
+
backgroundColor: "rgba(255, 255, 255, 0.95)",
|
|
41980
|
+
border: `1px solid ${theme.color_fg_text}`,
|
|
41981
|
+
fontSize: "12px",
|
|
41982
|
+
fontWeight: "500",
|
|
41983
|
+
letterSpacing: "0.5px",
|
|
41984
|
+
textTransform: "uppercase",
|
|
41985
|
+
cursor: "pointer",
|
|
41986
|
+
userSelect: "none",
|
|
41987
|
+
WebkitUserSelect: "none"
|
|
41988
|
+
};
|
|
41989
|
+
}
|
|
41810
41990
|
function AvatarControls({
|
|
41811
41991
|
selectedItems,
|
|
41812
41992
|
canTuck,
|
|
@@ -41823,7 +42003,9 @@ function AvatarControls({
|
|
|
41823
42003
|
const [popoverOpen, setPopoverOpen] = reactExports.useState(false);
|
|
41824
42004
|
const popoverWrapperRef = reactExports.useRef(null);
|
|
41825
42005
|
reactExports.useEffect(() => {
|
|
41826
|
-
if (!popoverOpen)
|
|
42006
|
+
if (!popoverOpen) {
|
|
42007
|
+
return;
|
|
42008
|
+
}
|
|
41827
42009
|
const onDocClick = (e) => {
|
|
41828
42010
|
if (popoverWrapperRef.current && !popoverWrapperRef.current.contains(e.target)) {
|
|
41829
42011
|
setPopoverOpen(false);
|
|
@@ -41846,20 +42028,7 @@ function AvatarControls({
|
|
|
41846
42028
|
alignItems: "flex-end"
|
|
41847
42029
|
},
|
|
41848
42030
|
pill: {
|
|
41849
|
-
|
|
41850
|
-
alignItems: "center",
|
|
41851
|
-
gap: "8px",
|
|
41852
|
-
padding: "8px 16px",
|
|
41853
|
-
borderRadius: "24px",
|
|
41854
|
-
backgroundColor: "rgba(255, 255, 255, 0.95)",
|
|
41855
|
-
border: `1px solid ${theme.color_fg_text}`,
|
|
41856
|
-
fontSize: "12px",
|
|
41857
|
-
fontWeight: "500",
|
|
41858
|
-
letterSpacing: "0.5px",
|
|
41859
|
-
textTransform: "uppercase",
|
|
41860
|
-
cursor: "pointer",
|
|
41861
|
-
userSelect: "none",
|
|
41862
|
-
WebkitUserSelect: "none",
|
|
42031
|
+
...pillBaseStyle(theme),
|
|
41863
42032
|
transition: "padding 500ms cubic-bezier(0.22, 1, 0.36, 1), gap 500ms cubic-bezier(0.22, 1, 0.36, 1)"
|
|
41864
42033
|
},
|
|
41865
42034
|
pillCollapsed: {
|
|
@@ -41961,13 +42130,114 @@ function AvatarControls({
|
|
|
41961
42130
|
] })
|
|
41962
42131
|
] });
|
|
41963
42132
|
}
|
|
42133
|
+
function MobileTuckControl({
|
|
42134
|
+
canTuck,
|
|
42135
|
+
forceUntuck,
|
|
42136
|
+
onToggleUntuck
|
|
42137
|
+
}) {
|
|
42138
|
+
const {
|
|
42139
|
+
t
|
|
42140
|
+
} = useTranslation();
|
|
42141
|
+
const css2 = useCss((theme) => ({
|
|
42142
|
+
wrapper: {
|
|
42143
|
+
position: "absolute",
|
|
42144
|
+
bottom: "12px",
|
|
42145
|
+
right: "12px"
|
|
42146
|
+
// No z-index: the pill sits above the avatar image (later sibling than
|
|
42147
|
+
// the frame viewer) but below the product-details sheet, which is a
|
|
42148
|
+
// later sibling in the try-on view — so the sheet hides the pill when
|
|
42149
|
+
// it expands over the image.
|
|
42150
|
+
},
|
|
42151
|
+
pill: pillBaseStyle(theme),
|
|
42152
|
+
pillIcon: {
|
|
42153
|
+
width: "14px",
|
|
42154
|
+
height: "14px",
|
|
42155
|
+
flex: "none"
|
|
42156
|
+
}
|
|
42157
|
+
}));
|
|
42158
|
+
if (!canTuck) {
|
|
42159
|
+
return null;
|
|
42160
|
+
}
|
|
42161
|
+
return /* @__PURE__ */ jsx$1("div", { css: css2.wrapper, children: /* @__PURE__ */ jsxs(Button, { variant: "base", css: css2.pill, onClick: onToggleUntuck, children: [
|
|
42162
|
+
/* @__PURE__ */ jsx$1(SvgIconTuck, { css: css2.pillIcon }),
|
|
42163
|
+
/* @__PURE__ */ jsx$1(Text, { variant: "base", children: t(forceUntuck ? "fitting_room.tuck_in" : "fitting_room.untuck") })
|
|
42164
|
+
] }) });
|
|
42165
|
+
}
|
|
42166
|
+
const DRAG_STEP_PX = 50;
|
|
42167
|
+
function useFrameRotation(frameUrls, setSelectedFrameIndex) {
|
|
42168
|
+
const frameCount = frameUrls?.length ?? 0;
|
|
42169
|
+
const rotateLeft = reactExports.useCallback(() => {
|
|
42170
|
+
setSelectedFrameIndex((prev2) => {
|
|
42171
|
+
if (prev2 == null || frameCount === 0) {
|
|
42172
|
+
return prev2;
|
|
42173
|
+
}
|
|
42174
|
+
return prev2 === 0 ? frameCount - 1 : prev2 - 1;
|
|
42175
|
+
});
|
|
42176
|
+
}, [frameCount, setSelectedFrameIndex]);
|
|
42177
|
+
const rotateRight = reactExports.useCallback(() => {
|
|
42178
|
+
setSelectedFrameIndex((prev2) => {
|
|
42179
|
+
if (prev2 == null || frameCount === 0) {
|
|
42180
|
+
return prev2;
|
|
42181
|
+
}
|
|
42182
|
+
return prev2 === frameCount - 1 ? 0 : prev2 + 1;
|
|
42183
|
+
});
|
|
42184
|
+
}, [frameCount, setSelectedFrameIndex]);
|
|
42185
|
+
const handleMouseDragStart = reactExports.useCallback((e) => {
|
|
42186
|
+
e.preventDefault();
|
|
42187
|
+
let startX = e.clientX;
|
|
42188
|
+
const onMove = (move) => {
|
|
42189
|
+
const deltaX = move.clientX - startX;
|
|
42190
|
+
if (Math.abs(deltaX) >= DRAG_STEP_PX) {
|
|
42191
|
+
if (deltaX > 0) {
|
|
42192
|
+
rotateRight();
|
|
42193
|
+
} else {
|
|
42194
|
+
rotateLeft();
|
|
42195
|
+
}
|
|
42196
|
+
startX = move.clientX;
|
|
42197
|
+
}
|
|
42198
|
+
};
|
|
42199
|
+
const onUp = () => {
|
|
42200
|
+
window.removeEventListener("mousemove", onMove);
|
|
42201
|
+
window.removeEventListener("mouseup", onUp);
|
|
42202
|
+
};
|
|
42203
|
+
window.addEventListener("mousemove", onMove);
|
|
42204
|
+
window.addEventListener("mouseup", onUp);
|
|
42205
|
+
}, [rotateLeft, rotateRight]);
|
|
42206
|
+
const handleTouchDragStart = reactExports.useCallback((e) => {
|
|
42207
|
+
e.preventDefault();
|
|
42208
|
+
let startX = e.touches[0].clientX;
|
|
42209
|
+
const onMove = (move) => {
|
|
42210
|
+
const deltaX = move.touches[0].clientX - startX;
|
|
42211
|
+
if (Math.abs(deltaX) >= DRAG_STEP_PX) {
|
|
42212
|
+
if (deltaX > 0) {
|
|
42213
|
+
rotateRight();
|
|
42214
|
+
} else {
|
|
42215
|
+
rotateLeft();
|
|
42216
|
+
}
|
|
42217
|
+
startX = move.touches[0].clientX;
|
|
42218
|
+
}
|
|
42219
|
+
};
|
|
42220
|
+
const onEnd = () => {
|
|
42221
|
+
window.removeEventListener("touchmove", onMove);
|
|
42222
|
+
window.removeEventListener("touchend", onEnd);
|
|
42223
|
+
};
|
|
42224
|
+
window.addEventListener("touchmove", onMove);
|
|
42225
|
+
window.addEventListener("touchend", onEnd);
|
|
42226
|
+
}, [rotateLeft, rotateRight]);
|
|
42227
|
+
return {
|
|
42228
|
+
rotateLeft,
|
|
42229
|
+
rotateRight,
|
|
42230
|
+
handleMouseDragStart,
|
|
42231
|
+
handleTouchDragStart
|
|
42232
|
+
};
|
|
42233
|
+
}
|
|
41964
42234
|
function AvatarFrameViewer({
|
|
41965
42235
|
frameUrls,
|
|
41966
42236
|
selectedFrameIndex,
|
|
41967
42237
|
setSelectedFrameIndex,
|
|
41968
42238
|
imageContainerStyle,
|
|
41969
42239
|
imageStyle,
|
|
41970
|
-
loadingT = "
|
|
42240
|
+
loadingT = "quick-view.avatar_loading"
|
|
41971
42241
|
}) {
|
|
41972
42242
|
const css2 = useCss((_theme) => ({
|
|
41973
42243
|
imageContainer: {
|
|
@@ -42011,59 +42281,17 @@ function AvatarFrameViewer({
|
|
|
42011
42281
|
}, 500);
|
|
42012
42282
|
return () => clearInterval(intervalId);
|
|
42013
42283
|
}, [frameUrls, selectedFrameIndex, setSelectedFrameIndex]);
|
|
42014
|
-
const
|
|
42015
|
-
|
|
42016
|
-
|
|
42017
|
-
|
|
42018
|
-
|
|
42019
|
-
}
|
|
42020
|
-
const rotateRight = reactExports.useCallback(() => {
|
|
42021
|
-
setSelectedFrameIndex((prevIndex) => {
|
|
42022
|
-
if (prevIndex == null) return null;
|
|
42023
|
-
return prevIndex === (frameUrls ? frameUrls.length - 1 : 0) ? 0 : prevIndex + 1;
|
|
42024
|
-
});
|
|
42025
|
-
}, [frameUrls, setSelectedFrameIndex]);
|
|
42026
|
-
const handleImageMouseDrag = reactExports.useCallback((e) => {
|
|
42027
|
-
e.preventDefault();
|
|
42028
|
-
let startX = e.clientX;
|
|
42029
|
-
const onMouseMove = (moveEvent) => {
|
|
42030
|
-
const deltaX = moveEvent.clientX - startX;
|
|
42031
|
-
if (Math.abs(deltaX) >= 50) {
|
|
42032
|
-
if (deltaX > 0) rotateRight();
|
|
42033
|
-
else rotateLeft();
|
|
42034
|
-
startX = moveEvent.clientX;
|
|
42035
|
-
}
|
|
42036
|
-
};
|
|
42037
|
-
const onMouseUp = () => {
|
|
42038
|
-
window.removeEventListener("mousemove", onMouseMove);
|
|
42039
|
-
window.removeEventListener("mouseup", onMouseUp);
|
|
42040
|
-
};
|
|
42041
|
-
window.addEventListener("mousemove", onMouseMove);
|
|
42042
|
-
window.addEventListener("mouseup", onMouseUp);
|
|
42043
|
-
}, [rotateLeft, rotateRight]);
|
|
42044
|
-
const handleImageTouchDrag = reactExports.useCallback((e) => {
|
|
42045
|
-
e.preventDefault();
|
|
42046
|
-
let startX = e.touches[0].clientX;
|
|
42047
|
-
const onTouchMove = (moveEvent) => {
|
|
42048
|
-
const deltaX = moveEvent.touches[0].clientX - startX;
|
|
42049
|
-
if (Math.abs(deltaX) >= 50) {
|
|
42050
|
-
if (deltaX > 0) rotateRight();
|
|
42051
|
-
else rotateLeft();
|
|
42052
|
-
startX = moveEvent.touches[0].clientX;
|
|
42053
|
-
}
|
|
42054
|
-
};
|
|
42055
|
-
const onTouchEnd = () => {
|
|
42056
|
-
window.removeEventListener("touchmove", onTouchMove);
|
|
42057
|
-
window.removeEventListener("touchend", onTouchEnd);
|
|
42058
|
-
};
|
|
42059
|
-
window.addEventListener("touchmove", onTouchMove);
|
|
42060
|
-
window.addEventListener("touchend", onTouchEnd);
|
|
42061
|
-
}, [rotateLeft, rotateRight]);
|
|
42284
|
+
const {
|
|
42285
|
+
rotateLeft,
|
|
42286
|
+
rotateRight,
|
|
42287
|
+
handleMouseDragStart,
|
|
42288
|
+
handleTouchDragStart
|
|
42289
|
+
} = useFrameRotation(frameUrls, setSelectedFrameIndex);
|
|
42062
42290
|
if (!frameUrls || selectedFrameIndex == null) {
|
|
42063
42291
|
return /* @__PURE__ */ jsx$1(Loading, { t: loadingT });
|
|
42064
42292
|
}
|
|
42065
42293
|
return /* @__PURE__ */ jsxs("div", { css: css2.imageContainer, style: imageContainerStyle, children: [
|
|
42066
|
-
/* @__PURE__ */ jsx$1("img", { src: frameUrls[selectedFrameIndex], css: css2.image, style: imageStyle, onMouseDown:
|
|
42294
|
+
/* @__PURE__ */ jsx$1("img", { src: frameUrls[selectedFrameIndex], css: css2.image, style: imageStyle, onMouseDown: handleMouseDragStart, onTouchStart: handleTouchDragStart }),
|
|
42067
42295
|
/* @__PURE__ */ jsx$1("div", { css: css2.chevronLeftContainer, onClick: rotateLeft, children: /* @__PURE__ */ jsx$1(SvgChevronLeft, { css: css2.chevronIcon }) }),
|
|
42068
42296
|
/* @__PURE__ */ jsx$1("div", { css: css2.chevronRightContainer, onClick: rotateRight, children: /* @__PURE__ */ jsx$1(SvgChevronRight, { css: css2.chevronIcon }) })
|
|
42069
42297
|
] });
|
|
@@ -42072,9 +42300,13 @@ function AvatarPane({
|
|
|
42072
42300
|
frameUrls,
|
|
42073
42301
|
hasSelection,
|
|
42074
42302
|
controls,
|
|
42075
|
-
mobileFullscreen
|
|
42303
|
+
mobileFullscreen,
|
|
42304
|
+
selectedFrameIndex: indexProp,
|
|
42305
|
+
setSelectedFrameIndex: setIndexProp
|
|
42076
42306
|
}) {
|
|
42077
|
-
const [
|
|
42307
|
+
const [localFrameIndex, setLocalFrameIndex] = reactExports.useState(null);
|
|
42308
|
+
const selectedFrameIndex = indexProp !== void 0 ? indexProp : localFrameIndex;
|
|
42309
|
+
const setSelectedFrameIndex = setIndexProp ?? setLocalFrameIndex;
|
|
42078
42310
|
const css2 = useCss((theme) => ({
|
|
42079
42311
|
container: {
|
|
42080
42312
|
width: "100%",
|
|
@@ -42132,12 +42364,14 @@ function AvatarPane({
|
|
|
42132
42364
|
}
|
|
42133
42365
|
}));
|
|
42134
42366
|
if (frameUrls && frameUrls.length > 0) {
|
|
42135
|
-
const viewer = /* @__PURE__ */ jsx$1(AvatarFrameViewer, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, imageContainerStyle: css2.frameContainer, imageStyle: css2.frameImage, loadingT: "
|
|
42367
|
+
const viewer = /* @__PURE__ */ jsx$1(AvatarFrameViewer, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, imageContainerStyle: css2.frameContainer, imageStyle: css2.frameImage, loadingT: "quick-view.avatar_loading" });
|
|
42136
42368
|
if (mobileFullscreen) {
|
|
42137
42369
|
return /* @__PURE__ */ jsxs("div", { css: css2.mobileContainer, children: [
|
|
42138
|
-
/* @__PURE__ */
|
|
42139
|
-
|
|
42140
|
-
|
|
42370
|
+
/* @__PURE__ */ jsxs("div", { css: css2.mobileFrameSlot, children: [
|
|
42371
|
+
viewer,
|
|
42372
|
+
controls
|
|
42373
|
+
] }),
|
|
42374
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.bottomFiller, children: " " })
|
|
42141
42375
|
] });
|
|
42142
42376
|
}
|
|
42143
42377
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
@@ -42146,7 +42380,7 @@ function AvatarPane({
|
|
|
42146
42380
|
] });
|
|
42147
42381
|
}
|
|
42148
42382
|
if (hasSelection) {
|
|
42149
|
-
return /* @__PURE__ */ jsx$1("div", { css: css2.container, children: /* @__PURE__ */ jsx$1(Loading, { t: "
|
|
42383
|
+
return /* @__PURE__ */ jsx$1("div", { css: css2.container, children: /* @__PURE__ */ jsx$1(Loading, { t: "quick-view.avatar_loading" }) });
|
|
42150
42384
|
}
|
|
42151
42385
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
42152
42386
|
/* @__PURE__ */ jsx$1("div", { css: css2.placeholder, children: /* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "fitting_room.avatar_placeholder_empty" }) }),
|
|
@@ -42251,7 +42485,9 @@ function ProductCard({
|
|
|
42251
42485
|
const disabled = availability === "disabled";
|
|
42252
42486
|
const selected = availability === "selected";
|
|
42253
42487
|
const handleClick = () => {
|
|
42254
|
-
if (disabled)
|
|
42488
|
+
if (disabled) {
|
|
42489
|
+
return;
|
|
42490
|
+
}
|
|
42255
42491
|
onClick();
|
|
42256
42492
|
};
|
|
42257
42493
|
const name2 = item.merchantProduct?.productName ?? item.externalId;
|
|
@@ -42297,9 +42533,13 @@ function CardRail({
|
|
|
42297
42533
|
setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
|
42298
42534
|
}, []);
|
|
42299
42535
|
reactExports.useLayoutEffect(() => {
|
|
42300
|
-
if (collapsed)
|
|
42536
|
+
if (collapsed) {
|
|
42537
|
+
return;
|
|
42538
|
+
}
|
|
42301
42539
|
const el = scrollRef.current;
|
|
42302
|
-
if (!el)
|
|
42540
|
+
if (!el) {
|
|
42541
|
+
return;
|
|
42542
|
+
}
|
|
42303
42543
|
updateScrollState();
|
|
42304
42544
|
const observer = new ResizeObserver(updateScrollState);
|
|
42305
42545
|
observer.observe(el);
|
|
@@ -42307,7 +42547,9 @@ function CardRail({
|
|
|
42307
42547
|
}, [collapsed, group.items, updateScrollState]);
|
|
42308
42548
|
const scrollByPage = reactExports.useCallback((dir) => {
|
|
42309
42549
|
const el = scrollRef.current;
|
|
42310
|
-
if (!el)
|
|
42550
|
+
if (!el) {
|
|
42551
|
+
return;
|
|
42552
|
+
}
|
|
42311
42553
|
el.scrollBy({
|
|
42312
42554
|
left: dir * el.clientWidth * 0.8,
|
|
42313
42555
|
behavior: "smooth"
|
|
@@ -42400,7 +42642,7 @@ function CardRail({
|
|
|
42400
42642
|
function AddToCartButton({
|
|
42401
42643
|
onClick
|
|
42402
42644
|
}) {
|
|
42403
|
-
return /* @__PURE__ */ jsx$1(ButtonT, { variant: "brand", t: "
|
|
42645
|
+
return /* @__PURE__ */ jsx$1(ButtonT, { variant: "brand", t: "quick-view.add_to_cart", onClick });
|
|
42404
42646
|
}
|
|
42405
42647
|
function ItemFitDetails({
|
|
42406
42648
|
loadedProductData,
|
|
@@ -42501,69 +42743,6 @@ function SizeSelector({
|
|
|
42501
42743
|
}), [loadedProductData.sizes, selectedSizeLabel, onChangeSize]);
|
|
42502
42744
|
return /* @__PURE__ */ jsx$1("div", { css: css2.container, children: sizeSelectorNodeList });
|
|
42503
42745
|
}
|
|
42504
|
-
const logger$b = getLogger("overlays/fitting-room/product-data");
|
|
42505
|
-
function buildVtoProductDataFromResolved(item) {
|
|
42506
|
-
const {
|
|
42507
|
-
merchantProduct,
|
|
42508
|
-
loadedProduct
|
|
42509
|
-
} = item;
|
|
42510
|
-
if (!merchantProduct || !loadedProduct) return null;
|
|
42511
|
-
const sizeRec = loadedProduct.sizeFitRecommendation;
|
|
42512
|
-
const recommendedSizeId = sizeRec.recommended_size.id || null;
|
|
42513
|
-
const recommendedSizeLabel = getSizeLabelFromSize(sizeRec.recommended_size);
|
|
42514
|
-
if (recommendedSizeId == null || !recommendedSizeLabel) {
|
|
42515
|
-
logger$b.logWarn("Missing recommended size for item", {
|
|
42516
|
-
externalId: item.externalId
|
|
42517
|
-
});
|
|
42518
|
-
return null;
|
|
42519
|
-
}
|
|
42520
|
-
const sizes = [];
|
|
42521
|
-
for (const sizeRecord of sizeRec.available_sizes) {
|
|
42522
|
-
const sizeLabel = getSizeLabelFromSize(sizeRecord);
|
|
42523
|
-
if (!sizeLabel) continue;
|
|
42524
|
-
const fit = sizeRec.fits.find((f) => f.size_id === sizeRecord.id);
|
|
42525
|
-
if (!fit) continue;
|
|
42526
|
-
const colors = [];
|
|
42527
|
-
for (const csa of sizeRecord.colorway_size_assets) {
|
|
42528
|
-
const variant = merchantProduct.variants.find((v) => v.sku === csa.sku);
|
|
42529
|
-
if (!variant) continue;
|
|
42530
|
-
colors.push({
|
|
42531
|
-
colorwaySizeAssetId: csa.id,
|
|
42532
|
-
colorLabel: variant.color || null,
|
|
42533
|
-
sku: csa.sku,
|
|
42534
|
-
priceFormatted: variant.priceFormatted
|
|
42535
|
-
});
|
|
42536
|
-
}
|
|
42537
|
-
if (colors.length === 0) continue;
|
|
42538
|
-
sizes.push({
|
|
42539
|
-
sizeId: sizeRecord.id,
|
|
42540
|
-
sizeLabel,
|
|
42541
|
-
isRecommended: sizeRecord.id === recommendedSizeId,
|
|
42542
|
-
fit,
|
|
42543
|
-
colors
|
|
42544
|
-
});
|
|
42545
|
-
}
|
|
42546
|
-
if (sizes.length === 0) return null;
|
|
42547
|
-
return {
|
|
42548
|
-
productName: merchantProduct.productName,
|
|
42549
|
-
productDescriptionHtml: merchantProduct.productDescriptionHtml,
|
|
42550
|
-
fitClassification: sizeRec.fit_classification,
|
|
42551
|
-
recommendedSizeId,
|
|
42552
|
-
recommendedSizeLabel,
|
|
42553
|
-
sizes,
|
|
42554
|
-
styleCategoryLabel: item.styleCategory?.label_singular ?? loadedProduct.style.style_category_label ?? null
|
|
42555
|
-
};
|
|
42556
|
-
}
|
|
42557
|
-
function findRecommendedColorSize(data, preferredColor) {
|
|
42558
|
-
const recommended = data.sizes.find((s) => s.isRecommended);
|
|
42559
|
-
if (!recommended || recommended.colors.length === 0) return null;
|
|
42560
|
-
return recommended.colors.find((c) => c.colorLabel === preferredColor) ?? recommended.colors[0];
|
|
42561
|
-
}
|
|
42562
|
-
function findCsaByLabel(data, sizeLabel, preferredColor) {
|
|
42563
|
-
const sizeRecord = data.sizes.find((s) => s.sizeLabel === sizeLabel);
|
|
42564
|
-
if (!sizeRecord || sizeRecord.colors.length === 0) return null;
|
|
42565
|
-
return sizeRecord.colors.find((c) => c.colorLabel === preferredColor) ?? sizeRecord.colors[0];
|
|
42566
|
-
}
|
|
42567
42746
|
function DetailAccordionItem({
|
|
42568
42747
|
item,
|
|
42569
42748
|
isOpen,
|
|
@@ -42580,9 +42759,13 @@ function DetailAccordionItem({
|
|
|
42580
42759
|
}) {
|
|
42581
42760
|
const productData = reactExports.useMemo(() => buildVtoProductDataFromResolved(item), [item]);
|
|
42582
42761
|
const selectedSizeLabel = reactExports.useMemo(() => {
|
|
42583
|
-
if (!productData)
|
|
42762
|
+
if (!productData) {
|
|
42763
|
+
return null;
|
|
42764
|
+
}
|
|
42584
42765
|
const csaId = item.storage.colorwaySizeAssetId;
|
|
42585
|
-
if (csaId == null)
|
|
42766
|
+
if (csaId == null) {
|
|
42767
|
+
return null;
|
|
42768
|
+
}
|
|
42586
42769
|
for (const sizeRec of productData.sizes) {
|
|
42587
42770
|
if (sizeRec.colors.some((c) => c.colorwaySizeAssetId === csaId)) {
|
|
42588
42771
|
return sizeRec.sizeLabel;
|
|
@@ -42591,12 +42774,18 @@ function DetailAccordionItem({
|
|
|
42591
42774
|
return null;
|
|
42592
42775
|
}, [productData, item.storage.colorwaySizeAssetId]);
|
|
42593
42776
|
const currentPrice = reactExports.useMemo(() => {
|
|
42594
|
-
if (!productData)
|
|
42777
|
+
if (!productData) {
|
|
42778
|
+
return null;
|
|
42779
|
+
}
|
|
42595
42780
|
const csaId = item.storage.colorwaySizeAssetId;
|
|
42596
|
-
if (csaId == null)
|
|
42781
|
+
if (csaId == null) {
|
|
42782
|
+
return null;
|
|
42783
|
+
}
|
|
42597
42784
|
for (const sizeRec of productData.sizes) {
|
|
42598
42785
|
const c = sizeRec.colors.find((c2) => c2.colorwaySizeAssetId === csaId);
|
|
42599
|
-
if (c)
|
|
42786
|
+
if (c) {
|
|
42787
|
+
return c.priceFormatted;
|
|
42788
|
+
}
|
|
42600
42789
|
}
|
|
42601
42790
|
return null;
|
|
42602
42791
|
}, [productData, item.storage.colorwaySizeAssetId]);
|
|
@@ -42923,6 +43112,119 @@ function DetailAccordion({
|
|
|
42923
43112
|
return /* @__PURE__ */ jsx$1(DetailAccordionItem, { item, isOpen, platform, detailMode, isMobileQuickRow, forceUntuck, canTuck, onToggleOpen: () => onOpenItem(isOpen ? null : item.externalId), onChangeDetailMode, onChangeSize: (label) => onChangeSize(item.externalId, label), onAddToCart: () => onAddToCart(item.externalId), onToggleUntuck }, item.externalId);
|
|
42924
43113
|
}) });
|
|
42925
43114
|
}
|
|
43115
|
+
function ZoomModal({
|
|
43116
|
+
frameUrls,
|
|
43117
|
+
selectedFrameIndex,
|
|
43118
|
+
setSelectedFrameIndex,
|
|
43119
|
+
onClose
|
|
43120
|
+
}) {
|
|
43121
|
+
reactExports.useEffect(() => {
|
|
43122
|
+
const onKeyDown = (e) => {
|
|
43123
|
+
if (e.key === "Escape") {
|
|
43124
|
+
e.stopPropagation();
|
|
43125
|
+
e.preventDefault();
|
|
43126
|
+
onClose();
|
|
43127
|
+
}
|
|
43128
|
+
};
|
|
43129
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
43130
|
+
return () => document.removeEventListener("keydown", onKeyDown, true);
|
|
43131
|
+
}, [onClose]);
|
|
43132
|
+
const {
|
|
43133
|
+
rotateLeft,
|
|
43134
|
+
rotateRight,
|
|
43135
|
+
handleMouseDragStart,
|
|
43136
|
+
handleTouchDragStart
|
|
43137
|
+
} = useFrameRotation(frameUrls, setSelectedFrameIndex);
|
|
43138
|
+
const css2 = useCss((_theme) => ({
|
|
43139
|
+
backdrop: {
|
|
43140
|
+
position: "fixed",
|
|
43141
|
+
inset: 0,
|
|
43142
|
+
backgroundColor: "#F4F4F4",
|
|
43143
|
+
zIndex: 100
|
|
43144
|
+
},
|
|
43145
|
+
scrollArea: {
|
|
43146
|
+
position: "absolute",
|
|
43147
|
+
// 40px padding on every side.
|
|
43148
|
+
inset: "40px",
|
|
43149
|
+
overflow: "auto"
|
|
43150
|
+
},
|
|
43151
|
+
// Centres the frame when it fits; grows past the scroll area when it
|
|
43152
|
+
// doesn't, so the scroll area scrolls instead of shrinking the image.
|
|
43153
|
+
imageWrap: {
|
|
43154
|
+
minWidth: "100%",
|
|
43155
|
+
minHeight: "100%",
|
|
43156
|
+
display: "flex",
|
|
43157
|
+
alignItems: "center",
|
|
43158
|
+
justifyContent: "center"
|
|
43159
|
+
},
|
|
43160
|
+
image: {
|
|
43161
|
+
// No sizing — the frame renders at its natural (full) resolution.
|
|
43162
|
+
display: "block",
|
|
43163
|
+
flex: "none",
|
|
43164
|
+
cursor: "grab"
|
|
43165
|
+
},
|
|
43166
|
+
// Rotation chevrons float at the modal's vertical centre, so they stay
|
|
43167
|
+
// put regardless of how the (possibly larger) frame is scrolled.
|
|
43168
|
+
chevron: {
|
|
43169
|
+
position: "absolute",
|
|
43170
|
+
top: "50%",
|
|
43171
|
+
transform: "translateY(-50%)",
|
|
43172
|
+
display: "flex",
|
|
43173
|
+
cursor: "pointer",
|
|
43174
|
+
zIndex: 1
|
|
43175
|
+
},
|
|
43176
|
+
chevronLeft: {
|
|
43177
|
+
left: "8px"
|
|
43178
|
+
},
|
|
43179
|
+
chevronRight: {
|
|
43180
|
+
right: "8px"
|
|
43181
|
+
},
|
|
43182
|
+
chevronIcon: {
|
|
43183
|
+
width: "48px",
|
|
43184
|
+
height: "48px"
|
|
43185
|
+
},
|
|
43186
|
+
close: {
|
|
43187
|
+
position: "absolute",
|
|
43188
|
+
top: "8px",
|
|
43189
|
+
right: "8px",
|
|
43190
|
+
width: "44px",
|
|
43191
|
+
height: "44px",
|
|
43192
|
+
display: "flex",
|
|
43193
|
+
alignItems: "center",
|
|
43194
|
+
justifyContent: "center",
|
|
43195
|
+
borderRadius: "50%",
|
|
43196
|
+
border: "none",
|
|
43197
|
+
// Reset native button chrome and default padding so the circle renders
|
|
43198
|
+
// exactly as styled.
|
|
43199
|
+
appearance: "none",
|
|
43200
|
+
WebkitAppearance: "none",
|
|
43201
|
+
padding: 0,
|
|
43202
|
+
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
43203
|
+
color: "#FFFFFF",
|
|
43204
|
+
fontSize: "32px",
|
|
43205
|
+
lineHeight: 1,
|
|
43206
|
+
cursor: "pointer",
|
|
43207
|
+
// Keep the "×" glyph from being text-selected — a stray selection
|
|
43208
|
+
// paints a dark highlight rectangle behind it.
|
|
43209
|
+
userSelect: "none",
|
|
43210
|
+
WebkitUserSelect: "none",
|
|
43211
|
+
zIndex: 1
|
|
43212
|
+
}
|
|
43213
|
+
}));
|
|
43214
|
+
const imageUrl = frameUrls[selectedFrameIndex ?? 0];
|
|
43215
|
+
return /* @__PURE__ */ jsxs("div", { css: css2.backdrop, children: [
|
|
43216
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.scrollArea, children: /* @__PURE__ */ jsx$1("div", { css: css2.imageWrap, children: /* @__PURE__ */ jsx$1("img", { src: imageUrl, css: css2.image, alt: "", onMouseDown: handleMouseDragStart, onTouchStart: handleTouchDragStart }) }) }),
|
|
43217
|
+
/* @__PURE__ */ jsx$1("div", { css: /* @__PURE__ */ css$1({
|
|
43218
|
+
...css2.chevron,
|
|
43219
|
+
...css2.chevronLeft
|
|
43220
|
+
}, "", ""), onClick: rotateLeft, children: /* @__PURE__ */ jsx$1(SvgChevronLeft, { css: css2.chevronIcon }) }),
|
|
43221
|
+
/* @__PURE__ */ jsx$1("div", { css: /* @__PURE__ */ css$1({
|
|
43222
|
+
...css2.chevron,
|
|
43223
|
+
...css2.chevronRight
|
|
43224
|
+
}, "", ""), onClick: rotateRight, children: /* @__PURE__ */ jsx$1(SvgChevronRight, { css: css2.chevronIcon }) }),
|
|
43225
|
+
/* @__PURE__ */ jsx$1("button", { css: css2.close, onClick: onClose, "aria-label": "Close zoom", children: "×" })
|
|
43226
|
+
] });
|
|
43227
|
+
}
|
|
42926
43228
|
const AVATAR_ASPECT_RATIO = 2 / 3;
|
|
42927
43229
|
const EDGE_INSET_PX = 16;
|
|
42928
43230
|
const AVATAR_MIN_WIDTH_PX = 240;
|
|
@@ -42938,7 +43240,6 @@ function DesktopLayout$1({
|
|
|
42938
43240
|
detailMode,
|
|
42939
43241
|
forceUntuck,
|
|
42940
43242
|
canTuck,
|
|
42941
|
-
zoomed,
|
|
42942
43243
|
frameUrls,
|
|
42943
43244
|
onSelectItem,
|
|
42944
43245
|
onRemoveItem,
|
|
@@ -42947,26 +43248,31 @@ function DesktopLayout$1({
|
|
|
42947
43248
|
onChangeSize,
|
|
42948
43249
|
onAddToCart,
|
|
42949
43250
|
onToggleUntuck,
|
|
42950
|
-
onToggleZoom,
|
|
42951
43251
|
onSignOut
|
|
42952
43252
|
}) {
|
|
42953
43253
|
const hasSelection = selectedItems.length > 0;
|
|
42954
43254
|
const [avatarHovered, setAvatarHovered] = reactExports.useState(false);
|
|
43255
|
+
const [zoomOpen, setZoomOpen] = reactExports.useState(false);
|
|
43256
|
+
const [selectedFrameIndex, setSelectedFrameIndex] = reactExports.useState(null);
|
|
42955
43257
|
const containerRef = reactExports.useRef(null);
|
|
42956
43258
|
const [avatarWidth, setAvatarWidth] = reactExports.useState(AVATAR_MIN_WIDTH_PX);
|
|
42957
43259
|
reactExports.useLayoutEffect(() => {
|
|
42958
43260
|
const el = containerRef.current;
|
|
42959
|
-
if (!el)
|
|
43261
|
+
if (!el) {
|
|
43262
|
+
return;
|
|
43263
|
+
}
|
|
42960
43264
|
const observer = new ResizeObserver(() => {
|
|
42961
43265
|
const availableHeightPx = el.clientHeight;
|
|
42962
|
-
if (availableHeightPx <= 0)
|
|
43266
|
+
if (availableHeightPx <= 0) {
|
|
43267
|
+
return;
|
|
43268
|
+
}
|
|
42963
43269
|
const target = Math.floor(availableHeightPx * AVATAR_ASPECT_RATIO);
|
|
42964
43270
|
setAvatarWidth(Math.min(AVATAR_MAX_WIDTH_PX, Math.max(AVATAR_MIN_WIDTH_PX, target)));
|
|
42965
43271
|
});
|
|
42966
43272
|
observer.observe(el);
|
|
42967
43273
|
return () => observer.disconnect();
|
|
42968
43274
|
}, []);
|
|
42969
|
-
const gridTemplateColumns =
|
|
43275
|
+
const gridTemplateColumns = hasSelection ? `${avatarWidth}px minmax(${DETAILS_MIN_WIDTH_PX}px, ${DETAILS_FR}fr) ${CARDS_FR}fr` : `${avatarWidth}px 1fr`;
|
|
42970
43276
|
const css2 = useCss((_theme) => ({
|
|
42971
43277
|
container: {
|
|
42972
43278
|
display: "grid",
|
|
@@ -43031,21 +43337,127 @@ function DesktopLayout$1({
|
|
|
43031
43337
|
fontSize: "14px"
|
|
43032
43338
|
}
|
|
43033
43339
|
}));
|
|
43034
|
-
const controls = hasSelection ? /* @__PURE__ */ jsx$1(AvatarControls, { selectedItems, canTuck, forceUntuck, zoomed, expanded: avatarHovered, onToggleUntuck, onToggleZoom, onRemoveItem }) : null;
|
|
43340
|
+
const controls = hasSelection ? /* @__PURE__ */ jsx$1(AvatarControls, { selectedItems, canTuck, forceUntuck, zoomed: zoomOpen, expanded: avatarHovered, onToggleUntuck, onToggleZoom: () => setZoomOpen(true), onRemoveItem }) : null;
|
|
43035
43341
|
return /* @__PURE__ */ jsxs("div", { ref: containerRef, css: css2.container, style: {
|
|
43036
43342
|
gridTemplateColumns
|
|
43037
43343
|
}, children: [
|
|
43038
|
-
/* @__PURE__ */ jsx$1("div", { css: css2.avatarColumn, onMouseEnter: () => setAvatarHovered(true), onMouseLeave: () => setAvatarHovered(false), children: /* @__PURE__ */ jsx$1(AvatarPane, { hasSelection, frameUrls, controls }) }),
|
|
43039
|
-
|
|
43040
|
-
|
|
43344
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.avatarColumn, onMouseEnter: () => setAvatarHovered(true), onMouseLeave: () => setAvatarHovered(false), children: /* @__PURE__ */ jsx$1(AvatarPane, { hasSelection, frameUrls, controls, selectedFrameIndex, setSelectedFrameIndex }) }),
|
|
43345
|
+
hasSelection ? /* @__PURE__ */ jsx$1("div", { css: css2.detailColumn, children: /* @__PURE__ */ jsx$1(DetailAccordion, { items: selectedItems, openItemExternalId: openAccordionItemId, platform: "desktop", detailMode, isMobileQuickRow: false, forceUntuck, canTuck, onOpenItem: onOpenAccordionItem, onChangeDetailMode, onChangeSize, onAddToCart, onToggleUntuck }) }) : null,
|
|
43346
|
+
/* @__PURE__ */ jsxs("div", { css: css2.railsColumn, children: [
|
|
43041
43347
|
/* @__PURE__ */ jsxs("span", { css: css2.signOutWrapper, onClick: onSignOut, children: [
|
|
43042
43348
|
/* @__PURE__ */ jsx$1(SvgTfrIcon, { css: css2.signOutIcon }),
|
|
43043
43349
|
/* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.signOut, t: "fitting_room.sign_out" })
|
|
43044
43350
|
] }),
|
|
43045
43351
|
resolved.groups.map((group) => /* @__PURE__ */ jsx$1(CardRail, { group, availabilityByExternalId, onSelectItem, onRemoveItem }, group.group.name))
|
|
43046
|
-
] })
|
|
43352
|
+
] }),
|
|
43353
|
+
zoomOpen && frameUrls && frameUrls.length > 0 ? /* @__PURE__ */ jsx$1(ZoomModal, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, onClose: () => setZoomOpen(false) }) : null
|
|
43047
43354
|
] });
|
|
43048
43355
|
}
|
|
43356
|
+
function MenuIcon({
|
|
43357
|
+
size = 20
|
|
43358
|
+
}) {
|
|
43359
|
+
return /* @__PURE__ */ jsx$1("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", children: /* @__PURE__ */ jsx$1("path", { d: "M4 7H20M4 12H20M4 17H20", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) });
|
|
43360
|
+
}
|
|
43361
|
+
function SectionNav({
|
|
43362
|
+
sections,
|
|
43363
|
+
activeName,
|
|
43364
|
+
onSelect
|
|
43365
|
+
}) {
|
|
43366
|
+
const [open, setOpen] = reactExports.useState(false);
|
|
43367
|
+
const wrapperRef = reactExports.useRef(null);
|
|
43368
|
+
reactExports.useEffect(() => {
|
|
43369
|
+
if (!open) {
|
|
43370
|
+
return;
|
|
43371
|
+
}
|
|
43372
|
+
const onDocClick = (e) => {
|
|
43373
|
+
if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
|
|
43374
|
+
setOpen(false);
|
|
43375
|
+
}
|
|
43376
|
+
};
|
|
43377
|
+
document.addEventListener("mousedown", onDocClick);
|
|
43378
|
+
return () => document.removeEventListener("mousedown", onDocClick);
|
|
43379
|
+
}, [open]);
|
|
43380
|
+
const handleSelect = reactExports.useCallback((name2) => {
|
|
43381
|
+
setOpen(false);
|
|
43382
|
+
onSelect(name2);
|
|
43383
|
+
}, [onSelect]);
|
|
43384
|
+
const css2 = useCss((theme) => ({
|
|
43385
|
+
wrapper: {
|
|
43386
|
+
// Floats over the card rails at the top-right instead of taking its own
|
|
43387
|
+
// row in the browse-view column (BrowseView's container is relative).
|
|
43388
|
+
position: "absolute",
|
|
43389
|
+
top: "12px",
|
|
43390
|
+
right: "16px",
|
|
43391
|
+
// Above the rails so the pill and its drop-down sit over the content.
|
|
43392
|
+
zIndex: 5
|
|
43393
|
+
},
|
|
43394
|
+
bar: {
|
|
43395
|
+
display: "inline-flex",
|
|
43396
|
+
alignItems: "center",
|
|
43397
|
+
gap: "8px",
|
|
43398
|
+
padding: "6px 16px",
|
|
43399
|
+
borderRadius: "999px",
|
|
43400
|
+
backgroundColor: theme.color_fg_text,
|
|
43401
|
+
color: "#FFFFFF",
|
|
43402
|
+
border: "none",
|
|
43403
|
+
cursor: "pointer",
|
|
43404
|
+
fontSize: "13px",
|
|
43405
|
+
fontWeight: "500",
|
|
43406
|
+
letterSpacing: "0.5px",
|
|
43407
|
+
textTransform: "uppercase",
|
|
43408
|
+
whiteSpace: "nowrap"
|
|
43409
|
+
},
|
|
43410
|
+
icon: {
|
|
43411
|
+
display: "inline-flex",
|
|
43412
|
+
alignItems: "center",
|
|
43413
|
+
flex: "none"
|
|
43414
|
+
},
|
|
43415
|
+
dropdown: {
|
|
43416
|
+
position: "absolute",
|
|
43417
|
+
top: "calc(100% + 6px)",
|
|
43418
|
+
right: 0,
|
|
43419
|
+
// At least as wide as the pill, growing to fit the longest label.
|
|
43420
|
+
minWidth: "100%",
|
|
43421
|
+
backgroundColor: theme.color_fg_text,
|
|
43422
|
+
borderRadius: "16px",
|
|
43423
|
+
maxHeight: "60vh",
|
|
43424
|
+
overflowY: "auto",
|
|
43425
|
+
boxShadow: "0 6px 16px rgba(0, 0, 0, 0.25)"
|
|
43426
|
+
},
|
|
43427
|
+
item: {
|
|
43428
|
+
display: "block",
|
|
43429
|
+
width: "100%",
|
|
43430
|
+
textAlign: "left",
|
|
43431
|
+
whiteSpace: "nowrap",
|
|
43432
|
+
padding: "8px 18px",
|
|
43433
|
+
backgroundColor: "transparent",
|
|
43434
|
+
color: "#FFFFFF",
|
|
43435
|
+
border: "none",
|
|
43436
|
+
cursor: "pointer",
|
|
43437
|
+
fontSize: "13px",
|
|
43438
|
+
letterSpacing: "0.5px",
|
|
43439
|
+
textTransform: "uppercase",
|
|
43440
|
+
"&:not(:first-of-type)": {
|
|
43441
|
+
borderTop: "1px solid rgba(255, 255, 255, 0.12)"
|
|
43442
|
+
}
|
|
43443
|
+
},
|
|
43444
|
+
itemActive: {
|
|
43445
|
+
backgroundColor: "rgba(255, 255, 255, 0.16)"
|
|
43446
|
+
}
|
|
43447
|
+
}));
|
|
43448
|
+
const activeLabel = sections.find((s) => s.name === activeName)?.label ?? sections[0]?.label ?? "";
|
|
43449
|
+
return /* @__PURE__ */ jsxs("div", { ref: wrapperRef, css: css2.wrapper, children: [
|
|
43450
|
+
/* @__PURE__ */ jsxs(Button, { variant: "base", css: css2.bar, onClick: () => setOpen((o) => !o), children: [
|
|
43451
|
+
/* @__PURE__ */ jsx$1("span", { children: activeLabel }),
|
|
43452
|
+
/* @__PURE__ */ jsx$1("span", { css: css2.icon, children: open ? /* @__PURE__ */ jsx$1(Chevron, { direction: "up", size: 20 }) : /* @__PURE__ */ jsx$1(MenuIcon, { size: 20 }) })
|
|
43453
|
+
] }),
|
|
43454
|
+
open ? /* @__PURE__ */ jsx$1("div", { css: css2.dropdown, children: sections.map((s) => /* @__PURE__ */ jsx$1(Button, { variant: "base", css: s.name === activeName ? {
|
|
43455
|
+
...css2.item,
|
|
43456
|
+
...css2.itemActive
|
|
43457
|
+
} : css2.item, onClick: () => handleSelect(s.name), children: s.label }, s.name)) }) : null
|
|
43458
|
+
] });
|
|
43459
|
+
}
|
|
43460
|
+
const SECTION_SCROLL_TOP_GAP_PX = 50;
|
|
43049
43461
|
function MobileLayout$1({
|
|
43050
43462
|
mode,
|
|
43051
43463
|
resolved,
|
|
@@ -43081,12 +43493,55 @@ function BrowseView({
|
|
|
43081
43493
|
onRemoveItem,
|
|
43082
43494
|
onTryItOn
|
|
43083
43495
|
}) {
|
|
43496
|
+
const railsAreaRef = reactExports.useRef(null);
|
|
43497
|
+
const sectionRefs = reactExports.useRef(/* @__PURE__ */ new Map());
|
|
43498
|
+
const [activeSectionName, setActiveSectionName] = reactExports.useState(null);
|
|
43499
|
+
const sections = resolved.groups.map((g) => ({
|
|
43500
|
+
name: g.group.name,
|
|
43501
|
+
label: g.group.label
|
|
43502
|
+
}));
|
|
43503
|
+
const recomputeActiveSection = reactExports.useCallback(() => {
|
|
43504
|
+
const container = railsAreaRef.current;
|
|
43505
|
+
if (!container) {
|
|
43506
|
+
return;
|
|
43507
|
+
}
|
|
43508
|
+
const containerTop = container.getBoundingClientRect().top;
|
|
43509
|
+
let active = null;
|
|
43510
|
+
for (const [name2, el] of sectionRefs.current) {
|
|
43511
|
+
if (el.getBoundingClientRect().top >= containerTop - 1) {
|
|
43512
|
+
active = name2;
|
|
43513
|
+
break;
|
|
43514
|
+
}
|
|
43515
|
+
}
|
|
43516
|
+
if (active == null) {
|
|
43517
|
+
const groups = resolved.groups;
|
|
43518
|
+
active = groups.length > 0 ? groups[groups.length - 1].group.name : null;
|
|
43519
|
+
}
|
|
43520
|
+
setActiveSectionName(active);
|
|
43521
|
+
}, [resolved.groups]);
|
|
43522
|
+
reactExports.useLayoutEffect(() => {
|
|
43523
|
+
recomputeActiveSection();
|
|
43524
|
+
}, [recomputeActiveSection, resolved.groups]);
|
|
43525
|
+
const scrollToSection = reactExports.useCallback((name2) => {
|
|
43526
|
+
const container = railsAreaRef.current;
|
|
43527
|
+
const el = sectionRefs.current.get(name2);
|
|
43528
|
+
if (!container || !el) {
|
|
43529
|
+
return;
|
|
43530
|
+
}
|
|
43531
|
+
const delta = el.getBoundingClientRect().top - container.getBoundingClientRect().top;
|
|
43532
|
+
container.scrollBy({
|
|
43533
|
+
top: delta - SECTION_SCROLL_TOP_GAP_PX,
|
|
43534
|
+
behavior: "smooth"
|
|
43535
|
+
});
|
|
43536
|
+
}, []);
|
|
43084
43537
|
const css2 = useCss((_theme) => ({
|
|
43085
43538
|
container: {
|
|
43086
43539
|
display: "flex",
|
|
43087
43540
|
flexDirection: "column",
|
|
43088
43541
|
height: "100%",
|
|
43089
|
-
width: "100%"
|
|
43542
|
+
width: "100%",
|
|
43543
|
+
// Positioning context for the floating SectionNav pill.
|
|
43544
|
+
position: "relative"
|
|
43090
43545
|
},
|
|
43091
43546
|
railsArea: {
|
|
43092
43547
|
flex: 1,
|
|
@@ -43104,7 +43559,14 @@ function BrowseView({
|
|
|
43104
43559
|
}
|
|
43105
43560
|
}));
|
|
43106
43561
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
43107
|
-
|
|
43562
|
+
!resolved.isLoading && resolved.groups.length > 0 ? /* @__PURE__ */ jsx$1(SectionNav, { sections, activeName: activeSectionName, onSelect: scrollToSection }) : null,
|
|
43563
|
+
/* @__PURE__ */ jsx$1("div", { ref: railsAreaRef, css: css2.railsArea, onScroll: recomputeActiveSection, children: resolved.groups.map((group) => /* @__PURE__ */ jsx$1("div", { ref: (el) => {
|
|
43564
|
+
if (el) {
|
|
43565
|
+
sectionRefs.current.set(group.group.name, el);
|
|
43566
|
+
} else {
|
|
43567
|
+
sectionRefs.current.delete(group.group.name);
|
|
43568
|
+
}
|
|
43569
|
+
}, children: /* @__PURE__ */ jsx$1(CardRail, { group, availabilityByExternalId, onSelectItem, onRemoveItem }) }, group.group.name)) }),
|
|
43108
43570
|
resolved.groups.length > 0 ? /* @__PURE__ */ jsx$1("div", { css: css2.bottomBar, children: /* @__PURE__ */ jsx$1(ButtonT, { variant: "brand", t: "fitting_room.try_it_on", onClick: onTryItOn, disabled: selectedCount === 0 }) }) : null
|
|
43109
43571
|
] });
|
|
43110
43572
|
}
|
|
@@ -43130,8 +43592,14 @@ function TryOnView({
|
|
|
43130
43592
|
reactExports.useEffect(() => {
|
|
43131
43593
|
function refresh() {
|
|
43132
43594
|
const el = innerRef.current;
|
|
43133
|
-
if (!el)
|
|
43134
|
-
|
|
43595
|
+
if (!el) {
|
|
43596
|
+
return;
|
|
43597
|
+
}
|
|
43598
|
+
const parentEl = el.parentElement;
|
|
43599
|
+
if (!parentEl) {
|
|
43600
|
+
return;
|
|
43601
|
+
}
|
|
43602
|
+
const maxHeightPx = Number(window.getComputedStyle(parentEl).getPropertyValue("max-height").replace("px", ""));
|
|
43135
43603
|
const heightPx = Math.min(el.clientHeight, maxHeightPx || el.clientHeight);
|
|
43136
43604
|
setSheetStyle({
|
|
43137
43605
|
height: `${heightPx}px`
|
|
@@ -43167,7 +43635,7 @@ function TryOnView({
|
|
|
43167
43635
|
},
|
|
43168
43636
|
sheetOuter: {
|
|
43169
43637
|
position: "absolute",
|
|
43170
|
-
// 8px gap to either side, matching
|
|
43638
|
+
// 8px gap to either side, matching quick-view's mobile sheet.
|
|
43171
43639
|
left: "8px",
|
|
43172
43640
|
right: "8px",
|
|
43173
43641
|
bottom: 0,
|
|
@@ -43208,7 +43676,7 @@ function TryOnView({
|
|
|
43208
43676
|
}
|
|
43209
43677
|
}));
|
|
43210
43678
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
43211
|
-
/* @__PURE__ */ jsx$1(AvatarPane, { hasSelection: selectedItems.length > 0, frameUrls, mobileFullscreen: true }),
|
|
43679
|
+
/* @__PURE__ */ jsx$1(AvatarPane, { hasSelection: selectedItems.length > 0, frameUrls, mobileFullscreen: true, controls: /* @__PURE__ */ jsx$1(MobileTuckControl, { canTuck, forceUntuck, onToggleUntuck }) }),
|
|
43212
43680
|
/* @__PURE__ */ jsx$1(Button, { variant: "base", css: css2.backButton, onClick: onBackToBrowse, "aria-label": "Back to browse", children: /* @__PURE__ */ jsx$1(SvgIconLeftArrow, { css: css2.backArrow }) }),
|
|
43213
43681
|
/* @__PURE__ */ jsx$1("div", { css: css2.sheetOuter, style: sheetStyle, children: /* @__PURE__ */ jsxs("div", { ref: innerRef, css: css2.sheetInner, style: sheetStyle, children: [
|
|
43214
43682
|
/* @__PURE__ */ jsxs("div", { css: css2.sheetHandleRow, onTouchStart: sheetTouchStart, children: [
|
|
@@ -43219,8 +43687,7 @@ function TryOnView({
|
|
|
43219
43687
|
] }) })
|
|
43220
43688
|
] });
|
|
43221
43689
|
}
|
|
43222
|
-
const logger$
|
|
43223
|
-
const NON_PRIORITY_REQUEST_DELAY_MS = 500;
|
|
43690
|
+
const logger$9 = getLogger("use-vto-requests");
|
|
43224
43691
|
function outfitKey(items) {
|
|
43225
43692
|
return items.map((i) => `${i.colorway_size_asset_id}:${i.untucked ? 1 : 0}`).sort().join("|");
|
|
43226
43693
|
}
|
|
@@ -43228,21 +43695,26 @@ function useVtoRequests() {
|
|
|
43228
43695
|
const [framesByKey, setFramesByKey] = reactExports.useState({});
|
|
43229
43696
|
const requestedKeysRef = reactExports.useRef(/* @__PURE__ */ new Set());
|
|
43230
43697
|
const lastPriorityTimeRef = reactExports.useRef(null);
|
|
43698
|
+
const pendingPrefetchTimersRef = reactExports.useRef(/* @__PURE__ */ new Set());
|
|
43231
43699
|
const [lastError, setLastError] = reactExports.useState(null);
|
|
43232
43700
|
const clearError = reactExports.useCallback(() => setLastError(null), []);
|
|
43233
43701
|
const request = reactExports.useCallback((items, priority) => {
|
|
43234
|
-
if (items.length === 0)
|
|
43702
|
+
if (items.length === 0) {
|
|
43703
|
+
return;
|
|
43704
|
+
}
|
|
43235
43705
|
const key = outfitKey(items);
|
|
43236
|
-
if (requestedKeysRef.current.has(key))
|
|
43706
|
+
if (requestedKeysRef.current.has(key)) {
|
|
43707
|
+
return;
|
|
43708
|
+
}
|
|
43237
43709
|
const exec = () => {
|
|
43238
43710
|
requestedKeysRef.current.add(key);
|
|
43239
|
-
logger$
|
|
43711
|
+
logger$9.logDebug("Requesting VTO composition", {
|
|
43240
43712
|
key,
|
|
43241
43713
|
items,
|
|
43242
43714
|
priority
|
|
43243
43715
|
});
|
|
43244
43716
|
requestVto(items).then((resp) => {
|
|
43245
|
-
logger$
|
|
43717
|
+
logger$9.logDebug("VTO frames ready", {
|
|
43246
43718
|
key,
|
|
43247
43719
|
count: resp.frames.length
|
|
43248
43720
|
});
|
|
@@ -43251,7 +43723,7 @@ function useVtoRequests() {
|
|
|
43251
43723
|
[key]: resp.frames
|
|
43252
43724
|
}));
|
|
43253
43725
|
}).catch((error) => {
|
|
43254
|
-
logger$
|
|
43726
|
+
logger$9.logError("VTO request failed", {
|
|
43255
43727
|
error,
|
|
43256
43728
|
items,
|
|
43257
43729
|
key
|
|
@@ -43261,6 +43733,10 @@ function useVtoRequests() {
|
|
|
43261
43733
|
});
|
|
43262
43734
|
};
|
|
43263
43735
|
if (priority) {
|
|
43736
|
+
for (const timer of pendingPrefetchTimersRef.current) {
|
|
43737
|
+
clearTimeout(timer);
|
|
43738
|
+
}
|
|
43739
|
+
pendingPrefetchTimersRef.current.clear();
|
|
43264
43740
|
lastPriorityTimeRef.current = Date.now();
|
|
43265
43741
|
exec();
|
|
43266
43742
|
return;
|
|
@@ -43269,20 +43745,39 @@ function useVtoRequests() {
|
|
|
43269
43745
|
let delay = 0;
|
|
43270
43746
|
if (last) {
|
|
43271
43747
|
const now = Date.now();
|
|
43272
|
-
const minNext = last +
|
|
43273
|
-
if (now < minNext)
|
|
43748
|
+
const minNext = last + getStaticData().config.api.vtoPrefetchDelayMs;
|
|
43749
|
+
if (now < minNext) {
|
|
43750
|
+
delay = minNext - now;
|
|
43751
|
+
}
|
|
43274
43752
|
}
|
|
43275
43753
|
if (delay > 0) {
|
|
43276
|
-
setTimeout(
|
|
43754
|
+
const timer = setTimeout(() => {
|
|
43755
|
+
pendingPrefetchTimersRef.current.delete(timer);
|
|
43756
|
+
exec();
|
|
43757
|
+
}, delay);
|
|
43758
|
+
pendingPrefetchTimersRef.current.add(timer);
|
|
43277
43759
|
} else {
|
|
43278
43760
|
exec();
|
|
43279
43761
|
}
|
|
43280
43762
|
}, []);
|
|
43763
|
+
reactExports.useEffect(() => {
|
|
43764
|
+
const timers = pendingPrefetchTimersRef.current;
|
|
43765
|
+
return () => {
|
|
43766
|
+
for (const timer of timers) {
|
|
43767
|
+
clearTimeout(timer);
|
|
43768
|
+
}
|
|
43769
|
+
timers.clear();
|
|
43770
|
+
};
|
|
43771
|
+
}, []);
|
|
43281
43772
|
const framesForOutfit = reactExports.useCallback((items) => {
|
|
43282
|
-
if (items.length === 0)
|
|
43773
|
+
if (items.length === 0) {
|
|
43774
|
+
return null;
|
|
43775
|
+
}
|
|
43283
43776
|
const key = outfitKey(items);
|
|
43284
43777
|
const frames = framesByKey[key];
|
|
43285
|
-
if (!frames || frames.length === 0)
|
|
43778
|
+
if (!frames || frames.length === 0) {
|
|
43779
|
+
return null;
|
|
43780
|
+
}
|
|
43286
43781
|
const baseUrl2 = getStaticData().config.frames.baseUrl;
|
|
43287
43782
|
return frames.map((u) => applyFrameBaseUrl(u, baseUrl2));
|
|
43288
43783
|
}, [framesByKey]);
|
|
@@ -43301,12 +43796,14 @@ function toWireItems(items) {
|
|
|
43301
43796
|
} : {}
|
|
43302
43797
|
}));
|
|
43303
43798
|
}
|
|
43304
|
-
const logger$
|
|
43799
|
+
const logger$8 = getLogger("overlays/fitting-room");
|
|
43305
43800
|
function measureTopOffset() {
|
|
43306
43801
|
const {
|
|
43307
43802
|
getOverlayTopOffset
|
|
43308
43803
|
} = getStaticData();
|
|
43309
|
-
if (!getOverlayTopOffset)
|
|
43804
|
+
if (!getOverlayTopOffset) {
|
|
43805
|
+
return 0;
|
|
43806
|
+
}
|
|
43310
43807
|
try {
|
|
43311
43808
|
const offset = getOverlayTopOffset();
|
|
43312
43809
|
return Number.isFinite(offset) && offset > 0 ? offset : 0;
|
|
@@ -43314,7 +43811,9 @@ function measureTopOffset() {
|
|
|
43314
43811
|
return 0;
|
|
43315
43812
|
}
|
|
43316
43813
|
}
|
|
43317
|
-
function FittingRoomOverlay(
|
|
43814
|
+
function FittingRoomOverlay({
|
|
43815
|
+
preselectExternalId
|
|
43816
|
+
}) {
|
|
43318
43817
|
const deviceLayout = useMainStore((state) => state.deviceLayout);
|
|
43319
43818
|
const userIsLoggedIn = useMainStore((state) => state.userIsLoggedIn);
|
|
43320
43819
|
const userHasAvatar = useMainStore((state) => state.userHasAvatar);
|
|
@@ -43330,7 +43829,6 @@ function FittingRoomOverlay() {
|
|
|
43330
43829
|
const [forceUntuck, setForceUntuck] = reactExports.useState(false);
|
|
43331
43830
|
const [lastAddedExternalId, setLastAddedExternalId] = reactExports.useState(null);
|
|
43332
43831
|
const [mobileMode, setMobileMode] = reactExports.useState("browse");
|
|
43333
|
-
const [zoomed, setZoomed] = reactExports.useState(false);
|
|
43334
43832
|
const {
|
|
43335
43833
|
snap: sheetSnap,
|
|
43336
43834
|
setSnap: setSheetSnap,
|
|
@@ -43345,13 +43843,17 @@ function FittingRoomOverlay() {
|
|
|
43345
43843
|
} = useVtoRequests();
|
|
43346
43844
|
reactExports.useEffect(() => {
|
|
43347
43845
|
const savedScrollY = window.scrollY;
|
|
43348
|
-
if (savedScrollY > 0)
|
|
43846
|
+
if (savedScrollY > 0) {
|
|
43847
|
+
window.scrollTo(0, 0);
|
|
43848
|
+
}
|
|
43349
43849
|
setTopOffset(measureTopOffset());
|
|
43350
43850
|
const onResize = () => setTopOffset(measureTopOffset());
|
|
43351
43851
|
window.addEventListener("resize", onResize);
|
|
43352
43852
|
return () => {
|
|
43353
43853
|
window.removeEventListener("resize", onResize);
|
|
43354
|
-
if (savedScrollY > 0)
|
|
43854
|
+
if (savedScrollY > 0) {
|
|
43855
|
+
window.scrollTo(0, savedScrollY);
|
|
43856
|
+
}
|
|
43355
43857
|
};
|
|
43356
43858
|
}, []);
|
|
43357
43859
|
const selectedItems = reactExports.useMemo(() => {
|
|
@@ -43364,14 +43866,22 @@ function FittingRoomOverlay() {
|
|
|
43364
43866
|
indexed.sort((a, b) => {
|
|
43365
43867
|
const aOrder = a.item.styleCategoryGroup?.display_order ?? Number.MAX_SAFE_INTEGER;
|
|
43366
43868
|
const bOrder = b.item.styleCategoryGroup?.display_order ?? Number.MAX_SAFE_INTEGER;
|
|
43367
|
-
if (aOrder !== bOrder)
|
|
43869
|
+
if (aOrder !== bOrder) {
|
|
43870
|
+
return aOrder - bOrder;
|
|
43871
|
+
}
|
|
43368
43872
|
return a.idx - b.idx;
|
|
43369
43873
|
});
|
|
43370
43874
|
return indexed.map(({
|
|
43371
43875
|
item
|
|
43372
43876
|
}) => item);
|
|
43373
43877
|
}, [resolved.items, selectedExternalIds]);
|
|
43374
|
-
const canTuck = reactExports.useMemo(() => selectedItems.some((top) =>
|
|
43878
|
+
const canTuck = reactExports.useMemo(() => selectedItems.some((top) => {
|
|
43879
|
+
const topCategory = top.styleCategory;
|
|
43880
|
+
if (!topCategory?.tuckable) {
|
|
43881
|
+
return false;
|
|
43882
|
+
}
|
|
43883
|
+
return selectedItems.some((other) => !!other.styleCategory && !other.styleCategory.tuckable && other.styleCategory.layer_order > topCategory.layer_order);
|
|
43884
|
+
}), [selectedItems]);
|
|
43375
43885
|
const availabilityByExternalId = reactExports.useMemo(() => {
|
|
43376
43886
|
const out = {};
|
|
43377
43887
|
for (const item of resolved.items) {
|
|
@@ -43380,11 +43890,17 @@ function FittingRoomOverlay() {
|
|
|
43380
43890
|
return out;
|
|
43381
43891
|
}, [resolved, selectedExternalIds]);
|
|
43382
43892
|
const ensureSizeForItem = reactExports.useCallback((item) => {
|
|
43383
|
-
if (item.storage.colorwaySizeAssetId != null)
|
|
43893
|
+
if (item.storage.colorwaySizeAssetId != null) {
|
|
43894
|
+
return;
|
|
43895
|
+
}
|
|
43384
43896
|
const productData = buildVtoProductDataFromResolved(item);
|
|
43385
|
-
if (!productData)
|
|
43897
|
+
if (!productData) {
|
|
43898
|
+
return;
|
|
43899
|
+
}
|
|
43386
43900
|
const csa = findRecommendedColorSize(productData, item.storage.color);
|
|
43387
|
-
if (!csa)
|
|
43901
|
+
if (!csa) {
|
|
43902
|
+
return;
|
|
43903
|
+
}
|
|
43388
43904
|
const sizeRec = item.loadedProduct?.sizeFitRecommendation;
|
|
43389
43905
|
const sizeLabel = sizeRec ? getSizeLabelFromSize(sizeRec.recommended_size) : productData.recommendedSizeLabel;
|
|
43390
43906
|
updateFittingRoomItem(item.externalId, {
|
|
@@ -43392,7 +43908,7 @@ function FittingRoomOverlay() {
|
|
|
43392
43908
|
size: sizeLabel,
|
|
43393
43909
|
color: csa.colorLabel
|
|
43394
43910
|
});
|
|
43395
|
-
logger$
|
|
43911
|
+
logger$8.logDebug("Auto-picked recommended size", {
|
|
43396
43912
|
externalId: item.externalId,
|
|
43397
43913
|
sizeLabel,
|
|
43398
43914
|
csaId: csa.colorwaySizeAssetId
|
|
@@ -43400,12 +43916,16 @@ function FittingRoomOverlay() {
|
|
|
43400
43916
|
}, [updateFittingRoomItem]);
|
|
43401
43917
|
const handleSelectItem = reactExports.useCallback((externalId) => {
|
|
43402
43918
|
const item = resolved.items.find((i) => i.externalId === externalId);
|
|
43403
|
-
if (!item)
|
|
43919
|
+
if (!item) {
|
|
43920
|
+
return;
|
|
43921
|
+
}
|
|
43404
43922
|
const isSelected = selectedExternalIds.has(externalId);
|
|
43405
43923
|
const nextSelected = new Set(selectedExternalIds);
|
|
43406
43924
|
if (isSelected) {
|
|
43407
43925
|
nextSelected.delete(externalId);
|
|
43408
|
-
if (openAccordionItemId === externalId)
|
|
43926
|
+
if (openAccordionItemId === externalId) {
|
|
43927
|
+
setOpenAccordionItemId(null);
|
|
43928
|
+
}
|
|
43409
43929
|
} else {
|
|
43410
43930
|
nextSelected.add(externalId);
|
|
43411
43931
|
ensureSizeForItem(item);
|
|
@@ -43419,11 +43939,17 @@ function FittingRoomOverlay() {
|
|
|
43419
43939
|
}, [resolved, selectedExternalIds, openAccordionItemId, isMobileLayout, ensureSizeForItem]);
|
|
43420
43940
|
const handleChangeSize = reactExports.useCallback((externalId, sizeLabel) => {
|
|
43421
43941
|
const item = resolved.items.find((i) => i.externalId === externalId);
|
|
43422
|
-
if (!item)
|
|
43942
|
+
if (!item) {
|
|
43943
|
+
return;
|
|
43944
|
+
}
|
|
43423
43945
|
const productData = buildVtoProductDataFromResolved(item);
|
|
43424
|
-
if (!productData)
|
|
43946
|
+
if (!productData) {
|
|
43947
|
+
return;
|
|
43948
|
+
}
|
|
43425
43949
|
const csa = findCsaByLabel(productData, sizeLabel, item.storage.color);
|
|
43426
|
-
if (!csa)
|
|
43950
|
+
if (!csa) {
|
|
43951
|
+
return;
|
|
43952
|
+
}
|
|
43427
43953
|
updateFittingRoomItem(externalId, {
|
|
43428
43954
|
colorwaySizeAssetId: csa.colorwaySizeAssetId,
|
|
43429
43955
|
size: sizeLabel,
|
|
@@ -43435,14 +43961,14 @@ function FittingRoomOverlay() {
|
|
|
43435
43961
|
addToCart
|
|
43436
43962
|
} = getStaticData();
|
|
43437
43963
|
if (!addToCart) {
|
|
43438
|
-
logger$
|
|
43964
|
+
logger$8.logWarn("No addToCart callback configured; skipping", {
|
|
43439
43965
|
externalId
|
|
43440
43966
|
});
|
|
43441
43967
|
return;
|
|
43442
43968
|
}
|
|
43443
43969
|
const item = resolved.items.find((i) => i.externalId === externalId);
|
|
43444
43970
|
if (!item || !item.storage.size || !item.storage.color) {
|
|
43445
|
-
logger$
|
|
43971
|
+
logger$8.logWarn("Cannot add to cart: missing size or color", {
|
|
43446
43972
|
externalId,
|
|
43447
43973
|
size: item?.storage.size,
|
|
43448
43974
|
color: item?.storage.color
|
|
@@ -43456,7 +43982,7 @@ function FittingRoomOverlay() {
|
|
|
43456
43982
|
});
|
|
43457
43983
|
closeOverlay();
|
|
43458
43984
|
} catch (error) {
|
|
43459
|
-
logger$
|
|
43985
|
+
logger$8.logError("addToCart failed", {
|
|
43460
43986
|
error,
|
|
43461
43987
|
externalId
|
|
43462
43988
|
});
|
|
@@ -43465,17 +43991,18 @@ function FittingRoomOverlay() {
|
|
|
43465
43991
|
const handleToggleUntuck = reactExports.useCallback(() => {
|
|
43466
43992
|
setForceUntuck((prev2) => !prev2);
|
|
43467
43993
|
}, []);
|
|
43468
|
-
const handleToggleZoom = reactExports.useCallback(() => {
|
|
43469
|
-
setZoomed((prev2) => !prev2);
|
|
43470
|
-
}, []);
|
|
43471
43994
|
const handleRemoveItem = reactExports.useCallback((externalId) => {
|
|
43472
43995
|
setSelectedExternalIds((prev2) => {
|
|
43473
|
-
if (!prev2.has(externalId))
|
|
43996
|
+
if (!prev2.has(externalId)) {
|
|
43997
|
+
return prev2;
|
|
43998
|
+
}
|
|
43474
43999
|
const next2 = new Set(prev2);
|
|
43475
44000
|
next2.delete(externalId);
|
|
43476
44001
|
return next2;
|
|
43477
44002
|
});
|
|
43478
|
-
if (openAccordionItemId === externalId)
|
|
44003
|
+
if (openAccordionItemId === externalId) {
|
|
44004
|
+
setOpenAccordionItemId(null);
|
|
44005
|
+
}
|
|
43479
44006
|
}, [openAccordionItemId]);
|
|
43480
44007
|
const handleTryItOn = reactExports.useCallback(() => {
|
|
43481
44008
|
setMobileMode("try-on");
|
|
@@ -43489,10 +44016,25 @@ function FittingRoomOverlay() {
|
|
|
43489
44016
|
setOpenAccordionItemId(null);
|
|
43490
44017
|
}
|
|
43491
44018
|
}, [openAccordionItemId, selectedExternalIds]);
|
|
44019
|
+
const preselectAppliedRef = reactExports.useRef(false);
|
|
44020
|
+
reactExports.useEffect(() => {
|
|
44021
|
+
if (preselectAppliedRef.current || !preselectExternalId) {
|
|
44022
|
+
return;
|
|
44023
|
+
}
|
|
44024
|
+
if (!resolved.items.some((i) => i.externalId === preselectExternalId)) {
|
|
44025
|
+
return;
|
|
44026
|
+
}
|
|
44027
|
+
preselectAppliedRef.current = true;
|
|
44028
|
+
handleSelectItem(preselectExternalId);
|
|
44029
|
+
}, [preselectExternalId, resolved.items, handleSelectItem]);
|
|
43492
44030
|
const outfit = reactExports.useMemo(() => buildOutfit(selectedExternalIds, resolved, forceUntuck, lastAddedExternalId), [selectedExternalIds, resolved, forceUntuck, lastAddedExternalId]);
|
|
43493
44031
|
reactExports.useEffect(() => {
|
|
43494
|
-
if (!userIsLoggedIn || !userHasAvatar)
|
|
43495
|
-
|
|
44032
|
+
if (!userIsLoggedIn || !userHasAvatar) {
|
|
44033
|
+
return;
|
|
44034
|
+
}
|
|
44035
|
+
if (outfit.items.length === 0) {
|
|
44036
|
+
return;
|
|
44037
|
+
}
|
|
43496
44038
|
requestVtoComposition(toWireItems(outfit.items), true);
|
|
43497
44039
|
if (getStaticData().config.features.vtoPrefetch) {
|
|
43498
44040
|
for (const alt of outfit.alternates) {
|
|
@@ -43503,7 +44045,9 @@ function FittingRoomOverlay() {
|
|
|
43503
44045
|
const frameUrls = reactExports.useMemo(() => {
|
|
43504
44046
|
if (outfit.items.length === 0) {
|
|
43505
44047
|
const bareFrames = userProfile?.avatar_frames;
|
|
43506
|
-
if (!bareFrames || bareFrames.length === 0)
|
|
44048
|
+
if (!bareFrames || bareFrames.length === 0) {
|
|
44049
|
+
return null;
|
|
44050
|
+
}
|
|
43507
44051
|
const baseUrl2 = getStaticData().config.frames.baseUrl;
|
|
43508
44052
|
return bareFrames.map((u) => applyFrameBaseUrl(u, baseUrl2));
|
|
43509
44053
|
}
|
|
@@ -43527,7 +44071,7 @@ function FittingRoomOverlay() {
|
|
|
43527
44071
|
closeOverlay();
|
|
43528
44072
|
const authManager2 = getAuthManager();
|
|
43529
44073
|
authManager2.logout().catch((error) => {
|
|
43530
|
-
logger$
|
|
44074
|
+
logger$8.logError("Error during logout", {
|
|
43531
44075
|
error
|
|
43532
44076
|
});
|
|
43533
44077
|
});
|
|
@@ -43574,29 +44118,6 @@ function FittingRoomOverlay() {
|
|
|
43574
44118
|
fontSize: "13px",
|
|
43575
44119
|
textDecoration: "underline",
|
|
43576
44120
|
marginTop: "8px"
|
|
43577
|
-
},
|
|
43578
|
-
snackbar: {
|
|
43579
|
-
position: "absolute",
|
|
43580
|
-
left: "50%",
|
|
43581
|
-
bottom: "24px",
|
|
43582
|
-
transform: "translateX(-50%)",
|
|
43583
|
-
padding: "12px 20px",
|
|
43584
|
-
borderRadius: "24px",
|
|
43585
|
-
backgroundColor: theme.color_fg_text,
|
|
43586
|
-
color: "#FFFFFF",
|
|
43587
|
-
fontSize: "13px",
|
|
43588
|
-
display: "flex",
|
|
43589
|
-
alignItems: "center",
|
|
43590
|
-
gap: "12px",
|
|
43591
|
-
zIndex: 10,
|
|
43592
|
-
maxWidth: "calc(100% - 32px)"
|
|
43593
|
-
},
|
|
43594
|
-
snackbarDismiss: {
|
|
43595
|
-
background: "none",
|
|
43596
|
-
border: "none",
|
|
43597
|
-
color: "#FFFFFF",
|
|
43598
|
-
fontSize: "16px",
|
|
43599
|
-
cursor: "pointer"
|
|
43600
44121
|
}
|
|
43601
44122
|
}));
|
|
43602
44123
|
const isMobileTryOn = isMobileLayout && mobileMode === "try-on";
|
|
@@ -43627,15 +44148,12 @@ function FittingRoomOverlay() {
|
|
|
43627
44148
|
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.emptyTagline, t: "landing.description" }),
|
|
43628
44149
|
/* @__PURE__ */ jsx$1("div", { css: css2.emptyShopNow, children: /* @__PURE__ */ jsx$1(ButtonT, { variant: "primary", t: "fitting_room.shop_now", onClick: handleShopNow }) }),
|
|
43629
44150
|
userIsLoggedIn ? /* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.emptySignOut, t: "fitting_room.sign_out", onClick: handleSignOut }) : null
|
|
43630
|
-
] }) }) : isMobileLayout ? /* @__PURE__ */ jsx$1(MobileLayout$1, { mode: mobileMode, resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, sheetSnap, sheetTouchStart, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onTryItOn: handleTryItOn, onBackToBrowse: handleBackToBrowse, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck }) : /* @__PURE__ */ jsx$1(DesktopLayout$1, { resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck,
|
|
43631
|
-
vtoError ? /* @__PURE__ */
|
|
43632
|
-
/* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "fitting_room.vto_error" }),
|
|
43633
|
-
/* @__PURE__ */ jsx$1("button", { css: css2.snackbarDismiss, onClick: clearVtoError, "aria-label": "Dismiss", children: "×" })
|
|
43634
|
-
] }) : null
|
|
44151
|
+
] }) }) : isMobileLayout ? /* @__PURE__ */ jsx$1(MobileLayout$1, { mode: mobileMode, resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, sheetSnap, sheetTouchStart, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onTryItOn: handleTryItOn, onBackToBrowse: handleBackToBrowse, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck }) : /* @__PURE__ */ jsx$1(DesktopLayout$1, { resolved, selectedItems, availabilityByExternalId, openAccordionItemId, detailMode, forceUntuck, canTuck, frameUrls, onSelectItem: handleSelectItem, onRemoveItem: handleRemoveItem, onOpenAccordionItem: setOpenAccordionItemId, onChangeDetailMode: setDetailMode, onChangeSize: handleChangeSize, onAddToCart: handleAddToCart, onToggleUntuck: handleToggleUntuck, onSignOut: handleSignOut }),
|
|
44152
|
+
vtoError ? /* @__PURE__ */ jsx$1(Snackbar, { messageKey: "fitting_room.vto_error", onDismiss: clearVtoError }) : null
|
|
43635
44153
|
] }) });
|
|
43636
44154
|
}
|
|
43637
44155
|
const CONTACT_US_LINK = "mailto:info@thefittingroom.tech?subject=Forgot%20Password%20Assistance";
|
|
43638
|
-
const logger$
|
|
44156
|
+
const logger$7 = getLogger("forgot-password");
|
|
43639
44157
|
function ForgotPasswordOverlay({
|
|
43640
44158
|
returnToOverlay
|
|
43641
44159
|
}) {
|
|
@@ -43701,7 +44219,7 @@ function ForgotPasswordOverlay({
|
|
|
43701
44219
|
await authManager2.sendPasswordResetEmail(email2);
|
|
43702
44220
|
setLinkSent(true);
|
|
43703
44221
|
} catch (error) {
|
|
43704
|
-
logger$
|
|
44222
|
+
logger$7.logError("Error sending password reset email:", {
|
|
43705
44223
|
error
|
|
43706
44224
|
});
|
|
43707
44225
|
}
|
|
@@ -43719,7 +44237,7 @@ function ForgotPasswordOverlay({
|
|
|
43719
44237
|
return;
|
|
43720
44238
|
}
|
|
43721
44239
|
const email = emailEl.value;
|
|
43722
|
-
resetUserPassword(email);
|
|
44240
|
+
void resetUserPassword(email);
|
|
43723
44241
|
}, [t]);
|
|
43724
44242
|
const handleBackToSignInClick = reactExports.useCallback(() => {
|
|
43725
44243
|
openOverlay(OverlayName.SIGN_IN, {
|
|
@@ -43920,7 +44438,7 @@ function TfrTitle() {
|
|
|
43920
44438
|
}));
|
|
43921
44439
|
return /* @__PURE__ */ jsx$1("div", { css: css2.container, children: /* @__PURE__ */ jsx$1(SvgTfrName, { css: css2.nameIcon }) });
|
|
43922
44440
|
}
|
|
43923
|
-
const logger$
|
|
44441
|
+
const logger$6 = getLogger("sign-in");
|
|
43924
44442
|
function SignInOverlay({
|
|
43925
44443
|
returnToOverlay
|
|
43926
44444
|
}) {
|
|
@@ -43994,7 +44512,7 @@ function SignInOverlay({
|
|
|
43994
44512
|
closeOverlay();
|
|
43995
44513
|
}
|
|
43996
44514
|
} catch (error) {
|
|
43997
|
-
logger$
|
|
44515
|
+
logger$6.logError("Login failed:", {
|
|
43998
44516
|
error
|
|
43999
44517
|
});
|
|
44000
44518
|
setEmailError(" ");
|
|
@@ -44026,7 +44544,7 @@ function SignInOverlay({
|
|
|
44026
44544
|
}
|
|
44027
44545
|
const email = emailEl.value;
|
|
44028
44546
|
const password = passwordEl.value;
|
|
44029
|
-
loginUser(email, password);
|
|
44547
|
+
void loginUser(email, password);
|
|
44030
44548
|
}, [returnToOverlay, closeOverlay, openOverlay, t]);
|
|
44031
44549
|
const handleForgotPasswordClick = reactExports.useCallback(() => {
|
|
44032
44550
|
openOverlay(OverlayName.FORGOT_PASSWORD, {
|
|
@@ -44354,15 +44872,11 @@ function FitChart({
|
|
|
44354
44872
|
] })
|
|
44355
44873
|
] });
|
|
44356
44874
|
}
|
|
44357
|
-
const NON_PRIORITY_VTO_REQUEST_DELAY_MS = 500;
|
|
44358
44875
|
const AVATAR_IMAGE_ASPECT_RATIO = 2 / 3;
|
|
44359
44876
|
const AVATAR_GUTTER_HEIGHT_PX = 100;
|
|
44360
44877
|
const CONTENT_AREA_WIDTH_PX = 550;
|
|
44361
|
-
const logger$
|
|
44362
|
-
function
|
|
44363
|
-
return `${csaId}:${0}`;
|
|
44364
|
-
}
|
|
44365
|
-
function VtoSingleOverlay() {
|
|
44878
|
+
const logger$5 = getLogger("overlays/quick-view");
|
|
44879
|
+
function QuickViewOverlay() {
|
|
44366
44880
|
const userIsLoggedIn = useMainStore((state) => state.userIsLoggedIn);
|
|
44367
44881
|
const userHasAvatar = useMainStore((state) => state.userHasAvatar);
|
|
44368
44882
|
const userProfile = useMainStore((state) => state.userProfile);
|
|
@@ -44374,19 +44888,22 @@ function VtoSingleOverlay() {
|
|
|
44374
44888
|
const [selectedSizeLabel, setSelectedSizeLabel] = reactExports.useState(null);
|
|
44375
44889
|
const [selectedColorLabel, setSelectedColorLabel] = reactExports.useState(null);
|
|
44376
44890
|
const [modalStyle, setModalStyle] = reactExports.useState({});
|
|
44377
|
-
const
|
|
44378
|
-
|
|
44379
|
-
|
|
44891
|
+
const {
|
|
44892
|
+
request: vtoRequest,
|
|
44893
|
+
framesForOutfit,
|
|
44894
|
+
lastError: vtoError,
|
|
44895
|
+
clearError: clearVtoError
|
|
44896
|
+
} = useVtoRequests();
|
|
44380
44897
|
reactExports.useEffect(() => {
|
|
44381
44898
|
if (!userIsLoggedIn) {
|
|
44382
44899
|
openOverlay(OverlayName.LANDING, {
|
|
44383
|
-
returnToOverlay: OverlayName.
|
|
44900
|
+
returnToOverlay: OverlayName.QUICK_VIEW
|
|
44384
44901
|
});
|
|
44385
44902
|
return;
|
|
44386
44903
|
}
|
|
44387
44904
|
if (userIsLoggedIn && userHasAvatar === false) {
|
|
44388
44905
|
openOverlay(OverlayName.GET_APP, {
|
|
44389
|
-
returnToOverlay: OverlayName.
|
|
44906
|
+
returnToOverlay: OverlayName.QUICK_VIEW,
|
|
44390
44907
|
noAvatar: true
|
|
44391
44908
|
});
|
|
44392
44909
|
return;
|
|
@@ -44454,7 +44971,7 @@ function VtoSingleOverlay() {
|
|
|
44454
44971
|
const sku = csaRec.sku;
|
|
44455
44972
|
const variant = variants.find((v) => v.sku === sku);
|
|
44456
44973
|
if (!variant) {
|
|
44457
|
-
logger$
|
|
44974
|
+
logger$5.logWarn(`Variant not found for externalId: ${currentProduct.externalId} sizeId: ${sizeId} sku: ${sku}`);
|
|
44458
44975
|
continue;
|
|
44459
44976
|
}
|
|
44460
44977
|
const colorLabel = variant.color || null;
|
|
@@ -44467,7 +44984,7 @@ function VtoSingleOverlay() {
|
|
|
44467
44984
|
});
|
|
44468
44985
|
}
|
|
44469
44986
|
if (!colors.length) {
|
|
44470
|
-
logger$
|
|
44987
|
+
logger$5.logWarn(`No valid colorways found for externalId: ${currentProduct.externalId} sizeId: ${sizeId}`);
|
|
44471
44988
|
continue;
|
|
44472
44989
|
}
|
|
44473
44990
|
sizes.push({
|
|
@@ -44510,7 +45027,7 @@ function VtoSingleOverlay() {
|
|
|
44510
45027
|
setSelectedColorLabel(recommendedColorLabel);
|
|
44511
45028
|
}
|
|
44512
45029
|
} catch (error) {
|
|
44513
|
-
logger$
|
|
45030
|
+
logger$5.logError("Error fetching initial data:", {
|
|
44514
45031
|
error
|
|
44515
45032
|
});
|
|
44516
45033
|
setVtoProductData(false);
|
|
@@ -44521,7 +45038,7 @@ function VtoSingleOverlay() {
|
|
|
44521
45038
|
if (vtoProductData !== null) {
|
|
44522
45039
|
return;
|
|
44523
45040
|
}
|
|
44524
|
-
setupInitialVtoData();
|
|
45041
|
+
void setupInitialVtoData();
|
|
44525
45042
|
}, [storeProductData, vtoProductData, userProfile]);
|
|
44526
45043
|
const {
|
|
44527
45044
|
sizeColorRecord: selectedColorSizeRecord,
|
|
@@ -44547,63 +45064,17 @@ function VtoSingleOverlay() {
|
|
|
44547
45064
|
availableColorLabels: availableColorLabels2
|
|
44548
45065
|
};
|
|
44549
45066
|
}, [vtoProductData, selectedSizeLabel, selectedColorLabel]);
|
|
44550
|
-
const
|
|
44551
|
-
|
|
44552
|
-
|
|
44553
|
-
|
|
44554
|
-
|
|
44555
|
-
|
|
44556
|
-
function executeRequest() {
|
|
44557
|
-
logger$6.timerStart(`requestVto_${sizeColorRecord.sku}`);
|
|
44558
|
-
logger$6.logDebug(`{{ts}} - Requesting VTO for sku: ${sizeColorRecord.sku}`, {
|
|
44559
|
-
priority,
|
|
44560
|
-
sizeColorRecord
|
|
44561
|
-
});
|
|
44562
|
-
requestedKeysRef.current.add(key);
|
|
44563
|
-
requestVto([{
|
|
44564
|
-
colorway_size_asset_id: csaId,
|
|
44565
|
-
untucked: false
|
|
44566
|
-
}]).then((resp) => {
|
|
44567
|
-
logger$6.timerEnd(`requestVto_${sizeColorRecord.sku}`);
|
|
44568
|
-
logger$6.logTimer(`requestVto_${sizeColorRecord.sku}`, `{{ts}} - VTO data is loaded for sku: ${sizeColorRecord.sku}`);
|
|
44569
|
-
setFramesByKey((prev2) => ({
|
|
44570
|
-
...prev2,
|
|
44571
|
-
[key]: resp.frames
|
|
44572
|
-
}));
|
|
44573
|
-
}).catch((error) => {
|
|
44574
|
-
logger$6.logError(`Error requesting VTO for sku: ${sizeColorRecord.sku}`, {
|
|
44575
|
-
error,
|
|
44576
|
-
sizeColorRecord
|
|
44577
|
-
});
|
|
44578
|
-
requestedKeysRef.current.delete(key);
|
|
44579
|
-
});
|
|
44580
|
-
}
|
|
44581
|
-
{
|
|
44582
|
-
let delay = 0;
|
|
44583
|
-
if (priority) {
|
|
44584
|
-
lastPriorityVtoRequestTimeRef.current = Date.now();
|
|
44585
|
-
} else {
|
|
44586
|
-
const lastPriorityTime = lastPriorityVtoRequestTimeRef.current;
|
|
44587
|
-
if (lastPriorityTime) {
|
|
44588
|
-
const now = Date.now();
|
|
44589
|
-
const minNextRequestTime = lastPriorityTime + NON_PRIORITY_VTO_REQUEST_DELAY_MS;
|
|
44590
|
-
if (now < minNextRequestTime) {
|
|
44591
|
-
delay = minNextRequestTime - now;
|
|
44592
|
-
}
|
|
44593
|
-
}
|
|
44594
|
-
}
|
|
44595
|
-
if (delay) {
|
|
44596
|
-
setTimeout(executeRequest, delay);
|
|
44597
|
-
return;
|
|
44598
|
-
}
|
|
44599
|
-
}
|
|
44600
|
-
executeRequest();
|
|
44601
|
-
}, []);
|
|
45067
|
+
const requestVto2 = reactExports.useCallback((sizeColorRecord, priority) => {
|
|
45068
|
+
vtoRequest([{
|
|
45069
|
+
colorway_size_asset_id: sizeColorRecord.colorwaySizeAssetId,
|
|
45070
|
+
untucked: false
|
|
45071
|
+
}], priority);
|
|
45072
|
+
}, [vtoRequest]);
|
|
44602
45073
|
reactExports.useEffect(() => {
|
|
44603
45074
|
if (selectedColorSizeRecord) {
|
|
44604
|
-
|
|
45075
|
+
requestVto2(selectedColorSizeRecord, true);
|
|
44605
45076
|
}
|
|
44606
|
-
}, [
|
|
45077
|
+
}, [requestVto2, selectedColorSizeRecord]);
|
|
44607
45078
|
reactExports.useEffect(() => {
|
|
44608
45079
|
if (!getStaticData().config.features.vtoPrefetch) {
|
|
44609
45080
|
return;
|
|
@@ -44614,33 +45085,33 @@ function VtoSingleOverlay() {
|
|
|
44614
45085
|
for (const sizeRecord of vtoProductData.sizes) {
|
|
44615
45086
|
const sizeColorRecord = sizeRecord.colors.find((c) => c.colorLabel === selectedColorLabel) ?? sizeRecord.colors[0];
|
|
44616
45087
|
if (sizeColorRecord) {
|
|
44617
|
-
|
|
45088
|
+
requestVto2(sizeColorRecord, false);
|
|
44618
45089
|
}
|
|
44619
45090
|
}
|
|
44620
|
-
}, [
|
|
45091
|
+
}, [requestVto2, vtoProductData, selectedColorLabel]);
|
|
44621
45092
|
const frameUrls = reactExports.useMemo(() => {
|
|
44622
45093
|
if (!selectedColorSizeRecord) {
|
|
44623
45094
|
return null;
|
|
44624
45095
|
}
|
|
44625
|
-
const
|
|
44626
|
-
|
|
44627
|
-
|
|
45096
|
+
const rewritten = framesForOutfit([{
|
|
45097
|
+
colorway_size_asset_id: selectedColorSizeRecord.colorwaySizeAssetId,
|
|
45098
|
+
untucked: false
|
|
45099
|
+
}]);
|
|
45100
|
+
if (!rewritten) {
|
|
44628
45101
|
return null;
|
|
44629
45102
|
}
|
|
44630
|
-
logger$
|
|
44631
|
-
const baseUrl2 = getStaticData().config.frames.baseUrl;
|
|
44632
|
-
const rewritten = frames.map((u) => applyFrameBaseUrl(u, baseUrl2));
|
|
45103
|
+
logger$5.logDebug(`{{ts}} - Displaying VTO for sku: ${selectedColorSizeRecord.sku}`);
|
|
44633
45104
|
rewritten.forEach((url) => {
|
|
44634
45105
|
const img = new Image();
|
|
44635
45106
|
img.src = url;
|
|
44636
45107
|
});
|
|
44637
45108
|
return rewritten;
|
|
44638
|
-
}, [selectedColorSizeRecord,
|
|
45109
|
+
}, [selectedColorSizeRecord, framesForOutfit]);
|
|
44639
45110
|
const handleSignOutClick = reactExports.useCallback(() => {
|
|
44640
45111
|
closeOverlay();
|
|
44641
45112
|
const authManager2 = getAuthManager();
|
|
44642
45113
|
authManager2.logout().catch((error) => {
|
|
44643
|
-
logger$
|
|
45114
|
+
logger$5.logError("Error during logout:", {
|
|
44644
45115
|
error
|
|
44645
45116
|
});
|
|
44646
45117
|
});
|
|
@@ -44662,7 +45133,7 @@ function VtoSingleOverlay() {
|
|
|
44662
45133
|
color: selectedColorLabel
|
|
44663
45134
|
});
|
|
44664
45135
|
} catch (error) {
|
|
44665
|
-
logger$
|
|
45136
|
+
logger$5.logError("Error adding to cart:", {
|
|
44666
45137
|
error
|
|
44667
45138
|
});
|
|
44668
45139
|
}
|
|
@@ -44679,7 +45150,10 @@ function VtoSingleOverlay() {
|
|
|
44679
45150
|
} else {
|
|
44680
45151
|
Layout = DesktopLayout;
|
|
44681
45152
|
}
|
|
44682
|
-
return /* @__PURE__ */
|
|
45153
|
+
return /* @__PURE__ */ jsxs(SidecarModalFrame, { onRequestClose: closeOverlay, contentStyle: modalStyle, children: [
|
|
45154
|
+
/* @__PURE__ */ jsx$1(Layout, { loadedProductData: vtoProductData, selectedColorSizeRecord, availableColorLabels, selectedColorLabel, selectedSizeLabel, frameUrls, setModalStyle, onClose: closeOverlay, onChangeColor: setSelectedColorLabel, onChangeSize: setSelectedSizeLabel, onAddToCart: handleAddToCartClick, onSignOut: handleSignOutClick }),
|
|
45155
|
+
vtoError ? /* @__PURE__ */ jsx$1(Snackbar, { messageKey: "quick-view.vto_error", onDismiss: clearVtoError }) : null
|
|
45156
|
+
] });
|
|
44683
45157
|
}
|
|
44684
45158
|
function NoFitLayout({
|
|
44685
45159
|
onClose,
|
|
@@ -44711,14 +45185,59 @@ function NoFitLayout({
|
|
|
44711
45185
|
}
|
|
44712
45186
|
}));
|
|
44713
45187
|
return /* @__PURE__ */ jsxs("div", { css: css2.mainContainer, children: [
|
|
44714
|
-
/* @__PURE__ */ jsx$1("div", { css: css2.titlebarContainer, children: /* @__PURE__ */ jsx$1(ModalTitlebar, { title: t("
|
|
45188
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.titlebarContainer, children: /* @__PURE__ */ jsx$1(ModalTitlebar, { title: t("quick-view.title"), onCloseClick: onClose }) }),
|
|
44715
45189
|
/* @__PURE__ */ jsxs("div", { css: css2.contentContainer, children: [
|
|
44716
45190
|
/* @__PURE__ */ jsx$1("div", { children: " " }),
|
|
44717
|
-
/* @__PURE__ */ jsx$1("div", { css: css2.messageContainer, children: /* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "
|
|
45191
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.messageContainer, children: /* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "quick-view.no_recommendation" }) }),
|
|
44718
45192
|
/* @__PURE__ */ jsx$1("div", { css: css2.footerContainer, children: /* @__PURE__ */ jsx$1(Footer, { onSignOutClick: onSignOut }) })
|
|
44719
45193
|
] })
|
|
44720
45194
|
] });
|
|
44721
45195
|
}
|
|
45196
|
+
function FittingRoomToggleButton() {
|
|
45197
|
+
const {
|
|
45198
|
+
currentProduct
|
|
45199
|
+
} = getStaticData();
|
|
45200
|
+
const productId = currentProduct?.externalId ?? null;
|
|
45201
|
+
const isInFittingRoom = useMainStore((state) => productId == null ? false : state.fittingRoom.some((item) => item.externalId === productId));
|
|
45202
|
+
const css2 = useCss((theme) => ({
|
|
45203
|
+
button: {
|
|
45204
|
+
marginTop: "10px",
|
|
45205
|
+
width: "100%",
|
|
45206
|
+
display: "flex",
|
|
45207
|
+
alignItems: "center",
|
|
45208
|
+
justifyContent: "center",
|
|
45209
|
+
gap: "10px",
|
|
45210
|
+
padding: "13px",
|
|
45211
|
+
backgroundColor: "#FFFFFF",
|
|
45212
|
+
border: `1px solid ${theme.color_fg_text}`,
|
|
45213
|
+
borderRadius: "30px",
|
|
45214
|
+
cursor: "pointer"
|
|
45215
|
+
},
|
|
45216
|
+
icon: {
|
|
45217
|
+
color: theme.color_fg_text,
|
|
45218
|
+
width: "20px",
|
|
45219
|
+
height: "20px"
|
|
45220
|
+
},
|
|
45221
|
+
text: {
|
|
45222
|
+
fontSize: "14px",
|
|
45223
|
+
textTransform: "uppercase"
|
|
45224
|
+
}
|
|
45225
|
+
}));
|
|
45226
|
+
if (productId == null) {
|
|
45227
|
+
return null;
|
|
45228
|
+
}
|
|
45229
|
+
const handleClick = () => {
|
|
45230
|
+
toggleFittingRoomItem(productId, currentProduct?.handle ?? null, true).catch((error) => {
|
|
45231
|
+
logger$5.logError("toggleFittingRoomItem failed", {
|
|
45232
|
+
error
|
|
45233
|
+
});
|
|
45234
|
+
});
|
|
45235
|
+
};
|
|
45236
|
+
return /* @__PURE__ */ jsxs("button", { type: "button", onClick: handleClick, css: css2.button, children: [
|
|
45237
|
+
/* @__PURE__ */ jsx$1(SvgFittingRoomIcon, { css: css2.icon }),
|
|
45238
|
+
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.text, t: isInFittingRoom ? "added_to_fitting_room" : "add_to_fitting_room" })
|
|
45239
|
+
] });
|
|
45240
|
+
}
|
|
44722
45241
|
function MobileLayout({
|
|
44723
45242
|
loadedProductData,
|
|
44724
45243
|
selectedColorSizeRecord,
|
|
@@ -44824,7 +45343,11 @@ function MobileLayout({
|
|
|
44824
45343
|
if (!bottomFrameInnerEl) {
|
|
44825
45344
|
return;
|
|
44826
45345
|
}
|
|
44827
|
-
const
|
|
45346
|
+
const parentEl = bottomFrameInnerEl.parentElement;
|
|
45347
|
+
if (!parentEl) {
|
|
45348
|
+
return;
|
|
45349
|
+
}
|
|
45350
|
+
const maxHeightPx = Number(window.getComputedStyle(parentEl).getPropertyValue("max-height").replace("px", ""));
|
|
44828
45351
|
const heightPx = Math.min(bottomFrameInnerEl.clientHeight, maxHeightPx);
|
|
44829
45352
|
const bottomFrameStyle = {
|
|
44830
45353
|
height: `${heightPx}px`
|
|
@@ -44929,8 +45452,11 @@ function MobileContentExpanded({
|
|
|
44929
45452
|
/* @__PURE__ */ jsx$1("div", { css: css2.sizeSelectorContainer, children: /* @__PURE__ */ jsx$1(SizeSelector, { loadedProductData, selectedSizeLabel, onChangeSize }) }),
|
|
44930
45453
|
/* @__PURE__ */ jsx$1("div", { css: css2.itemFitTextContainer, children: /* @__PURE__ */ jsx$1(ItemFitText, { loadedProductData }) }),
|
|
44931
45454
|
/* @__PURE__ */ jsx$1("div", { css: css2.itemFitDetailsContainer, children: /* @__PURE__ */ jsx$1(ItemFitDetails, { loadedProductData, selectedSizeLabel }) }),
|
|
44932
|
-
/* @__PURE__ */
|
|
44933
|
-
|
|
45455
|
+
/* @__PURE__ */ jsxs("div", { css: css2.buttonContainer, children: [
|
|
45456
|
+
/* @__PURE__ */ jsx$1(AddToCartButton, { onClick: onAddToCart }),
|
|
45457
|
+
/* @__PURE__ */ jsx$1(FittingRoomToggleButton, {})
|
|
45458
|
+
] }),
|
|
45459
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.productDetailsContainer, children: /* @__PURE__ */ jsx$1(LinkT, { variant: "base", css: css2.productDetailsText, t: "quick-view.view_product_details", onClick: handleProductDetailsClick }) })
|
|
44934
45460
|
] });
|
|
44935
45461
|
}
|
|
44936
45462
|
function MobileContentFull({
|
|
@@ -45025,8 +45551,11 @@ function MobileContentFull({
|
|
|
45025
45551
|
] }),
|
|
45026
45552
|
fitChartNode,
|
|
45027
45553
|
/* @__PURE__ */ jsx$1("div", { css: css2.colorSelectorContainer, children: /* @__PURE__ */ jsx$1(ColorSelector, { availableColorLabels, selectedColorLabel, onChangeColor }) }),
|
|
45028
|
-
/* @__PURE__ */
|
|
45029
|
-
|
|
45554
|
+
/* @__PURE__ */ jsxs("div", { css: css2.buttonContainer, children: [
|
|
45555
|
+
/* @__PURE__ */ jsx$1(AddToCartButton, { onClick: onAddToCart }),
|
|
45556
|
+
/* @__PURE__ */ jsx$1(FittingRoomToggleButton, {})
|
|
45557
|
+
] }),
|
|
45558
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.productDetailsContainer, children: /* @__PURE__ */ jsx$1(LinkT, { variant: "base", css: css2.productDetailsText, t: "quick-view.hide_product_details", onClick: handleProductDetailsClick }) }),
|
|
45030
45559
|
/* @__PURE__ */ jsx$1("div", { css: css2.priceContainer, children: /* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.priceText, children: selectedColorSizeRecord.priceFormatted }) }),
|
|
45031
45560
|
/* @__PURE__ */ jsx$1("div", { css: css2.productDescriptionContainer, children: /* @__PURE__ */ jsx$1(ProductDescriptionText, { loadedProductData }) }),
|
|
45032
45561
|
/* @__PURE__ */ jsx$1("div", { css: css2.footerContainer, children: /* @__PURE__ */ jsx$1(Footer, { onSignOutClick: onSignOut }) })
|
|
@@ -45142,7 +45671,7 @@ function DesktopLayout({
|
|
|
45142
45671
|
return /* @__PURE__ */ jsxs("div", { css: css2.mainContainer, children: [
|
|
45143
45672
|
/* @__PURE__ */ jsx$1(Avatar, { frameUrls, setModalStyle }),
|
|
45144
45673
|
/* @__PURE__ */ jsxs("div", { css: css2.rightContainer, children: [
|
|
45145
|
-
/* @__PURE__ */ jsx$1(ModalTitlebar, { title: t("
|
|
45674
|
+
/* @__PURE__ */ jsx$1(ModalTitlebar, { title: t("quick-view.title"), onCloseClick: onClose }),
|
|
45146
45675
|
/* @__PURE__ */ jsxs("div", { css: css2.contentContainer, children: [
|
|
45147
45676
|
/* @__PURE__ */ jsx$1("div", { css: css2.productNameContainer, children: /* @__PURE__ */ jsx$1(Text, { variant: "brand", css: css2.productNameText, children: loadedProductData.productName }) }),
|
|
45148
45677
|
/* @__PURE__ */ jsx$1("div", { css: css2.priceContainer, children: /* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.priceText, children: selectedColorSizeRecord.priceFormatted }) }),
|
|
@@ -45158,7 +45687,10 @@ function DesktopLayout({
|
|
|
45158
45687
|
/* @__PURE__ */ jsx$1("div", { css: css2.itemFitDetailsContainer, children: /* @__PURE__ */ jsx$1(ItemFitDetails, { loadedProductData, selectedSizeLabel }) })
|
|
45159
45688
|
] }),
|
|
45160
45689
|
fitChartNode,
|
|
45161
|
-
/* @__PURE__ */
|
|
45690
|
+
/* @__PURE__ */ jsxs("div", { css: css2.buttonContainer, children: [
|
|
45691
|
+
/* @__PURE__ */ jsx$1(AddToCartButton, { onClick: onAddToCart }),
|
|
45692
|
+
/* @__PURE__ */ jsx$1(FittingRoomToggleButton, {})
|
|
45693
|
+
] }),
|
|
45162
45694
|
/* @__PURE__ */ jsx$1("div", { css: css2.descriptionContainer, children: /* @__PURE__ */ jsx$1(ProductDescriptionText, { loadedProductData }) })
|
|
45163
45695
|
] }),
|
|
45164
45696
|
/* @__PURE__ */ jsx$1(Footer, { onSignOutClick: onSignOut })
|
|
@@ -45178,10 +45710,37 @@ function Avatar({
|
|
|
45178
45710
|
bottomContainerStyle: {}
|
|
45179
45711
|
});
|
|
45180
45712
|
const [selectedFrameIndex, setSelectedFrameIndex] = reactExports.useState(null);
|
|
45713
|
+
const [zoomOpen, setZoomOpen] = reactExports.useState(false);
|
|
45181
45714
|
const css2 = useCss((theme) => ({
|
|
45182
45715
|
topContainer: {
|
|
45183
45716
|
flex: "none",
|
|
45184
|
-
height: "100%"
|
|
45717
|
+
height: "100%",
|
|
45718
|
+
// Positioning context for the zoom pill overlaid on the avatar.
|
|
45719
|
+
position: "relative"
|
|
45720
|
+
},
|
|
45721
|
+
zoomPill: {
|
|
45722
|
+
position: "absolute",
|
|
45723
|
+
// Bottom-right of the avatar image, clear of the slider gutter below it.
|
|
45724
|
+
bottom: `${AVATAR_GUTTER_HEIGHT_PX + 16}px`,
|
|
45725
|
+
right: "16px",
|
|
45726
|
+
display: "inline-flex",
|
|
45727
|
+
alignItems: "center",
|
|
45728
|
+
gap: "8px",
|
|
45729
|
+
padding: "8px 16px",
|
|
45730
|
+
borderRadius: "24px",
|
|
45731
|
+
backgroundColor: "rgba(255, 255, 255, 0.95)",
|
|
45732
|
+
border: `1px solid ${theme.color_fg_text}`,
|
|
45733
|
+
fontSize: "12px",
|
|
45734
|
+
fontWeight: "500",
|
|
45735
|
+
letterSpacing: "0.5px",
|
|
45736
|
+
textTransform: "uppercase",
|
|
45737
|
+
cursor: "pointer",
|
|
45738
|
+
zIndex: 2
|
|
45739
|
+
},
|
|
45740
|
+
zoomPillIcon: {
|
|
45741
|
+
width: "14px",
|
|
45742
|
+
height: "14px",
|
|
45743
|
+
flex: "none"
|
|
45185
45744
|
},
|
|
45186
45745
|
bottomContainer: {
|
|
45187
45746
|
position: "absolute",
|
|
@@ -45295,10 +45854,15 @@ function Avatar({
|
|
|
45295
45854
|
}, [isMobileLayout]);
|
|
45296
45855
|
const isReady = !!frameUrls && selectedFrameIndex != null;
|
|
45297
45856
|
return /* @__PURE__ */ jsxs("div", { css: css2.topContainer, style: layoutData.topContainerStyle, children: [
|
|
45298
|
-
/* @__PURE__ */ jsx$1(AvatarFrameViewer, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, imageContainerStyle: layoutData.imageContainerStyle, imageStyle: layoutData.imageStyle, loadingT: "
|
|
45299
|
-
isReady ? /* @__PURE__ */
|
|
45857
|
+
/* @__PURE__ */ jsx$1(AvatarFrameViewer, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, imageContainerStyle: layoutData.imageContainerStyle, imageStyle: layoutData.imageStyle, loadingT: "quick-view.avatar_loading" }),
|
|
45858
|
+
isReady && !isMobileLayout ? /* @__PURE__ */ jsxs(Button, { variant: "base", css: css2.zoomPill, onClick: () => setZoomOpen(true), children: [
|
|
45859
|
+
/* @__PURE__ */ jsx$1(SvgIconZoom, { css: css2.zoomPillIcon }),
|
|
45860
|
+
/* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "quick-view.zoom_in" })
|
|
45861
|
+
] }) : null,
|
|
45862
|
+
zoomOpen && frameUrls && frameUrls.length > 0 ? /* @__PURE__ */ jsx$1(ZoomModal, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, onClose: () => setZoomOpen(false) }) : null,
|
|
45863
|
+
frameUrls && selectedFrameIndex != null ? /* @__PURE__ */ jsx$1("div", { css: css2.bottomContainer, style: layoutData.bottomContainerStyle, children: isMobileLayout ? /* @__PURE__ */ jsx$1(Fragment, { children: " " }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
45300
45864
|
/* @__PURE__ */ jsx$1("input", { type: "range", min: 0, max: frameUrls.length - 1, step: 1, value: selectedFrameIndex, onChange: (e) => setSelectedFrameIndex(Number(e.target.value)), css: css2.sliderInput }),
|
|
45301
|
-
/* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "
|
|
45865
|
+
/* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "quick-view.slide_to_rotate", css: css2.sliderText })
|
|
45302
45866
|
] }) }) : null
|
|
45303
45867
|
] });
|
|
45304
45868
|
}
|
|
@@ -45353,7 +45917,7 @@ function ColorSelector({
|
|
|
45353
45917
|
return null;
|
|
45354
45918
|
}
|
|
45355
45919
|
return /* @__PURE__ */ jsx$1("div", { css: css2.colorContainer, children: /* @__PURE__ */ jsxs("label", { children: [
|
|
45356
|
-
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.colorLabelText, t: "
|
|
45920
|
+
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.colorLabelText, t: "quick-view.color_label" }),
|
|
45357
45921
|
/* @__PURE__ */ jsx$1("select", { value: selectedColorLabel ?? "", onChange: handleColorSelectChange, css: css2.colorSelect, children: availableColorLabels.map((colorLabel) => /* @__PURE__ */ jsx$1("option", { value: colorLabel, children: colorLabel }, colorLabel)) })
|
|
45358
45922
|
] }) });
|
|
45359
45923
|
}
|
|
@@ -45400,11 +45964,11 @@ function Footer({
|
|
|
45400
45964
|
}
|
|
45401
45965
|
}));
|
|
45402
45966
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
45403
|
-
/* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.signOutLink, onClick: onSignOutClick, t: "
|
|
45967
|
+
/* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.signOutLink, onClick: onSignOutClick, t: "quick-view.sign_out" }),
|
|
45404
45968
|
/* @__PURE__ */ jsx$1(SvgTfrName, { css: css2.tfrIcon })
|
|
45405
45969
|
] });
|
|
45406
45970
|
}
|
|
45407
|
-
const logger$
|
|
45971
|
+
const logger$4 = getLogger("widgets/add-to-fitting-room-compact");
|
|
45408
45972
|
function AddToFittingRoomCompactWidget({
|
|
45409
45973
|
attributes
|
|
45410
45974
|
}) {
|
|
@@ -45450,7 +46014,7 @@ function AddToFittingRoomCompactWidget({
|
|
|
45450
46014
|
}
|
|
45451
46015
|
const handleClick = () => {
|
|
45452
46016
|
toggleFittingRoomItem(productId, productHandle, isPdp).catch((error) => {
|
|
45453
|
-
logger$
|
|
46017
|
+
logger$4.logError("toggleFittingRoomItem failed", {
|
|
45454
46018
|
error
|
|
45455
46019
|
});
|
|
45456
46020
|
});
|
|
@@ -45458,64 +46022,8 @@ function AddToFittingRoomCompactWidget({
|
|
|
45458
46022
|
const ariaLabel = t(isInFittingRoom ? "added_to_fitting_room" : "add_to_fitting_room");
|
|
45459
46023
|
return /* @__PURE__ */ jsx$1("button", { type: "button", onClick: handleClick, css: [css2.button, isInFittingRoom && css2.buttonAdded, "", ""], "aria-label": ariaLabel, "aria-pressed": isInFittingRoom, children: /* @__PURE__ */ jsx$1(SvgFittingRoomIcon, { css: [css2.icon, isInFittingRoom && css2.iconAdded, "", ""] }) });
|
|
45460
46024
|
}
|
|
45461
|
-
const logger$4 = getLogger("widgets/add-to-fitting-room");
|
|
45462
|
-
function AddToFittingRoomWidget({
|
|
45463
|
-
attributes
|
|
45464
|
-
}) {
|
|
45465
|
-
const {
|
|
45466
|
-
currentProduct
|
|
45467
|
-
} = getStaticData();
|
|
45468
|
-
const attrProductId = attributes["product-id"];
|
|
45469
|
-
const attrProductHandle = attributes["product-handle"];
|
|
45470
|
-
const productId = attrProductId || currentProduct?.externalId || null;
|
|
45471
|
-
const isPdp = productId != null && productId === currentProduct?.externalId;
|
|
45472
|
-
const productHandle = attrProductHandle || (isPdp ? currentProduct?.handle ?? null : null);
|
|
45473
|
-
const isInFittingRoom = useMainStore((state) => productId == null ? false : state.fittingRoom.some((item) => item.externalId === productId));
|
|
45474
|
-
const css2 = useCss((theme) => ({
|
|
45475
|
-
button: {
|
|
45476
|
-
marginTop: "10px",
|
|
45477
|
-
marginBottom: "10px",
|
|
45478
|
-
width: "100%",
|
|
45479
|
-
maxWidth: "440px",
|
|
45480
|
-
display: "flex",
|
|
45481
|
-
alignItems: "center",
|
|
45482
|
-
justifyContent: "center",
|
|
45483
|
-
gap: "10px",
|
|
45484
|
-
padding: "13px",
|
|
45485
|
-
backgroundColor: "white",
|
|
45486
|
-
borderWidth: "1px",
|
|
45487
|
-
borderColor: theme.color_fg_text,
|
|
45488
|
-
borderStyle: "solid",
|
|
45489
|
-
borderRadius: "30px",
|
|
45490
|
-
cursor: "pointer"
|
|
45491
|
-
},
|
|
45492
|
-
icon: {
|
|
45493
|
-
color: theme.color_fg_text,
|
|
45494
|
-
width: "20px",
|
|
45495
|
-
height: "20px"
|
|
45496
|
-
},
|
|
45497
|
-
text: {
|
|
45498
|
-
fontSize: "14px",
|
|
45499
|
-
textTransform: "uppercase"
|
|
45500
|
-
}
|
|
45501
|
-
}));
|
|
45502
|
-
if (productId == null) {
|
|
45503
|
-
return null;
|
|
45504
|
-
}
|
|
45505
|
-
const handleClick = () => {
|
|
45506
|
-
toggleFittingRoomItem(productId, productHandle, isPdp).catch((error) => {
|
|
45507
|
-
logger$4.logError("toggleFittingRoomItem failed", {
|
|
45508
|
-
error
|
|
45509
|
-
});
|
|
45510
|
-
});
|
|
45511
|
-
};
|
|
45512
|
-
return /* @__PURE__ */ jsxs("button", { type: "button", onClick: handleClick, css: css2.button, children: [
|
|
45513
|
-
/* @__PURE__ */ jsx$1(SvgFittingRoomIcon, { css: css2.icon }),
|
|
45514
|
-
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.text, t: isInFittingRoom ? "added_to_fitting_room" : "add_to_fitting_room" })
|
|
45515
|
-
] });
|
|
45516
|
-
}
|
|
45517
46025
|
const logger$3 = getLogger("widgets/fitting-room-icon");
|
|
45518
|
-
function FittingRoomIconWidget(
|
|
46026
|
+
function FittingRoomIconWidget(_props) {
|
|
45519
46027
|
const {
|
|
45520
46028
|
t
|
|
45521
46029
|
} = useTranslation();
|
|
@@ -45577,7 +46085,7 @@ function FittingRoomIconWidget({}) {
|
|
|
45577
46085
|
] });
|
|
45578
46086
|
}
|
|
45579
46087
|
const logger$2 = getLogger("widgets/fitting-room");
|
|
45580
|
-
function FittingRoomWidget(
|
|
46088
|
+
function FittingRoomWidget(_props) {
|
|
45581
46089
|
const count = useMainStore((state) => state.fittingRoom.length);
|
|
45582
46090
|
const openOverlay = useMainStore((state) => state.openOverlay);
|
|
45583
46091
|
const css2 = useCss((theme) => ({
|
|
@@ -45634,11 +46142,11 @@ function FittingRoomWidget({}) {
|
|
|
45634
46142
|
] });
|
|
45635
46143
|
}
|
|
45636
46144
|
const logger$1 = getLogger("size-rec");
|
|
45637
|
-
function SizeRecWidget(
|
|
46145
|
+
function SizeRecWidget(_props) {
|
|
45638
46146
|
const openOverlay = useMainStore((state) => state.openOverlay);
|
|
45639
46147
|
const openedOverlays = useMainStore((state) => state.openedOverlays);
|
|
45640
46148
|
const storeProductData = useMainStore((state) => state.productData);
|
|
45641
|
-
const
|
|
46149
|
+
const hasOpenedQuickViewOverlay = openedOverlays.includes(OverlayName.QUICK_VIEW);
|
|
45642
46150
|
const sizeRecommendationRecord = reactExports.useMemo(() => {
|
|
45643
46151
|
const {
|
|
45644
46152
|
currentProduct
|
|
@@ -45662,9 +46170,9 @@ function SizeRecWidget({}) {
|
|
|
45662
46170
|
return productData.sizeFitRecommendation || null;
|
|
45663
46171
|
}, [storeProductData]);
|
|
45664
46172
|
const handleLinkClick = reactExports.useCallback(() => {
|
|
45665
|
-
openOverlay(OverlayName.
|
|
46173
|
+
openOverlay(OverlayName.QUICK_VIEW);
|
|
45666
46174
|
}, [openOverlay]);
|
|
45667
|
-
if (!sizeRecommendationRecord || !
|
|
46175
|
+
if (!sizeRecommendationRecord || !hasOpenedQuickViewOverlay) {
|
|
45668
46176
|
return null;
|
|
45669
46177
|
}
|
|
45670
46178
|
const sizeLabel = getSizeLabelFromSize(sizeRecommendationRecord.recommended_size);
|
|
@@ -45676,8 +46184,11 @@ function SizeRecWidget({}) {
|
|
|
45676
46184
|
} });
|
|
45677
46185
|
}
|
|
45678
46186
|
const logger = getLogger("widgets/vto-button");
|
|
45679
|
-
function VtoButtonWidget(
|
|
46187
|
+
function VtoButtonWidget(_props) {
|
|
45680
46188
|
const openOverlay = useMainStore((state) => state.openOverlay);
|
|
46189
|
+
const currentProduct = getStaticData().currentProduct ?? null;
|
|
46190
|
+
const currentProductId = currentProduct?.externalId ?? null;
|
|
46191
|
+
const hasOtherFittingRoomItems = useMainStore((state) => state.fittingRoom.some((item) => item.externalId !== currentProductId));
|
|
45681
46192
|
const css2 = useCss((theme) => ({
|
|
45682
46193
|
button: {
|
|
45683
46194
|
marginTop: "10px",
|
|
@@ -45704,13 +46215,29 @@ function VtoButtonWidget({}) {
|
|
|
45704
46215
|
textTransform: "uppercase"
|
|
45705
46216
|
}
|
|
45706
46217
|
}));
|
|
45707
|
-
const
|
|
45708
|
-
|
|
45709
|
-
|
|
46218
|
+
const handleClick = () => {
|
|
46219
|
+
if (!hasOtherFittingRoomItems) {
|
|
46220
|
+
logger.logDebug("{{ts}} - Opening quick-view overlay");
|
|
46221
|
+
openOverlay(OverlayName.QUICK_VIEW);
|
|
46222
|
+
return;
|
|
46223
|
+
}
|
|
46224
|
+
logger.logDebug("{{ts}} - Opening fitting-room overlay");
|
|
46225
|
+
if (!currentProductId) {
|
|
46226
|
+
openOverlay(OverlayName.FITTING_ROOM);
|
|
46227
|
+
return;
|
|
46228
|
+
}
|
|
46229
|
+
ensureFittingRoomItem(currentProductId, currentProduct?.handle ?? null, true).catch((error) => {
|
|
46230
|
+
logger.logError("Failed to add current product to fitting room", {
|
|
46231
|
+
error
|
|
46232
|
+
});
|
|
46233
|
+
});
|
|
46234
|
+
openOverlay(OverlayName.FITTING_ROOM, {
|
|
46235
|
+
preselectExternalId: currentProductId
|
|
46236
|
+
});
|
|
45710
46237
|
};
|
|
45711
|
-
return /* @__PURE__ */ jsxs("button", { type: "button", onClick:
|
|
46238
|
+
return /* @__PURE__ */ jsxs("button", { type: "button", onClick: handleClick, css: css2.button, children: [
|
|
45712
46239
|
/* @__PURE__ */ jsx$1(SvgTfrIcon, { css: css2.icon }),
|
|
45713
|
-
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.text, t: "try_it_on" })
|
|
46240
|
+
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.text, t: hasOtherFittingRoomItems ? "try_it_on" : "quick-view.title" })
|
|
45714
46241
|
] });
|
|
45715
46242
|
}
|
|
45716
46243
|
var DeviceLayout = /* @__PURE__ */ ((DeviceLayout2) => {
|
|
@@ -45775,10 +46302,6 @@ function _init$1() {
|
|
|
45775
46302
|
});
|
|
45776
46303
|
}
|
|
45777
46304
|
const WIDGETS = {
|
|
45778
|
-
[
|
|
45779
|
-
"add-to-fitting-room"
|
|
45780
|
-
/* ADD_TO_FITTING_ROOM */
|
|
45781
|
-
]: AddToFittingRoomWidget,
|
|
45782
46305
|
[
|
|
45783
46306
|
"add-to-fitting-room-compact"
|
|
45784
46307
|
/* ADD_TO_FITTING_ROOM_COMPACT */
|
|
@@ -45806,7 +46329,7 @@ var OverlayName = /* @__PURE__ */ ((OverlayName2) => {
|
|
|
45806
46329
|
OverlayName2["GET_APP"] = "get-app";
|
|
45807
46330
|
OverlayName2["LANDING"] = "landing";
|
|
45808
46331
|
OverlayName2["SIGN_IN"] = "sign-in";
|
|
45809
|
-
OverlayName2["
|
|
46332
|
+
OverlayName2["QUICK_VIEW"] = "quick-view";
|
|
45810
46333
|
return OverlayName2;
|
|
45811
46334
|
})(OverlayName || {});
|
|
45812
46335
|
const OVERLAYS = {
|
|
@@ -45831,9 +46354,9 @@ const OVERLAYS = {
|
|
|
45831
46354
|
/* SIGN_IN */
|
|
45832
46355
|
]: SignInOverlay,
|
|
45833
46356
|
[
|
|
45834
|
-
"
|
|
45835
|
-
/*
|
|
45836
|
-
]:
|
|
46357
|
+
"quick-view"
|
|
46358
|
+
/* QUICK_VIEW */
|
|
46359
|
+
]: QuickViewOverlay
|
|
45837
46360
|
};
|
|
45838
46361
|
let staticData = null;
|
|
45839
46362
|
function _init(initStaticData) {
|
|
@@ -45968,6 +46491,7 @@ function Widget({
|
|
|
45968
46491
|
var EnvName = /* @__PURE__ */ ((EnvName2) => {
|
|
45969
46492
|
EnvName2["DEVELOPMENT"] = "development";
|
|
45970
46493
|
EnvName2["PRODUCTION"] = "production";
|
|
46494
|
+
EnvName2["DEMO"] = "demo";
|
|
45971
46495
|
EnvName2["LOCAL"] = "local";
|
|
45972
46496
|
return EnvName2;
|
|
45973
46497
|
})(EnvName || {});
|
|
@@ -45977,9 +46501,9 @@ const SHARED_CONFIG = {
|
|
|
45977
46501
|
appGooglePlayUrl: "https://play.google.com/store/apps/details?id=com.thefittingroom.marketplace"
|
|
45978
46502
|
},
|
|
45979
46503
|
build: {
|
|
45980
|
-
version: `${"5.0.
|
|
45981
|
-
commitHash: `${"
|
|
45982
|
-
date: `${"2026-05-
|
|
46504
|
+
version: `${"5.0.24"}`,
|
|
46505
|
+
commitHash: `${"931e0b2"}`,
|
|
46506
|
+
date: `${"2026-05-19T21:17:10.057Z"}`
|
|
45983
46507
|
}
|
|
45984
46508
|
};
|
|
45985
46509
|
const CONFIGS = {
|
|
@@ -45998,7 +46522,8 @@ const CONFIGS = {
|
|
|
45998
46522
|
},
|
|
45999
46523
|
api: {
|
|
46000
46524
|
baseUrl: "https://tfr.dev.thefittingroom.xyz",
|
|
46001
|
-
vtoTimeoutMs: 12e4
|
|
46525
|
+
vtoTimeoutMs: 12e4,
|
|
46526
|
+
vtoPrefetchDelayMs: 3e3
|
|
46002
46527
|
},
|
|
46003
46528
|
asset: {
|
|
46004
46529
|
baseUrl: "https://assets.dev.thefittingroom.xyz/shop-sdk/assets/v5"
|
|
@@ -46007,7 +46532,7 @@ const CONFIGS = {
|
|
|
46007
46532
|
baseUrl: "https://assets.dev.thefittingroom.xyz"
|
|
46008
46533
|
},
|
|
46009
46534
|
features: {
|
|
46010
|
-
vtoPrefetch:
|
|
46535
|
+
vtoPrefetch: true
|
|
46011
46536
|
},
|
|
46012
46537
|
...SHARED_CONFIG
|
|
46013
46538
|
},
|
|
@@ -46026,7 +46551,8 @@ const CONFIGS = {
|
|
|
46026
46551
|
},
|
|
46027
46552
|
api: {
|
|
46028
46553
|
baseUrl: "https://tfr.p.thefittingroom.xyz",
|
|
46029
|
-
vtoTimeoutMs: 12e4
|
|
46554
|
+
vtoTimeoutMs: 12e4,
|
|
46555
|
+
vtoPrefetchDelayMs: 3e3
|
|
46030
46556
|
},
|
|
46031
46557
|
asset: {
|
|
46032
46558
|
baseUrl: "https://assets.p.thefittingroom.xyz/shop-sdk/assets/v5"
|
|
@@ -46035,13 +46561,13 @@ const CONFIGS = {
|
|
|
46035
46561
|
baseUrl: "https://assets.p.thefittingroom.xyz"
|
|
46036
46562
|
},
|
|
46037
46563
|
features: {
|
|
46038
|
-
vtoPrefetch:
|
|
46564
|
+
vtoPrefetch: true
|
|
46039
46565
|
},
|
|
46040
46566
|
...SHARED_CONFIG
|
|
46041
46567
|
},
|
|
46042
46568
|
[
|
|
46043
|
-
"
|
|
46044
|
-
/*
|
|
46569
|
+
"demo"
|
|
46570
|
+
/* DEMO */
|
|
46045
46571
|
]: {
|
|
46046
46572
|
firebase: {
|
|
46047
46573
|
apiKey: "AIzaSyDfjBWzpmzb-mhGN8VSURxzLg6nkzmKUD8",
|
|
@@ -46054,7 +46580,8 @@ const CONFIGS = {
|
|
|
46054
46580
|
},
|
|
46055
46581
|
api: {
|
|
46056
46582
|
baseUrl: "https://demo.thefittingroom.xyz/api",
|
|
46057
|
-
vtoTimeoutMs: 12e4
|
|
46583
|
+
vtoTimeoutMs: 12e4,
|
|
46584
|
+
vtoPrefetchDelayMs: 3e3
|
|
46058
46585
|
},
|
|
46059
46586
|
asset: {
|
|
46060
46587
|
baseUrl: "http://demo.thefittingroom.xyz/s3/tfr-assets-dev/shop-sdk/assets/v5"
|
|
@@ -46063,7 +46590,36 @@ const CONFIGS = {
|
|
|
46063
46590
|
baseUrl: "http://demo.thefittingroom.xyz/s3/tfr-assets-dev"
|
|
46064
46591
|
},
|
|
46065
46592
|
features: {
|
|
46066
|
-
vtoPrefetch:
|
|
46593
|
+
vtoPrefetch: true
|
|
46594
|
+
},
|
|
46595
|
+
...SHARED_CONFIG
|
|
46596
|
+
},
|
|
46597
|
+
[
|
|
46598
|
+
"local"
|
|
46599
|
+
/* LOCAL */
|
|
46600
|
+
]: {
|
|
46601
|
+
firebase: {
|
|
46602
|
+
apiKey: "AIzaSyDfjBWzpmzb-mhGN8VSURxzLg6nkzmKUD8",
|
|
46603
|
+
authDomain: "fittingroom-dev-5d248.firebaseapp.com",
|
|
46604
|
+
projectId: "fittingroom-dev-5d248",
|
|
46605
|
+
storageBucket: "fittingroom-dev-5d248.appspot.com",
|
|
46606
|
+
messagingSenderId: "2298664147",
|
|
46607
|
+
appId: "1:2298664147:web:340bda75cd5d25f3997026",
|
|
46608
|
+
measurementId: "G-B7GDQ1Y9LL"
|
|
46609
|
+
},
|
|
46610
|
+
api: {
|
|
46611
|
+
baseUrl: "http://localhost:8080",
|
|
46612
|
+
vtoTimeoutMs: 12e4,
|
|
46613
|
+
vtoPrefetchDelayMs: 3e3
|
|
46614
|
+
},
|
|
46615
|
+
asset: {
|
|
46616
|
+
baseUrl: "http://localhost:9000/tfr-assets-dev/shop-sdk/assets/v5"
|
|
46617
|
+
},
|
|
46618
|
+
frames: {
|
|
46619
|
+
baseUrl: "http://localhost:9000/tfr-assets-dev"
|
|
46620
|
+
},
|
|
46621
|
+
features: {
|
|
46622
|
+
vtoPrefetch: true
|
|
46067
46623
|
},
|
|
46068
46624
|
...SHARED_CONFIG
|
|
46069
46625
|
}
|
|
@@ -46071,7 +46627,7 @@ const CONFIGS = {
|
|
|
46071
46627
|
const getConfig = (envName) => {
|
|
46072
46628
|
return CONFIGS[envName];
|
|
46073
46629
|
};
|
|
46074
|
-
const css = "
|
|
46630
|
+
const css = "\n@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');\n/* Inter — the SDK's own typeface, matching the Figma designs. Loaded here so\n overlay text renders in Inter regardless of the host page's fonts. */\nbody.tfr-modal-open {\n overflow: hidden;\n position: fixed;\n width: 100%;\n}\n";
|
|
46075
46631
|
class TfrWidgetElement extends HTMLElement {
|
|
46076
46632
|
connectedCallback() {
|
|
46077
46633
|
const attributes = this.getAttributeNames().reduce((attrs, name2) => {
|