How to Add Customer Profile to Your Next.js Ecommerce Store
Tags: javascript, programming, webdev, opensource
Published: 2022-04-14 11:03:43

[Medusa](https://medusajs.com) is an open source headless commerce platform that aims to provide developers with a great developer experience. Although it provides [Next.js](https://docs.medusajs.com/starters/nextjs-medusa-starter) and [Gatsby](https://docs.medusajs.com/starters/gatsby-medusa-starter) storefronts to use, you can also use any storefront of your choice.

To make your developer experience even easier, Medusa provides a [client NPM package](https://www.npmjs.com/package/@medusajs/medusa-js) that you can use with JavaScript and Typescript frameworks.

In this tutorial, you’ll learn how to install and use the Medusa JS Client in your storefront to implement a customer sign-up and profile flow.

You can find the code for this tutorial in [this GitHub repository](https://github.com/shahednasser/medusa-customer-storefront).

## Prerequisites

This tutorial assumes you already have a Medusa server installed. If not, please follow along the [quickstart guide](https://docs.medusajs.com/quickstart/quick-start).

Furthermore, this tutorial uses the [Next.js starter](https://docs.medusajs.com/starters/nextjs-medusa-starter) to implement the customer profile. However, the tutorial will focus on how to use the Medusa JS Client in particular. So, you can still follow along if you are using a different framework for your storefront.

## Install the Medusa JS Client

In your storefront project’s directory, install the Medusa JS client if you don’t have it installed already:

```bash
npm install @medusajs/medusa-js
```

> If you’re using our Next.js or [Gatsby](https://docs.medusajs.com/starters/gatsby-medusa-starter) starters, then you don’t need to install it.
> 

## Initialize Client

In the Next.js starter, the client is initialized in `utils/client.js` and you can just import it into your components. However, if you’re using your custom storefront here’s how you can initialize the Medusa client:

```jsx
const client = new Medusa({ baseUrl: BACKEND_URL });
```

Where `BACKEND_URL` is the URL to your Medusa server.

You can then use the methods and resources in the client to send all types of requests to your Medusa server which you’ll see later in this tutorial.

## Add Styles

This step is optional and can be skipped. To add some styling for the rest of the tutorial, you can create the file `styles/customer.module.css` with [this content](https://github.com/shahednasser/medusa-customer-storefront/blob/master/styles/customer.module.css).

## Add Customer to Context

In the Next.js starter, the `StoreContext` holds all variables and methods important to the store like the `cart` object.

In this section, you’ll add a variable and a method to the context: `customer` and `setCustomer` respectively.

In the `defaultStoreContext` variable in `context/store-context.js` add the following:

```jsx
export const defaultStoreContext = {
	...,
	customer: null,
	setCustomer: async () => {}
}
```

Then, in the `reducer` function, add a case for the `setCustomer` action:

```jsx
case "setCustomer":
      return {
        ...state,
        customer: action.payload
      }
```

Inside the `StoreProvider` function, add inside the `useEffect` under the cart initialization the following to retrieve the customer if they are logged in and set it in the context:

```jsx
//try to retrieve customer
client.auth.getSession()
  .then(({customer}) => {
    setCustomer(customer)
  })
  .catch((e) => setCustomer(null))
```

Notice here that you’re using `client.auth.getSession`. `client` has been initialized earlier in the file, so if you’re implementing this in your own storefront you’d need to initialize it before this code snippet.

Then, you use `auth.getSession` which allows you to [retrieve the current logged in customer](https://docs.medusajs.com/api/store/auth/get-session), if there is any.

If the customer is logged in and is returned in the response, you set it in the context, otherwise you set the customer to `null`.

Then, add a new function inside `StoreProvider` to handle setting the customer:

```jsx
const setCustomer = (customer) => {
    dispatch({type: 'setCustomer', payload: customer})
}
```

This will just dispatch the action to the reducer which will set the customer object in the context.

Finally, add the `setCustomer` function to the `value` prop of `StoreContext.Provider` returned in `StoreProvider`:

```jsx
return (
    <StoreContext.Provider
      value={{
        ...,
        setCustomer
      }}
    >
      {children}
    </StoreContext.Provider>
  )
```

## Create Sign Up and Sign In Pages

In this section, you’ll create the sign up and sign in pages to allow the customer to either create an account or log in with an existing one.

### Sign Up Page

Create the file `pages/sign-up.js` with the following content:

```jsx
import * as Yup from 'yup';

import { useContext, useEffect, useRef } from 'react';

import StoreContext from '../context/store-context';
import { createClient } from "../utils/client"
import styles from "../styles/customer.module.css";
import { useFormik } from "formik";
import { useRouter } from 'next/router';

export default function SignUp() {
  const router = useRouter();
  const { setCustomer, customer } = useContext(StoreContext)
  useEffect(() => {
    if (customer) {
      router.push("/")
    }
  }, [customer, router])
  const buttonRef = useRef();
  const { handleSubmit, handleBlur, handleChange, values, touched, errors } = useFormik({
    initialValues: {
      email: '',
      first_name: '',
      last_name: '',
      password: ''
    },
    validationSchema: Yup.object().shape({
      email: Yup.string().email().required(),
      first_name: Yup.string().required(),
      last_name: Yup.string().required(),
      password: Yup.string().required()
    }),
    onSubmit: function (values) {
      if (buttonRef.current) {
        buttonRef.current.disabled = true;
      }

      const client = createClient()

      client.customers.create({
        email: values.email,
        first_name: values.first_name,
        last_name: values.last_name,
        password: values.password
      }).then(({ customer }) => {
        setCustomer(customer);
      })
    }
  })
  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <form onSubmit={handleSubmit} className={styles.signForm}>
          <h1>Sign Up</h1>
          <div className={styles.inputContainer}>
            <label htmlFor="email">Email</label>
            <input type="email" name="email" id="email" className={styles.input} 
              onChange={handleChange} onBlur={handleBlur} value={values.email} />
            {errors.email && touched.email && <span className={styles.error}>{errors.email}</span>}
          </div>
          <div className={styles.inputContainer}>
            <label htmlFor="first_name">First Name</label>
            <input type="text" name="first_name" id="first_name" className={styles.input} 
              onChange={handleChange} onBlur={handleBlur} value={values.first_name} />
            {errors.first_name && touched.first_name && <span className={styles.error}>{errors.first_name}</span>}
          </div>
          <div className={styles.inputContainer}>
            <label htmlFor="last_name">Last Name</label>
            <input type="text" name="last_name" id="last_name" className={styles.input} 
              onChange={handleChange} onBlur={handleBlur} value={values.last_name} />
            {errors.last_name && touched.last_name && <span className={styles.error}>{errors.last_name}</span>}
          </div>
          <div className={styles.inputContainer}>
            <label htmlFor="password">Password</label>
            <input type="password" name="password" id="password" className={styles.input} 
              onChange={handleChange} onBlur={handleBlur} value={values.password} />
            {errors.password && touched.password && <span className={styles.error}>{errors.password}</span>}
          </div>
          <div className={styles.inputContainer}>
            <button type="submit" className={styles.btn} ref={buttonRef}>Sign Up</button>
          </div>
        </form>
      </main>
    </div>
  )
}
```

In this page, you use [Formik and Yup](https://formik.org/docs/guides/validation) to create and validate the form. This form has 4 fields: email, first name, last name, and password. These fields are required to sign up a customer in Medusa.

The important bit here is the part that uses the Medusa client in the `onSubmit` function passed to `useFormik`:

```jsx
const client = createClient()

client.customers.create({
  email: values.email,
  first_name: values.first_name,
  last_name: values.last_name,
  password: values.password
}).then(({ customer }) => {
  setCustomer(customer);
})
```

You first initialize the Medusa client. You use the utility function in `utils/client.js` to do that, but if you don’t have that in your storefront you can replace it with the initialization mentioned earlier in the tutorial.

Then, you use `client.customers.create` which will send a request to the [create customer endpoint](https://docs.medusajs.com/api/store/customer/create-a-customer). This endpoint requires the `email`, `first_name`, `last_name`, and `password` fields.

If the sign up is successful, the `customer` object will be returned and a session token will be saved in the cookies to keep the user logged in. You use the `customer` object to set the customer in the context.

Notice also that at the beginning of the component you check if the customer is already logged in and redirect them to the home page in that case:

```jsx
useEffect(() => {
  if (customer) {
    router.push("/")
  }
}, [customer, router])
```

### Sign In Page

Next, create the file `pages/sign-in.js` with the following content:

```jsx
import * as Yup from 'yup';

import { useContext, useEffect, useRef } from 'react';

import StoreContext from '../context/store-context';
import { createClient } from "../utils/client"
import styles from "../styles/customer.module.css";
import { useFormik } from "formik";
import { useRouter } from 'next/router';

export default function SignIn() {
  const router = useRouter();
  const { setCustomer, customer } = useContext(StoreContext)
  useEffect(() => {
    if (customer) {
      router.push("/")
    }
  }, [customer, router])
  const buttonRef = useRef();
  const { handleSubmit, handleBlur, handleChange, values, touched, errors } = useFormik({
    initialValues: {
      email: '',
      password: ''
    },
    validationSchema: Yup.object().shape({
      email: Yup.string().email().required(),
      password: Yup.string().required()
    }),
    onSubmit: function (values) {
      if (buttonRef.current) {
        buttonRef.current.disabled = true;
      }

      const client = createClient()

      client.auth.authenticate({
        email: values.email,
        password: values.password
      }).then(({ customer }) => {
        setCustomer(customer);
      })
    }
  })
  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <form onSubmit={handleSubmit} className={styles.signForm}>
          <h1>Sign In</h1>
          <div className={styles.inputContainer}>
            <label htmlFor="email">Email</label>
            <input type="email" name="email" id="email" className={styles.input} 
              onChange={handleChange} onBlur={handleBlur} value={values.email} />
            {errors.email && touched.email && <span className={styles.error}>{errors.email}</span>}
          </div>
          <div className={styles.inputContainer}>
            <label htmlFor="password">Password</label>
            <input type="password" name="password" id="password" className={styles.input} 
              onChange={handleChange} onBlur={handleBlur} value={values.password} />
            {errors.password && touched.password && <span className={styles.error}>{errors.password}</span>}
          </div>
          <div className={styles.inputContainer}>
            <button type="submit" className={styles.btn} ref={buttonRef}>Sign In</button>
          </div>
        </form>
      </main>
    </div>
  )
}
```

This page also makes use of Formik and Yup to create and validate the form. This form only needs an email and a password.

The important bit is in the `onSubmit` function passed to `useFormik`:

```jsx
const client = createClient()

client.auth.authenticate({
  email: values.email,
  password: values.password
}).then(({ customer }) => {
  setCustomer(customer);
})
```

Just like before, you start by initializing the Medusa client. Then, you authenticate the customer using `client.auth.authenticate` which calls the [Authenticate Customer](https://docs.medusajs.com/api/store/auth/authenticate-customer) endpoint. This endpoint requires 2 parameters: `email` and `password`.

If successful, a customer object is returned which you use to set the customer in the store context using `setCustomer`. A cookie will also be set to maintain the login session for the customer.

### Add Links to Navigation Bar

Finally, in `components/layout/nav-bar.jsx` , initialize the customer from the `StoreContext`:

```jsx
const { cart, customer } = useContext(StoreContext)
```

Then, in the returned JSX add the following to add a link to the new pages:

```jsx
{!customer && <Link href="/sign-up">Sign Up</Link>}
{!customer && <Link href="/sign-in">Sign In</Link>}
{customer && <Link href="/customer">Profile</Link>}
```

Notice that you also add a link to the customer profile, which you’ll implement in the next section.

### Test it Out

Make sure that the Medusa server is running first. Then, run the server for your storefront:

```jsx
npm run dev
```

If you open `localhost:8000` now, you’ll see that there are 2 new links in the navigation bar for sign up and sign in.

![Navigation Links](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/napt5gty206pkng02iiz.png)

You can try clicking on Sign Up and registering as a new user.

![Sign Up Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s6sg76b5rqa5vbpb501f.png)

Or click Sign In and log in as an existing user.

![Sign In Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kl9vlcv6erjxj0q78go3.png)

Once you’re logged in, you should be redirected back to the home page and you should see a Profile link in the navigation bar.

## Add Customer Profile

The customer profile will have 3 pages: Edit customer info, view orders, and view addresses.

### Create Profile Layout

You’ll start by creating a layout that all profile pages will use.

Create `components/layout/profile.jsx` with the following content:

```jsx
import { useContext, useEffect } from 'react';

import Link from 'next/link';
import StoreContext from '../../context/store-context';
import styles from "../../styles/customer.module.css";
import { useRouter } from 'next/router';

export default function Profile ({children, activeLink}) {
  const router = useRouter()
  const { customer } = useContext(StoreContext)
  useEffect(() => {
    if (!customer) {
      router.push('/')
    }
  }, [customer, router])

  return (
    <div className={styles.container}>
      <main className={styles.main}>
        <div className={styles.profile}>
          <div className={styles.profileSidebar}>
            <Link href="/customer">
              <a className={activeLink === 'customer' ? styles.active : ''}>Edit Profile</a>
            </Link>
            <Link href="/customer/orders">
              <a className={activeLink === 'orders' ? styles.active : ''}>Orders</a>
            </Link>
            <Link href="/customer/addresses">
              <a className={activeLink === 'addresses' ? styles.active : ''}>Addresses</a>
            </Link>
          </div>
          <div className={styles.profileContent}>
            {children}
          </div>
        </div>
      </main>
    </div>
  )
}
```

This first checks the customer and context to see if the user is logged in. Then, it displays a sidebar with 3 links, and the main content displays the children.

### Create Edit Profile Page

The edit profile page will be the main customer profile page. Create the file `pages/customer/index.js` with the following content:

```jsx
import * as Yup from 'yup';

import { useContext, useRef } from 'react';

import Profile from '../../components/layout/profile';
import StoreContext from "../../context/store-context";
import { createClient } from "../../utils/client"
import styles from "../../styles/customer.module.css";
import { useFormik } from 'formik';

export default function CustomerIndex() {
  const { customer, setCustomer } = useContext(StoreContext)
  const buttonRef = useRef()
  const { handleSubmit, handleChange, handleBlur, values, errors, touched } = useFormik({
    initialValues: {
      email: customer?.email,
      first_name: customer?.first_name,
      last_name: customer?.last_name,
      password: ''
    },
    validationSchema: Yup.object().shape({
      email: Yup.string().email().required(),
      first_name: Yup.string().required(),
      last_name: Yup.string().required(),
      password: Yup.string()
    }),

    onSubmit: (values) => {
      buttonRef.current.disabled = true;

      const client = createClient()

      if (!values.password) {
        delete values['password']
      }

      client.customers.update(values)
        .then(({ customer }) => {
          setCustomer(customer)
          alert("Account updated successfully")
          buttonRef.current.disabled = false;
        })
    }
  })

  return (
    <Profile activeLink='customer'>
      <form onSubmit={handleSubmit}>
        <h1>Edit Profile</h1>
        <div className={styles.inputContainer}>
          <label htmlFor="email">Email</label>
          <input type="email" name="email" id="email" className={styles.input} 
            onChange={handleChange} onBlur={handleBlur} value={values.email} />
          {errors.email && touched.email && <span className={styles.error}>{errors.email}</span>}
        </div>
        <div className={styles.inputContainer}>
          <label htmlFor="first_name">First Name</label>
          <input type="text" name="first_name" id="first_name" className={styles.input} 
            onChange={handleChange} onBlur={handleBlur} value={values.first_name} />
          {errors.first_name && touched.first_name && <span className={styles.error}>{errors.first_name}</span>}
        </div>
        <div className={styles.inputContainer}>
          <label htmlFor="last_name">Last Name</label>
          <input type="text" name="last_name" id="last_name" className={styles.input} 
            onChange={handleChange} onBlur={handleBlur} value={values.last_name} />
          {errors.last_name && touched.last_name && <span className={styles.error}>{errors.last_name}</span>}
        </div>
        <div className={styles.inputContainer}>
          <label htmlFor="password">Password</label>
          <input type="password" name="password" id="password" className={styles.input} 
            onChange={handleChange} onBlur={handleBlur} value={values.password} />
          {errors.password && touched.password && <span className={styles.error}>{errors.password}</span>}
        </div>
        <div className={styles.inputContainer}>
          <button type="submit" className={styles.btn} ref={buttonRef}>Save</button>
        </div>
      </form>
    </Profile>
  )
}
```

This is very similar to the sign-up form. You use Formik and Yup to create and validate the form. The form has 4 inputs: `email`, `first_name`, `last_name`, and `password` which is optional.

The important bit here is the part in the `onSubmit` function passed to `useFormik`:

```jsx
const client = createClient()

if (!values.password) {
  delete values['password']
}

client.customers.update(values)
  .then(({ customer }) => {
    setCustomer(customer)
    alert("Account updated successfully")
    buttonRef.current.disabled = false;
  })
```

Just like you’ve done before, you start by initializing the Medusa client. Then, if the password is not set, you remove it from the list of values since you’ll be passing it to the server as-is. You should only pass the password if the customer wants to change it.

To update the customer info, you can use `client.customers.update` which sends a request to the [Update Customer](https://docs.medusajs.com/api/store/customer/update-customer-details) endpoint. This endpoint accepts a few optional parameters including `email`, `last_name`, `first_name`, and `password`.

If the customer info is updated successfully, a customer object is returned which you use to set the updated customer in the context. You also show an alert to the customer that their account is now updated.

If you click on the Profile link in the navigation bar now, you’ll see the profile page with the sidebar and the edit profile page as the first page.

![Profile Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fydqjs6pyv5cziarew9q.png)

Try updating any of the information and click Save. You should then see an alert to let you know that it’s been updated successfully.


![Update Alert](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q6i7mkw1jw3f1jkir2hh.png)

### Orders Page

The next page you’ll create is an orders page which will display the customer’s orders.

Create a new file `pages/customer/orders.js` with the following content:

```jsx
import { useEffect, useState } from 'react';

import Link from 'next/link';
import Profile from '../../components/layout/profile';
import { createClient } from "../../utils/client"
import { formatMoneyAmount } from '../../utils/prices';
import styles from "../../styles/customer.module.css";
import { useRouter } from 'next/router';

export default function Orders () {
  const [orders, setOrders] = useState([])
  const [pages, setPages] = useState(0)
  const router = useRouter()
  const p = router.query.p ? parseInt(router.query.p - 1) : 0
  
  useEffect(() => {
    const client = createClient()

    client.customers.listOrders({
      limit: 20,
      offset: 20 * p
    }).then((result) => {
      setOrders(result.orders)
      setPages(Math.ceil(result.count / result.limit))
    })
  }, [p])

  return (
    <Profile activeLink='orders'>
      <h1>Orders</h1>
      <table className={styles.table}>
        <thead>
          <tr>
            <th>ID</th>
            <th>Total</th>
            <th>Status</th>
          </tr>
        </thead>
        <tbody>
          {orders.map((order) => (
            <tr key={order.id}>
              <td>{order.id}</td>
              <td>{formatMoneyAmount({
                currencyCode: order.currency_code,
                amount: order.total
              }, 2)}</td>
              <td>{order.status}</td>
            </tr>
          ))}
        </tbody>
      </table>
      <div className={styles.pagination}>
        {pages > 0 && p > 1 && (
          <Link href={`/customer/orders?p=${p - 1}`}>Previous</Link>
        )}
        {pages > 1 && p > 0 && p < pages && <span> - </span>}
        {pages > 1 && (p + 1) < pages && (
          <Link href={`/customer/orders?p=${p + 1}`}>Next</Link>
        )}
      </div>
    </Profile>
  )
}
```

You first create an `orders` state variable which starts out as empty. You also have a `pages` state variable to keep track of the number of pages available. Then, in `useEffect`, you retrieve the orders using the Medusa client:

```jsx
useEffect(() => {
  const client = createClient()

  client.customers.listOrders({
    limit: 20,
    offset: 20 * p
  }).then((result) => {
    setOrders(result.orders)
    setPages(Math.ceil(result.count / result.limit))
  })
}, [p])
```

After initializing the client, you retrieve the orders of the customer using `client.customers.listOrders`. This method sends a request to the [Retrieve Customer Orders endpoint](https://docs.medusajs.com/api/store/customer/retrieve-customer-orders). This endpoint accepts 4 fields: `limit`, `offset`, `fields`, and `expand`. Here, you just use `limit` and `offset`. 

`limit` indicates how many orders should be retrieved per page, and `offset` indicates how many orders to skip from the beginning to get the orders of the current page.

This request returns the list of orders as well as additional fields important for pagination including `count` which indicates the total count of the orders and `limit` which is the current limit set.

You set the `orders` state variable to the orders returned from the method and you set the number of pages based on the `count` and `limit` fields.

Finally, you display the `orders` in a table showing the ID, total, and status. You also show pagination links for “Previous” and “Next” if applicable for the page. This is done for the simplicity of the tutorial.

If you open the orders page now, you’ll see the list of orders for your customer if they have any.

![Orders List](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/enkysj46egsk92icz92v.png)

### Addresses Page

The last page you’ll create in the profile is the Addresses page which will allow the customer to see their shipping addresses.

Create the file `pages/customer/addresses.js` with the following content:

```jsx
import Profile from "../../components/layout/profile"
import StoreContext from "../../context/store-context"
import styles from "../../styles/customer.module.css"
import { useContext } from 'react'

export default function Addresses() {
  const { customer } = useContext(StoreContext)

  return (
    <Profile activeLink='addresses'>
      <h1>Addresses</h1>
      {customer && customer.shipping_addresses.length === 0 && <p>You do not have any addresses</p>}
      {customer && customer.shipping_addresses.map((address) => (
        <div key={address.id} className={styles.address}>
          <span><b>First Name:</b> {address.first_name}</span>
          <span><b>Last Name:</b> {address.last_name}</span>
          <span><b>Company:</b> {address.company}</span>
          <span><b>Address Line 1:</b> {address.address_1}</span>
          <span><b>Address Line 2:</b> {address.address_2}</span>
          <span><b>City:</b> {address.city}</span>
          <span><b>Country:</b> {address.country}</span>
        </div>
      ))}
    </Profile>
  )
}
```

You use the `shipping_addresses` field in the `customer` object stored in the context and display the addresses one after the other. You can also access the billing address if the customer has any using `customer.billing_address`.

If you go to the Addresses page now, you’ll see the customer’s shipping addresses listed.

![Addresses Page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6inuoaop0bqitvu0c974.png)

## What’s Next

Using the Medusa JS Client, you can easily interact with the APIs to create an even better customer experience in your storefront.

This tutorial did not cover all the aspects of a profile for simplicity. Here’s what else you can implement:

1. **View Single Orders:** You can use the orders object you already retrieved on the orders page to show the information of a single order or you can use the [Retrieve Order](https://docs.medusajs.com/api/store/order/retrieves-an-order) endpoint which is accessible in the client under `client.orders.retrieve`.
2. **Address Management:** You can use the [Update Shipping Address endpoint](https://docs.medusajs.com/api/store/customer/update-a-shipping-address) accessible in the client under `client.customers.addresses.updateAddress`; you can use the [Add Shipping Address](https://docs.medusajs.com/api/store/customer/add-a-shipping-address) endpoint which is accessible in the client under `client.customers.addresses.addAddress`; and you can use the [Delete Shipping Address endpoint](https://docs.medusajs.com/api/store/customer/delete-an-address) which is accessible in the client under `client.customers.addresses.deleteAddress`.
3. **Saved Payment Methods:** You can retrieve the saved payment methods if you use a payment provider that supports saving payment methods like [Stripe](https://docs.medusajs.com/add-plugins/stripe) using the [Retrieve Saved Payment Methods](https://docs.medusajs.com/api/store/customer/retrieve-saved-payment-methods) endpoint accessible in the client under `client.customers.paymentMethods.list`.
4. **Reset Password:** You can add reset password functionality using the [Create Reset Password Token endpoint](https://docs.medusajs.com/api/store/customer/creates-a-reset-password-token) accessible in the client under `client.customers.generatePasswordToken`, then you can reset the password using the [Reset Customer Password endpoint](https://docs.medusajs.com/api/store/customer/resets-customer-password) accessible in the client under `client.customers.resetPassword`.

You can check out the [API documentation](https://docs.medusajs.com/api/store/auth/authenticate-customer) for a full list of endpoints to see what more functionalities you can add to your storefront.

> Should you have any issues or questions related to Medusa, then feel free to reach out to the Medusa team via [Discord](https://discord.gg/F87eGuwkTp).