@graphcommerce/google-datalayer 8.0.5-canary.0 → 8.0.5-canary.1

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.
Files changed (71) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/Config.graphqls +5 -13
  3. package/README.md +2 -3
  4. package/api/sendEvent.ts +50 -0
  5. package/components/DatalayerViewItemList.tsx +45 -0
  6. package/index.ts +1 -0
  7. package/mapping/cartItemToDatalayerItem/CartItem_DatalayerItem.graphql +31 -0
  8. package/mapping/cartItemToDatalayerItem/cartItemToDatalayerItem.ts +27 -0
  9. package/mapping/cartItemToRemoveFromCart/CartItem_RemoveFromCart.graphql +3 -0
  10. package/mapping/cartItemToRemoveFromCart/cartToRemoveFromCart.ts +13 -0
  11. package/mapping/cartToAddPaymentInfo/Cart_AddPaymentInfo.graphql +10 -0
  12. package/mapping/cartToAddPaymentInfo/cartToAddPaymentInfo.ts +10 -0
  13. package/mapping/cartToAddShippingInfo/Cart_AddShippingInfo.graphql +12 -0
  14. package/mapping/cartToAddShippingInfo/cartToAddShippingInfo.ts +15 -0
  15. package/mapping/cartToBeginCheckout/Cart_BeginCheckout.graphql +6 -0
  16. package/mapping/cartToBeginCheckout/cartToBeginCheckout.ts +9 -0
  17. package/mapping/cartToDatalayerItems/Cart_DatalayerItems.graphql +11 -0
  18. package/mapping/cartToDatalayerItems/cartToDatalayerItems.ts +10 -0
  19. package/mapping/cartToViewCart/Cart_ViewCart.graphql +4 -0
  20. package/mapping/cartToViewCart/cartToViewCart.ts +6 -0
  21. package/mapping/datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue.ts +8 -0
  22. package/mapping/orderToPurchase/orderToPurchase.ts +17 -0
  23. package/mapping/productItemsToViewItemList/productItemsToViewItemList.ts +22 -0
  24. package/{lib/productToItem/ProductToItem.graphql → mapping/productToDatalayerItem/Product_DatalayerItem.graphql} +3 -6
  25. package/{lib/productToItem/productToItem.ts → mapping/productToDatalayerItem/productToDatalayerItem.ts} +17 -9
  26. package/mapping/productToViewItem/Product_ViewItem.graphql +3 -0
  27. package/mapping/productToViewItem/productToViewItem.ts +11 -0
  28. package/package.json +12 -11
  29. package/plugins/GoogleDatalayerAddProductsToCartForm.tsx +33 -4
  30. package/plugins/GoogleDatalayerCartStartCheckout.tsx +17 -3
  31. package/plugins/GoogleDatalayerCartStartCheckoutLinkOrButton.tsx +4 -14
  32. package/plugins/GoogleDatalayerPaymentMethodButton.tsx +6 -4
  33. package/plugins/GoogleDatalayerPaymentMethodContextProvider.tsx +4 -2
  34. package/plugins/GoogleDatalayerProductListItem.tsx +7 -8
  35. package/plugins/GoogleDatalayerProductListItemsBase.tsx +4 -4
  36. package/plugins/GoogleDatalayerRemoveItemFromCart.tsx +13 -10
  37. package/plugins/GoogleDatalayerRemoveItemFromCartFab.tsx +9 -8
  38. package/plugins/GoogleDatalayerShippingMethodForm.tsx +10 -4
  39. package/plugins/GoogleDatalayerUpdateItemQuantity.tsx +15 -32
  40. package/plugins/GoogleDatalayerViewItem.tsx +5 -13
  41. package/plugins/GoogleDatalayerWebVitals.tsx +40 -0
  42. package/components/AnalyticsItemList.tsx +0 -63
  43. package/events/add_payment_info/AddPaymentInfoFragment.graphql +0 -36
  44. package/events/add_payment_info/addPaymentInfo.ts +0 -23
  45. package/events/add_payment_info/index.ts +0 -2
  46. package/events/add_shipping_info/AddSchippingInfoFragment.graphql +0 -38
  47. package/events/add_shipping_info/addShippingInfo.ts +0 -22
  48. package/events/add_shipping_info/index.ts +0 -2
  49. package/events/add_to_cart/AddToCartFragment.graphql +0 -30
  50. package/events/add_to_cart/addToCart.ts +0 -58
  51. package/events/add_to_cart/index.ts +0 -2
  52. package/events/begin_checkout/BeginCheckoutFragment.graphql +0 -38
  53. package/events/begin_checkout/beginCheckout.ts +0 -22
  54. package/events/begin_checkout/index.ts +0 -2
  55. package/events/purchase/index.ts +0 -1
  56. package/events/purchase/purchase.ts +0 -27
  57. package/events/remove_from_cart/RemoveFromCartFragment.graphql +0 -36
  58. package/events/remove_from_cart/index.ts +0 -2
  59. package/events/remove_from_cart/removeFromCart.ts +0 -21
  60. package/events/select_item/index.ts +0 -1
  61. package/events/select_item/select_item.ts +0 -8
  62. package/events/view_cart/ViewCartFragment.graphql +0 -35
  63. package/events/view_cart/index.ts +0 -2
  64. package/events/view_cart/viewCart.ts +0 -21
  65. package/events/view_item/index.ts +0 -1
  66. package/events/view_item/view_item.ts +0 -8
  67. package/events/view_item_list/index.ts +0 -1
  68. package/events/view_item_list/view_item_list.ts +0 -8
  69. package/lib/event.ts +0 -39
  70. package/lib/index.ts +0 -2
  71. package/plugins/GoogleDatalayerAllPagesPageview.tsx +0 -37
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @graphcommerce/google-datalayer
2
2
 
3
+ ## 8.0.5-canary.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#2233](https://github.com/graphcommerce-org/graphcommerce/pull/2233) [`f120bce`](https://github.com/graphcommerce-org/graphcommerce/commit/f120bce617808d756aebb7c500aa1deb9e4cf487) - Google Datalayer, Analytics and Tagmanager improvements.
8
+
9
+ - Removed `eventFormat` as we could automatically detec the correct event format and it is now the responsibility of GTM or the GTAG to handle the event format.
10
+ - Created cartItemToGoogleDatalayerItem and productToGoogleDatalayerItem for easier modifications. ([@paales](https://github.com/paales))
11
+
12
+ - [#2233](https://github.com/graphcommerce-org/graphcommerce/pull/2233) [`cabeadc`](https://github.com/graphcommerce-org/graphcommerce/commit/cabeadce2b73ce072a2fa8b8ab1ab49907cda13b) - Added core web vitals measurements to the datalayer.
13
+ ([@paales](https://github.com/paales))
14
+
3
15
  ## 8.0.5-canary.0
4
16
 
5
17
  ## 8.0.4
package/Config.graphqls CHANGED
@@ -1,21 +1,13 @@
1
1
  extend input GraphCommerceConfig {
2
- analytics: AnalyticsConfig
2
+ dataLayer: DatalayerConfig
3
3
  }
4
4
 
5
5
  """
6
- EventFormat is an enumatation of different event formats. This decides what the format of the event data will be.
6
+ GoogleDatalayerConfig to allow enabling certain aspects of the datalayer
7
7
  """
8
- enum EventFormat {
9
- GA3
10
- GA4
11
- }
12
-
13
- """
14
- AnalyticsConfig will contain all configuration values for the analytics in GraphCommerce.
15
- """
16
- input AnalyticsConfig {
8
+ input DatalayerConfig {
17
9
  """
18
- eventFormat contains the list of fired and formatted events
10
+ Enable core web vitals tracking for GraphCommerce
19
11
  """
20
- eventFormat: [EventFormat!]
12
+ coreWebVitals: Boolean
21
13
  }
package/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  # @graphcommerce/google-datalayer
2
2
 
3
- This package contains utilities that can be used in different app analytics
4
- trackers.
3
+ Implemenation of the datalayer in GraphCommerce.
5
4
 
6
- add_payment_info add_shipping_info
5
+ See [./Config.graphqls](./Config.graphqls) for additional configuration.
@@ -0,0 +1,50 @@
1
+ export const googleEventNames = [
2
+ 'add_payment_info',
3
+ 'add_shipping_info',
4
+ 'add_to_cart',
5
+ 'add_to_wishlist',
6
+ 'begin_checkout',
7
+ 'checkout_progress',
8
+ 'earn_virtual_currency',
9
+ 'exception',
10
+ 'generate_lead',
11
+ 'join_group',
12
+ 'level_end',
13
+ 'level_start',
14
+ 'level_up',
15
+ 'login',
16
+ 'page_view',
17
+ 'post_score',
18
+ 'purchase',
19
+ 'refund',
20
+ 'remove_from_cart',
21
+ 'screen_view',
22
+ 'search',
23
+ 'select_content',
24
+ 'select_item',
25
+ 'select_promotion',
26
+ 'set_checkout_option',
27
+ 'share',
28
+ 'sign_up',
29
+ 'spend_virtual_currency',
30
+ 'tutorial_begin',
31
+ 'tutorial_complete',
32
+ 'unlock_achievement',
33
+ 'timing_complete',
34
+ 'view_cart',
35
+ 'view_item',
36
+ 'view_item_list',
37
+ 'view_promotion',
38
+ 'view_search_results',
39
+ ] as const
40
+
41
+ export type EventMapFunctionType = (
42
+ eventName: (typeof googleEventNames)[number] | (string & Record<never, never>),
43
+ eventData: {
44
+ [key: string]: unknown
45
+ },
46
+ ) => void
47
+
48
+ export const sendEvent: EventMapFunctionType = (eventName, eventData) => {
49
+ // This is a generic event handler and is plugins from google-analytics and google datalayer
50
+ }
@@ -0,0 +1,45 @@
1
+ import { ProductItemsGridProps } from '@graphcommerce/magento-product'
2
+ import { useMemoObject } from '@graphcommerce/next-ui'
3
+ import { useEventCallback } from '@mui/material'
4
+ import React, { useContext, useEffect } from 'react'
5
+ import { sendEvent } from '../api/sendEvent'
6
+ import {
7
+ productItemsToViewItemList,
8
+ viewItemListToSelectItem,
9
+ } from '../mapping/productItemsToViewItemList/productItemsToViewItemList'
10
+
11
+ const DatalayerSelectItemContext = React.createContext<((itemId: string) => void) | undefined>(
12
+ undefined,
13
+ )
14
+
15
+ export function useViewItemList() {
16
+ const context = useContext(DatalayerSelectItemContext)
17
+ if (!context) {
18
+ return (itemId: string) => {
19
+ console.log(`No DatalayerSelectItemContext provider found, trying to select item ${itemId}`)
20
+ }
21
+ }
22
+ return context
23
+ }
24
+
25
+ export function DatalayerViewItemList(
26
+ props: ProductItemsGridProps & { children: React.ReactNode },
27
+ ) {
28
+ const { title: item_list_name, items, children } = props
29
+ const item_list_id = item_list_name.toLowerCase().replace(/\s/g, '_')
30
+
31
+ const viewItemList = useMemoObject(
32
+ productItemsToViewItemList(item_list_id, item_list_name, items),
33
+ )
34
+ useEffect(() => sendEvent('view_item_list', viewItemList), [viewItemList])
35
+
36
+ const selectItem = useEventCallback((itemId: string) => {
37
+ sendEvent('select_item', viewItemListToSelectItem(viewItemList, itemId))
38
+ })
39
+
40
+ return (
41
+ <DatalayerSelectItemContext.Provider value={selectItem}>
42
+ {children}
43
+ </DatalayerSelectItemContext.Provider>
44
+ )
45
+ }
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './api/sendEvent'
@@ -0,0 +1,31 @@
1
+ fragment CartItem_DatalayerItem on CartItemInterface {
2
+ __typename
3
+ uid
4
+ product {
5
+ ...Product_DatalayerItem
6
+ }
7
+ prices {
8
+ price {
9
+ ...Money
10
+ }
11
+ price_including_tax {
12
+ ...Money
13
+ }
14
+ row_total {
15
+ ...Money
16
+ }
17
+ row_total_including_tax {
18
+ ...Money
19
+ }
20
+ total_item_discount {
21
+ ...Money
22
+ }
23
+ }
24
+ quantity
25
+ ... on ConfigurableCartItem {
26
+ configured_variant {
27
+ uid
28
+ sku
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,27 @@
1
+ import {
2
+ GoogleDatalayerItem,
3
+ productToDatalayerItem,
4
+ } from '../productToDatalayerItem/productToDatalayerItem'
5
+ import { CartItem_DatalayerItemFragment } from './CartItem_DatalayerItem.gql'
6
+
7
+ export function cartItemToDatalayerItem<P extends CartItem_DatalayerItemFragment>(
8
+ item: P,
9
+ ): GoogleDatalayerItem {
10
+ const discount = item.prices?.total_item_discount?.value
11
+ ? item.prices.total_item_discount.value / item.quantity
12
+ : 0
13
+
14
+ const price = (item?.prices?.price_including_tax?.value ?? 0) - discount
15
+
16
+ return {
17
+ ...productToDatalayerItem(item.product),
18
+ currency: item.prices?.price.currency as string,
19
+ discount,
20
+ price,
21
+ quantity: item.quantity,
22
+ item_variant:
23
+ item.__typename === 'ConfigurableCartItem'
24
+ ? item.configured_variant.sku ?? undefined
25
+ : undefined,
26
+ }
27
+ }
@@ -0,0 +1,3 @@
1
+ fragment CartItem_RemoveFromCart on CartItemInterface @inject(into: ["CartItem"]) {
2
+ ...CartItem_DatalayerItem
3
+ }
@@ -0,0 +1,13 @@
1
+ import { cartItemToDatalayerItem } from '../cartItemToDatalayerItem/cartItemToDatalayerItem'
2
+ import { datalayerItemsToCurrencyValue } from '../datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue'
3
+ import { CartItem_RemoveFromCartFragment } from './CartItem_RemoveFromCart.gql'
4
+
5
+ export const cartItemToRemoveFromCart = <C extends CartItem_RemoveFromCartFragment>(
6
+ cartItem: C,
7
+ ) => {
8
+ const items = [cartItemToDatalayerItem(cartItem)]
9
+ return {
10
+ ...datalayerItemsToCurrencyValue(items),
11
+ items,
12
+ }
13
+ }
@@ -0,0 +1,10 @@
1
+ fragment Cart_AddPaymentInfo on Cart
2
+ @inject(into: ["PaymentMethodContext", "PaymentMethodUpdated"]) {
3
+ applied_coupons {
4
+ code
5
+ }
6
+ selected_payment_method {
7
+ code
8
+ }
9
+ ...Cart_DatalayerItems
10
+ }
@@ -0,0 +1,10 @@
1
+ import { cartToDatalayerItems } from '../cartToDatalayerItems/cartToDatalayerItems'
2
+ import { Cart_AddPaymentInfoFragment } from './Cart_AddPaymentInfo.gql'
3
+
4
+ export function cartToAddPaymentInfo<C extends Cart_AddPaymentInfoFragment>(cart: C) {
5
+ return {
6
+ coupon: cart?.applied_coupons?.map((coupon) => coupon?.code).join(' '),
7
+ payment_type: cart?.selected_payment_method?.code,
8
+ ...cartToDatalayerItems(cart),
9
+ }
10
+ }
@@ -0,0 +1,12 @@
1
+ fragment Cart_AddShippingInfo on Cart @inject(into: ["ShippingMethodSelected"]) {
2
+ applied_coupons {
3
+ code
4
+ }
5
+ shipping_addresses {
6
+ selected_shipping_method {
7
+ carrier_code
8
+ method_code
9
+ }
10
+ }
11
+ ...Cart_DatalayerItems
12
+ }
@@ -0,0 +1,15 @@
1
+ import { cartToDatalayerItems } from '../cartToDatalayerItems/cartToDatalayerItems'
2
+ import { Cart_AddShippingInfoFragment } from './Cart_AddShippingInfo.gql'
3
+
4
+ export function cartToAddShippingInfo<C extends Cart_AddShippingInfoFragment>(cart: C) {
5
+ return {
6
+ coupon: cart?.applied_coupons?.map((coupon) => coupon?.code).join(' '),
7
+ shipping_tier: cart?.shipping_addresses
8
+ .map(
9
+ (address) =>
10
+ `${address?.selected_shipping_method?.carrier_code}_${address?.selected_shipping_method?.method_code}`,
11
+ )
12
+ .join(' '),
13
+ ...cartToDatalayerItems(cart),
14
+ }
15
+ }
@@ -0,0 +1,6 @@
1
+ fragment Cart_BeginCheckout on Cart @inject(into: ["CartStartCheckout"]) {
2
+ applied_coupons {
3
+ code
4
+ }
5
+ ...Cart_DatalayerItems
6
+ }
@@ -0,0 +1,9 @@
1
+ import { cartToDatalayerItems } from '../cartToDatalayerItems/cartToDatalayerItems'
2
+ import { Cart_BeginCheckoutFragment } from './Cart_BeginCheckout.gql'
3
+
4
+ export function cartToBeginCheckout<C extends Cart_BeginCheckoutFragment>(cart: C) {
5
+ return {
6
+ coupon: cart?.applied_coupons?.map((coupon) => coupon?.code).join(' '),
7
+ ...cartToDatalayerItems(cart),
8
+ }
9
+ }
@@ -0,0 +1,11 @@
1
+ fragment Cart_DatalayerItems on Cart {
2
+ __typename
3
+ items {
4
+ ...CartItem_DatalayerItem
5
+ }
6
+ prices {
7
+ subtotal_including_tax {
8
+ currency
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,10 @@
1
+ import { nonNullable } from '@graphcommerce/next-ui'
2
+ import { cartItemToDatalayerItem } from '../cartItemToDatalayerItem/cartItemToDatalayerItem'
3
+ import { datalayerItemsToCurrencyValue } from '../datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue'
4
+ import { Cart_DatalayerItemsFragment } from './Cart_DatalayerItems.gql'
5
+
6
+ export function cartToDatalayerItems<C extends Cart_DatalayerItemsFragment>(cart: C) {
7
+ const items = cart.items?.filter(nonNullable).map(cartItemToDatalayerItem)
8
+ if (!items) return {}
9
+ return { ...datalayerItemsToCurrencyValue(items), items }
10
+ }
@@ -0,0 +1,4 @@
1
+ fragment Cart_ViewCart on Cart @inject(into: ["CartItemCountChanged"]) {
2
+ __typename
3
+ ...Cart_DatalayerItems
4
+ }
@@ -0,0 +1,6 @@
1
+ import { cartToDatalayerItems } from '../cartToDatalayerItems/cartToDatalayerItems'
2
+ import { Cart_ViewCartFragment } from './Cart_ViewCart.gql'
3
+
4
+ export function cartToViewCart<C extends Cart_ViewCartFragment>(cart: C) {
5
+ return cartToDatalayerItems(cart)
6
+ }
@@ -0,0 +1,8 @@
1
+ import { GoogleDatalayerItem } from '../productToDatalayerItem/productToDatalayerItem'
2
+
3
+ export function datalayerItemsToCurrencyValue(items: GoogleDatalayerItem[]) {
4
+ return {
5
+ currency: items[0].currency,
6
+ value: items.reduce((acc, item) => acc + (item.price ?? 0) * item.quantity, 0),
7
+ }
8
+ }
@@ -0,0 +1,17 @@
1
+ import { PaymentMethodContextFragment } from '@graphcommerce/magento-cart-payment-method/Api/PaymentMethodContext.gql'
2
+ import { cartToDatalayerItems } from '../cartToDatalayerItems/cartToDatalayerItems'
3
+
4
+ export function orderToPurchase<C extends PaymentMethodContextFragment>(
5
+ orderNumber: string,
6
+ cart: C | null | undefined,
7
+ ) {
8
+ if (!cart) return { transaction_id: orderNumber }
9
+
10
+ return {
11
+ transaction_id: orderNumber,
12
+ coupon: cart.applied_coupons?.map((coupon) => coupon?.code).join(' '),
13
+ payment_type: cart.selected_payment_method?.code,
14
+ tax: cart.prices?.applied_taxes?.reduce((sum, tax) => sum + (tax?.amount?.value ?? 0), 0),
15
+ ...cartToDatalayerItems(cart),
16
+ }
17
+ }
@@ -0,0 +1,22 @@
1
+ import { ProductListItemFragment } from '@graphcommerce/magento-product'
2
+ import { nonNullable } from '@graphcommerce/next-ui'
3
+ import { productToDatalayerItem } from '../productToDatalayerItem/productToDatalayerItem'
4
+
5
+ export function productItemsToViewItemList<P extends ProductListItemFragment>(
6
+ item_list_id: string,
7
+ item_list_name: string,
8
+ items: Array<P | null | undefined> | null | undefined,
9
+ ) {
10
+ return {
11
+ item_list_id,
12
+ item_list_name,
13
+ items: items?.filter(nonNullable)?.map((item) => productToDatalayerItem(item)) ?? [],
14
+ }
15
+ }
16
+
17
+ export function viewItemListToSelectItem(
18
+ viewItemList: ReturnType<typeof productItemsToViewItemList>,
19
+ itemId: string,
20
+ ) {
21
+ return { ...viewItemList, items: viewItemList.items.filter((i) => i.item_id === itemId) }
22
+ }
@@ -1,4 +1,5 @@
1
- fragment ProductToItem on ProductInterface {
1
+ fragment Product_DatalayerItem on ProductInterface {
2
+ uid
2
3
  name
3
4
  sku
4
5
  price_range {
@@ -12,9 +13,5 @@ fragment ProductToItem on ProductInterface {
12
13
  }
13
14
  }
14
15
  }
15
- categories {
16
- uid
17
- url_key
18
- name
19
- }
16
+ ...ProductPageBreadcrumb
20
17
  }
@@ -1,6 +1,8 @@
1
- import { ProductToItemFragment } from './ProductToItem.gql'
1
+ import { productPageCategory } from '@graphcommerce/magento-product'
2
+ import { nonNullable } from '@graphcommerce/next-ui'
3
+ import { Product_DatalayerItemFragment } from './Product_DatalayerItem.gql'
2
4
 
3
- export type Item = {
5
+ export type GoogleDatalayerItem = {
4
6
  item_id: string
5
7
  item_name: string
6
8
  affiliation?: string
@@ -19,20 +21,26 @@ export type Item = {
19
21
  item_variant?: string
20
22
  location_id?: string
21
23
  price?: number
22
- quantity?: number
24
+ quantity: number
23
25
  }
24
26
 
25
- export function productToItem<P extends ProductToItemFragment>(item: P): Item {
27
+ export function productToDatalayerItem<P extends Product_DatalayerItemFragment>(
28
+ item: P,
29
+ ): GoogleDatalayerItem {
30
+ const category = productPageCategory(item)
31
+ const item_categories = Object.fromEntries(
32
+ [...(category?.breadcrumbs?.map((b) => b?.category_name) ?? []), category?.name]
33
+ .filter(nonNullable)
34
+ .map((name, index) => [`item_category${index > 0 ? index + 1 : ''}`, name]),
35
+ )
36
+
26
37
  return {
27
38
  item_id: item.sku ?? '',
28
39
  item_name: item.name ?? '',
29
40
  price: item.price_range?.minimum_price.final_price.value ?? undefined,
30
41
  currency: item.price_range?.minimum_price.final_price.currency ?? undefined,
31
42
  discount: item.price_range?.minimum_price.discount?.amount_off ?? undefined,
32
- item_category: item.categories?.[0]?.name ?? undefined,
33
- item_category2: item.categories?.[1]?.name ?? undefined,
34
- item_category3: item.categories?.[2]?.name ?? undefined,
35
- item_category4: item.categories?.[3]?.name ?? undefined,
36
- item_category5: item.categories?.[4]?.name ?? undefined,
43
+ quantity: 1,
44
+ ...item_categories,
37
45
  }
38
46
  }
@@ -0,0 +1,3 @@
1
+ fragment Product_ViewItem on ProductInterface {
2
+ ...Product_DatalayerItem
3
+ }
@@ -0,0 +1,11 @@
1
+ import { datalayerItemsToCurrencyValue } from '../datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue'
2
+ import { productToDatalayerItem } from '../productToDatalayerItem/productToDatalayerItem'
3
+ import { Product_ViewItemFragment } from './Product_ViewItem.gql'
4
+
5
+ export function productToViewItem<C extends Product_ViewItemFragment>(product: C) {
6
+ const items = [productToDatalayerItem(product)]
7
+ return {
8
+ ...datalayerItemsToCurrencyValue(items),
9
+ items,
10
+ }
11
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/google-datalayer",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "8.0.5-canary.0",
5
+ "version": "8.0.5-canary.1",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -12,16 +12,14 @@
12
12
  }
13
13
  },
14
14
  "peerDependencies": {
15
- "@graphcommerce/eslint-config-pwa": "^8.0.5-canary.0",
16
- "@graphcommerce/graphql-mesh": "^8.0.5-canary.0",
17
- "@graphcommerce/magento-cart": "^8.0.5-canary.0",
18
- "@graphcommerce/magento-cart-payment-method": "^8.0.5-canary.0",
19
- "@graphcommerce/magento-cart-shipping-method": "^8.0.5-canary.0",
20
- "@graphcommerce/magento-product": "^8.0.5-canary.0",
21
- "@graphcommerce/next-config": "^8.0.5-canary.0",
22
- "@graphcommerce/next-ui": "^8.0.5-canary.0",
23
- "@graphcommerce/prettier-config-pwa": "^8.0.5-canary.0",
24
- "@graphcommerce/typescript-config-pwa": "^8.0.5-canary.0",
15
+ "@graphcommerce/eslint-config-pwa": "^8.0.5-canary.1",
16
+ "@graphcommerce/magento-cart": "^8.0.5-canary.1",
17
+ "@graphcommerce/magento-cart-payment-method": "^8.0.5-canary.1",
18
+ "@graphcommerce/magento-cart-shipping-method": "^8.0.5-canary.1",
19
+ "@graphcommerce/magento-product": "^8.0.5-canary.1",
20
+ "@graphcommerce/next-ui": "^8.0.5-canary.1",
21
+ "@graphcommerce/prettier-config-pwa": "^8.0.5-canary.1",
22
+ "@graphcommerce/typescript-config-pwa": "^8.0.5-canary.1",
25
23
  "@mui/material": "^5.14.20",
26
24
  "next": "^14",
27
25
  "react": "^18.2.0",
@@ -40,5 +38,8 @@
40
38
  "@graphcommerce/magento-product": {
41
39
  "optional": true
42
40
  }
41
+ },
42
+ "dependencies": {
43
+ "web-vitals": "^3.5.2"
43
44
  }
44
45
  }
@@ -1,6 +1,13 @@
1
- import { AddProductsToCartFormProps } from '@graphcommerce/magento-product'
2
- import { PluginProps } from '@graphcommerce/next-config'
3
- import { addToCart } from '../events/add_to_cart'
1
+ import {
2
+ AddProductsToCartFormProps,
3
+ findAddedItems,
4
+ toUserErrors,
5
+ } from '@graphcommerce/magento-product'
6
+ import type { PluginProps } from '@graphcommerce/next-config'
7
+ import { nonNullable } from '@graphcommerce/next-ui'
8
+ import { sendEvent } from '../api/sendEvent'
9
+ import { cartItemToDatalayerItem } from '../mapping/cartItemToDatalayerItem/cartItemToDatalayerItem'
10
+ import { datalayerItemsToCurrencyValue } from '../mapping/datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue'
4
11
 
5
12
  export const component = 'AddProductsToCartForm'
6
13
  export const exported = '@graphcommerce/magento-product'
@@ -13,7 +20,29 @@ function GoogleDatalayerAddProductsToCartForm(props: PluginProps<AddProductsToCa
13
20
  <Prev
14
21
  {...rest}
15
22
  onComplete={(result, variables) => {
16
- addToCart(result, variables)
23
+ const { data, errors } = result
24
+ const addedItems = findAddedItems(data, variables)
25
+
26
+ const items = addedItems
27
+ .map(({ itemVariable, itemInCart }) => {
28
+ if (!itemInCart) return null
29
+ return { ...cartItemToDatalayerItem(itemInCart), quantity: itemVariable.quantity }
30
+ })
31
+ .filter(nonNullable)
32
+
33
+ const userErrors = toUserErrors(result.data)
34
+ if ((errors && errors.length > 0) || userErrors.length > 0) {
35
+ sendEvent('add_to_cart_error', {
36
+ userErrors: userErrors?.map((e) => e.message),
37
+ errors: errors?.map((e) => e.message),
38
+ variables,
39
+ })
40
+ }
41
+
42
+ if (items.length > 0) {
43
+ sendEvent('add_to_cart', { ...datalayerItemsToCurrencyValue(items), items })
44
+ }
45
+
17
46
  return onComplete?.(result, variables)
18
47
  }}
19
48
  />
@@ -1,17 +1,31 @@
1
1
  import { CartStartCheckoutProps } from '@graphcommerce/magento-cart'
2
- import { PluginProps } from '@graphcommerce/next-config'
3
- import { beginCheckout } from '../events/begin_checkout'
2
+ import type { PluginProps } from '@graphcommerce/next-config'
3
+ import { useMemoObject } from '@graphcommerce/next-ui'
4
+ import { useEffect, useRef } from 'react'
5
+ import { sendEvent } from '../api/sendEvent'
6
+ import { cartToBeginCheckout } from '../mapping/cartToBeginCheckout/cartToBeginCheckout'
7
+ import { cartToViewCart } from '../mapping/cartToViewCart/cartToViewCart'
4
8
 
5
9
  export const component = 'CartStartCheckout'
6
10
  export const exported = '@graphcommerce/magento-cart'
7
11
 
8
12
  export function GoogleDatalayerCartStartCheckout(props: PluginProps<CartStartCheckoutProps>) {
9
13
  const { Prev, onStart, ...rest } = props
14
+
15
+ const send = useRef(false)
16
+ const viewCart = useMemoObject(cartToViewCart({ __typename: 'Cart', ...props }))
17
+ useEffect(() => {
18
+ if (!send.current) {
19
+ sendEvent('view_cart', viewCart)
20
+ send.current = true
21
+ }
22
+ }, [viewCart])
23
+
10
24
  return (
11
25
  <Prev
12
26
  {...rest}
13
27
  onStart={(e, cart) => {
14
- beginCheckout(cart)
28
+ if (cart) sendEvent('begin_checkout', cartToBeginCheckout(cart))
15
29
  return onStart?.(e, cart)
16
30
  }}
17
31
  />
@@ -1,9 +1,7 @@
1
1
  import { CartStartCheckoutLinkOrButtonProps } from '@graphcommerce/magento-cart'
2
- import { PluginProps } from '@graphcommerce/next-config'
3
- import { useMemoObject } from '@graphcommerce/next-ui'
4
- import { useEffect } from 'react'
5
- import { beginCheckout } from '../events/begin_checkout'
6
- import { viewCart } from '../events/view_cart'
2
+ import type { PluginProps } from '@graphcommerce/next-config'
3
+ import { sendEvent } from '../api/sendEvent'
4
+ import { cartToBeginCheckout } from '../mapping/cartToBeginCheckout/cartToBeginCheckout'
7
5
 
8
6
  export const component = 'CartStartCheckoutLinkOrButton'
9
7
  export const exported = '@graphcommerce/magento-cart'
@@ -13,19 +11,11 @@ export function GoogleDatalayerCartStartCheckoutLinkOrButton(
13
11
  ) {
14
12
  const { Prev, onStart, ...rest } = props
15
13
 
16
- const cartObject = useMemoObject({ items: rest.items, prices: rest.prices })
17
-
18
- useEffect(() => {
19
- if (cartObject.items) {
20
- viewCart(cartObject)
21
- }
22
- }, [cartObject])
23
-
24
14
  return (
25
15
  <Prev
26
16
  {...rest}
27
17
  onStart={(e, cart) => {
28
- beginCheckout(cart)
18
+ sendEvent('begin_checkout', cartToBeginCheckout(cart))
29
19
  return onStart?.(e, cart)
30
20
  }}
31
21
  />