Adding a form to an ecommerce site and sending data to Sanity and Stripe
8 replies
Last updated: Jul 6, 2022
L
Hey guys, I am admittedly a total noob with the back end. Heck, I am even pretty new to JS in general. I am using React for the first time as well on this project. I have a simple question with hopefully a simple solution. Bonus points if you explain it assuming I am 5 years old. So my issue is this. I currently have an ecommerce shop that sells customizable goods (customizable text, color, etc) all set up through sanity, nextjs, and react... I want to add a simple two or three required text fields form to a product page (probably with react hook form) above two buttons (these buttons pass state to my cart component). I need this form to send the text the customer typed in the field back to the same sanity studio where I push out products to the database (if possible?) so I can view the customer's order requests they input into the form externally (is there a way to have only the successful orders from stripe send back the custom data into the sanity studio?)
Within my ecommerce page is a dynamic single product page where you find the typical things: pictures of product, title of product, description of product all of which are pulled dynamically from the slug. Under the description I have the quantity and then under this I have the add to cart and buy now buttons. The buy now button just adds to cart and opens the cart sidebar component. Within the cart sidebar component there is a proceed to payment button which redirects them to stripes checkout page. This page will redirect them back to either my success or cancel page.
Within my ecommerce page is a dynamic single product page where you find the typical things: pictures of product, title of product, description of product all of which are pulled dynamically from the slug. Under the description I have the quantity and then under this I have the add to cart and buy now buttons. The buy now button just adds to cart and opens the cart sidebar component. Within the cart sidebar component there is a proceed to payment button which redirects them to stripes checkout page. This page will redirect them back to either my success or cancel page.
Jul 6, 2022, 12:52 AM
J
You could setup a webhook in stripe to trigger on successful payments https://stripe.com/docs/webhooks .. Stripe should send your order data in the body of the request, use that to patch in the data into sanity https://www.sanity.io/docs/http-mutations
Jul 6, 2022, 2:04 AM
L
Thank you so much!!! That actually helps a lot. But how could I collect this data and send it to stripe? I am still a bit confused on how to actually implement the forms for asking what text they would like on their order, etc?
Jul 6, 2022, 2:19 AM
L
user X
Jul 6, 2022, 2:20 AM
L
If it helps at all, this is the data structure I mimicked since a lot of this is new to me https://github.com/adrianhajdin/ecommerce_sanity_stripe
Jul 6, 2022, 2:35 AM
J
user N
Heres a quick way to do in your /product/[slug] page...in sanity create an object for your product options, then patch in the data. You will probably have to return the options object in your stripe.js file tooimport React, { useState } from 'react'; import { AiOutlineMinus, AiOutlinePlus, AiFillStar, AiOutlineStar } from 'react-icons/ai'; import { client, urlFor } from '../../lib/client'; import { Product } from '../../components'; import { useStateContext } from '../../context/StateContext'; const ProductDetails = ({ product, products }) => { const [options, setOptions] = useState({optionOne: '', optionTwo: ''}); const { image, name, details, price, } = product; product.options = options const [index, setIndex] = useState(0); const { decQty, incQty, qty, onAdd, setShowCart } = useStateContext(); console.log(product) const handleBuyNow = () => { onAdd(product, qty); setShowCart(true); } return ( <div> <div className="product-detail-container"> <div> <div className="image-container"> <img src={urlFor(image && image[index])} className="product-detail-image" /> </div> <div className="small-images-container"> {image?.map((item, i) => ( <img key={i} src={urlFor(item)} className={i === index ? 'small-image selected-image' : 'small-image'} onMouseEnter={() => setIndex(i)} /> ))} </div> </div> <div className="product-detail-desc"> <h1>{name}</h1> <div className="reviews"> <div> <AiFillStar /> <AiFillStar /> <AiFillStar /> <AiFillStar /> <AiOutlineStar /> </div> <p> (20) </p> </div> <h4>Details: </h4> <p>{details}</p> <p className="price">${price}</p> <div className="quantity"> <h3>Quantity:</h3> <p className="quantity-desc"> <span className="minus" onClick={decQty}><AiOutlineMinus /></span> <span className="num">{qty}</span> <span className="plus" onClick={incQty}><AiOutlinePlus /></span> </p> </div> <div> <label htmlFor='option1'>Option 1</label><input type='text' name='optionOne' onChange={(e) => setOptions({...options, optionOne: e.target.value})}/> <label htmlFor='option1'>Option 2</label><input type='text' name='optionTwo' onChange={(e) => setOptions({...options, optionTwo: e.target.value})}/> </div> <div className="buttons"> <button type="button" className="add-to-cart" onClick={() => onAdd(product, qty)}>Add to Cart</button> <button type="button" className="buy-now" onClick={handleBuyNow}>Buy Now</button> </div> </div> </div> <div className="maylike-products-wrapper"> <h2>You may also like</h2> <div className="marquee"> <div className="maylike-products-container track"> {products.map((item) => ( <Product key={item._id} product={item} /> ))} </div> </div> </div> </div> ) } export const getStaticPaths = async () => { const query = `*[_type == "product"] { slug { current } } `; const products = await client.fetch(query); const paths = products.map((product) => ({ params: { slug: product.slug.current } })); return { paths, fallback: 'blocking' } } export const getStaticProps = async ({ params: { slug }}) => { const query = `*[_type == "product" && slug.current == '${slug}'][0]`; const productsQuery = '*[_type == "product"]' const product = await client.fetch(query); const products = await client.fetch(productsQuery); console.log(product); return { props: { products, product } } } export default ProductDetails
stripe.js return { price_data: { currency: 'usd', product_data: { name: item.name, images: [newImage], }, unit_amount: item.price * 100, }, adjustable_quantity: { enabled:true, minimum: 1, }, quantity: item.quantity, options: item.options }
Jul 6, 2022, 2:54 AM
V
user N
New to JavaScript and React and you chose to make a headless shop? My friend, you are my hero of the day! ๐Jul 6, 2022, 5:55 AM
L
LOL well, it all started out by me underestimating the complexity behind processing payments securely. Built an entirely static site that was gorgeous but without a tutorial for all of the backend stuff I was helplessly lost on how to execute what I needed with best practice. So I scrapped my progress and started fresh following a youtube tutorial for this. I have officially gone down the rabbit hole, but I have learned a TON and am so excited to get a better understanding of all the fundamentals now that I seen the whole process in action! Struggling through foreign coding languages has been surprisingly addicting haha
user S
Jul 6, 2022, 6:00 AM
V
I totally get it. I do the seven stages of grief for every major project but I'm still here so something must be keeping me in the mix!
Jul 6, 2022, 2:36 PM
Sanityโ build remarkable experiences at scale
The Sanity Composable Content Cloud is the headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.