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
Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.