From c3e2b4de814b74be2d121b6b07521e3feb284180 Mon Sep 17 00:00:00 2001 From: Helen Lin Date: Mon, 17 Jun 2024 16:34:28 -0700 Subject: [PATCH 1/5] auto cookie domain detect and update error message --- .../src/analytics-manager/CartAnalytics.tsx | 2 +- .../analytics-manager/ShopifyAnalytics.tsx | 63 +++++++++---------- .../ShopifyCustomerPrivacy.tsx | 40 +++++++++--- 3 files changed, 60 insertions(+), 45 deletions(-) diff --git a/packages/hydrogen/src/analytics-manager/CartAnalytics.tsx b/packages/hydrogen/src/analytics-manager/CartAnalytics.tsx index 6e713f5bb5..fad620b48f 100644 --- a/packages/hydrogen/src/analytics-manager/CartAnalytics.tsx +++ b/packages/hydrogen/src/analytics-manager/CartAnalytics.tsx @@ -10,7 +10,7 @@ import {flattenConnection} from '@shopify/hydrogen-react'; function logMissingField(fieldName: string) { // eslint-disable-next-line no-console console.error( - `[h2:error:CartAnalytics] Can't set up cart analytics events because the \`cart.${fieldName}\` value is missing from your GraphQL cart query. In standard Hydrogen projects, the cart query is contained in \`app/lib/fragments.js\`. Make sure it includes \`cart.${fieldName}\`. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/lib/fragments.ts#L59.`, + `[h2:error:CartAnalytics] Can't set up cart analytics events because the \`cart.${fieldName}\` value is missing from your GraphQL cart query. In your project, search for where \`fragment CartApiQuery on Cart\` is defined and make sure \`${fieldName}\` is part of your cart query. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/lib/fragments.ts#L59.`, ); } diff --git a/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx b/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx index 86298d5f20..d7b363b2c6 100644 --- a/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx +++ b/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx @@ -208,10 +208,7 @@ function productViewHandler(payload: ProductViewPayload) { if ( eventPayload && validateProducts({ - eventName: PRODUCT_VIEWED, - productField: 'products', - variantField: 'product.', - fromSource: 'product_viewed products array', + type: 'product', products: payload.products, }) ) { @@ -318,10 +315,7 @@ function sendCartAnalytics({ }; if ( validateProducts({ - eventName: ADD_TO_CART, - productField: 'merchandise.product', - variantField: 'merchandise', - fromSource: 'cart query', + type: 'cart', products: [product], }) ) { @@ -335,17 +329,23 @@ function sendCartAnalytics({ } } -const PRODUCT_VIEWED = 'Product viewed'; -const ADD_TO_CART = 'Add to cart'; function missingErrorMessage( - eventName: string, - missingFieldName: string, - fromSource: string, + type: 'cart' | 'product', + fieldName: string, + isVariantField: boolean, + viewKeyName?: string, ) { - // eslint-disable-next-line no-console - console.error( - `[h2:error:ShopifyAnalytics] ${eventName}: ${missingFieldName} is required from the ${fromSource}.`, - ); + if(type === 'cart') { + // eslint-disable-next-line no-console + console.error( + `[h2:error:ShopifyAnalytics] Can't set up cart analytics events because the \`cart.lines[].${isVariantField ? 'merchandise' : 'merchandise.product'}.${fieldName}\` value is missing from your GraphQL cart query. In your project, search for where \`fragment CartLine on CartLine\` is defined and make sure \`${isVariantField ? 'merchandise' : 'merchandise.product'}.${fieldName}\` is part of your cart query. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/lib/fragments.ts#L25-L56.`, + ); + } else { + // eslint-disable-next-line no-console + console.error( + `[h2:error:ShopifyAnalytics] Can't set up product view analytics events because the \`${viewKeyName || fieldName}\` is missing from your \`\`. Make sure \`${viewKeyName || fieldName}\` is part of your products data prop. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/routes/products.%24handle.tsx#L159-L165.`, + ); + } } // Product expected field and types: @@ -360,50 +360,45 @@ function missingErrorMessage( // category: string, optional // quantity: float function validateProducts({ - eventName, - productField, - variantField, + type, products, - fromSource, }: { - eventName: string; - productField: string; - variantField: string; - fromSource: string; + type: 'cart' | 'product'; products: Array>; }) { if (!products || products.length === 0) { - missingErrorMessage(eventName, `${productField}`, fromSource); + missingErrorMessage(type, '', false, 'data.products'); return false; } products.forEach((product) => { if (!product.id) { - missingErrorMessage(eventName, `${productField}.id`, fromSource); + missingErrorMessage(type, 'id', false); return false; } if (!product.title) { - missingErrorMessage(eventName, `${productField}.title`, fromSource); + missingErrorMessage(type, 'title', false); return false; } if (!product.price) { missingErrorMessage( - eventName, - `${variantField}.price.amount`, - fromSource, + type, + 'price.amount', + true, + 'price', ); return false; } if (!product.vendor) { - missingErrorMessage(eventName, `${productField}.vendor`, fromSource); + missingErrorMessage(type, 'vendor', false); return false; } if (!product.variantId) { - missingErrorMessage(eventName, `${variantField}.id`, fromSource); + missingErrorMessage(type, 'id', true, 'variantId'); return false; } if (!product.variantTitle) { - missingErrorMessage(eventName, `${variantField}.title`, fromSource); + missingErrorMessage(type, 'title', true, 'variantTitle'); return false; } }); diff --git a/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx b/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx index a396f2e93e..640ad7111b 100644 --- a/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx +++ b/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx @@ -143,14 +143,15 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) { if (scriptStatus !== 'done' || loadedEvent.current) return; loadedEvent.current = true; - if (!consentConfig.checkoutDomain) logMissingConfig('checkoutDomain'); - if (!consentConfig.storefrontAccessToken) + const {checkoutDomain, storefrontAccessToken} = consentConfig; + if (!checkoutDomain) logMissingConfig('checkoutDomain'); + if (!storefrontAccessToken) logMissingConfig('storefrontAccessToken'); // validate that the storefront access token is not a server API token if ( - consentConfig.storefrontAccessToken.startsWith('shpat_') || - consentConfig.storefrontAccessToken.length !== 32 + storefrontAccessToken.startsWith('shpat_') || + storefrontAccessToken.length !== 32 ) { // eslint-disable-next-line no-console console.error( @@ -158,11 +159,31 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) { ); } - if (withPrivacyBanner && window?.privacyBanner) { - window?.privacyBanner?.loadBanner({ - checkoutRootDomain: consentConfig.checkoutDomain, - storefrontAccessToken: consentConfig.storefrontAccessToken, + const config: CustomerPrivacyConsentConfig = { + checkoutRootDomain: checkoutDomain, + storefrontAccessToken, + } + + if (checkoutDomain) { + let storefrontRootDomain = window.document.location.host; + const checkoutDomainParts = checkoutDomain.split('.').reverse(); + const currentDomainParts = storefrontRootDomain.split('.').reverse(); + const sameDomainParts: Array = []; + checkoutDomainParts.forEach((part, index) => { + if (part === currentDomainParts[index]) { + sameDomainParts.push(part); + } }); + + storefrontRootDomain = sameDomainParts.reverse().join('.'); + + if (storefrontRootDomain) { + config.storefrontRootDomain = storefrontRootDomain; + } + } + + if (withPrivacyBanner && window?.privacyBanner) { + window?.privacyBanner?.loadBanner(config); } if (!window.Shopify?.customerPrivacy) return; @@ -179,8 +200,7 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) { { ...consent, headlessStorefront: true, - checkoutRootDomain: consentConfig.checkoutDomain, - storefrontAccessToken: consentConfig.storefrontAccessToken, + ...config, }, callback, ); From 7fff7861d7a3f6d0878f6b21ea2b190adee26d23 Mon Sep 17 00:00:00 2001 From: Helen Lin Date: Mon, 17 Jun 2024 16:48:04 -0700 Subject: [PATCH 2/5] changeset and format --- .changeset/stupid-falcons-wash.md | 5 +++++ .../analytics-manager/ShopifyAnalytics.tsx | 21 +++++++++++-------- .../ShopifyCustomerPrivacy.tsx | 5 ++--- 3 files changed, 19 insertions(+), 12 deletions(-) create mode 100644 .changeset/stupid-falcons-wash.md diff --git a/.changeset/stupid-falcons-wash.md b/.changeset/stupid-falcons-wash.md new file mode 100644 index 0000000000..2b94d123e8 --- /dev/null +++ b/.changeset/stupid-falcons-wash.md @@ -0,0 +1,5 @@ +--- +'@shopify/hydrogen': patch +--- + +Auto cookie domain detection for customer privacy api and better error message for missing analytic fields diff --git a/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx b/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx index d7b363b2c6..f67572a20f 100644 --- a/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx +++ b/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx @@ -335,15 +335,23 @@ function missingErrorMessage( isVariantField: boolean, viewKeyName?: string, ) { - if(type === 'cart') { + if (type === 'cart') { // eslint-disable-next-line no-console console.error( - `[h2:error:ShopifyAnalytics] Can't set up cart analytics events because the \`cart.lines[].${isVariantField ? 'merchandise' : 'merchandise.product'}.${fieldName}\` value is missing from your GraphQL cart query. In your project, search for where \`fragment CartLine on CartLine\` is defined and make sure \`${isVariantField ? 'merchandise' : 'merchandise.product'}.${fieldName}\` is part of your cart query. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/lib/fragments.ts#L25-L56.`, + `[h2:error:ShopifyAnalytics] Can't set up cart analytics events because the \`cart.lines[].${ + isVariantField ? 'merchandise' : 'merchandise.product' + }.${fieldName}\` value is missing from your GraphQL cart query. In your project, search for where \`fragment CartLine on CartLine\` is defined and make sure \`${ + isVariantField ? 'merchandise' : 'merchandise.product' + }.${fieldName}\` is part of your cart query. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/lib/fragments.ts#L25-L56.`, ); } else { // eslint-disable-next-line no-console console.error( - `[h2:error:ShopifyAnalytics] Can't set up product view analytics events because the \`${viewKeyName || fieldName}\` is missing from your \`\`. Make sure \`${viewKeyName || fieldName}\` is part of your products data prop. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/routes/products.%24handle.tsx#L159-L165.`, + `[h2:error:ShopifyAnalytics] Can't set up product view analytics events because the \`${ + viewKeyName || fieldName + }\` is missing from your \`\`. Make sure \`${ + viewKeyName || fieldName + }\` is part of your products data prop. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/routes/products.%24handle.tsx#L159-L165.`, ); } } @@ -381,12 +389,7 @@ function validateProducts({ return false; } if (!product.price) { - missingErrorMessage( - type, - 'price.amount', - true, - 'price', - ); + missingErrorMessage(type, 'price.amount', true, 'price'); return false; } if (!product.vendor) { diff --git a/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx b/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx index 640ad7111b..7bd5abf040 100644 --- a/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx +++ b/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx @@ -145,8 +145,7 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) { const {checkoutDomain, storefrontAccessToken} = consentConfig; if (!checkoutDomain) logMissingConfig('checkoutDomain'); - if (!storefrontAccessToken) - logMissingConfig('storefrontAccessToken'); + if (!storefrontAccessToken) logMissingConfig('storefrontAccessToken'); // validate that the storefront access token is not a server API token if ( @@ -162,7 +161,7 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) { const config: CustomerPrivacyConsentConfig = { checkoutRootDomain: checkoutDomain, storefrontAccessToken, - } + }; if (checkoutDomain) { let storefrontRootDomain = window.document.location.host; From 59e39ad6c314132e1772cd12212c788d716bbb3f Mon Sep 17 00:00:00 2001 From: Helen Lin Date: Mon, 17 Jun 2024 16:58:17 -0700 Subject: [PATCH 3/5] clean up --- .../src/analytics-manager/ShopifyAnalytics.tsx | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx b/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx index f67572a20f..62cf59e1eb 100644 --- a/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx +++ b/packages/hydrogen/src/analytics-manager/ShopifyAnalytics.tsx @@ -336,22 +336,18 @@ function missingErrorMessage( viewKeyName?: string, ) { if (type === 'cart') { + const name = `${ + isVariantField ? 'merchandise' : 'merchandise.product' + }.${fieldName}`; // eslint-disable-next-line no-console console.error( - `[h2:error:ShopifyAnalytics] Can't set up cart analytics events because the \`cart.lines[].${ - isVariantField ? 'merchandise' : 'merchandise.product' - }.${fieldName}\` value is missing from your GraphQL cart query. In your project, search for where \`fragment CartLine on CartLine\` is defined and make sure \`${ - isVariantField ? 'merchandise' : 'merchandise.product' - }.${fieldName}\` is part of your cart query. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/lib/fragments.ts#L25-L56.`, + `[h2:error:ShopifyAnalytics] Can't set up cart analytics events because the \`cart.lines[].${name}\` value is missing from your GraphQL cart query. In your project, search for where \`fragment CartLine on CartLine\` is defined and make sure \`${name}\` is part of your cart query. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/lib/fragments.ts#L25-L56.`, ); } else { + const name = `${viewKeyName || fieldName}`; // eslint-disable-next-line no-console console.error( - `[h2:error:ShopifyAnalytics] Can't set up product view analytics events because the \`${ - viewKeyName || fieldName - }\` is missing from your \`\`. Make sure \`${ - viewKeyName || fieldName - }\` is part of your products data prop. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/routes/products.%24handle.tsx#L159-L165.`, + `[h2:error:ShopifyAnalytics] Can't set up product view analytics events because the \`${name}\` is missing from your \`\`. Make sure \`${name}\` is part of your products data prop. Check the Hydrogen Skeleton template for reference: https://github.com/Shopify/hydrogen/blob/main/templates/skeleton/app/routes/products.%24handle.tsx#L159-L165.`, ); } } From b23b40d8ebe2c6ea2c386bdd9e55d217b3a63caf Mon Sep 17 00:00:00 2001 From: Helen Lin Date: Tue, 18 Jun 2024 08:53:26 -0700 Subject: [PATCH 4/5] Update .changeset/stupid-falcons-wash.md Co-authored-by: Bret Little --- .changeset/stupid-falcons-wash.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/stupid-falcons-wash.md b/.changeset/stupid-falcons-wash.md index 2b94d123e8..d4410c5a55 100644 --- a/.changeset/stupid-falcons-wash.md +++ b/.changeset/stupid-falcons-wash.md @@ -2,4 +2,4 @@ '@shopify/hydrogen': patch --- -Auto cookie domain detection for customer privacy api and better error message for missing analytic fields +Auto cookie domain detection for customer privacy api and better error message for missing analytics fields From e620e1fa798cfb333aa819faf26492288eeccf2a Mon Sep 17 00:00:00 2001 From: Helen Lin Date: Tue, 18 Jun 2024 08:55:00 -0700 Subject: [PATCH 5/5] remove unneeded ternary --- .../hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx b/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx index 7bd5abf040..88ab65cb1c 100644 --- a/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx +++ b/packages/hydrogen/src/customer-privacy/ShopifyCustomerPrivacy.tsx @@ -182,7 +182,7 @@ export function useCustomerPrivacy(props: CustomerPrivacyApiProps) { } if (withPrivacyBanner && window?.privacyBanner) { - window?.privacyBanner?.loadBanner(config); + window.privacyBanner?.loadBanner(config); } if (!window.Shopify?.customerPrivacy) return;