Cart and Checkout
Updated over a week ago


The Cart

👍 Heads up

  • If you are using Starter Kit, there's no need need to manually create the Sections and Components below.

  • All the code examples below are just an implementation suggestions. For brevity, the styles are omitted.

  • For this guide, we will be creating Sections and Components locally. Make sure you have your Local Development Environment ready.

👉 Remember to commit and push newly created Sections and Components to your remote repository to sync the changes with Shogun Frontend.

It’s common to have a cart open as a drawer, sliding from right to left to indicate a product was added to the cart. This allows the customer to edit the quantity without navigating away from their current page.

This section will cover the cart drawer and normal cart page. The cart page isn't a necessity, but it can serve as a landing page for the customer if they navigate back from the Shopify checkout page.

For both scenarios, we need specific data points:
-a list of products in the cart
-the total price of the products
-a link to redirect us to checkout itself.

Luckily, the frontend-checkout package provides all of this information via the useCartState hook.

This guide will cover creating:
-CartItem: responsible for rendering a single row of a product in the cart.
-CartItems: shows a list of CartItems.
-CartDrawer: a section that will act as a wrapper and will handle the drawer itself.

Creating CartItem

The CartItem component accepts a product as a prop coming from frontend-checkout's useCartState hook, which we will cover in the next step.

components/CartItem/index.js

// CartItem component
import * as React from 'react'
import { useCartActions } from 'frontend-checkout'
import { IconButton } from '@chakra-ui/react
import Link from 'frontend-link'
import NumberInput from 'Components/NumberInput'

const CartItem = ({ product }) => {
const { id, quantity, title: name, variant } = product
const { image, price, product: variantProduct, title: variantTitle } = variant
const { src } = image
const { handle: slug } = variantProduct
const { removeItems, updateItems } = useCartActions()

const onChangeItemQuantity = (_, quantityAsNumber) => {
updateItems({ id, quantity: quantityAsNumber })
}

return (
<div>
<div>
<Link to={`/products/${slug}`}>
<div>
<img alt="" src={src} height="120px" width="180px" sizes="120px" />
</div>
<div>
<h3>
{name}
</h3>
{variantTitle && (
<p>
{variantTitle}
</p>
)}
</div>
</Link>
</div>
<p>
${price}
</p>
<div>
<NumberInput
defaultValue={quantity}
onChange={onChangeItemQuantity}
inputProps={{
'aria-label': 'Product quantity',
size: 'xs',
}}
buttonProps={{
size: 'xs',
}}
/>
</div>
<p>
${Number(price) * quantity}
</p>
<div>
<IconButton
icon={<Icon icon="CloseIcon" />}
aria-label={`Remove ${name} from cart`}
border="0"
borderRadius="0"
size="xs"
variant="outline"
_hover={{ color: 'gray.700' }}
onClick={() => removeItems(id)}
/>
</div>
</div>
)
}

export default CartItem

Creating CartItems

The useCartState hook will give us access to all products a customer may have in their cart, the subtotalprice, and the checkoutUrl.

components/CartItems/index.js

// CartItems component
import * as React from 'react'
import { useCartState } from 'frontend-checkout'
import Link from 'frontend-link'
import CartItem from 'Components/CartItem'

const CartItems = () => {
const { checkoutUrl, items, subtotalPrice } = useCartState()

return (
<div>
<p>
Shopping cart ({items.length})
</p>
{items.length ? (
<React.Fragment>
{items.map(product => (
<div key={product.id}>
<CartItem product={product} />
<hr />
</div>
))}
<div>
<div>
<strong>Subtotal:</strong>
<p>${subtotalPrice}</p>
</div>
<div>
<Link to="/">
Continue shopping
</Link>
<Link to={checkoutUrl}target="_self">
Checkout
</Link>
</div>
</div>
</React.Fragment>
) : (
<React.Fragment>
<p>Your cart is currently empty.</p>
<Link to="/">
Start shopping
</Link>
</React.Fragment>
)}
</div>
)
}

export default CartItems

Creating CartDrawer

This step will assemble everything in the CartDrawer section. We will use hideCart from useCartActions and isCartShown from the useCartState hook and have the showCart function to display the CartDrawer when a product is successfully added to the cart.

sections/CartDrawer/index.js

// CartDrawer section
import * as React from 'react'
import { useCartActions, useCartState } from 'frontend-checkout'
import CartItems from 'Components/CartItems'
import Drawer from 'Components/Drawer'

const CartDrawer = () => {
const { hideCart } = useCartActions()
const { isCartShown } = useCartState()

return (
<Drawer isOpen={isCartShown} onClose={hideCart} size="md">
<CartItems />
</Drawer>
)
}

export default CartDrawer

The CartDrawer section will live inside the App component. If you are using the Starter Kit, an App component already exists and you will just need to import the CartDrawer into it:

components/App/index.js

import React from 'react'
import { ChakraProvider } from '@chakra-ui/react'
import { theme } from 'Components/Theme'
import CartDrawer from 'Components/CartDrawer'

const App = props => {
const { children } = props

return (
<ChakraProvider theme={theme}>
<CartDrawer />
{children}
</ChakraProvider>
)
}

export default App

You will now be able to see the CartDrawer if you add a product to the cart.

The Cart Page

Similar to the CartDrawer, the Cart page will also show a list of the products and will use CartItems.

As a wrapper to the CartItems, we will create a section called CartPage and call the CartItems:

sections/CartPage/index.js

import * as React from 'react'
import CartItems from 'Components/CartItems'
import Container from 'Components/Container'

const CartPage = () => (
<Container>
<CartItems />
</Container>
)

export default CartPage

Next, create a page called Cart, making sure to use /cart for the path, and add the CartPage section to the Cart page. Reference Adding a section in the Homepage Guide if an example is needed.

The cart page is now complete and your customers can now add products to their cart and checkout!

Multipass Setup (Shopify)

When the checkout is on a subdomain, the headless store and Shopify checkout pages don't share the same authentication sessions. Therefore, login sessions on Frontend won't be reflected on the checkout page. In order to pass on authentication from Frontend to Shopify, we must use multipass. Follow this guide to setup multipass authentication for your store's checkout.

Note that multipass is only necessary when the checkout and Frontend store are on different domains (subdomains)

Prerequisites

Before setting up multipass, the following needs to be setup on your store:

  • Account Pages, to setup account pages follow these steps

  • Checkout Sub-domain pointed to Shopify in your DNS provider

Step One: Setup Checkout Subdomain

  1. In your DNS provider, point your subdomain to Shopify by setting up a CNAME record with the value shops.myshopify.com

  2. In Shopify Admin, go to Settings > Domains > Connect Existing Domain

2846
  1. Add your checkout subdomain and verify the connection

  2. Set the checkout subdomain as the primary domain

Step Two: Enable Multipass

  1. In Shopify Admin, go to the Settings > Checkout and Accounts section

  2. Scroll down to Customer Accounts

  3. Select Enable Multipass. Once enabled, a secret will be shared with you. Make sure you keep your secret private.

Step Three: Send Details to Shogun

  1. Contact Shogun support and create a ticket to enable multipass for your Frontend Store

  2. In the ticket add the following:

    1. The multipass secret, avoid sending the multipass secret in plaintext by using onetimesecret or similar service

    2. Your checkout subdomain

Logout on Checkout Pages

When using multipass, the session created by the multipass login cannot be communicated back to Frontend. Therefore if a user logs out on Shopify, the user will remain logged in on Frontend.

Since the checkout and the headless store are on separate domains (even if subdomains) it’s not possible to retrieve the login state on the subdomain.

There is a workaround for this for Shopify Plus stores by following this process:

  1. In Frontend, create a new page with the path /account/logout

  2. Create a section called Logout

  3. Add the following code into the section

import React from 'react'
import { useCustomerState, useCustomerActions } from 'frontend-customer'

const Logout = () => {
const { isLoggedIn } = useCustomerState()
const { logout } = useCustomerActions()

React.useEffect(() => {
logout()
}, [])

React.useEffect(() => {
if (!isLoggedIn) {
window.location.href = 'https://{YOUR CHECKOUT SUBDOMAIN}/account/logout?return_url=/cart'
}
}, isLoggedIn)

return (
<p></p>
)
}

export default Logout
  1. Create a build and publish the store

  2. If you don’t already have a checkout.liquid layout

    1. In Shopify, navigate to Theme > Edit Code > Add New Layout

    2. Select checkout

  3. If you already have a checkout.liquid layout, add the following snippet above the </body> tag

<script>
Checkout.$(document).on('page:load', function() {
Checkout.$('a[href*="account/logout"]').attr("href", "https://{YOUR-FE-DOMAIN}/account/logout");
})
</script>

This will log the user out of both Shopify and FE, and will redirect back to the cart.

Did this answer your question?