Get started with Medusa Part 3: Exploring our Admin Dashboard
Tags: webdev, javascript, tutorial, opensource
Published: 2021-12-21 10:00:30

In the previous parts of the series, I went over how to set up [Medus](https://www.medusajs.com/)[a](https://www.medusajs.com/), 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](https://github.com/shahednasser/medusa-admin-tutorial). You can also use [this GitHub repository](https://github.com/shahednasser/medusa-store-tutorial) 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](https://discord.gg/F87eGuwkTp).

## Dashboard Key Features

### Settings

![Settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6m1ad7v2ncowxpwxquwe.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4toob3ruw262tzmvnsj4.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/096ojez8ljrdygit9yfy.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ti1es2vmrhxihygftv31.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5veoxiyptsy9i3bxp5ks.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lo00kkl1ug3u11b1naag.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xd0j3yq97b50yhhq1e3t.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpg79o2yp6mo1t85qrkc.png)

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

![Create Draft Order - Customer](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7l05qm476ufh0hh0ebt.png)

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](https://www.invespcro.com/blog/ecommerce-product-return-rate-statistics/). 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xse7jdtyq1bu4x6zderd.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yp4rwhsst34kgg2zl9lc.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ohtl4962wlgwr57qbre9.png)

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](https://www.invespcro.com/blog/ecommerce-product-return-rate-statistics/).

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gsu0m9cpy8pa37v4x616.png)

### 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](https://docs.magento.com/user-guide/catalog/product-gift-card-create.html), 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](https://docs.medusajs.com/how-to/making-your-store-more-powerful-with-contentful) or [Strapi](https://strapi.io/) 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](https://sendgrid.com) or [Mailchimp](https://mailchimp.com).

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:

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

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

```js
    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()
      })
    })
```

This will make use of the [cors](https://expressjs.com/en/resources/middleware/cors.html) 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:

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

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:

```js
    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
```
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:

```js
    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)
        },
      }
```
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`:

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

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:

```js
    <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>
```

Everything is ready. Let’s try it out.

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

```bash
    npm start
```

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

```bash
    npm start
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7a1qp6ghz6uwuav974u2.png)

## 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](https://www.medusajs.com/post/admin-redesign). You can see the new design below. You can also sign-up for the release of the new Admin Dashboard [here](https://www.producthunt.com/upcoming/medusa-3). Disclaimer: The re-design will not change any of the functionality or steps from the walkthrough above.


![Admin Dashboard Redesigned](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0k2rscopimpjzgal3oi2.jpg)