Terms & Conditions
something for everyone
Related Products
Copyright 2025. All Rights Reserved by The John Muir Country Store. Site by
Fifth House
Choosing a selection results in a full page refresh.
ow._EcomSendNamespace._loadedMobx = loadedMobx;
window.mobx = existingMobx;
}
// Complete namespace initialization
window.EcomSend = window.EcomSend || {};
window.EcomSend.mobx = mobxToUse;
// Initialize namespace
window.initializeEcomSendNamespace(
window.EcomSend.React,
window.EcomSend.ReactDOM,
window.EcomSend.mobx
);
resolve();
};
mobxScript.onerror = () => {
if (isResolved) return;
isResolved = true;
window.EcomSend.appStatus.mobx_status = 'failed';
reject(new Error('Failed to load MobX'));
};
document.head.appendChild(mobxScript);
// Fallback check: if onload doesn't trigger but mobx is available
setTimeout(() => {
// If already resolved in 500ms, no need to start interval
if (isResolved) return;
let checkCount = 0;
const maxChecks = 10
; // Check for 10 seconds
const checkInterval = setInterval(() => {
checkCount++;
if (isResolved) {
// Already resolved, stop checking
clearInterval(checkInterval);
return;
}
if (window.mobx) {
// MobX exists but onload didn't trigger
isResolved = true;
clearInterval(checkInterval);
const mobxToUse = window.mobx;
window.EcomSend = window.EcomSend || {};
window.EcomSend.mobx = mobxToUse;
window.EcomSend.appStatus.mobx_status = 'loaded';
// Initialize namespace
window.initializeEcomSendNamespace(
window.EcomSend.React,
window.EcomSend.ReactDOM,
window.EcomSend.mobx
);
resolve();
return;
}
if (checkCount >= maxChecks) {
/
Opens in a new window.
function loadReactDependencies() {
return new Promise((resolve, reject) => {
// Check if React is already loaded by other apps
const existingReact = window.React;
const existingReactDOM = window.ReactDOM;
// If React already exists, use it and initialize namespace
if (existingReact && existingReactDOM) {
window.EcomSend = window.EcomSend || {};
window.EcomSend.React = existingReact;
window.EcomSend.ReactDOM = existingReactDOM;
window.EcomSend.appStatus.react_status = 'loaded';
window.EcomSend.appStatus.reactdom_status = 'loaded';
resolve();
return;
}
window.EcomSend.appStatus.react_status = 'loading';
window.EcomSend.appStatus.reactdom_status = 'loading';
let isResolved = false;
const reactScript = document.createElement('script');
reactScript.async = false;
reactScript.src = 'https://cdn.shopify.com/extensions/019ab39b-6f76-721d-9144-1a729619dbae/ecomsend-99/assets/react_react-dom.min.js';
reactScript.onload = () => {
if (isResolved) return;
isResolved = true;
window.EcomSend.appStatus.react_status = 'loaded';
window.EcomSend.appStatus.reactdom_status = 'loaded';
// Save the newly loaded React to namespace
window.EcomSend = window.EcomSend || {};
window.EcomSend.React = window.React;
window.EcomSend.ReactDOM = window.ReactDOM;
// If React existed before (might be added by other scripts during loading)
// Save our loaded version, then restore the previous version
if (existingReact && window.React !== existingReact) {
window._EcomSendNamespace._loadedReact = window.React;
window._EcomSendNamespace._loadedReactDOM = window.ReactDOM;
// Use our loaded version as EcomSend's version
window.EcomSend.React = window._EcomSendNamespace._loadedReact;
window.EcomSend.ReactDOM = window._EcomSendNamespace._loadedReactDOM;
// Restore global variables
window.React = existingReact;
window.ReactDOM = existingReactDOM;
}
resolve();
};
reactScript.onerror = () => {
if (isResolved) return;
isResolved = true;
window.EcomSend.appStatus.react_status = 'failed';
window.EcomSend.appStatus.reactdom_status = 'failed';
reject(new Error('Failed to load React'));
};
document.head.appendChild(reactScript);
// Fallback check: if onload doesn't trigger but React is available
setTimeout(() => {
// If already resolved in 500ms, no need to start interval
if (isResolved) return;
let checkCount = 0;
const maxChecks = 10; // Check for 10 seconds
const checkInterval = setInterval(() => {
checkCount++;
if (isResolved) {
// Already resolved, stop checking
clearInterval(checkInterval);
return;
}
if (window.React && window.ReactDOM) {
// React exists but onload didn't trigger
isResolved = true;
clearInterval(checkInterval);
window.EcomSend = window.EcomSend || {};
window.EcomSend.React = window.React;
window.EcomSend.ReactDOM = window.ReactDOM;
window.EcomSend.appStatus.react_status = 'loaded';
window.EcomSend.appStatus.reactdom_status = 'loaded';
resolve();
return;
}
if (checkCount >= maxChecks) {
// Stop checking after max attempts
clearInterval(checkInterval);
return;
}
}, 1000);
}, 500);
});
}
function loadMobxDependencies() {
return new Promise(
(resolve, reject) => {
// Check if MobX is already loaded by other apps
const existingMobx = window.mobx;
window.EcomSend.appStatus.mobx_status = 'loading';
let isResolved = false;
const mobxScript = document.createElement('script');
mobxScript.async = false;
mobxScript.src = 'https://cdn.shopify.com/extensions/019ab39b-6f76-721d-9144-1a729619dbae/ecomsend-99/assets/mobx_react-custom-roulette.min.js';
mobxScript.onload = () => {
if (isResolved) return;
isResolved = true;
window.EcomSend.appStatus.mobx_status = 'loaded';
// Save the newly loaded MobX (if exists)
const loadedMobx = window.mobx;
// Decide which MobX to use
const mobxToUse = loadedMobx || existingMobx;
// If MobX existed before, restore the original global variable (to avoid affecting other apps)
if (existingMobx && loadedMobx && loadedMobx !== existingMobx) {
wind
function createEcomSendMainStyleEle() {
const ele = document.createElement("link");
ele.rel = "stylesheet";
ele.href = 'https://cdn.shopify.com/extensions/019ab39b-6f76-721d-9144-1a729619dbae/ecomsend-99/assets/style.css';
ele.dataset.ecomsendTag = "load-alternate-css";
return ele;
};
if (window.EcomSendApps?.enableAlternateCSSLoading ?? false) {
document.head.appendChild(createEcomSendMainStyleEle());
};
try {
function checkMarketingEvent() {
const urlParams = new URLSearchParams(window.location.search)
const marketingId = urlParams.get("es_marketingId")
if (marketingId && window.localStorage) {
window.localStorage.setItem("ecomsend_marketingId", marketingId)
}
}
checkMarketingEvent()
} catch (e) {}
let isEcomSendInitialized = false;
function createEcomSendMainJSEle() {
if (isEcomSendInitialized) return;
// Check if dependencies in EcomSend namespace are loaded
if (!window.EcomSend || !window.EcomSend.React || !window.EcomSend.ReactDOM || !window.EcomSend.mobx || !window.EcomSend.React.useContext) {
if (!window.React || !window.ReactDOM || !window.mobx || !window.React.useContext) {
return false;
}
}
const ele = document.createElement("script");
ele.defer = true;
ele.id = "ecomsend-main-js";
ele.src = 'https://cdn.shopify.com/extensions/019ab39b-6f76-721d-9144-1a729619dbae/ecomsend-99/assets/ecomsend.js';
window.EcomSend.appStatus.main_script_status = 'loading';
// Script onload handler
ele.onload = function() {
// Script loaded successfully
window.EcomSend.appStatus.main_script_status = 'loaded';
};
ele.onerror = function() {
// Script failed to load
window.EcomSend.appStatus.main_script_status = 'failed';
};
if (null === document.getElementById(ele.id)) {
document.head.appendChild(ele);
isEcomSendInitialized = true;
return true;
}
return false;
};
function EcomsendOnMobxLoaded() {
// Load main script in EcomSend namespace context
setTimeout(() => {
// Try to use namespace context
if (window.withEcomSendContext) {
window.withEcomSendContext(() => {
createEcomSendMainJSEle();
});
} else {
// Fallback to direct loading
createEcomSendMainJSEle();
}
}, 100);
};
let checkCount = 0;
const maxChecks = 20;
function EcomsendBackupCheck() {
if (isEcomSendInitialized) return;
checkCount++;
// First check dependencies in namespace
if (window.EcomSend &&
window.EcomSend.React &&
window.EcomSend.ReactDOM &&
window.EcomSend.mobx &&
window.EcomSend.React.useContext &&
window.EcomSend.React.createElement) {
// Use namespace context
if (window.withEcomSendContext) {
window.withEcomSendContext(()
=> {
if (createEcomSendMainJSEle()) {
return;
}
});
}
}
// Fallback to checking global dependencies
else if (window.React &&
window.ReactDOM &&
window.mobx &&
window.React.useContext &&
window.React.createElement &&
window.ReactDOM.createRoot) {
if (createEcomSendMainJSEle()) {
return;
}
}
if (checkCount £0.00 <
/**
* EcomSend Namespace Encapsulation
* This script encapsulates React and MobX dependencies within the EcomSend namespace
* to prevent conflicts with other applications' dependencies.
*/
// Save original global variables (if they exist)
window._EcomSendNamespace = {
_originalReact: window.React,
_originalReactDOM: window.ReactDOM,
_originalMobx: window.mobx,
}
// Create EcomSend namespace
window.EcomSend = window.EcomSend || {}
// Initialize app status tracker
window.EcomSend.appStatus = {
react_status: 'pending',
reactdom_status: 'pending',
mobx_status: 'pending',
main_script_status: 'pending',
initialization_status: 'pending',
// Helper method to get overall status
getOverallStatus: function() {
const statuses = [
this.react_status,
this.reactdom_status,
this.mobx_status,
this.main_script_status
];
if (statuses.includes('failed')) {
return 'failed';
}
if (statuses.includes('loading')) {
return 'loading';
}
if (statuses.every(s => s === 'loaded') && this.main_script_status === 'loaded') {
return 'ready';
}
if (statuses.includes('loaded')) {
return 'loading';
}
return 'pending';
}
}
// Define initialization method
window.initializeEcomSendNamespace = function(React, ReactDOM, mobx) {
// Save dependencies to EcomSend namespace
window.EcomSend.React = React
window.EcomSend.ReactDOM = ReactDOM
window.EcomSend.mobx = mobx
// Trigger ready event
const event = new CustomEvent("EcomSendNamespaceReady")
window.dispatchEvent(event)
return {
React: React,
ReactDOM: ReactDOM,
mobx: mobx,
}
}
// Provide context switching method
window.withEcomSendContext = function(callback) {
// Save current global variables
const originalReact = window.React
const originalReactDOM = window.ReactDOM
const originalMobx = window.mobx
// Set EcomSend's version to global
window.React = window.EcomSend.React
window.ReactDOM = window.EcomSend.ReactDOM
window.mobx = window.EcomSend.mobx
try {
// Execute callback in EcomSend context
return callback()
} finally {
// Restore original global variables
window.React = originalReact
window.ReactDOM = originalReactDOM
window.mobx = originalMobx
}
}
// Add method to restore original global variables
window.restoreOriginalGlobals = function() {
window.React = window._EcomSendNamespace._originalReact
window.ReactDOM = window._EcomSendNamespace._originalReactDOM
window.mobx = window._EcomSendNamespace._originalMobx
}
// If use
have the URL discount code: willDiscountCode=**, update the cart data for use discount code
try {
const urlParams = new URLSearchParams(window.location.search)
const willDiscountCode = urlParams.get("willDiscountCode")
if (willDiscountCode) {
fetch("/cart/update.js", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
discount: willDiscountCode,
}),
})
}
} catch (error) {
// Error handling for discount code update
}