@thefittingroom/shop-ui 5.0.23 → 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 +913 -353
- 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$g.logDebug("{{ts}} - Removing from fitting room", {
|
|
14109
|
-
productId
|
|
14110
|
-
});
|
|
14111
|
-
state.removeFromFittingRoom(productId);
|
|
14112
|
-
return;
|
|
14113
|
-
}
|
|
14114
|
-
logger$g.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
|
});
|
|
@@ -41662,12 +41717,14 @@ function buildVtoProductDataFromResolved(item) {
|
|
|
41662
41717
|
merchantProduct,
|
|
41663
41718
|
loadedProduct
|
|
41664
41719
|
} = item;
|
|
41665
|
-
if (!merchantProduct || !loadedProduct)
|
|
41720
|
+
if (!merchantProduct || !loadedProduct) {
|
|
41721
|
+
return null;
|
|
41722
|
+
}
|
|
41666
41723
|
const sizeRec = loadedProduct.sizeFitRecommendation;
|
|
41667
41724
|
const recommendedSizeId = sizeRec.recommended_size.id || null;
|
|
41668
41725
|
const recommendedSizeLabel = getSizeLabelFromSize(sizeRec.recommended_size);
|
|
41669
41726
|
if (recommendedSizeId == null || !recommendedSizeLabel) {
|
|
41670
|
-
logger$
|
|
41727
|
+
logger$a.logWarn("Missing recommended size for item", {
|
|
41671
41728
|
externalId: item.externalId
|
|
41672
41729
|
});
|
|
41673
41730
|
return null;
|
|
@@ -41675,13 +41732,19 @@ function buildVtoProductDataFromResolved(item) {
|
|
|
41675
41732
|
const sizes = [];
|
|
41676
41733
|
for (const sizeRecord of sizeRec.available_sizes) {
|
|
41677
41734
|
const sizeLabel = getSizeLabelFromSize(sizeRecord);
|
|
41678
|
-
if (!sizeLabel)
|
|
41735
|
+
if (!sizeLabel) {
|
|
41736
|
+
continue;
|
|
41737
|
+
}
|
|
41679
41738
|
const fit = sizeRec.fits.find((f) => f.size_id === sizeRecord.id);
|
|
41680
|
-
if (!fit)
|
|
41739
|
+
if (!fit) {
|
|
41740
|
+
continue;
|
|
41741
|
+
}
|
|
41681
41742
|
const colors = [];
|
|
41682
41743
|
for (const csa of sizeRecord.colorway_size_assets) {
|
|
41683
41744
|
const variant = merchantProduct.variants.find((v) => v.sku === csa.sku);
|
|
41684
|
-
if (!variant)
|
|
41745
|
+
if (!variant) {
|
|
41746
|
+
continue;
|
|
41747
|
+
}
|
|
41685
41748
|
colors.push({
|
|
41686
41749
|
colorwaySizeAssetId: csa.id,
|
|
41687
41750
|
colorLabel: variant.color || null,
|
|
@@ -41689,7 +41752,9 @@ function buildVtoProductDataFromResolved(item) {
|
|
|
41689
41752
|
priceFormatted: variant.priceFormatted
|
|
41690
41753
|
});
|
|
41691
41754
|
}
|
|
41692
|
-
if (colors.length === 0)
|
|
41755
|
+
if (colors.length === 0) {
|
|
41756
|
+
continue;
|
|
41757
|
+
}
|
|
41693
41758
|
sizes.push({
|
|
41694
41759
|
sizeId: sizeRecord.id,
|
|
41695
41760
|
sizeLabel,
|
|
@@ -41698,7 +41763,9 @@ function buildVtoProductDataFromResolved(item) {
|
|
|
41698
41763
|
colors
|
|
41699
41764
|
});
|
|
41700
41765
|
}
|
|
41701
|
-
if (sizes.length === 0)
|
|
41766
|
+
if (sizes.length === 0) {
|
|
41767
|
+
return null;
|
|
41768
|
+
}
|
|
41702
41769
|
return {
|
|
41703
41770
|
productName: merchantProduct.productName,
|
|
41704
41771
|
productDescriptionHtml: merchantProduct.productDescriptionHtml,
|
|
@@ -41711,12 +41778,16 @@ function buildVtoProductDataFromResolved(item) {
|
|
|
41711
41778
|
}
|
|
41712
41779
|
function findRecommendedColorSize(data, preferredColor) {
|
|
41713
41780
|
const recommended = data.sizes.find((s) => s.isRecommended);
|
|
41714
|
-
if (!recommended || recommended.colors.length === 0)
|
|
41781
|
+
if (!recommended || recommended.colors.length === 0) {
|
|
41782
|
+
return null;
|
|
41783
|
+
}
|
|
41715
41784
|
return recommended.colors.find((c) => c.colorLabel === preferredColor) ?? recommended.colors[0];
|
|
41716
41785
|
}
|
|
41717
41786
|
function findCsaByLabel(data, sizeLabel, preferredColor) {
|
|
41718
41787
|
const sizeRecord = data.sizes.find((s) => s.sizeLabel === sizeLabel);
|
|
41719
|
-
if (!sizeRecord || sizeRecord.colors.length === 0)
|
|
41788
|
+
if (!sizeRecord || sizeRecord.colors.length === 0) {
|
|
41789
|
+
return null;
|
|
41790
|
+
}
|
|
41720
41791
|
return sizeRecord.colors.find((c) => c.colorLabel === preferredColor) ?? sizeRecord.colors[0];
|
|
41721
41792
|
}
|
|
41722
41793
|
function useMobileSheetSnap(initial = "collapsed") {
|
|
@@ -41726,7 +41797,9 @@ function useMobileSheetSnap(initial = "collapsed") {
|
|
|
41726
41797
|
const initialSnap = snap;
|
|
41727
41798
|
const onTouchMove = (moveEvent) => {
|
|
41728
41799
|
const deltaY = moveEvent.touches[0].clientY - startY;
|
|
41729
|
-
if (Math.abs(deltaY) < 30)
|
|
41800
|
+
if (Math.abs(deltaY) < 30) {
|
|
41801
|
+
return;
|
|
41802
|
+
}
|
|
41730
41803
|
if (deltaY > 0) {
|
|
41731
41804
|
if (initialSnap === "full" || initialSnap === "expanded") {
|
|
41732
41805
|
setSnap("collapsed");
|
|
@@ -41755,11 +41828,16 @@ function useMobileSheetSnap(initial = "collapsed") {
|
|
|
41755
41828
|
}
|
|
41756
41829
|
const MAX_OUTFIT_ITEMS = 4;
|
|
41757
41830
|
function asStringList(value) {
|
|
41758
|
-
if (!Array.isArray(value))
|
|
41831
|
+
if (!Array.isArray(value)) {
|
|
41832
|
+
return [];
|
|
41833
|
+
}
|
|
41759
41834
|
const out = [];
|
|
41760
41835
|
for (const v of value) {
|
|
41761
|
-
if (typeof v === "string")
|
|
41762
|
-
|
|
41836
|
+
if (typeof v === "string") {
|
|
41837
|
+
out.push(v);
|
|
41838
|
+
} else if (v != null) {
|
|
41839
|
+
out.push(String(v));
|
|
41840
|
+
}
|
|
41763
41841
|
}
|
|
41764
41842
|
return out;
|
|
41765
41843
|
}
|
|
@@ -41800,8 +41878,12 @@ function computeAvailability(item, selectedExternalIds, resolved) {
|
|
|
41800
41878
|
}
|
|
41801
41879
|
const itemCat = item.styleCategory;
|
|
41802
41880
|
for (const sel of resolved.items) {
|
|
41803
|
-
if (!selectedExternalIds.has(sel.externalId))
|
|
41804
|
-
|
|
41881
|
+
if (!selectedExternalIds.has(sel.externalId)) {
|
|
41882
|
+
continue;
|
|
41883
|
+
}
|
|
41884
|
+
if (!sel.styleCategory) {
|
|
41885
|
+
continue;
|
|
41886
|
+
}
|
|
41805
41887
|
if (!pairCompatible(sel.styleCategory, itemCat, sel.styleCategoryGroup)) {
|
|
41806
41888
|
return "disabled";
|
|
41807
41889
|
}
|
|
@@ -41809,8 +41891,12 @@ function computeAvailability(item, selectedExternalIds, resolved) {
|
|
|
41809
41891
|
return "available";
|
|
41810
41892
|
}
|
|
41811
41893
|
function makeOutfitItem(r, forceUntuck) {
|
|
41812
|
-
if (!r.styleCategory)
|
|
41813
|
-
|
|
41894
|
+
if (!r.styleCategory) {
|
|
41895
|
+
return null;
|
|
41896
|
+
}
|
|
41897
|
+
if (r.storage.colorwaySizeAssetId == null) {
|
|
41898
|
+
return null;
|
|
41899
|
+
}
|
|
41814
41900
|
const tuckable = !!r.styleCategory.tuckable;
|
|
41815
41901
|
const untucked = forceUntuck && tuckable;
|
|
41816
41902
|
const layerOrder = untucked ? r.styleCategory.layer_order_untucked : r.styleCategory.layer_order;
|
|
@@ -41830,10 +41916,16 @@ function buildOutfit(selectedExternalIds, resolved, forceUntuck, lastAddedExtern
|
|
|
41830
41916
|
const entries = [];
|
|
41831
41917
|
let lastAddedResolved = null;
|
|
41832
41918
|
for (const r of resolved.items) {
|
|
41833
|
-
if (!selectedExternalIds.has(r.externalId))
|
|
41834
|
-
|
|
41919
|
+
if (!selectedExternalIds.has(r.externalId)) {
|
|
41920
|
+
continue;
|
|
41921
|
+
}
|
|
41922
|
+
if (r.externalId === lastAddedExternalId) {
|
|
41923
|
+
lastAddedResolved = r;
|
|
41924
|
+
}
|
|
41835
41925
|
const entry = makeOutfitItem(r, forceUntuck);
|
|
41836
|
-
if (entry)
|
|
41926
|
+
if (entry) {
|
|
41927
|
+
entries.push(entry);
|
|
41928
|
+
}
|
|
41837
41929
|
}
|
|
41838
41930
|
entries.sort((a, b) => a.layerOrder - b.layerOrder);
|
|
41839
41931
|
const items = entries.slice(0, MAX_OUTFIT_ITEMS).map((e) => e.outfitItem);
|
|
@@ -41844,10 +41936,16 @@ function buildOutfit(selectedExternalIds, resolved, forceUntuck, lastAddedExtern
|
|
|
41844
41936
|
};
|
|
41845
41937
|
}
|
|
41846
41938
|
function buildAlternateOutfits(primary, lastAddedResolved) {
|
|
41847
|
-
if (!lastAddedResolved || !lastAddedResolved.loadedProduct)
|
|
41939
|
+
if (!lastAddedResolved || !lastAddedResolved.loadedProduct) {
|
|
41940
|
+
return [];
|
|
41941
|
+
}
|
|
41848
41942
|
const currentCsaId = lastAddedResolved.storage.colorwaySizeAssetId;
|
|
41849
|
-
if (currentCsaId == null)
|
|
41850
|
-
|
|
41943
|
+
if (currentCsaId == null) {
|
|
41944
|
+
return [];
|
|
41945
|
+
}
|
|
41946
|
+
if (!primary.some((i) => i.externalId === lastAddedResolved.externalId)) {
|
|
41947
|
+
return [];
|
|
41948
|
+
}
|
|
41851
41949
|
const sizeRec = lastAddedResolved.loadedProduct.sizeFitRecommendation;
|
|
41852
41950
|
let currentColorwayId = null;
|
|
41853
41951
|
for (const sz of sizeRec.available_sizes) {
|
|
@@ -41860,7 +41958,9 @@ function buildAlternateOutfits(primary, lastAddedResolved) {
|
|
|
41860
41958
|
const out = [];
|
|
41861
41959
|
for (const sz of sizeRec.available_sizes) {
|
|
41862
41960
|
const altCsa = sz.colorway_size_assets.find((c) => c.id !== currentCsaId && (currentColorwayId == null || c.colorway_id === currentColorwayId));
|
|
41863
|
-
if (!altCsa)
|
|
41961
|
+
if (!altCsa) {
|
|
41962
|
+
continue;
|
|
41963
|
+
}
|
|
41864
41964
|
const alternate = primary.map((it) => it.externalId === lastAddedResolved.externalId ? {
|
|
41865
41965
|
...it,
|
|
41866
41966
|
colorwaySizeAssetId: altCsa.id
|
|
@@ -41869,6 +41969,24 @@ function buildAlternateOutfits(primary, lastAddedResolved) {
|
|
|
41869
41969
|
}
|
|
41870
41970
|
return out;
|
|
41871
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
|
+
}
|
|
41872
41990
|
function AvatarControls({
|
|
41873
41991
|
selectedItems,
|
|
41874
41992
|
canTuck,
|
|
@@ -41885,7 +42003,9 @@ function AvatarControls({
|
|
|
41885
42003
|
const [popoverOpen, setPopoverOpen] = reactExports.useState(false);
|
|
41886
42004
|
const popoverWrapperRef = reactExports.useRef(null);
|
|
41887
42005
|
reactExports.useEffect(() => {
|
|
41888
|
-
if (!popoverOpen)
|
|
42006
|
+
if (!popoverOpen) {
|
|
42007
|
+
return;
|
|
42008
|
+
}
|
|
41889
42009
|
const onDocClick = (e) => {
|
|
41890
42010
|
if (popoverWrapperRef.current && !popoverWrapperRef.current.contains(e.target)) {
|
|
41891
42011
|
setPopoverOpen(false);
|
|
@@ -41908,20 +42028,7 @@ function AvatarControls({
|
|
|
41908
42028
|
alignItems: "flex-end"
|
|
41909
42029
|
},
|
|
41910
42030
|
pill: {
|
|
41911
|
-
|
|
41912
|
-
alignItems: "center",
|
|
41913
|
-
gap: "8px",
|
|
41914
|
-
padding: "8px 16px",
|
|
41915
|
-
borderRadius: "24px",
|
|
41916
|
-
backgroundColor: "rgba(255, 255, 255, 0.95)",
|
|
41917
|
-
border: `1px solid ${theme.color_fg_text}`,
|
|
41918
|
-
fontSize: "12px",
|
|
41919
|
-
fontWeight: "500",
|
|
41920
|
-
letterSpacing: "0.5px",
|
|
41921
|
-
textTransform: "uppercase",
|
|
41922
|
-
cursor: "pointer",
|
|
41923
|
-
userSelect: "none",
|
|
41924
|
-
WebkitUserSelect: "none",
|
|
42031
|
+
...pillBaseStyle(theme),
|
|
41925
42032
|
transition: "padding 500ms cubic-bezier(0.22, 1, 0.36, 1), gap 500ms cubic-bezier(0.22, 1, 0.36, 1)"
|
|
41926
42033
|
},
|
|
41927
42034
|
pillCollapsed: {
|
|
@@ -42023,13 +42130,114 @@ function AvatarControls({
|
|
|
42023
42130
|
] })
|
|
42024
42131
|
] });
|
|
42025
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
|
+
}
|
|
42026
42234
|
function AvatarFrameViewer({
|
|
42027
42235
|
frameUrls,
|
|
42028
42236
|
selectedFrameIndex,
|
|
42029
42237
|
setSelectedFrameIndex,
|
|
42030
42238
|
imageContainerStyle,
|
|
42031
42239
|
imageStyle,
|
|
42032
|
-
loadingT = "
|
|
42240
|
+
loadingT = "quick-view.avatar_loading"
|
|
42033
42241
|
}) {
|
|
42034
42242
|
const css2 = useCss((_theme) => ({
|
|
42035
42243
|
imageContainer: {
|
|
@@ -42073,59 +42281,17 @@ function AvatarFrameViewer({
|
|
|
42073
42281
|
}, 500);
|
|
42074
42282
|
return () => clearInterval(intervalId);
|
|
42075
42283
|
}, [frameUrls, selectedFrameIndex, setSelectedFrameIndex]);
|
|
42076
|
-
const
|
|
42077
|
-
|
|
42078
|
-
|
|
42079
|
-
|
|
42080
|
-
|
|
42081
|
-
}
|
|
42082
|
-
const rotateRight = reactExports.useCallback(() => {
|
|
42083
|
-
setSelectedFrameIndex((prevIndex) => {
|
|
42084
|
-
if (prevIndex == null) return null;
|
|
42085
|
-
return prevIndex === (frameUrls ? frameUrls.length - 1 : 0) ? 0 : prevIndex + 1;
|
|
42086
|
-
});
|
|
42087
|
-
}, [frameUrls, setSelectedFrameIndex]);
|
|
42088
|
-
const handleImageMouseDrag = reactExports.useCallback((e) => {
|
|
42089
|
-
e.preventDefault();
|
|
42090
|
-
let startX = e.clientX;
|
|
42091
|
-
const onMouseMove = (moveEvent) => {
|
|
42092
|
-
const deltaX = moveEvent.clientX - startX;
|
|
42093
|
-
if (Math.abs(deltaX) >= 50) {
|
|
42094
|
-
if (deltaX > 0) rotateRight();
|
|
42095
|
-
else rotateLeft();
|
|
42096
|
-
startX = moveEvent.clientX;
|
|
42097
|
-
}
|
|
42098
|
-
};
|
|
42099
|
-
const onMouseUp = () => {
|
|
42100
|
-
window.removeEventListener("mousemove", onMouseMove);
|
|
42101
|
-
window.removeEventListener("mouseup", onMouseUp);
|
|
42102
|
-
};
|
|
42103
|
-
window.addEventListener("mousemove", onMouseMove);
|
|
42104
|
-
window.addEventListener("mouseup", onMouseUp);
|
|
42105
|
-
}, [rotateLeft, rotateRight]);
|
|
42106
|
-
const handleImageTouchDrag = reactExports.useCallback((e) => {
|
|
42107
|
-
e.preventDefault();
|
|
42108
|
-
let startX = e.touches[0].clientX;
|
|
42109
|
-
const onTouchMove = (moveEvent) => {
|
|
42110
|
-
const deltaX = moveEvent.touches[0].clientX - startX;
|
|
42111
|
-
if (Math.abs(deltaX) >= 50) {
|
|
42112
|
-
if (deltaX > 0) rotateRight();
|
|
42113
|
-
else rotateLeft();
|
|
42114
|
-
startX = moveEvent.touches[0].clientX;
|
|
42115
|
-
}
|
|
42116
|
-
};
|
|
42117
|
-
const onTouchEnd = () => {
|
|
42118
|
-
window.removeEventListener("touchmove", onTouchMove);
|
|
42119
|
-
window.removeEventListener("touchend", onTouchEnd);
|
|
42120
|
-
};
|
|
42121
|
-
window.addEventListener("touchmove", onTouchMove);
|
|
42122
|
-
window.addEventListener("touchend", onTouchEnd);
|
|
42123
|
-
}, [rotateLeft, rotateRight]);
|
|
42284
|
+
const {
|
|
42285
|
+
rotateLeft,
|
|
42286
|
+
rotateRight,
|
|
42287
|
+
handleMouseDragStart,
|
|
42288
|
+
handleTouchDragStart
|
|
42289
|
+
} = useFrameRotation(frameUrls, setSelectedFrameIndex);
|
|
42124
42290
|
if (!frameUrls || selectedFrameIndex == null) {
|
|
42125
42291
|
return /* @__PURE__ */ jsx$1(Loading, { t: loadingT });
|
|
42126
42292
|
}
|
|
42127
42293
|
return /* @__PURE__ */ jsxs("div", { css: css2.imageContainer, style: imageContainerStyle, children: [
|
|
42128
|
-
/* @__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 }),
|
|
42129
42295
|
/* @__PURE__ */ jsx$1("div", { css: css2.chevronLeftContainer, onClick: rotateLeft, children: /* @__PURE__ */ jsx$1(SvgChevronLeft, { css: css2.chevronIcon }) }),
|
|
42130
42296
|
/* @__PURE__ */ jsx$1("div", { css: css2.chevronRightContainer, onClick: rotateRight, children: /* @__PURE__ */ jsx$1(SvgChevronRight, { css: css2.chevronIcon }) })
|
|
42131
42297
|
] });
|
|
@@ -42134,9 +42300,13 @@ function AvatarPane({
|
|
|
42134
42300
|
frameUrls,
|
|
42135
42301
|
hasSelection,
|
|
42136
42302
|
controls,
|
|
42137
|
-
mobileFullscreen
|
|
42303
|
+
mobileFullscreen,
|
|
42304
|
+
selectedFrameIndex: indexProp,
|
|
42305
|
+
setSelectedFrameIndex: setIndexProp
|
|
42138
42306
|
}) {
|
|
42139
|
-
const [
|
|
42307
|
+
const [localFrameIndex, setLocalFrameIndex] = reactExports.useState(null);
|
|
42308
|
+
const selectedFrameIndex = indexProp !== void 0 ? indexProp : localFrameIndex;
|
|
42309
|
+
const setSelectedFrameIndex = setIndexProp ?? setLocalFrameIndex;
|
|
42140
42310
|
const css2 = useCss((theme) => ({
|
|
42141
42311
|
container: {
|
|
42142
42312
|
width: "100%",
|
|
@@ -42194,12 +42364,14 @@ function AvatarPane({
|
|
|
42194
42364
|
}
|
|
42195
42365
|
}));
|
|
42196
42366
|
if (frameUrls && frameUrls.length > 0) {
|
|
42197
|
-
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" });
|
|
42198
42368
|
if (mobileFullscreen) {
|
|
42199
42369
|
return /* @__PURE__ */ jsxs("div", { css: css2.mobileContainer, children: [
|
|
42200
|
-
/* @__PURE__ */
|
|
42201
|
-
|
|
42202
|
-
|
|
42370
|
+
/* @__PURE__ */ jsxs("div", { css: css2.mobileFrameSlot, children: [
|
|
42371
|
+
viewer,
|
|
42372
|
+
controls
|
|
42373
|
+
] }),
|
|
42374
|
+
/* @__PURE__ */ jsx$1("div", { css: css2.bottomFiller, children: " " })
|
|
42203
42375
|
] });
|
|
42204
42376
|
}
|
|
42205
42377
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
@@ -42208,7 +42380,7 @@ function AvatarPane({
|
|
|
42208
42380
|
] });
|
|
42209
42381
|
}
|
|
42210
42382
|
if (hasSelection) {
|
|
42211
|
-
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" }) });
|
|
42212
42384
|
}
|
|
42213
42385
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
42214
42386
|
/* @__PURE__ */ jsx$1("div", { css: css2.placeholder, children: /* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "fitting_room.avatar_placeholder_empty" }) }),
|
|
@@ -42313,7 +42485,9 @@ function ProductCard({
|
|
|
42313
42485
|
const disabled = availability === "disabled";
|
|
42314
42486
|
const selected = availability === "selected";
|
|
42315
42487
|
const handleClick = () => {
|
|
42316
|
-
if (disabled)
|
|
42488
|
+
if (disabled) {
|
|
42489
|
+
return;
|
|
42490
|
+
}
|
|
42317
42491
|
onClick();
|
|
42318
42492
|
};
|
|
42319
42493
|
const name2 = item.merchantProduct?.productName ?? item.externalId;
|
|
@@ -42359,9 +42533,13 @@ function CardRail({
|
|
|
42359
42533
|
setCanScrollRight(el.scrollLeft + el.clientWidth < el.scrollWidth - 1);
|
|
42360
42534
|
}, []);
|
|
42361
42535
|
reactExports.useLayoutEffect(() => {
|
|
42362
|
-
if (collapsed)
|
|
42536
|
+
if (collapsed) {
|
|
42537
|
+
return;
|
|
42538
|
+
}
|
|
42363
42539
|
const el = scrollRef.current;
|
|
42364
|
-
if (!el)
|
|
42540
|
+
if (!el) {
|
|
42541
|
+
return;
|
|
42542
|
+
}
|
|
42365
42543
|
updateScrollState();
|
|
42366
42544
|
const observer = new ResizeObserver(updateScrollState);
|
|
42367
42545
|
observer.observe(el);
|
|
@@ -42369,7 +42547,9 @@ function CardRail({
|
|
|
42369
42547
|
}, [collapsed, group.items, updateScrollState]);
|
|
42370
42548
|
const scrollByPage = reactExports.useCallback((dir) => {
|
|
42371
42549
|
const el = scrollRef.current;
|
|
42372
|
-
if (!el)
|
|
42550
|
+
if (!el) {
|
|
42551
|
+
return;
|
|
42552
|
+
}
|
|
42373
42553
|
el.scrollBy({
|
|
42374
42554
|
left: dir * el.clientWidth * 0.8,
|
|
42375
42555
|
behavior: "smooth"
|
|
@@ -42462,7 +42642,7 @@ function CardRail({
|
|
|
42462
42642
|
function AddToCartButton({
|
|
42463
42643
|
onClick
|
|
42464
42644
|
}) {
|
|
42465
|
-
return /* @__PURE__ */ jsx$1(ButtonT, { variant: "brand", t: "
|
|
42645
|
+
return /* @__PURE__ */ jsx$1(ButtonT, { variant: "brand", t: "quick-view.add_to_cart", onClick });
|
|
42466
42646
|
}
|
|
42467
42647
|
function ItemFitDetails({
|
|
42468
42648
|
loadedProductData,
|
|
@@ -42579,9 +42759,13 @@ function DetailAccordionItem({
|
|
|
42579
42759
|
}) {
|
|
42580
42760
|
const productData = reactExports.useMemo(() => buildVtoProductDataFromResolved(item), [item]);
|
|
42581
42761
|
const selectedSizeLabel = reactExports.useMemo(() => {
|
|
42582
|
-
if (!productData)
|
|
42762
|
+
if (!productData) {
|
|
42763
|
+
return null;
|
|
42764
|
+
}
|
|
42583
42765
|
const csaId = item.storage.colorwaySizeAssetId;
|
|
42584
|
-
if (csaId == null)
|
|
42766
|
+
if (csaId == null) {
|
|
42767
|
+
return null;
|
|
42768
|
+
}
|
|
42585
42769
|
for (const sizeRec of productData.sizes) {
|
|
42586
42770
|
if (sizeRec.colors.some((c) => c.colorwaySizeAssetId === csaId)) {
|
|
42587
42771
|
return sizeRec.sizeLabel;
|
|
@@ -42590,12 +42774,18 @@ function DetailAccordionItem({
|
|
|
42590
42774
|
return null;
|
|
42591
42775
|
}, [productData, item.storage.colorwaySizeAssetId]);
|
|
42592
42776
|
const currentPrice = reactExports.useMemo(() => {
|
|
42593
|
-
if (!productData)
|
|
42777
|
+
if (!productData) {
|
|
42778
|
+
return null;
|
|
42779
|
+
}
|
|
42594
42780
|
const csaId = item.storage.colorwaySizeAssetId;
|
|
42595
|
-
if (csaId == null)
|
|
42781
|
+
if (csaId == null) {
|
|
42782
|
+
return null;
|
|
42783
|
+
}
|
|
42596
42784
|
for (const sizeRec of productData.sizes) {
|
|
42597
42785
|
const c = sizeRec.colors.find((c2) => c2.colorwaySizeAssetId === csaId);
|
|
42598
|
-
if (c)
|
|
42786
|
+
if (c) {
|
|
42787
|
+
return c.priceFormatted;
|
|
42788
|
+
}
|
|
42599
42789
|
}
|
|
42600
42790
|
return null;
|
|
42601
42791
|
}, [productData, item.storage.colorwaySizeAssetId]);
|
|
@@ -42922,6 +43112,119 @@ function DetailAccordion({
|
|
|
42922
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);
|
|
42923
43113
|
}) });
|
|
42924
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
|
+
}
|
|
42925
43228
|
const AVATAR_ASPECT_RATIO = 2 / 3;
|
|
42926
43229
|
const EDGE_INSET_PX = 16;
|
|
42927
43230
|
const AVATAR_MIN_WIDTH_PX = 240;
|
|
@@ -42937,7 +43240,6 @@ function DesktopLayout$1({
|
|
|
42937
43240
|
detailMode,
|
|
42938
43241
|
forceUntuck,
|
|
42939
43242
|
canTuck,
|
|
42940
|
-
zoomed,
|
|
42941
43243
|
frameUrls,
|
|
42942
43244
|
onSelectItem,
|
|
42943
43245
|
onRemoveItem,
|
|
@@ -42946,26 +43248,31 @@ function DesktopLayout$1({
|
|
|
42946
43248
|
onChangeSize,
|
|
42947
43249
|
onAddToCart,
|
|
42948
43250
|
onToggleUntuck,
|
|
42949
|
-
onToggleZoom,
|
|
42950
43251
|
onSignOut
|
|
42951
43252
|
}) {
|
|
42952
43253
|
const hasSelection = selectedItems.length > 0;
|
|
42953
43254
|
const [avatarHovered, setAvatarHovered] = reactExports.useState(false);
|
|
43255
|
+
const [zoomOpen, setZoomOpen] = reactExports.useState(false);
|
|
43256
|
+
const [selectedFrameIndex, setSelectedFrameIndex] = reactExports.useState(null);
|
|
42954
43257
|
const containerRef = reactExports.useRef(null);
|
|
42955
43258
|
const [avatarWidth, setAvatarWidth] = reactExports.useState(AVATAR_MIN_WIDTH_PX);
|
|
42956
43259
|
reactExports.useLayoutEffect(() => {
|
|
42957
43260
|
const el = containerRef.current;
|
|
42958
|
-
if (!el)
|
|
43261
|
+
if (!el) {
|
|
43262
|
+
return;
|
|
43263
|
+
}
|
|
42959
43264
|
const observer = new ResizeObserver(() => {
|
|
42960
43265
|
const availableHeightPx = el.clientHeight;
|
|
42961
|
-
if (availableHeightPx <= 0)
|
|
43266
|
+
if (availableHeightPx <= 0) {
|
|
43267
|
+
return;
|
|
43268
|
+
}
|
|
42962
43269
|
const target = Math.floor(availableHeightPx * AVATAR_ASPECT_RATIO);
|
|
42963
43270
|
setAvatarWidth(Math.min(AVATAR_MAX_WIDTH_PX, Math.max(AVATAR_MIN_WIDTH_PX, target)));
|
|
42964
43271
|
});
|
|
42965
43272
|
observer.observe(el);
|
|
42966
43273
|
return () => observer.disconnect();
|
|
42967
43274
|
}, []);
|
|
42968
|
-
const gridTemplateColumns =
|
|
43275
|
+
const gridTemplateColumns = hasSelection ? `${avatarWidth}px minmax(${DETAILS_MIN_WIDTH_PX}px, ${DETAILS_FR}fr) ${CARDS_FR}fr` : `${avatarWidth}px 1fr`;
|
|
42969
43276
|
const css2 = useCss((_theme) => ({
|
|
42970
43277
|
container: {
|
|
42971
43278
|
display: "grid",
|
|
@@ -43030,21 +43337,127 @@ function DesktopLayout$1({
|
|
|
43030
43337
|
fontSize: "14px"
|
|
43031
43338
|
}
|
|
43032
43339
|
}));
|
|
43033
|
-
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;
|
|
43034
43341
|
return /* @__PURE__ */ jsxs("div", { ref: containerRef, css: css2.container, style: {
|
|
43035
43342
|
gridTemplateColumns
|
|
43036
43343
|
}, children: [
|
|
43037
|
-
/* @__PURE__ */ jsx$1("div", { css: css2.avatarColumn, onMouseEnter: () => setAvatarHovered(true), onMouseLeave: () => setAvatarHovered(false), children: /* @__PURE__ */ jsx$1(AvatarPane, { hasSelection, frameUrls, controls }) }),
|
|
43038
|
-
|
|
43039
|
-
|
|
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: [
|
|
43040
43347
|
/* @__PURE__ */ jsxs("span", { css: css2.signOutWrapper, onClick: onSignOut, children: [
|
|
43041
43348
|
/* @__PURE__ */ jsx$1(SvgTfrIcon, { css: css2.signOutIcon }),
|
|
43042
43349
|
/* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.signOut, t: "fitting_room.sign_out" })
|
|
43043
43350
|
] }),
|
|
43044
43351
|
resolved.groups.map((group) => /* @__PURE__ */ jsx$1(CardRail, { group, availabilityByExternalId, onSelectItem, onRemoveItem }, group.group.name))
|
|
43045
|
-
] })
|
|
43352
|
+
] }),
|
|
43353
|
+
zoomOpen && frameUrls && frameUrls.length > 0 ? /* @__PURE__ */ jsx$1(ZoomModal, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, onClose: () => setZoomOpen(false) }) : null
|
|
43354
|
+
] });
|
|
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
|
|
43046
43458
|
] });
|
|
43047
43459
|
}
|
|
43460
|
+
const SECTION_SCROLL_TOP_GAP_PX = 50;
|
|
43048
43461
|
function MobileLayout$1({
|
|
43049
43462
|
mode,
|
|
43050
43463
|
resolved,
|
|
@@ -43080,12 +43493,55 @@ function BrowseView({
|
|
|
43080
43493
|
onRemoveItem,
|
|
43081
43494
|
onTryItOn
|
|
43082
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
|
+
}, []);
|
|
43083
43537
|
const css2 = useCss((_theme) => ({
|
|
43084
43538
|
container: {
|
|
43085
43539
|
display: "flex",
|
|
43086
43540
|
flexDirection: "column",
|
|
43087
43541
|
height: "100%",
|
|
43088
|
-
width: "100%"
|
|
43542
|
+
width: "100%",
|
|
43543
|
+
// Positioning context for the floating SectionNav pill.
|
|
43544
|
+
position: "relative"
|
|
43089
43545
|
},
|
|
43090
43546
|
railsArea: {
|
|
43091
43547
|
flex: 1,
|
|
@@ -43103,7 +43559,14 @@ function BrowseView({
|
|
|
43103
43559
|
}
|
|
43104
43560
|
}));
|
|
43105
43561
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
43106
|
-
|
|
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)) }),
|
|
43107
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
|
|
43108
43571
|
] });
|
|
43109
43572
|
}
|
|
@@ -43129,8 +43592,14 @@ function TryOnView({
|
|
|
43129
43592
|
reactExports.useEffect(() => {
|
|
43130
43593
|
function refresh() {
|
|
43131
43594
|
const el = innerRef.current;
|
|
43132
|
-
if (!el)
|
|
43133
|
-
|
|
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", ""));
|
|
43134
43603
|
const heightPx = Math.min(el.clientHeight, maxHeightPx || el.clientHeight);
|
|
43135
43604
|
setSheetStyle({
|
|
43136
43605
|
height: `${heightPx}px`
|
|
@@ -43166,7 +43635,7 @@ function TryOnView({
|
|
|
43166
43635
|
},
|
|
43167
43636
|
sheetOuter: {
|
|
43168
43637
|
position: "absolute",
|
|
43169
|
-
// 8px gap to either side, matching
|
|
43638
|
+
// 8px gap to either side, matching quick-view's mobile sheet.
|
|
43170
43639
|
left: "8px",
|
|
43171
43640
|
right: "8px",
|
|
43172
43641
|
bottom: 0,
|
|
@@ -43207,7 +43676,7 @@ function TryOnView({
|
|
|
43207
43676
|
}
|
|
43208
43677
|
}));
|
|
43209
43678
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
43210
|
-
/* @__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 }) }),
|
|
43211
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 }) }),
|
|
43212
43681
|
/* @__PURE__ */ jsx$1("div", { css: css2.sheetOuter, style: sheetStyle, children: /* @__PURE__ */ jsxs("div", { ref: innerRef, css: css2.sheetInner, style: sheetStyle, children: [
|
|
43213
43682
|
/* @__PURE__ */ jsxs("div", { css: css2.sheetHandleRow, onTouchStart: sheetTouchStart, children: [
|
|
@@ -43218,7 +43687,7 @@ function TryOnView({
|
|
|
43218
43687
|
] }) })
|
|
43219
43688
|
] });
|
|
43220
43689
|
}
|
|
43221
|
-
const logger$
|
|
43690
|
+
const logger$9 = getLogger("use-vto-requests");
|
|
43222
43691
|
function outfitKey(items) {
|
|
43223
43692
|
return items.map((i) => `${i.colorway_size_asset_id}:${i.untucked ? 1 : 0}`).sort().join("|");
|
|
43224
43693
|
}
|
|
@@ -43230,18 +43699,22 @@ function useVtoRequests() {
|
|
|
43230
43699
|
const [lastError, setLastError] = reactExports.useState(null);
|
|
43231
43700
|
const clearError = reactExports.useCallback(() => setLastError(null), []);
|
|
43232
43701
|
const request = reactExports.useCallback((items, priority) => {
|
|
43233
|
-
if (items.length === 0)
|
|
43702
|
+
if (items.length === 0) {
|
|
43703
|
+
return;
|
|
43704
|
+
}
|
|
43234
43705
|
const key = outfitKey(items);
|
|
43235
|
-
if (requestedKeysRef.current.has(key))
|
|
43706
|
+
if (requestedKeysRef.current.has(key)) {
|
|
43707
|
+
return;
|
|
43708
|
+
}
|
|
43236
43709
|
const exec = () => {
|
|
43237
43710
|
requestedKeysRef.current.add(key);
|
|
43238
|
-
logger$
|
|
43711
|
+
logger$9.logDebug("Requesting VTO composition", {
|
|
43239
43712
|
key,
|
|
43240
43713
|
items,
|
|
43241
43714
|
priority
|
|
43242
43715
|
});
|
|
43243
43716
|
requestVto(items).then((resp) => {
|
|
43244
|
-
logger$
|
|
43717
|
+
logger$9.logDebug("VTO frames ready", {
|
|
43245
43718
|
key,
|
|
43246
43719
|
count: resp.frames.length
|
|
43247
43720
|
});
|
|
@@ -43250,7 +43723,7 @@ function useVtoRequests() {
|
|
|
43250
43723
|
[key]: resp.frames
|
|
43251
43724
|
}));
|
|
43252
43725
|
}).catch((error) => {
|
|
43253
|
-
logger$
|
|
43726
|
+
logger$9.logError("VTO request failed", {
|
|
43254
43727
|
error,
|
|
43255
43728
|
items,
|
|
43256
43729
|
key
|
|
@@ -43260,7 +43733,9 @@ function useVtoRequests() {
|
|
|
43260
43733
|
});
|
|
43261
43734
|
};
|
|
43262
43735
|
if (priority) {
|
|
43263
|
-
for (const timer of pendingPrefetchTimersRef.current)
|
|
43736
|
+
for (const timer of pendingPrefetchTimersRef.current) {
|
|
43737
|
+
clearTimeout(timer);
|
|
43738
|
+
}
|
|
43264
43739
|
pendingPrefetchTimersRef.current.clear();
|
|
43265
43740
|
lastPriorityTimeRef.current = Date.now();
|
|
43266
43741
|
exec();
|
|
@@ -43271,7 +43746,9 @@ function useVtoRequests() {
|
|
|
43271
43746
|
if (last) {
|
|
43272
43747
|
const now = Date.now();
|
|
43273
43748
|
const minNext = last + getStaticData().config.api.vtoPrefetchDelayMs;
|
|
43274
|
-
if (now < minNext)
|
|
43749
|
+
if (now < minNext) {
|
|
43750
|
+
delay = minNext - now;
|
|
43751
|
+
}
|
|
43275
43752
|
}
|
|
43276
43753
|
if (delay > 0) {
|
|
43277
43754
|
const timer = setTimeout(() => {
|
|
@@ -43286,15 +43763,21 @@ function useVtoRequests() {
|
|
|
43286
43763
|
reactExports.useEffect(() => {
|
|
43287
43764
|
const timers = pendingPrefetchTimersRef.current;
|
|
43288
43765
|
return () => {
|
|
43289
|
-
for (const timer of timers)
|
|
43766
|
+
for (const timer of timers) {
|
|
43767
|
+
clearTimeout(timer);
|
|
43768
|
+
}
|
|
43290
43769
|
timers.clear();
|
|
43291
43770
|
};
|
|
43292
43771
|
}, []);
|
|
43293
43772
|
const framesForOutfit = reactExports.useCallback((items) => {
|
|
43294
|
-
if (items.length === 0)
|
|
43773
|
+
if (items.length === 0) {
|
|
43774
|
+
return null;
|
|
43775
|
+
}
|
|
43295
43776
|
const key = outfitKey(items);
|
|
43296
43777
|
const frames = framesByKey[key];
|
|
43297
|
-
if (!frames || frames.length === 0)
|
|
43778
|
+
if (!frames || frames.length === 0) {
|
|
43779
|
+
return null;
|
|
43780
|
+
}
|
|
43298
43781
|
const baseUrl2 = getStaticData().config.frames.baseUrl;
|
|
43299
43782
|
return frames.map((u) => applyFrameBaseUrl(u, baseUrl2));
|
|
43300
43783
|
}, [framesByKey]);
|
|
@@ -43313,12 +43796,14 @@ function toWireItems(items) {
|
|
|
43313
43796
|
} : {}
|
|
43314
43797
|
}));
|
|
43315
43798
|
}
|
|
43316
|
-
const logger$
|
|
43799
|
+
const logger$8 = getLogger("overlays/fitting-room");
|
|
43317
43800
|
function measureTopOffset() {
|
|
43318
43801
|
const {
|
|
43319
43802
|
getOverlayTopOffset
|
|
43320
43803
|
} = getStaticData();
|
|
43321
|
-
if (!getOverlayTopOffset)
|
|
43804
|
+
if (!getOverlayTopOffset) {
|
|
43805
|
+
return 0;
|
|
43806
|
+
}
|
|
43322
43807
|
try {
|
|
43323
43808
|
const offset = getOverlayTopOffset();
|
|
43324
43809
|
return Number.isFinite(offset) && offset > 0 ? offset : 0;
|
|
@@ -43326,7 +43811,9 @@ function measureTopOffset() {
|
|
|
43326
43811
|
return 0;
|
|
43327
43812
|
}
|
|
43328
43813
|
}
|
|
43329
|
-
function FittingRoomOverlay(
|
|
43814
|
+
function FittingRoomOverlay({
|
|
43815
|
+
preselectExternalId
|
|
43816
|
+
}) {
|
|
43330
43817
|
const deviceLayout = useMainStore((state) => state.deviceLayout);
|
|
43331
43818
|
const userIsLoggedIn = useMainStore((state) => state.userIsLoggedIn);
|
|
43332
43819
|
const userHasAvatar = useMainStore((state) => state.userHasAvatar);
|
|
@@ -43342,7 +43829,6 @@ function FittingRoomOverlay() {
|
|
|
43342
43829
|
const [forceUntuck, setForceUntuck] = reactExports.useState(false);
|
|
43343
43830
|
const [lastAddedExternalId, setLastAddedExternalId] = reactExports.useState(null);
|
|
43344
43831
|
const [mobileMode, setMobileMode] = reactExports.useState("browse");
|
|
43345
|
-
const [zoomed, setZoomed] = reactExports.useState(false);
|
|
43346
43832
|
const {
|
|
43347
43833
|
snap: sheetSnap,
|
|
43348
43834
|
setSnap: setSheetSnap,
|
|
@@ -43357,13 +43843,17 @@ function FittingRoomOverlay() {
|
|
|
43357
43843
|
} = useVtoRequests();
|
|
43358
43844
|
reactExports.useEffect(() => {
|
|
43359
43845
|
const savedScrollY = window.scrollY;
|
|
43360
|
-
if (savedScrollY > 0)
|
|
43846
|
+
if (savedScrollY > 0) {
|
|
43847
|
+
window.scrollTo(0, 0);
|
|
43848
|
+
}
|
|
43361
43849
|
setTopOffset(measureTopOffset());
|
|
43362
43850
|
const onResize = () => setTopOffset(measureTopOffset());
|
|
43363
43851
|
window.addEventListener("resize", onResize);
|
|
43364
43852
|
return () => {
|
|
43365
43853
|
window.removeEventListener("resize", onResize);
|
|
43366
|
-
if (savedScrollY > 0)
|
|
43854
|
+
if (savedScrollY > 0) {
|
|
43855
|
+
window.scrollTo(0, savedScrollY);
|
|
43856
|
+
}
|
|
43367
43857
|
};
|
|
43368
43858
|
}, []);
|
|
43369
43859
|
const selectedItems = reactExports.useMemo(() => {
|
|
@@ -43376,14 +43866,22 @@ function FittingRoomOverlay() {
|
|
|
43376
43866
|
indexed.sort((a, b) => {
|
|
43377
43867
|
const aOrder = a.item.styleCategoryGroup?.display_order ?? Number.MAX_SAFE_INTEGER;
|
|
43378
43868
|
const bOrder = b.item.styleCategoryGroup?.display_order ?? Number.MAX_SAFE_INTEGER;
|
|
43379
|
-
if (aOrder !== bOrder)
|
|
43869
|
+
if (aOrder !== bOrder) {
|
|
43870
|
+
return aOrder - bOrder;
|
|
43871
|
+
}
|
|
43380
43872
|
return a.idx - b.idx;
|
|
43381
43873
|
});
|
|
43382
43874
|
return indexed.map(({
|
|
43383
43875
|
item
|
|
43384
43876
|
}) => item);
|
|
43385
43877
|
}, [resolved.items, selectedExternalIds]);
|
|
43386
|
-
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]);
|
|
43387
43885
|
const availabilityByExternalId = reactExports.useMemo(() => {
|
|
43388
43886
|
const out = {};
|
|
43389
43887
|
for (const item of resolved.items) {
|
|
@@ -43392,11 +43890,17 @@ function FittingRoomOverlay() {
|
|
|
43392
43890
|
return out;
|
|
43393
43891
|
}, [resolved, selectedExternalIds]);
|
|
43394
43892
|
const ensureSizeForItem = reactExports.useCallback((item) => {
|
|
43395
|
-
if (item.storage.colorwaySizeAssetId != null)
|
|
43893
|
+
if (item.storage.colorwaySizeAssetId != null) {
|
|
43894
|
+
return;
|
|
43895
|
+
}
|
|
43396
43896
|
const productData = buildVtoProductDataFromResolved(item);
|
|
43397
|
-
if (!productData)
|
|
43897
|
+
if (!productData) {
|
|
43898
|
+
return;
|
|
43899
|
+
}
|
|
43398
43900
|
const csa = findRecommendedColorSize(productData, item.storage.color);
|
|
43399
|
-
if (!csa)
|
|
43901
|
+
if (!csa) {
|
|
43902
|
+
return;
|
|
43903
|
+
}
|
|
43400
43904
|
const sizeRec = item.loadedProduct?.sizeFitRecommendation;
|
|
43401
43905
|
const sizeLabel = sizeRec ? getSizeLabelFromSize(sizeRec.recommended_size) : productData.recommendedSizeLabel;
|
|
43402
43906
|
updateFittingRoomItem(item.externalId, {
|
|
@@ -43404,7 +43908,7 @@ function FittingRoomOverlay() {
|
|
|
43404
43908
|
size: sizeLabel,
|
|
43405
43909
|
color: csa.colorLabel
|
|
43406
43910
|
});
|
|
43407
|
-
logger$
|
|
43911
|
+
logger$8.logDebug("Auto-picked recommended size", {
|
|
43408
43912
|
externalId: item.externalId,
|
|
43409
43913
|
sizeLabel,
|
|
43410
43914
|
csaId: csa.colorwaySizeAssetId
|
|
@@ -43412,12 +43916,16 @@ function FittingRoomOverlay() {
|
|
|
43412
43916
|
}, [updateFittingRoomItem]);
|
|
43413
43917
|
const handleSelectItem = reactExports.useCallback((externalId) => {
|
|
43414
43918
|
const item = resolved.items.find((i) => i.externalId === externalId);
|
|
43415
|
-
if (!item)
|
|
43919
|
+
if (!item) {
|
|
43920
|
+
return;
|
|
43921
|
+
}
|
|
43416
43922
|
const isSelected = selectedExternalIds.has(externalId);
|
|
43417
43923
|
const nextSelected = new Set(selectedExternalIds);
|
|
43418
43924
|
if (isSelected) {
|
|
43419
43925
|
nextSelected.delete(externalId);
|
|
43420
|
-
if (openAccordionItemId === externalId)
|
|
43926
|
+
if (openAccordionItemId === externalId) {
|
|
43927
|
+
setOpenAccordionItemId(null);
|
|
43928
|
+
}
|
|
43421
43929
|
} else {
|
|
43422
43930
|
nextSelected.add(externalId);
|
|
43423
43931
|
ensureSizeForItem(item);
|
|
@@ -43431,11 +43939,17 @@ function FittingRoomOverlay() {
|
|
|
43431
43939
|
}, [resolved, selectedExternalIds, openAccordionItemId, isMobileLayout, ensureSizeForItem]);
|
|
43432
43940
|
const handleChangeSize = reactExports.useCallback((externalId, sizeLabel) => {
|
|
43433
43941
|
const item = resolved.items.find((i) => i.externalId === externalId);
|
|
43434
|
-
if (!item)
|
|
43942
|
+
if (!item) {
|
|
43943
|
+
return;
|
|
43944
|
+
}
|
|
43435
43945
|
const productData = buildVtoProductDataFromResolved(item);
|
|
43436
|
-
if (!productData)
|
|
43946
|
+
if (!productData) {
|
|
43947
|
+
return;
|
|
43948
|
+
}
|
|
43437
43949
|
const csa = findCsaByLabel(productData, sizeLabel, item.storage.color);
|
|
43438
|
-
if (!csa)
|
|
43950
|
+
if (!csa) {
|
|
43951
|
+
return;
|
|
43952
|
+
}
|
|
43439
43953
|
updateFittingRoomItem(externalId, {
|
|
43440
43954
|
colorwaySizeAssetId: csa.colorwaySizeAssetId,
|
|
43441
43955
|
size: sizeLabel,
|
|
@@ -43447,14 +43961,14 @@ function FittingRoomOverlay() {
|
|
|
43447
43961
|
addToCart
|
|
43448
43962
|
} = getStaticData();
|
|
43449
43963
|
if (!addToCart) {
|
|
43450
|
-
logger$
|
|
43964
|
+
logger$8.logWarn("No addToCart callback configured; skipping", {
|
|
43451
43965
|
externalId
|
|
43452
43966
|
});
|
|
43453
43967
|
return;
|
|
43454
43968
|
}
|
|
43455
43969
|
const item = resolved.items.find((i) => i.externalId === externalId);
|
|
43456
43970
|
if (!item || !item.storage.size || !item.storage.color) {
|
|
43457
|
-
logger$
|
|
43971
|
+
logger$8.logWarn("Cannot add to cart: missing size or color", {
|
|
43458
43972
|
externalId,
|
|
43459
43973
|
size: item?.storage.size,
|
|
43460
43974
|
color: item?.storage.color
|
|
@@ -43468,7 +43982,7 @@ function FittingRoomOverlay() {
|
|
|
43468
43982
|
});
|
|
43469
43983
|
closeOverlay();
|
|
43470
43984
|
} catch (error) {
|
|
43471
|
-
logger$
|
|
43985
|
+
logger$8.logError("addToCart failed", {
|
|
43472
43986
|
error,
|
|
43473
43987
|
externalId
|
|
43474
43988
|
});
|
|
@@ -43477,17 +43991,18 @@ function FittingRoomOverlay() {
|
|
|
43477
43991
|
const handleToggleUntuck = reactExports.useCallback(() => {
|
|
43478
43992
|
setForceUntuck((prev2) => !prev2);
|
|
43479
43993
|
}, []);
|
|
43480
|
-
const handleToggleZoom = reactExports.useCallback(() => {
|
|
43481
|
-
setZoomed((prev2) => !prev2);
|
|
43482
|
-
}, []);
|
|
43483
43994
|
const handleRemoveItem = reactExports.useCallback((externalId) => {
|
|
43484
43995
|
setSelectedExternalIds((prev2) => {
|
|
43485
|
-
if (!prev2.has(externalId))
|
|
43996
|
+
if (!prev2.has(externalId)) {
|
|
43997
|
+
return prev2;
|
|
43998
|
+
}
|
|
43486
43999
|
const next2 = new Set(prev2);
|
|
43487
44000
|
next2.delete(externalId);
|
|
43488
44001
|
return next2;
|
|
43489
44002
|
});
|
|
43490
|
-
if (openAccordionItemId === externalId)
|
|
44003
|
+
if (openAccordionItemId === externalId) {
|
|
44004
|
+
setOpenAccordionItemId(null);
|
|
44005
|
+
}
|
|
43491
44006
|
}, [openAccordionItemId]);
|
|
43492
44007
|
const handleTryItOn = reactExports.useCallback(() => {
|
|
43493
44008
|
setMobileMode("try-on");
|
|
@@ -43501,10 +44016,25 @@ function FittingRoomOverlay() {
|
|
|
43501
44016
|
setOpenAccordionItemId(null);
|
|
43502
44017
|
}
|
|
43503
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]);
|
|
43504
44030
|
const outfit = reactExports.useMemo(() => buildOutfit(selectedExternalIds, resolved, forceUntuck, lastAddedExternalId), [selectedExternalIds, resolved, forceUntuck, lastAddedExternalId]);
|
|
43505
44031
|
reactExports.useEffect(() => {
|
|
43506
|
-
if (!userIsLoggedIn || !userHasAvatar)
|
|
43507
|
-
|
|
44032
|
+
if (!userIsLoggedIn || !userHasAvatar) {
|
|
44033
|
+
return;
|
|
44034
|
+
}
|
|
44035
|
+
if (outfit.items.length === 0) {
|
|
44036
|
+
return;
|
|
44037
|
+
}
|
|
43508
44038
|
requestVtoComposition(toWireItems(outfit.items), true);
|
|
43509
44039
|
if (getStaticData().config.features.vtoPrefetch) {
|
|
43510
44040
|
for (const alt of outfit.alternates) {
|
|
@@ -43515,7 +44045,9 @@ function FittingRoomOverlay() {
|
|
|
43515
44045
|
const frameUrls = reactExports.useMemo(() => {
|
|
43516
44046
|
if (outfit.items.length === 0) {
|
|
43517
44047
|
const bareFrames = userProfile?.avatar_frames;
|
|
43518
|
-
if (!bareFrames || bareFrames.length === 0)
|
|
44048
|
+
if (!bareFrames || bareFrames.length === 0) {
|
|
44049
|
+
return null;
|
|
44050
|
+
}
|
|
43519
44051
|
const baseUrl2 = getStaticData().config.frames.baseUrl;
|
|
43520
44052
|
return bareFrames.map((u) => applyFrameBaseUrl(u, baseUrl2));
|
|
43521
44053
|
}
|
|
@@ -43539,7 +44071,7 @@ function FittingRoomOverlay() {
|
|
|
43539
44071
|
closeOverlay();
|
|
43540
44072
|
const authManager2 = getAuthManager();
|
|
43541
44073
|
authManager2.logout().catch((error) => {
|
|
43542
|
-
logger$
|
|
44074
|
+
logger$8.logError("Error during logout", {
|
|
43543
44075
|
error
|
|
43544
44076
|
});
|
|
43545
44077
|
});
|
|
@@ -43586,29 +44118,6 @@ function FittingRoomOverlay() {
|
|
|
43586
44118
|
fontSize: "13px",
|
|
43587
44119
|
textDecoration: "underline",
|
|
43588
44120
|
marginTop: "8px"
|
|
43589
|
-
},
|
|
43590
|
-
snackbar: {
|
|
43591
|
-
position: "absolute",
|
|
43592
|
-
left: "50%",
|
|
43593
|
-
bottom: "24px",
|
|
43594
|
-
transform: "translateX(-50%)",
|
|
43595
|
-
padding: "12px 20px",
|
|
43596
|
-
borderRadius: "24px",
|
|
43597
|
-
backgroundColor: theme.color_fg_text,
|
|
43598
|
-
color: "#FFFFFF",
|
|
43599
|
-
fontSize: "13px",
|
|
43600
|
-
display: "flex",
|
|
43601
|
-
alignItems: "center",
|
|
43602
|
-
gap: "12px",
|
|
43603
|
-
zIndex: 10,
|
|
43604
|
-
maxWidth: "calc(100% - 32px)"
|
|
43605
|
-
},
|
|
43606
|
-
snackbarDismiss: {
|
|
43607
|
-
background: "none",
|
|
43608
|
-
border: "none",
|
|
43609
|
-
color: "#FFFFFF",
|
|
43610
|
-
fontSize: "16px",
|
|
43611
|
-
cursor: "pointer"
|
|
43612
44121
|
}
|
|
43613
44122
|
}));
|
|
43614
44123
|
const isMobileTryOn = isMobileLayout && mobileMode === "try-on";
|
|
@@ -43639,15 +44148,12 @@ function FittingRoomOverlay() {
|
|
|
43639
44148
|
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.emptyTagline, t: "landing.description" }),
|
|
43640
44149
|
/* @__PURE__ */ jsx$1("div", { css: css2.emptyShopNow, children: /* @__PURE__ */ jsx$1(ButtonT, { variant: "primary", t: "fitting_room.shop_now", onClick: handleShopNow }) }),
|
|
43641
44150
|
userIsLoggedIn ? /* @__PURE__ */ jsx$1(LinkT, { variant: "underline", css: css2.emptySignOut, t: "fitting_room.sign_out", onClick: handleSignOut }) : null
|
|
43642
|
-
] }) }) : 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,
|
|
43643
|
-
vtoError ? /* @__PURE__ */
|
|
43644
|
-
/* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "fitting_room.vto_error" }),
|
|
43645
|
-
/* @__PURE__ */ jsx$1("button", { css: css2.snackbarDismiss, onClick: clearVtoError, "aria-label": "Dismiss", children: "×" })
|
|
43646
|
-
] }) : 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
|
|
43647
44153
|
] }) });
|
|
43648
44154
|
}
|
|
43649
44155
|
const CONTACT_US_LINK = "mailto:info@thefittingroom.tech?subject=Forgot%20Password%20Assistance";
|
|
43650
|
-
const logger$
|
|
44156
|
+
const logger$7 = getLogger("forgot-password");
|
|
43651
44157
|
function ForgotPasswordOverlay({
|
|
43652
44158
|
returnToOverlay
|
|
43653
44159
|
}) {
|
|
@@ -43713,7 +44219,7 @@ function ForgotPasswordOverlay({
|
|
|
43713
44219
|
await authManager2.sendPasswordResetEmail(email2);
|
|
43714
44220
|
setLinkSent(true);
|
|
43715
44221
|
} catch (error) {
|
|
43716
|
-
logger$
|
|
44222
|
+
logger$7.logError("Error sending password reset email:", {
|
|
43717
44223
|
error
|
|
43718
44224
|
});
|
|
43719
44225
|
}
|
|
@@ -43731,7 +44237,7 @@ function ForgotPasswordOverlay({
|
|
|
43731
44237
|
return;
|
|
43732
44238
|
}
|
|
43733
44239
|
const email = emailEl.value;
|
|
43734
|
-
resetUserPassword(email);
|
|
44240
|
+
void resetUserPassword(email);
|
|
43735
44241
|
}, [t]);
|
|
43736
44242
|
const handleBackToSignInClick = reactExports.useCallback(() => {
|
|
43737
44243
|
openOverlay(OverlayName.SIGN_IN, {
|
|
@@ -43932,7 +44438,7 @@ function TfrTitle() {
|
|
|
43932
44438
|
}));
|
|
43933
44439
|
return /* @__PURE__ */ jsx$1("div", { css: css2.container, children: /* @__PURE__ */ jsx$1(SvgTfrName, { css: css2.nameIcon }) });
|
|
43934
44440
|
}
|
|
43935
|
-
const logger$
|
|
44441
|
+
const logger$6 = getLogger("sign-in");
|
|
43936
44442
|
function SignInOverlay({
|
|
43937
44443
|
returnToOverlay
|
|
43938
44444
|
}) {
|
|
@@ -44006,7 +44512,7 @@ function SignInOverlay({
|
|
|
44006
44512
|
closeOverlay();
|
|
44007
44513
|
}
|
|
44008
44514
|
} catch (error) {
|
|
44009
|
-
logger$
|
|
44515
|
+
logger$6.logError("Login failed:", {
|
|
44010
44516
|
error
|
|
44011
44517
|
});
|
|
44012
44518
|
setEmailError(" ");
|
|
@@ -44038,7 +44544,7 @@ function SignInOverlay({
|
|
|
44038
44544
|
}
|
|
44039
44545
|
const email = emailEl.value;
|
|
44040
44546
|
const password = passwordEl.value;
|
|
44041
|
-
loginUser(email, password);
|
|
44547
|
+
void loginUser(email, password);
|
|
44042
44548
|
}, [returnToOverlay, closeOverlay, openOverlay, t]);
|
|
44043
44549
|
const handleForgotPasswordClick = reactExports.useCallback(() => {
|
|
44044
44550
|
openOverlay(OverlayName.FORGOT_PASSWORD, {
|
|
@@ -44369,8 +44875,8 @@ function FitChart({
|
|
|
44369
44875
|
const AVATAR_IMAGE_ASPECT_RATIO = 2 / 3;
|
|
44370
44876
|
const AVATAR_GUTTER_HEIGHT_PX = 100;
|
|
44371
44877
|
const CONTENT_AREA_WIDTH_PX = 550;
|
|
44372
|
-
const logger$
|
|
44373
|
-
function
|
|
44878
|
+
const logger$5 = getLogger("overlays/quick-view");
|
|
44879
|
+
function QuickViewOverlay() {
|
|
44374
44880
|
const userIsLoggedIn = useMainStore((state) => state.userIsLoggedIn);
|
|
44375
44881
|
const userHasAvatar = useMainStore((state) => state.userHasAvatar);
|
|
44376
44882
|
const userProfile = useMainStore((state) => state.userProfile);
|
|
@@ -44384,18 +44890,20 @@ function VtoSingleOverlay() {
|
|
|
44384
44890
|
const [modalStyle, setModalStyle] = reactExports.useState({});
|
|
44385
44891
|
const {
|
|
44386
44892
|
request: vtoRequest,
|
|
44387
|
-
framesForOutfit
|
|
44893
|
+
framesForOutfit,
|
|
44894
|
+
lastError: vtoError,
|
|
44895
|
+
clearError: clearVtoError
|
|
44388
44896
|
} = useVtoRequests();
|
|
44389
44897
|
reactExports.useEffect(() => {
|
|
44390
44898
|
if (!userIsLoggedIn) {
|
|
44391
44899
|
openOverlay(OverlayName.LANDING, {
|
|
44392
|
-
returnToOverlay: OverlayName.
|
|
44900
|
+
returnToOverlay: OverlayName.QUICK_VIEW
|
|
44393
44901
|
});
|
|
44394
44902
|
return;
|
|
44395
44903
|
}
|
|
44396
44904
|
if (userIsLoggedIn && userHasAvatar === false) {
|
|
44397
44905
|
openOverlay(OverlayName.GET_APP, {
|
|
44398
|
-
returnToOverlay: OverlayName.
|
|
44906
|
+
returnToOverlay: OverlayName.QUICK_VIEW,
|
|
44399
44907
|
noAvatar: true
|
|
44400
44908
|
});
|
|
44401
44909
|
return;
|
|
@@ -44463,7 +44971,7 @@ function VtoSingleOverlay() {
|
|
|
44463
44971
|
const sku = csaRec.sku;
|
|
44464
44972
|
const variant = variants.find((v) => v.sku === sku);
|
|
44465
44973
|
if (!variant) {
|
|
44466
|
-
logger$
|
|
44974
|
+
logger$5.logWarn(`Variant not found for externalId: ${currentProduct.externalId} sizeId: ${sizeId} sku: ${sku}`);
|
|
44467
44975
|
continue;
|
|
44468
44976
|
}
|
|
44469
44977
|
const colorLabel = variant.color || null;
|
|
@@ -44476,7 +44984,7 @@ function VtoSingleOverlay() {
|
|
|
44476
44984
|
});
|
|
44477
44985
|
}
|
|
44478
44986
|
if (!colors.length) {
|
|
44479
|
-
logger$
|
|
44987
|
+
logger$5.logWarn(`No valid colorways found for externalId: ${currentProduct.externalId} sizeId: ${sizeId}`);
|
|
44480
44988
|
continue;
|
|
44481
44989
|
}
|
|
44482
44990
|
sizes.push({
|
|
@@ -44519,7 +45027,7 @@ function VtoSingleOverlay() {
|
|
|
44519
45027
|
setSelectedColorLabel(recommendedColorLabel);
|
|
44520
45028
|
}
|
|
44521
45029
|
} catch (error) {
|
|
44522
|
-
logger$
|
|
45030
|
+
logger$5.logError("Error fetching initial data:", {
|
|
44523
45031
|
error
|
|
44524
45032
|
});
|
|
44525
45033
|
setVtoProductData(false);
|
|
@@ -44530,7 +45038,7 @@ function VtoSingleOverlay() {
|
|
|
44530
45038
|
if (vtoProductData !== null) {
|
|
44531
45039
|
return;
|
|
44532
45040
|
}
|
|
44533
|
-
setupInitialVtoData();
|
|
45041
|
+
void setupInitialVtoData();
|
|
44534
45042
|
}, [storeProductData, vtoProductData, userProfile]);
|
|
44535
45043
|
const {
|
|
44536
45044
|
sizeColorRecord: selectedColorSizeRecord,
|
|
@@ -44592,7 +45100,7 @@ function VtoSingleOverlay() {
|
|
|
44592
45100
|
if (!rewritten) {
|
|
44593
45101
|
return null;
|
|
44594
45102
|
}
|
|
44595
|
-
logger$
|
|
45103
|
+
logger$5.logDebug(`{{ts}} - Displaying VTO for sku: ${selectedColorSizeRecord.sku}`);
|
|
44596
45104
|
rewritten.forEach((url) => {
|
|
44597
45105
|
const img = new Image();
|
|
44598
45106
|
img.src = url;
|
|
@@ -44603,7 +45111,7 @@ function VtoSingleOverlay() {
|
|
|
44603
45111
|
closeOverlay();
|
|
44604
45112
|
const authManager2 = getAuthManager();
|
|
44605
45113
|
authManager2.logout().catch((error) => {
|
|
44606
|
-
logger$
|
|
45114
|
+
logger$5.logError("Error during logout:", {
|
|
44607
45115
|
error
|
|
44608
45116
|
});
|
|
44609
45117
|
});
|
|
@@ -44625,7 +45133,7 @@ function VtoSingleOverlay() {
|
|
|
44625
45133
|
color: selectedColorLabel
|
|
44626
45134
|
});
|
|
44627
45135
|
} catch (error) {
|
|
44628
|
-
logger$
|
|
45136
|
+
logger$5.logError("Error adding to cart:", {
|
|
44629
45137
|
error
|
|
44630
45138
|
});
|
|
44631
45139
|
}
|
|
@@ -44642,7 +45150,10 @@ function VtoSingleOverlay() {
|
|
|
44642
45150
|
} else {
|
|
44643
45151
|
Layout = DesktopLayout;
|
|
44644
45152
|
}
|
|
44645
|
-
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
|
+
] });
|
|
44646
45157
|
}
|
|
44647
45158
|
function NoFitLayout({
|
|
44648
45159
|
onClose,
|
|
@@ -44674,14 +45185,59 @@ function NoFitLayout({
|
|
|
44674
45185
|
}
|
|
44675
45186
|
}));
|
|
44676
45187
|
return /* @__PURE__ */ jsxs("div", { css: css2.mainContainer, children: [
|
|
44677
|
-
/* @__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 }) }),
|
|
44678
45189
|
/* @__PURE__ */ jsxs("div", { css: css2.contentContainer, children: [
|
|
44679
45190
|
/* @__PURE__ */ jsx$1("div", { children: " " }),
|
|
44680
|
-
/* @__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" }) }),
|
|
44681
45192
|
/* @__PURE__ */ jsx$1("div", { css: css2.footerContainer, children: /* @__PURE__ */ jsx$1(Footer, { onSignOutClick: onSignOut }) })
|
|
44682
45193
|
] })
|
|
44683
45194
|
] });
|
|
44684
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
|
+
}
|
|
44685
45241
|
function MobileLayout({
|
|
44686
45242
|
loadedProductData,
|
|
44687
45243
|
selectedColorSizeRecord,
|
|
@@ -44787,7 +45343,11 @@ function MobileLayout({
|
|
|
44787
45343
|
if (!bottomFrameInnerEl) {
|
|
44788
45344
|
return;
|
|
44789
45345
|
}
|
|
44790
|
-
const
|
|
45346
|
+
const parentEl = bottomFrameInnerEl.parentElement;
|
|
45347
|
+
if (!parentEl) {
|
|
45348
|
+
return;
|
|
45349
|
+
}
|
|
45350
|
+
const maxHeightPx = Number(window.getComputedStyle(parentEl).getPropertyValue("max-height").replace("px", ""));
|
|
44791
45351
|
const heightPx = Math.min(bottomFrameInnerEl.clientHeight, maxHeightPx);
|
|
44792
45352
|
const bottomFrameStyle = {
|
|
44793
45353
|
height: `${heightPx}px`
|
|
@@ -44892,8 +45452,11 @@ function MobileContentExpanded({
|
|
|
44892
45452
|
/* @__PURE__ */ jsx$1("div", { css: css2.sizeSelectorContainer, children: /* @__PURE__ */ jsx$1(SizeSelector, { loadedProductData, selectedSizeLabel, onChangeSize }) }),
|
|
44893
45453
|
/* @__PURE__ */ jsx$1("div", { css: css2.itemFitTextContainer, children: /* @__PURE__ */ jsx$1(ItemFitText, { loadedProductData }) }),
|
|
44894
45454
|
/* @__PURE__ */ jsx$1("div", { css: css2.itemFitDetailsContainer, children: /* @__PURE__ */ jsx$1(ItemFitDetails, { loadedProductData, selectedSizeLabel }) }),
|
|
44895
|
-
/* @__PURE__ */
|
|
44896
|
-
|
|
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 }) })
|
|
44897
45460
|
] });
|
|
44898
45461
|
}
|
|
44899
45462
|
function MobileContentFull({
|
|
@@ -44988,8 +45551,11 @@ function MobileContentFull({
|
|
|
44988
45551
|
] }),
|
|
44989
45552
|
fitChartNode,
|
|
44990
45553
|
/* @__PURE__ */ jsx$1("div", { css: css2.colorSelectorContainer, children: /* @__PURE__ */ jsx$1(ColorSelector, { availableColorLabels, selectedColorLabel, onChangeColor }) }),
|
|
44991
|
-
/* @__PURE__ */
|
|
44992
|
-
|
|
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 }) }),
|
|
44993
45559
|
/* @__PURE__ */ jsx$1("div", { css: css2.priceContainer, children: /* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.priceText, children: selectedColorSizeRecord.priceFormatted }) }),
|
|
44994
45560
|
/* @__PURE__ */ jsx$1("div", { css: css2.productDescriptionContainer, children: /* @__PURE__ */ jsx$1(ProductDescriptionText, { loadedProductData }) }),
|
|
44995
45561
|
/* @__PURE__ */ jsx$1("div", { css: css2.footerContainer, children: /* @__PURE__ */ jsx$1(Footer, { onSignOutClick: onSignOut }) })
|
|
@@ -45105,7 +45671,7 @@ function DesktopLayout({
|
|
|
45105
45671
|
return /* @__PURE__ */ jsxs("div", { css: css2.mainContainer, children: [
|
|
45106
45672
|
/* @__PURE__ */ jsx$1(Avatar, { frameUrls, setModalStyle }),
|
|
45107
45673
|
/* @__PURE__ */ jsxs("div", { css: css2.rightContainer, children: [
|
|
45108
|
-
/* @__PURE__ */ jsx$1(ModalTitlebar, { title: t("
|
|
45674
|
+
/* @__PURE__ */ jsx$1(ModalTitlebar, { title: t("quick-view.title"), onCloseClick: onClose }),
|
|
45109
45675
|
/* @__PURE__ */ jsxs("div", { css: css2.contentContainer, children: [
|
|
45110
45676
|
/* @__PURE__ */ jsx$1("div", { css: css2.productNameContainer, children: /* @__PURE__ */ jsx$1(Text, { variant: "brand", css: css2.productNameText, children: loadedProductData.productName }) }),
|
|
45111
45677
|
/* @__PURE__ */ jsx$1("div", { css: css2.priceContainer, children: /* @__PURE__ */ jsx$1(Text, { variant: "base", css: css2.priceText, children: selectedColorSizeRecord.priceFormatted }) }),
|
|
@@ -45121,7 +45687,10 @@ function DesktopLayout({
|
|
|
45121
45687
|
/* @__PURE__ */ jsx$1("div", { css: css2.itemFitDetailsContainer, children: /* @__PURE__ */ jsx$1(ItemFitDetails, { loadedProductData, selectedSizeLabel }) })
|
|
45122
45688
|
] }),
|
|
45123
45689
|
fitChartNode,
|
|
45124
|
-
/* @__PURE__ */
|
|
45690
|
+
/* @__PURE__ */ jsxs("div", { css: css2.buttonContainer, children: [
|
|
45691
|
+
/* @__PURE__ */ jsx$1(AddToCartButton, { onClick: onAddToCart }),
|
|
45692
|
+
/* @__PURE__ */ jsx$1(FittingRoomToggleButton, {})
|
|
45693
|
+
] }),
|
|
45125
45694
|
/* @__PURE__ */ jsx$1("div", { css: css2.descriptionContainer, children: /* @__PURE__ */ jsx$1(ProductDescriptionText, { loadedProductData }) })
|
|
45126
45695
|
] }),
|
|
45127
45696
|
/* @__PURE__ */ jsx$1(Footer, { onSignOutClick: onSignOut })
|
|
@@ -45141,10 +45710,37 @@ function Avatar({
|
|
|
45141
45710
|
bottomContainerStyle: {}
|
|
45142
45711
|
});
|
|
45143
45712
|
const [selectedFrameIndex, setSelectedFrameIndex] = reactExports.useState(null);
|
|
45713
|
+
const [zoomOpen, setZoomOpen] = reactExports.useState(false);
|
|
45144
45714
|
const css2 = useCss((theme) => ({
|
|
45145
45715
|
topContainer: {
|
|
45146
45716
|
flex: "none",
|
|
45147
|
-
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"
|
|
45148
45744
|
},
|
|
45149
45745
|
bottomContainer: {
|
|
45150
45746
|
position: "absolute",
|
|
@@ -45258,10 +45854,15 @@ function Avatar({
|
|
|
45258
45854
|
}, [isMobileLayout]);
|
|
45259
45855
|
const isReady = !!frameUrls && selectedFrameIndex != null;
|
|
45260
45856
|
return /* @__PURE__ */ jsxs("div", { css: css2.topContainer, style: layoutData.topContainerStyle, children: [
|
|
45261
|
-
/* @__PURE__ */ jsx$1(AvatarFrameViewer, { frameUrls, selectedFrameIndex, setSelectedFrameIndex, imageContainerStyle: layoutData.imageContainerStyle, imageStyle: layoutData.imageStyle, loadingT: "
|
|
45262
|
-
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: [
|
|
45263
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 }),
|
|
45264
|
-
/* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "
|
|
45865
|
+
/* @__PURE__ */ jsx$1(TextT, { variant: "base", t: "quick-view.slide_to_rotate", css: css2.sliderText })
|
|
45265
45866
|
] }) }) : null
|
|
45266
45867
|
] });
|
|
45267
45868
|
}
|
|
@@ -45316,7 +45917,7 @@ function ColorSelector({
|
|
|
45316
45917
|
return null;
|
|
45317
45918
|
}
|
|
45318
45919
|
return /* @__PURE__ */ jsx$1("div", { css: css2.colorContainer, children: /* @__PURE__ */ jsxs("label", { children: [
|
|
45319
|
-
/* @__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" }),
|
|
45320
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)) })
|
|
45321
45922
|
] }) });
|
|
45322
45923
|
}
|
|
@@ -45363,11 +45964,11 @@ function Footer({
|
|
|
45363
45964
|
}
|
|
45364
45965
|
}));
|
|
45365
45966
|
return /* @__PURE__ */ jsxs("div", { css: css2.container, children: [
|
|
45366
|
-
/* @__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" }),
|
|
45367
45968
|
/* @__PURE__ */ jsx$1(SvgTfrName, { css: css2.tfrIcon })
|
|
45368
45969
|
] });
|
|
45369
45970
|
}
|
|
45370
|
-
const logger$
|
|
45971
|
+
const logger$4 = getLogger("widgets/add-to-fitting-room-compact");
|
|
45371
45972
|
function AddToFittingRoomCompactWidget({
|
|
45372
45973
|
attributes
|
|
45373
45974
|
}) {
|
|
@@ -45413,7 +46014,7 @@ function AddToFittingRoomCompactWidget({
|
|
|
45413
46014
|
}
|
|
45414
46015
|
const handleClick = () => {
|
|
45415
46016
|
toggleFittingRoomItem(productId, productHandle, isPdp).catch((error) => {
|
|
45416
|
-
logger$
|
|
46017
|
+
logger$4.logError("toggleFittingRoomItem failed", {
|
|
45417
46018
|
error
|
|
45418
46019
|
});
|
|
45419
46020
|
});
|
|
@@ -45421,64 +46022,8 @@ function AddToFittingRoomCompactWidget({
|
|
|
45421
46022
|
const ariaLabel = t(isInFittingRoom ? "added_to_fitting_room" : "add_to_fitting_room");
|
|
45422
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, "", ""] }) });
|
|
45423
46024
|
}
|
|
45424
|
-
const logger$4 = getLogger("widgets/add-to-fitting-room");
|
|
45425
|
-
function AddToFittingRoomWidget({
|
|
45426
|
-
attributes
|
|
45427
|
-
}) {
|
|
45428
|
-
const {
|
|
45429
|
-
currentProduct
|
|
45430
|
-
} = getStaticData();
|
|
45431
|
-
const attrProductId = attributes["product-id"];
|
|
45432
|
-
const attrProductHandle = attributes["product-handle"];
|
|
45433
|
-
const productId = attrProductId || currentProduct?.externalId || null;
|
|
45434
|
-
const isPdp = productId != null && productId === currentProduct?.externalId;
|
|
45435
|
-
const productHandle = attrProductHandle || (isPdp ? currentProduct?.handle ?? null : null);
|
|
45436
|
-
const isInFittingRoom = useMainStore((state) => productId == null ? false : state.fittingRoom.some((item) => item.externalId === productId));
|
|
45437
|
-
const css2 = useCss((theme) => ({
|
|
45438
|
-
button: {
|
|
45439
|
-
marginTop: "10px",
|
|
45440
|
-
marginBottom: "10px",
|
|
45441
|
-
width: "100%",
|
|
45442
|
-
maxWidth: "440px",
|
|
45443
|
-
display: "flex",
|
|
45444
|
-
alignItems: "center",
|
|
45445
|
-
justifyContent: "center",
|
|
45446
|
-
gap: "10px",
|
|
45447
|
-
padding: "13px",
|
|
45448
|
-
backgroundColor: "white",
|
|
45449
|
-
borderWidth: "1px",
|
|
45450
|
-
borderColor: theme.color_fg_text,
|
|
45451
|
-
borderStyle: "solid",
|
|
45452
|
-
borderRadius: "30px",
|
|
45453
|
-
cursor: "pointer"
|
|
45454
|
-
},
|
|
45455
|
-
icon: {
|
|
45456
|
-
color: theme.color_fg_text,
|
|
45457
|
-
width: "20px",
|
|
45458
|
-
height: "20px"
|
|
45459
|
-
},
|
|
45460
|
-
text: {
|
|
45461
|
-
fontSize: "14px",
|
|
45462
|
-
textTransform: "uppercase"
|
|
45463
|
-
}
|
|
45464
|
-
}));
|
|
45465
|
-
if (productId == null) {
|
|
45466
|
-
return null;
|
|
45467
|
-
}
|
|
45468
|
-
const handleClick = () => {
|
|
45469
|
-
toggleFittingRoomItem(productId, productHandle, isPdp).catch((error) => {
|
|
45470
|
-
logger$4.logError("toggleFittingRoomItem failed", {
|
|
45471
|
-
error
|
|
45472
|
-
});
|
|
45473
|
-
});
|
|
45474
|
-
};
|
|
45475
|
-
return /* @__PURE__ */ jsxs("button", { type: "button", onClick: handleClick, css: css2.button, children: [
|
|
45476
|
-
/* @__PURE__ */ jsx$1(SvgFittingRoomIcon, { css: css2.icon }),
|
|
45477
|
-
/* @__PURE__ */ jsx$1(TextT, { variant: "base", css: css2.text, t: isInFittingRoom ? "added_to_fitting_room" : "add_to_fitting_room" })
|
|
45478
|
-
] });
|
|
45479
|
-
}
|
|
45480
46025
|
const logger$3 = getLogger("widgets/fitting-room-icon");
|
|
45481
|
-
function FittingRoomIconWidget(
|
|
46026
|
+
function FittingRoomIconWidget(_props) {
|
|
45482
46027
|
const {
|
|
45483
46028
|
t
|
|
45484
46029
|
} = useTranslation();
|
|
@@ -45540,7 +46085,7 @@ function FittingRoomIconWidget({}) {
|
|
|
45540
46085
|
] });
|
|
45541
46086
|
}
|
|
45542
46087
|
const logger$2 = getLogger("widgets/fitting-room");
|
|
45543
|
-
function FittingRoomWidget(
|
|
46088
|
+
function FittingRoomWidget(_props) {
|
|
45544
46089
|
const count = useMainStore((state) => state.fittingRoom.length);
|
|
45545
46090
|
const openOverlay = useMainStore((state) => state.openOverlay);
|
|
45546
46091
|
const css2 = useCss((theme) => ({
|
|
@@ -45597,11 +46142,11 @@ function FittingRoomWidget({}) {
|
|
|
45597
46142
|
] });
|
|
45598
46143
|
}
|
|
45599
46144
|
const logger$1 = getLogger("size-rec");
|
|
45600
|
-
function SizeRecWidget(
|
|
46145
|
+
function SizeRecWidget(_props) {
|
|
45601
46146
|
const openOverlay = useMainStore((state) => state.openOverlay);
|
|
45602
46147
|
const openedOverlays = useMainStore((state) => state.openedOverlays);
|
|
45603
46148
|
const storeProductData = useMainStore((state) => state.productData);
|
|
45604
|
-
const
|
|
46149
|
+
const hasOpenedQuickViewOverlay = openedOverlays.includes(OverlayName.QUICK_VIEW);
|
|
45605
46150
|
const sizeRecommendationRecord = reactExports.useMemo(() => {
|
|
45606
46151
|
const {
|
|
45607
46152
|
currentProduct
|
|
@@ -45625,9 +46170,9 @@ function SizeRecWidget({}) {
|
|
|
45625
46170
|
return productData.sizeFitRecommendation || null;
|
|
45626
46171
|
}, [storeProductData]);
|
|
45627
46172
|
const handleLinkClick = reactExports.useCallback(() => {
|
|
45628
|
-
openOverlay(OverlayName.
|
|
46173
|
+
openOverlay(OverlayName.QUICK_VIEW);
|
|
45629
46174
|
}, [openOverlay]);
|
|
45630
|
-
if (!sizeRecommendationRecord || !
|
|
46175
|
+
if (!sizeRecommendationRecord || !hasOpenedQuickViewOverlay) {
|
|
45631
46176
|
return null;
|
|
45632
46177
|
}
|
|
45633
46178
|
const sizeLabel = getSizeLabelFromSize(sizeRecommendationRecord.recommended_size);
|
|
@@ -45639,8 +46184,11 @@ function SizeRecWidget({}) {
|
|
|
45639
46184
|
} });
|
|
45640
46185
|
}
|
|
45641
46186
|
const logger = getLogger("widgets/vto-button");
|
|
45642
|
-
function VtoButtonWidget(
|
|
46187
|
+
function VtoButtonWidget(_props) {
|
|
45643
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));
|
|
45644
46192
|
const css2 = useCss((theme) => ({
|
|
45645
46193
|
button: {
|
|
45646
46194
|
marginTop: "10px",
|
|
@@ -45667,13 +46215,29 @@ function VtoButtonWidget({}) {
|
|
|
45667
46215
|
textTransform: "uppercase"
|
|
45668
46216
|
}
|
|
45669
46217
|
}));
|
|
45670
|
-
const
|
|
45671
|
-
|
|
45672
|
-
|
|
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
|
+
});
|
|
45673
46237
|
};
|
|
45674
|
-
return /* @__PURE__ */ jsxs("button", { type: "button", onClick:
|
|
46238
|
+
return /* @__PURE__ */ jsxs("button", { type: "button", onClick: handleClick, css: css2.button, children: [
|
|
45675
46239
|
/* @__PURE__ */ jsx$1(SvgTfrIcon, { css: css2.icon }),
|
|
45676
|
-
/* @__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" })
|
|
45677
46241
|
] });
|
|
45678
46242
|
}
|
|
45679
46243
|
var DeviceLayout = /* @__PURE__ */ ((DeviceLayout2) => {
|
|
@@ -45738,10 +46302,6 @@ function _init$1() {
|
|
|
45738
46302
|
});
|
|
45739
46303
|
}
|
|
45740
46304
|
const WIDGETS = {
|
|
45741
|
-
[
|
|
45742
|
-
"add-to-fitting-room"
|
|
45743
|
-
/* ADD_TO_FITTING_ROOM */
|
|
45744
|
-
]: AddToFittingRoomWidget,
|
|
45745
46305
|
[
|
|
45746
46306
|
"add-to-fitting-room-compact"
|
|
45747
46307
|
/* ADD_TO_FITTING_ROOM_COMPACT */
|
|
@@ -45769,7 +46329,7 @@ var OverlayName = /* @__PURE__ */ ((OverlayName2) => {
|
|
|
45769
46329
|
OverlayName2["GET_APP"] = "get-app";
|
|
45770
46330
|
OverlayName2["LANDING"] = "landing";
|
|
45771
46331
|
OverlayName2["SIGN_IN"] = "sign-in";
|
|
45772
|
-
OverlayName2["
|
|
46332
|
+
OverlayName2["QUICK_VIEW"] = "quick-view";
|
|
45773
46333
|
return OverlayName2;
|
|
45774
46334
|
})(OverlayName || {});
|
|
45775
46335
|
const OVERLAYS = {
|
|
@@ -45794,9 +46354,9 @@ const OVERLAYS = {
|
|
|
45794
46354
|
/* SIGN_IN */
|
|
45795
46355
|
]: SignInOverlay,
|
|
45796
46356
|
[
|
|
45797
|
-
"
|
|
45798
|
-
/*
|
|
45799
|
-
]:
|
|
46357
|
+
"quick-view"
|
|
46358
|
+
/* QUICK_VIEW */
|
|
46359
|
+
]: QuickViewOverlay
|
|
45800
46360
|
};
|
|
45801
46361
|
let staticData = null;
|
|
45802
46362
|
function _init(initStaticData) {
|
|
@@ -45941,9 +46501,9 @@ const SHARED_CONFIG = {
|
|
|
45941
46501
|
appGooglePlayUrl: "https://play.google.com/store/apps/details?id=com.thefittingroom.marketplace"
|
|
45942
46502
|
},
|
|
45943
46503
|
build: {
|
|
45944
|
-
version: `${"5.0.
|
|
45945
|
-
commitHash: `${"
|
|
45946
|
-
date: `${"2026-05-
|
|
46504
|
+
version: `${"5.0.24"}`,
|
|
46505
|
+
commitHash: `${"931e0b2"}`,
|
|
46506
|
+
date: `${"2026-05-19T21:17:10.057Z"}`
|
|
45947
46507
|
}
|
|
45948
46508
|
};
|
|
45949
46509
|
const CONFIGS = {
|
|
@@ -46067,7 +46627,7 @@ const CONFIGS = {
|
|
|
46067
46627
|
const getConfig = (envName) => {
|
|
46068
46628
|
return CONFIGS[envName];
|
|
46069
46629
|
};
|
|
46070
|
-
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";
|
|
46071
46631
|
class TfrWidgetElement extends HTMLElement {
|
|
46072
46632
|
connectedCallback() {
|
|
46073
46633
|
const attributes = this.getAttributeNames().reduce((attrs, name2) => {
|