diff --git a/packages/core/src/Layout.tsx b/packages/core/src/Layout.tsx index 1f1dd96b4c..eea429341e 100644 --- a/packages/core/src/Layout.tsx +++ b/packages/core/src/Layout.tsx @@ -1,9 +1,9 @@ -import { type PropsWithChildren } from 'react' +import type { PropsWithChildren, ReactElement } from 'react' import { usePageViewEvent } from './sdk/analytics/hooks/usePageViewEvent' function Layout({ children }: PropsWithChildren) { - usePageViewEvent() + usePageViewEvent((children as ReactElement)?.props) return <>{children} } diff --git a/packages/core/src/sdk/analytics/hooks/usePageViewEvent.ts b/packages/core/src/sdk/analytics/hooks/usePageViewEvent.ts index ba957ff129..db5b4a2161 100644 --- a/packages/core/src/sdk/analytics/hooks/usePageViewEvent.ts +++ b/packages/core/src/sdk/analytics/hooks/usePageViewEvent.ts @@ -2,7 +2,7 @@ import type { PageViewEvent } from '@faststore/sdk' import { useRouter } from 'next/router' import { useCallback, useEffect } from 'react' -export const usePageViewEvent = () => { +export const usePageViewEvent = (props?: any) => { const sendPageViewEvent = useCallback(() => { import('@faststore/sdk').then(({ sendAnalyticsEvent }) => { sendAnalyticsEvent({ @@ -11,10 +11,11 @@ export const usePageViewEvent = () => { page_title: document.title, page_location: location.href, send_page_view: true, + ...props, }, }) }) - }, []) + }, [props]) const router = useRouter() diff --git a/packages/core/src/sdk/analytics/platform/vtex/index.ts b/packages/core/src/sdk/analytics/platform/vtex/index.ts index e0cfd3a4f4..c554d0c63e 100644 --- a/packages/core/src/sdk/analytics/platform/vtex/index.ts +++ b/packages/core/src/sdk/analytics/platform/vtex/index.ts @@ -1,10 +1,11 @@ import type { AnalyticsEvent } from '@faststore/sdk' import handleSearchEvent from './search' +import handleRCEvent from './rc' export default function sendEvent(event: AnalyticsEvent) { // VTEX RC - window?.sendrc?.(event.name, event.params) + handleRCEvent(event) // VTEX Intelligent Search handleSearchEvent(event) diff --git a/packages/core/src/sdk/analytics/platform/vtex/rc.ts b/packages/core/src/sdk/analytics/platform/vtex/rc.ts new file mode 100644 index 0000000000..602597939d --- /dev/null +++ b/packages/core/src/sdk/analytics/platform/vtex/rc.ts @@ -0,0 +1,111 @@ +import { AnalyticsEvent, PageViewEvent } from '@faststore/sdk' +import { + CategoryView, + DepartmentView, + HomeView, + IntelligentSearchQueryEvent, + InternalSiteSearchView, + OtherView, + ProductView, + SearchSelectItemEvent, +} from '../../types' + +const EventNames = { + OTHER_VIEW: 'otherView', + HOME_VIEW: 'homeView', + CATEGORY_VIEW: 'categoryView', + DEPARTMENT_VIEW: 'departmentView', + INTERNAL_SITE_SEARCH_VIEW: 'internalSiteSearchView', + PRODUCT_VIEW: 'productView', +} as const + +type EventNames = (typeof EventNames)[keyof typeof EventNames] +type EventParams = + | HomeView + | CategoryView + | DepartmentView + | InternalSiteSearchView + | ProductView + | OtherView + +const sendEvent = (eventName: EventNames, eventParams: EventParams) => { + window?.sendrc?.(eventName, eventParams) +} + +const handleEvent = ( + event: AnalyticsEvent | SearchSelectItemEvent | IntelligentSearchQueryEvent +) => { + let eventParams + switch (event.name) { + //TODO: add missing events - eg 'add_to_cart' and 'view_cart' + case 'page_view': + eventParams = (event as PageViewEvent).params + switch (eventParams.type) { + case 'plp': + const collection = eventParams?.data?.collection + const collectionCategoryList = + collection?.breadcrumbList?.itemListElement + if (collectionCategoryList.length > 1) { + // console.log('✨ Category View Event:', eventParams) + sendEvent(EventNames.CATEGORY_VIEW, { + //TODO: add missing arg - categoryId + departmentId: collection?.id, + departmentName: collectionCategoryList[0]?.name, + categoryName: + collectionCategoryList[collectionCategoryList.length - 1]?.name, + }) + } else { + // console.log('✨ Department View Event:', eventParams) + sendEvent(EventNames.DEPARTMENT_VIEW, { + departmentId: collection?.id, + departmentName: collectionCategoryList[0]?.name, + }) + } + break + case 'pdp': + // console.log('✨ Product View Event: ', eventParams) + const product = eventParams?.data?.product + const offers = product?.offers + const productCategoryList = product?.breadcrumbList?.itemListElement + sendEvent(EventNames.PRODUCT_VIEW, { + //TODO: add missing args - skuStockOutFromProductDetail, productReferenceId, + // productEans, skuStocks, productBrandId, productDepartmentId, + // productCategoryId, productListPrice, sellerIds + productId: product?.isVariantOf?.productGroupID, + productName: product?.isVariantOf?.name, + productBrandName: product?.brand?.name, + productDepartmentName: productCategoryList + ? productCategoryList[0]?.name + : '', + productCategoryName: + productCategoryList.length > 1 + ? productCategoryList[productCategoryList.length - 2]?.name + : '', + productPrice: offers?.price, + sellerId: offers?.seller?.id, + }) + break + default: + if (eventParams?.page?.type === 'home') { + // console.log('✨ Home View Event:', eventParams) + sendEvent(EventNames.HOME_VIEW, {}) + } else { + // console.log('✨ Other View Event:', eventParams) + sendEvent(EventNames.OTHER_VIEW, {}) + } + } + break + case 'intelligent_search_query': + console.log('✨ Internal Site Search View Event:', event) + eventParams = (event as IntelligentSearchQueryEvent).params + sendEvent(EventNames.INTERNAL_SITE_SEARCH_VIEW, { + siteSearchTerm: eventParams.term, + siteSearchForm: eventParams.url, + siteSearchResults: eventParams.totalCount, + }) + break + default: + } +} + +export default handleEvent diff --git a/packages/core/src/sdk/analytics/types.ts b/packages/core/src/sdk/analytics/types.ts index 5cbdb7e698..01f7bd5fe9 100644 --- a/packages/core/src/sdk/analytics/types.ts +++ b/packages/core/src/sdk/analytics/types.ts @@ -34,3 +34,52 @@ export interface IntelligentSearchQueryEvent { name: 'intelligent_search_query' params: IntelligentSearchQueryParams } + +/** + * RC event types + * Types copied from Request Capture App: https://github.com/vtex/request-capture-app/blob/1becac32c002cb03a57bf36c8a7f9400eab8b933/react/typings/rcevents.d.ts + */ + +export interface HomeView {} + +export interface CategoryView { + departmentId?: string + departmentName?: string + categoryId?: string + categoryName?: string +} + +export interface DepartmentView { + departmentId?: string + departmentName?: string +} + +export interface InternalSiteSearchView { + siteSearchTerm?: string // ex: "areia" + siteSearchForm?: string // ex: "/gatos/ambiente--gatos/caixa-de-areia/areia?PS=20" + siteSearchCategory?: string // ex: "10000283" + siteSearchResults?: number // ex: 26 +} + +type SkuId = string + +export interface ProductView { + skuStockOutFromProductDetail: string[] + productId: string + productReferenceId: string + productEans: string[] + skuStocks: Record + productName: string + productBrandId: string + productBrandName: string + productDepartmentId: string + productDepartmentName: string + productCategoryId: string + productCategoryName: string + productListPrice: number + productPrice: number + sellerId: string + sellerIds: string // ex: "00443713,04412311,1" +} + +export interface OtherView {} diff --git a/packages/sdk/src/analytics/events/page_view.ts b/packages/sdk/src/analytics/events/page_view.ts index ab9cf18e6b..72315bfeb1 100644 --- a/packages/sdk/src/analytics/events/page_view.ts +++ b/packages/sdk/src/analytics/events/page_view.ts @@ -2,6 +2,7 @@ export interface PageViewParams { page_title?: string, page_location?: string, send_page_view?: boolean, + [key: string]: any } export interface PageViewEvent {