cloudcommerce 0.33.1 → 0.33.3
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 +22 -0
- package/ecomplus-stores/barra-doce/functions/many/package.json +3 -3
- package/ecomplus-stores/barra-doce/functions/ssr/package.json +6 -6
- package/ecomplus-stores/barra-doce/functions/with-apps/package.json +3 -3
- package/ecomplus-stores/barra-doce/package.json +2 -2
- package/ecomplus-stores/monocard/functions/many/package.json +3 -3
- package/ecomplus-stores/monocard/functions/ssr/package.json +6 -6
- package/ecomplus-stores/monocard/functions/with-apps/package.json +3 -3
- package/ecomplus-stores/monocard/package.json +2 -2
- package/package.json +6 -6
- package/packages/api/package.json +1 -1
- package/packages/apps/affilate-program/package.json +1 -1
- package/packages/apps/correios/package.json +2 -2
- package/packages/apps/custom-payment/package.json +1 -1
- package/packages/apps/custom-shipping/package.json +1 -1
- package/packages/apps/datafrete/package.json +2 -2
- package/packages/apps/discounts/package.json +1 -1
- package/packages/apps/emails/package.json +1 -1
- package/packages/apps/fb-conversions/package.json +1 -1
- package/packages/apps/flash-courier/package.json +2 -2
- package/packages/apps/frenet/package.json +2 -2
- package/packages/apps/galaxpay/package.json +2 -2
- package/packages/apps/google-analytics/package.json +2 -2
- package/packages/apps/jadlog/package.json +2 -2
- package/packages/apps/loyalty-points/package.json +1 -1
- package/packages/apps/mandae/package.json +2 -2
- package/packages/apps/melhor-envio/package.json +2 -2
- package/packages/apps/mercadopago/package.json +2 -2
- package/packages/apps/pagarme/package.json +2 -2
- package/packages/apps/pagarme-v5/package.json +2 -2
- package/packages/apps/paghiper/package.json +2 -2
- package/packages/apps/pix/package.json +2 -2
- package/packages/apps/tiny-erp/package.json +2 -2
- package/packages/apps/webhooks/package.json +2 -2
- package/packages/cli/package.json +1 -1
- package/packages/config/package.json +1 -1
- package/packages/emails/package.json +2 -2
- package/packages/eslint/package.json +4 -4
- package/packages/events/package.json +1 -1
- package/packages/feeds/package.json +1 -1
- package/packages/firebase/package.json +1 -1
- package/packages/i18n/package.json +1 -1
- package/packages/modules/package.json +2 -2
- package/packages/passport/package.json +1 -1
- package/packages/ssr/lib/analytics-events.js +26 -5
- package/packages/ssr/lib/analytics-events.js.map +1 -1
- package/packages/ssr/lib/firebase/serve-storefront.js +16 -12
- package/packages/ssr/lib/firebase/serve-storefront.js.map +1 -1
- package/packages/ssr/package.json +2 -1
- package/packages/ssr/src/analytics-events.ts +29 -5
- package/packages/ssr/src/firebase/serve-storefront.ts +17 -12
- package/packages/storefront/package.json +6 -5
- package/packages/storefront/src/analytics/event-to-fbq.ts +77 -10
- package/packages/storefront/src/analytics/event-to-ttq.ts +15 -0
- package/packages/storefront/src/helpers/sf-utils.ts +15 -0
- package/packages/storefront/src/lib/composables/use-product-card.ts +3 -2
- package/packages/storefront/src/lib/scripts/push-analytics-events.ts +31 -25
- package/packages/storefront/src/lib/state/shopping-cart.ts +35 -2
- package/packages/storefront/src/lib/state/use-analytics.ts +116 -75
- package/packages/test-base/package.json +1 -1
- package/packages/types/package.json +1 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { Products, CartSet, SearchItem } from '@cloudcommerce/api/types';
|
|
2
|
-
import { computed } from 'vue';
|
|
2
|
+
import { computed, watch } from 'vue';
|
|
3
|
+
import mitt from 'mitt';
|
|
3
4
|
import useStorage from '@@sf/state/use-storage';
|
|
4
5
|
import addItem from '@@sf/state/shopping-cart/add-cart-item';
|
|
5
6
|
import parseProduct from '@@sf/state/shopping-cart/parse-product';
|
|
6
7
|
|
|
8
|
+
type CartItem = CartSet['items'][0];
|
|
7
9
|
const storageKey = 'ecomShoppingCart';
|
|
8
10
|
const emptyCart = {
|
|
9
11
|
items: [],
|
|
@@ -64,7 +66,7 @@ const shoppingCart = computed({
|
|
|
64
66
|
},
|
|
65
67
|
});
|
|
66
68
|
|
|
67
|
-
const addCartItem = (newItem:
|
|
69
|
+
const addCartItem = (newItem: CartItem) => {
|
|
68
70
|
const cartObj = shoppingCart.value;
|
|
69
71
|
const upsertedItem = addItem(cartObj, newItem);
|
|
70
72
|
if (upsertedItem) {
|
|
@@ -97,3 +99,34 @@ export {
|
|
|
97
99
|
parseProduct,
|
|
98
100
|
addProductToCart,
|
|
99
101
|
};
|
|
102
|
+
|
|
103
|
+
type CartEvent = {
|
|
104
|
+
addCartItem: CartItem,
|
|
105
|
+
removeCartItem: CartItem,
|
|
106
|
+
};
|
|
107
|
+
const cartEmitter = mitt<CartEvent>();
|
|
108
|
+
const cloneItems = () => shoppingCart.value.items.map((item) => ({ ...item }));
|
|
109
|
+
let oldItems = cloneItems();
|
|
110
|
+
watch(shoppingCart, ({ items }) => {
|
|
111
|
+
['addCartItem' as const, 'removeCartItem' as const].forEach((evName) => {
|
|
112
|
+
const isAdd = evName === 'addCartItem';
|
|
113
|
+
const baseItems = isAdd ? items : oldItems;
|
|
114
|
+
const compareItems = isAdd ? oldItems : items;
|
|
115
|
+
baseItems.forEach((baseItem) => {
|
|
116
|
+
if (!baseItem.quantity) return;
|
|
117
|
+
const compareItem = compareItems.find(({ _id }) => _id === baseItem._id);
|
|
118
|
+
if (compareItem && baseItem.quantity > compareItem.quantity) {
|
|
119
|
+
cartEmitter.emit(evName, {
|
|
120
|
+
...baseItem,
|
|
121
|
+
quantity: baseItem.quantity - (compareItem?.quantity || 0),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
oldItems = cloneItems();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
export const cartEvents = {
|
|
130
|
+
on: cartEmitter.on,
|
|
131
|
+
off: cartEmitter.off,
|
|
132
|
+
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Products, Carts, SearchItem } from '@cloudcommerce/types';
|
|
2
|
+
import { watchOnce } from '@vueuse/core';
|
|
2
3
|
import { price as getPrice, name as getName } from '@ecomplus/utils';
|
|
3
|
-
import { customer } from '@@sf/state/customer-session';
|
|
4
|
+
import { customer, isLogged } from '@@sf/state/customer-session';
|
|
5
|
+
import { cartEvents } from '@@sf/state/shopping-cart';
|
|
4
6
|
import utm from '@@sf/scripts/session-utm';
|
|
5
7
|
|
|
6
8
|
export const trackingIds: {
|
|
@@ -13,93 +15,53 @@ export const trackingIds: {
|
|
|
13
15
|
session_id?: string,
|
|
14
16
|
} = {};
|
|
15
17
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
// `page_view` params not typed
|
|
19
|
+
// https://developers.google.com/tag-platform/gtagjs/reference/events#page_view
|
|
20
|
+
type PageViewParams = {
|
|
21
|
+
page_location: string,
|
|
22
|
+
client_id?: string,
|
|
23
|
+
language: string,
|
|
24
|
+
page_encoding?: string,
|
|
25
|
+
page_title: string,
|
|
26
|
+
user_agent: string,
|
|
22
27
|
};
|
|
23
|
-
|
|
24
28
|
const pageViewState = {} as {
|
|
25
29
|
resolve: ((...args: any[]) => void) | null | undefined,
|
|
26
30
|
waiting: Promise<unknown> | undefined,
|
|
31
|
+
params: PageViewParams | undefined,
|
|
32
|
+
};
|
|
33
|
+
const resetPageViewPromise = () => {
|
|
34
|
+
if (pageViewState.resolve) return;
|
|
35
|
+
pageViewState.waiting = new Promise((resolve) => {
|
|
36
|
+
pageViewState.resolve = resolve;
|
|
37
|
+
});
|
|
27
38
|
};
|
|
28
39
|
if (!import.meta.env.SSR) {
|
|
29
|
-
const resetPageViewPromise = () => {
|
|
30
|
-
if (pageViewState.resolve) return;
|
|
31
|
-
pageViewState.waiting = new Promise((resolve) => {
|
|
32
|
-
pageViewState.resolve = resolve;
|
|
33
|
-
});
|
|
34
|
-
};
|
|
35
40
|
resetPageViewPromise();
|
|
36
|
-
document.addEventListener('astro:beforeload', resetPageViewPromise);
|
|
37
|
-
const {
|
|
38
|
-
gtag,
|
|
39
|
-
GTAG_TAG_ID,
|
|
40
|
-
GA_TRACKING_ID,
|
|
41
|
-
} = window as { [k:string]: any, gtag?: Gtag.Gtag };
|
|
42
|
-
const tagId = GTAG_TAG_ID || GA_TRACKING_ID;
|
|
43
|
-
if (tagId && typeof gtag === 'function') {
|
|
44
|
-
['client_id', 'session_id', 'gclid'].forEach((key) => {
|
|
45
|
-
gtag('get', tagId, key, (id) => {
|
|
46
|
-
trackingIds[key === 'gclid' ? key : `g_${key}`] = id;
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
const url = new URL(window.location.toString());
|
|
51
|
-
['gclid', 'fbclid'].forEach((key) => {
|
|
52
|
-
const id = trackingIds[key] || url.searchParams.get(key);
|
|
53
|
-
if (id) {
|
|
54
|
-
trackingIds[key] = id;
|
|
55
|
-
sessionStorage.setItem(`analytics_${key}`, id);
|
|
56
|
-
} else {
|
|
57
|
-
trackingIds[key] = sessionStorage.getItem(`analytics_${key}`) || undefined;
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
const cookieNames = ['_fbp'];
|
|
61
|
-
if (!trackingIds.fbclid) cookieNames.push('_fbc');
|
|
62
|
-
if (!trackingIds.g_client_id) cookieNames.push('_ga');
|
|
63
|
-
cookieNames.forEach((cookieName) => {
|
|
64
|
-
document.cookie.split(';').forEach((cookie) => {
|
|
65
|
-
const [key, value] = cookie.split('=');
|
|
66
|
-
if (key.trim() === cookieName && value) {
|
|
67
|
-
switch (cookieName) {
|
|
68
|
-
case '_fbp': trackingIds.fbp = value; break;
|
|
69
|
-
case '_fbc': trackingIds.fbclid = value; break;
|
|
70
|
-
case '_ga': trackingIds.g_client_id = value.substring(6); break;
|
|
71
|
-
default:
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
['client_id', 'session_id'].forEach((key) => {
|
|
77
|
-
const storage = key === 'client_id' ? localStorage : sessionStorage;
|
|
78
|
-
const storedValue = storage.getItem(`analytics_${key}`);
|
|
79
|
-
if (storedValue) {
|
|
80
|
-
trackingIds[key] = storedValue;
|
|
81
|
-
} else {
|
|
82
|
-
trackingIds[key] = trackingIds[`g_${key}`]
|
|
83
|
-
|| `${Math.ceil(Math.random() * 1000000)}.${Math.ceil(Math.random() * 1000000)}`;
|
|
84
|
-
}
|
|
85
|
-
storage.setItem(`analytics_${key}`, trackingIds[key]);
|
|
86
|
-
});
|
|
87
41
|
}
|
|
88
42
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
43
|
+
export const getPageViewParams = () => {
|
|
44
|
+
return {
|
|
45
|
+
page_location: window.location.toString(),
|
|
46
|
+
language: globalThis.$storefront.settings.lang || 'pt_br',
|
|
47
|
+
page_title: document.title,
|
|
48
|
+
user_agent: navigator.userAgent,
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const getAnalyticsContext = () => {
|
|
53
|
+
return {
|
|
54
|
+
...(pageViewState.params || getPageViewParams()),
|
|
55
|
+
...trackingIds,
|
|
56
|
+
user_id: customer.value._id,
|
|
57
|
+
utm,
|
|
58
|
+
};
|
|
98
59
|
};
|
|
99
60
|
|
|
100
61
|
export const GTAG_EVENT_TYPE = 'GtagEvent';
|
|
101
62
|
|
|
102
63
|
export type GtagEventMessage = typeof trackingIds &
|
|
64
|
+
PageViewParams &
|
|
103
65
|
{ utm: typeof utm } &
|
|
104
66
|
{
|
|
105
67
|
type: typeof GTAG_EVENT_TYPE,
|
|
@@ -118,7 +80,7 @@ let defaultItemsList = '';
|
|
|
118
80
|
|
|
119
81
|
export const emitGtagEvent = async <N extends Gtag.EventNames = 'view_item'>(
|
|
120
82
|
name: N,
|
|
121
|
-
_params: N extends 'page_view' ? PageViewParams : Gtag.EventParams
|
|
83
|
+
_params: N extends 'page_view' ? PageViewParams : Gtag.EventParams,
|
|
122
84
|
) => {
|
|
123
85
|
if (import.meta.env.SSR) return;
|
|
124
86
|
const params = _params as Gtag.EventParams;
|
|
@@ -148,6 +110,7 @@ export const emitGtagEvent = async <N extends Gtag.EventNames = 'view_item'>(
|
|
|
148
110
|
}
|
|
149
111
|
}
|
|
150
112
|
if (pageViewState.resolve) {
|
|
113
|
+
pageViewState.params = (_params as PageViewParams);
|
|
151
114
|
pageViewState.resolve();
|
|
152
115
|
pageViewState.resolve = null;
|
|
153
116
|
}
|
|
@@ -156,6 +119,14 @@ export const emitGtagEvent = async <N extends Gtag.EventNames = 'view_item'>(
|
|
|
156
119
|
if (name === 'view_item') {
|
|
157
120
|
params.items?.forEach((item) => {
|
|
158
121
|
if (item.index !== undefined) return;
|
|
122
|
+
if (!item.item_list_id && !item.item_list_name) {
|
|
123
|
+
const { apiContext } = window.$storefront;
|
|
124
|
+
// @ts-ignore
|
|
125
|
+
if (apiContext?.doc._id === item.object_id) {
|
|
126
|
+
item.item_list_id = 'product-page';
|
|
127
|
+
item.item_list_name = 'Product page';
|
|
128
|
+
}
|
|
129
|
+
}
|
|
159
130
|
const listKey = item.item_list_id
|
|
160
131
|
|| item.item_list_name
|
|
161
132
|
|| defaultItemsList;
|
|
@@ -207,6 +178,9 @@ export const getGtagItem = (product: Partial<Products> | SearchItem | CartItem)
|
|
|
207
178
|
item_name: name,
|
|
208
179
|
item_id: product.sku,
|
|
209
180
|
price: Math.round(getPrice(product) * 100) / 100,
|
|
181
|
+
// https://developers.google.com/analytics/devguides/collection/ga4/item-scoped-ecommerce#add_an_item-scoped_custom_parameter
|
|
182
|
+
// @ts-ignore
|
|
183
|
+
object_id: product._id,
|
|
210
184
|
};
|
|
211
185
|
if (variants && variants.length) {
|
|
212
186
|
item.item_variant = variants.join(' / ');
|
|
@@ -240,3 +214,70 @@ export const getGtagItem = (product: Partial<Products> | SearchItem | CartItem)
|
|
|
240
214
|
}
|
|
241
215
|
return item;
|
|
242
216
|
};
|
|
217
|
+
|
|
218
|
+
export const useAnalytics = () => {
|
|
219
|
+
document.addEventListener('astro:beforeload', resetPageViewPromise);
|
|
220
|
+
if (isLogged.value) {
|
|
221
|
+
emitGtagEvent('login', {});
|
|
222
|
+
} else {
|
|
223
|
+
watchOnce(isLogged, () => emitGtagEvent('login', {}));
|
|
224
|
+
}
|
|
225
|
+
cartEvents.on('*', (evName, cartItem) => {
|
|
226
|
+
emitGtagEvent(
|
|
227
|
+
evName === 'addCartItem' ? 'add_to_cart' : 'remove_from_cart',
|
|
228
|
+
{ items: [getGtagItem(cartItem)] },
|
|
229
|
+
);
|
|
230
|
+
});
|
|
231
|
+
const {
|
|
232
|
+
gtag,
|
|
233
|
+
GTAG_TAG_ID,
|
|
234
|
+
GA_TRACKING_ID,
|
|
235
|
+
} = window as { [k:string]: any, gtag?: Gtag.Gtag };
|
|
236
|
+
const tagId = GTAG_TAG_ID || GA_TRACKING_ID;
|
|
237
|
+
if (tagId && typeof gtag === 'function') {
|
|
238
|
+
['client_id', 'session_id', 'gclid'].forEach((key) => {
|
|
239
|
+
gtag('get', tagId, key, (id) => {
|
|
240
|
+
trackingIds[key === 'gclid' ? key : `g_${key}`] = id;
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
const url = new URL(window.location.toString());
|
|
245
|
+
['gclid', 'fbclid'].forEach((key) => {
|
|
246
|
+
const id = trackingIds[key] || url.searchParams.get(key);
|
|
247
|
+
if (id) {
|
|
248
|
+
trackingIds[key] = id;
|
|
249
|
+
sessionStorage.setItem(`analytics_${key}`, id);
|
|
250
|
+
} else {
|
|
251
|
+
trackingIds[key] = sessionStorage.getItem(`analytics_${key}`) || undefined;
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
const cookieNames = ['_fbp'];
|
|
255
|
+
if (!trackingIds.fbclid) cookieNames.push('_fbc');
|
|
256
|
+
if (!trackingIds.g_client_id) cookieNames.push('_ga');
|
|
257
|
+
cookieNames.forEach((cookieName) => {
|
|
258
|
+
document.cookie.split(';').forEach((cookie) => {
|
|
259
|
+
const [key, value] = cookie.split('=');
|
|
260
|
+
if (key.trim() === cookieName && value) {
|
|
261
|
+
switch (cookieName) {
|
|
262
|
+
case '_fbp': trackingIds.fbp = value; break;
|
|
263
|
+
case '_fbc': trackingIds.fbclid = value; break;
|
|
264
|
+
case '_ga': trackingIds.g_client_id = value.substring(6); break;
|
|
265
|
+
default:
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
['client_id', 'session_id'].forEach((key) => {
|
|
271
|
+
const storage = key === 'client_id' ? localStorage : sessionStorage;
|
|
272
|
+
const storedValue = storage.getItem(`analytics_${key}`);
|
|
273
|
+
if (storedValue) {
|
|
274
|
+
trackingIds[key] = storedValue;
|
|
275
|
+
} else {
|
|
276
|
+
trackingIds[key] = trackingIds[`g_${key}`]
|
|
277
|
+
|| `${Math.ceil(Math.random() * 1000000)}.${Math.ceil(Math.random() * 1000000)}`;
|
|
278
|
+
}
|
|
279
|
+
storage.setItem(`analytics_${key}`, trackingIds[key]);
|
|
280
|
+
});
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
export default useAnalytics;
|