gatsby-shopify-starter
gatsby-shopify-starter copied to clipboard
Clear cart on success?
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.
Good point! I haven't even thought about that yet. I'll take a look at it!
Perhaps a success/thank you template to redirect back to from Shopify that has a clear cart function in it?
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.
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.
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.
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.
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).
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?
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.
Thank you! This is a great solution, I didn’t know you could add scripts to the checkout but it perfectly fixes the problem.
Has this solution been implemented into master?
@hoektoe The solution suggested by @mister-cairns needs to be implemented individually therefore I haven't merged it into the master.
clearCheckout()
@mister-cairns How does your clearCheckout()
function look like? Do you just remove all line items using removeLineItems()
from Shopify js buy?
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.
@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?
Yeah, maybe try logging the line items in the effect to make sure they're all showing up?
@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?
I call it at the top of the component file. You shouldn't put it inside of another useEffect
. Could you share the file?
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,
}))
})
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.
Has this issue been solved yet?
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.
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;
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)
}