@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.
- package/CHANGELOG.md +12 -0
- package/Config.graphqls +5 -13
- package/README.md +2 -3
- package/api/sendEvent.ts +50 -0
- package/components/DatalayerViewItemList.tsx +45 -0
- package/index.ts +1 -0
- package/mapping/cartItemToDatalayerItem/CartItem_DatalayerItem.graphql +31 -0
- package/mapping/cartItemToDatalayerItem/cartItemToDatalayerItem.ts +27 -0
- package/mapping/cartItemToRemoveFromCart/CartItem_RemoveFromCart.graphql +3 -0
- package/mapping/cartItemToRemoveFromCart/cartToRemoveFromCart.ts +13 -0
- package/mapping/cartToAddPaymentInfo/Cart_AddPaymentInfo.graphql +10 -0
- package/mapping/cartToAddPaymentInfo/cartToAddPaymentInfo.ts +10 -0
- package/mapping/cartToAddShippingInfo/Cart_AddShippingInfo.graphql +12 -0
- package/mapping/cartToAddShippingInfo/cartToAddShippingInfo.ts +15 -0
- package/mapping/cartToBeginCheckout/Cart_BeginCheckout.graphql +6 -0
- package/mapping/cartToBeginCheckout/cartToBeginCheckout.ts +9 -0
- package/mapping/cartToDatalayerItems/Cart_DatalayerItems.graphql +11 -0
- package/mapping/cartToDatalayerItems/cartToDatalayerItems.ts +10 -0
- package/mapping/cartToViewCart/Cart_ViewCart.graphql +4 -0
- package/mapping/cartToViewCart/cartToViewCart.ts +6 -0
- package/mapping/datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue.ts +8 -0
- package/mapping/orderToPurchase/orderToPurchase.ts +17 -0
- package/mapping/productItemsToViewItemList/productItemsToViewItemList.ts +22 -0
- package/{lib/productToItem/ProductToItem.graphql → mapping/productToDatalayerItem/Product_DatalayerItem.graphql} +3 -6
- package/{lib/productToItem/productToItem.ts → mapping/productToDatalayerItem/productToDatalayerItem.ts} +17 -9
- package/mapping/productToViewItem/Product_ViewItem.graphql +3 -0
- package/mapping/productToViewItem/productToViewItem.ts +11 -0
- package/package.json +12 -11
- package/plugins/GoogleDatalayerAddProductsToCartForm.tsx +33 -4
- package/plugins/GoogleDatalayerCartStartCheckout.tsx +17 -3
- package/plugins/GoogleDatalayerCartStartCheckoutLinkOrButton.tsx +4 -14
- package/plugins/GoogleDatalayerPaymentMethodButton.tsx +6 -4
- package/plugins/GoogleDatalayerPaymentMethodContextProvider.tsx +4 -2
- package/plugins/GoogleDatalayerProductListItem.tsx +7 -8
- package/plugins/GoogleDatalayerProductListItemsBase.tsx +4 -4
- package/plugins/GoogleDatalayerRemoveItemFromCart.tsx +13 -10
- package/plugins/GoogleDatalayerRemoveItemFromCartFab.tsx +9 -8
- package/plugins/GoogleDatalayerShippingMethodForm.tsx +10 -4
- package/plugins/GoogleDatalayerUpdateItemQuantity.tsx +15 -32
- package/plugins/GoogleDatalayerViewItem.tsx +5 -13
- package/plugins/GoogleDatalayerWebVitals.tsx +40 -0
- package/components/AnalyticsItemList.tsx +0 -63
- package/events/add_payment_info/AddPaymentInfoFragment.graphql +0 -36
- package/events/add_payment_info/addPaymentInfo.ts +0 -23
- package/events/add_payment_info/index.ts +0 -2
- package/events/add_shipping_info/AddSchippingInfoFragment.graphql +0 -38
- package/events/add_shipping_info/addShippingInfo.ts +0 -22
- package/events/add_shipping_info/index.ts +0 -2
- package/events/add_to_cart/AddToCartFragment.graphql +0 -30
- package/events/add_to_cart/addToCart.ts +0 -58
- package/events/add_to_cart/index.ts +0 -2
- package/events/begin_checkout/BeginCheckoutFragment.graphql +0 -38
- package/events/begin_checkout/beginCheckout.ts +0 -22
- package/events/begin_checkout/index.ts +0 -2
- package/events/purchase/index.ts +0 -1
- package/events/purchase/purchase.ts +0 -27
- package/events/remove_from_cart/RemoveFromCartFragment.graphql +0 -36
- package/events/remove_from_cart/index.ts +0 -2
- package/events/remove_from_cart/removeFromCart.ts +0 -21
- package/events/select_item/index.ts +0 -1
- package/events/select_item/select_item.ts +0 -8
- package/events/view_cart/ViewCartFragment.graphql +0 -35
- package/events/view_cart/index.ts +0 -2
- package/events/view_cart/viewCart.ts +0 -21
- package/events/view_item/index.ts +0 -1
- package/events/view_item/view_item.ts +0 -8
- package/events/view_item_list/index.ts +0 -1
- package/events/view_item_list/view_item_list.ts +0 -8
- package/lib/event.ts +0 -39
- package/lib/index.ts +0 -2
- 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
|
-
|
|
2
|
+
dataLayer: DatalayerConfig
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
"""
|
|
6
|
-
|
|
6
|
+
GoogleDatalayerConfig to allow enabling certain aspects of the datalayer
|
|
7
7
|
"""
|
|
8
|
-
|
|
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
|
-
|
|
10
|
+
Enable core web vitals tracking for GraphCommerce
|
|
19
11
|
"""
|
|
20
|
-
|
|
12
|
+
coreWebVitals: Boolean
|
|
21
13
|
}
|
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# @graphcommerce/google-datalayer
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
trackers.
|
|
3
|
+
Implemenation of the datalayer in GraphCommerce.
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
See [./Config.graphqls](./Config.graphqls) for additional configuration.
|
package/api/sendEvent.ts
ADDED
|
@@ -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,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
|
+
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,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,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,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,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
|
|
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
|
-
|
|
16
|
-
uid
|
|
17
|
-
url_key
|
|
18
|
-
name
|
|
19
|
-
}
|
|
16
|
+
...ProductPageBreadcrumb
|
|
20
17
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import {
|
|
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
|
|
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
|
|
24
|
+
quantity: number
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
export function
|
|
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
|
-
|
|
33
|
-
|
|
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,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.
|
|
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.
|
|
16
|
-
"@graphcommerce/
|
|
17
|
-
"@graphcommerce/magento-cart": "^8.0.5-canary.
|
|
18
|
-
"@graphcommerce/magento-cart-
|
|
19
|
-
"@graphcommerce/magento-
|
|
20
|
-
"@graphcommerce/
|
|
21
|
-
"@graphcommerce/
|
|
22
|
-
"@graphcommerce/
|
|
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 {
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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 {
|
|
4
|
-
import {
|
|
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
|
-
|
|
18
|
+
sendEvent('begin_checkout', cartToBeginCheckout(cart))
|
|
29
19
|
return onStart?.(e, cart)
|
|
30
20
|
}}
|
|
31
21
|
/>
|