docs: documentation changes for release (#4300)
* docs: added manage reservations user guide (#4290) * docs: added manage reservations user guide * removed feature flag details * docs: added how-to for custom reservations (#4292) * docs: added how-to for custom reservations * eslint fixes * docs: added product module documentation (#4287) * docs: added product module documentation * added details about optional environment variables * small fixes * Remove reference link * added example usages * added link to sample project * address PR feedback * docs: moved product module guide + added product module tabs (#4307) * added product module tab * adjust design of badge * docs: added onboarding features (#4168) * added marketplace page * added subscription roadmap * added rating for onboarding * added learning path components * small fixes * fix build error * fix eslint errors * change roadmaps to recipes * small change in text * optimize learning path and notifications * fix tracking usage * fix eslint errors * added enter/exit animation * allow starting a path using a query parameter * fix gap between notifications * address vercel comments * fixed links issue * changed create-medusa-app docs steps * move troubleshooting section * improved tracking across docs * fix build errors * remove console * added a note about `boilerplate` option * added troubleshooting section for eagain * added invite option in cli reference * added track event for finished onboarding * update boilerplate option name * redesigned learning path component * docs: added how to create widget docs (#4318) * docs: added how to create widget docs * remove development guide * added types * docs: added details about createCustomAdminHooks (#4288) * docs: added details about createCustomAdminHooks * small improvement * added missing import * small changes * docs: added onboarding guide (#4320) * docs: added how to create widget docs * remove development guide * docs: added onboarding guide * added types * added recipes link * small adjustments * fixed eslint errors * styling fixes * change to singular product module * updated the what's new section * shorten down medusa react card * updated tailwind configurations * fix build error * fix newspaper icon * style fixes * change modal shadow * fix color of line numbers * fix code fade color * docs: updated admin documentations * eslint fixes * text changes * added a note about beta version * remove empty object argument * remove demo repo url * fix selection color for code headers * general fixes * fix eslint error * changed code theme * added preparation step * changes regarding beta version * Update docs/content/modules/products/serverless-module.md Co-authored-by: Riqwan Thamir <rmthamir@gmail.com> * Update docs/content/modules/products/serverless-module.md Co-authored-by: Riqwan Thamir <rmthamir@gmail.com> --------- Co-authored-by: Riqwan Thamir <rmthamir@gmail.com> Co-authored-by: Oliver Windall Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
@@ -1,111 +0,0 @@
|
||||
---
|
||||
description: 'Learn how to set up the Medusa Admin repository for local development and customization. This includes cloning the GitHub repository and adding an upstream repository.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
# Customize Medusa Admin
|
||||
|
||||
In this document, you’ll learn how to customize the Medusa admin by forking it, and how to keep it updated with changes from the main repository.
|
||||
|
||||
:::warning
|
||||
|
||||
This guide explains how to customize the Medusa Admin repository, which is now deprecated. This guide doesn't work with the [admin plugin](./quickstart.mdx).
|
||||
|
||||
:::
|
||||
|
||||
## Overview
|
||||
|
||||
Although Medusa provides an intuitive admin that should cover all your ecommerce needs, you are free to customize the Medusa admin as you see fit.
|
||||
|
||||
For customization and development, it’s recommended that you fork the main Medusa admin repository. That way, you can configure your forked repository to pull changes from the main Medusa admin repository for any latest updates.
|
||||
|
||||
In this document, you’ll learn how to:
|
||||
|
||||
- Fork the Medusa admin repository.
|
||||
- Configure the Medusa admin repository as an upstream repository.
|
||||
- Pull changes from the upstream repository to keep your fork synced with the Medusa admin repository.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Required Tools
|
||||
|
||||
[Git CLI tool](../development/backend/prepare-environment.mdx#git)
|
||||
|
||||
### Required Accounts
|
||||
|
||||
[GitHub](https://github.com/)
|
||||
|
||||
---
|
||||
|
||||
## Fork the Medusa Admin Repository
|
||||
|
||||
To fork the Medusa admin:
|
||||
|
||||
1. Go to the [Medusa admin repository](https://github.com/medusajs/admin).
|
||||
2. Click on the Fork button at the top right.
|
||||
3. You can optionally change the name of the repository and description.
|
||||
4. Once done, click on the Create fork button.
|
||||
5. After your fork is created, you can clone it using the following command:
|
||||
|
||||
```bash
|
||||
git clone <REPOSITORY_URL>
|
||||
```
|
||||
|
||||
Where `<REPOSITORY_URL>` is the HTTPS URL of your repository. You can obtain it from your forked repository’s GitHub page by clicking on the Code button and copying the URL.
|
||||
|
||||
---
|
||||
|
||||
## Configure Upstream Repository
|
||||
|
||||
To configure the Medusa admin as the upstream repository:
|
||||
|
||||
1. Change to the directory of your cloned forked repository.
|
||||
2. Run the following command to add the Medusa admin repository as an upstream repository:
|
||||
|
||||
```bash
|
||||
git remote add upstream https://github.com/medusajs/admin
|
||||
```
|
||||
|
||||
1. You can verify that it has been added by running the following command:
|
||||
|
||||
```bash
|
||||
git remote -v
|
||||
```
|
||||
|
||||
You should see an `origin` repository which is your forked repository, and an `upstream` repository which is the Medusa admin repository.
|
||||
|
||||
---
|
||||
|
||||
## Update your Fork with Latest Changes
|
||||
|
||||
To update your fork with the latest changes from the Medusa admin repository:
|
||||
|
||||
1. Change to the directory of your cloned forked repository.
|
||||
2. Run the following command to fetch the latest changes from the Medusa admin repository:
|
||||
|
||||
```bash
|
||||
git fetch upstream
|
||||
```
|
||||
|
||||
1. Make sure you’re on your `main` or `master` branch of the forked repository:
|
||||
|
||||
```bash
|
||||
git checkout main
|
||||
```
|
||||
|
||||
1. Merge the changes from the `main` branch of the Medusa admin repository:
|
||||
|
||||
```bash
|
||||
git merge upstream/main
|
||||
```
|
||||
|
||||
If your forked repository doesn’t have any conflicts with the changes from the Medusa admin repository, the merge will be done successfully. Otherwise, you’ll need to [resolve these conflicts](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line).
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Admin API reference](/api/admin).
|
||||
- [Local development with Medusa](../development/fundamentals/local-development.md).
|
||||
2420
docs/content/admin/onboarding.md
Normal file
2420
docs/content/admin/onboarding.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,30 +6,18 @@ addHowToData: true
|
||||
import Feedback from '@site/src/components/Feedback';
|
||||
import Troubleshooting from '@site/src/components/Troubleshooting'
|
||||
import AdminLoginSection from '../troubleshooting/signing-in-to-admin.md'
|
||||
import CorsSection from '../troubleshooting/cors-issues.md'
|
||||
|
||||
# Admin Dashboard Quickstart
|
||||
|
||||
This document will guide you through setting up the admin dashboard in the Medusa backend.
|
||||
|
||||
:::note
|
||||
|
||||
The admin dashboard is now shipped as an NPM package, and the previous GitHub repository has been deprecated.
|
||||
|
||||
:::
|
||||
|
||||
## Overview
|
||||
|
||||
The admin dashboard is installed on the Medusa backend. The admin dashboard starts when you start the Medusa backend. This also means you can later deploy the Medusa backend along with the admin dashboard on the same hosting.
|
||||
|
||||
This guide will explain the steps and configurations required to set up the admin dashboard.
|
||||
|
||||
<!-- The admin dashboard is installed on the Medusa backend. Setting it up depends on how you intend to use it:
|
||||
|
||||
1. [Served alongside the Medusa backend](#option-1-install-and-serve-admin-with-the-backend): with this approach, the admin dashboard starts when you start the Medusa backend. This also means you can later deploy the Medusa backend along with the admin dashboard on the same hosting.
|
||||
2. [Served separately from the Medusa backend](#option-2-install-and-serve-admin-separately): with this approach, the admin dashboard starts separately from the Medusa backend. You still need the Medusa backend to be running as the admin uses its APIs. This is useful if you intend to later deploy the admin dashboard on a different hosting than the Medusa Backend, such as using Vercel.
|
||||
|
||||
This guide will explain the steps and configurations required for both approaches. -->
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
@@ -52,20 +40,10 @@ You can install Node from the [official website](https://nodejs.org/en/).
|
||||
|
||||
---
|
||||
|
||||
<!-- ## Option 1: Install and Serve Admin with the Backend -->
|
||||
|
||||
## Install and Serve Admin with the Backend
|
||||
|
||||
This section explains how to install the admin to be served with the Medusa Backend and later deployed together.
|
||||
|
||||
<!-- :::note
|
||||
|
||||
If you decide later to serve the admin for development separately or deploy it on a different hosting, you can go back and follow the steps in [Option 2](#option-2-install-and-serve-admin-serparately).
|
||||
|
||||
:::
|
||||
|
||||
-->
|
||||
|
||||
### Step 1: Install the Package
|
||||
|
||||
In the directory of your Medusa backend, run the following command to install admin dashboard:
|
||||
@@ -74,6 +52,16 @@ In the directory of your Medusa backend, run the following command to install ad
|
||||
npm install @medusajs/admin
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
Installing the `@beta` version of the admin and Medusa core allows you to perform customizations such as creating [Admin Widgets](./widgets.md) or [Admin Dashboard Routes](./routes.md). You can install the `beta` version with the following command:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @medusajs/admin@beta @medusajs/medusa@beta
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### Step 2: Add Admin to Medusa Configurations
|
||||
|
||||
In `medusa-config.js`, add the admin plugin into the array of `plugins`:
|
||||
@@ -94,7 +82,7 @@ const plugins = [
|
||||
The plugin accepts the following options:
|
||||
|
||||
1. `serve`: (default: `true`) a boolean indicating whether to serve the admin dashboard when the Medusa backend starts. If set to `false`, you can serve the admin dashboard using the [dev command](#dev-command-options).
|
||||
2. `path`: (default: `app`) a string indicating the path the admin server should run on. It shouldn't be prefixed or suffixed with a slash `/`, and it can't be one of the reserved paths: "admin" and "store".
|
||||
2. `path`: (default: `app`) a string indicating the path the admin server should run on when [running the Medusa backend in production](#note-on-admin-path). It shouldn't be prefixed or suffixed with a slash `/`, and it can't be one of the reserved paths: "admin" and "store".
|
||||
3. `outDir`: Optional path for where to output the admin build files.
|
||||
4. `autoRebuild`: (default: `false`) a boolean indicating whether the admin UI should be rebuilt if there are any changes or if a missing build is detected when the backend starts. If not set, you must [manually build the admin dashboard](#build-command-options).
|
||||
|
||||
@@ -116,66 +104,14 @@ You can test the admin dashboard by running the following command in the directo
|
||||
npx @medusajs/medusa-cli develop
|
||||
```
|
||||
|
||||
This starts the Medusa Backend and the admin dashboard. By default, the admin will be available on the URL `localhost:9000/app`. If you set the `path` option, then the admin will be available on `localhost:9000/<PATH>` with `<PATH>` being the value of the `path` option.
|
||||
|
||||
<Feedback
|
||||
event="survey_admin_quickstart"
|
||||
question="Did you set up the admin successfully?"
|
||||
positiveQuestion="Is there anything that should improved?"
|
||||
negativeQuestion="Please describe the issue you faced."
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
## Option 2: Install and Serve Admin Separately
|
||||
|
||||
This section explains how to install the admin dashboard using approach 2, which allows you to serve and later deploy the admin separately.
|
||||
This starts the Medusa Backend and the admin dashboard. By default, the admin will be available on the URL `localhost:9000/app`. If you set the path option, then the admin will be available on `localhost:9000/<PATH>` with `<PATH>` being the value of the path option.
|
||||
|
||||
:::note
|
||||
|
||||
If you decide later to serve and deploy the admin alongside the server, you can go back and follow the steps in [Option 1](#option-1-install-and-serve-admin-with-the-backend).
|
||||
If you're using the `@beta` version of the admin plugin, the admin dashboard will run on `localhost:7001` when you run the `develop` command.
|
||||
|
||||
:::
|
||||
|
||||
### Step 1: Install the Package
|
||||
|
||||
In the directory of your Medusa backend, run the following command to install admin dashboard:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @medusajs/admin --save-dev
|
||||
```
|
||||
|
||||
### Step 2: Add Scripts to Package.json
|
||||
|
||||
Add the following scripts to `package.json` in the directory of the Medusa backend:
|
||||
|
||||
```json title=package.json
|
||||
{
|
||||
"scripts": {
|
||||
// other scripts...
|
||||
"build:admin": "medusa-admin build",
|
||||
"dev:admin": "medusa-admin dev"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
- `build:admin`: Used to manually create a build of the admin. In this approach, it's useful with the `--deployment` option to build the admin for deployment. You can learn more about all available options in [this section](#build-command-options).
|
||||
- `dev:admin`: Used to run the development server of the admin. You can learn about other available options for this command in [this section](#dev-command-options).
|
||||
|
||||
### Step 3: Start Admin in Development
|
||||
|
||||
Make sure to run the Medusa backend first. Then, in the root directory of the backend, run the following command to start the admin development server:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run dev:admin
|
||||
```
|
||||
|
||||
This runs the admin dashboard on `localhost:7001`.
|
||||
|
||||
<Feedback
|
||||
event="survey_admin_quickstart"
|
||||
question="Did you set up the admin successfully?"
|
||||
@@ -185,8 +121,6 @@ This runs the admin dashboard on `localhost:7001`.
|
||||
|
||||
---
|
||||
|
||||
-->
|
||||
|
||||
## Demo Credentials
|
||||
|
||||
If you installed the demo data when you installed the Medusa backend by running:
|
||||
@@ -276,5 +210,16 @@ You can learn more about the admin dashboard and its features in the [User Guide
|
||||
title: 'Signing into Admin',
|
||||
content: <AdminLoginSection />
|
||||
},
|
||||
{
|
||||
title: 'CORS Errors',
|
||||
content: <CorsSection />
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Admin widgets](./widgets.md)
|
||||
- [Admin UI routes](./routes.md)
|
||||
|
||||
326
docs/content/admin/routes.md
Normal file
326
docs/content/admin/routes.md
Normal file
@@ -0,0 +1,326 @@
|
||||
---
|
||||
title: 'How to Create an Admin UI Route'
|
||||
description: 'Learn how to create a new route in the admin dashboard.'
|
||||
addHowToData: true
|
||||
badge:
|
||||
variant: orange
|
||||
text: beta
|
||||
---
|
||||
|
||||
In this document, you’ll learn how to create a new route in the admin dashboard.
|
||||
|
||||
## Overview
|
||||
|
||||
You can customize the admin dashboard that Medusa provides to add new routes. This is useful if you want to add new subpages to the admin dashboard, or you want to add new pages that appear in the sidebar as well.
|
||||
|
||||
An admin UI route is essentially a React Component created under the `src/admin/routes` directory.
|
||||
|
||||
This guide explains how to create a new route in the admin dashboard with some examples.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
It’s assumed you already have a Medusa backend with the admin plugin installed before you move forward with this guide. If not, you can follow [this documentation page](../create-medusa-app.mdx) to install a Medusa project.
|
||||
|
||||
Furthermore, Admin UI Routes are currently available as a beta feature. So, you must install the `beta` version of the `@medusajs/admin` and `@medusajs/medusa` packages:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @medusajs/admin@beta @medusajs/medusa@beta
|
||||
```
|
||||
|
||||
### (Optional) TypeScript Preparations
|
||||
|
||||
Since routes are React components, they should be written in `.tsx` or `.jsx` files. If you’re using Typescript, you need to make some adjustments to avoid Typescript errors in your Admin files.
|
||||
|
||||
This section provides recommended configurations to avoid any TypeScript errors.
|
||||
|
||||
:::note
|
||||
|
||||
These changes may already be available in your Medusa project. They're included here for reference purposes.
|
||||
|
||||
:::
|
||||
|
||||
First, update your `tsconfig.json` with the following configurations:
|
||||
|
||||
```json title=tsconfig.json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2019",
|
||||
"module": "commonjs",
|
||||
"allowJs": true,
|
||||
"checkJs": false,
|
||||
"jsx": "react-jsx",
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"noEmit": false,
|
||||
"strict": false,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": ["src/"],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"build",
|
||||
".cache",
|
||||
"tests",
|
||||
"**/*.spec.js",
|
||||
"**/*.spec.ts",
|
||||
"node_modules",
|
||||
".eslintrc.js"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The important changes to note here are the inclusion of the field `"jsx": "react-jsx"` and the addition of `"build"` and `“.cache”` to `exclude`.
|
||||
|
||||
The addition of `"jsx": "react-jsx"` specified how should TypeScript transform JSX, and excluding `build` and `.cache` ensures that TypeScript ignores build and development files.
|
||||
|
||||
Next, create the file `tsconfig.server.json` with the following content:
|
||||
|
||||
```json title=tsconfig.server.json
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
/* Emit a single file with source maps instead of having a separate file. */
|
||||
"inlineSourceMap": true
|
||||
},
|
||||
"exclude": ["src/admin", "**/*.spec.js"]
|
||||
}
|
||||
```
|
||||
|
||||
This is the configuration that will be used to transpile your custom backend code, such as services or entities. The important part is that it excludes `src/admin` as that is where your Admin code will live.
|
||||
|
||||
Finally, create the file `tsconfig.admin.json` with the following content:
|
||||
|
||||
```json title=tsconfig.admin.json
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "esnext"
|
||||
},
|
||||
"include": ["src/admin"],
|
||||
"exclude": ["**/*.spec.js"]
|
||||
}
|
||||
```
|
||||
|
||||
This is the configuration that will be used when transpiling your admin code.
|
||||
|
||||
---
|
||||
|
||||
## Create the Admin UI Route
|
||||
|
||||
In this section, you’ll learn the basics of creating an admin UI route.
|
||||
|
||||
### Step 1: Create File
|
||||
|
||||
Custom admin UI routes are added under the `src/admin/routes` directory of your Medusa project. The path of the file depends on the path you want the route to be available under. It is based on [Next.js 13’s App Router](https://nextjs.org/docs/app/building-your-application/routing/defining-routes).
|
||||
|
||||
For example, if you want the route to be available in the admin dashboard under the path `/a/custom` you should create your admin route under the path `src/admin/routes/custom/page.tsx`.
|
||||
|
||||
:::tip
|
||||
|
||||
All admin routes are prefixed with `/a` by default.
|
||||
|
||||
:::
|
||||
|
||||
You can also create [dynamic routes](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes). For example, you can create the route `/a/custom/[id]` by creating an admin router under the path `src/admin/routes/custom/[id]/page.tsx`.
|
||||
|
||||
### Step 2: Create React Component in File
|
||||
|
||||
For an admin route to be valid, it must default export a React component. There are no restrictions on the content of the React component.
|
||||
|
||||
For example, you can create the file `src/admin/routes/custom/page.tsx` with the following content:
|
||||
|
||||
```tsx title=src/admin/routes/custom/page.tsx
|
||||
const CustomPage = () => {
|
||||
return (
|
||||
<div>
|
||||
This is my custom route
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
### Step 3: Test it Out
|
||||
|
||||
To test your admin UI route, run the following command in the root directory of the Medusa backend project:
|
||||
|
||||
```bash npm2yarn
|
||||
npx @medusajs/medusa-cli develop
|
||||
```
|
||||
|
||||
This will build your admin and opens a window in your default browser to `localhost:7001`. After you log in, if you go to `localhost:7001/a/custom`, you’ll find the page you just created.
|
||||
|
||||
:::note
|
||||
|
||||
When using the `develop` command, the admin dashboard will run in development mode and will restart whenever you make changes to your admin customizations. This allows you to see changes in the dashboard instantly during your development.
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Show Route in Sidebar
|
||||
|
||||
You can add your routes into the admin dashboard sidebar by exporting an object of type `RouteConfig` import from `@medusajs/admin` in the same route file.
|
||||
|
||||
The object has one property `link`, which is an object having the following properties:
|
||||
|
||||
- `label`: a string indicating the sidebar item’s label of your custom route.
|
||||
- `icon`: an optional React component that acts as an icon in the sidebar. If none provided, a default icon is used.
|
||||
|
||||
For example, you can change the content of the previous route you created to export a config object:
|
||||
|
||||
```tsx title=src/admin/routes/custom/page.tsx
|
||||
import { RouteConfig } from "@medusajs/admin"
|
||||
import { CustomIcon } from "../../icons/custom"
|
||||
|
||||
const CustomPage = () => {
|
||||
return (
|
||||
<div>
|
||||
This is my custom route
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const config: RouteConfig = {
|
||||
link: {
|
||||
label: "Custom Route",
|
||||
icon: CustomIcon,
|
||||
},
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Retrieve Path Parameters
|
||||
|
||||
As mentioned earlier, you can create dynamic routes like `/a/custom/[id]` by creating a route file at the path `src/admin/routes/custom/[id]/page.tsx`.
|
||||
|
||||
To retrieve the path parameter, you can use the [useParams hook](https://reactrouter.com/en/main/hooks/use-params) retrieved from the [react-router-dom](https://reactrouter.com/en/main) package.
|
||||
|
||||
:::note
|
||||
|
||||
`react-router-dom` is available as one of the `@medusajs/admin` dependencies. You can also install it within your project using the following command:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install react-router-dom
|
||||
```
|
||||
|
||||
If you're installing it in a plugin with admin customizations, make sure to include it in `peerDependencies`.
|
||||
|
||||
:::
|
||||
|
||||
For example:
|
||||
|
||||
```tsx title=src/admin/routes/custom/[id]/page.tsx
|
||||
import { useParams } from "react-router-dom"
|
||||
|
||||
const CustomPage = () => {
|
||||
const { id } = useParams()
|
||||
|
||||
return (
|
||||
<div>
|
||||
Passed ID: {id}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
### Routing Functionalities
|
||||
|
||||
If you want to use routing functionalities such as linking to another page or navigating between pages, you can use `react-router-dom`'s utility hooks and functions.
|
||||
|
||||
For example, to add a link to another page:
|
||||
|
||||
```tsx title=src/admin/routes/custom/page.tsx
|
||||
import { Link } from "react-router-dom"
|
||||
|
||||
const CustomPage = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Link to={"/a/products"}>
|
||||
View Products
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
View [react-router-dom’s documentation](https://reactrouter.com/en/main) for other available components and hooks.
|
||||
|
||||
---
|
||||
|
||||
## Styling Route
|
||||
|
||||
Admin UI routes support [Tailwind CSS](https://tailwindcss.com/) by default.
|
||||
|
||||
For example, to customize your custom route:
|
||||
|
||||
<!-- eslint-disable max-len -->
|
||||
|
||||
```tsx title=src/admin/routes/custom/page.tsx
|
||||
const CustomPage = () => {
|
||||
return (
|
||||
<div
|
||||
className="bg-white p-8 border border-gray-200 rounded-lg">
|
||||
This is my custom route
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Querying and Mutating Data
|
||||
|
||||
You might need to interact with the Medusa backend from your admin route. To do so, you can utilize the [Medusa React package](../medusa-react/overview.md). It contains a collection of queries and mutation built on `@tanstack/react-query` that lets you interact with the Medusa backend.
|
||||
|
||||
:::note
|
||||
|
||||
Make sure to also install the Medusa React package first if you’re intending to use it, as explained in the [Medusa React guide](../medusa-react/overview.md).
|
||||
|
||||
:::
|
||||
|
||||
For example, you can retrieve available products and display them in your route:
|
||||
|
||||
```tsx title=src/admin/routes/custom/page.tsx
|
||||
import { useAdminProducts } from "medusa-react"
|
||||
|
||||
const CustomPage = () => {
|
||||
const { products } = useAdminProducts()
|
||||
return (
|
||||
<div className="bg-white">
|
||||
{products?.map((product) => product.title)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
You can also use `medusa-react` to interact with custom endpoints using the [createCustomAdminHooks utility function](../medusa-react/overview.md#custom-hooks).
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Admin widgets](./widgets.md)
|
||||
- [Create a plugin for your admin customizations](../development/plugins/create.mdx)
|
||||
1283
docs/content/admin/widgets.md
Normal file
1283
docs/content/admin/widgets.md
Normal file
File diff suppressed because it is too large
Load Diff
@@ -204,9 +204,10 @@ medusa user --email <email> [--password <password>]
|
||||
|
||||
| Name | Description |
|
||||
| --- | --- |
|
||||
| `-e`, `--email` | The email to create a user with. (required) |
|
||||
| `-p`, `--password` | The password to use with the user. If not included, the user will not have a password. |
|
||||
| `-i`, `--id` | The user’s ID. By default it is automatically generated. |
|
||||
| `-e <email>`, `--email <email>` | The email to create a user with. (required) |
|
||||
| `-p <passowrd>`, `--password <password>` | The password to use with the user. If not included, the user will not have a password. |
|
||||
| `-i <id>`, `--id <id>` | The user’s ID. By default it is automatically generated. |
|
||||
| `--invite` | Whether to create an invite instead of a user. When using this option, you don't need to specify a password. If ran successfully, you'll receive the invite token in the output. |
|
||||
|
||||
### telemetry
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ addHowToData: true
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import Feedback from '@site/src/components/Feedback';
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import DocCard from '@theme/DocCard';
|
||||
import Icons from '@theme/Icon';
|
||||
import Troubleshooting from '@site/src/components/Troubleshooting'
|
||||
import TypeErrorSection from "./troubleshooting/create-medusa-app-errors/_typeerror.md"
|
||||
@@ -17,13 +17,22 @@ import FreshInstallationSection from './troubleshooting/awilix-resolution-error/
|
||||
|
||||
# Install Medusa with create-medusa-app
|
||||
|
||||
In this document, you’ll learn how to use create-medusa-app to set up a Medusa backend.
|
||||
In this document, you’ll learn how to use create-medusa-app to set up a Medusa backend and an admin dashboard.
|
||||
|
||||
## Overview
|
||||
|
||||
Medusa is a toolkit for developers to create digital commerce applications. In its simplest form, Medusa is a Node.js backend with the core API, plugins, and modules installed through npm.
|
||||
|
||||
`create-medusa-app` is a command that facilitates creating a Medusa ecosystem. It installs the Medusa backend, along with the necessary configurations to run the backend.
|
||||
`create-medusa-app` is a command that facilitates creating a Medusa ecosystem. It installs the Medusa backend and admin dashboard, along with the necessary configurations to run the backend.
|
||||
|
||||
:::note
|
||||
|
||||
`create-medusa-app` uses a beta version of the admin dashboard. If you want to use a stable Medusa setup, you can install the stable backend and the admin using the following guides:
|
||||
|
||||
1. [Install Medusa backend](./development/backend/install.mdx)
|
||||
2. [Install admin package](./admin/quickstart.mdx)
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
@@ -75,7 +84,8 @@ In your terminal, run the following command:
|
||||
<summary>Available Options</summary>
|
||||
|
||||
- `--repo-url <url>`: The repository URL to create the project from. By default it will be `https://github.com/medusajs/medusa-starter-default`.
|
||||
- `--no-boilerplate`: A flag that removes all files added for an enhanced onboarding experience (files under `src/api`, etc...). This is helpful if you want to create a clean project, and is only recommended if you're familiar with Medusa.
|
||||
- `--seed`: A flag indicating whether the database should be seeded with demo data. By default, seeding is disabled.
|
||||
- `--no-boilerplate`: A flag that removes all files added for an enhanced onboarding experience (files under `src/admin`, `src/api`, etc...). This is helpful if you want to create a clean project, and is only recommended if you're familiar with Medusa.
|
||||
|
||||
</details>
|
||||
|
||||
@@ -89,7 +99,11 @@ By default, this command will try to use the default PostgreSQL credentials to c
|
||||
|
||||
These credentials will be used to create a database during this setup and configure your Medusa backend to connect to that database.
|
||||
|
||||
### Step 3: Wait for Project Setup
|
||||
### Step 3: Enter an admin email
|
||||
|
||||
You'll then be prompted to enter an admin email for your admin user. You'll be using this admin email later to login to your admin dashboard. You can use the default `admin@medusa-test.com` or enter any other email.
|
||||
|
||||
### Step 4: Wait for Project Setup
|
||||
|
||||
After the above steps, the project setup will start which includes:
|
||||
|
||||
@@ -97,17 +111,14 @@ After the above steps, the project setup will start which includes:
|
||||
2. Creating the project database.
|
||||
3. Installing dependencies in your project directory.
|
||||
4. Building project and running migrations to migrate the Medusa schema into your project database.
|
||||
5. Seed the database
|
||||
5. Create the admin user.
|
||||
6. Seeding the database with demo data.
|
||||
|
||||
### Step 4: Test it Out
|
||||
### Step 5: Log into admin dashboard
|
||||
|
||||
Once the installation is finished, the Medusa backend will be started automatically. You can test it out by either opening the URL `localhost:9000/store/products` in your browser or using cURL:
|
||||
Once the project is prepared, the Medusa backend will start and the admin dashboard will be opened in your default browser. You'll then be asked to enter a password for the admin email you entered earlier, as well as other account information.
|
||||
|
||||
```bash
|
||||
cURL localhost:9000/store/products
|
||||
```
|
||||
|
||||
This endpoint returns an array of available products in your Medusa backend.
|
||||
Once you're logged in, you can start using Medusa! Try following the setup guide to create your first product and order.
|
||||
|
||||
<Feedback
|
||||
event="survey_create-medusa-app"
|
||||
@@ -122,26 +133,15 @@ This endpoint returns an array of available products in your Medusa backend.
|
||||
|
||||
Based on what you're building, you can find a development path for you in the Recipes page.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/overview',
|
||||
label: 'Commerce Modules',
|
||||
customProps: {
|
||||
icon: Icons['puzzle-solid'],
|
||||
description: "Learn about available commerce modules and features in Medusa."
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/overview',
|
||||
label: 'Medusa Development',
|
||||
customProps: {
|
||||
icon: Icons['server-stack-solid'],
|
||||
description: "Learn how to develop customized digital commerce applications with Medusa."
|
||||
}
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/recipes',
|
||||
label: 'Recipes',
|
||||
customProps: {
|
||||
icon: Icons['map'],
|
||||
description: "Find learning paths based on what you're building"
|
||||
}
|
||||
]} />
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,334 +0,0 @@
|
||||
---
|
||||
description: 'Learn step-by-step.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
# Deploy Gatsby Storefront on Netlify
|
||||
|
||||
:::note
|
||||
|
||||
The Gatsby storefront has been deprecated and it's not recommended to use it moving forward. You can use the [Next.js storefront](../../starters/nextjs-medusa-starter.mdx) instead or build your own.
|
||||
|
||||
:::
|
||||
|
||||
In this document, you’ll learn how to deploy the Gatsby Storefront on [Netlify](https://www.netlify.com/).
|
||||
|
||||
Alternatively, you can use this button to deploy the Gatsby Storefront to Netlify directly:
|
||||
|
||||
<a href="https://app.netlify.com/start/deploy?repository=https://github.com/medusajs/gatsby-starter-medusa" class="img-url no-zoom-img">
|
||||
<img src="https://www.netlify.com/img/deploy/button.svg" alt="Deploy to Netlify" class="no-zoom-img" />
|
||||
</a>
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
Before proceeding with this documentation, it is assumed you already have the Gatsby storefront installed locally.
|
||||
|
||||
Additionally, this documentation does not cover how to deploy the Medusa backend. If you want to deploy the Medusa backend, [check out one of the deployment documentation related to the Medusa backend](../server/index.mdx).
|
||||
|
||||
### Needed Accounts
|
||||
|
||||
- A [Netlify](https://app.netlify.com/signup) account to deploy the Gatsby storefront.
|
||||
- A [GitHub](https://github.com/signup) account where you will host the repository for the Gatsby storefront.
|
||||
|
||||
:::tip
|
||||
|
||||
If you want to use another Git Provider, it’s possible to follow along with this guide but you’ll have to perform the equivalent steps in your Git Provider.
|
||||
|
||||
:::
|
||||
|
||||
### Required Tools
|
||||
|
||||
- Git’s CLI tool. You can follow [this documentation to learn how to install it for your operating system](../../development/backend/prepare-environment.mdx#git).
|
||||
|
||||
---
|
||||
|
||||
## Create GitHub Repository
|
||||
|
||||
Before you can deploy your Gatsby storefront you need to create a GitHub repository and push the code base to it.
|
||||
|
||||
On GitHub, click the plus icon at the top right, then click New Repository.
|
||||
|
||||

|
||||
|
||||
You’ll then be redirected to a new page with a form. In the form, enter the Repository Name then scroll down and click Create repository.
|
||||
|
||||

|
||||
|
||||
### Push Code to GitHub Repository
|
||||
|
||||
The next step is to push the code to the GitHub repository you just created.
|
||||
|
||||
After creating the repository, you’ll be redirected to the repository’s page. On that page, you should see a URL that you can copy to connect your repository to a local directory.
|
||||
|
||||

|
||||
|
||||
Copy the link. Then, open your terminal in the directory that holds your Gatsby storefront codebase and run the following commands:
|
||||
|
||||
```bash
|
||||
git init
|
||||
git remote add origin <GITHUB_URL>
|
||||
```
|
||||
|
||||
Where `<GITHUB_URL>` is the URL you just copied.
|
||||
|
||||
Then, add, commit, and push the changes into the repository:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "initial commit"
|
||||
git push origin master
|
||||
```
|
||||
|
||||
After pushing the changes, you can find the files in your GitHub repository.
|
||||
|
||||
---
|
||||
|
||||
## Deploy to Netlify
|
||||
|
||||
This section covers how to deploy Netlify either through the Netlify website or using Netlify’s CLI tool.
|
||||
|
||||
### Option 1: Using Netlify’s Website
|
||||
|
||||
After logging in with Netlify, go to the [dashboard](https://app.netlify.com/). Then, at the top right of the “Sites” section, click on “Add new site”, then click on “Import an existing project” from the dropdown.
|
||||
|
||||
:::note
|
||||
|
||||
Alternatively, if you don’t have any other websites, you’ll see a big button that says “Import an existing project”.
|
||||
|
||||
:::
|
||||
|
||||

|
||||
|
||||
You’ll then be asked to connect to a Git provider.
|
||||
|
||||

|
||||
|
||||
Choose GitHub. You’ll then be redirected to GitHub’s website to give Netlify permissions if you haven’t done that before.
|
||||
|
||||
After you authorize Netlify to use GitHub, you’ll be asked to pick the repository you want to deploy. Pick the repository you just created.
|
||||
|
||||

|
||||
|
||||
In the form that shows, keep all fields the same and click on the “Show advanced” button before the “Deploy site” button.
|
||||
|
||||

|
||||
|
||||
Under the “Advanced build settings” section click on the “New variable” button. This will show two inputs for the key and value of the environment variable.
|
||||
|
||||
For the first field enter the key `GATSBY_MEDUSA_BACKEND_URL` and for the value enter the URL of your Medusa backend.
|
||||
|
||||
:::caution
|
||||
|
||||
If you haven’t deployed your Medusa backend yet, you can leave the value blank for now and add it later. However, the build process for the Gatsby storefront will fail.
|
||||
|
||||
:::
|
||||
|
||||

|
||||
|
||||
:::note
|
||||
|
||||
If you use more environment variables in your storefront be sure to add them here.
|
||||
|
||||
:::
|
||||
|
||||
Once you’re done, scroll down and click on Deploy site.
|
||||
|
||||
You’ll be then redirected to the dashboard of the new website. Netlify will build your website in the background. You should see “Site deploy in progress” on the top card.
|
||||
|
||||

|
||||
|
||||
The deployment can take a few minutes.
|
||||
|
||||
Once the deployment is done, you’ll find the URL in the place of the “Site deploy in progress” message you saw earlier.
|
||||
|
||||
:::tip
|
||||
|
||||
If you haven’t added any products to your Medusa backend, the build process might fail. It’s recommended to add some products to the backend first in that case.
|
||||
|
||||
Alternatively, you can seed the backend with demo data by running this command in the root directory of the backend:
|
||||
|
||||
```bash noReport
|
||||
npx @medusajs/medusa-cli seed -f data/seed.json
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||

|
||||
|
||||
If you click on it, you’ll be redirected to the deployed storefront website.
|
||||
|
||||

|
||||
|
||||
:::caution
|
||||
|
||||
At this point, you will face errors related to Cross-Origin Resource Sharing (CORS) while using the storefront. Before you start using the storefront, follow along the [Configure CORS on the Medusa Backend section](#configure-cors-variable-on-the-medusa-backend).
|
||||
|
||||
:::
|
||||
|
||||
### Option 2: Using Netlify’s CLI Tool
|
||||
|
||||
In this section, you’ll deploy the Gatsby storefront using Netlify’s CLI tool.
|
||||
|
||||
#### Install the Netlify CLI tool
|
||||
|
||||
If you don’t have the tool installed, run the following command to install it:
|
||||
|
||||
```bash
|
||||
npm install netlify-cli -g
|
||||
```
|
||||
|
||||
#### Login to Netlify
|
||||
|
||||
Then, run the following command to log in to Netlify in your terminal:
|
||||
|
||||
```bash
|
||||
netlify login
|
||||
```
|
||||
|
||||
This opens a page to log in on your browser. You’ll be asked to authorize the Netlify CLI tool.
|
||||
|
||||

|
||||
|
||||
Click on Authorize. Then, you can go back to your terminal and see that you’ve successfully logged in.
|
||||
|
||||

|
||||
|
||||
#### Initialize Netlify Website
|
||||
|
||||
In your terminal, run the following command:
|
||||
|
||||
```bash
|
||||
netlify init
|
||||
```
|
||||
|
||||
You’ll have to follow five steps for the initialization:
|
||||
|
||||
##### Step 1: Create Netlify Website
|
||||
|
||||
You’ll be asked to either connect to an existing Netlify website or create a new one. Choose the second option to create a new site:
|
||||
|
||||
```bash noReport
|
||||
? What would you like to do?
|
||||
⇄ Connect this directory to an existing Netlify site
|
||||
❯ + Create & configure a new site
|
||||
```
|
||||
|
||||
##### Step 2: Choose Netlify Team
|
||||
|
||||
Choose the team you want to create the website in if you have multiple teams.
|
||||
|
||||
##### Step 3: Enter Site Name
|
||||
|
||||
You’ll be asked to optionally enter a site name.
|
||||
|
||||
##### Step 4: Configure Webhooks and Deployment Keys
|
||||
|
||||
At this point, the website is created on Netlify. However, Netlify needs to configure Webhooks and deployment keys. You’ll be asked to either authorize GitHub through Netlify’s website or through a personal access token. You’re free to choose either:
|
||||
|
||||
```bash noReport
|
||||
? Netlify CLI needs access to your GitHub account to configure Webhooks and Depl
|
||||
oy Keys. What would you like to do? (Use arrow keys)
|
||||
❯ Authorize with GitHub through app.netlify.com
|
||||
Authorize with a GitHub personal access token
|
||||
```
|
||||
|
||||
If you pick the first option, a page in your browser will open where you have to grant authorization to your Git provider.
|
||||
|
||||
If you pick the second option, you’ll need to create a personal access token on GitHub. You can follow [this guide in GitHub’s documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) to learn how to do it.
|
||||
|
||||
##### Last Step: Steps with Default Values
|
||||
|
||||
For the rest of the steps, you can keep the default values provided by Netlify and press the “Enter” key on your keyboard for each.
|
||||
|
||||
#### Set Environment Variables
|
||||
|
||||
After the previous command has finished running, your Netlify website will be created. The next step is to add an environment variable that points to your Medusa backend.
|
||||
|
||||
:::caution
|
||||
|
||||
If you haven’t deployed your Medusa backend yet, you can leave the value blank for now and add it later. However, the build process for the Gatsby storefront will fail.
|
||||
|
||||
:::
|
||||
|
||||
Run the following command to add the environment variable:
|
||||
|
||||
```bash
|
||||
netlify env:set GATSBY_MEDUSA_BACKEND_URL "<YOUR_BACKKEND_URL>"
|
||||
```
|
||||
|
||||
Where `<YOUR_BACKKEND_URL>` is the URL of your Medusa backend.
|
||||
|
||||
:::note
|
||||
|
||||
If you use more environment variables in your storefront be sure to add them here.
|
||||
|
||||
:::
|
||||
|
||||
#### Check deployment status
|
||||
|
||||
You can check the deployment status of your website by running the following command:
|
||||
|
||||
```bash
|
||||
netlify watch
|
||||
```
|
||||
|
||||
After the deployment has been completed, you should see a message saying “Deploy complete” with URLs to your website.
|
||||
|
||||
:::tip
|
||||
|
||||
If you haven’t added any products to your Medusa backend, the build process might fail. It’s recommended to add some products to the backend first in that case.
|
||||
|
||||
Alternatively, you can seed the backend with demo data by running this command in the root directory of the backend:
|
||||
|
||||
```bash noReport
|
||||
npx @medusajs/medusa-cli seed -f data/seed.json
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#### Open the Gatsby storefront Website
|
||||
|
||||
To open the Gatsby storefront website, either use the URL shown to you or run the following command:
|
||||
|
||||
```bash
|
||||
netlify open:site
|
||||
```
|
||||
|
||||
The Gatsby storefront will then open in your browser.
|
||||
|
||||

|
||||
|
||||
Before you can use the Gatsby storefront, you must add the URL as an environment variable on your deployed Medusa backend.
|
||||
|
||||
---
|
||||
|
||||
## Configure CORS Variable on the Medusa Backend
|
||||
|
||||
To send requests to the Medusa backend from the Gatsby storefront, you must set the `STORE_CORS` environment variable on your backend to the Gatsby storefront’s URL.
|
||||
|
||||
:::caution
|
||||
|
||||
If you want to set a custom domain to your Gatsby storefront website on Netlify, make sure to do it before this step. You can refer to this guide on [Netlify’s documentation to learn how to add a custom domain](https://docs.netlify.com/domains-https/custom-domains/#assign-a-domain-to-a-site).
|
||||
|
||||
:::
|
||||
|
||||
On your Medusa backend, add the following environment variable:
|
||||
|
||||
```bash
|
||||
STORE_CORS=<STOREFRONT_URL>
|
||||
```
|
||||
|
||||
Where `<STOREFRONT_URL>` is the URL of your Gatsby storefront that you just deployed.
|
||||
|
||||
Then, restart your Medusa backend. Once the backend is running again, you can use your Gatsby storefront.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Deploy the Medusa Admin](../admin/index.mdx)
|
||||
- [Configure your Medusa backend](../../development/backend/configurations.md)
|
||||
@@ -431,4 +431,4 @@ export default () => {
|
||||
## See Also
|
||||
|
||||
- [How to create a plugin](../plugins/create.mdx)
|
||||
- [How to publish a plugin](../plugins/publish.md)
|
||||
- [How to publish a plugin](../plugins/publish.mdx)
|
||||
|
||||
@@ -124,11 +124,123 @@ The `watch` command outputs the files in the destination specified in the value
|
||||
|
||||
:::
|
||||
|
||||
### Changes for Admin Plugins
|
||||
|
||||
:::note
|
||||
|
||||
Admin customizations are currently in beta and require you to use the `beta` version of `@medusajs/admin` and `@medusajs/medusa`. You can install it with the following command:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @medusajs/admin@beta @medusajs/medusa@beta
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
If your plugin contains customizations to the admin dashboard, it's recommended to create different `tsconfig` files for backend and admin customizations, then modify the scripts in `package.json` to handle building backend and admin customizations separately.
|
||||
|
||||
:::note
|
||||
|
||||
These changes may already be available in your Medusa project. They're included here for reference purposes.
|
||||
|
||||
:::
|
||||
|
||||
Start by updating your `tsconfig.json` with the following configurations:
|
||||
|
||||
```json title=tsconfig.json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es2019",
|
||||
"module": "commonjs",
|
||||
"allowJs": true,
|
||||
"checkJs": false,
|
||||
"jsx": "react-jsx",
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"noEmit": false,
|
||||
"strict": false,
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": ["src/"],
|
||||
"exclude": [
|
||||
"dist",
|
||||
"build",
|
||||
".cache",
|
||||
"tests",
|
||||
"**/*.spec.js",
|
||||
"**/*.spec.ts",
|
||||
"node_modules",
|
||||
".eslintrc.js"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The important changes to note here are the inclusion of the field `"jsx": "react-jsx"` and the addition of `"build"` and `“.cache”` to `exclude`.
|
||||
|
||||
The addition of `"jsx": "react-jsx"` specified how should TypeScript transform JSX, and excluding `build` and `.cache` ensures that TypeScript ignores build and development files.
|
||||
|
||||
Next, create the file `tsconfig.server.json` with the following content:
|
||||
|
||||
```json title=tsconfig.server.json
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
/* Emit a single file with source maps instead of having a separate file. */
|
||||
"inlineSourceMap": true
|
||||
},
|
||||
"exclude": ["src/admin", "**/*.spec.js"]
|
||||
}
|
||||
```
|
||||
|
||||
This is the configuration that will be used to transpile your custom backend code, such as services or entities. The important part is that it excludes `src/admin` as that is where your Admin code will live.
|
||||
|
||||
Then, create the file `tsconfig.admin.json` with the following content:
|
||||
|
||||
```json title=tsconfig.admin.json
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "esnext"
|
||||
},
|
||||
"include": ["src/admin"],
|
||||
"exclude": ["**/*.spec.js"]
|
||||
}
|
||||
```
|
||||
|
||||
This is the configuration that will be used when transpiling your admin code.
|
||||
|
||||
Finally, update the `build` script in your project:
|
||||
|
||||
```json title=package.json
|
||||
"scripts": {
|
||||
// other scripts...
|
||||
"build": "tsc -p ./tsconfig.server.json && medusa-admin bundle"
|
||||
}
|
||||
```
|
||||
|
||||
This `build` script builds the backend customizations, then bundles the admin plugin using `medusa-admin bundle`.
|
||||
|
||||
Furthermore, make sure to add `react` to `peerDependencies` along with `react-router-dom` if you're using it:
|
||||
|
||||
```json title=package.json
|
||||
"peerDependencies": {
|
||||
// other dependencies...
|
||||
"react": "^18.2.0",
|
||||
"react-router-dom": "^6.13.0"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Develop your Plugin
|
||||
|
||||
Now, You can start developing your plugin. This can include adding services, endpoints, entities, or anything that's relevant to your plugin.
|
||||
Now, You can start developing your plugin. This can include adding services, endpoints, entities, admin customizations, or anything that's relevant to your plugin.
|
||||
|
||||
### Plugin Structure
|
||||
|
||||
@@ -185,6 +297,32 @@ This guide doesn't cover how to create different files and components. If you’
|
||||
description: 'Learn how to create a subscriber.'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/widgets',
|
||||
label: 'Create an Admin Widget',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create an admin widget.',
|
||||
badge: {
|
||||
variant: 'orange',
|
||||
children: 'Beta'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/admin/routes',
|
||||
label: 'Create an Admin UI Route',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create an admin UI route.',
|
||||
badge: {
|
||||
variant: 'orange',
|
||||
children: 'Beta'
|
||||
}
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
If you're developing something specific, such as a payment processor plugin, you can follow one of the following guides to learn how to create different services within your plugin.
|
||||
@@ -299,6 +437,49 @@ Make sure to include in the README of your plugin the configurations that can be
|
||||
|
||||
:::
|
||||
|
||||
### enableUI Plugin Option
|
||||
|
||||
All plugins accept an option named `enableUI`. This option is useful mainly if your plugin contains admin customizations. It allows users to enable or disable admin customizations in the admin dashboard.
|
||||
|
||||
You can pass the `enableUI` option to plugins as follows:
|
||||
|
||||
```js title=medusa-config.js
|
||||
const plugins = [
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-plugin-custom`,
|
||||
options: {
|
||||
// other options
|
||||
enableUI: true,
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
If you're passing your plugin options to third-party services, make sure to omit it from the plugin options you receive in your resources, such as services. The `enableUI` option will always be passed as part of your plugin options.
|
||||
|
||||
For example:
|
||||
|
||||
```js title=src/service/test.ts
|
||||
// In a service in your plugin
|
||||
class MyService extends TransactionBaseService {
|
||||
constructor(container, options) {
|
||||
super(container)
|
||||
// options contains plugin configurations
|
||||
const { enableUI, ...otherOptions } = options
|
||||
// pass otherOptions to a third-party service
|
||||
const client = new Client(otherOptions)
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
Since admin customizations are still in `beta` mode, `enableUI`'s default value is `false` if not provided by the plugin users. This means that it must be enabled manually in a plugin's configuration for the customizations to appear in the admin dashboard. Once the admin customizations are out of beta, this behavior will be reversed.
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Test Your Plugin
|
||||
@@ -413,4 +594,4 @@ It is safe to ignore any `cross-env: command not found` error you may receive.
|
||||
|
||||
Once you're done with the development of the plugin, you can publish it to NPM so that other Medusa developers and users can use it.
|
||||
|
||||
Please refer to [this guide on required steps to publish a plugin](./publish.md).
|
||||
Please refer to [this guide on required steps to publish a plugin](./publish.mdx).
|
||||
|
||||
@@ -21,6 +21,8 @@ An alternative approach is developing a custom way of handling payment on your e
|
||||
|
||||
Plugins run within the same process as the core Medusa backend eliminating the need for extra backend capacity, infrastructure, and maintenance. As a result, plugins can use all other services as dependencies and access the database.
|
||||
|
||||
Plugins can contain customizations to the Medusa backend or the admin dashboard.
|
||||
|
||||
---
|
||||
|
||||
## Using Existing Plugins
|
||||
@@ -41,6 +43,8 @@ You can find community plugins by [searching NPM for the `medusa` or `medusa-plu
|
||||
|
||||
You can also check the [Awesome Medusa repository](https://github.com/adrien2p/awesome-medusajs#plugins) for a list of community plugins among other resources.
|
||||
|
||||
---
|
||||
|
||||
## How to Install a Plugin
|
||||
|
||||
To install an existing plugin, in your Medusa backend run the following command:
|
||||
@@ -57,6 +61,31 @@ If you’re installing an official plugin from the Medusa repository, you can fi
|
||||
|
||||
For community plugins, please refer to the installation instructions of that plugin to learn about any required configurations.
|
||||
|
||||
### enableUI Plugin Option
|
||||
|
||||
All plugins accept an option named `enableUI`. This option allows you to disable admin customizations from appearing in the admin dashboard.
|
||||
|
||||
:::note
|
||||
|
||||
Since admin customizations are still in `beta` mode, `enableUI`'s default value is `false` if not provided by the plugin users. This means that it must be enabled manually in a plugin's configuration for the customizations to appear in the admin dashboard. Once the admin customizations are out of beta, this behavior will be reversed.
|
||||
|
||||
:::
|
||||
|
||||
You can set the `enableUI` value by passing it as part of the plugin's configurations:
|
||||
|
||||
```js title=medusa-config.js
|
||||
const plugins = [
|
||||
// ...
|
||||
{
|
||||
resolve: `medusa-plugin-custom`,
|
||||
options: {
|
||||
// other options
|
||||
enableUI: true,
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Custom Development
|
||||
|
||||
@@ -3,6 +3,9 @@ description: 'Learn how to publish a Medusa plugin to NPM. This guide lists some
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Publish a Plugin
|
||||
|
||||
In this document, you'll learn how to publish a Medusa plugin to NPM and what are some requirements to keep in mind before publishing. Afterwards, your plugin will be published on the [Medusa Plugins page](https://medusajs.com/plugins/).
|
||||
@@ -35,26 +38,63 @@ Before publishing your plugin, make sure you've set the following fields in your
|
||||
- `medusa-plugin-storage`: For plugins that add a file service or storage integration.
|
||||
- `medusa-plugin-source`: For plugins that help migrate or import data into Medusa from another platform.
|
||||
- `medusa-plugin-storefront`: For storefronts that can be integrated with a Medusa backend.
|
||||
- `medusa-plugin-admin`: For plugins that include only admin customizations.
|
||||
- `medusa-plugin-other`: For any other type of plugin.
|
||||
|
||||
### Scripts in package.json
|
||||
|
||||
Make sure you add the `publish` command to your `scripts` field and make the following change to the `build` command:
|
||||
<Tabs groupId="plugin-preference">
|
||||
<TabItem value="without-admin" label="Without Admin Customizations" default>
|
||||
|
||||
```json title=package.json
|
||||
"build": "babel src --out-dir . --ignore **/__tests__ --extensions \".ts,.js\"",
|
||||
"prepare": "cross-env NODE_ENV=production npm run build"
|
||||
```
|
||||
Make sure you add the `publish` command to your `scripts` field and make the following change to the `build` command:
|
||||
|
||||
The `build` command ensures that the plugin's built files are placed as explained in the [plugin structure](./create.mdx#plugin-structure) section of the Create Plugin documentation.
|
||||
```json title=package.json
|
||||
"scripts": {
|
||||
// other scripts...
|
||||
"build": "cross-env npm run clean && tsc",
|
||||
"prepare": "cross-env NODE_ENV=production npm run build"
|
||||
}
|
||||
```
|
||||
|
||||
The `prepare` command facilitates your publishing process. You would typically run this script before publishing your plugin.
|
||||
The `build` command ensures that the plugin's built files are placed as explained in the [plugin structure](./create.mdx#plugin-structure) section of the Create Plugin documentation.
|
||||
|
||||
This new script requires installing the package `cross-env` as a development dependency:
|
||||
The `prepare` command facilitates your publishing process. You would typically run this script before publishing your plugin.
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save-dev cross-env
|
||||
```
|
||||
This new script requires installing the package `cross-env` as a development dependency:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save-dev cross-env
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="with-admin" label="With Admin Customizations">
|
||||
|
||||
First, make sure to change `tsconfig` files as recommended in the [create guide](./create.mdx#changes-for-admin-plugins).
|
||||
|
||||
Then, add the `publish` command to your `scripts` field and make the following change to the `build` command:
|
||||
|
||||
```json title=package.json
|
||||
"scripts": {
|
||||
// other scripts...
|
||||
"build": "tsc -p ./tsconfig.server.json && medusa-admin bundle",
|
||||
"prepare": "cross-env NODE_ENV=production npm run build"
|
||||
}
|
||||
```
|
||||
|
||||
The `build` command ensures that the plugin's built files are placed as explained in the [plugin structure](./create.mdx#plugin-structure) section of the Create Plugin documentation, and bundles the admin customizations.
|
||||
|
||||
The `prepare` command facilitates your publishing process. You would typically run this script before publishing your plugin.
|
||||
|
||||
This new script requires installing the package `cross-env` as a development dependency:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install --save-dev cross-env
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
###
|
||||
|
||||
### Plugin Structure
|
||||
|
||||
@@ -83,6 +123,8 @@ src
|
||||
.eslintrc
|
||||
.babelrc
|
||||
.prettierrc
|
||||
build
|
||||
.cache
|
||||
|
||||
# These are files that are included in a
|
||||
# Medusa project and can be removed from a
|
||||
@@ -413,4 +413,4 @@ You can then send a request to the [Search Products endpoint](/api/store#tag/Pro
|
||||
## See Also
|
||||
|
||||
- [How to create a plugin](../plugins/create.mdx)
|
||||
- [How to publish a plugin](../plugins/publish.md)
|
||||
- [How to publish a plugin](../plugins/publish.mdx)
|
||||
|
||||
@@ -162,40 +162,40 @@ Learn about all the new features and enhancements in Medusa.
|
||||
<DocCardList colSize={4} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/multiwarehouse/overview',
|
||||
label: 'Multi-Warehouse',
|
||||
href: '/modules/products/serverless-module',
|
||||
label: 'Product Module',
|
||||
customProps: {
|
||||
icon: Icons['building-solid'],
|
||||
description: 'Allows merchants to store a product in multiple locations with accurate and consistent inventory data.',
|
||||
icon: Icons['tag-solid'],
|
||||
description: 'Learn about the new product module and how to use it in a serverless setup.',
|
||||
badge: {
|
||||
variant: 'blue',
|
||||
children: 'New'
|
||||
variant: 'orange',
|
||||
children: 'Beta'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/products/categories',
|
||||
label: 'Product Categories',
|
||||
href: '/admin/widgets',
|
||||
label: 'Admin Widgets',
|
||||
customProps: {
|
||||
icon: Icons['swatch-solid'],
|
||||
description: 'Clearer organization of your products under categories that can be nested and ranked.',
|
||||
icon: Icons['component-solid'],
|
||||
description: 'Learn how you can customize the admin dashboard with admin widgets.',
|
||||
badge: {
|
||||
variant: 'blue',
|
||||
children: 'New'
|
||||
variant: 'orange',
|
||||
children: 'Beta'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/modules/overview',
|
||||
label: 'Modules',
|
||||
href: '/admin/routes',
|
||||
label: 'Admin UI Routes',
|
||||
customProps: {
|
||||
icon: Icons['puzzle-solid'],
|
||||
description: 'Modules are self-contained packaged functionalities that are isolated from the Medusa core.',
|
||||
icon: Icons['computer-desktop-solid'],
|
||||
description: 'Learn how you can customize the admin dashboard with admin UI routes.',
|
||||
badge: {
|
||||
variant: 'blue',
|
||||
children: 'New'
|
||||
variant: 'orange',
|
||||
children: 'Beta'
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -207,4 +207,4 @@ Learn about all the new features and enhancements in Medusa.
|
||||
|
||||
<!-- vale docs.HeadingPunctuation = YES -->
|
||||
|
||||
If you’re still not sure that Medusa is the right solution for you, you can get in-touch with the core Medusa team over at [Discord](https://discord.gg/medusajs) and get help from the community.
|
||||
If you’re still not sure that Medusa is the right solution for you, you can get in-touch with the core Medusa team over at [Discord](https://discord.gg/medusajs) and get help from the community.
|
||||
|
||||
@@ -188,6 +188,95 @@ Instead of using `mutate`, you can use `mutateAsync` to receive a Promise that r
|
||||
|
||||
Learn more about how you can use mutations in [Tanstack Query’s documentation](https://tanstack.com/query/v4/docs/react/guides/mutations).
|
||||
|
||||
### Custom Hooks
|
||||
|
||||
Medusa React provides a utility function `createCustomAdminHooks` that allows developers to consume their admin custom endpoints using the same Medusa React methods and conventions. It returns custom mutation and query hooks that you can use to retrieve and manipulate data using your custom endpoints. This utility function is useful when customizing the admin with widgets.
|
||||
|
||||
```ts
|
||||
import { createCustomAdminHooks } from "medusa-react"
|
||||
|
||||
const {
|
||||
useAdminEntity,
|
||||
useAdminEntities,
|
||||
useAdminCreateMutation,
|
||||
useAdminUpdateMutation,
|
||||
useAdminDeleteMutation,
|
||||
} = createCustomAdminHooks(
|
||||
`/vendors`,
|
||||
"vendors",
|
||||
{ product: true }
|
||||
)
|
||||
```
|
||||
|
||||
It accepts the following parameters:
|
||||
|
||||
1. `path`: (required) the first parameter is a string that indicates the base path to the custom endpoint. For example, if you have custom endpoints that begin with `/admin/vendors`, the value of this parameter would be `vendors`. The `/admin` prefix will be added automatically.
|
||||
2. `queryKey`: (required) the second parameter is a string used to generate query keys for all `GET` hooks, which is used by Tanstack Query for caching. When a mutation related to this same key succeeds, the key will be automatically invalidated.
|
||||
3. `relatedDomains`: (optional) the third parameter is an object that can be used to specify domains related to this custom hook. This will ensure that Tanstack Query invalides the keys for those domains when your custom mutations succeed. For example, if your custom endpoint is related to products, you can pass `{ product: true }` as the value of this parameter. Then, when you use your custom mutation and it succeeds, the product's key `adminProductKeys.all` will be invalidated automatically, and all products will be re-fetched.
|
||||
|
||||
:::note
|
||||
|
||||
While the mechanism implemented using the `relatedDomains` parameter may seem a bit excessive, Tanstack Query is smart enough to only re-fetch the queries that are currently active. So, it won't result in all queries being re-fetched simultaneously.
|
||||
|
||||
:::
|
||||
|
||||
The function returns an object containing the following hooks:
|
||||
|
||||
- `useAdminEntity`: is a query hook that allows retrieving a single entry using your custom endpoint. For example, if you have the `GET` endpoint `/admin/vendors/:id`, where `:id` is the ID of a vendor, you can use this hook to call that endpoint and retrieve a vendor by its ID.
|
||||
- `useAdminEntities`: is a query hook that allows retrieving a list of entries using your custom endpoint. For example, if you have the `GET` endpoint `/admin/vendors`, you can use this hook to call that endpoint and retrieve the list of vendors.
|
||||
- `useAdminCreateMutation`: is a mutation hook that allows creating an entry using your custom endpoint. For example, if you have the `POST` endpoint `/admin/vendors`, you can use this hook to call that endpoint and create a vendor.
|
||||
- `useAdminUpdateMutation`: is a mutation hook that allows updating an entry using your custom endpoint. For example, if you have the `POST` endpoint `/admin/vendors/:id`, you can use this hook to call that endpoint and update a vendor.
|
||||
- `useAdminDeleteMutation`: is a mutation hook that allows deleting an entry using your custom endpoint. For example, if you have the `DELETE` endpoint `/admin/vendors/:id`, you can use this hook to call that endpoint and delete a vendor.
|
||||
|
||||
Each of these hooks are generic, allowing you to set the types for the functions and receive IntelliSense for the query parameters, the payload, and return data. The first generic type accepted would be the type of the request, and the second type accepted would be the type of the response.
|
||||
|
||||
An example of using `createCustomAdminHooks`:
|
||||
|
||||
```ts
|
||||
import { createCustomAdminHooks } from "medusa-react"
|
||||
|
||||
type PostVendorsReq = {
|
||||
name: string
|
||||
}
|
||||
|
||||
type PostVendorRes = {
|
||||
vendor: Vendor // assuming there's a type vendor
|
||||
}
|
||||
|
||||
const MyWidget = () => {
|
||||
const {
|
||||
useAdminCreateMutation: useCreateVendor,
|
||||
} = createCustomAdminHooks(
|
||||
`/vendors`,
|
||||
"vendors",
|
||||
{ product: true }
|
||||
)
|
||||
|
||||
const { mutate } = useCreateVendor<
|
||||
PostVendorsReq,
|
||||
PostVendorRes
|
||||
>()
|
||||
|
||||
// ...
|
||||
|
||||
const handleCreate = () => {
|
||||
mutate({
|
||||
name: "Vendor 1",
|
||||
}, {
|
||||
onSuccess({ vendor }) {
|
||||
console.log(vendor)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
In the example above, you use `createCustomAdminHooks` to create the custom hook `useAdminCreateMutation`, renamed to `useCreateVendor`. You then use `useCreateVendor` to initialize the `mutate` function. You set the generic types of useCreateVendor to the types `PostVendorsReq` and `PostVendorRes`, which are assumed to be the types of the create endpoint's request and response respectively.
|
||||
|
||||
Later in your code, you can use the `mutate` function to send a request to your endpoint and create a new vendor. The `mutate` function accepts the request's body parameters as an object. You can use the `onSuccess` function, which can be defined in the second parameter object of the `mutate` function, to get access to the response received.
|
||||
|
||||
---
|
||||
|
||||
## Utilities
|
||||
|
||||
@@ -123,22 +123,22 @@ export default CreateReservation
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/reservations`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
line_item_id,
|
||||
location_id,
|
||||
inventory_item_id,
|
||||
quantity,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ reservation }) => {
|
||||
console.log(reservation.id)
|
||||
})
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
line_item_id,
|
||||
location_id,
|
||||
inventory_item_id,
|
||||
quantity,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ reservation }) => {
|
||||
console.log(reservation.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
@@ -0,0 +1,401 @@
|
||||
---
|
||||
description: 'Learn how to manage custom reservations of a product variant using the admin APIs. This includes how to list, create, update, and delete reservations.'
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
# How to Manage Custom Reservations
|
||||
|
||||
In this document, you’ll learn how to manage custom reservations of a product variant using the admin APIs.
|
||||
|
||||
:::tip
|
||||
|
||||
Although this guide covers how to manage custom reservations of product variants, you can create custom reservations for any entity that is associated with an Inventory Item.
|
||||
|
||||
:::
|
||||
|
||||
## Overview
|
||||
|
||||
When an order is created, reservations are created for the items in that order automatically. However, Medusa also provides the capability to create custom reservations that aren’t related to any order. Custom reservations allow you to allocate quantities of a product variant manually. You can do that using the Reservations admin APIs.
|
||||
|
||||
The functionalities in this guide apply to all types of reservations, including those associated with an order and those that aren’t.
|
||||
|
||||
### Scenario
|
||||
|
||||
You want to add or use the following admin functionalities:
|
||||
|
||||
- List reservations, including custom reservations or those associated with orders.
|
||||
- Manage a reservation, including creating, updating, and deleting a reservation.
|
||||
|
||||
:::note
|
||||
|
||||
You can check the [API reference](/api/admin) for all available Reservations endpoints.
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Medusa Components
|
||||
|
||||
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow the [quickstart guide](../../../development/backend/install.mdx) to get started.
|
||||
|
||||
### Required Module
|
||||
|
||||
This guide assumes you have a stock location and inventory modules installed. You can use Medusa’s [Stock Location and Inventory modules](../install-modules.md) or create your own modules.
|
||||
|
||||
### JS Client
|
||||
|
||||
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.
|
||||
|
||||
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client](../../../js-client/overview.md) installed and have [created an instance of the client](../../../js-client/overview.md#configuration).
|
||||
|
||||
### Medusa React
|
||||
|
||||
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.md) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.md#usage).
|
||||
|
||||
### Authenticated Admin User
|
||||
|
||||
You must be an authenticated admin user before following along with the steps in the tutorial.
|
||||
|
||||
You can learn more about [authenticating as an admin user in the API reference](/api/admin/#section/Authentication).
|
||||
|
||||
---
|
||||
|
||||
## List Reservations
|
||||
|
||||
You can list all reservations in your store by sending a request to the [List Reservations endpoint](https://docs.medusajs.com/api/admin#tag/Reservations/operation/GetReservations):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.reservations.list()
|
||||
.then(({ reservations, limit, count, offset }) => {
|
||||
console.log(reservations.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminReservations } from "medusa-react"
|
||||
|
||||
const Reservations = () => {
|
||||
const { reservations, isLoading } = useAdminReservations()
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading && <span>Loading...</span>}
|
||||
{reservations && !reservations.length && (
|
||||
<span>No Reservations</span>
|
||||
)}
|
||||
{reservations && reservations.length > 0 && (
|
||||
<ul>
|
||||
{reservations.map((reservation) => (
|
||||
<li key={reservation.id}>{reservation.quantity}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Reservations
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/reservations`, {
|
||||
credentials: "include",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ reservations, limit, count, offset }) => {
|
||||
console.log(reservations.length)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X GET '<BACKEND_URL>/admin/reservations' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint does not require any query or path parameters. You can pass it query parameters for filtering or pagination purposes. Check out the [API reference](/api/admin#tag/Reservations/operation/GetReservations) for a list of accepted query parameters.
|
||||
|
||||
This endpoint returns an array of reservations along with [pagination parameters](/api/admin#section/Pagination).
|
||||
|
||||
---
|
||||
|
||||
## Create a Reservation
|
||||
|
||||
:::note
|
||||
|
||||
Before you create a reservation for a product variant, make sure you’ve created an inventory item for that variant. You can learn how to do that in [this guide](./manage-inventory-items.mdx#create-an-inventory-item).
|
||||
|
||||
:::
|
||||
|
||||
You can create a reservation by sending a request to the [Create Reservation endpoint](/api/admin#tag/Reservations/operation/PostReservations):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.reservations.create({
|
||||
location_id,
|
||||
inventory_item_id,
|
||||
quantity,
|
||||
})
|
||||
.then(({ reservation }) => {
|
||||
console.log(reservation.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminCreateReservation } from "medusa-react"
|
||||
|
||||
const CreateReservation = () => {
|
||||
const createReservation = useAdminCreateReservation()
|
||||
// ...
|
||||
|
||||
const handleCreate = () => {
|
||||
createReservation.mutate({
|
||||
location_id,
|
||||
inventory_item_id,
|
||||
quantity,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default CreateReservation
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/reservations`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
location_id,
|
||||
inventory_item_id,
|
||||
quantity,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ reservation }) => {
|
||||
console.log(reservation.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/reservations' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"location_id": "<LOC_ID>",
|
||||
"inventory_item_id": "<INV_ITEM_ID>",
|
||||
"quantity": 1
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the following body parameters:
|
||||
|
||||
- `location_id`: The ID of the location the reservation is created in.
|
||||
- `inventory_item_id`: The ID of the inventory item the product variant is associated with.
|
||||
- `quantity`: The quantity to allocate.
|
||||
|
||||
The request returns the created reservation as an object.
|
||||
|
||||
---
|
||||
|
||||
## Update a Reservation
|
||||
|
||||
You can update a reservation by sending a request to the [Update Reservation endpoint](/api/admin#tag/Reservations/operation/PostReservationsReservation):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.reservations.update(reservationId, {
|
||||
quantity,
|
||||
})
|
||||
.then(({ reservation }) => {
|
||||
console.log(reservation.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminUpdateReservation } from "medusa-react"
|
||||
|
||||
const UpdateReservation = () => {
|
||||
const updateReservation = useAdminUpdateReservation(
|
||||
reservationId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleCreate = () => {
|
||||
updateReservation.mutate({
|
||||
quantity,
|
||||
})
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default UpdateReservation
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/reservations/${reservationId}`, {
|
||||
credentials: "include",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
quantity,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ reservation }) => {
|
||||
console.log(reservation.id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X POST '<BACKEND_URL>/admin/reservations/<RESERVATION_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>' \
|
||||
-H 'Content-Type: application/json' \
|
||||
--data-raw '{
|
||||
"quantity": 3
|
||||
}'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the ID of the reservation as a path parameter.
|
||||
|
||||
In the request body parameters, you can optionally pass any of the following parameters to make updates to the reservation:
|
||||
|
||||
- `quantity`: The quantity that should be reserved.
|
||||
- `location_id`: The ID of the location that the product variant should be allocated from.
|
||||
- `metadata`: set or change the reservation’s metadata.
|
||||
|
||||
The request returns the updated reservation as an object.
|
||||
|
||||
---
|
||||
|
||||
## Delete a Reservation
|
||||
|
||||
You can delete a reservation by sending a request to the [Delete Reservation endpoint](/api/admin#tag/Reservations/operation/DeleteReservationsReservation):
|
||||
|
||||
<Tabs groupId="request-type" isCodeTabs={true}>
|
||||
<TabItem value="client" label="Medusa JS Client" default>
|
||||
|
||||
```ts
|
||||
medusa.admin.reservations.delete(reservationId)
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="medusa-react" label="Medusa React">
|
||||
|
||||
```tsx
|
||||
import { useAdminDeleteReservation } from "medusa-react"
|
||||
|
||||
const DeleteReservation = () => {
|
||||
const deleteReservation = useAdminDeleteReservation(
|
||||
reservationId
|
||||
)
|
||||
// ...
|
||||
|
||||
const handleDelete = () => {
|
||||
deleteReservation.mutate()
|
||||
}
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export default DeleteReservation
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
```ts
|
||||
fetch(`<BACKEND_URL>/admin/reservations/${reservationId}`, {
|
||||
credentials: "include",
|
||||
method: "DELETE",
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then(({ id, object, deleted }) => {
|
||||
console.log(id)
|
||||
})
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="curl" label="cURL">
|
||||
|
||||
```bash
|
||||
curl -L -X DELETE '<BACKEND_URL>/admin/reservations/<RESERVATION_ID>' \
|
||||
-H 'Authorization: Bearer <API_TOKEN>'
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This endpoint requires the reservation ID to be passed as a path parameter.
|
||||
|
||||
The request returns the following fields:
|
||||
|
||||
- `id`: The ID of the reservation.
|
||||
- `object`: The type of object that was removed. In this case, the value will be `reservation`.
|
||||
- `deleted`: A boolean value indicating whether the reservation was successfully deleted.
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [How to manage inventory items](./manage-inventory-items.mdx)
|
||||
- [How to manage stock locations](./manage-stock-locations.mdx)
|
||||
386
docs/content/modules/products/serverless-module.md
Normal file
386
docs/content/modules/products/serverless-module.md
Normal file
@@ -0,0 +1,386 @@
|
||||
---
|
||||
title: 'How to Use Serverless Product Module'
|
||||
description: 'Learn how to use the product module in a serverless setup by installing it in a Next.js application.'
|
||||
addHowToData: true
|
||||
badge:
|
||||
variant: orange
|
||||
text: beta
|
||||
---
|
||||
|
||||
In this document, you’ll learn how to use the Product module in a serverless setup.
|
||||
|
||||
## Overview
|
||||
|
||||
Medusa’s modules increase extensibility and customization capabilities. Instead of having to manage a fully-fledged ecommerce system, you can use these modules in serverless applications, such as a Next.js project.
|
||||
|
||||
The module only needs to connect to a PostgreSQL database. You can also connect it to an existing Medusa database. Then, you can use the Product module to connect directly to the PostgreSQL database and retrieve or manipulate data.
|
||||
|
||||
This guide explains how to use the Product Module in a Next.js application as an example. You can use it with other frameworks, such as Remix, as well.
|
||||
|
||||
### Benefits of Serverless Modules
|
||||
|
||||
- Keep packages small enough to be deployed to serverless Infrastructure easily
|
||||
- Bring Medusa closer to Edge runtime compatibility.
|
||||
- Make it easier to integrate modules into an ecosystem of existing commerce services.
|
||||
- Make it easier to customize or extend core logic in Medusa.
|
||||
|
||||
:::info
|
||||
|
||||
The product module is currently in beta, and it provides only functionalities related to browsing products. In later versions, the product module would include more powerful ecommerce features.
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- The Product Module requires a project using Node v16+.
|
||||
- The Product Module must connect to a PostgreSQL database. You can refer to [this guide](../../development/backend/prepare-environment.mdx#postgresql) to learn how to install PostgreSQL locally. Alternatively, you can use free PostgreSQL database hosting, such as [Vercel Postgres](https://vercel.com/docs/storage/vercel-postgres). If you have an existing Medusa database, you can use it as well.
|
||||
|
||||
---
|
||||
|
||||
## Installation in Next.js Project
|
||||
|
||||
This section explains how to install the Product module in a Next.js project.
|
||||
|
||||
If you don’t have a Next.js project, you can create one with the following command:
|
||||
|
||||
```bash
|
||||
npx create-next-app@latest
|
||||
```
|
||||
|
||||
Refer to the [Next.js documentation](https://nextjs.org/docs/getting-started/installation) for other available installation options.
|
||||
|
||||
### Step 1: Install Product Module
|
||||
|
||||
In the root directory of your Next.js project, run the following command to install the product module:
|
||||
|
||||
```bash npm2yarn
|
||||
npm install @medusajs/product
|
||||
```
|
||||
|
||||
### Step 2: Add Database Configurations
|
||||
|
||||
Create a `.env` file and add the following environment variable:
|
||||
|
||||
```bash
|
||||
POSTGRES_URL=<DATABASE_URL>
|
||||
```
|
||||
|
||||
Where `<DATABASE_URL>` is your database connection URL of the format `postgres://[user][:password]@[host][:port]/[dbname]`. You can learn more about the connection URL format in [this guide](../../development/backend/configurations.md#postgresql-configurations).
|
||||
|
||||
You can also set the following optional environment variables:
|
||||
|
||||
- `POSTGRES_SCHEMA`: a string indicating the PostgreSQL schema to use. By default, it's `public`.
|
||||
- `POSTGRES_DRIVER_OPTIONS`: a stringified JSON object indicating the PostgreSQL options to use. The JSON object is then parsed to be used as a JavaScript object. By default, it's `{"connection":{"ssl":false}}` for local PostgreSQL databases, and `{"connection":{"ssl":{"rejectUnauthorized":false}}}` for remote databases.
|
||||
|
||||
:::note
|
||||
|
||||
If `POSTGRES_DRIVER_OPTIONS` is not specified, the PostgreSQL database is considered local if `POSTGRES_URL` includes `localhost`. Otherwise, it's considered remote.
|
||||
|
||||
:::
|
||||
|
||||
### Step 3: Run Database Migrations
|
||||
|
||||
:::note
|
||||
|
||||
If you are using an existing Medusa database, you can skip this step.
|
||||
|
||||
:::
|
||||
|
||||
Migrations are used to create your database schema. Before you can run migrations, add in your `package.json` the following scripts:
|
||||
|
||||
```json title=package.json
|
||||
"scripts": {
|
||||
//...other scripts
|
||||
"product:migrations:run": "medusa-product-migrations-up",
|
||||
"product:seed": "medusa-product-seed ./seed-data.js"
|
||||
},
|
||||
```
|
||||
|
||||
The first command runs the migrations, and the second command allows you to optionally seed your database with demo products. However, you’d need the following seed file added in the root of your Next.js directory:
|
||||
|
||||
<details>
|
||||
<summary>Seed file</summary>
|
||||
|
||||
```js title=seed-data.js
|
||||
const productCategoriesData = [
|
||||
{
|
||||
id: "category-0",
|
||||
name: "category 0",
|
||||
parent_category_id: null,
|
||||
},
|
||||
{
|
||||
id: "category-1",
|
||||
name: "category 1",
|
||||
parent_category_id: "category-0",
|
||||
},
|
||||
{
|
||||
id: "category-1-a",
|
||||
name: "category 1 a",
|
||||
parent_category_id: "category-1",
|
||||
},
|
||||
{
|
||||
id: "category-1-b",
|
||||
name: "category 1 b",
|
||||
parent_category_id: "category-1",
|
||||
is_internal: true,
|
||||
},
|
||||
{
|
||||
id: "category-1-b-1",
|
||||
name: "category 1 b 1",
|
||||
parent_category_id: "category-1-b",
|
||||
},
|
||||
]
|
||||
|
||||
const productsData = [
|
||||
{
|
||||
id: "test-1",
|
||||
title: "product 1",
|
||||
status: "published",
|
||||
descriptions: "Lorem ipsum dolor sit amet, consectetur.",
|
||||
tags: [
|
||||
{
|
||||
id: "tag-1",
|
||||
value: "France",
|
||||
},
|
||||
],
|
||||
categories: [
|
||||
{
|
||||
id: "category-0",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "test-2",
|
||||
title: "product",
|
||||
status: "published",
|
||||
descriptions: "Lorem ipsum dolor sit amet, consectetur.",
|
||||
tags: [
|
||||
{
|
||||
id: "tag-2",
|
||||
value: "Germany",
|
||||
},
|
||||
],
|
||||
categories: [
|
||||
{
|
||||
id: "category-1",
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const variantsData = [
|
||||
{
|
||||
id: "test-1",
|
||||
title: "variant title",
|
||||
sku: "sku 1",
|
||||
product: { id: productsData[0].id },
|
||||
inventory_quantity: 10,
|
||||
},
|
||||
{
|
||||
id: "test-2",
|
||||
title: "variant title",
|
||||
sku: "sku 2",
|
||||
product: { id: productsData[1].id },
|
||||
inventory_quantity: 10,
|
||||
},
|
||||
]
|
||||
|
||||
module.exports = {
|
||||
productCategoriesData,
|
||||
productsData,
|
||||
variantsData,
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Then run the first and optionally second commands to migrate the database schema:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run product:migrations:run
|
||||
# optionally
|
||||
npm run product:seed
|
||||
```
|
||||
|
||||
### Step 4: Adjust Next.js Configurations
|
||||
|
||||
Next.js uses Webpack for compilation. Since quite a few of the dependencies used by the product module are not Webpack optimized, you have to add the product module as an external dependency.
|
||||
|
||||
To do that, add the `serverComponentsExternalPackages` option in `next.config.js`:
|
||||
|
||||
```js title=next.config.js
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
experimental: {
|
||||
serverComponentsExternalPackages: [
|
||||
"@medusajs/product",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
```
|
||||
|
||||
### Step 5: Create API Route
|
||||
|
||||
The product module is ready for use now! You can now use it to create API endpoints within your Next.js application.
|
||||
|
||||
:::note
|
||||
|
||||
This guide uses Next.js's App Router.
|
||||
|
||||
:::
|
||||
|
||||
For example, create the file `app/api/products/route.ts` with the following content:
|
||||
|
||||
```ts title=app/api/products/route.ts
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const productService = await initializeProductModule()
|
||||
|
||||
const data = await productService.list()
|
||||
|
||||
return NextResponse.json({ products: data })
|
||||
}
|
||||
```
|
||||
|
||||
This creates a `GET` endpoint at the route `/api/products`. You import the `initialize` function, aliased as `initializeProductModule`, from `@medusajs/product`. Then, in the endpoint, you invoke the `initializeProductModule` function, which returns an instance of the `ProductModuleService`. Using the product module service’s `list` method, you retrieve all available products and return them in the response of the endpoint.
|
||||
|
||||
### Step 6: Test Next.js Application
|
||||
|
||||
To test the endpoint you added, start your Next.js application with the following command:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Then, open in your browser the URL `http://localhost:3000/api/products`. If you seeded your database with demo products, or you’re using a Medusa database schema, you’ll receive the products in your database. Otherwise, the request will return an empty array.
|
||||
|
||||
---
|
||||
|
||||
## Example Usages
|
||||
|
||||
This section includes some examples of the different functionalities or ways you can use the product module. The code snippets are shown in the context of endpoints.
|
||||
|
||||
### List Products
|
||||
|
||||
```ts title=app/api/products/route.ts
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const productService = await initializeProductModule()
|
||||
|
||||
const data = await productService.list()
|
||||
|
||||
return NextResponse.json({ products: data })
|
||||
}
|
||||
```
|
||||
|
||||
### Retrieve Product by Id
|
||||
|
||||
```ts title=app/api/product/[id]/route.ts
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Record<string, any> }) {
|
||||
|
||||
const { id } = params
|
||||
const productService = await initializeProductModule()
|
||||
|
||||
const data = await productService.list({
|
||||
id,
|
||||
})
|
||||
|
||||
return NextResponse.json({ product: data[0] })
|
||||
}
|
||||
```
|
||||
|
||||
### Retrieve Product by Handle
|
||||
|
||||
```ts title=app/api/product/[handle]/route.ts
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Record<string, any> }) {
|
||||
|
||||
const { handle } = params
|
||||
const productService = await initializeProductModule()
|
||||
|
||||
const data = await productService.list({
|
||||
handle,
|
||||
})
|
||||
|
||||
return NextResponse.json({ product: data[0] })
|
||||
}
|
||||
```
|
||||
|
||||
### Retrieve Categories
|
||||
|
||||
```ts title=app/api/categories/route.ts
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const productService = await initializeProductModule()
|
||||
|
||||
const data = await productService.listCategories()
|
||||
|
||||
return NextResponse.json({ categories: data })
|
||||
}
|
||||
```
|
||||
|
||||
### Retrieve Category by Handle
|
||||
|
||||
```ts title=app/api/category/[handle]/route.ts
|
||||
import { NextResponse } from "next/server"
|
||||
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: Record<string, any> }) {
|
||||
|
||||
const { handle } = params
|
||||
const productService = await initializeProductModule()
|
||||
|
||||
const data = await productService.listCategories({
|
||||
handle,
|
||||
})
|
||||
|
||||
return NextResponse.json({ category: data[0] })
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Products Commerce Module Overview](./overview.mdx)
|
||||
- [How to show products in a storefront](./storefront/show-products.mdx)
|
||||
- [How to show categories in a storefront](./storefront/use-categories.mdx)
|
||||
@@ -5,6 +5,7 @@ addHowToData: true
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import Badge from '@site/src/components/Badge';
|
||||
|
||||
# How to Show Products on the Storefront
|
||||
|
||||
@@ -45,6 +46,12 @@ This guide also includes code snippets to send requests to your Medusa backend u
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.md) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.md#usage).
|
||||
|
||||
### @medusajs/product Module
|
||||
|
||||
This guide also includes code snippets to utilize the `@medusajs/product` module in your storefront, among other methods.
|
||||
|
||||
If you follow the `@medusajs/product` code blocks, it's assumed you already have the [@medusajs/product](../serverless-module.md) installed.
|
||||
|
||||
---
|
||||
|
||||
## List Products
|
||||
@@ -89,6 +96,31 @@ const Products = () => {
|
||||
export default Products
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="module" label={(
|
||||
<>
|
||||
@medusajs/product
|
||||
<Badge variant="orange-dark">beta</Badge>
|
||||
</>
|
||||
)} attributes={{
|
||||
badge: true
|
||||
}}>
|
||||
|
||||
```ts
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
// in an async function, or you can use promises
|
||||
async () => {
|
||||
// ...
|
||||
const productService = await initializeProductModule()
|
||||
const products = await productService.list()
|
||||
|
||||
console.log(products.length)
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
@@ -164,6 +196,33 @@ const Products = () => {
|
||||
export default Products
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="module" label={(
|
||||
<>
|
||||
@medusajs/product
|
||||
<Badge variant="orange-dark">beta</Badge>
|
||||
</>
|
||||
)} attributes={{
|
||||
badge: true
|
||||
}}>
|
||||
|
||||
```ts
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
// in an async function, or you can use promises
|
||||
async () => {
|
||||
// ...
|
||||
const productService = await initializeProductModule()
|
||||
const products = await productService.list({
|
||||
category_ids: ["cat_123"],
|
||||
})
|
||||
|
||||
console.log(products)
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
@@ -235,6 +294,33 @@ const Products = () => {
|
||||
export default Products
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="module" label={(
|
||||
<>
|
||||
@medusajs/product
|
||||
<Badge variant="orange-dark">beta</Badge>
|
||||
</>
|
||||
)} attributes={{
|
||||
badge: true
|
||||
}}>
|
||||
|
||||
```ts
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
// in an async function, or you can use promises
|
||||
async () => {
|
||||
// ...
|
||||
const productService = await initializeProductModule()
|
||||
const products = await productService.list({}, {
|
||||
relations: ["categories"],
|
||||
})
|
||||
|
||||
console.log(products)
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
@@ -581,6 +667,33 @@ const Products = () => {
|
||||
export default Products
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="module" label={(
|
||||
<>
|
||||
@medusajs/product
|
||||
<Badge variant="orange-dark">beta</Badge>
|
||||
</>
|
||||
)} attributes={{
|
||||
badge: true
|
||||
}}>
|
||||
|
||||
```ts
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
// in an async function, or you can use promises
|
||||
async () => {
|
||||
// ...
|
||||
const productService = await initializeProductModule()
|
||||
const products = await productService.list({
|
||||
id: productId,
|
||||
})
|
||||
|
||||
console.log(products[0])
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
@@ -658,6 +771,33 @@ const Products = () => {
|
||||
export default Products
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="module" label={(
|
||||
<>
|
||||
@medusajs/product
|
||||
<Badge variant="orange-dark">beta</Badge>
|
||||
</>
|
||||
)} attributes={{
|
||||
badge: true
|
||||
}}>
|
||||
|
||||
```ts
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
// in an async function, or you can use promises
|
||||
async () => {
|
||||
// ...
|
||||
const productService = await initializeProductModule()
|
||||
const products = await productService.list({
|
||||
handle,
|
||||
})
|
||||
|
||||
console.log(products[0])
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
|
||||
@@ -43,6 +43,12 @@ This guide also includes code snippets to send requests to your Medusa backend u
|
||||
|
||||
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.md) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.md#usage).
|
||||
|
||||
### @medusajs/product Module
|
||||
|
||||
This guide also includes code snippets to utilize the `@medusajs/product` module in your storefront, among other methods.
|
||||
|
||||
If you follow the `@medusajs/product` code blocks, it's assumed you already have the [@medusajs/product](../serverless-module.md) installed.
|
||||
|
||||
---
|
||||
|
||||
## List Categories
|
||||
@@ -94,6 +100,29 @@ function Categories() {
|
||||
export default Categories
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="module" label={(
|
||||
<>
|
||||
@medusajs/product
|
||||
<Badge variant="orange-dark">beta</Badge>
|
||||
</>
|
||||
)}>
|
||||
|
||||
```ts
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
// in an async function, or you can use promises
|
||||
async () => {
|
||||
// ...
|
||||
const productService = await initializeProductModule()
|
||||
const categories = await productService.listCategories()
|
||||
|
||||
console.log(categories)
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
@@ -162,6 +191,31 @@ function Category() {
|
||||
export default Category
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="module" label={(
|
||||
<>
|
||||
@medusajs/product
|
||||
<Badge variant="orange-dark">beta</Badge>
|
||||
</>
|
||||
)}>
|
||||
|
||||
```ts
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
// in an async function, or you can use promises
|
||||
async () => {
|
||||
// ...
|
||||
const productService = await initializeProductModule()
|
||||
const categories = await productService.listCategories({
|
||||
id: productCategoryId,
|
||||
})
|
||||
|
||||
console.log(categories[0])
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
@@ -252,6 +306,31 @@ function Categories() {
|
||||
export default Categories
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="module" label={(
|
||||
<>
|
||||
@medusajs/product
|
||||
<Badge variant="orange-dark">beta</Badge>
|
||||
</>
|
||||
)}>
|
||||
|
||||
```ts
|
||||
import {
|
||||
initialize as initializeProductModule,
|
||||
} from "@medusajs/product"
|
||||
|
||||
// in an async function, or you can use promises
|
||||
async () => {
|
||||
// ...
|
||||
const productService = await initializeProductModule()
|
||||
const categories = await productService.listCategories({
|
||||
handle,
|
||||
})
|
||||
|
||||
console.log(categories[0])
|
||||
}
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="fetch" label="Fetch API">
|
||||
|
||||
|
||||
@@ -332,5 +332,4 @@ Restart the Gatsby storefront then open a product that you added Rich Text conte
|
||||
|
||||
## See Also
|
||||
|
||||
- Deploy your Medusa backend to [Heroku](../../../deployments/server/deploying-on-heroku.mdx), [Qovery](../../../deployments/server/deploying-on-qovery.md), or [DigitalOcean](../../../deployments/server/deploying-on-digital-ocean.md).
|
||||
- [How to deploy your Gatsby storefront to Netlify](../../../deployments/storefront/deploying-gatsby-on-netlify.md).
|
||||
- How to deploy your Medusa backend to [Heroku](../../../deployments/server/deploying-on-heroku.mdx), or [DigitalOcean](../../../deployments/server/deploying-on-digital-ocean.md), or [other providers](../../../deployments/server/index.mdx)
|
||||
@@ -294,5 +294,4 @@ Learn [How to customize your Contentful backend and storefront](./customize-cont
|
||||
|
||||
## See Also
|
||||
|
||||
- How to deploy your Medusa backend to [Heroku](../../../deployments/server/deploying-on-heroku.mdx), [Qovery](../../../deployments/server/deploying-on-qovery.md), or [DigitalOcean](../../../deployments/server/deploying-on-digital-ocean.md).
|
||||
- [How to deploy your Gatsby storefront to Netlify](../../../deployments/storefront/deploying-gatsby-on-netlify.md).
|
||||
- How to deploy your Medusa backend to [Heroku](../../../deployments/server/deploying-on-heroku.mdx), or [DigitalOcean](../../../deployments/server/deploying-on-digital-ocean.md), or [other providers](../../../deployments/server/index.mdx)
|
||||
@@ -79,7 +79,7 @@ Other optional options include:
|
||||
|
||||
- `payment_description`: a string that is used as the default description of a payment if none is provided.
|
||||
- `capture`: a boolean value that indicates whether payment should be captured manually or automatically. By default, it will be `false`, leading admins to capture the payment manually.
|
||||
- `automatic_payment_methods`: enables Stripe's automatic payment methods. This is useful if you're integrating services like Apple pay or Google pay.
|
||||
- `automatic_payment_methods`: a boolean value that enables Stripe's automatic payment methods. This is useful if you're integrating services like Apple pay or Google pay.
|
||||
|
||||
### Retrieve Stripe's Keys
|
||||
|
||||
|
||||
99
docs/content/recipes/index.mdx
Normal file
99
docs/content/recipes/index.mdx
Normal file
@@ -0,0 +1,99 @@
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import DocCard from '@theme/DocCard';
|
||||
import Icons from '@theme/Icon';
|
||||
import Feedback from '@site/src/components/Feedback';
|
||||
import LearningPath from '@site/src/components/LearningPath';
|
||||
import LargeCard from '@site/src/components/LargeCard';
|
||||
import Button from '@site/src/components/Button';
|
||||
|
||||
# Medusa Recipes
|
||||
|
||||
This document provides you resources for different paths based on what you're building with Medusa.
|
||||
|
||||
:::note
|
||||
|
||||
These recipes assume you already have a Medusa backend setup. If not, you can create a Medusa project with the following command:
|
||||
|
||||
```bash
|
||||
npx create-medusa-app
|
||||
```
|
||||
|
||||
[Learn more in this guide](../create-medusa-app.mdx).
|
||||
|
||||
:::
|
||||
|
||||
## Recipe: Setup Ecommerce Store
|
||||
|
||||
Follow this recipe if you want to use Medusa for an ecommerce store. This recipe includes three steps that will get you a storefront deployed to Vercel and a backend deployed to Railway.
|
||||
|
||||
<LearningPath pathName="simple-quickstart" />
|
||||
|
||||
---
|
||||
|
||||
## Recipe: Build a Marketplace
|
||||
|
||||
Follow this guide if you want to build a Marketplace with Medusa.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/recipes/marketplace',
|
||||
label: 'Build a Marketplace',
|
||||
customProps: {
|
||||
icon: Icons['building-storefront'],
|
||||
description: 'Learn how you can build a marketplace with Medusa.'
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Recipe: Build Subscription Purchases
|
||||
|
||||
Follow this guide if you want to implement subscription-based purhcases with Medusa.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/recipes/subscriptions',
|
||||
label: 'Build Subscription Purchases',
|
||||
customProps: {
|
||||
icon: Icons['credit-card-solid'],
|
||||
description: 'Learn how you can implement subscription-based purchase in Medusa.'
|
||||
}
|
||||
}} />
|
||||
|
||||
<Feedback
|
||||
event="survey_use_cases"
|
||||
question="Did your find your use case?"
|
||||
positiveQuestion="Is there anything that should improved?"
|
||||
negativeQuestion="What was your use case?"
|
||||
/>
|
||||
|
||||
---
|
||||
|
||||
<!-- vale docs.HeadingPunctuation = NO -->
|
||||
|
||||
## Can't find your path?
|
||||
|
||||
<!-- vale docs.HeadingPunctuation = YES -->
|
||||
|
||||
Medusa is a customizable commerce solution that can be used to build any custom use case. If you can't find your use case mentioned above, the following guides give you a general understanding of how Medusa can be used and how you can customize it.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/overview',
|
||||
label: 'Commerce Modules',
|
||||
customProps: {
|
||||
icon: Icons['puzzle-solid'],
|
||||
description: "Learn about Medusa's commerce features and how to customize them."
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '#',
|
||||
label: 'Medusa Development',
|
||||
customProps: {
|
||||
icon: Icons['server-stack-solid'],
|
||||
description: "Learn how about Medusa's architecture and how to customize it."
|
||||
}
|
||||
},
|
||||
]} />
|
||||
400
docs/content/recipes/marketplace.mdx
Normal file
400
docs/content/recipes/marketplace.mdx
Normal file
@@ -0,0 +1,400 @@
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import DocCard from '@theme/DocCard';
|
||||
import Icons from '@theme/Icon';
|
||||
import LearningPath from '@site/src/components/LearningPath';
|
||||
|
||||
# Build a Marketplace
|
||||
|
||||
This document guides you through the different documentation resources that will help you build a marketplace with Medusa.
|
||||
|
||||
## Overview
|
||||
|
||||
A marketplace is an online commerce store that allows different vendors to sell their products within the same commerce system. Customers can purchase products from any of these vendors, and vendors can manage their orders separately.
|
||||
|
||||
<LearningPath pathName="marketplace" />
|
||||
|
||||
---
|
||||
|
||||
## Associate Entities with Stores
|
||||
|
||||
:::tip
|
||||
|
||||
Entities represent tables in the database.
|
||||
|
||||
:::
|
||||
|
||||
By default, entities like users, products, or orders aren't associated with a store, as it's assumed there's one store in Medusa. For a marketplace, each of these entities should be associated with their respective stores.
|
||||
|
||||
To associate these entities with the `Store` entity, you need to extend and customize entities created in the Medusa core package `@medusajs/medusa`, such as the `User` entity, to add a relation to the `Store` entity.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/entities/extend-entity',
|
||||
label: 'Extend an Entity',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to extend an entity in Medusa.',
|
||||
}
|
||||
}} />
|
||||
|
||||
<details>
|
||||
<summary>Example: Associate User with Store</summary>
|
||||
|
||||
For example, to associate the `User` entity with the `Store` entity, create the file `src/models/user.ts` with the following content:
|
||||
|
||||
```ts title=src/models/user.ts
|
||||
import {
|
||||
Column,
|
||||
Entity,
|
||||
Index,
|
||||
JoinColumn,
|
||||
ManyToOne,
|
||||
} from "typeorm"
|
||||
import {
|
||||
User as MedusaUser,
|
||||
} from "@medusajs/medusa"
|
||||
import { Store } from "./store"
|
||||
|
||||
@Entity()
|
||||
export class User extends MedusaUser {
|
||||
@Index("UserStoreId")
|
||||
@Column({ nullable: true })
|
||||
store_id?: string
|
||||
|
||||
@ManyToOne(() => Store, (store) => store.members)
|
||||
@JoinColumn({ name: "store_id", referencedColumnName: "id" })
|
||||
store?: Store
|
||||
}
|
||||
```
|
||||
|
||||
Then, you need to extend the `UserRepository` to point to your extended entity. To do that, create the file `src/repositories/user.ts` with the following content:
|
||||
|
||||
```ts title=src/repositories/user.ts
|
||||
import { User } from "../models/user"
|
||||
import {
|
||||
dataSource,
|
||||
} from "@medusajs/medusa/dist/loaders/database"
|
||||
import {
|
||||
UserRepository as MedusaUserRepository,
|
||||
} from "@medusajs/medusa/dist/repositories/user"
|
||||
|
||||
export const UserRepository = dataSource
|
||||
.getRepository(User)
|
||||
.extend({
|
||||
...Object.assign(
|
||||
MedusaUserRepository,
|
||||
{ target: User }
|
||||
),
|
||||
})
|
||||
|
||||
export default UserRepository
|
||||
```
|
||||
|
||||
Next, you need to create a migration that reflects the changes on the `User` entity in your database. To do that, run the following command to create a migration file:
|
||||
|
||||
```bash
|
||||
npx typeorm migration:create src/migrations/add-user-store-id
|
||||
```
|
||||
|
||||
This creates a file in the `src/migrations` directory of the format `<TIMESTAMP>_add-user-store-id.ts`. Replace the `up` and `down` methods in that file with the methods here:
|
||||
|
||||
```ts title=src/migrations/<TIMESTAMP>_add-user-store-id.ts
|
||||
// ...
|
||||
|
||||
export class AddUserStoreId1681287255173
|
||||
implements MigrationInterface {
|
||||
// ...
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "user" ADD "store_id" character varying`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`CREATE INDEX "UserStoreId" ON "user" ("store_id")`
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`DROP INDEX "public"."UserStoreId"`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "user" DROP COLUMN "store_id"`
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Finally, to reflect these changes and start using them, `build` your changes and run migrations with the following commands:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run build
|
||||
npx @medusajs/medusa migrations run
|
||||
```
|
||||
|
||||
You can extend other entities in a similar manner to associate them with a store.
|
||||
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Accessing Logged-in User
|
||||
|
||||
Throughout your development, you'll likely need access to the logged-in user. For example, you'll need to know which user is logged in to know which store to associate a new product with.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/endpoints/example-logged-in-user',
|
||||
label: 'Access Logged-in User',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to access the logged-in user throughout your project using a Middleware.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Customize Data Management Functionalities
|
||||
|
||||
After associating entities with stores, you'll need to customize how certain data management functionalities are implemented in the Medusa core package.
|
||||
|
||||
For example, when a new user is created, you need to ensure that it's associated either with a new store or with the store of the logged-in user. Another example is associating a new product with the logged-in user's store.
|
||||
|
||||
You can customize these functionalities by extending services. Services are classes that contain helper methods specific to an entity. For example, the `UserService` is used to manage functionalities related to the `User` entity, such as creating a user.
|
||||
|
||||
You can also extend services if you need to customize a functionality implemented in a service for other reasons.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/services/extend-service',
|
||||
label: 'Extend a Service',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to extend a service in Medusa',
|
||||
}
|
||||
}} />
|
||||
|
||||
<details>
|
||||
<summary>Example: Extend User Service</summary>
|
||||
|
||||
You can extend the user service to change how the `create` method is implemented.
|
||||
|
||||
To extend the user service, create the file `src/services/user.ts` with the following content:
|
||||
|
||||
<!-- eslint-disable prefer-rest-params -->
|
||||
|
||||
```ts
|
||||
import { Lifetime } from "awilix"
|
||||
import {
|
||||
UserService as MedusaUserService,
|
||||
} from "@medusajs/medusa"
|
||||
import { User } from "../models/user"
|
||||
import {
|
||||
CreateUserInput as MedusaCreateUserInput,
|
||||
} from "@medusajs/medusa/dist/types/user"
|
||||
import StoreRepository from "../repositories/store"
|
||||
|
||||
type CreateUserInput = {
|
||||
store_id?: string
|
||||
} & MedusaCreateUserInput
|
||||
|
||||
class UserService extends MedusaUserService {
|
||||
static LIFE_TIME = Lifetime.SCOPED
|
||||
protected readonly loggedInUser_: User | null
|
||||
protected readonly storeRepository_: typeof StoreRepository
|
||||
|
||||
constructor(container, options) {
|
||||
super(...arguments)
|
||||
this.storeRepository_ = container.storeRepository
|
||||
|
||||
try {
|
||||
this.loggedInUser_ = container.loggedInUser
|
||||
} catch (e) {
|
||||
// avoid errors when backend first runs
|
||||
}
|
||||
}
|
||||
|
||||
async create(
|
||||
user: CreateUserInput,
|
||||
password: string
|
||||
): Promise<User> {
|
||||
if (!user.store_id) {
|
||||
const storeRepo = this.manager_.withRepository(
|
||||
this.storeRepository_
|
||||
)
|
||||
let newStore = storeRepo.create()
|
||||
newStore = await storeRepo.save(newStore)
|
||||
user.store_id = newStore.id
|
||||
}
|
||||
|
||||
return await super.create(user, password)
|
||||
}
|
||||
}
|
||||
|
||||
export default UserService
|
||||
```
|
||||
|
||||
In the `create` method of this extended service, you create a new store if the user being created doesn't have a store associated with it.
|
||||
|
||||
You can then test out your customization by running the `build` command and starting the backend:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx @medusajs/medusa develop
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Listening to Events
|
||||
|
||||
While implementing your marketplace, you'll typically need to listen to certain events then perform actions asynchronously. For example, you can listen to the `order.placed` event and, when triggered, create child orders of the order, separating ordered items by their associated store.
|
||||
|
||||
To listen to events, you need to create Subscribers that subscribe a handler method to an event. In that handler method, you can implement the desired functionality.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/development/events/create-subscriber',
|
||||
label: 'Create a Subscriber',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a subscriber in Medusa.',
|
||||
}
|
||||
}} />
|
||||
|
||||
<details>
|
||||
<summary>Example: Listen to Order Created Event</summary>
|
||||
|
||||
To listen to the `order.placed` event, create the file `src/subscribers/orderNotifier.ts` with the following content:
|
||||
|
||||
```ts
|
||||
class OrderNotifierSubscriber {
|
||||
constructor({ eventBusService }) {
|
||||
eventBusService.subscribe("order.placed", this.handleOrder)
|
||||
}
|
||||
|
||||
handleOrder = async (data) => {
|
||||
// TODO perform functionality
|
||||
}
|
||||
}
|
||||
|
||||
export default OrderNotifierSubscriber
|
||||
```
|
||||
|
||||
This subscribes the `handleOrder` method to be executed whenever the `order.placed` event is emitted.
|
||||
|
||||
You can then test out your subscriber by running the `build` command and starting the backend:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx @medusajs/medusa develop
|
||||
```
|
||||
</details>
|
||||
|
||||
---
|
||||
|
||||
## Add Payment and Fulfillment Providers
|
||||
|
||||
Payment and fulfillment providers can be added through plugins or directly in your project. You can either create your own provider, use one of Medusa's official plugins, or use community plugins.
|
||||
|
||||
:::note
|
||||
|
||||
Payment and fulfillment providers are associated with regions, which are not associated with a store, by default. If you want to allow each store to specify its own payment and fulfillment providers, you'll need to [associate the region with a store](#associate-entities-with-stores).
|
||||
|
||||
:::
|
||||
|
||||
### Option 1: Create your own providers
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-payment-provider',
|
||||
label: 'Create a Payment Processor',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a payment processor.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-fulfillment-provider',
|
||||
label: 'Create a Fulfillment Provider',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a fulfillment provider.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
### Option 2: Install a Plugin
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/plugins/overview',
|
||||
label: 'Install an Official Medusa Plugin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out available Medusa plugins to install.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://medusajs.com/plugins/',
|
||||
label: 'Install a Community Plugin',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Check out available community plugins to install.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Build a Storefront
|
||||
|
||||
Medusa provides a Next.js starter storefront that you can use with Medusa. Since you've customized your Medusa project, you'll need to either customize the existing Next.js storefront, or create a custom storefront.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/starters/nextjs-medusa-starter',
|
||||
label: 'Option 1: Use Next.js Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Install the Next.js Storefront to customize it.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/storefront/roadmap',
|
||||
label: 'Option 2: Build Custom Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Find useful resources to build your own storefront.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Deploy Marketplace
|
||||
|
||||
Our documentation includes deployment guides for a basic Medusa backend. You should be able to follow it to deploy your customized marketplace, as well.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/deployments/server',
|
||||
label: 'Deploy Backend',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to deploy your marketplace backend to different hosting providers.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Additional Development
|
||||
|
||||
You can find other resources for your marketplace development in the [Medusa Development section](../development/overview.mdx) of this documentation.
|
||||
161
docs/content/recipes/subscriptions.mdx
Normal file
161
docs/content/recipes/subscriptions.mdx
Normal file
@@ -0,0 +1,161 @@
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import DocCard from '@theme/DocCard';
|
||||
import Icons from '@theme/Icon';
|
||||
import LearningPath from '@site/src/components/LearningPath';
|
||||
|
||||
# Build Subscription-based Purchases
|
||||
|
||||
This document guides you through the different documentation resources that will help you build subscription-based purchasing in Medusa.
|
||||
|
||||
## Overview
|
||||
|
||||
Subscription-based purchase allows customers to purchase products for a specified period, and the payment and fulfillment is processed within a regular interval in that period.
|
||||
|
||||
For example, a customer can purchase a book subscription box for a period of three months. Each month, the payment will be captured for that order and, if the payment is successful, the fulfillment will be processed.
|
||||
|
||||
<LearningPath pathName="subscriptions" />
|
||||
|
||||
---
|
||||
|
||||
## Save Subscription Details in the Database
|
||||
|
||||
Subscriptions have details related to the subscription interval, subscription period, and more.
|
||||
|
||||
Based on the approach you choose to implement the subscription logic (which is discussed in the next section), you might need to store different data in your backend.
|
||||
|
||||
If you want to store the subscription details in a new table in the database, you can do that by creating an entity. If you want to extend an existing entity in Medusa's core, such as the `Order` entity, to add details related to the subscription, you can extend an entity.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/entities/create',
|
||||
label: "Create an Entity",
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create an entity in Medusa.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/entities/extend-entity',
|
||||
label: 'Extend an Entity',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to extend an entity in Medusa.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Decide on Subscription Approach
|
||||
|
||||
There are different ways to implement subscriptions in your Medusa backend. This document discusses two options: using Stripe subscriptions, or implementing subscriptions logic within the backend, independent of a specific payment provider.
|
||||
|
||||
### Option 1: Using Stripe Subscriptions
|
||||
|
||||
Stripe provides a [subscription payments](https://stripe.com/docs/billing/subscriptions/overview) that allows you to authorize payment on a subscription basis within Stripe. Stripe then handles checking for recurring payments and capturing payment at the specified interval.
|
||||
|
||||
This approach allows you to deligate the complications of implementing the subscription logic to Stripe, but does not support using other payment providers.
|
||||
|
||||
Medusa provides a Stripe plugin, however, it doesn't handle subscriptions. You can either use that plugin to add the subscription feature on top of it, or create a custom Stripe Subscription payment provider.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: 'https://github.com/medusajs/medusa/tree/develop/packages/medusa-payment-stripe',
|
||||
label: "Use Medusa's Stripe Plugin",
|
||||
customProps: {
|
||||
icon: Icons['github'],
|
||||
description: "Check out Medusa's stripe plugin to build subscription on top of it.",
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/modules/carts-and-checkout/backend/add-payment-provider',
|
||||
label: 'Create Payment Processor',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Create a Stripe Subscription payment processor from scratch.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
### Option 2: Implement Subscription Logic
|
||||
|
||||
By implementing the subscription logic within your backend, you can have full control over the subscription logic. You'll also be independent of payment providers, allowing you to provide customers with more than payment provider option.
|
||||
|
||||
Implementing the logic depends on your use case, but you'll mainly need to do two things:
|
||||
|
||||
1. Perform an action when an order is placed, such as saving subscription details. This can be done using subscribers, which register handler methods to be triggered when an event is emitted. When an order is placed, the `order.placed` event is emitted.
|
||||
2. Check daily for subscriptions that need renewal. This can be done using a scheduled job, which is a cron job that can be executed on a defined interval. Within that job, you can define your renewal logic.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/events/create-subscriber',
|
||||
label: 'Create a Subscriber',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a subscriber in Medusa.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/development/scheduled-jobs/create',
|
||||
label: 'Create a Scheduled Job',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to create a scheduled job in Medusa.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Build a Storefront
|
||||
|
||||
Medusa provides a Next.js starter storefront that you can use with Medusa. Since you've customized your Medusa project, you'll need to either customize the existing Next.js storefront, or create a custom storefront.
|
||||
|
||||
<DocCardList colSize={6} items={[
|
||||
{
|
||||
type: 'link',
|
||||
href: '/starters/nextjs-medusa-starter',
|
||||
label: 'Option 1: Use Next.js Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Install the Next.js Storefront to customize it.',
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
href: '/storefront/roadmap',
|
||||
label: 'Option 2: Build Custom Storefront',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Find useful resources to build your own storefront.',
|
||||
}
|
||||
},
|
||||
]} />
|
||||
|
||||
---
|
||||
|
||||
## Deploy Backend
|
||||
|
||||
Our documentation includes deployment guides for a basic Medusa backend. You should be able to follow it to deploy your customized backend, as well.
|
||||
|
||||
<DocCard item={{
|
||||
type: 'link',
|
||||
href: '/deployments/server',
|
||||
label: 'Deploy Backend',
|
||||
customProps: {
|
||||
icon: Icons['academic-cap-solid'],
|
||||
description: 'Learn how to deploy your subscription-based backend to different hosting providers.',
|
||||
}
|
||||
}} />
|
||||
|
||||
---
|
||||
|
||||
## Additional Development
|
||||
|
||||
You can find other resources for your development in the [Medusa Development section](../development/overview.mdx) of this documentation.
|
||||
@@ -30,12 +30,13 @@ This document guides you to install and set up the Next.js Starter Storefront.
|
||||
|
||||

|
||||
|
||||
## Instant Deployment to Netlify
|
||||
## Instant Deployment to Vercel
|
||||
|
||||
Instead of manually following this guide to install then later deploy the Next.js Storefront, you can deploy the Next.js Storefront to Netlify with this button:
|
||||
Instead of manually following this guide to install then later deploy the Next.js Storefront, you can deploy the Next.js Storefront to Vercel with this button:
|
||||
|
||||
<a href="https://app.netlify.com/start/deploy?repository=https://github.com/medusajs/nextjs-starter-medusa" className="img-url">
|
||||
<img src="https://www.netlify.com/img/deploy/button.svg" alt="Deploy to Netlify" className="no-zoom-img" />
|
||||
<a
|
||||
href="https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fmedusajs%2Fnextjs-starter-medusa.git&env=NEXT_PUBLIC_MEDUSA_BACKEND_URL&envDescription=URL%20of%20your%20Medusa%20Backend" class="img-url no-zoom-img">
|
||||
<img src="https://vercel.com/button" alt="Deploy with Vercel" class="no-zoom-img"/>
|
||||
</a>
|
||||
|
||||
---
|
||||
|
||||
@@ -20,13 +20,19 @@ npm run build
|
||||
npx @medusajs/medusa-cli migrations run
|
||||
```
|
||||
|
||||
4\. Optionally seed the database:
|
||||
4\. Create an admin user:
|
||||
|
||||
```bash
|
||||
npx @medusajs/medusa-cli user -e user@test.com -p supersecret
|
||||
```
|
||||
|
||||
5\. Optionally seed the database:
|
||||
|
||||
```bash
|
||||
npx @medusajs/medusa-cli seed -f ./data/seed.json
|
||||
```
|
||||
|
||||
5\. Start project:
|
||||
6\. Start project:
|
||||
|
||||
```bash
|
||||
npx @medusajs/medusa-cli develop
|
||||
|
||||
@@ -4,7 +4,7 @@ description: 'Upgrade guides on how to update the Medusa backend along with othe
|
||||
---
|
||||
|
||||
import DocCard from '@theme/DocCard';
|
||||
import getFirstCategoryItem from '@site/src/utils/getFirstCategoryItem';
|
||||
import getFirstCategoryItem from '@site/src/utils/get-first-category-item';
|
||||
|
||||
# Upgrade Guides
|
||||
|
||||
|
||||
@@ -30,3 +30,4 @@ It should be noted that the following are not explained within this section of t
|
||||
|
||||
- [Manage Inventory](./inventory.mdx)
|
||||
- [Manage Locations](./locations.mdx)
|
||||
- [Manage Reservations](./reservations.mdx)
|
||||
|
||||
99
docs/content/user-guide/multiwarehouse/reservations.mdx
Normal file
99
docs/content/user-guide/multiwarehouse/reservations.mdx
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
description: "This user guide explains how to manage reservations in your store. Learn how to view, create, edit, and delete reservations."
|
||||
addHowToData: true
|
||||
---
|
||||
|
||||
import UiIcon from '@site/src/components/UiIcon';
|
||||
|
||||
# Manage Reservations
|
||||
|
||||
In this document, you’ll learn how to manage reservations in your store.
|
||||
|
||||
## View Reservations
|
||||
|
||||
To view reservations, go to Inventory from the sidebar, and click on the Reservations header.
|
||||
|
||||
In the reservations page, you can view all reservations, either created by an order or created manually.
|
||||
|
||||
### Filter by Location
|
||||
|
||||
To filter reservations by location:
|
||||
|
||||
1. Click on the “All locations” button.
|
||||
2. Choose the location you want to filter reservations by.
|
||||
|
||||
### Other Filters
|
||||
|
||||
You can also filter by description, creation date, reserved quantity, and more.
|
||||
|
||||
To do that:
|
||||
|
||||
1. Click on the “View” button.
|
||||
2. Apply any filters relevant for you.
|
||||
3. Click on the “Apply” button.
|
||||
|
||||
To reset applied filters:
|
||||
|
||||
1. Click on the “View” button.
|
||||
2. Toggle off applied filters.
|
||||
3. Click on the “Apply” button.
|
||||
|
||||
---
|
||||
|
||||
## Create a Reservation
|
||||
|
||||
Reservations are created manually when an order is created, and you can also manage them from the order’s page.
|
||||
|
||||
You can also manually create a reservation from the Reservations page. To create a reservation:
|
||||
|
||||
1. Go to Inventory → Reservations.
|
||||
2. Click on the “Create reservation” button.
|
||||
3. In the form that opens:
|
||||
1. For the “Location” field, select the location the reservation is created in.
|
||||
2. For the “Item to reserve” field, enter the SKU of the item you want to create a reservation for.
|
||||
3. Select the item from the results that appear. Once you do that, a table shows. In the table:
|
||||
1. Next to the “Reserve” row, specify the reservation quantity.
|
||||
2. If you want to remove the selected item and choose a different one, click on the “Remove item” button.
|
||||
4. You can optionally enter a Description of the reservation.
|
||||
5. You can optionally enter key-value metadata fields if you have any custom data you want to attach to the reservation. To add or manage the metadata fields:
|
||||
1. Hover over the available row in the table.
|
||||
2. Click on the <UiIcon lightIcon="https://res.cloudinary.com/dza7lstvk/image/upload/v1667999308/Medusa%20Docs/UI%20Icons/1ordBC6_ssysel.png" darkIcon="https://res.cloudinary.com/dza7lstvk/image/upload/v1667999326/Medusa%20Docs/UI%20Icons/dSwWYBH_stzgoi.png" alt="three dots" /> icon.
|
||||
3. Choose the actions in the dropdown to manage the metadata fields.
|
||||
4. Once you’re done, click the “Save reservation” button.
|
||||
|
||||
---
|
||||
|
||||
## Edit Reservation
|
||||
|
||||
To edit a reservation:
|
||||
|
||||
1. Go to Inventory → Reservations
|
||||
2. Find the reservation you want to edit, and click on the <UiIcon lightIcon="https://res.cloudinary.com/dza7lstvk/image/upload/v1667999308/Medusa%20Docs/UI%20Icons/1ordBC6_ssysel.png" darkIcon="https://res.cloudinary.com/dza7lstvk/image/upload/v1667999326/Medusa%20Docs/UI%20Icons/dSwWYBH_stzgoi.png" alt="three dots" /> icon on its right.
|
||||
3. Click on “Edit” from the dropdown.
|
||||
4. In the side window that opens:
|
||||
1. You can change the location of the reservation using the Location field.
|
||||
2. In the table, you can change the reserved quantity by changing the value of the Allocate row.
|
||||
3. You can change the description of the reservation using the Description field.
|
||||
4. You can manage the metadata of the reservation:
|
||||
1. If there aren’t any metadata fields, you can add a metadata field using the “Add metadata” button.
|
||||
2. You can add more metadata fields or manage available ones by hovering over a row, clicking the <UiIcon lightIcon="https://res.cloudinary.com/dza7lstvk/image/upload/v1667999308/Medusa%20Docs/UI%20Icons/1ordBC6_ssysel.png" darkIcon="https://res.cloudinary.com/dza7lstvk/image/upload/v1667999326/Medusa%20Docs/UI%20Icons/dSwWYBH_stzgoi.png" alt="three dots" /> icon, and choosing an action from the dropdown.
|
||||
3. You can remove metadata fields by clicking the “Remove metadata” button.
|
||||
5. Once you’re done, click the “Save and close” button.
|
||||
|
||||
---
|
||||
|
||||
## Delete Reservation
|
||||
|
||||
:::warning
|
||||
|
||||
Deleting a reservation can’t be undone, and the reservation data can’t be restored.
|
||||
|
||||
:::
|
||||
|
||||
To delete a reservation:
|
||||
|
||||
1. Go to Inventory → Reservations
|
||||
2. Find the reservation you want to edit, and click on the <UiIcon lightIcon="https://res.cloudinary.com/dza7lstvk/image/upload/v1667999308/Medusa%20Docs/UI%20Icons/1ordBC6_ssysel.png" darkIcon="https://res.cloudinary.com/dza7lstvk/image/upload/v1667999326/Medusa%20Docs/UI%20Icons/dSwWYBH_stzgoi.png" alt="three dots" /> icon on its right.
|
||||
3. Click on “Delete” from the dropdown.
|
||||
4. Confirm deleting the reservation by clicking the “Yes, remove" button in the pop-up.
|
||||
Reference in New Issue
Block a user