@graphcommerce/google-datalayer 9.0.0-canary.72 → 9.0.0-canary.73
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 +6 -0
- package/api/googleEventNames.ts +116 -0
- package/api/sendEvent.ts +15 -7
- package/components/DatalayerViewItemList.tsx +7 -4
- package/mapping/cartItemToDatalayerItem/cartItemToDatalayerItem.ts +3 -2
- package/mapping/cartItemToRemoveFromCart/cartToRemoveFromCart.ts +2 -5
- package/mapping/cartToAddPaymentInfo/Cart_AddPaymentInfo.graphql +1 -1
- package/mapping/cartToAddPaymentInfo/cartToAddPaymentInfo.ts +10 -3
- package/mapping/cartToAddShippingInfo/Cart_AddShippingInfo.graphql +1 -1
- package/mapping/cartToAddShippingInfo/cartToAddShippingInfo.ts +14 -6
- package/mapping/cartToBeginCheckout/Cart_BeginCheckout.graphql +1 -1
- package/mapping/cartToBeginCheckout/cartToBeginCheckout.ts +7 -3
- package/mapping/cartToPurchase/Cart_PurchaseEvent.graphql +18 -0
- package/mapping/cartToPurchase/cartToPurchase.ts +28 -0
- package/mapping/cartToViewCart/Cart_ViewCart.graphql +8 -1
- package/mapping/cartToViewCart/cartToViewCart.ts +12 -3
- package/mapping/datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue.ts +9 -2
- package/mapping/productItemsToViewItemList/productItemsToViewItemList.ts +28 -6
- package/mapping/productToDatalayerItem/productToDatalayerItem.ts +11 -4
- package/mapping/productToViewItem/productToViewItem.ts +13 -8
- package/package.json +12 -9
- package/plugins/GoogleDatalayerAddProductsToCartForm.tsx +7 -3
- package/plugins/GoogleDatalayerCartStartCheckout.tsx +3 -2
- package/plugins/GoogleDatalayerCartStartCheckoutLinkOrButton.tsx +2 -1
- package/plugins/GoogleDatalayerPaymentMethodButton.tsx +2 -1
- package/plugins/GoogleDatalayerPaymentMethodContextProvider.tsx +5 -3
- package/plugins/GoogleDatalayerRemoveItemFromCart.tsx +5 -3
- package/plugins/GoogleDatalayerShippingMethodForm.tsx +4 -2
- package/plugins/GoogleDatalayerUseRemoveItemFromCart.tsx +3 -2
- package/plugins/GoogleDatalayerUseSignInForm.tsx +0 -0
- package/plugins/GoogleDatalayerViewItem.tsx +4 -3
- package/plugins/GoogleDatalayerWebVitals.tsx +2 -1
- package/mapping/cartToDatalayerItems/Cart_DatalayerItems.graphql +0 -11
- package/mapping/cartToDatalayerItems/cartToDatalayerItems.ts +0 -10
- package/mapping/orderToPurchase/orderToPurchase.ts +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @graphcommerce/google-datalayer
|
|
2
2
|
|
|
3
|
+
## 9.0.0-canary.73
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#2337](https://github.com/graphcommerce-org/graphcommerce/pull/2337) [`18898df`](https://github.com/graphcommerce-org/graphcommerce/commit/18898df44b786dd68d8e6fec538e3db947c157e4) - All sendEvent calls are now the return type of useSendEvent, to allow plugins to use hooks themselves ([@Renzovh](https://github.com/Renzovh))
|
|
8
|
+
|
|
3
9
|
## 9.0.0-canary.72
|
|
4
10
|
|
|
5
11
|
## 9.0.0-canary.71
|
package/api/googleEventNames.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import { Metric } from 'web-vitals'
|
|
2
|
+
import type { AddPaymentInfo } from '../mapping/cartToAddPaymentInfo/cartToAddPaymentInfo'
|
|
3
|
+
import type { AddShippingInfo } from '../mapping/cartToAddShippingInfo/cartToAddShippingInfo'
|
|
4
|
+
import type { BeginCheckout } from '../mapping/cartToBeginCheckout/cartToBeginCheckout'
|
|
5
|
+
import type { PurchaseOrRefund } from '../mapping/cartToPurchase/cartToPurchase'
|
|
6
|
+
import type { ViewCart } from '../mapping/cartToViewCart/cartToViewCart'
|
|
7
|
+
import type { DataLayerCurrencyValue } from '../mapping/datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue'
|
|
8
|
+
import type {
|
|
9
|
+
SelectItem,
|
|
10
|
+
ViewItemList,
|
|
11
|
+
} from '../mapping/productItemsToViewItemList/productItemsToViewItemList'
|
|
12
|
+
import type { GoogleDatalayerItem } from '../mapping/productToDatalayerItem/productToDatalayerItem'
|
|
13
|
+
import type { ViewItem } from '../mapping/productToViewItem/productToViewItem'
|
|
14
|
+
|
|
1
15
|
export const googleEventNames = [
|
|
2
16
|
'add_payment_info',
|
|
3
17
|
'add_shipping_info',
|
|
@@ -37,3 +51,105 @@ export const googleEventNames = [
|
|
|
37
51
|
'view_promotion',
|
|
38
52
|
'view_search_results',
|
|
39
53
|
] as const
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @see https://developers.google.com/tag-platform/gtagjs/reference/events
|
|
57
|
+
*/
|
|
58
|
+
export type GoogleEventTypes = {
|
|
59
|
+
exception: { description?: string; fatal?: boolean }
|
|
60
|
+
share: { method?: string; content_type?: string; item_id?: string }
|
|
61
|
+
|
|
62
|
+
add_payment_info: AddPaymentInfo
|
|
63
|
+
add_shipping_info: AddShippingInfo
|
|
64
|
+
add_to_cart: ViewCart
|
|
65
|
+
add_to_wishlist: DataLayerCurrencyValue & { items: GoogleDatalayerItem[] }
|
|
66
|
+
begin_checkout: BeginCheckout
|
|
67
|
+
|
|
68
|
+
login: { method?: string }
|
|
69
|
+
sign_up: {
|
|
70
|
+
method?: string
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
page_view: {
|
|
74
|
+
page_location?: string
|
|
75
|
+
client_id?: string
|
|
76
|
+
language?: string
|
|
77
|
+
page_encoding?: string
|
|
78
|
+
page_title?: string
|
|
79
|
+
user_agent?: string
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
purchase: PurchaseOrRefund
|
|
83
|
+
refund: PurchaseOrRefund
|
|
84
|
+
remove_from_cart: ViewCart
|
|
85
|
+
|
|
86
|
+
select_content: {
|
|
87
|
+
content_type?: string
|
|
88
|
+
content_id?: string
|
|
89
|
+
data?: object
|
|
90
|
+
}
|
|
91
|
+
select_item: SelectItem
|
|
92
|
+
|
|
93
|
+
view_cart: ViewCart
|
|
94
|
+
view_item: ViewItem
|
|
95
|
+
view_item_list: ViewItemList
|
|
96
|
+
|
|
97
|
+
search: { search_term?: string }
|
|
98
|
+
view_search_results: { search_term?: string }
|
|
99
|
+
|
|
100
|
+
view_promotion: {
|
|
101
|
+
creative_name?: string
|
|
102
|
+
creative_slot?: string
|
|
103
|
+
promotion_id?: string
|
|
104
|
+
promotion_name?: string
|
|
105
|
+
items?: GoogleDatalayerItem[]
|
|
106
|
+
}
|
|
107
|
+
select_promotion: {
|
|
108
|
+
creative_name?: string
|
|
109
|
+
creative_slot?: string
|
|
110
|
+
promotion_id?: string
|
|
111
|
+
promotion_name?: string
|
|
112
|
+
items?: GoogleDatalayerItem[]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Tutorial
|
|
116
|
+
tutorial_begin: object
|
|
117
|
+
tutorial_complete: object
|
|
118
|
+
|
|
119
|
+
// Gaming
|
|
120
|
+
earn_virtual_currency: { value?: string; virtual_currency_name?: string }
|
|
121
|
+
join_group: { group_id?: string }
|
|
122
|
+
level_end: { level_name?: string; success?: boolean }
|
|
123
|
+
level_start: { level_name?: string }
|
|
124
|
+
level_up: { level?: number; character?: string }
|
|
125
|
+
post_score: { score?: number; level?: number; character?: string }
|
|
126
|
+
spend_virtual_currency: {
|
|
127
|
+
value?: string
|
|
128
|
+
virtual_currency_name?: string
|
|
129
|
+
item_name?: string
|
|
130
|
+
}
|
|
131
|
+
unlock_achievement: { achievement_id: string }
|
|
132
|
+
|
|
133
|
+
// Leads
|
|
134
|
+
close_convert_lead: DataLayerCurrencyValue
|
|
135
|
+
close_unconvert_lead: DataLayerCurrencyValue & { unconvert_lead_reason?: string }
|
|
136
|
+
disqualify_lead: DataLayerCurrencyValue & { disqualified_lead_reason?: string }
|
|
137
|
+
generate_lead: DataLayerCurrencyValue & { lead_source?: string }
|
|
138
|
+
qualify_lead: DataLayerCurrencyValue
|
|
139
|
+
working_lead: DataLayerCurrencyValue & { lead_status?: string }
|
|
140
|
+
|
|
141
|
+
// Custom events
|
|
142
|
+
add_to_cart_error: {
|
|
143
|
+
userErrors?: string[]
|
|
144
|
+
errors?: string[]
|
|
145
|
+
variables?: object
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Core web vitals tracking.
|
|
149
|
+
[key: `cwv_${string}`]: {
|
|
150
|
+
value: Metric['delta']
|
|
151
|
+
debug_target?: string
|
|
152
|
+
} & {
|
|
153
|
+
[K in keyof Metric as K extends string ? `metric_${K}` : never]?: Metric[K]
|
|
154
|
+
}
|
|
155
|
+
}
|
package/api/sendEvent.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { GoogleEventTypes } from './googleEventNames'
|
|
2
2
|
|
|
3
|
-
export type
|
|
4
|
-
eventName:
|
|
5
|
-
eventData: {
|
|
6
|
-
[key: string]: unknown
|
|
7
|
-
},
|
|
3
|
+
export type SendEvent = (
|
|
4
|
+
eventName: Event | (string & Record<never, never>),
|
|
5
|
+
eventData: { [key: string]: unknown },
|
|
8
6
|
) => void
|
|
9
7
|
|
|
10
|
-
export
|
|
8
|
+
export function sendEvent<Event extends keyof GoogleEventTypes>(
|
|
9
|
+
eventName: Event,
|
|
10
|
+
eventData: GoogleEventTypes[Event],
|
|
11
|
+
) {
|
|
11
12
|
// This is a generic event handler and is plugins from google-analytics and google datalayer
|
|
12
13
|
}
|
|
14
|
+
|
|
15
|
+
export function useSendEvent() {
|
|
16
|
+
return <Event extends keyof GoogleEventTypes>(
|
|
17
|
+
eventName: Event,
|
|
18
|
+
eventData: GoogleEventTypes[Event],
|
|
19
|
+
) => sendEvent<Event>(eventName, eventData)
|
|
20
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ProductItemsGridProps } from '@graphcommerce/magento-product'
|
|
1
|
+
import { ProductItemsGridProps, useProductFiltersPro } from '@graphcommerce/magento-product'
|
|
2
2
|
import { useMemoObject } from '@graphcommerce/next-ui'
|
|
3
3
|
import { useEventCallback } from '@mui/material'
|
|
4
4
|
import React, { useContext, useEffect } from 'react'
|
|
5
|
-
import {
|
|
5
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
6
6
|
import {
|
|
7
7
|
productItemsToViewItemList,
|
|
8
8
|
viewItemListToSelectItem,
|
|
@@ -28,10 +28,13 @@ export function DatalayerViewItemList(
|
|
|
28
28
|
const { title: item_list_name, items, children } = props
|
|
29
29
|
const item_list_id = item_list_name.toLowerCase().replace(/\s/g, '_')
|
|
30
30
|
|
|
31
|
+
const params = useProductFiltersPro(true)?.params
|
|
32
|
+
|
|
33
|
+
const sendEvent = useSendEvent()
|
|
31
34
|
const viewItemList = useMemoObject(
|
|
32
|
-
productItemsToViewItemList(item_list_id, item_list_name, items),
|
|
35
|
+
productItemsToViewItemList(item_list_id, item_list_name, items, params),
|
|
33
36
|
)
|
|
34
|
-
useEffect(() => sendEvent('view_item_list', viewItemList), [viewItemList])
|
|
37
|
+
useEffect(() => sendEvent('view_item_list', viewItemList), [sendEvent, viewItemList])
|
|
35
38
|
|
|
36
39
|
const selectItem = useEventCallback((itemId: string) => {
|
|
37
40
|
sendEvent('select_item', viewItemListToSelectItem(viewItemList, itemId))
|
|
@@ -6,6 +6,7 @@ import { CartItem_DatalayerItemFragment } from './CartItem_DatalayerItem.gql'
|
|
|
6
6
|
|
|
7
7
|
export function cartItemToDatalayerItem<P extends CartItem_DatalayerItemFragment>(
|
|
8
8
|
item: P,
|
|
9
|
+
index: number,
|
|
9
10
|
): GoogleDatalayerItem {
|
|
10
11
|
const discount = item.prices?.total_item_discount?.value
|
|
11
12
|
? item.prices.total_item_discount.value / item.quantity
|
|
@@ -14,14 +15,14 @@ export function cartItemToDatalayerItem<P extends CartItem_DatalayerItemFragment
|
|
|
14
15
|
const price = (item?.prices?.price_including_tax?.value ?? 0) - discount
|
|
15
16
|
|
|
16
17
|
return {
|
|
17
|
-
...productToDatalayerItem(item.product),
|
|
18
|
+
...productToDatalayerItem(item.product, index),
|
|
18
19
|
currency: item.prices?.price.currency as string,
|
|
19
20
|
discount,
|
|
20
21
|
price,
|
|
21
22
|
quantity: item.quantity,
|
|
22
23
|
item_variant:
|
|
23
24
|
item.__typename === 'ConfigurableCartItem'
|
|
24
|
-
? item.configured_variant.sku ?? undefined
|
|
25
|
+
? (item.configured_variant.sku ?? undefined)
|
|
25
26
|
: undefined,
|
|
26
27
|
}
|
|
27
28
|
}
|
|
@@ -5,9 +5,6 @@ import { CartItem_RemoveFromCartFragment } from './CartItem_RemoveFromCart.gql'
|
|
|
5
5
|
export const cartItemToRemoveFromCart = <C extends CartItem_RemoveFromCartFragment>(
|
|
6
6
|
cartItem: C,
|
|
7
7
|
) => {
|
|
8
|
-
const items = [cartItemToDatalayerItem(cartItem)]
|
|
9
|
-
return {
|
|
10
|
-
...datalayerItemsToCurrencyValue(items),
|
|
11
|
-
items,
|
|
12
|
-
}
|
|
8
|
+
const items = [cartItemToDatalayerItem(cartItem, 0)]
|
|
9
|
+
return { ...datalayerItemsToCurrencyValue(items), items }
|
|
13
10
|
}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cartToViewCart, ViewCart } from '../cartToViewCart/cartToViewCart'
|
|
2
2
|
import { Cart_AddPaymentInfoFragment } from './Cart_AddPaymentInfo.gql'
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export type AddPaymentInfo = ViewCart & {
|
|
5
|
+
coupon?: string
|
|
6
|
+
payment_type?: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function cartToAddPaymentInfo<C extends Cart_AddPaymentInfoFragment>(
|
|
10
|
+
cart: C,
|
|
11
|
+
): AddPaymentInfo {
|
|
5
12
|
return {
|
|
13
|
+
...cartToViewCart(cart),
|
|
6
14
|
coupon: cart?.applied_coupons?.map((coupon) => coupon?.code).join(' '),
|
|
7
15
|
payment_type: cart?.selected_payment_method?.code,
|
|
8
|
-
...cartToDatalayerItems(cart),
|
|
9
16
|
}
|
|
10
17
|
}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { filterNonNullableKeys } from '@graphcommerce/next-ui'
|
|
2
|
+
import { cartToViewCart, ViewCart } from '../cartToViewCart/cartToViewCart'
|
|
2
3
|
import { Cart_AddShippingInfoFragment } from './Cart_AddShippingInfo.gql'
|
|
3
4
|
|
|
4
|
-
export
|
|
5
|
+
export type AddShippingInfo = ViewCart & {
|
|
6
|
+
coupon?: string
|
|
7
|
+
shipping_tier?: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function cartToAddShippingInfo<C extends Cart_AddShippingInfoFragment>(
|
|
11
|
+
cart: C,
|
|
12
|
+
): AddShippingInfo {
|
|
5
13
|
return {
|
|
6
14
|
coupon: cart?.applied_coupons?.map((coupon) => coupon?.code).join(' '),
|
|
7
|
-
shipping_tier: cart?.shipping_addresses
|
|
15
|
+
shipping_tier: filterNonNullableKeys(cart?.shipping_addresses, ['selected_shipping_method'])
|
|
8
16
|
.map(
|
|
9
|
-
(
|
|
10
|
-
`${
|
|
17
|
+
({ selected_shipping_method: { carrier_code, method_code } }) =>
|
|
18
|
+
`${carrier_code}_${method_code}`,
|
|
11
19
|
)
|
|
12
20
|
.join(' '),
|
|
13
|
-
...
|
|
21
|
+
...cartToViewCart(cart),
|
|
14
22
|
}
|
|
15
23
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cartToViewCart, ViewCart } from '../cartToViewCart/cartToViewCart'
|
|
2
2
|
import { Cart_BeginCheckoutFragment } from './Cart_BeginCheckout.gql'
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export type BeginCheckout = ViewCart & {
|
|
5
|
+
coupon?: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function cartToBeginCheckout<C extends Cart_BeginCheckoutFragment>(cart: C): BeginCheckout {
|
|
5
9
|
return {
|
|
6
10
|
coupon: cart?.applied_coupons?.map((coupon) => coupon?.code).join(' '),
|
|
7
|
-
...
|
|
11
|
+
...cartToViewCart(cart),
|
|
8
12
|
}
|
|
9
13
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
fragment Cart_PurchaseEvent on Cart
|
|
2
|
+
@inject(into: ["PaymentMethodContext", "PaymentMethodUpdated"]) {
|
|
3
|
+
...Cart_AddPaymentInfo
|
|
4
|
+
shipping_addresses {
|
|
5
|
+
selected_shipping_method {
|
|
6
|
+
price_excl_tax {
|
|
7
|
+
...Money
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
prices {
|
|
12
|
+
applied_taxes {
|
|
13
|
+
amount {
|
|
14
|
+
...Money
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { cartToViewCart, ViewCart } from '../cartToViewCart/cartToViewCart'
|
|
2
|
+
import { Cart_PurchaseEventFragment } from './Cart_PurchaseEvent.gql'
|
|
3
|
+
|
|
4
|
+
export type PurchaseOrRefund = ViewCart & {
|
|
5
|
+
transaction_id: string
|
|
6
|
+
coupon?: string
|
|
7
|
+
shipping?: number
|
|
8
|
+
tax?: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function cartToPurchase<C extends Cart_PurchaseEventFragment>(
|
|
12
|
+
orderNumber: string,
|
|
13
|
+
cart: C | null | undefined,
|
|
14
|
+
): PurchaseOrRefund {
|
|
15
|
+
// Although the fallback information is wrong, we find it to be more important to register a purchase even in the cart object is missing.
|
|
16
|
+
const base = cart ? cartToViewCart(cart) : { items: [], currency: '', value: 0 }
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
transaction_id: orderNumber,
|
|
20
|
+
coupon: cart?.applied_coupons?.map((coupon) => coupon?.code).join(' '),
|
|
21
|
+
shipping: cart?.shipping_addresses.reduce(
|
|
22
|
+
(sum, address) => sum + (address?.selected_shipping_method?.price_excl_tax.value ?? 0),
|
|
23
|
+
0,
|
|
24
|
+
),
|
|
25
|
+
tax: cart?.prices?.applied_taxes?.reduce((sum, tax) => sum + (tax?.amount?.value ?? 0), 0),
|
|
26
|
+
...base,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { nonNullable } from '@graphcommerce/next-ui'
|
|
2
|
+
import { cartItemToDatalayerItem } from '../cartItemToDatalayerItem/cartItemToDatalayerItem'
|
|
3
|
+
import {
|
|
4
|
+
DataLayerCurrencyValue,
|
|
5
|
+
datalayerItemsToCurrencyValue,
|
|
6
|
+
} from '../datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue'
|
|
7
|
+
import { GoogleDatalayerItem } from '../productToDatalayerItem/productToDatalayerItem'
|
|
2
8
|
import { Cart_ViewCartFragment } from './Cart_ViewCart.gql'
|
|
3
9
|
|
|
4
|
-
export
|
|
5
|
-
|
|
10
|
+
export type ViewCart = DataLayerCurrencyValue & { items: GoogleDatalayerItem[] }
|
|
11
|
+
|
|
12
|
+
export function cartToViewCart<C extends Cart_ViewCartFragment>(cart: C): ViewCart {
|
|
13
|
+
const items = cart?.items?.filter(nonNullable).map(cartItemToDatalayerItem) ?? []
|
|
14
|
+
return { ...datalayerItemsToCurrencyValue(items), items }
|
|
6
15
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { GoogleDatalayerItem } from '../productToDatalayerItem/productToDatalayerItem'
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export type DataLayerCurrencyValue = {
|
|
4
|
+
currency: string
|
|
5
|
+
value: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function datalayerItemsToCurrencyValue(
|
|
9
|
+
items: GoogleDatalayerItem[],
|
|
10
|
+
): DataLayerCurrencyValue {
|
|
4
11
|
return {
|
|
5
|
-
currency: items[0]
|
|
12
|
+
currency: items[0]?.currency ?? '',
|
|
6
13
|
value: items.reduce((acc, item) => acc + (item.price ?? 0) * item.quantity, 0),
|
|
7
14
|
}
|
|
8
15
|
}
|
|
@@ -1,22 +1,44 @@
|
|
|
1
|
-
import { ProductListItemFragment } from '@graphcommerce/magento-product'
|
|
1
|
+
import { ProductFilterParams, ProductListItemFragment } from '@graphcommerce/magento-product'
|
|
2
2
|
import { nonNullable } from '@graphcommerce/next-ui'
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
GoogleDatalayerItem,
|
|
5
|
+
productToDatalayerItem,
|
|
6
|
+
} from '../productToDatalayerItem/productToDatalayerItem'
|
|
7
|
+
|
|
8
|
+
export type ViewItemList = {
|
|
9
|
+
item_list_id: string
|
|
10
|
+
item_list_name: string
|
|
11
|
+
items: GoogleDatalayerItem[]
|
|
12
|
+
filter_params?: ProductFilterParams | null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type SelectItem = {
|
|
16
|
+
item_list_id: string
|
|
17
|
+
item_list_name: string
|
|
18
|
+
items: GoogleDatalayerItem[]
|
|
19
|
+
filter_params?: ProductFilterParams | null
|
|
20
|
+
}
|
|
4
21
|
|
|
5
22
|
export function productItemsToViewItemList<P extends ProductListItemFragment>(
|
|
6
23
|
item_list_id: string,
|
|
7
24
|
item_list_name: string,
|
|
8
25
|
items: Array<P | null | undefined> | null | undefined,
|
|
9
|
-
|
|
26
|
+
filter_params: ProductFilterParams | null | undefined,
|
|
27
|
+
): ViewItemList {
|
|
10
28
|
return {
|
|
11
29
|
item_list_id,
|
|
12
30
|
item_list_name,
|
|
13
|
-
items: items?.filter(nonNullable)?.map(
|
|
31
|
+
items: (items ?? [])?.filter(nonNullable)?.map(productToDatalayerItem),
|
|
32
|
+
filter_params,
|
|
14
33
|
}
|
|
15
34
|
}
|
|
16
35
|
|
|
17
36
|
export function viewItemListToSelectItem(
|
|
18
37
|
viewItemList: ReturnType<typeof productItemsToViewItemList>,
|
|
19
38
|
itemId: string,
|
|
20
|
-
) {
|
|
21
|
-
return {
|
|
39
|
+
): SelectItem {
|
|
40
|
+
return {
|
|
41
|
+
...viewItemList,
|
|
42
|
+
items: viewItemList.items.filter((i) => i.item_id === itemId),
|
|
43
|
+
}
|
|
22
44
|
}
|
|
@@ -2,14 +2,18 @@ import { productPageCategory } from '@graphcommerce/magento-product'
|
|
|
2
2
|
import { nonNullable } from '@graphcommerce/next-ui'
|
|
3
3
|
import { Product_DatalayerItemFragment } from './Product_DatalayerItem.gql'
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* https://developers.google.com/tag-platform/gtagjs/reference/events#add_to_cart_item
|
|
7
|
+
*/
|
|
5
8
|
export type GoogleDatalayerItem = {
|
|
6
9
|
item_id: string
|
|
10
|
+
item_uid: string
|
|
7
11
|
item_name: string
|
|
8
12
|
affiliation?: string
|
|
9
13
|
coupon?: string
|
|
10
14
|
currency?: string
|
|
11
15
|
discount?: number
|
|
12
|
-
index
|
|
16
|
+
index: number
|
|
13
17
|
item_brand?: string
|
|
14
18
|
item_category?: string
|
|
15
19
|
item_category2?: string
|
|
@@ -20,27 +24,30 @@ export type GoogleDatalayerItem = {
|
|
|
20
24
|
item_list_name?: string
|
|
21
25
|
item_variant?: string
|
|
22
26
|
location_id?: string
|
|
23
|
-
price
|
|
27
|
+
price: number
|
|
24
28
|
quantity: number
|
|
25
29
|
}
|
|
26
30
|
|
|
27
31
|
export function productToDatalayerItem<P extends Product_DatalayerItemFragment>(
|
|
28
32
|
item: P,
|
|
33
|
+
index: number,
|
|
29
34
|
): GoogleDatalayerItem {
|
|
30
35
|
const category = productPageCategory(item)
|
|
31
36
|
const item_categories = Object.fromEntries(
|
|
32
37
|
[...(category?.breadcrumbs?.map((b) => b?.category_name) ?? []), category?.name]
|
|
33
38
|
.filter(nonNullable)
|
|
34
|
-
.map((name,
|
|
39
|
+
.map((name, idx) => [`item_category${idx > 0 ? idx + 1 : ''}`, name]),
|
|
35
40
|
)
|
|
36
41
|
|
|
37
42
|
return {
|
|
38
43
|
item_id: item.sku ?? '',
|
|
44
|
+
item_uid: item.uid,
|
|
39
45
|
item_name: item.name ?? '',
|
|
40
|
-
price: item.price_range?.minimum_price.final_price.value ??
|
|
46
|
+
price: item.price_range?.minimum_price.final_price.value ?? 0,
|
|
41
47
|
currency: item.price_range?.minimum_price.final_price.currency ?? undefined,
|
|
42
48
|
discount: item.price_range?.minimum_price.discount?.amount_off ?? undefined,
|
|
43
49
|
quantity: 1,
|
|
50
|
+
index,
|
|
44
51
|
...item_categories,
|
|
45
52
|
}
|
|
46
53
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
DataLayerCurrencyValue,
|
|
3
|
+
datalayerItemsToCurrencyValue,
|
|
4
|
+
} from '../datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue'
|
|
5
|
+
import {
|
|
6
|
+
GoogleDatalayerItem,
|
|
7
|
+
productToDatalayerItem,
|
|
8
|
+
} from '../productToDatalayerItem/productToDatalayerItem'
|
|
3
9
|
import { Product_ViewItemFragment } from './Product_ViewItem.gql'
|
|
4
10
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
+
export type ViewItem = { items: GoogleDatalayerItem[] } & DataLayerCurrencyValue
|
|
12
|
+
|
|
13
|
+
export function productToViewItem<C extends Product_ViewItemFragment>(product: C): ViewItem {
|
|
14
|
+
const items = [productToDatalayerItem(product, 0)]
|
|
15
|
+
return { ...datalayerItemsToCurrencyValue(items), items }
|
|
11
16
|
}
|
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": "9.0.0-canary.
|
|
5
|
+
"version": "9.0.0-canary.73",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
8
8
|
"eslintConfig": {
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@graphcommerce/eslint-config-pwa": "^9.0.0-canary.
|
|
16
|
-
"@graphcommerce/magento-cart": "^9.0.0-canary.
|
|
17
|
-
"@graphcommerce/magento-cart-payment-method": "^9.0.0-canary.
|
|
18
|
-
"@graphcommerce/magento-cart-shipping-method": "^9.0.0-canary.
|
|
19
|
-
"@graphcommerce/magento-product": "^9.0.0-canary.
|
|
20
|
-
"@graphcommerce/next-ui": "^9.0.0-canary.
|
|
21
|
-
"@graphcommerce/prettier-config-pwa": "^9.0.0-canary.
|
|
22
|
-
"@graphcommerce/typescript-config-pwa": "^9.0.0-canary.
|
|
15
|
+
"@graphcommerce/eslint-config-pwa": "^9.0.0-canary.73",
|
|
16
|
+
"@graphcommerce/magento-cart": "^9.0.0-canary.73",
|
|
17
|
+
"@graphcommerce/magento-cart-payment-method": "^9.0.0-canary.73",
|
|
18
|
+
"@graphcommerce/magento-cart-shipping-method": "^9.0.0-canary.73",
|
|
19
|
+
"@graphcommerce/magento-product": "^9.0.0-canary.73",
|
|
20
|
+
"@graphcommerce/next-ui": "^9.0.0-canary.73",
|
|
21
|
+
"@graphcommerce/prettier-config-pwa": "^9.0.0-canary.73",
|
|
22
|
+
"@graphcommerce/typescript-config-pwa": "^9.0.0-canary.73",
|
|
23
23
|
"@mui/material": "^5.14.20",
|
|
24
24
|
"next": "^14",
|
|
25
25
|
"react": "^18.2.0",
|
|
@@ -37,6 +37,9 @@
|
|
|
37
37
|
},
|
|
38
38
|
"@graphcommerce/magento-product": {
|
|
39
39
|
"optional": true
|
|
40
|
+
},
|
|
41
|
+
"@graphcommerce/magento-product-configurable": {
|
|
42
|
+
"optional": true
|
|
40
43
|
}
|
|
41
44
|
},
|
|
42
45
|
"dependencies": {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from '@graphcommerce/magento-product'
|
|
6
6
|
import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
|
|
7
7
|
import { nonNullable } from '@graphcommerce/next-ui'
|
|
8
|
-
import {
|
|
8
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
9
9
|
import { cartItemToDatalayerItem } from '../mapping/cartItemToDatalayerItem/cartItemToDatalayerItem'
|
|
10
10
|
import { datalayerItemsToCurrencyValue } from '../mapping/datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue'
|
|
11
11
|
|
|
@@ -18,6 +18,7 @@ export const config: PluginConfig = {
|
|
|
18
18
|
export function AddProductsToCartForm(props: PluginProps<AddProductsToCartFormProps>) {
|
|
19
19
|
const { Prev, onComplete, ...rest } = props
|
|
20
20
|
|
|
21
|
+
const sendEvent = useSendEvent()
|
|
21
22
|
return (
|
|
22
23
|
<Prev
|
|
23
24
|
{...rest}
|
|
@@ -26,9 +27,12 @@ export function AddProductsToCartForm(props: PluginProps<AddProductsToCartFormPr
|
|
|
26
27
|
const addedItems = findAddedItems(data, variables)
|
|
27
28
|
|
|
28
29
|
const items = addedItems
|
|
29
|
-
.map(({ itemVariable, itemInCart }) => {
|
|
30
|
+
.map(({ itemVariable, itemInCart }, index) => {
|
|
30
31
|
if (!itemInCart) return null
|
|
31
|
-
return {
|
|
32
|
+
return {
|
|
33
|
+
...cartItemToDatalayerItem(itemInCart, index),
|
|
34
|
+
quantity: itemVariable.quantity,
|
|
35
|
+
}
|
|
32
36
|
})
|
|
33
37
|
.filter(nonNullable)
|
|
34
38
|
|
|
@@ -2,7 +2,7 @@ import { CartStartCheckoutProps } from '@graphcommerce/magento-cart'
|
|
|
2
2
|
import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
|
|
3
3
|
import { useMemoObject } from '@graphcommerce/next-ui'
|
|
4
4
|
import { useEffect, useRef } from 'react'
|
|
5
|
-
import {
|
|
5
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
6
6
|
import { cartToBeginCheckout } from '../mapping/cartToBeginCheckout/cartToBeginCheckout'
|
|
7
7
|
import { cartToViewCart } from '../mapping/cartToViewCart/cartToViewCart'
|
|
8
8
|
|
|
@@ -15,13 +15,14 @@ export function CartStartCheckout(props: PluginProps<CartStartCheckoutProps>) {
|
|
|
15
15
|
const { Prev, onStart, ...rest } = props
|
|
16
16
|
|
|
17
17
|
const send = useRef(false)
|
|
18
|
+
const sendEvent = useSendEvent()
|
|
18
19
|
const viewCart = useMemoObject(cartToViewCart({ __typename: 'Cart', ...props }))
|
|
19
20
|
useEffect(() => {
|
|
20
21
|
if (!send.current) {
|
|
21
22
|
sendEvent('view_cart', viewCart)
|
|
22
23
|
send.current = true
|
|
23
24
|
}
|
|
24
|
-
}, [viewCart])
|
|
25
|
+
}, [sendEvent, viewCart])
|
|
25
26
|
|
|
26
27
|
return (
|
|
27
28
|
<Prev
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CartStartCheckoutLinkOrButtonProps } from '@graphcommerce/magento-cart'
|
|
2
2
|
import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
|
|
3
|
-
import {
|
|
3
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
4
4
|
import { cartToBeginCheckout } from '../mapping/cartToBeginCheckout/cartToBeginCheckout'
|
|
5
5
|
|
|
6
6
|
export const config: PluginConfig = {
|
|
@@ -13,6 +13,7 @@ export function CartStartCheckoutLinkOrButton(
|
|
|
13
13
|
) {
|
|
14
14
|
const { Prev, onStart, ...rest } = props
|
|
15
15
|
|
|
16
|
+
const sendEvent = useSendEvent()
|
|
16
17
|
return (
|
|
17
18
|
<Prev
|
|
18
19
|
{...rest}
|
|
@@ -2,7 +2,7 @@ import { useCartQuery } from '@graphcommerce/magento-cart'
|
|
|
2
2
|
import { PaymentMethodButtonProps } from '@graphcommerce/magento-cart-payment-method'
|
|
3
3
|
import { GetPaymentMethodContextDocument } from '@graphcommerce/magento-cart-payment-method/PaymentMethodContext/GetPaymentMethodContext.gql'
|
|
4
4
|
import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
|
|
5
|
-
import {
|
|
5
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
6
6
|
import { cartToAddPaymentInfo } from '../mapping/cartToAddPaymentInfo/cartToAddPaymentInfo'
|
|
7
7
|
|
|
8
8
|
export const config: PluginConfig = {
|
|
@@ -14,6 +14,7 @@ export function PaymentMethodButton(props: PluginProps<PaymentMethodButtonProps>
|
|
|
14
14
|
const { Prev, onSubmitSuccessful, ...rest } = props
|
|
15
15
|
const methodContext = useCartQuery(GetPaymentMethodContextDocument)
|
|
16
16
|
|
|
17
|
+
const sendEvent = useSendEvent()
|
|
17
18
|
return (
|
|
18
19
|
<Prev
|
|
19
20
|
{...rest}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PaymentMethodContextProviderProps } from '@graphcommerce/magento-cart-payment-method'
|
|
2
2
|
import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
4
|
+
import { cartToPurchase } from '../mapping/cartToPurchase/cartToPurchase'
|
|
5
5
|
|
|
6
6
|
export const config: PluginConfig = {
|
|
7
7
|
module: '@graphcommerce/magento-cart-payment-method',
|
|
@@ -12,11 +12,13 @@ export function PaymentMethodContextProvider(
|
|
|
12
12
|
props: PluginProps<PaymentMethodContextProviderProps>,
|
|
13
13
|
) {
|
|
14
14
|
const { Prev, onSuccess, ...rest } = props
|
|
15
|
+
|
|
16
|
+
const sendEvent = useSendEvent()
|
|
15
17
|
return (
|
|
16
18
|
<Prev
|
|
17
19
|
{...rest}
|
|
18
20
|
onSuccess={(orderNumber, cart) => {
|
|
19
|
-
sendEvent('purchase',
|
|
21
|
+
sendEvent('purchase', cartToPurchase(orderNumber, cart))
|
|
20
22
|
return onSuccess?.(orderNumber, cart)
|
|
21
23
|
}}
|
|
22
24
|
/>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { useRemoveItemFromCart as useRemoveItemFromCartBase } from '@graphcommerce/magento-cart-items'
|
|
2
2
|
import type { FunctionPlugin, PluginConfig } from '@graphcommerce/next-config'
|
|
3
|
-
import {
|
|
3
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
4
4
|
import { cartItemToRemoveFromCart } from '../mapping/cartItemToRemoveFromCart/cartToRemoveFromCart'
|
|
5
5
|
|
|
6
6
|
export const config: PluginConfig = {
|
|
@@ -11,8 +11,9 @@ export const config: PluginConfig = {
|
|
|
11
11
|
export const useRemoveItemFromCart: FunctionPlugin<typeof useRemoveItemFromCartBase> = (
|
|
12
12
|
usePrev,
|
|
13
13
|
props,
|
|
14
|
-
) =>
|
|
15
|
-
|
|
14
|
+
) => {
|
|
15
|
+
const sendEvent = useSendEvent()
|
|
16
|
+
return usePrev({
|
|
16
17
|
...props,
|
|
17
18
|
onComplete: (result, variables) => {
|
|
18
19
|
if (!result.errors) {
|
|
@@ -24,3 +25,4 @@ export const useRemoveItemFromCart: FunctionPlugin<typeof useRemoveItemFromCartB
|
|
|
24
25
|
return props.onComplete?.(result, variables)
|
|
25
26
|
},
|
|
26
27
|
})
|
|
28
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ShippingMethodFormProps } from '@graphcommerce/magento-cart-shipping-method'
|
|
2
2
|
import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
|
|
3
|
-
import {
|
|
3
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
4
4
|
import { cartToAddShippingInfo } from '../mapping/cartToAddShippingInfo/cartToAddShippingInfo'
|
|
5
5
|
|
|
6
6
|
export const config: PluginConfig = {
|
|
@@ -10,6 +10,8 @@ export const config: PluginConfig = {
|
|
|
10
10
|
|
|
11
11
|
export function ShippingMethodForm(props: PluginProps<ShippingMethodFormProps>) {
|
|
12
12
|
const { Prev, onComplete, ...rest } = props
|
|
13
|
+
|
|
14
|
+
const sendEvent = useSendEvent()
|
|
13
15
|
return (
|
|
14
16
|
<Prev
|
|
15
17
|
{...rest}
|
|
@@ -17,7 +19,7 @@ export function ShippingMethodForm(props: PluginProps<ShippingMethodFormProps>)
|
|
|
17
19
|
if (result.data?.setShippingMethodsOnCart?.cart) {
|
|
18
20
|
sendEvent(
|
|
19
21
|
'add_shipping_info',
|
|
20
|
-
cartToAddShippingInfo(result.data
|
|
22
|
+
cartToAddShippingInfo(result.data.setShippingMethodsOnCart.cart),
|
|
21
23
|
)
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { UpdateItemQuantityProps } from '@graphcommerce/magento-cart-items'
|
|
2
2
|
import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
|
|
3
|
-
import {
|
|
3
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
4
4
|
import { cartItemToDatalayerItem } from '../mapping/cartItemToDatalayerItem/cartItemToDatalayerItem'
|
|
5
5
|
import { datalayerItemsToCurrencyValue } from '../mapping/datalayerItemsToCurrencyValue/datalayerItemsToCurrencyValue'
|
|
6
6
|
|
|
@@ -16,6 +16,7 @@ export const config: PluginConfig = {
|
|
|
16
16
|
export function UpdateItemQuantity(props: PluginProps<UpdateItemQuantityProps>) {
|
|
17
17
|
const { Prev, formOptions, quantity, ...rest } = props
|
|
18
18
|
|
|
19
|
+
const sendEvent = useSendEvent()
|
|
19
20
|
return (
|
|
20
21
|
<Prev
|
|
21
22
|
{...rest}
|
|
@@ -33,7 +34,7 @@ export function UpdateItemQuantity(props: PluginProps<UpdateItemQuantityProps>)
|
|
|
33
34
|
|
|
34
35
|
if (!itemInCart?.quantity || diffQuantity === 0) return original
|
|
35
36
|
|
|
36
|
-
const items = [{ ...cartItemToDatalayerItem(itemInCart), quantity: absQuantity }]
|
|
37
|
+
const items = [{ ...cartItemToDatalayerItem(itemInCart, 0), quantity: absQuantity }]
|
|
37
38
|
sendEvent(diffQuantity < 0 ? 'remove_from_cart' : 'add_to_cart', {
|
|
38
39
|
...datalayerItemsToCurrencyValue(items),
|
|
39
40
|
items,
|
|
File without changes
|
|
@@ -2,7 +2,7 @@ import type { ProductPageMetaProps } from '@graphcommerce/magento-product'
|
|
|
2
2
|
import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
|
|
3
3
|
import { useMemoObject } from '@graphcommerce/next-ui'
|
|
4
4
|
import { useEffect } from 'react'
|
|
5
|
-
import {
|
|
5
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
6
6
|
import { productToViewItem } from '../mapping/productToViewItem/productToViewItem'
|
|
7
7
|
|
|
8
8
|
export const config: PluginConfig = {
|
|
@@ -10,12 +10,13 @@ export const config: PluginConfig = {
|
|
|
10
10
|
type: 'component',
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
/** When a product
|
|
13
|
+
/** When a product detail page is viewed, send a Google Analytics event */
|
|
14
14
|
export function ProductPageMeta(props: PluginProps<ProductPageMetaProps>) {
|
|
15
15
|
const { Prev, product } = props
|
|
16
16
|
|
|
17
|
+
const sendEvent = useSendEvent()
|
|
17
18
|
const viewItem = useMemoObject(productToViewItem(product))
|
|
18
|
-
useEffect(() => sendEvent('view_item', viewItem), [viewItem])
|
|
19
|
+
useEffect(() => sendEvent('view_item', viewItem), [sendEvent, viewItem])
|
|
19
20
|
|
|
20
21
|
return <Prev {...props} />
|
|
21
22
|
}
|
|
@@ -3,7 +3,7 @@ import type { PluginConfig, PluginProps } from '@graphcommerce/next-config'
|
|
|
3
3
|
import { useEventCallback } from '@mui/material'
|
|
4
4
|
import { useEffect } from 'react'
|
|
5
5
|
import { onCLS, onFCP, onFID, onINP, onLCP, onTTFB, Metric } from 'web-vitals/attribution'
|
|
6
|
-
import {
|
|
6
|
+
import { useSendEvent } from '../api/sendEvent'
|
|
7
7
|
|
|
8
8
|
export const config: PluginConfig = {
|
|
9
9
|
type: 'component',
|
|
@@ -19,6 +19,7 @@ export const config: PluginConfig = {
|
|
|
19
19
|
export function FramerNextPages(props: PluginProps<PagesProps>) {
|
|
20
20
|
const { Prev, ...rest } = props
|
|
21
21
|
|
|
22
|
+
const sendEvent = useSendEvent()
|
|
22
23
|
const sendCoreWebVitals = useEventCallback((m: Metric, debug_target?: string | undefined) => {
|
|
23
24
|
sendEvent(`cwv_${m.name.toLowerCase()}`, {
|
|
24
25
|
value: m.delta,
|
|
@@ -1,10 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
}
|