Skip to content

Commit

Permalink
Migrate to new Analytics
Browse files Browse the repository at this point in the history
Add UNSTABLE_Analytics and remove useAnalytics hook
Add PUBLIC_CHECKOUT_DOMAIN
  • Loading branch information
thomasKn committed May 15, 2024
1 parent 1f9e37e commit 8c76c8a
Show file tree
Hide file tree
Showing 15 changed files with 165 additions and 233 deletions.
1 change: 1 addition & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ PUBLIC_STOREFRONT_API_TOKEN="046fc93a591ca78ec9dc34657b660ac6"
PRIVATE_STOREFRONT_API_TOKEN="shpat_•••••••••••••••••••••••••"
PUBLIC_STOREFRONT_ID="22227"
PUBLIC_STOREFRONT_API_VERSION="2024-01"
PUBLIC_CHECKOUT_DOMAIN="checkout.frontvibe.com"

# Sanity project ID
SANITY_STUDIO_PROJECT_ID="gbcm3da4"
Expand Down
32 changes: 32 additions & 0 deletions app/components/CustomAnalytics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {unstable_useAnalytics as useAnalytics} from '@shopify/hydrogen';
import {useEffect} from 'react';

import {useIsDev} from '~/hooks/useIsDev';

export function CustomAnalytics() {
const {subscribe} = useAnalytics();
const isDev = useIsDev();

useEffect(() => {
if (!isDev) return;

// Standard events
subscribe('page_viewed', (data) => {
console.log('CustomAnalytics - Page viewed:', data);
});
subscribe('product_viewed', (data) => {
console.log('CustomAnalytics - Product viewed:', data);
});
subscribe('collection_viewed', (data) => {
console.log('CustomAnalytics - Collection viewed:', data);
});
subscribe('cart_viewed', (data) => {
console.log('CustomAnalytics - Cart viewed:', data);
});
subscribe('cart_updated', (data) => {
console.log('CustomAnalytics - Cart updated:', data);
});
}, [subscribe, isDev]);

return null;
}
151 changes: 47 additions & 104 deletions app/components/product/AddToCartForm.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,10 @@
import type {FetcherWithComponents} from '@remix-run/react';
import type {ShopifyAddToCartPayload} from '@shopify/hydrogen';
import type {ProductVariantFragmentFragment} from 'storefrontapi.generated';

import {useNavigation} from '@remix-run/react';
import {
AnalyticsEventName,
CartForm,
OptimisticInput,
ShopPayButton,
getClientBrowserParameters,
sendShopifyAnalytics,
} from '@shopify/hydrogen';
import {CartForm, OptimisticInput, ShopPayButton} from '@shopify/hydrogen';
import {useEffect, useState} from 'react';
import {useIdle, useSessionStorage} from 'react-use';

import {usePageAnalytics} from '~/hooks/useAnalytics';
import {useLocalePath} from '~/hooks/useLocalePath';
import {useSanityThemeContent} from '~/hooks/useSanityThemeContent';
import {useSelectedVariant} from '~/hooks/useSelectedVariant';
Expand Down Expand Up @@ -78,57 +68,55 @@ export function AddToCartForm(props: {
// Button is also disabled if navigation is loading (new variant is being fetched)
// to prevent adding the wrong variant to the cart.
return (
<AddToCartAnalytics fetcher={fetcher}>
<div className="grid gap-3">
<OptimisticInput
data={{
action: 'add',
line: {
cost: {
amountPerQuantity: selectedVariant.price,
totalAmount: selectedVariant.price,
},
id: selectedVariant.id,
merchandise: {
image: selectedVariant.image,
product: {
handle: selectedVariant.product?.handle,
title: selectedVariant.product?.title,
},
selectedOptions: selectedVariant.selectedOptions,
<div className="grid gap-3">
<OptimisticInput
data={{
action: 'add',
line: {
cost: {
amountPerQuantity: selectedVariant.price,
totalAmount: selectedVariant.price,
},
id: selectedVariant.id,
merchandise: {
image: selectedVariant.image,
product: {
handle: selectedVariant.product?.handle,
title: selectedVariant.product?.title,
},
quantity,
selectedOptions: selectedVariant.selectedOptions,
},
}}
id="cart-line-item"
/>
<Button
className={cn([
isOutOfStock && 'opacity-50',
// Opacity does not change when is loading to prevent flickering
'data-[loading="true"]:disabled:opacity-100',
])}
data-loading={isLoading}
data-sanity-edit-target
disabled={isOutOfStock || isLoading}
type="submit"
>
{isOutOfStock ? (
<CleanString value={themeContent?.product?.soldOut} />
) : (
<CleanString value={themeContent?.product?.addToCart} />
)}
</Button>
{showShopPay && selectedVariant.id && (
<ShopPay
isLoading={isLoading}
isOutOfStock={isOutOfStock}
quantity={quantity}
variantId={selectedVariant.id}
/>
quantity,
},
}}
id="cart-line-item"
/>
<Button
className={cn([
isOutOfStock && 'opacity-50',
// Opacity does not change when is loading to prevent flickering
'data-[loading="true"]:disabled:opacity-100',
])}
data-loading={isLoading}
data-sanity-edit-target
disabled={isOutOfStock || isLoading}
type="submit"
>
{isOutOfStock ? (
<CleanString value={themeContent?.product?.soldOut} />
) : (
<CleanString value={themeContent?.product?.addToCart} />
)}
</div>
</AddToCartAnalytics>
</Button>
{showShopPay && selectedVariant.id && (
<ShopPay
isLoading={isLoading}
isOutOfStock={isOutOfStock}
quantity={quantity}
variantId={selectedVariant.id}
/>
)}
</div>
);
}}
</CartForm>
Expand Down Expand Up @@ -193,51 +181,6 @@ function ShopPay(props: {
);
}

function AddToCartAnalytics({
children,
fetcher,
}: {
children: React.ReactNode;
fetcher: FetcherWithComponents<any>;
}): JSX.Element {
const fetcherData = fetcher.data;
const formData = fetcher.formData;
const pageAnalytics = usePageAnalytics({hasUserConsent: true});

useEffect(() => {
if (formData) {
const cartData: Record<string, unknown> = {};
const cartInputs = CartForm.getFormInput(formData);

try {
if (cartInputs.inputs.analytics) {
const dataInForm: unknown = JSON.parse(
String(cartInputs.inputs.analytics),
);
Object.assign(cartData, dataInForm);
}
} catch {
// do nothing
}

if (Object.keys(cartData).length && fetcherData) {
const addToCartPayload: ShopifyAddToCartPayload = {
...getClientBrowserParameters(),
...pageAnalytics,
...cartData,
cartId: fetcherData.cart.id,
};

sendShopifyAnalytics({
eventName: AnalyticsEventName.ADD_TO_CART,
payload: addToCartPayload,
});
}
}
}, [fetcherData, formData, pageAnalytics]);
return <>{children}</>;
}

function ShopPayLogo() {
return (
<svg
Expand Down
1 change: 1 addition & 0 deletions app/entry.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export default async function handleRequest(
) {
const {NonceProvider, header, nonce} = createContentSecurityPolicy({
shop: {
checkoutDomain: context.env.PUBLIC_CHECKOUT_DOMAIN,
storeDomain: context.env.PUBLIC_STORE_DOMAIN,
},
...createCspHeaders(),
Expand Down
2 changes: 2 additions & 0 deletions app/graphql/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ export const CART_QUERY_FRAGMENT = `#graphql
}
product {
handle
vendor
title
id
}
Expand All @@ -190,6 +191,7 @@ export const CART_QUERY_FRAGMENT = `#graphql
}
fragment CartApiQuery on Cart {
id
updatedAt
checkoutUrl
totalQuantity
buyerIdentity {
Expand Down
67 changes: 0 additions & 67 deletions app/hooks/useAnalytics.tsx

This file was deleted.

6 changes: 5 additions & 1 deletion app/lib/env.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* some are only available through the process.env object
*/

import {AppLoadContext} from '@shopify/remix-oxygen';
import type {AppLoadContext} from '@shopify/remix-oxygen';

export function envVariables(contextEnv: Env) {
let env: Env | NodeJS.ProcessEnv = contextEnv;
Expand All @@ -19,6 +19,10 @@ export function envVariables(contextEnv: Env) {
env.PRIVATE_STOREFRONT_API_TOKEN,
'PRIVATE_STOREFRONT_API_TOKEN',
),
PUBLIC_CHECKOUT_DOMAIN: checkRequiredEnv(
env.PUBLIC_CHECKOUT_DOMAIN,
'PUBLIC_CHECKOUT_DOMAIN',
),
PUBLIC_STORE_DOMAIN: checkRequiredEnv(
env.PUBLIC_STORE_DOMAIN,
'PUBLIC_STORE_DOMAIN',
Expand Down
Loading

0 comments on commit 8c76c8a

Please sign in to comment.