Developer Blog

Calculating shopping cart price

In a default Sharetribe marketplace, a transaction price is calculated based on a single listing. With a shopping cart, we want to calculate the price of the transaction based on all the listings in the cart. In this blog series, we are diving into the ins and outs of building a multi-vendor shopping cart with single-vendor checkout using the Sharetribe Developer Platform.

Mar 11, 2024

A farmer's market table full of vegetables and their price signs, with cherry tomato baskets and their price sign in the forefront.

In a default Sharetribe marketplace, a transaction price is calculated based on a single listing. The price may also include shipping costs, as well as customer and provider commissions.

With a shopping cart, we want to calculate the price of the transaction based on all the listings in the cart. To do this, we need to modify the line item calculation in the template, since line items define the pricing of a transaction on a Sharetribe marketplace.

We need to make the following changes:

  • Add a new server endpoint for fetching cart line items
  • Add a dedicated calculation for cart line items
  • Modify OrderBreakdown.js component to handle multiple base price line items

All the code examples used in this guide can be found in this Gist.

The previous articles in this guide dived into

If you didn't already, read those first!

Add a new server endpoint for fetching cart line items


Most API calls from the Sharetribe Web Template front-end are made directly to Sharetribe using the Sharetribe SDK. However, the template server also has a handful of endpoints with customizable handling. Let’s add a new endpoint for fetching cart line items, similar to the default endpoint for fetching transaction line items.

   src
   ├── util
         ├── api.js

In src/util/api.js, add the following endpoint:

// Fetch cart transaction line items from the local API endpoint.
//
// See `server/api/cart-transaction-line-items.js` to see what data should
// be sent in the body.
export const cartTransactionLineItems = body => {
  return post('/api/cart-transaction-line-items', body);
};

Next, add the corresponding endpoint on the server side. 

server
	├── api
	│ 	├── cart-transaction-line-items.js
	├── api-util
	│ 	├── cartLineItems.js
	│ 	├── lineItemHelpers.js
	├── apiRouter.js

First, let’s create a new file in server/api/cart-transaction-line-items.js and add this code

This endpoint

  • parses listing ids from the cart and fetches then with the Sharetribe SDK
  • calls a helper function transactionLineItems imported from cartLineItems.js to calculate an array of line items based on the cart
  • enhances the line items to correspond with what the Sharetribe backend would create
  • returns the line item array to the frontend

Next, let’s add a new file to server/api-util called cartLineItems.js, and add this code

This function

  • only creates line items for orders with listings of unitType: item, because in this implementation only listings with that unit type can be added to cart
  • maps the cart listing array to line items
  • determines the shipping price based on the listing with the highest shipping price and additional price in the cart
  • calculates commissions similarly to the default line item calculation
  • returns an array of line items

This same line item calculation is eventually used when initiating the actual purchase of these items.

In server/api-util/lineItemHelpers.js, add the following helper function:

/**
 * Return listing ids from a single vendor shopping cart, filtering
 * out delivery method
 * @param {*} cart 
 * @returns 
 */
exports.getListingIdsFromCart = cart => {
  return Object.keys(cart).filter(key => key !== 'deliveryMethod');
};

Now, we can add the actual endpoint to the server/apiRouter.js file:

const cartTransactionLineItems = require('./api/cart-transaction-line-items');
...
// ================ API router endpoints: ================ //
...
router.post('/cart-transaction-line-items', cartTransactionLineItems);

Finally, you can uncomment the cartLineItems import from src/containers/CartPage/CartPage.duck.js:

import { cartTransactionLineItems } from '../../util/api';

Now, you can see a line item calculation on your cart page. However, we still need to modify the OrderBreakdown component to handle multiple base price line items, since now only the first line item is shown in the breakdown.

Update OrderBreakdown


Make the following changes in src/components/OrderBreakdown/OrderBreakdown.js file:

  const unitLineItems = lineItems.filter(li => li.code === lineItemUnitType);
  const basePrices = unitLineItems.map((uli, idx) => (
    <LineItemBasePriceMaybe lineItems={[uli]} key={idx} code={lineItemUnitType} intl={intl} />
  ));
...
	{/* replace the single LineItemBasePriceMaybe component with {basePrices} */}
	{basePrices} 
	<LineItemShippingFeeMaybe lineItems={lineItems} intl={intl} />
...

Now, you can see the full line item calculation on your cart page. The Buy now button also shows up, since the cart now has line items.

Summary


In this guide, we added line item calculation for our single vendor shopping cart. We made the following changes:

  • We added a new server endpoint for fetching cart line items
  • We added a dedicated calculation for cart line items
  • We modified OrderBreakdown.js component to handle multiple base price line items

In the next article, we will look at designing a transaction flow for a shopping cart purchase process!