Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added product reviews #38

Merged
merged 2 commits into from
Mar 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .cursorrules
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
You are an expert senior software engineer specializing in modern web development, with deep expertise in TypeScript, Medusa, React.js, and TailwindCSS.

## Medusa Rules

### General Rules

- Don't use type aliases when importing files.

### Workflow Rules

- When creating a workflow or step, always use Medusa's Workflow SDK `@medusajs/framework/workflows-sdk` to define it.
- When creating a feature, always create a workflow for it.
- When creating a workflow, always create a step for it.
- In workflows, use `transform` for any data transformation.
- In workflows, use `when` to define conditions.
- Don't use `await` when calling steps.
- In workflows, don't make the workflow function async.
- Don't add typing to compenstion function's input.
- Only use steps in a workflow.

### Data Model Rules

- Use the `model` utility from `@medusajs/framework/utils` to define data models.
- Data model variables should be camelCase. Data model names as passed to `model.define` should be snake case.
- When adding an `id` field to a data model, always make it a primary key with `.primaryKey()`.
- A data model can have one `id` only, other IDs should be `text` instead.
- Data model fields should be snake case.

### Service Rules

- When create a service, always make methods async.

### Admin Customization Rules

- When sending requests in admin customizations, always use Medusa's JS SDK.
- Use TailwindCSS for styling.
9 changes: 9 additions & 0 deletions product-reviews/.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
STORE_CORS=http://localhost:8000,https://docs.medusajs.com
ADMIN_CORS=http://localhost:5173,http://localhost:9000,https://docs.medusajs.com
AUTH_CORS=http://localhost:5173,http://localhost:9000,https://docs.medusajs.com
REDIS_URL=redis://localhost:6379
JWT_SECRET=supersecret
COOKIE_SECRET=supersecret
DATABASE_URL=postgres://postgres@localhost/$DB_NAME # change user and password if necessary
DB_NAME=medusa-product-reviews
POSTGRES_URL=
26 changes: 26 additions & 0 deletions product-reviews/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/dist
.env
.DS_Store
/uploads
/node_modules
yarn-error.log

.idea

coverage

!src/**

./tsconfig.tsbuildinfo
medusa-db.sql
build
.cache

.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

.medusa
1 change: 1 addition & 0 deletions product-reviews/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
82 changes: 82 additions & 0 deletions product-reviews/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Medusa v2 Example: Product Reviews

This directory holds the code for the [Product Review Guide](https://docs.medusajs.com/resources/how-to-tutorials/tutorials/product-reviews).

You can either:

- [install and use it as a Medusa application](#installation);
- or [copy its source files into an existing Medusa application](#copy-into-existing-medusa-application).

## Prerequisites

- [Node.js v20+](https://nodejs.org/en/download)
- [Git CLI](https://git-scm.com/downaloads)
- [PostgreSQL](https://www.postgresql.org/download/)

## Installation

1. Clone the repository and change to the `product-review` directory:

```bash
git clone https://github.com/medusajs/examples.git
cd examples/product-review
```

2\. Rename the `.env.template` file to `.env`.

3\. If necessary, change the PostgreSQL username, password, and host in the `DATABASE_URL` environment variable.

4\. Install dependencies:

```bash
yarn # or npm install
```

5\. Setup and seed the database:

```bash
npx medusa db:setup
yarn seed # or npm run seed
```

6\. Start the Medusa application:

```bash
yarn dev # or npm run dev
```

You'll find a "Reviews" page in the Medusa Admin.

## Copy into Existing Medusa Application

If you have an existing Medusa application, copy the following directories and files into your project:

- `src/admin`
- `src/api`
- `src/links`
- `src/modules/product-review`
- `src/workflows`

Then, add the Product Review Module to `medusa-config.ts`:

```ts
module.exports = defineConfig({
// ...
modules: [
{
resolve: "./src/modules/product-review",
}
],
})
```

Finally, run migrations:

```bash
npx medusa db:migrate
```

## More Resources

- [Medusa Documentatin](https://docs.medusajs.com)
- [OpenAPI Spec file](https://res.cloudinary.com/dza7lstvk/raw/upload/v1741941475/OpenApi/product-reviews_jh8ohj.yaml): Can be imported into tools like Postman to view and send requests to this project's API routes.
24 changes: 24 additions & 0 deletions product-reviews/instrumentation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Uncomment this file to enable instrumentation and observability using OpenTelemetry
// Refer to the docs for installation instructions: https://docs.medusajs.com/learn/debugging-and-testing/instrumentation

// import { registerOtel } from "@medusajs/medusa"
// // If using an exporter other than Zipkin, require it here.
// import { ZipkinExporter } from "@opentelemetry/exporter-zipkin"

// // If using an exporter other than Zipkin, initialize it here.
// const exporter = new ZipkinExporter({
// serviceName: 'my-medusa-project',
// })

// export function register() {
// registerOtel({
// serviceName: 'medusajs',
// // pass exporter
// exporter,
// instrument: {
// http: true,
// workflows: true,
// query: true
// },
// })
// }
29 changes: 29 additions & 0 deletions product-reviews/integration-tests/http/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Integration Tests

The `medusa-test-utils` package provides utility functions to create integration tests for your API routes and workflows.

For example:

```ts
import { medusaIntegrationTestRunner } from "medusa-test-utils"

medusaIntegrationTestRunner({
testSuite: ({ api, getContainer }) => {
describe("Custom endpoints", () => {
describe("GET /store/custom", () => {
it("returns correct message", async () => {
const response = await api.get(
`/store/custom`
)

expect(response.status).toEqual(200)
expect(response.data).toHaveProperty("message")
expect(response.data.message).toEqual("Hello, World!")
})
})
})
}
})
```

Learn more in [this documentation](https://docs.medusajs.com/learn/debugging-and-testing/testing-tools/integration-tests).
15 changes: 15 additions & 0 deletions product-reviews/integration-tests/http/health.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
jest.setTimeout(60 * 1000)

medusaIntegrationTestRunner({
inApp: true,
env: {},
testSuite: ({ api }) => {
describe("Ping", () => {
it("ping the server health endpoint", async () => {
const response = await api.get('/health')
expect(response.status).toEqual(200)
})
})
},
})
3 changes: 3 additions & 0 deletions product-reviews/integration-tests/setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const { MetadataStorage } = require("@mikro-orm/core")

MetadataStorage.clear()
27 changes: 27 additions & 0 deletions product-reviews/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { loadEnv } = require("@medusajs/utils");
loadEnv("test", process.cwd());

module.exports = {
transform: {
"^.+\\.[jt]s$": [
"@swc/jest",
{
jsc: {
parser: { syntax: "typescript", decorators: true },
},
},
],
},
testEnvironment: "node",
moduleFileExtensions: ["js", "ts", "json"],
modulePathIgnorePatterns: ["dist/", "<rootDir>/.medusa/"],
setupFiles: ["./integration-tests/setup.js"],
};

if (process.env.TEST_TYPE === "integration:http") {
module.exports.testMatch = ["**/integration-tests/http/*.spec.[jt]s"];
} else if (process.env.TEST_TYPE === "integration:modules") {
module.exports.testMatch = ["**/src/modules/*/__tests__/**/*.[jt]s"];
} else if (process.env.TEST_TYPE === "unit") {
module.exports.testMatch = ["**/src/**/__tests__/**/*.unit.spec.[jt]s"];
}
21 changes: 21 additions & 0 deletions product-reviews/medusa-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { loadEnv, defineConfig } from '@medusajs/framework/utils'

loadEnv(process.env.NODE_ENV || 'development', process.cwd())

module.exports = defineConfig({
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
http: {
storeCors: process.env.STORE_CORS!,
adminCors: process.env.ADMIN_CORS!,
authCors: process.env.AUTH_CORS!,
jwtSecret: process.env.JWT_SECRET || "supersecret",
cookieSecret: process.env.COOKIE_SECRET || "supersecret",
}
},
modules: [
{
resolve: "./src/modules/product-review"
}
]
})
57 changes: 57 additions & 0 deletions product-reviews/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "product-reviews",
"version": "0.0.1",
"description": "A starter for Medusa projects.",
"author": "Medusa (https://medusajs.com)",
"license": "MIT",
"keywords": [
"sqlite",
"postgres",
"typescript",
"ecommerce",
"headless",
"medusa"
],
"scripts": {
"build": "medusa build",
"seed": "medusa exec ./src/scripts/seed.ts",
"start": "medusa start",
"dev": "medusa develop",
"test:integration:http": "TEST_TYPE=integration:http NODE_OPTIONS=--experimental-vm-modules jest --silent=false --runInBand --forceExit",
"test:integration:modules": "TEST_TYPE=integration:modules NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit",
"test:unit": "TEST_TYPE=unit NODE_OPTIONS=--experimental-vm-modules jest --silent --runInBand --forceExit"
},
"dependencies": {
"@medusajs/admin-sdk": "2.6.1",
"@medusajs/cli": "2.6.1",
"@medusajs/framework": "2.6.1",
"@medusajs/medusa": "2.6.1",
"@mikro-orm/core": "6.4.3",
"@mikro-orm/knex": "6.4.3",
"@mikro-orm/migrations": "6.4.3",
"@mikro-orm/postgresql": "6.4.3",
"awilix": "^8.0.1",
"pg": "^8.13.0"
},
"devDependencies": {
"@medusajs/test-utils": "2.6.1",
"@mikro-orm/cli": "6.4.3",
"@swc/core": "1.5.7",
"@swc/jest": "^0.2.36",
"@types/jest": "^29.5.13",
"@types/node": "^20.0.0",
"@types/react": "^18.3.2",
"@types/react-dom": "^18.2.25",
"jest": "^29.7.0",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"ts-node": "^10.9.2",
"typescript": "^5.6.2",
"vite": "^5.2.11",
"yalc": "^1.0.0-pre.53"
},
"engines": {
"node": ">=20"
}
}
33 changes: 33 additions & 0 deletions product-reviews/src/admin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Admin Customizations

You can extend the Medusa Admin to add widgets and new pages. Your customizations interact with API routes to provide merchants with custom functionalities.

> Learn more about Admin Extensions in [this documentation](https://docs.medusajs.com/learn/fundamentals/admin).

## Example: Create a Widget

A widget is a React component that can be injected into an existing page in the admin dashboard.

For example, create the file `src/admin/widgets/product-widget.tsx` with the following content:

```tsx title="src/admin/widgets/product-widget.tsx"
import { defineWidgetConfig } from "@medusajs/admin-sdk"

// The widget
const ProductWidget = () => {
return (
<div>
<h2>Product Widget</h2>
</div>
)
}

// The widget's configurations
export const config = defineWidgetConfig({
zone: "product.details.after",
})

export default ProductWidget
```

This inserts a widget with the text “Product Widget” at the end of a product’s details page.
9 changes: 9 additions & 0 deletions product-reviews/src/admin/lib/sdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Medusa from "@medusajs/js-sdk"

export const sdk = new Medusa({
baseUrl: "http://localhost:9000",
debug: process.env.NODE_ENV === "development",
auth: {
type: "session",
},
})
Loading