Skip to content
This repository has been archived by the owner on Mar 3, 2023. It is now read-only.

Commit

Permalink
Adding analytics docs (#138)
Browse files Browse the repository at this point in the history
* Adding analytics docs basic setup

* Fix doc typing to use the magic generated one

* clean up eslint errors and ts errors

* break functions into each own files for documentation

* move fn back to analytics file and fix up doc

* fix up test

* add more docs

* create doc for constants

* more updates

* add changeset

* fix types

* format

* lint

* rename to shopify constants

* fix type again

* add related docs

* fix type in test

* fix types

* add type for other const

* One more fix

---------

Co-authored-by: Helen Lin <helen.lin@shopify.com>
  • Loading branch information
frehner and wizardlyhel committed Jan 30, 2023
1 parent 804365f commit 8d8ab13
Show file tree
Hide file tree
Showing 30 changed files with 1,843 additions and 150 deletions.
11 changes: 11 additions & 0 deletions .changeset/sour-months-complain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@shopify/storefront-kit-react': patch
---

## Breaking Changes on Shopify analytics components

- `useShopifyCookies` - if hasUserConsent is `false`, no cookies will be set
- `sendShopifyAnalytics` - if `hasUserConsent` is false, no analytics will be sent
- `ShopifyAppSource` got rename to `ShopifySalesChannel`
- `getClientBrowserParameters` returns empty string for each field key if run on server
- Added documents on analytics components
1,174 changes: 1,152 additions & 22 deletions packages/react/docs/generated/generated_docs_data.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@
"@graphql-codegen/introspection": "2.2.3",
"@graphql-codegen/typescript": "^2.8.7",
"@ladle/react": "^2.4.5",
"@shopify/generate-docs": "^0.6.0",
"@shopify/generate-docs": "^0.8.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^14.4.3",
Expand Down
49 changes: 46 additions & 3 deletions packages/react/src/analytics-constants.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export const AnalyticsEventName = {
export const AnalyticsEventName: AnalyticsEventName = {
PAGE_VIEW: 'PAGE_VIEW',
ADD_TO_CART: 'ADD_TO_CART',
} as const;

export const AnalyticsPageType = {
export const AnalyticsPageType: AnalyticsPageType = {
article: 'article',
blog: 'blog',
captcha: 'captcha',
Expand All @@ -28,7 +28,7 @@ export const AnalyticsPageType = {
search: 'search',
} as const;

export const ShopifyAppSource = {
export const ShopifySalesChannel: ShopifySalesChannel = {
hydrogen: 'hydrogen',
headless: 'headless',
} as const;
Expand All @@ -37,3 +37,46 @@ export const ShopifyAppId = {
hydrogen: '6167201',
headless: '12875497473',
} as const;

/**
* These duplicated interface declaration is so that we can generate proper documentation
* for these public facing constants
*/
interface AnalyticsEventName {
/** Page view */
PAGE_VIEW: 'PAGE_VIEW';
/** Add to cart */
ADD_TO_CART: 'ADD_TO_CART';
}

interface AnalyticsPageType {
article: 'article';
blog: 'blog';
captcha: 'captcha';
cart: 'cart';
collection: 'collection';
customersAccount: 'customers/account';
customersActivateAccount: 'customers/activate_account';
customersAddresses: 'customers/addresses';
customersLogin: 'customers/login';
customersOrder: 'customers/order';
customersRegister: 'customers/register';
customersResetPassword: 'customers/reset_password';
giftCard: 'gift_card';
home: 'index';
listCollections: 'list-collections';
forbidden: '403';
notFound: '404';
page: 'page';
password: 'password';
product: 'product';
policy: 'policy';
search: 'search';
}

interface ShopifySalesChannel {
/** Shopify Hydrogen sales channel */
hydrogen: 'hydrogen';
/** Shopify Headless sales channel */
headless: 'headless';
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {expectType} from 'ts-expect';
import {ShopifyAppSource} from './analytics-constants.js';
import {ShopifySalesChannel} from './analytics-constants.js';
import {
pageView,
addToCart,
Expand All @@ -11,6 +11,7 @@ import {
import type {
ShopifyAnalyticsPayload,
ShopifyMonorailPayload,
ShopifyPageViewPayload,
} from './analytics-types.js';

describe(`analytics schema - custom storefront customer tracking`, () => {
Expand All @@ -30,14 +31,14 @@ describe(`analytics schema - custom storefront customer tracking`, () => {
});

it(`base payload with non-default values`, () => {
const pageViewPayload = {
const pageViewPayload: ShopifyPageViewPayload = {
...BASE_PAYLOAD,
shopId: 'gid://shopify/Shop/2',
hasUserConsent: false,
url: 'https://example.com/fr',
shopifyAppSource: ShopifyAppSource.hydrogen,
shopifySalesChannel: ShopifySalesChannel.hydrogen,
storefrontId: '1',
acceptedLanguage: 'fr',
acceptedLanguage: 'FR',
customerId: '1',
pageType: 'index',
resourceId: 'gid://shopify/Product/1',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
ShopifyAnalyticsProduct,
ShopifyMonorailEvent,
} from './analytics-types.js';
import {AnalyticsPageType, ShopifyAppSource} from './analytics-constants.js';
import {AnalyticsPageType, ShopifySalesChannel} from './analytics-constants.js';
import {addDataIf, schemaWrapper, parseGid} from './analytics-utils.js';
import {buildUUID} from './cookies-utils.js';

Expand Down Expand Up @@ -120,7 +120,7 @@ function formatPayload(
payload: ShopifyAnalyticsPayload
): ShopifyMonorailPayload {
return {
source: payload.shopifyAppSource || ShopifyAppSource.headless,
source: payload.shopifySalesChannel || ShopifySalesChannel.headless,
hydrogenSubchannelId: payload.storefrontId || '0',

is_persistent_cookie: payload.hasUserConsent,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import {expectType} from 'ts-expect';
import {ShopifyAppSource} from './analytics-constants.js';
import {ShopifySalesChannel} from './analytics-constants.js';
import {pageView} from './analytics-schema-trekkie-storefront-page-view.js';
import {BASE_PAYLOAD} from './analytics-schema.test.helpers.js';
import type {ShopifyMonorailPayload} from './analytics-types.js';
import type {
ShopifyAnalyticsPayload,
ShopifyMonorailPayload,
ShopifyPageViewPayload,
} from './analytics-types.js';

describe(`analytics schema - trekkie storefront page view`, () => {
it(`base payload with default values`, () => {
Expand All @@ -28,14 +32,14 @@ describe(`analytics schema - trekkie storefront page view`, () => {
});

it(`base payload with non-default values`, () => {
const pageViewPayload = {
const pageViewPayload: ShopifyPageViewPayload = {
...BASE_PAYLOAD,
hasUserConsent: false,
shopId: 'gid://shopify/Shop/2',
url: 'https://example.com',
shopifyAppSource: ShopifyAppSource.hydrogen,
shopifySalesChannel: ShopifySalesChannel.hydrogen,
storefrontId: '1',
acceptedLanguage: 'fr',
acceptedLanguage: 'FR',
customerId: '1',
pageType: 'product',
resourceId: 'gid://shopify/Product/1',
Expand All @@ -54,7 +58,7 @@ describe(`analytics schema - trekkie storefront page view`, () => {
hydrogenSubchannelId: '1',
isPersistentCookie: false,
pageType: 'product',
contentLanguage: 'fr',
contentLanguage: 'FR',
customerId: '1',
resourceId: 1,
resourceType: 'product',
Expand Down Expand Up @@ -91,7 +95,7 @@ describe(`analytics schema - trekkie storefront page view`, () => {
});
});

export function getForwardedPayload(initPayload: ShopifyMonorailPayload) {
export function getForwardedPayload(initPayload: ShopifyAnalyticsPayload) {
return {
shopId: 1,
uniqToken: initPayload.uniqueToken,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ function formatPayload(
payload: ShopifyPageViewPayload
): ShopifyMonorailPayload {
return {
appClientId: payload.shopifyAppSource
? ShopifyAppId[payload.shopifyAppSource]
appClientId: payload.shopifySalesChannel
? ShopifyAppId[payload.shopifySalesChannel]
: ShopifyAppId.headless,
isMerchantRequest: isMerchantRequest(payload.url),
hydrogenSubchannelId: payload.storefrontId || '0',
Expand Down
8 changes: 6 additions & 2 deletions packages/react/src/analytics-schema.test.helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import {faker} from '@faker-js/faker';
import type {
ShopifyAnalyticsPayload,
ShopifyAnalyticsProduct,
} from './analytics-types.js';

export const BASE_PAYLOAD = {
export const BASE_PAYLOAD: ShopifyAnalyticsPayload = {
hasUserConsent: true,
shopId: 'gid://shopify/Shop/1',
currency: 'USD',
Expand All @@ -16,7 +20,7 @@ export const BASE_PAYLOAD = {
navigationApi: faker.datatype.string(),
};

export const BASE_PRODUCT_PAYLOAD = {
export const BASE_PRODUCT_PAYLOAD: ShopifyAnalyticsProduct = {
productGid: 'gid://shopify/Product/1',
name: faker.datatype.string(),
brand: faker.datatype.string(),
Expand Down
68 changes: 54 additions & 14 deletions packages/react/src/analytics-types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
import type {Product, ProductVariant} from './storefront-api-types.js';
import {AnalyticsEventName, ShopifyAppSource} from './analytics-constants.js';
import type {
CurrencyCode,
LanguageCode,
Product,
ProductVariant,
} from './storefront-api-types.js';
import {
AnalyticsEventName,
ShopifySalesChannel,
} from './analytics-constants.js';
import {SHOPIFY_Y, SHOPIFY_S} from './cart-constants.js';

export type ClientBrowserParameters = {
/** Shopify unique user token: Value of `_shopify_y` cookie. Use `getClientBrowserParameters()` to collect this value. */
uniqueToken: string;
/** Shopify session token: Value of `_shopify_s` cookie. Use `getClientBrowserParameters()` to collect this value. */
visitToken: string;
/** `window.location.href`. Use `getClientBrowserParameters()` to collect this value. */
url: string;
/** `window.location.pathname`. Use `getClientBrowserParameters()` to collect this value. */
path: string;
/** `window.location.search`. Use `getClientBrowserParameters()` to collect this value. */
search: string;
/** `window.location.referrer`. Use `getClientBrowserParameters()` to collect this value. */
referrer: string;
/** `document.title`. Use `getClientBrowserParameters()` to collect this value. */
title: string;
/** `navigator.userAgent`. Use `getClientBrowserParameters()` to collect this value. */
userAgent: string;
/** Navigation type: 'navigate' | 'reload' | 'back_forward' | 'prerender' | 'unknown <number>'. Use `getClientBrowserParameters()` to collect this value. */
navigationType: string;
/** Navigation api: 'PerformanceNavigationTiming' | 'performance.navigation'. Use `getClientBrowserParameters()` to collect this value. */
navigationApi: string;
};

Expand All @@ -27,40 +45,60 @@ export type ShopifyAnalyticsProduct = {
quantity?: number;
};

export type ShopifyAppSources = keyof typeof ShopifyAppSource;
export type AnalyticsEventNames = keyof typeof AnalyticsEventName;

export type ShopifyCommonPayload = ClientBrowserParameters & {
shopifyAppSource?: ShopifyAppSources;
type ShopifyAnalyticsBase = {
/** If we have consent from buyer for data collection */
hasUserConsent: boolean;
/** Shopify shop id in the form of `gid://shopify/Shop/<id>`. */
shopId: string;
currency: string;
/** Currency code. */
currency: CurrencyCode;
/** Shopify storefront id generated by Hydrogen sales channel. */
storefrontId?: string;
acceptedLanguage?: string;
/** Language displayed to buyer. */
acceptedLanguage?: LanguageCode;
/** Shopify sales channel. */
shopifySalesChannel?: ShopifySalesChannels;
/** Shopify customer id in the form of `gid://shopify/Customer/<id>`. */
customerId?: string;
/** Total value of products. */
totalValue?: number;
/** Shopify products. */
products?: ShopifyAnalyticsProduct[];
};

export type ShopifyPageViewPayload = ShopifyCommonPayload & {
export type ShopifySalesChannels = keyof typeof ShopifySalesChannel;
export type AnalyticsEventNames = keyof typeof AnalyticsEventName;

export interface ShopifyPageViewPayload
extends ShopifyAnalyticsBase,
ClientBrowserParameters {
/** Canonical url. */
canonicalUrl?: string;
/** Shopify page type. */
pageType?: string;
/** Shopify resource id in the form of `gid://shopify/<type>/<id>`. */
resourceId?: string;
/** Shopify collection handle. */
collectionHandle?: string;
/** Search term used on a search results page. */
searchString?: string;
};
}

export type ShopifyPageView = {
/** Use `AnalyticsEventName.PAGE_VIEW` constant. */
eventName: string;
payload: ShopifyPageViewPayload;
};

export type ShopifyAddToCartPayload = ShopifyCommonPayload & {
/** The cart's ID if it has been created through the Storefront API. */
export interface ShopifyAddToCartPayload
extends ShopifyAnalyticsBase,
ClientBrowserParameters {
/** Shopify cart id in the form of `gid://shopify/Cart/<id>`. */
cartId: string;
};
}

export type ShopifyAddToCart = {
/** Use `AnalyticsEventName.ADD_TO_CART` constant. */
eventName: string;
payload: ShopifyAddToCartPayload;
};
Expand All @@ -84,7 +122,9 @@ export type ShopifyAnalyticsPayload =
export type ShopifyAnalytics = ShopifyPageView | ShopifyAddToCart;

export type ShopifyCookies = {
/** Shopify unique user token: Value of `_shopify_y` cookie. */
[SHOPIFY_Y]: string;
/** Shopify session token: Value of `_shopify_s` cookie. */
[SHOPIFY_S]: string;
};

Expand Down

0 comments on commit 8d8ab13

Please sign in to comment.