UNPKG

@shopify/hydrogen-react

Version:

React components, hooks, and utilities for creating custom Shopify storefronts

147 lines (146 loc) 4.96 kB
import { useEffect, useState, useRef } from "react"; import { stringify } from "worktop/cookie"; import { SHOPIFY_Y, SHOPIFY_S } from "./cart-constants.mjs"; import { buildUUID } from "./cookies-utils.mjs"; import { getTrackingValues, SHOPIFY_UNIQUE_TOKEN_HEADER, SHOPIFY_VISIT_TOKEN_HEADER } from "./tracking-utils.mjs"; 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 }); 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 = getTrackingValues(); if ((trackingValues.uniqueToken || trackingValues.visitToken || "").startsWith("00000000-")) { return; } setCookie( SHOPIFY_Y, trackingValues.uniqueToken || buildUUID(), longTermLength, domainWithLeadingDot ); setCookie( SHOPIFY_S, trackingValues.visitToken || buildUUID(), shortTermLength, domainWithLeadingDot ); } else { setCookie(SHOPIFY_Y, "", 0, domainWithLeadingDot); setCookie(SHOPIFY_S, "", 0, domainWithLeadingDot); } }, [ coreCookiesReady, hasUserConsent, domain, checkoutDomain, ignoreDeprecatedCookies ]); return coreCookiesReady; } function setCookie(name, value, maxage, domain) { document.cookie = stringify(name, value, { maxage, domain, samesite: "Lax", path: "/" }); } async function fetchTrackingValuesFromBrowser(storefrontAccessToken, storefrontApiDomain = "") { const { uniqueToken, visitToken } = 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 ? { [SHOPIFY_VISIT_TOKEN_HEADER]: visitToken, [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(); getTrackingValues(); } function useCoreShopifyCookies({ checkoutDomain, storefrontAccessToken, fetchTrackingValues = false }) { const [cookiesReady, setCookiesReady] = useState(!fetchTrackingValues); const hasFetchedTrackingValues = useRef(false); 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; } export { useShopifyCookies }; //# sourceMappingURL=useShopifyCookies.mjs.map