Skip to content

Instantly share code, notes, and snippets.

@viggin543
Created March 13, 2025 18:07
Show Gist options
  • Save viggin543/0409e55ac1212f7abc161ca7e0299af5 to your computer and use it in GitHub Desktop.
Save viggin543/0409e55ac1212f7abc161ca7e0299af5 to your computer and use it in GitHub Desktop.
reference
import React, { useEffect, useState } from 'react';
import {
useCart,
useCartAddAttributes,
useCartAddItem,
useCartClear,
useCurrency,
} from '@backpackjs/storefront';
import Script from 'next/script';
import { useGlobalContext } from '../contexts';
function getPageType(resourceType) {
if (resourceType === 'home_page') {
return 'home';
}
if (resourceType === 'product_page') {
return 'product';
}
if (resourceType === 'collection_page') {
return 'collection';
}
return 'other';
}
function maybe(f, def = undefined) {
try {
return f();
} catch {
return def;
}
}
function transformCart(cart) {
return cart
? {
item_count: maybe(() => cart.lines.reduce((p, c) => p + c.quantity, 0)),
attributes: cart?.attributes || [],
items: cart.lines.map((l) => ({
handle: l.variant.product.handle,
price: maybe(() => parseFloat(l.variant.priceV2.amount) * 100),
product_id: maybe(() =>
parseInt(
l.variant.product.id.replace('gid://shopify/Product/', ''),
10
)
),
quantity: l.quantity,
variant_id: maybe(() =>
parseInt(
l.variant.id.replace('gid://shopify/ProductVariant/', ''),
10
)
),
})),
currency: maybe(() => cart.estimatedCost.totalAmount.currencyCode, 0),
total_price: maybe(
() => parseFloat(cart.estimatedCost.totalAmount.amount) * 100,
0
),
token: maybe(() => cart.id.replace('gid://shopify/Cart/', ''), ''),
}
: undefined;
}
function useVisuallyIo({ product, resourceType, visuallyLoaded }) {
const currency = useCurrency();
const cart = useCart();
const { cartClear } = useCartClear();
const { cartAddItem } = useCartAddItem();
const { cartAddAttributes } = useCartAddAttributes();
const pageType = getPageType(resourceType);
const {
actions: { openCart },
} = useGlobalContext();
useEffect(() => {
if (visuallyLoaded && window.visually) {
maybe(() => window.visually.onCartChanged(transformCart(cart)));
}
}, [cart, visuallyLoaded]);
useEffect(() => {
if (visuallyLoaded && window.visually) {
maybe(() =>
window.visually.visuallyConnect({
cartClear,
initialProductId: maybe(() =>
product.id.replace('gid://shopify/Product/', '')
),
initialVariantPrice: maybe(() =>
parseInt(product.variants[0].priceV2.amount, 10)
),
initialVariantId: maybe(() =>
product.variants[0].replace('gid://shopify/ProductVariant/', '')
),
addToCart: (variantId, quantity) =>
cartAddItem({
merchandiseId: `gid://shopify/ProductVariant/${variantId}`,
quantity,
}),
cartAddAttributes,
openCartDrawer: openCart,
pageType,
initialCurrency: currency,
initialLocale: 'en-US',
})
);
}
}, [pageType, currency, product, visuallyLoaded]);
}
export function VisuallyIo({ page, product }) {
const [visuallyLoaded, setVisuallyLoaded] = useState(false);
useVisuallyIo({
product,
resourceType: page?.resourceType,
visuallyLoaded,
});
return (
<>
<Script
strategy="beforeInteractive"
rel="preconnect prefetch"
src="https://live.visually-io.com/widgets/vsly-preact.min.js?k=<KEY>&e=2&s=<ALIAS>"
onLoad={() => setVisuallyLoaded(true)}
/>
<Script
strategy="beforeInteractive"
rel="preconnect prefetch"
src="https://live.visually-io.com//v/visually-spa.js"
/>
<Script
strategy="afterInteractive"
src="https://live.visually-io.com//v/visually-a-spa.js"
/>
</>
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment