chore(docs): added eslint to lint documentation code blocks (#2920)

* docs: added rule for code length

* chore: fixes based on vale errors

* changed to use eslint

* fixes using eslint

* added github action for documentation eslint

* changed allowed max-length

* fixed incorrect heading level

* removed comment
This commit is contained in:
Shahed Nasser
2022-12-30 18:44:46 +02:00
committed by GitHub
parent 99add15fc3
commit d1b4b11ff6
67 changed files with 2611 additions and 1735 deletions
+32 -23
View File
@@ -97,7 +97,7 @@ Finally, in `medusa-config.js` add the following item into the `plugins` arr
```jsx title=medusa-config.js
const plugins = [
//...
// ...
{
resolve: `medusa-plugin-algolia`,
options: {
@@ -123,7 +123,7 @@ const plugins = [
},
},
},
];
]
```
The `searchableAttributes` are the attributes in a product that are searchable, and `attributesToRetrieve` are the attributes to retrieve for each product result. Youre free to make changes to these attributes as you see fit, but these are the recommended attributes.
@@ -207,7 +207,7 @@ Finally, change the code in `src/lib/search-client.ts` to the following:
```jsx title=src/lib/search-client.ts
import algoliasearch from "algoliasearch/lite"
const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || "" // You should add this to your environment variables
const appId = process.env.NEXT_PUBLIC_SEARCH_APP_ID || ""
const apiKey = process.env.NEXT_PUBLIC_SEARCH_API_KEY || "test_key"
@@ -227,9 +227,7 @@ To make sure the Next.js storefront properly displays the products in the search
![Search pop up in the Next.js storefront](https://res.cloudinary.com/dza7lstvk/image/upload/v1668000082/Medusa%20Docs/Algolia/1f9qqK6_c0z8zi.png)
---
## Add to Gatsby and React-Based Storefronts
### Add to Gatsby and React-Based Storefronts
This section covers adding the search UI to React-based storefronts. It uses the Gatsby storefront as an example, but you can use the same steps on any React-based framework.
@@ -269,11 +267,11 @@ import {
Hits,
InstantSearch,
SearchBox,
connectStateResults
connectStateResults,
} from "react-instantsearch-dom"
import React from "react"
import algoliasearch from 'algoliasearch/lite';
import algoliasearch from "algoliasearch/lite"
const searchClient = algoliasearch(
process.env.GATSBY_ALGOLIA_APP_ID,
@@ -281,19 +279,28 @@ const searchClient = algoliasearch(
)
const Search = () => {
const Results = connectStateResults(({ searchState, searchResults, children }) =>
searchState && searchState.query && searchResults && searchResults.nbHits !== 0 ? (
<div className="absolute top-full w-full p-2 bg-gray-200 shadow-md">
{children}
</div>
) : (
<div></div>
)
);
const Results = connectStateResults(
({ searchState, searchResults, children }) => {
return (
searchState && searchState.query &&
searchResults && searchResults.nbHits !== 0 ?
(
<div
className="absolute top-full w-full p-2 bg-gray-200 shadow-md">
{children}
</div>
) : (
<div></div>
)
)
}
)
return (
<div className="relative">
<InstantSearch indexName={process.env.GATSBY_SEARCH_INDEX_NAME} searchClient={searchClient}>
<InstantSearch
indexName={process.env.GATSBY_SEARCH_INDEX_NAME}
searchClient={searchClient}>
<SearchBox submit={null} reset={null} />
<Results>
<Hits hitComponent={Hit} />
@@ -313,7 +320,7 @@ const Hit = ({ hit }) => {
)
}
export default Search;
export default Search
```
This file uses the dependencies you installed to show the search results. It also initializes Algolia using the environment variables you added.
@@ -333,10 +340,12 @@ import Search from "./search"
And add the `Search` component in the returned JSX before `RegionPopover`:
```jsx title=src/components/header/index.jsx
//...
<Search />
<RegionPopover regions={mockData.regions} />
//...
// ...
<div className="...">
<Search />
<RegionPopover regions={mockData.regions} />
</div>
// ...
```
If you run your Gatsby storefront while the Medusa server is running, you should find a search bar in the header of the page. Try entering a query to search through the products in your store.
@@ -29,32 +29,32 @@ Heres an example of a migration created in a new file `contentful-migrations/
```jsx title=contentful-migrations/rich-text.js
#! /usr/bin/env node
require("dotenv").config();
require("dotenv").config()
const { runMigration } = require("contentful-migration");
const { runMigration } = require("contentful-migration")
const options = {
spaceId: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
environment: process.env.CONTENTFUL_ENVIRONMENT,
yes: true,
};
}
const migration = async () => {
await runMigration({
...options,
migrationFunction: function (migration, context) {
//create Rich Text content model
// create Rich Text content model
const richText = migration
.createContentType("richText")
.name("Rich Text")
.displayField("title");
.displayField("title")
richText.createField("title").name("Title (Internal)").type("Symbol");
richText.createField("body").name("Body").type("RichText");
richText.createField("title").name("Title (Internal)").type("Symbol")
richText.createField("body").name("Body").type("RichText")
//edit Page content model
// edit Page content model
const page = migration.editContentType("page")
page.editField("contentModules").items({
@@ -67,7 +67,7 @@ const migration = async () => {
],
})
//edit Product content model
// edit Product content model
const product = migration.editContentType("product")
product
@@ -83,11 +83,11 @@ const migration = async () => {
},
],
})
}
});
},
})
}
migration();
migration()
```
This example creates a new content model Rich Text that has two fields: title and body. It also edits the Page content model to allow using Rich Text content models on the page.
@@ -97,7 +97,19 @@ In addition, it edits the Product content model by adding a new field `contentMo
You can also add other types of content models the `contentModules` should accept. For example, to accept `tileSection` add it to the `linkContentType` option:
```jsx
linkContentType: ["tileSection", "richText"],
product
.createField("contentModules")
.name("Content Modules")
.type("Array")
.items({
type: "Link",
linkType: "Entry",
validations: [
{
linkContentType: ["richText", "tileSection"],
},
],
})
```
### Run a Contentful Migration
@@ -165,10 +177,10 @@ import { renderRichText } from "gatsby-source-contentful/rich-text"
const RichText = ({ data }) => {
return (
<div style={{
maxWidth: '870px',
margin: '0 auto',
paddingTop: '20px',
paddingBottom: '20px'
maxWidth: "870px",
margin: "0 auto",
paddingTop: "20px",
paddingBottom: "20px",
}}>
{data.body ? renderRichText(data.body) : ""}
</div>
@@ -194,7 +206,7 @@ Then, in the returned JSX add a new case to the switch statement:
```jsx title=src/pages/{ContentfulPage.slug}.js
switch (cm.internal.type) {
//...
// ...
case "ContentfulRichText":
return <RichText key={cm.id} data={cm} />
default:
+3 -3
View File
@@ -123,14 +123,14 @@ Then, in `medusa-config.js` in the exported object, comment out or remove the SQ
```jsx title=medusa-config.js
module.exports = {
projectConfig: {
//...
// ...
database_url: DATABASE_URL,
database_type: "postgres",
//REMOVE OR COMMENT OUT THE BELOW:
// REMOVE OR COMMENT OUT THE BELOW:
// database_database: "./medusa-db.sql",
// database_type: "sqlite",
},
};
}
```
### Migrate Content Types to Contentful
+7 -7
View File
@@ -55,22 +55,22 @@ Finally, in `medusa-config.js`, add the Klarna plugin to the `plugins` array wit
```jsx title=medusa-config.js
const plugins = [
//other plugins...
// other plugins...
{
resolve: `medusa-payment-klarnal`,
options: {
backend_url: process.env.KLARNA_BACKEND_URL
backend_url: process.env.KLARNA_BACKEND_URL,
url: process.env.KLARNA_URL,
user: process.env.KLARNA_USER,
password: process.env.KLARNA_PASSWORD,
merchant_urls: {
terms: process.env.KLARNA_TERMS_URL,
checkout: process.env.KLARNA_CHECKOUT_URL,
confirmation: process.env.KLARNA_CONFIRMATION_URL
}
}
}
];
confirmation: process.env.KLARNA_CONFIRMATION_URL,
},
},
},
]
```
---
+16 -14
View File
@@ -59,15 +59,15 @@ Open `medusa-config.js` and add the new plugin into the `plugins` array:
```js title=medusa-config.js
const plugins = [
...,
// ...,
{
resolve: `medusa-plugin-mailchimp`,
options: {
api_key: process.env.MAILCHIMP_API_KEY,
newsletter_list_id: process.env.MAILCHIMP_NEWSLETTER_LIST_ID
}
}
];
newsletter_list_id: process.env.MAILCHIMP_NEWSLETTER_LIST_ID,
},
},
]
```
---
@@ -147,35 +147,37 @@ npm install axios
Then, in the component you want to add the subscription form add the following code:
```jsx
import axios from 'axios'
import { useState } from "react";
import axios from "axios"
import { useState } from "react"
export default function NewsletterForm() {
const [email, setEmail] = useState("")
function subscribe(e) {
e.preventDefault();
e.preventDefault()
if (!email) {
return;
return
}
axios.post('http://localhost:9000/mailchimp/subscribe', {
email
axios.post("http://localhost:9000/mailchimp/subscribe", {
email,
})
.then((e) => {
alert("Subscribed sucessfully!")
setEmail("")
})
.catch((e) => {
console.error(e);
alert("An error occurred");
console.error(e)
alert("An error occurred")
})
}
return (
<form onSubmit={subscribe}>
<h2>Sign Up for our newsletter</h2>
<input type="email" name="email" id="email" placeholder="example@gmail.com"
<input
type="email" name="email" id="email"
placeholder="example@gmail.com"
value={email} onChange={(e) => setEmail(e.target.value)} />
<button type="submit">Subscribe</button>
</form>
+38 -20
View File
@@ -57,11 +57,12 @@ Finally, in `medusa-config.js` add the following item into the `plugins` array:
```jsx title=medusa-config.js
const plugins = [
//...
// ...
{
resolve: `medusa-plugin-meilisearch`,
options: {
// config object passed when creating an instance of the MeiliSearch client
// config object passed when creating an instance
// of the MeiliSearch client
config: {
host: process.env.MEILISEARCH_HOST,
apiKey: process.env.MEILISEARCH_API_KEY,
@@ -71,12 +72,18 @@ const plugins = [
products: {
// MeiliSearch's setting options to be set on a particular index
searchableAttributes: ["title", "description", "variant_sku"],
displayedAttributes: ["title", "description", "variant_sku", "thumbnail", "handle"],
displayedAttributes: [
"title",
"description",
"variant_sku",
"thumbnail",
"handle",
],
},
},
},
},
];
]
```
You can change the `searchableAttributes` and `displayedAttributes` as you see fit. However, the attributes included are the recommended attributes.
@@ -220,7 +227,7 @@ import {
Hits,
InstantSearch,
SearchBox,
connectStateResults
connectStateResults,
} from "react-instantsearch-dom"
import React from "react"
@@ -232,19 +239,28 @@ const searchClient = instantMeiliSearch(
)
const Search = () => {
const Results = connectStateResults(({ searchState, searchResults, children }) =>
searchState && searchState.query && searchResults && searchResults.nbHits !== 0 ? (
<div className="absolute top-full w-full p-2 bg-gray-200 shadow-md">
{children}
</div>
) : (
<div></div>
)
);
const Results = connectStateResults(
({ searchState, searchResults, children }) => {
return (
searchState && searchState.query &&
searchResults && searchResults.nbHits !== 0 ?
(
<div
className="absolute top-full w-full p-2 bg-gray-200 shadow-md">
{children}
</div>
) : (
<div></div>
)
)
}
)
return (
<div className="relative">
<InstantSearch indexName={process.env.GATSBY_SEARCH_INDEX_NAME} searchClient={searchClient}>
<InstantSearch
indexName={process.env.GATSBY_SEARCH_INDEX_NAME}
searchClient={searchClient}>
<SearchBox submit={null} reset={null} />
<Results>
<Hits hitComponent={Hit} />
@@ -264,7 +280,7 @@ const Hit = ({ hit }) => {
)
}
export default Search;
export default Search
```
This file uses the dependencies you installed to show the search results. It also initializes MeiliSearch using the environment variables you added.
@@ -284,10 +300,12 @@ import Search from "./search"
And add the `Search` component in the returned JSX before `RegionPopover`:
```jsx title=src/components/header/index.jsx
//...
<Search />
<RegionPopover regions={mockData.regions} />
//...
// ...
<div className="...">
<Search />
<RegionPopover regions={mockData.regions} />
</div>
// ...
```
If you run your Gatsby storefront while the Medusa server and the MeiliSearch instance are running, you should find a search bar in the header of the page. Try entering a query to search through the products in your store.
+22 -13
View File
@@ -104,7 +104,9 @@ Where `<ENDPOINT>` is the URL of your MinIO server, `<BUCKET>` is the name of th
Finally, configure your `medusa-config.js` to include the plugin with the required options:
```js title=medusa-config.js
{
const plugins = [
// ...
{
resolve: `medusa-file-minio`,
options: {
endpoint: process.env.MINIO_ENDPOINT,
@@ -112,7 +114,8 @@ Finally, configure your `medusa-config.js` to include the plugin with the requ
access_key_id: process.env.MINIO_ACCESS_KEY,
secret_access_key: process.env.MINIO_SECRET_KEY,
},
},
},
]
```
:::caution
@@ -156,13 +159,16 @@ MINIO_PRIVATE_BUCKET=exports
Then, add a new option to the plugins options in `medusa-config.js`:
```jsx title=medusa-config.js
{
const plugins = [
// ...
{
resolve: `medusa-file-minio`,
options: {
//...
private_bucket: process.env.MINIO_PRIVATE_BUCKET
// ...
private_bucket: process.env.MINIO_PRIVATE_BUCKET,
},
},
},
]
```
### Use Different Secret and Access Keys
@@ -181,14 +187,17 @@ Where `<YOUR_PRIVATE_ACCESS_KEY>` and `<YOUR_PRIVATE_SECRET_KEY>` are the access
Then, add two new options to the plugins options in `medusa-config.js`:
```jsx title=medusa-config.js
{
const plugins = [
// ...
{
resolve: `medusa-file-minio`,
options: {
//...
// ...
private_access_key_id: process.env.MINIO_PRIVATE_ACCESS_KEY,
private_secret_access_key: process.env.MINIO_PRIVATE_SECRET_KEY
private_secret_access_key: process.env.MINIO_PRIVATE_SECRET_KEY,
},
},
},
]
```
---
@@ -204,13 +213,13 @@ In `next.config.js` add the following option in the exported object:
```jsx title=next.config.js
const { withStoreConfig } = require("./store-config")
//...
// ...
module.exports = withStoreConfig({
//...
// ...
images: {
domains: [
//...
// ...
"127.0.0.1",
],
},
+53 -41
View File
@@ -57,17 +57,17 @@ Then, in `medusa-config.js`, add the PayPal plugin to the `plugins` array with t
```jsx title=medusa-config.js
const plugins = [
//other plugins...
// other plugins...
{
resolve: `medusa-payment-paypal`,
options: {
sandbox: process.env.PAYPAL_SANDBOX,
client_id: process.env.PAYPAL_CLIENT_ID,
client_secret: process.env.PAYPAL_CLIENT_SECRET,
auth_webhook_id: process.env.PAYPAL_AUTH_WEBHOOK_ID
}
}
];
auth_webhook_id: process.env.PAYPAL_AUTH_WEBHOOK_ID,
},
},
]
```
Thats all you need to install PayPal on your Medusa server!
@@ -158,12 +158,15 @@ npm install @paypal/react-paypal-js
Next, create a new file `src/components/payment/paypal-payment/index.jsx` with the following content:
```jsx title=src/components/payment/paypal-payment/index.jsx
import { PayPalButtons, PayPalScriptProvider } from "@paypal/react-paypal-js";
import React, { useMemo, useState } from "react";
import {
PayPalButtons,
PayPalScriptProvider,
} from "@paypal/react-paypal-js"
import React, { useMemo, useState } from "react"
import { navigate } from "gatsby"
import { useCart } from "../../../hooks/use-cart"
import { useMedusa } from "../../../hooks/use-medusa";
import { useMedusa } from "../../../hooks/use-medusa"
const paypalClientId = process.env.GATSBY_PAYPAL_CLIENT_ID || ""
@@ -179,7 +182,7 @@ const PaypalPayment = () => {
const paypalSession = useMemo(() => {
if (cart.payment_sessions) {
return cart.payment_sessions.find(s => s.provider_id === "paypal")
return cart.payment_sessions.find((s) => s.provider_id === "paypal")
}
return null
@@ -200,10 +203,10 @@ const PaypalPayment = () => {
await client.carts.updatePaymentSession(cart.id, "paypal", {
data: {
data: {
...authorizationOrder
}
}
});
...authorizationOrder,
},
},
})
const order = await completeCart(cart.id)
@@ -218,10 +221,12 @@ const PaypalPayment = () => {
const handlePayment = (data, actions) => {
actions.order.authorize().then((authorization) => {
if (authorization.status !== 'COMPLETED') {
setErrorMessage(`An error occurred, status: ${authorization.status}`);
setProcessing(false);
return;
if (authorization.status !== "COMPLETED") {
setErrorMessage(
`An error occurred, status: ${authorization.status}`
)
setProcessing(false)
return
}
completeOrder(authorization)
@@ -232,7 +237,7 @@ const PaypalPayment = () => {
<PayPalScriptProvider options={{
"client-id": paypalClientId,
"currency": cart.region.currency_code.toUpperCase(),
"intent": "authorize"
"intent": "authorize",
}}>
{errorMessage && (
<span className="text-rose-500 mt-4">{errorMessage}</span>
@@ -246,7 +251,7 @@ const PaypalPayment = () => {
)
}
export default PaypalPayment;
export default PaypalPayment
```
Heres briefly what this code snippet does:
@@ -264,9 +269,11 @@ In `src/components/payment/index.js` youll find in the return statement a swi
```jsx title=src/components/payment/index.js
switch (ps.provider_id) {
case "stripe":
//...
// ...
break
case "manual":
//...
// ...
break
case "paypal":
return <PaypalPayment />
default:
@@ -303,28 +310,33 @@ Then, add the Client ID as an environment variable based on the framework you
Next, create the file that will hold the PayPal component with the following content:
```jsx
import { PayPalButtons, PayPalScriptProvider } from "@paypal/react-paypal-js";
import {
PayPalButtons,
PayPalScriptProvider,
} from "@paypal/react-paypal-js"
import { useEffect, useState } from "react"
import Medusa from "@medusajs/medusa-js"
function Paypal() {
const client = new Medusa();
const client = new Medusa()
const [errorMessage, setErrorMessage] = useState(undefined)
const [processing, setProcessing] = useState(false)
const cart //TODO retrieve the cart here
const cart = "..." // TODO retrieve the cart here
const handlePayment = (data, actions) => {
actions.order.authorize().then(async (authorization) => {
if (authorization.status !== 'COMPLETED') {
setErrorMessage(`An error occurred, status: ${authorization.status}`);
setProcessing(false);
return;
if (authorization.status !== "COMPLETED") {
setErrorMessage(
`An error occurred, status: ${authorization.status}`
)
setProcessing(false)
return
}
const response = await client.carts.setPaymentSession(cart.id, {
"provider_id": "paypal"
});
"provider_id": "paypal",
})
if (!response.cart) {
setProcessing(false)
@@ -334,30 +346,30 @@ function Paypal() {
await client.carts.updatePaymentSession(cart.id, "paypal", {
data: {
data: {
...authorization
}
}
});
...authorization,
},
},
})
const {data} = await client.carts.complete(cart.id)
const { data } = await client.carts.complete(cart.id)
if (!data || data.object !== "order") {
setProcessing(false)
return
}
//order successful
// order successful
alert("success")
})
}
return (
<div style={{marginTop: "10px", marginLeft: "10px"}}>
<div style={{ marginTop: "10px", marginLeft: "10px" }}>
{cart !== undefined && (
<PayPalScriptProvider options={{
"client-id": <CLIENT_ID>,
"client-id": "<CLIENT_ID>",
"currency": "EUR",
"intent": "authorize"
"intent": "authorize",
}}>
{errorMessage && (
<span className="text-rose-500 mt-4">{errorMessage}</span>
@@ -370,10 +382,10 @@ function Paypal() {
</PayPalScriptProvider>
)}
</div>
);
)
}
export default Paypal;
export default Paypal
```
Heres briefly what this code snippet does:
+9 -9
View File
@@ -118,7 +118,7 @@ Finally, in `medusa-config.js`, add to the `plugins` array the following new ite
```jsx title=medusa-config.js
const plugins = [
//...
// ...
{
resolve: `medusa-file-s3`,
options: {
@@ -129,7 +129,7 @@ const plugins = [
secret_access_key: process.env.S3_SECRET_ACCESS_KEY,
},
},
];
]
```
### Add AWS Configurations
@@ -140,7 +140,7 @@ For example, you can pass the `region`, `access_key_id` and `secret_access_key`
```jsx title=medusa-config.js
const plugins = [
//...
// ...
{
resolve: `medusa-file-s3`,
options: {
@@ -150,10 +150,10 @@ const plugins = [
region: process.env.S3_REGION,
access_key_id: process.env.S3_ACCESS_KEY_ID,
secret_access_key: process.env.S3_SECRET_ACCESS_KEY,
}
},
},
},
];
]
```
Make sure to define `S3_REGION`, `S3_ACCESS_KEY_ID`, and `S3_SECRET_ACCESS_KEY` in your environment variables first.
@@ -198,14 +198,14 @@ In `next.config.js` add the following option in the exported object:
```jsx title=next.config.js
const { withStoreConfig } = require("./store-config")
//...
// ...
module.exports = withStoreConfig({
//...
// ...
images: {
domains: [
//...
"<BUCKET_NAME>.s3.amazonaws.com"
// ...
"<BUCKET_NAME>.s3.amazonaws.com",
],
},
})
+12 -12
View File
@@ -110,14 +110,14 @@ Finally, in `medusa-config.js`, add the following new item to the `plugins` arra
```jsx title=medusa-config.js
const plugins = [
//...
// ...
{
resolve: `medusa-plugin-segment`,
options: {
write_key: process.env.SEGMENT_WRITE_KEY,
}
}
];
},
},
]
```
---
@@ -155,24 +155,24 @@ For example, you can add the following subscriber to listen to the `customer.cre
```jsx title=src/subscribers/customer.ts
class CustomerSubscriber {
constructor({ segmentService, eventBusService }) {
this.segmentService = segmentService;
this.segmentService = segmentService
eventBusService.subscribe("customer.created", this.handleCustomer);
eventBusService.subscribe("customer.created", this.handleCustomer)
}
handleCustomer = async (data) => {
const customerData = data;
delete customerData['password_hash'];
const customerData = data
delete customerData["password_hash"]
this.segmentService.track({
event: 'Customer Created',
event: "Customer Created",
userId: data.id,
properties: customerData
properties: customerData,
})
};
}
}
export default CustomerSubscriber;
export default CustomerSubscriber
```
You resolve the `SegmentService` using dependency injection. Then, when the `customer.created` event is triggered, you use the `track` method available in the `SegmentService` to send tracking data to Segment.
+8 -7
View File
@@ -3928,7 +3928,7 @@ Finally, in your `medusa-config.js` file, add the SendGrid plugin into the array
```jsx title=medusa-config.js
const plugins = [
...,
// ...,
{
resolve: `medusa-plugin-sendgrid`,
options: {
@@ -3937,12 +3937,13 @@ const plugins = [
order_placed_template: process.env.SENDGRID_ORDER_PLACED_ID,
localization: {
"de-DE": { // locale key
order_placed_template: process.env.SENDGRID_ORDER_PLACED_ID_LOCALIZED,
}
}
}
}
];
order_placed_template:
process.env.SENDGRID_ORDER_PLACED_ID_LOCALIZED,
},
},
},
},
]
```
The `api_key` and `from` options are required. Then, use the key of each template you create (from the [reference](#template-reference)) as the option name with the template ID as the value.
+5 -5
View File
@@ -83,16 +83,16 @@ After that, open `medusa-config.js` and add the new plugin with its configuratio
```jsx title=medusa-config.js
const plugins = [
...,
// ...,
{
resolve: `medusa-plugin-slack-notification`,
options: {
show_discount_code: false,
slack_url: `<WEBHOOK_URL>`,
admin_orders_url: `http://localhost:7001/a/orders`
}
}
];
admin_orders_url: `http://localhost:7001/a/orders`,
},
},
]
```
- Make sure to change `<WEBHOOK_URL>` with the Webhook URL you copied after creating the Slack app.
+6 -6
View File
@@ -105,7 +105,7 @@ Finally, in `medusa-config.js` add a new item to the `plugins` array:
```jsx title=medusa-config.js
const plugins = [
//...
// ...
{
resolve: `medusa-file-spaces`,
options: {
@@ -116,7 +116,7 @@ const plugins = [
secret_access_key: process.env.SPACE_SECRET_ACCESS_KEY,
},
},
];
]
```
:::caution
@@ -158,14 +158,14 @@ In `next.config.js` add the following option in the exported object:
```jsx title=next.config.js
const { withStoreConfig } = require("./store-config")
//...
// ...
module.exports = withStoreConfig({
//...
// ...
images: {
domains: [
//...
"<YOUR_SPACE_DOMAIN>"
// ...
"<YOUR_SPACE_DOMAIN>",
],
},
})
+11 -11
View File
@@ -94,10 +94,10 @@ Once the command is done executing, change to the newly created `medusa-server`
module.exports = {
projectConfig: {
redis_url: REDIS_URL,
//...
}
//...
};
// ...
},
// ...
}
```
This uses the default Redis configurations. If you want to learn more about configuring Redis, [check out this documentation](../usage/configurations.md#redis).
@@ -140,18 +140,18 @@ Finally, open `medusa-config.js` and add the following new item to the `plugins`
```jsx title=medusa-config.js
const plugins = [
//...
// ...
{
resolve: `medusa-plugin-strapi`,
options: {
strapi_medusa_user: process.env.STRAPI_USER,
strapi_medusa_password: process.env.STRAPI_PASSWORD,
strapi_url: process.env.STRAPI_URL, //optional
strapi_port: process.env.STRAPI_PORT, //optional
strapi_protocol: process.env.STRAPI_PROTOCOL //optional
}
}
];
strapi_url: process.env.STRAPI_URL, // optional
strapi_port: process.env.STRAPI_PORT, // optional
strapi_protocol: process.env.STRAPI_PROTOCOL, // optional
},
},
]
```
---
+42 -36
View File
@@ -48,7 +48,7 @@ In `medusa-config.js` add the following at the end of the `plugins` array:
```jsx title=medusa-config.js
const plugins = [
...,
// ...
{
resolve: `medusa-payment-stripe`,
options: {
@@ -56,7 +56,7 @@ const plugins = [
webhook_secret: process.env.STRIPE_WEBHOOK_SECRET,
},
},
];
]
```
:::note
@@ -75,7 +75,7 @@ Youll first retrieve the API key. You can find it by choosing API Keys from t
Next, you need to add the key to your environment variables. In your Medusa server, create `.env` if it doesnt already exist and add the Stripe key:
```jsx
```bash
STRIPE_API_KEY=sk_...
```
@@ -95,7 +95,7 @@ Then, you can add a description. You must select at least one event to listen to
After the Webhook is created, youll see "Signing secret" in the Webhook details. Click on "Reveal" to reveal the secret key. Copy that key and in your Medusa server add the Webhook secret environment variable:
```jsx
```bash
STRIPE_WEBHOOK_SECRET=whsec_...
```
@@ -195,30 +195,30 @@ In this section, youll initialize Stripe without Medusas checkout workflow
Create a container component that will hold the payment card component:
```jsx
import { useState } from 'react';
import { useState } from "react"
import {Elements} from '@stripe/react-stripe-js';
import Form from './Form';
import {loadStripe} from '@stripe/stripe-js';
import { Elements } from "@stripe/react-stripe-js"
import Form from "./Form"
import { loadStripe } from "@stripe/stripe-js"
const stripePromise = loadStripe('pk_...');
const stripePromise = loadStripe("pk_...")
export default function Container() {
const [clientSecret, setClientSecret] = useState()
//TODO set clientSecret
// TODO set clientSecret
return (
<div>
{clientSecret && (
<Elements stripe={stripePromise} options={{
clientSecret
clientSecret,
}}>
<Form clientSecret={clientSecret} cartId={cartId} />
</Elements>
)}
</div>
);
)
};
```
@@ -237,15 +237,19 @@ Once the clientSecret is set, the `Elements` Stripe component will wrap a `Form`
Create a new file for the `Form` component with the following content:
```jsx
import {CardElement, useElements, useStripe} from '@stripe/react-stripe-js';
import {
CardElement,
useElements,
useStripe,
} from "@stripe/react-stripe-js"
export default function Form({clientSecret, cartId}) {
const stripe = useStripe();
const elements = useElements();
export default function Form({ clientSecret, cartId }) {
const stripe = useStripe()
const elements = useElements()
async function handlePayment(e) {
e.preventDefault()
//TODO handle payment
// TODO handle payment
}
return (
@@ -253,7 +257,7 @@ export default function Form({clientSecret, cartId}) {
<CardElement />
<button onClick={handlePayment}>Submit</button>
</form>
);
)
};
```
@@ -267,8 +271,8 @@ Youll now implement the workflow explained earlier. Youll use Medusas J
import Medusa from "@medusajs/medusa-js"
export default function Container() {
const client = new Medusa();
...
const client = new Medusa()
// ...
}
```
@@ -282,19 +286,21 @@ Then, in the place of the `//TODO` inside the `Container` element, initialize th
```jsx
client.carts.createPaymentSessions(cart.id)
.then(({cart}) => {
//check if stripe is selected
const isStripeAvailable = cart.payment_sessions?.some((session) => session.provider_id === 'stripe');
.then(({ cart }) => {
// check if stripe is selected
const isStripeAvailable = cart.payment_sessions?.some((session) => (
session.provider_id === "stripe"
))
if (!isStripeAvailable) {
return;
return
}
//select stripe payment session
// select stripe payment session
client.carts.setPaymentSession(cart.id, {
provider_id: 'stripe'
}).then(({cart}) => {
setClientSecret(cart.payment_session.data.client_secret);
});
provider_id: "stripe",
}).then(({ cart }) => {
setClientSecret(cart.payment_session.data.client_secret)
})
})
```
@@ -314,8 +320,8 @@ As youll use Medusas client again make sure to import it and initialize it
import Medusa from "@medusajs/medusa-js"
export default function Form() {
const client = new Medusa();
...
const client = new Medusa()
// ...
}
```
@@ -335,12 +341,12 @@ return stripe.confirmCardPayment(clientSecret, {
line1,
line2,
postal_code,
}
}
}
},
},
},
}).then(({ error, paymentIntent }) => {
//TODO handle errors
client.carts.complete(cartId).then(resp => console.log(resp))
// TODO handle errors
client.carts.complete(cartId).then((resp) => console.log(resp))
})
```
+13 -13
View File
@@ -52,16 +52,16 @@ Finally, add the plugin and its options in the `medusa-config.js` file to the `p
```jsx title=medusa-config.js
const plugins = [
...,
// ...
{
resolve: `medusa-plugin-twilio-sms`,
options: {
account_sid: process.env.TWILIO_SMS_ACCOUNT_SID,
auth_token: process.env.TWILIO_SMS_AUTH_TOKEN,
from_number: process.env.TWILIO_SMS_FROM_NUMBER
}
}
];
from_number: process.env.TWILIO_SMS_FROM_NUMBER,
},
},
]
```
---
@@ -83,27 +83,27 @@ Create the file `src/services/sms.js` in your Medusa server with the following c
```jsx title=src/services/sms.js
class SmsSubscriber {
constructor({ twilioSmsService, orderService, eventBusService }) {
this.twilioSmsService_ = twilioSmsService;
this.orderService = orderService;
this.twilioSmsService_ = twilioSmsService
this.orderService = orderService
eventBusService.subscribe("order.placed", this.sendSMS);
eventBusService.subscribe("order.placed", this.sendSMS)
}
sendSMS = async (data) => {
const order = await this.orderService.retrieve(data.id, {
relations: ['shipping_address']
});
relations: ["shipping_address"],
})
if (order.shipping_address.phone) {
this.twilioSmsService_.sendSms({
to: order.shipping_address.phone,
body: 'We have received your order #' + data.id,
body: "We have received your order #" + data.id,
})
}
};
}
}
export default SmsSubscriber;
export default SmsSubscriber
```
In the `constructor`, you resolve the `twilioSmsService` and `orderService` using dependency injection to use it later in the `sendSMS` method.