Skip to content

Commit 80cf8ba

Browse files
committed
feat: pricing modul in products route
1 parent 29e8b3f commit 80cf8ba

File tree

13 files changed

+611
-188
lines changed

13 files changed

+611
-188
lines changed

.env.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ NEXT_PUBLIC_MEDUSA_BACKEND_URL=http://localhost:9000
55
NEXT_PUBLIC_BASE_URL=http://localhost:8000
66

77
# Posgres URL for your Medusa DB for the Product Module. See - https://docs.medusajs.com/modules/products/serverless-module
8-
PRODUCT_POSTGRES_URL=postgres://postgres:postgres@localhost:5432/medusa
8+
POSTGRES_URL=postgres://postgres:postgres@localhost:5432/medusa
99

1010
# Your Stripe public key. See – https://docs.medusajs.com/add-plugins/stripe
1111
NEXT_PUBLIC_STRIPE_KEY=

next.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ const store = require("./store.config.json")
44
module.exports = withStoreConfig({
55
experimental: {
66
serverActions: true,
7-
serverComponentsExternalPackages: ["@medusajs/product"],
7+
serverComponentsExternalPackages: [
8+
"@medusajs/product",
9+
"@medusajs/modules-sdk",
10+
],
811
},
912
features: store.features,
1013
reactStrictMode: true,

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@
2222
"dependencies": {
2323
"@headlessui/react": "^1.6.1",
2424
"@hookform/error-message": "^2.0.0",
25+
"@medusajs/link-modules": "^0.1.0",
2526
"@medusajs/medusa-js": "^6.0.3",
26-
"@medusajs/product": "^0.1.7",
27+
"@medusajs/modules-sdk": "^1.10.0",
28+
"@medusajs/pricing": "^0.0.2",
29+
"@medusajs/product": "^0.2.0",
2730
"@meilisearch/instant-meilisearch": "^0.7.1",
2831
"@paypal/paypal-js": "^5.0.6",
2932
"@paypal/react-paypal-js": "^7.8.1",
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { NextRequest, NextResponse } from "next/server"
2+
import { initialize as initializeProductModule } from "@medusajs/product"
3+
import { ProductCollectionDTO } from "@medusajs/types/dist/product"
4+
import { notFound } from "next/navigation"
5+
import getPrices from "@lib/util/get-product-prices"
6+
7+
/**
8+
* This endpoint uses the serverless Product Module to retrieve a collection and its products by handle.
9+
* The module connects directly to you Medusa database to retrieve and manipulate data, without the need for a dedicated server.
10+
* Read more about the Product Module here: https://docs.medusajs.com/modules/products/serverless-module
11+
*/
12+
export async function GET(
13+
request: NextRequest,
14+
{ params }: { params: Record<string, any> }
15+
) {
16+
const productService = await initializeProductModule()
17+
18+
const { handle } = params
19+
20+
const searchParams = Object.fromEntries(request.nextUrl.searchParams)
21+
const { page, limit, cart_id } = searchParams
22+
23+
const collections = await productService.listCollections()
24+
25+
const collectionsByHandle = new Map<string, ProductCollectionDTO>()
26+
27+
for (const collection of collections) {
28+
collectionsByHandle.set(collection.handle, collection)
29+
}
30+
31+
const collection = collectionsByHandle.get(handle)
32+
33+
if (!collection) {
34+
return notFound()
35+
}
36+
37+
const count = collection.products?.length || 0
38+
39+
const { products, ...collectionMeta } =
40+
await productService.retrieveCollection(collection.id, {
41+
relations: [
42+
"products",
43+
"products.variants",
44+
"products.variants.options",
45+
"products.tags",
46+
"products.options",
47+
"products.status",
48+
],
49+
take: parseInt(limit) || 100,
50+
skip: parseInt(page) || 0,
51+
})
52+
53+
if (!products) {
54+
return notFound()
55+
}
56+
57+
const publishedProducts = products.filter(
58+
(product) => product.status === "published"
59+
)
60+
61+
const productsWithPrices = await getPrices(publishedProducts, cart_id)
62+
63+
const nextPage = parseInt(page) + parseInt(limit)
64+
65+
return NextResponse.json({
66+
collections: [collectionMeta],
67+
response: {
68+
products: productsWithPrices,
69+
count,
70+
},
71+
nextPage: count > nextPage ? nextPage : null,
72+
})
73+
}
Lines changed: 93 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { NextRequest, NextResponse } from "next/server"
2-
import { initialize as initializeProductModule } from "@medusajs/product"
3-
import { ProductCollectionDTO } from "@medusajs/types/dist/product"
42
import { notFound } from "next/navigation"
5-
import getPrices from "@lib/util/get-product-prices"
3+
4+
import { initialize as initializeProductModule } from "@medusajs/product"
5+
import { MedusaApp, Modules } from "@medusajs/modules-sdk"
6+
import { ProductCollectionDTO, ProductDTO } from "@medusajs/types/dist/product"
67

78
/**
89
* This endpoint uses the serverless Product Module to retrieve a collection and its products by handle.
@@ -18,7 +19,7 @@ export async function GET(
1819
const { handle } = params
1920

2021
const searchParams = Object.fromEntries(request.nextUrl.searchParams)
21-
const { page, limit, cart_id } = searchParams
22+
const { page, limit } = searchParams
2223

2324
const collections = await productService.listCollections()
2425

@@ -34,40 +35,104 @@ export async function GET(
3435
return notFound()
3536
}
3637

37-
const count = collection.products?.length || 0
38-
39-
const { products, ...collectionMeta } =
40-
await productService.retrieveCollection(collection.id, {
41-
relations: [
42-
"products",
43-
"products.variants",
44-
"products.variants.options",
45-
"products.tags",
46-
"products.options",
47-
"products.status",
48-
],
49-
take: parseInt(limit) || 100,
50-
skip: parseInt(page) || 0,
51-
})
52-
53-
if (!products) {
54-
return notFound()
55-
}
38+
const {
39+
rows: products,
40+
metadata: { count },
41+
} = await getProductsByCollectionId(collection.id, searchParams)
5642

57-
const publishedProducts = products.filter(
43+
const publishedProducts: ProductDTO[] = products.filter(
5844
(product) => product.status === "published"
5945
)
6046

61-
const productsWithPrices = await getPrices(publishedProducts, cart_id)
62-
6347
const nextPage = parseInt(page) + parseInt(limit)
6448

6549
return NextResponse.json({
66-
collections: [collectionMeta],
50+
collections: [collection],
6751
response: {
68-
products: productsWithPrices,
52+
products: publishedProducts,
6953
count,
7054
},
7155
nextPage: count > nextPage ? nextPage : null,
7256
})
7357
}
58+
59+
async function getProductsByCollectionId(
60+
collection_id: string,
61+
params: Record<string, any>
62+
): Promise<{ rows: ProductDTO[]; metadata: Record<string, any> }> {
63+
const { query } = await MedusaApp({
64+
modulesConfig: [
65+
{
66+
module: Modules.PRODUCT,
67+
path: "@medusajs/product",
68+
},
69+
{
70+
module: Modules.PRICING,
71+
path: "@medusajs/pricing",
72+
},
73+
],
74+
sharedResourcesConfig: {
75+
database: { clientUrl: process.env.POSTGRES_URL },
76+
},
77+
})
78+
79+
const filters = {
80+
take: parseInt(params.limit) || 100,
81+
skip: parseInt(params.offset) || 0,
82+
filters: {
83+
collection_id: [collection_id],
84+
},
85+
}
86+
87+
const productsQuery = `#graphql
88+
query($filters: Record, $take: Int, $skip: Int) {
89+
products(filters: $filters, take: $take, skip: $skip) {
90+
id
91+
title
92+
handle
93+
tags
94+
status
95+
collection
96+
collection_id
97+
thumbnail
98+
images {
99+
url
100+
alt_text
101+
id
102+
}
103+
options {
104+
id
105+
value
106+
title
107+
}
108+
variants {
109+
id
110+
title
111+
created_at
112+
updated_at
113+
thumbnail
114+
inventory_quantity
115+
material
116+
weight
117+
length
118+
height
119+
width
120+
options {
121+
id
122+
value
123+
title
124+
}
125+
prices {
126+
money_amount {
127+
amount
128+
currency_code
129+
}
130+
}
131+
}
132+
}
133+
}`
134+
135+
const response = await query(productsQuery, filters)
136+
137+
return response
138+
}
Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,83 @@
11
import { NextResponse, NextRequest } from "next/server"
2-
import getPrices from "@lib/util/get-product-prices"
32

4-
import { initialize as initializeProductModule } from "@medusajs/product"
3+
import { MedusaApp, Modules } from "@medusajs/modules-sdk"
54

65
/**
7-
* This endpoint uses the serverless Product Module to retrieve a product by handle.
8-
* The module connects directly to you Medusa database to retrieve and manipulate data, without the need for a dedicated server.
6+
* This endpoint uses the serverless Product and Pricing Modules to retrieve a product by handle.
7+
* The modules connect directly to your Medusa database to retrieve and manipulate data, without the need for a dedicated server.
98
* Read more about the Product Module here: https://docs.medusajs.com/modules/products/serverless-module
109
*/
1110
export async function GET(
1211
request: NextRequest,
1312
{ params }: { params: Record<string, any> }
1413
) {
1514
const { handle } = params
16-
const { cart_id, region_id } = Object.fromEntries(
17-
request.nextUrl.searchParams
18-
)
19-
const productService = await initializeProductModule()
2015

21-
const data = await productService.list(
22-
{ handle },
23-
{
24-
relations: [
25-
"variants",
26-
"variants.options",
27-
"tags",
28-
"options",
29-
"options.values",
30-
"images",
31-
"description",
32-
"collection",
33-
"status",
34-
],
35-
take: 1,
36-
}
37-
)
16+
const { query } = await MedusaApp({
17+
modulesConfig: [
18+
{
19+
module: Modules.PRODUCT,
20+
path: "@medusajs/product",
21+
},
22+
{
23+
module: Modules.PRICING,
24+
path: "@medusajs/pricing",
25+
},
26+
],
27+
sharedResourcesConfig: {
28+
database: { clientUrl: process.env.POSTGRES_URL },
29+
},
30+
})
3831

39-
const productsWithPrices = await getPrices(data, cart_id, region_id)
32+
const productsQuery = `#graphql
33+
query {
34+
products(handle: "${handle}", take: 1) {
35+
id
36+
title
37+
handle
38+
tags
39+
status
40+
collection
41+
collection_id
42+
thumbnail
43+
images {
44+
url
45+
alt_text
46+
id
47+
}
48+
options {
49+
id
50+
value
51+
title
52+
}
53+
variants {
54+
id
55+
title
56+
created_at
57+
updated_at
58+
thumbnail
59+
inventory_quantity
60+
material
61+
weight
62+
length
63+
height
64+
width
65+
prices {
66+
money_amount {
67+
amount
68+
currency_code
69+
}
70+
}
71+
options {
72+
id
73+
value
74+
title
75+
}
76+
}
77+
}
78+
}`
4079

41-
return NextResponse.json({ products: productsWithPrices })
80+
const products = await query(productsQuery)
81+
82+
return NextResponse.json({ products })
4283
}

0 commit comments

Comments
 (0)