@shopify/hydrogen-react
Version:
React components, hooks, and utilities for creating custom Shopify storefronts
147 lines (146 loc) • 5.16 kB
JavaScript
;
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const React = require("react");
const cookie = require("worktop/cookie");
const cartConstants = require("./cart-constants.js");
const cookiesUtils = require("./cookies-utils.js");
const trackingUtils = require("./tracking-utils.js");
const longTermLength = 60 * 60 * 24 * 360 * 1;
const shortTermLength = 60 * 30;
function useShopifyCookies(options) {
const {
hasUserConsent,
domain = "",
checkoutDomain = "",
storefrontAccessToken,
fetchTrackingValues,
ignoreDeprecatedCookies = false
} = options || {};
const coreCookiesReady = useCoreShopifyCookies({
storefrontAccessToken,
fetchTrackingValues,
checkoutDomain
});
React.useEffect(() => {
if (ignoreDeprecatedCookies || !coreCookiesReady) return;
let currentDomain = domain || window.location.host;
if (checkoutDomain) {
const checkoutDomainParts = checkoutDomain.split(".").reverse();
const currentDomainParts = currentDomain.split(".").reverse();
const sameDomainParts = [];
checkoutDomainParts.forEach((part, index) => {
if (part === currentDomainParts[index]) {
sameDomainParts.push(part);
}
});
currentDomain = sameDomainParts.reverse().join(".");
}
if (/^localhost/.test(currentDomain)) currentDomain = "";
const domainWithLeadingDot = currentDomain ? /^\./.test(currentDomain) ? currentDomain : `.${currentDomain}` : "";
if (hasUserConsent) {
const trackingValues = trackingUtils.getTrackingValues();
if ((trackingValues.uniqueToken || trackingValues.visitToken || "").startsWith("00000000-")) {
return;
}
setCookie(
cartConstants.SHOPIFY_Y,
trackingValues.uniqueToken || cookiesUtils.buildUUID(),
longTermLength,
domainWithLeadingDot
);
setCookie(
cartConstants.SHOPIFY_S,
trackingValues.visitToken || cookiesUtils.buildUUID(),
shortTermLength,
domainWithLeadingDot
);
} else {
setCookie(cartConstants.SHOPIFY_Y, "", 0, domainWithLeadingDot);
setCookie(cartConstants.SHOPIFY_S, "", 0, domainWithLeadingDot);
}
}, [
coreCookiesReady,
hasUserConsent,
domain,
checkoutDomain,
ignoreDeprecatedCookies
]);
return coreCookiesReady;
}
function setCookie(name, value, maxage, domain) {
document.cookie = cookie.stringify(name, value, {
maxage,
domain,
samesite: "Lax",
path: "/"
});
}
async function fetchTrackingValuesFromBrowser(storefrontAccessToken, storefrontApiDomain = "") {
const { uniqueToken, visitToken } = trackingUtils.getTrackingValues();
const response = await fetch(
// TODO: update this endpoint when it becomes stable
`${storefrontApiDomain.replace(/\/+$/, "")}/api/unstable/graphql.json`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
...storefrontAccessToken && {
"X-Shopify-Storefront-Access-Token": storefrontAccessToken
},
...visitToken || uniqueToken ? {
[trackingUtils.SHOPIFY_VISIT_TOKEN_HEADER]: visitToken,
[trackingUtils.SHOPIFY_UNIQUE_TOKEN_HEADER]: uniqueToken
} : void 0
},
body: JSON.stringify({
query: (
// This query ensures we get _cmp (consent) server-timing header, which is not available in other queries.
// This value can be passed later to consent-tracking-api and privacy-banner scripts to avoid extra requests.
"query ensureCookies { consentManagement { cookies(visitorConsent:{}) { cookieDomain } } }"
)
})
}
);
if (!response.ok) {
throw new Error(
`Failed to fetch consent from browser: ${response.status} ${response.statusText}`
);
}
await response.json();
trackingUtils.getTrackingValues();
}
function useCoreShopifyCookies({
checkoutDomain,
storefrontAccessToken,
fetchTrackingValues = false
}) {
const [cookiesReady, setCookiesReady] = React.useState(!fetchTrackingValues);
const hasFetchedTrackingValues = React.useRef(false);
React.useEffect(() => {
if (!fetchTrackingValues) {
setCookiesReady(true);
return;
}
if (hasFetchedTrackingValues.current) return;
hasFetchedTrackingValues.current = true;
fetchTrackingValuesFromBrowser(storefrontAccessToken).catch(
(error) => checkoutDomain ? (
// Retry with checkout domain if available to at least
// get the server-timing values for tracking.
fetchTrackingValuesFromBrowser(
storefrontAccessToken,
checkoutDomain
)
) : Promise.reject(error)
).catch((error) => {
console.warn(
"[h2:warn:useShopifyCookies] Failed to fetch tracking values from browser: " + (error instanceof Error ? error.message : String(error))
);
}).finally(() => {
setCookiesReady(true);
});
}, [checkoutDomain, fetchTrackingValues, storefrontAccessToken]);
return cookiesReady;
}
exports.useShopifyCookies = useShopifyCookies;
//# sourceMappingURL=useShopifyCookies.js.map