DEV Community

Cover image for Get started with Medusa Part 3: Exploring our Admin Dashboard
Shahed Nasser for Medusa

Posted on • Updated on • Originally published at medusajs.com

Get started with Medusa Part 3: Exploring our Admin Dashboard

In the previous parts of the series, I went over how to set up Medusa, the project as a whole and how it compares against e-commerce platforms like Shopify. I also went over how to add new API endpoints, services, and subscribers. I added a new endpoint to retrieve the top products, a service to set and get a product’s number of sales, and a subscriber that, when an order is placed, increments a product’s number of sales.

In this section, you’ll learn more about the admin dashboard. You’ll see the main features of it and how they set Medusa apart from other e-commerce platforms. Then, as a continuation to what I added to the backend in the previous part, you’ll learn how to customize the admin platform by adding a page to view the top selling products.

The code for this tutorial can be found on this GitHub repository. You can also use this GitHub repository for the changes I made last time to Medusa’s backend. At last, should you have any questions in regard to the setup, then feel free to catch the Medusa team directly on their Discord.

Dashboard Key Features

Settings

Settings

Medusa provides an easy-to-use interface to manage the core settings and enable you to set up unique configurations across stores in different regions. Using the admin dashboard, you can manage simple settings like the website’s name, and more essential settings like currencies or shipping methods.

In the admin dashboard, you can add as many regions as you want to your store. Adding a region means you can specify for one or more countries a set of rules including tax rules, currency, payment methods, and more.

Regions Management

This allows you to customize each regional experience by providing local currency, payment, and shipping options in line with the customer needs and regulations of the paritcular region. This helps you cater your e-commerce platform to more users around the world, and provide optimized local solutions they are used to working with.

Medusa also comes with multi-currency support, and you can add all currencies to your store directly from the dashboard. You can specify the default currency and choose which other currencies that can be used in your store.

Multi-Currency Support

Adding to the customization possibilities, Medusa enables you to set specific prices for each product per currency. This allows you to manage and format the price yourself and you avoid many of the notriously bad looking price roudings that normally accumulates with non-customized pricing (e.g. a product costing $17.89 instead of just $18)

Multiple Prices

The regional adaptiability of Medusa was built-in because many of the existing solutions (e.g. Shopify, WooCommerce, etc.) lacked regional flexibility. To solve multi-currency problems or to integrate with local payment/shipping providers the solution for other platforms have often been to create seperate stores. This eventually leads to a setup where you have a new store for each market which is a real hurdle to maintain. Instead, Medusa ensures you can customize setting and collect orders across countries in one backend without the need to manage multiple stores at once.

Order Management

From the admin dashboard, you can view all orders and manage them efficiently. You can easily view the information of each order and the customer that placed the order, but you can also do much more than that.

On an order’s page, you can view all details necessary related to the customer and shipping and payment methods. You can also see a timeline that demonstrates clearly the stages this order went through until fulfillment for customer service purposes.

Order Details

Something you’ll notice as a constant throughout the main dashboard is that you can access any entity’s raw data right from the dashboard. The raw data is the information about that entity in JSON format, just how you’d receive it from the backend using the APIs. For developers, this is a time-saving features as you don’t have to send out requests to the server whenever you need to debug or check something. You can just view it on the dashboard. This applies to orders, products, and other entities as well.

Raw Data

In addition, you can fulfill an order, which means shipping it out to the customer, using the shipping methods you add to your store. You can also mark items shipped or cancel shipping items for easily maneuvering as a customer service professional.

Create Fulfilment

Another feature that Medusa provides for order management is the ability to create draft orders directly from the admin. A lot of businesses take orders from different channels, not just on the website. If a business takes an order over the phone, for example, it becomes a hassle to manage orders separately from the website’s orders.

On the admin dashboard, you can create a draft order that helps solve such use cases. When you create an order, you can search from the products already existing on the platform and add them to the order. Alternatively, you can add a custom item that doesn’t necessarily exist on the platform. This is very useful if you sell different products or services on different channels.

Create Draft Order - Items

You can also either select an existing customer for the order or create a new one.

Create Draft Order - Customer

You can choose a shipping method and even set a custom price for it. This feature is pretty detailed and makes managing orders, regardless of their origin, very simple.
**

Exchanges, Swaps, and Claim Handling

30% of e-commerce orders are returned. The customer might not like the product. The size didn’t fit them or they picked a wrong size. In worse cases, there could be a defect in the product.

Although this is something essential to handle, most e-commerce platforms don’t support the handling of these cases natively and you would need to purchase external plugins or modules to add such features.

Medusa provides support of these features out of the box. In the admin panel, you can issue a return request for any item in an order. You can specify the shipping method to use, and the refund amount, if any.

Request Return

In addition, you can issue a swap request. You can swap an item for another with details regarding the shipping method to use and the difference in the amount after the swap.

Create Swap

You can also create a claim to handle different cases or log reasons of why an item should be returned or replaced. This option offers more details when handling certain cases of malfunctioned items, wrong items delivered, and more.

Create Claim

And the best part about all of this is that these features are automated. For the customer, they can always file a return request. They will then receive and email with the next steps they need to take to return the order. This leads to better user experience, and as research suggest, 92% of customers end up placing orders in the future if the order return experience was easy and simple.

The automation of these features also affect the accounting side of things. Any refunded amounts or additional amounts added due to a refund or swap is all logged in the system and automatically cleared on the acoounting side so that you do not need to manually adjust for differences between swaps or return orders.

Other Features

In addition to some of these key features, Medusa offers the basic features you expect from every e-commerce platform.

Product Management

On the admin dashboard, you can manage your products including variants, stock and inventory, and more.

Product Information

Customer Management

You can likewise manage your customers from the admin dashboard. You can see their order details, shipping address, and more.

Discount Management

The admin dashboard also lets you add and manage discounts with many options. These options include number of usages, type of discount (free shipping or fixed amount), how to apply the discount, and more.

Gift Cards

Another cool feature that the admin dashboard has is managing gift cards. As opposed to other platforms like Magento that only offer Gift Cards for their paid commerce version, Medusa lets you add gift cards and manage details like image, values, description, and more.

Easily Add Integrations

The coolest part about Medusa is that you can integrate popular or custom services easily into the admin dashboard. You can integrate the admin dashboard with CMS tools like Contentful or Strapi to add more CMS related fields and features.

You can also add integrations that help you manage your platform’s marketing and analytics. You can integrate email services like Sendgrid or Mailchimp.

Of course, you can add your own custom integrations as well based on your use case. For example, you can add integrations for payment or shipment methods that are specific to your local customers.

Round Up

Comparing Medusa to many of the existing proprietary platforms on the market, it is clear that much of the standard ecommerce functionalities are built-in to Medus. In additon, there has been a focus on adding additional value in areas that were not well covered such as regional extendibility, exchange/return handling etc.

In addition, due to its open source nature you can customize the admin dashboard as it fits your needs. From the look and feel to the functionalities it provides. You can change up the admin panel to make it your own.

Customize the Admin Dashboard

A unique attribute for an open-source project like Medusa which really do not set any boundaries to the types of customization you want to make on the backend. In this section, you will learn how to customize the Admin dashboard to add your own features. As a continuation to the previous part, you will add a page to view the top selling products on the admin dashboard.

Add Admin Endpoint
In the last tutorial, you added an endpoint on the backend to get the top selling endpoints. This time, you’ll add the same endpoint for the admin side to access.

To make sure the admin panel is able to access the endpoint, you need to add some configurations related to cross-origin resource sharing (or CORS).

In the backend in the file src/api/index.js add the following imports at the top of the file:



    import bodyParser from "body-parser"
    import cors from "cors"
    import { projectConfig } from "../../medusa-config"


Enter fullscreen mode Exit fullscreen mode

Then, below the endpoint added in the previous tutorial, add the following:



    const corsOptions = {
      origin: projectConfig. admin_cors.split(","),
      credentials: true,
    }
    router.options('/admin/top-products', cors(corsOptions))
    router.get("/admin/top-products", cors(corsOptions), bodyParser.json(), async (req, res) => {
      const topProductsService = req.scope.resolve("topProductsService")
      res.json({
        products: await topProductsService.getTopProducts()
      })
    })


Enter fullscreen mode Exit fullscreen mode

This will make use of the cors middleware, passing it the admin CORS configuration from medusa-config.js in the root of the backend. Then, you add an OPTIONS and GET endpoints. In the GET endpoint, you retrieve the top products just like you did last time.

Add New Admin Page
Next, you’ll add the new admin page to show the top products. You’ll add the page as a sub-page of the Products section of the admin panel. So, you need to add the page and add it in the sidebar under Products.

Pages in the admin dashboard are added under the directory src/domain. In that directory, top pages in the admin dashboard are the main directories, then, inside each of those directories you’ll find JavaScript files for each page.

Let’s take a look at the products directory, for instance. You’ll find inside it an index.js file, which includes the page that you first see when you click on Products in the sidebar. You’ll also find a router inside the file like the following:



    const Products = () => {
      return (
        <Router>
          <ProductIndex path="/" />
          <Details path=":id" />
          <New path="new" />
        </Router>
      )
    }


Enter fullscreen mode Exit fullscreen mode

This adds nested routes under the /products route.

You’ll find under the products directory other directories with nested files for each page.

So, to add a new page you need to create the file top-selling.js under the products directory, then add it as a nested route in index.js.

Create the file src/domain/products/top-selling.js with the following content:



    import React, { useState } from "react"
    import { Link } from "gatsby"
    import _ from "lodash"
    import { Flex, Text, Box, Image } from "rebass"
    import ImagePlaceholder from "../../assets/svg/image-placeholder.svg"
    import Spinner from "../../components/spinner"
    import {
      Table,
      TableHead,
      TableHeaderCell,
      TableHeaderRow,
      TableBody,
      TableRow,
      TableDataCell,
      DefaultCellContent,
    } from "../../components/table"
    import useMedusa from "../../hooks/use-medusa"
    import styled from "@emotion/styled"
    const LinkWrapper = styled(Link)`
      width: 100%;
      height: 100%;
      text-decoration: none;
      color: black;
      > div {
        color: blue;
      }
      &:focus {
        outline: none;
      }
      display: flex;
    `
    const TopSelling = () => {
      const {
        products,
        hasCache,
        isLoading,
        isReloading,
      } = useMedusa("topSelling")
      return (
        <Flex flexDirection="column" pb={5} pt={5}>
          <Flex>
            <Text mb={3} fontSize={20} fontWeight="bold">
              Top Selling Products
            </Text>
          </Flex>
          {(isLoading && !hasCache) || isReloading ? (
            <Flex
              flexDirection="column"
              alignItems="center"
              height="100vh"
              mt="20%"
            >
              <Box height="50px" width="50px">
                <Spinner dark />
              </Box>
            </Flex>
          ) : (
            <Table>
              <TableHead>
                <TableHeaderRow>
                  <TableHeaderCell sx={{ maxWidth: "75px" }} />
                  <TableHeaderCell>Name</TableHeaderCell>
                  <TableHeaderCell>Number of Sales</TableHeaderCell>
                </TableHeaderRow>
              </TableHead>
              <TableBody>
                {products.map(p => {
                  return (
                    <TableRow key={p.id}>
                      <LinkWrapper
                        to={`/a/products${p.is_giftcard ? "/gift-card" : ""}/${
                          p.id
                        }`}
                      >
                        <TableDataCell
                          maxWidth="75px"
                          p={2}
                          height="100%"
                          textAlign="center"
                        >
                          <DefaultCellContent>
                            <Image
                              src={p.thumbnail || ImagePlaceholder}
                              height={38}
                              width={38}
                              p={!p.thumbnail && "8px"}
                              sx={{
                                objectFit: "contain",
                                border: "1px solid #f1f3f5",
                              }}
                            />
                          </DefaultCellContent>
                        </TableDataCell>
                        <TableDataCell>
                          <DefaultCellContent>{p.title}</DefaultCellContent>
                        </TableDataCell>
                        <TableDataCell>
                          <DefaultCellContent>
                            {p.metadata.sales}
                          </DefaultCellContent>
                        </TableDataCell>
                      </LinkWrapper>
                    </TableRow>
                  )
                })}
              </TableBody>
            </Table>
          )}
        </Flex>
      )
    }
    export default TopSelling


Enter fullscreen mode Exit fullscreen mode

This creates the component TopSelling which uses the useMedusa hook to get the top selling products, then show them in a table with the image, name, and number of sales of the product.

The useMedusa hook, which resides in src/hooks/use-medusa.js takes as a first parameter an endpoint name. You can use any of Medusa’s default endpoints like products or orders. useMedusa will check if the endpoint exists in src/services/api.js, then, executes the request to retrieve the data.

So, in order to make sure useMedusa("topSelling") retrieves the top selling products from the custom endpoint you created earlier, you need to add to the exported object in src/services/api.js the following property at the end of it:



    topSelling: {
        list(search = {}) {
          const params = Object.keys(search)
            .map(k => `${k}=${search[k]}`)
            .join("&")
          let path = `/admin/top-products${params && `?${params}`}`
          return medusaRequest("GET", path)
        },
      }


Enter fullscreen mode Exit fullscreen mode

This will send a GET request to /admin/top-products with any parameters that might be passed to the function.

The TopSelling component is ready. You can now add it to the nested router in src/domain/products/index.js:



    const Products = () => {
      return (
        <Router>
          <ProductIndex path="/" />
          <Details path=":id" />
          <New path="new" />
          <TopSelling path="top-selling" />
        </Router>
      )
    }


Enter fullscreen mode Exit fullscreen mode

The last thing left to do is add the link in the sidebar below the Products link. In src/components/sidebar/index.js Find the link to Products and add the link below it next to the Collections link:



    <StyledItemContainer
      to="/a/products/top-selling"
      activeClassName="active"
      partiallyActive
    >
      <Flex alignItems="center" pl={3} width="100%">
        <Text ml="14px" variant="nav" fontSize="12px">
          Top Selling
        </Text>
      </Flex>
    </StyledItemContainer>


Enter fullscreen mode Exit fullscreen mode

Everything is ready. Let’s try it out.

Start the backend server if it’s not started yet with the following command:



    npm start


Enter fullscreen mode Exit fullscreen mode

Then, start the server for the admin dashboard with the following command:



    npm start


Enter fullscreen mode Exit fullscreen mode

Go to the Admin panel link, which by default is localhost:7000 unless yours started at a different port. You will need to login with your admin credentials. By default, Medusa comes with a test admin user admin@medusa-test.com with the password supersecret.

Once you login, click on Products, and once the sidebar item expands you should see a new menu item Top Selling. If you click on it, a new page should open showing a table of top selling products with the number of sales for each of them.

Top Selling Products

Conclusion and teaser

In this tutorial, you learned all the great features in the admin dashboard and how to add your own! You can utilize Medusa’s power to tackle most e-commerce use cases, and for your own unique use cases you can easily add your own features into the admin dashboard.

In the next part of the series, you’ll learn about Medusa’s storefront. You’ll create a new component on the frontend that will utilize the top-products endpoint to show the user the store’s top products.

Throughout the article, I have used pictures from the current Admin Dashboard as per December, 2021. However, a redesign of the dasboard will be released in mid-January and early mock-ups and a feature walkthrough was recently released. Read more here. You can see the new design below. You can also sign-up for the release of the new Admin Dashboard here. Disclaimer: The re-design will not change any of the functionality or steps from the walkthrough above.

Admin Dashboard Redesigned

Top comments (1)

Collapse
 
peteregbujie profile image
Peter Egbujie

Will be using MedusaJS. Thank you for this post.