Integrating on Hydrogen

Integrating on Hydrogen

Required Packages

lit

@lit-labs/react

@loadable/component

Setup

Install the required packages as listed above.

Example Repository [Hydrogen Playground]

Linked is the example repository that follows the instructions from this article. This example repository is built from the latest version of Shopify's Hydrogen Demo Store template (as of 12/20/22) and can be used with Node 16.14.0 or greater.

Step 1 - Adding the Skio Plan Picker component

Using the code provided in the example repository, create a new component called SkioPlanPicker.client.jsx

Step 2 - Update Product Queries

Under /src/routes/products/[handle].server.jsx update the variable PRODUCT_QUERY to match the following:

const PRODUCT_QUERY = gql`
${MEDIA_FRAGMENT}
query Product(
$country: CountryCode
$language: LanguageCode
$handle: String!
) @inContext(country: $country, language: $language) {
product(handle: $handle) {
id
title
vendor
descriptionHtml
media(first: 7) {
nodes {
...Media
}
}

requiresSellingPlan
sellingPlanGroups(first: 10) {
edges {
node {
name
options {
name
values
}
sellingPlans(first: 10) {
edges {
node {
id
name
description
recurringDeliveries
options {
name
value
}
}
}
}
appName
}
}
}


variants(first: 100) {
nodes {
id
availableForSale
selectedOptions {
name
value
}
image {
id
url
altText
width
height
}
priceV2 {
amount
currencyCode
}
compareAtPriceV2 {
amount
currencyCode
}
sku
title
unitPrice {
amount
currencyCode
}

sellingPlanAllocations(first: 10) {
edges {
node {
sellingPlan {
id
name
options {
name
value
}
}
priceAdjustments {
price {
amount
currencyCode
}
compareAtPrice {
amount
currencyCode
}
perDeliveryPrice {
amount
currencyCode
}
unitPrice {
amount
currencyCode
}
}
}
}
}

}
}
seo {
description
title
}
}
shop {
shippingPolicy {
body
handle
}
refundPolicy {
body
handle
}
}
}
`;

We're also going to update our ProductForm component to accept the full product data object

<ProductForm product={product} />

Step 3 - Update the Product Form

In the file ProductForm.client.jsx, load in the Skio Plan Picker component without the use of SSR

import loadable from '@loadable/component';
const SkioPlanPicker = loadable(() => import('~/components/skio/SkioPlanPicker.client'), {
ssr: false,
fallback: <div>Loading...</div>
})

Update the ProductForm function to accept the new product data we are passing

export function ProductForm({ product }) {

Add a new state called subscription under the ProductForm function

const [subscription, setSubscription] = useState(null);

Add a new callback function called onPlanChange under the ProductForm function

const onPlanChange = async(subscription) => {
setSubscription(subscription);
}

Add the Skio Plan Picker component to the render function as a child of the form element

<SkioPlanPicker product={ product } selectedVariant={ selectedVariant } onPlanChange={ onPlanChange }></SkioPlanPicker>

Update the AddToCartButton component to include a selling plan id when adding to cart. Hydrogen's AddToCartButton component naturally supports native subscriptions by just passing the selling plan id.

<AddToCartButton
variantId={selectedVariant?.id}
sellingPlanId={subscription?.sellingPlan?.id}
quantity={1}
accessibleAddingToCartLabel="Adding item to your cart"
disabled={isOutOfStock}
type="button"
>

If you'd like, you can update various aspects of the product form to get more dynamic subscription information to be displayed.

Example: When subscription is selected, show the discounted subscription amount and change the add to cart button to read Subscription.

<AddToCartButton
variantId={selectedVariant?.id}
sellingPlanId={subscription?.sellingPlan?.id}
quantity={1}
accessibleAddingToCartLabel="Adding item to your cart"
disabled={isOutOfStock}
type="button">

<Button
width="full"
variant={isOutOfStock ? 'secondary' : 'primary'}
as="span">

{isOutOfStock ? (
<Text>Sold out</Text>
) : (
<Text
as="span"
className="flex items-center justify-center gap-2"
>
<span>{ subscription ? 'Subscription' : 'Add to bag' }</span> <span>·</span>{' '}
<Money
withoutTrailingZeros
data={subscription ? subscription.pricev2 : selectedVariant.priceV2}
as="span"
/>
{isOnSale ? (
<Money
withoutTrailingZeros
data={selectedVariant.compareAtPriceV2}
as="span"
className="opacity-50 strike"
/>
): (subscription && subscription.pricev2.amount < selectedVariant.priceV2.amount) && (
<Money
withoutTrailingZeros
data={selectedVariant.priceV2}
as="span"
className="opacity-50 strike"
/>
)}
</Text>
)}
</Button>
</AddToCartButton>

Step 4 - Extend the cart query to include selling plan information

Under App.server.jsx add a new variable called cartFrag. This will extend the Cart GraphQL Query to include information about our subscription

Import gql from the @shopify/hydrogen package then create a new variable as follows:

const cartFrag = gql`
fragment CartFragment on Cart {
id
checkoutUrl
totalQuantity
buyerIdentity {
countryCode
customer {
id
email
firstName
lastName
displayName
}
email
phone
}
lines(first: $numCartLines) {
edges {
node {
id
quantity
attributes {
key
value
}
cost {
totalAmount {
amount
currencyCode
}
compareAtAmountPerQuantity {
amount
currencyCode
}
}
sellingPlanAllocation {
sellingPlan {
id
name
options {
name
value
}
}
}
merchandise {
... on ProductVariant {
id
availableForSale
compareAtPriceV2 {
...MoneyFragment
}
priceV2 {
...MoneyFragment
}
requiresShipping
title
image {
...ImageFragment
}
product {
vendor
id
handle
title
}
selectedOptions {
name
value
}
}
}
}
}
}
cost {
subtotalAmount {
...MoneyFragment
}
totalAmount {
...MoneyFragment
}
totalDutyAmount {
...MoneyFragment
}
totalTaxAmount {
...MoneyFragment
}
}
note
attributes {
key
value
}
discountCodes {
code
}
}
fragment MoneyFragment on MoneyV2 {
currencyCode
amount
}
fragment ImageFragment on Image {
id
url
altText
width
height
}
`;

Load the new cart fragment into the CartProvider component located in the same App.server.jsx file

<CartProvider countryCode={countryCode} cartFragment={cartFrag}></CartProvider>

Step 5 - Update the Cart to show the proper labels

In the CartLineItem.client.jsx file, pull in our new selling plan allocation data

const {id: lineId, quantity, merchandise, sellingPlanAllocation} = useCartLine();

Now let's display the currently selected selling plan name under the selected options displayed in the cart

<div className="grid pb-2">
{sellingPlanAllocation && (
<Text color="subtle">
{sellingPlanAllocation.sellingPlan.name}
</Text>
)}
</div>

You're front end is now setup to sell subscriptions!

Step 6 - Skio Customer Portal

The Skio Customer Portal, like many other Shopify apps, utilizes Shopify's App Proxy system to load the customer portal. Unfortunately, there is currently no way for App Proxies to load on Headless stores. Because of this, a subdomain should be setup that directs to the liquid version of the storefront (ie: account.mystore.com or shop.mystore.com). When a customer is navigating to manage their subscription they should be directed to this subdomain (ie: shop.mystore.com/a/account/login). A redirect should be setup on the liquid theme as well to handle any other traffic that may need to be directed back to the headless storefront!

As always if you have any questions or need any assistance with setup, please reach out to migrations@skio.com for more information or assistance!


How did we do?


Powered by HelpDocs (opens in a new tab)