From 1bc517da6473005352929b5c3f53cba984b3e2f8 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 10 Aug 2022 14:54:15 +0300 Subject: [PATCH] docs: improved cart documentation (#2027) --- .../how-to-implement-checkout-flow.mdx | 3 + docs/content/guides/carts-in-medusa.md | 163 ------- docs/content/guides/carts-in-medusa.mdx | 404 ++++++++++++++++++ www/docs/sidebars.js | 8 +- www/docs/src/css/custom.css | 4 + 5 files changed, 415 insertions(+), 167 deletions(-) delete mode 100644 docs/content/guides/carts-in-medusa.md create mode 100644 docs/content/guides/carts-in-medusa.mdx diff --git a/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx b/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx index 724fa3c7bf..5c05cac164 100644 --- a/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx +++ b/docs/content/advanced/storefront/how-to-implement-checkout-flow.mdx @@ -18,6 +18,8 @@ It’s recommended to go through the [Shipping Architecture Overview](../backend This document assumes you’ve already taken care of the add-to-cart flow. So, you should have a [cart created](https://docs.medusajs.com/api/store/cart/create-a-cart) for the customer with at least [one product in it](https://docs.medusajs.com/api/store/cart/add-a-line-item). +You can learn how to implement the cart flow using [this documentation](../../guides/carts-in-medusa.mdx). + To follow along with this tutorial, you can make use of the [Medusa JS Client](https://www.npmjs.com/package/@medusajs/medusa-js). You can install it with this command: ```bash npm2yarn @@ -325,5 +327,6 @@ If the order is placed successfully, you can access the order data in `response. ## What’s Next 🚀 +- Learn more about the [JS Client and how to use it](../../js-client/overview.md). - Check out available plugins for popular payment providers such as [Stripe](../../add-plugins/stripe.md) and [PayPal](/add-plugins/paypal.md). - Learn more about the [Payment](../backend/payment/overview.md) and [Shipping](../backend/shipping/overview.md) Architectures. diff --git a/docs/content/guides/carts-in-medusa.md b/docs/content/guides/carts-in-medusa.md deleted file mode 100644 index 9c00b9d1cb..0000000000 --- a/docs/content/guides/carts-in-medusa.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: Carts ---- - -# Carts - -In Medusa a Cart serves the purpose of collecting the information needed to create an Order, including what products to purchase, what address to send the products to and which payment method the purchase will be processed by. - -To create a cart using the `@medusajs/medusa-js` SDK you can use: - -```javascript -const client = new Medusa({ baseUrl: "http://localhost:9000" }) -const { cart } = await client.carts.create() -``` - -A Cart will always belong to a Region and you may provide a `region_id` upon Cart creation. If no `region_id` is specified Medusa will assign the Cart to a random Region. Regions specify information about how the Cart should be taxed, what currency the Cart should be paid with and what payment and fulfillment options will be available at checkout. Below are some of the properties that can be found on the Cart response. For a full example of a Cart response [check our fixtures](https://github.com/medusajs/medusa/blob/docs/api/docs/api/fixtures/store/GetCartsCart.json). - -```json - "cart": { - "id": "cart_01FEWZSRFWT8QWMHJ7ZCPRP3BZ", - "email": null, - "billing_address": null, - "shipping_address": null, - "items": [ ... ], - "region": { - "id": "reg_01FEWZSRD7HVHBSQRC4KYMG5XM", - "name": "United States", - "currency_code": "usd", - "tax_rate": "0", - ... - }, - "discounts": [], - "gift_cards": [], - "customer_id": null, - "payment_sessions": [], - "payment": null, - "shipping_methods": [], - "type": "default", - "metadata": null, - "shipping_total": 0, - "discount_total": 0, - "tax_total": 0, - "gift_card_total": 0, - "subtotal": 1000, - "total": 1000, - ... - } -``` - -## Adding products to the Cart - -Customers can add products to the Cart in order to start gathering the items that will eventually be purchased. In Medusa adding a product to a Cart will result in a _Line Item_ being generated. To add a product using the SDK use: - -```javascript -const { cart } = await client.carts.lineItems.create(cartId, { - variant_id: "[id-of-variant-to-add]", - quantity: 1, -}) -``` - -The resulting response will look something like this: - -```json -{ - "cart": { - "id": "cart_01FEWZSRFWT8QWMHJ7ZCPRP3BZ", - "items": [ - { - "id": "item_01FEWZSRMBAN85SKPCRMM30N6W", - "cart_id": "cart_01FEWZSRFWT8QWMHJ7ZCPRP3BZ", - "title": "Basic Tee", - "description": "Small", - "thumbnail": null, - "is_giftcard": false, - "should_merge": true, - "allow_discounts": true, - "has_shipping": false, - "unit_price": 1000, - "variant": { - "id": "variant_01FEWZSRDNWABVFZTZ21JWKHRG", - "title": "Small", - "product_id": "prod_01FEWZSRDHDDSHQV6ATG6MS2MF", - "sku": null, - "barcode": null, - "ean": null, - "upc": null, - "allow_backorder": false, - "hs_code": null, - "origin_country": null, - "mid_code": null, - "material": null, - "weight": null, - "length": null, - "height": null, - "width": null, - "metadata": null, - ... - }, - "quantity": 1, - "metadata": {}, - ... - } - ], - ... - } -} -``` - -The properties stored on a Line Item are useful for explaining and displaying the contents of the Cart. For example, Line Items can have a thumbnail assigned which can be used to display a pack shot of the product that is being purchased, a title to show name the products in the cart and a description to give further details about the product. By default the Line Item will be generated with properties inherited from the Product that is being added to the Cart, but the behaviour can be customized for other purposes as well. - -## Adding Customer information to a Cart - -After adding products to the Cart, you should gather information about where to send the products, this is done using the `update` method in the SDK. - -```javascript -const { cart } = await client.carts.update(cartId, { - email: "jane.doe@mail.com", - shipping_address: { - first_name: "Jane", - last_name: "Doe", - address_1: "4242 Hollywood Dr", - postal_code: "12345", - country_code: "us", - city: "Los Angeles", - region: "CA", - }, -}) -``` - -Note that the country code in the shipping address must be the country code for one of the countries in a Region - otherwise this method will fail. - -## Initializing Payment Sessions - -In Medusa payments are handled through the long lived entities called _Payment Sessions_. Payment Sessions cary provider specific data that can later be used to authorize the payments, which is the step required before an order can be created. The SDK provides a `createPaymentSessions` method that can be used to initialize the payment sessions with the Payment Providers available in the Region. - -```javascript -const { cart } = await client.carts.createPaymentSessions(cartId) -``` - -You can read more about Payment Sessions in our [guide to checkouts](https://docs.medusajs.com/guides/checkouts). - -## Changing the Cart region - -To update the Region that the cart belongs to you should also use the `update` method from the SDK. - -```javascript -const { cart } = await client.carts.update(cartId, { - region_id: "[id-of-region-to-switch-to]", -}) -``` - -When changing the Cart region you should be aware of a couple of things: - -- If switching to a Region with a different currency the line item prices and cart totals will change -- If switching to a Region with a different tax rate prices and totals will change -- If switching to a Region serving only one country the `shipping_address.country_code` will automatically be set to that country -- If the Cart already has initialized payment sessions all of these will be canceled and a new call to `createPaymentSessions` will have to be made - -## What's next? - -Carts are at the core of the shopping process in Medusa and provide all the necessary functionality to gather products for purchase. If you want to read a more detailed guide about how to complete checkouts please go to our [Checkout Guide](https://docs.medusajs.com/guides/checkout). - -If you have questions or issues feel free to reach out via our [Discord server](https://discord.gg/xpCwq3Kfn8) for direct access to the Medusa engineering team. diff --git a/docs/content/guides/carts-in-medusa.mdx b/docs/content/guides/carts-in-medusa.mdx new file mode 100644 index 0000000000..589b2ee56b --- /dev/null +++ b/docs/content/guides/carts-in-medusa.mdx @@ -0,0 +1,404 @@ +# How to Add Cart Functionality + +This document guides you through how you can add cart-related functionalities to your storefront. That includes creating and updating a cart and managing items in the cart. + +## Overview + +Carts are necessary for ecommerce platforms to allow customers to buy products. Each customer, whether logged in or as a guest, should have a cart associated with them. The customer can then add products to the cart. + +This document helps you understand how to add the cart functionality to your storefront. This is helpful if you’re creating the storefront from scratch, or you want to understand how the process generally works in Medusa’s starter storefronts. + +:::note + +This document does not cover implementing the checkout flow. You can refer to [this documentation instead to learn how to implement the checkout flow](../advanced/storefront/how-to-implement-checkout-flow.mdx). + +::: + +### Glossary + +- **Line Item**: When products are added to the cart in Medusa, they are referred to as line items. Line items have, by default, the same properties and attributes as a product. However, you can customize line items specifically for a cart if necessary. + +## Prerequisites + +It is assumed you already have a Medusa server installed before following along with this tutorial. If not, you can get started in minutes by following the [quickstart guide](../quickstart/quick-start.md). + +It is also assumed you already have a storefront set up. It can be a custom storefront or one of Medusa’s storefronts. If you don’t have a storefront set up, you can install either the [Next.js](../starters/nextjs-medusa-starter.md) or [Gatsby](../starters/gatsby-medusa-starter.md) storefronts. + +## Install the JS Client + +It is recommended to use Medusa’s JS Client in your storefront. You can install it using the following command: + +```bash npm2yarn +npm install @medusajs/medusa-js +``` + +:::note + +This document alternatively shows code examples using [JavaScript’s Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch). Make sure to replace `` in those examples with your server URL. + +::: + +Then, initialize the Medusa JS Client in a single file that all of your components can access: + +```jsx +import Medusa from '@medusajs/medusa-js'; + +export const client = new Medusa({ + baseUrl: '', + maxRetries: 3 +}); +``` + +Where `` is the URL of your server. If you’re using a local server, it runs on `http://localhost:9000` by default. + +:::caution + +Make sure to include `http://` in the URL when sending requests to the local server. Otherwise, all requests will fail. + +::: + +## Create a Cart + +You can create a cart with the following code snippet: + + + + +```jsx +client.carts.create() +.then(({cart}) => { + localStorage.setItem('cart_id', cart.id); + //assuming you have a state variable to store the cart + setCart(cart); +}); +``` + + + + +```jsx +fetch(`/store/carts`, { + method: 'POST' +}) +.then((response) => response.json()) +.then(({cart}) => { + localStorage.setItem('cart_id', cart.id); + //assuming you have a state variable to store the cart + setCart(cart) +}); +``` + + + + +A cart will be created with a random region assigned to it. + +:::note + +The region a cart is associated with determines the currency the cart uses, the tax, payment, and fulfillment providers, and other details and options. So, make sure you use the correct region for a cart. + +::: + +Otherwise, you can assign it a specific region during creation: + + + + +```jsx +client.carts.create({ + region_id +}) +.then(({cart}) => { + localStorage.setItem('cart_id', cart.id); + //assuming you have a state variable to store the cart + setCart(cart); +}); +``` + + + + +```jsx +fetch(`/store/carts`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + region_id + }) +}) +.then((response) => response.json()) +.then(({cart}) => { + localStorage.setItem('cart_id', cart.id); + //assuming you have a state variable to store the cart + setCart(cart) +}); +``` + + + + +To learn about what parameters you can pass during the cart’s creation, check out the [JS Client Reference](../references/js-client/classes/CartsResource.md#create) or the [API Reference](/api/store#tag/Cart/operation/PostCart). + +## Retrieve a Cart + +Notice that in the previous code snippets, you set the cart’s ID in the local storage. This is helpful to persist the customer’s cart even when they leave the website and come back later. + +You can retrieve the cart at any given point using its ID with the following code snippet: + + + + +```jsx +const id = localStorage.getItem('cart_id'); + +if (id) { + client.carts.retrieve(id) + .then(({cart}) => setCart(cart)); +} +``` + + + + +```jsx +const id = localStorage.getItem('cart_id'); + +if (id) { + fetch(`/store/carts/${id}`) + .then((response) => response.json()) + .then(({cart}) => setCart(cart)); +} +``` + + + + +You can run this code snippet every time the storefront is opened. If a customer has a cart ID stored in their local storage, it’s loaded from the server. + +:::tip + +Make sure to remove the ID from the local storage after the customer places an order with this cart. + +::: + +## Update a Cart + +A cart has different data associated with it including the region, email, address, customer, and more. + +You can use the following snippet to update any of the cart’s data: + +```jsx +client.carts.update(cart.id, { + region_id +}) +.then(({cart}) => setCart(cart)); +``` + +```jsx +fetch(`/store/carts/${cart.id}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + region_id + }) +}) +.then((response) => response.json()) +.then(({cart}) => setCart(cart)); +``` + +This updates the region in the cart. + +To find out what data you can update in the cart, check out the [JS Client reference](../references/js-client/classes/CartsResource.md#update) or the [API reference](/api/store/#tag/Cart/operation/PostCartsCart). + +### Associate a Logged-In Customer with the Cart + +A customer might add items to their cart, then creates an account or log in. In that case, you should ensure that the cart is associated with the logged-in customer moving forward. + +This can be done using the same update operation: + + + + +```jsx +client.carts.update(cart.id, { + customer_id +}) +.then(({cart}) => setCart(cart)); +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + customer_id + }) +}) +.then((response) => response.json()) +.then(({cart}) => setCart(cart)); +``` + + + + +This updates the `customer_id` associated with the cart to make sure it belongs to a specific customer. + +### Associate Guest Customers with a Cart using Email + +In case the customer does not want to use their own account, you must at least associate an email address with the cart before completing the cart and placing the order. + +This can be done using the same update operation: + + + + +```jsx +client.carts.update(cart.id, { + email: 'user@example.com' +}) +.then(({cart}) => setCart(cart)); +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + email: 'user@example.com' + }) +}) +.then((response) => response.json()) +.then(({cart}) => setCart(cart)); +``` + + + + +## Add Line Item to the Cart + +To create a line item of a product and add it to a cart, you can use the following code snippet: + + + + +```jsx +client.carts.lineItems.create(cart.id, { + variant_id, + quantity: 1 +}) +.then(({cart}) => setCart(cart)); +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/line-items`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + variant_id, + quantity: 1 + }) +}) +.then((response) => response.json()) +.then(({cart}) => setCart(cart)); +``` + + + + +Where `variant_id` is the variant of the product you want to add to the cart. + +:::note + +If you’re using Sales Channels, make sure that the cart and the product belong to the same sales channel. You can update the cart’s sales channel by [updating the cart](#update-a-cart). + +::: + +This adds a new line item to the cart. Line items can be accessed using `cart.items` which is an array that holds all line items in the cart. You can learn more about what properties line items have in the [API reference](/api/store/#tag/Cart/operation/PostCartsCartLineItems). + +## Update Line Item in the Cart + +To update a line item in the cart, you can use the following code snippet: + + + + +```jsx +client.carts.lineItems.update(cart.id, line_item_id, { + quantity: 3 +}) +.then(({cart}) => setCart(cart)) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/line-items/${line_item_id}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + quantity: 3 + }) +}) +.then((response) => response.json()) +.then(({cart}) => setCart(cart)); +``` + + + + +This updates the quantity of the line item in the cart using the item’s ID. + +## Delete a Line Item from the Cart + +To delete a line item from the cart, you can use the following code snippet: + + + + +```jsx +client.carts.lineItems.delete(cart.id, line_item_id) +.then(({cart}) => setCart(cart)) +``` + + + + +```jsx +fetch(`/store/carts/${cart.id}/line-items/${line_item_id}`, { + method: 'DELETE' +}) +.then((response) => response.json()) +.then(({cart}) => setCart(cart)); +``` + + + + +This deletes a line item from the cart using the item’s ID. + +## What’s Next 🚀 + +- Learn [how to implement the checkout flow in your storefront](../advanced/storefront/how-to-implement-checkout-flow.mdx). +- Learn more about the [JS Client and how to use it](../js-client/overview.md). diff --git a/www/docs/sidebars.js b/www/docs/sidebars.js index 4c1941de5d..ea77fefcbc 100644 --- a/www/docs/sidebars.js +++ b/www/docs/sidebars.js @@ -268,10 +268,6 @@ module.exports = { } ] }, - { - type: "doc", - id: "guides/carts-in-medusa", - }, { type: "doc", id: "advanced/backend/migrations", @@ -304,6 +300,10 @@ module.exports = { type: "doc", id: "advanced/storefront/how-to-implement-checkout-flow", }, + { + type: "doc", + id: "guides/carts-in-medusa", + }, ] } ] diff --git a/www/docs/src/css/custom.css b/www/docs/src/css/custom.css index 3e4f918b06..118e1397fe 100644 --- a/www/docs/src/css/custom.css +++ b/www/docs/src/css/custom.css @@ -299,6 +299,10 @@ details summary { text-decoration: none; } +[data-theme="dark"] a:hover { + color: rgba(255, 255, 255, 0.8); +} + .DocSearch-Container { z-index: 1001 !important; }