In part 1 of the B2B series, you learned how to set up your Medusa server for a B2B ecommerce use case. You set up a B2B Sales Channel, Customer Groups, and Price List. You also added an endpoint that checks whether a customer is a B2B customer or not.
In this part of the series, you’ll customize Medusa’s Next.js storefront to add a Wholesaler login screen and a different way of displaying products for B2B customers. You’ll also explore how the checkout flow works for B2B customers.
You can find the full code for this tutorial series in this GitHub repository.
Install Next.js Storefront
In your terminal, run the following command to install the Next.js Storefront:
This installs the Next.js storefront in a newly created directory
.Copy to clipboardb2b-storefront
Then, change to the
directory and rename theCopy to clipboardb2b-storefront
file:Copy to clipboard.env.template
Install Dependencies
To ensure you’re using the latest version of Medusa dependencies, run the following command to update Medusa dependencies:
In addition, install
to send requests to the custom endpoint you created in the previous tutorial:Copy to clipboardaxios
Add Sales Channel Environment Variable
You’ll be using the Sales Channel you created in the first part to retrieve B2B products for B2B customers and to set the correct Sales Channel for B2B customers’ carts.
So, you need to set the ID of the sales channel in an environment variable.
If you’re unsure what the ID of the sales channel is, you can send a request to the List Sales Channel admin endpoint. You should find a Sales Channel with the name “B2B”. Copy the ID of that Sales Channel.
Then, add the following environment variable in
:Copy to clipboard.env.local
Where
is the ID of the B2B Sales Channel.Copy to clipboard<YOUR_SALES_CHANNEL_ID>
Create a Wholesale Login Page
In this section, you’ll add a login page specific to B2B customers. This requires adding some new pages and files, but also customizing existing logic.
Change AccountContext
The Next.js storefront defines an
that allows you to get access to customer-related data and functionalities across your storefront. You need to make changes to it to add a new variable to the context:Copy to clipboardAccountContext
. This variable will allow you to check whether the customer is a B2B customer or not throughout the storefront.Copy to clipboardis_b2b
In
, add theCopy to clipboardsrc/lib/context/account-context.tsx
attribute to theCopy to clipboardis_b2b
interface:Copy to clipboardAccountContext
Then, at the beginning of the
function, add a new state variableCopy to clipboardAccountProvider
:Copy to clipboardis_b2b
Next, add a new callback function
inside theCopy to clipboardcheckB2b
function:Copy to clipboardAccountProvider
This function sends a request to the
endpoint that you created in part 1. It then changes the value of theCopy to clipboard/store/customers/is-b2b
state variable based on the response received.Copy to clipboardis_b2b
You also run this callback function in
which triggers the function whenever there’s a change in the callback. In other words, whenever theCopy to clipboarduseEffect
is changed.Copy to clipboardcustomer
You also need to set the value of
back toCopy to clipboardis_b2b
when the customer logs out. You can add that in theCopy to clipboardfalse
function inCopy to clipboardhandleLogout
:Copy to clipboardAccountProvider
Lastly, pass
in theCopy to clipboardis_b2b
prop ofCopy to clipboardvalue
:Copy to clipboardAccountContext.Provider
These are all the changes necessary to enable checking whether the customer is a B2B customer or not throughout the storefront.
There’s also one last change to make that enhances the customer experience. Change the
function inCopy to clipboardcheckSession
to the following:Copy to clipboardAccountProvider
Previously, the function redirects the customer to
if they were trying to access account pages. To ensure that a guest customer gets redirected to the wholesaler login page when they try to access a wholesale page, you add a condition that determines where the guest customer should be redirected.Copy to clipboard/account/login
Change StoreContext
The Next.js storefront also defines a
that manages the store’s regions, cart, and more.Copy to clipboardStoreContext
In this section, you’ll make changes to the
to ensure the correct sales channel is assigned to B2B customers’ carts.Copy to clipboardStoreContext
In
, change theCopy to clipboardsrc/lib/context/store-context.tsx
function in theCopy to clipboardcreateNewCart
function to the following:Copy to clipboardStoreProvider
Previously, this function only passed the region ID to the
mutation. By making the above change you check first if the customer is a B2B customer and add theCopy to clipboardcreateCart
field to the data to be passed to theCopy to clipboardsales_channel_id
mutation.Copy to clipboardcreateCart
Next, change the
function in theCopy to clipboardresetCart
function to the following:Copy to clipboardStoreProvider
This change is similar to the previous change. It ensures that the correct sales channel ID is assigned to the cart when it’s reset.
Finally, change the
function insideCopy to clipboardensureCart
to the following:Copy to clipboarduseEffect
Similar to the previous changes, this ensures that when the storefront is opened and the cart is retrieved, the correct sales channel is assigned to the cart.
Change the Nav Component
To ensure customers can access the wholesale login page, you’ll add a new link to the navigation bar.
In
add the following in the returned JSX above the Account link:Copy to clipboardsrc/modules/layout/templates/nav/index.tsx
Add Login Form Component
The login page should display a login form for the customer.
To create the login form, create the file
with the following content:Copy to clipboardsrc/modules/wholesale/components/login/index.tsx
This login form shows the customer the fields
andCopy to clipboard
. When the customer submits the form and they’re authenticated successfully, you check if the customer is a B2B customer and accordingly update the cart’s sales channel ID.Copy to clipboardpassword
This is important as products can only be added to a cart that belongs to the same sales channel.
Add Login Template Component
The login template component will be displayed on the Login page.
Create the file
with the following content:Copy to clipboardsrc/modules/wholesale/templates/login-template.tsx
In this template, you first check if the customer is already logged in and redirect them to their account page based on whether they’re a B2B customer or not.
If the customer is not logged in, you show the
form component.Copy to clipboardLogin
Add Login Page
Create the file
with the following content:Copy to clipboardsrc/pages/wholesale/account/login.tsx
This is the login page that the customer sees when they access the
path. It shows theCopy to clipboard/wholesale/account/login
component.Copy to clipboardLoginTemplate
Add Wholesale Account Page
The last part you’ll add to finish the Wholesale login functionality is the account page for wholesalers. This page is shown when the B2B customer is logged in.
Create the file
with the following content:Copy to clipboardsrc/pages/wholesale/account/index.tsx
In this page, you first check whether the customer is logged in but they’re not a B2B customer. In that case, you redirect them to the
page which is used by other types of customers.Copy to clipboard/account
On this page, you show the same
that is shown by default for customers. This is for the simplicity of the tutorial. If you want to display other information to B2B customers, you can make the changes on this page.Copy to clipboardOverviewTemplate
Test Wholesale Login
Make sure the Medusa server you created in part 1 is running. Then, run the following command to run the Next.js storefront:
Open the storefront at
and click on the Wholesale Account link in the navigation bar. This will open the login page you created.Copy to clipboardlocalhost:8000
In part 1 you created a customer in a B2B customer group. Use the email and password of that customer to log in.
Once you’re logged in, you’ll be redirected to the
page.Copy to clipboard/wholesale/account
Create B2B Products Page
In this section, you’ll customize the current product page (available on the page
) to show products as a list of variants in a table. This makes it easier for B2B customers to view available products and their variants and add big quantities of them to the cart.Copy to clipboard/store
Change ProductContext
Another context that the Next.js storefront defines is the
which manages a product’s options, price, variants, and more.Copy to clipboardProductContext
You’ll be customizing this context to expose in the context the
function that allows setting the quantity to be added to the cart.Copy to clipboardsetQuantity
In
, add in theCopy to clipboardsrc/lib/context/product-context.tsx
interface theCopy to clipboardProductContext
function:Copy to clipboardsetQuantity
Then, add the function to the object passed to the
'sCopy to clipboardProductActionContext.Provider
prop:Copy to clipboardvalue
Please note that the function is already defined in the context with the
state variable.Copy to clipboardquantity
Create ProductActions Component
The
component is a component that displays a button and a quantity input and handles the add-to-cart functionality. It’ll be displayed for each variant in the products table.Copy to clipboardProductActions
Create the file
with the following content:Copy to clipboardsrc/modules/wholesale/components/product-actions/index.tsx
This component uses the
hook which exposes the values in theCopy to clipboarduseProductActions
. InCopy to clipboardProductContext
, it preselects the options in the current variant.Copy to clipboarduseEffect
It displays a quantity input and an add-to-cart button. Both the value of the quantity input and the add-to-cart handler are managed by
.Copy to clipboardProductContext
Create ProductPrice Component
The
component handles showing the correct variant price to the customer. It’ll be used to show the price of variants in the products table.Copy to clipboardProductPrice
Create the file
with the following content:Copy to clipboardsrc/modules/wholesale/components/product-price/index.tsx
This component uses the
hook which makes it easier to manage the price of a variant, then display the price to the customer.Copy to clipboarduseProductPrice
Create Products Component
The
component is the products table that will be shown to the B2B customer.Copy to clipboardProducts
Create the file
with the following content:Copy to clipboardsrc/modules/wholesale/components/products/index.tsx
This component retrieves the products in the B2B Sales Channel and displays them in a table. It also shows pagination controls to move between different pages.
For each product, you loop over its variants and display them one by one in different rows. For each variant, you use the
and theCopy to clipboardProductActions
components you created to show the quantity input, the add to cart button, and the variant’s price.Copy to clipboardProductPrice
Change Store Page
Currently, the store page displays products in an infinite-scroll mode for all customers. You’ll change it to display the Products table for B2B customers, and the infinite-scroll mode for other customers.
Change the content of
to the following:Copy to clipboardsrc/pages/store.tsx
You first retrieve
fromCopy to clipboardis_b2b
. Then, ifCopy to clipboarduseAccount
is false, you display theCopy to clipboardis_b2b
component. Otherwise, for B2B customers, you display theCopy to clipboardInfiniteProducts
component that you created.Copy to clipboardProducts
Change Store Dropdown
When you hover over the Store link in the navigation bar, it currently shows a dropdown with some products and collections. As this is distracting for B2B customers, you’ll remove it for them.
In
, retrieve theCopy to clipboardsrc/modules/layout/components/dropdown-menu/index.tsx
variable from theCopy to clipboardis_b2b
:Copy to clipboardAccountContext
And change the returned JSX to the following:
If
is true, the dropdown is hidden. Otherwise,Copy to clipboardis_b2b
is shown.Copy to clipboardis_b2b
Test Products Page
Make sure your Medusa server is still running and restart your Next.js storefront.
Then, open the Next.js storefront and, after logging in as a B2B customer, click on the Store link in the navigation bar at the top left. You’ll see your list of product variants in a table.
Notice how the prices of the variants are different than those shown to other customers. These prices are the prices you defined in the B2B Price List.
You can also test the prices with quantity-based conditions you added to the Price List. For example, if the condition was that product Medusa Hoodie’s variant S should have a different price if its quantity in the cart is more than 10, try changing the quantity to 10 or more and clicking Add to Cart. You’ll see a different price for that variant in the cart.
Test Checkout Flow
The checkout flow is pretty similar to those of regular customers:
- Add a couple of items to the cart from the table.
- Click on the My Bag link at the top right of the navigation bar.
- Click on Go to Checkout.
- Fill out the Shipping Address information and choose a Fulfillment method.
- Choose a payment method. Since in this tutorial you didn’t add any payment methods, you’ll use the manual payment method. However, you can integrate many other payment methods with Medusa such as Stripe or PayPal, or create your own.
- Click on the Checkout button.
This places the order on the Medusa server. Please note that Medusa does not capture the payment when an order is placed; it only authorizes it. You’ll need to capture it from the Medusa admin.
View Order Details on Medusa Admin
Run both the Medusa server and Medusa admin you created in part 1. Then, access the Medusa admin on
.Copy to clipboardlocalhost:7000
After logging in, you should see the list of orders in your store. In the list, you can see the payment status of the order, the sales channel, and more.
You should find the order you just created in the list. Click on the order to view its details.
On the order details page, you can see all the details of the order such as the items ordered, the payment and fulfillment details, the customer’s details, and more.
Capture Payment
To capture the payment of the order:
- Scroll to the Payment section.
- Click on the Capture Payment.
If you chose the Test payment provider during checkout, this will not actually do anything other than change the payment status of the order. If you’re using other payment providers such as Stripe, this is when the payment will actually be captured.
Conclusion
By following this two-part tutorial series, you should have the basis of a B2B ecommerce store built with Medusa. You can perform much more customizations and add additional features to your store including:
- Add a payment provider. As mentioned, you can add payment providers like Stripe and PayPal, or create your own.
- Create a Fulfillment Provider.
- Integrate search engines such as Algolia or MeiliSearch.
Should you have any issues or questions related to Medusa, then feel free to reach out to the Medusa team via Discord.
Share this post
Try Medusa
Spin up your environment in a few minutes.
