AlexanderProd / gatsby-shopify-starter

🛍 Simple starter to build a blazing fast Shopify store with Gatsby.
https://gatsby-shopify-starter.alexanderhoerl.de
Other
422 stars 95 forks source link

Clear cart on success? #17

Open mister-cairns opened 5 years ago

mister-cairns commented 5 years ago

Would there be any way to clear the cart once a transaction is complete? I can redirect from the Shopify checkout back to my site, but how to clear the cart as the users' products will still be in in the cart.

AlexanderProd commented 5 years ago

Good point! I haven't even thought about that yet. I'll take a look at it!

mister-cairns commented 5 years ago

Perhaps a success/thank you template to redirect back to from Shopify that has a clear cart function in it?

AlexanderProd commented 5 years ago

The cart automatically clears if you reload the page after finishing the checkout process. The problem is the checkout happens in another tab (on the Shopify site). I'll investigate further.

Chompas commented 5 years ago

Hi, I'm using your project as help for my site. Thanks a lot for your hard work. I'm having the same issue so let me know if you found a solution for it.

rubas commented 4 years ago

Would it be a solution to refresh the content of the cart via API every x seconds, while the user is on the cart page?

Or show a modal window with button (please do checkout on other tab) after you clicked on the checkout. If he comes back and click the modal away, you reload the page.

AlexanderProd commented 4 years ago

While it's not the cleanest approach, checking periodically if the cart has already been bought would be an option I guess.

The modal version would definitely work, the only thing I'm concerned of is that's a kind of unusual behavior since I don't know any other e-commerce page doing it that way. Don't think its a UX problem though.

The last option I've though of would be to just clear the cart after the user has clicked the checkout button. I'd suspect the checkout to go successfully in most cases, just when this is not the case the user might wonder why the cart is empty and he'd have to put everything in again. Would be a nice and easy solution for most times. But I'm clearly playing the probability card here.

chanmathew commented 4 years ago

Perhaps a success/thank you template to redirect back to from Shopify that has a clear cart function in it?

I think this is definitely the best approach, probably a good spot for post purchase call to actions as well (social share, referrals, upsells, etc).

nandorojo commented 4 years ago

Perhaps a success/thank you template to redirect back to from Shopify that has a clear cart function in it?

I think this is definitely the best approach, probably a good spot for post purchase call to actions as well (social share, referrals, upsells, etc).

Agreed on this. Has anyone built a straightforward example so far?

mister-cairns commented 4 years ago

My solution is as follows:

In Shopify, go to Settings > Checkout, and in the Addition Scripts section, add your redirect URL (I set a timeout so it wasn't instantaneous).

 <script type="text/JavaScript">
      setTimeout("location.href = 'https://your-url.com/thank-you/';",6000);
 </script>

I then created the thank you page template with a clear cart function:

import React, { useContext, useEffect } from 'react'
import StoreContext from '../context/StoreContext'

const ThanksPage = () => {
  const context = useContext(StoreContext)
  const { clearCheckout,checkout } = context
  useEffect(() => {
    if(checkout.lineItems.length !== 0) {
      clearCheckout()
    }
  },[checkout])

  return (

)}

export default ThanksPage

Hope that makes sense.

AlexanderProd commented 4 years ago

Thank you! This is a great solution, I didn’t know you could add scripts to the checkout but it perfectly fixes the problem.

hoektoe commented 4 years ago

Has this solution been implemented into master?

AlexanderProd commented 4 years ago

@hoektoe The solution suggested by @mister-cairns needs to be implemented individually therefore I haven't merged it into the master.

AlexanderProd commented 3 years ago

clearCheckout()

@mister-cairns How does your clearCheckout() function look like? Do you just remove all line items using removeLineItems() from Shopify js buy?

nandorojo commented 3 years ago

Yup, this is what I use in mine:

import { useContext, useEffect, useRef } from 'react'
import StoreContext from 'src/context/StoreContext'

/**
 * Clear the user's cart when they're redirected to this thank you page.
 */
export const useThankYouClearCart = () => {
  const {
    checkout: { lineItems },
    removeLineItem,
  } = useContext(StoreContext)

  const isRemoving = useRef(false)

  useEffect(() => {
    if (!isRemoving.current) {
      isRemoving.current = !!lineItems.length
      lineItems?.forEach(({ id }) => {
        removeLineItem(id as string)
      })
    }
  }, [lineItems, removeLineItem])
}

If there's a function to remove multiple line items at once, even better.

AlexanderProd commented 3 years ago

@nandorojo I've added your solution to my 'thank you' page but when I load it, only one line item gets removed. For every time I reload the page one more line item gets removed. Have you tested your solution with multiple items in the cart?

nandorojo commented 3 years ago

Yeah, maybe try logging the line items in the effect to make sure they're all showing up?

AlexanderProd commented 3 years ago

@nandorojo Yeah they're all showing up. How do you run your useThankYouClearCart() hook on your 'thank you' page? Just inside a useEffect() when the page loads?

nandorojo commented 3 years ago

I call it at the top of the component file. You shouldn't put it inside of another useEffect. Could you share the file?

AlexanderProd commented 3 years ago

Sure, this is how my file looks like, I had to rewrite your code in plain JS since I don't use TS in my project.

import React, { useEffect, useContext, useRef } from 'react'

import Page from '~/templates/Page'
import StoreContext from '~/context/StoreContext'

const ThankYou = () => {
  const { client, checkout, removeLineItem } = useContext(StoreContext)

  const isRemoving = useRef(false)

  useEffect(() => {
    const script = document.createElement('script')
    script.src = '/confetti.js'
    script.async = true
    document.body.appendChild(script)

    return () => {
      document.body.removeChild(script)
    }
  }, [])

  useEffect(() => {
    if (!isRemoving.current) {
      isRemoving.current = !!checkout.lineItems.length
      if (checkout.lineItems !== null && checkout.lineItems !== undefined) {
        checkout.lineItems.forEach(({ id }) => {
          removeLineItem(client, checkout.id, id)
        })
      }
    }
  }, [checkout.lineItems, removeLineItem, checkout.id, client])

  return (
    <Page title="">
      <div style={{ textAlign: 'center' }}>
        <h1>Thank you!</h1>
        <span role="img" aria-label="Heart">
          ❤️
        </span>
      </div>
    </Page>
  )
}

export default ThankYou

My removeLineItem function looks like this:

removeLineItem: (client, checkoutID, lineItemID) => {
      return client.checkout
        .removeLineItems(checkoutID, [lineItemID])
        .then(res => {
          this.setState(state => ({
            ...state,
            checkout: res,
          }))
        })
nandorojo commented 3 years ago

Hmm, not sure why this works for me then.

Maybe try creating a removeLineItems in the StoreContext which receives an array of IDs, and pass that list of IDs from the useEffect?

Also, I think it makes sense to have the useThankYouPage-style hook as a standalone function so that you can export it for easier usage, but that's just a stylistic choice.

The problem could be the dependency array in the useEffect hook, though. Mine are a bit different.

I also have my removeLineItem function wrapped in useCallback. I would make sure to memoize like that.

krichey15 commented 3 years ago

Has this issue been solved yet?

AlexanderProd commented 3 years ago

To my knowledge it hasn’t been solved, I’ve tried the technique with adding a script in the Shopify checkout section but it doesn’t work.

krichey15 commented 3 years ago

To my knowledge it hasn’t been solved, I’ve tried the technique with adding a script in the Shopify checkout section but it doesn’t work.

I actually got mine to work

added this to Shopify:

And this was my thank you page

import React from 'react'
import ThanksText from '../components/SiteText/ThanksText';

class Thanks extends React.Component {
  constructor(props) {
    super(props)
  }

  componentDidMount() {
    localStorage.clear();
  }

  render() {
    return (
      <>
        <ThanksText  />
      </>
    )
  }
}

export default Thanks;
kertzi commented 3 years ago

I implement @krichey15 solution and it works really well. Have anyone implemented some kind of polling or other type of checking on original cart page for checkout complete? So when user clicks "Checkout" on cart page new page/tab is opened and everything is done there also redirect to thank you page. BUT original cart page still shows that there is items in cart. There should be some kind of polling about when checkout is completed and original cart page refreshes and redirects to frontpage or somewhere.

Update: I solved this by changing checkout url to open same window:

  const handleCheckout = () => {
    window.location.assign(checkout.webUrl)
  }