feat: Add collection and category endpoints to store (#7155)
* feat: Add collection endpoints to store * feat: Add category store endpoints
This commit is contained in:
1 parent
2c807df99d
commit
ec37576dd0
25 files changed
+621
-279
No files matched your search
@@ -1,52 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`/store/collections /store/collections lists collections 1`] = `
|
|
||||||
Object {
|
|
||||||
"collections": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"handle": "test-collection2",
|
|
||||||
"id": "test-collection2",
|
|
||||||
"metadata": null,
|
|
||||||
"title": "Test collection 2",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"handle": "test-collection1",
|
|
||||||
"id": "test-collection1",
|
|
||||||
"metadata": null,
|
|
||||||
"title": "Test collection 1",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"handle": "test-collection",
|
|
||||||
"id": "test-collection",
|
|
||||||
"metadata": null,
|
|
||||||
"title": "Test collection",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"count": 3,
|
|
||||||
"limit": 10,
|
|
||||||
"offset": 0,
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`/store/collections /store/collections/:id gets collection 1`] = `
|
|
||||||
Object {
|
|
||||||
"collection": Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"handle": "test-collection",
|
|
||||||
"id": "test-collection",
|
|
||||||
"metadata": null,
|
|
||||||
"title": "Test collection",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
const { ProductCollection } = require("@medusajs/medusa")
|
|
||||||
const path = require("path")
|
|
||||||
const setupServer = require("../../../environment-helpers/setup-server")
|
|
||||||
const { useApi } = require("../../../environment-helpers/use-api")
|
|
||||||
const { initDb, useDb } = require("../../../environment-helpers/use-db")
|
|
||||||
|
|
||||||
const productSeeder = require("../../../helpers/product-seeder")
|
|
||||||
|
|
||||||
jest.setTimeout(30000)
|
|
||||||
describe("/store/collections", () => {
|
|
||||||
let medusaProcess
|
|
||||||
let dbConnection
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
|
||||||
dbConnection = await initDb({ cwd })
|
|
||||||
medusaProcess = await setupServer({ cwd })
|
|
||||||
})
|
|
||||||
|
|
||||||
afterAll(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.shutdown()
|
|
||||||
medusaProcess.kill()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("/store/collections/:id", () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await productSeeder(dbConnection)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("gets collection", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get("/store/collections/test-collection")
|
|
||||||
|
|
||||||
expect(response.data).toMatchSnapshot({
|
|
||||||
collection: {
|
|
||||||
id: "test-collection",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe("/store/collections", () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
await productSeeder(dbConnection)
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("lists collections", async () => {
|
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get("/store/collections")
|
|
||||||
|
|
||||||
expect(response.data).toMatchSnapshot({
|
|
||||||
collections: [
|
|
||||||
{
|
|
||||||
id: "test-collection2",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-collection1",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-collection",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
count: 3,
|
|
||||||
limit: 10,
|
|
||||||
offset: 0,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||||
|
import {
|
||||||
|
createAdminUser,
|
||||||
|
adminHeaders,
|
||||||
|
} from "../../../helpers/create-admin-user"
|
||||||
|
|
||||||
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
env: { MEDUSA_FF_PRODUCT_CATEGORIES: true },
|
||||||
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
|
let baseCollection
|
||||||
|
let baseCollection1
|
||||||
|
let baseCollection2
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const container = getContainer()
|
||||||
|
await createAdminUser(dbConnection, adminHeaders, container)
|
||||||
|
|
||||||
|
baseCollection = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/collections",
|
||||||
|
{ title: "test-collection" },
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.collection
|
||||||
|
|
||||||
|
baseCollection1 = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/collections",
|
||||||
|
{ title: "test-collection1" },
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.collection
|
||||||
|
|
||||||
|
baseCollection2 = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/collections",
|
||||||
|
{ title: "test-collection2" },
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.collection
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("/store/collections", () => {
|
||||||
|
describe("/store/collections/:id", () => {
|
||||||
|
it("gets collection", async () => {
|
||||||
|
const response = await api.get(
|
||||||
|
`/store/collections/${baseCollection.id}`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data.collection).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: baseCollection.id,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("/store/collections", () => {
|
||||||
|
it("lists collections", async () => {
|
||||||
|
const response = await api.get("/store/collections")
|
||||||
|
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
collections: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: baseCollection2.id,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: baseCollection1.id,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: baseCollection.id,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
count: 3,
|
||||||
|
limit: 10,
|
||||||
|
offset: 0,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,102 +1,113 @@
|
|||||||
import {ProductCategory} from "@medusajs/medusa"
|
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||||
import path from "path"
|
import {
|
||||||
|
adminHeaders,
|
||||||
import startServerWithEnvironment
|
createAdminUser,
|
||||||
from "../../../environment-helpers/start-server-with-environment"
|
} from "../../../helpers/create-admin-user"
|
||||||
import {useApi} from "../../../environment-helpers/use-api"
|
import { breaking } from "../../../helpers/breaking"
|
||||||
import {useDb} from "../../../environment-helpers/use-db"
|
|
||||||
import {simpleProductCategoryFactory} from "../../../factories"
|
|
||||||
|
|
||||||
jest.setTimeout(30000)
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
describe("/store/product-categories", () => {
|
medusaIntegrationTestRunner({
|
||||||
let medusaProcess
|
|
||||||
let dbConnection
|
|
||||||
let productCategory!: ProductCategory
|
|
||||||
let productCategory2!: ProductCategory
|
|
||||||
let productCategoryChild!: ProductCategory
|
|
||||||
let productCategoryParent!: ProductCategory
|
|
||||||
let productCategoryChild2!: ProductCategory
|
|
||||||
let productCategoryChild3!: ProductCategory
|
|
||||||
let productCategoryChild4!: ProductCategory
|
|
||||||
|
|
||||||
beforeAll(async () => {
|
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
|
||||||
const [process, connection] = await startServerWithEnvironment({
|
|
||||||
cwd,
|
|
||||||
env: { MEDUSA_FF_PRODUCT_CATEGORIES: true },
|
env: { MEDUSA_FF_PRODUCT_CATEGORIES: true },
|
||||||
})
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
dbConnection = connection
|
let productCategoryParent
|
||||||
medusaProcess = process
|
let productCategory
|
||||||
})
|
let productCategoryChild
|
||||||
|
let productCategoryChild2
|
||||||
afterAll(async () => {
|
let productCategoryChild3
|
||||||
const db = useDb()
|
let productCategoryChild4
|
||||||
await db.shutdown()
|
|
||||||
|
|
||||||
medusaProcess.kill()
|
|
||||||
})
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
productCategoryParent = await simpleProductCategoryFactory(dbConnection, {
|
const container = getContainer()
|
||||||
|
await createAdminUser(dbConnection, adminHeaders, container)
|
||||||
|
|
||||||
|
productCategoryParent = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/product-categories",
|
||||||
|
{
|
||||||
name: "category parent",
|
name: "category parent",
|
||||||
description: "test description",
|
description: "test description",
|
||||||
is_active: true,
|
is_active: true,
|
||||||
is_internal: false,
|
is_internal: false,
|
||||||
rank: 0,
|
},
|
||||||
})
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product_category
|
||||||
|
|
||||||
productCategory = await simpleProductCategoryFactory(dbConnection, {
|
productCategory = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/product-categories",
|
||||||
|
{
|
||||||
name: "category",
|
name: "category",
|
||||||
parent_category: productCategoryParent,
|
parent_category_id: productCategoryParent.id,
|
||||||
is_active: true,
|
is_active: true,
|
||||||
rank: 0,
|
},
|
||||||
})
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product_category
|
||||||
|
|
||||||
productCategoryChild = await simpleProductCategoryFactory(dbConnection, {
|
// The order in which the children are created is intentional as in v1 there was no way to explicitly set the rank.
|
||||||
name: "category child",
|
productCategoryChild2 = (
|
||||||
parent_category: productCategory,
|
await api.post(
|
||||||
is_active: true,
|
"/admin/product-categories",
|
||||||
is_internal: false,
|
{
|
||||||
rank: 3,
|
|
||||||
})
|
|
||||||
|
|
||||||
productCategoryChild2 = await simpleProductCategoryFactory(dbConnection, {
|
|
||||||
name: "category child 2",
|
name: "category child 2",
|
||||||
parent_category: productCategory,
|
parent_category_id: productCategory.id,
|
||||||
is_internal: true,
|
is_internal: true,
|
||||||
is_active: true,
|
is_active: true,
|
||||||
rank: 0,
|
},
|
||||||
})
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product_category
|
||||||
|
|
||||||
productCategoryChild3 = await simpleProductCategoryFactory(dbConnection, {
|
productCategoryChild3 = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/product-categories",
|
||||||
|
{
|
||||||
name: "category child 3",
|
name: "category child 3",
|
||||||
parent_category: productCategory,
|
parent_category_id: productCategory.id,
|
||||||
is_active: false,
|
|
||||||
is_internal: false,
|
is_internal: false,
|
||||||
rank: 1,
|
is_active: false,
|
||||||
})
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product_category
|
||||||
|
|
||||||
productCategoryChild4 = await simpleProductCategoryFactory(dbConnection, {
|
productCategoryChild4 = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/product-categories",
|
||||||
|
{
|
||||||
name: "category child 4",
|
name: "category child 4",
|
||||||
parent_category: productCategory,
|
parent_category_id: productCategory.id,
|
||||||
|
is_internal: false,
|
||||||
|
is_active: true,
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product_category
|
||||||
|
|
||||||
|
productCategoryChild = (
|
||||||
|
await api.post(
|
||||||
|
"/admin/product-categories",
|
||||||
|
{
|
||||||
|
name: "category child",
|
||||||
|
parent_category_id: productCategory.id,
|
||||||
is_active: true,
|
is_active: true,
|
||||||
is_internal: false,
|
is_internal: false,
|
||||||
rank: 2,
|
},
|
||||||
})
|
adminHeaders
|
||||||
|
)
|
||||||
|
).data.product_category
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("/store/product-categories", () => {
|
||||||
describe("GET /store/product-categories/:id", () => {
|
describe("GET /store/product-categories/:id", () => {
|
||||||
afterEach(async () => {
|
|
||||||
const db = useDb()
|
|
||||||
return await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("gets product category with children tree and parent", async () => {
|
it("gets product category with children tree and parent", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/store/product-categories/${productCategory.id}?fields=handle,name,description`
|
`/store/product-categories/${productCategory.id}?${breaking(
|
||||||
|
() => "fields=handle,name,description",
|
||||||
|
() => "include_ancestors_tree=true&include_descendants_tree=true"
|
||||||
|
)}`
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.data.product_category).toEqual(
|
expect(response.data.product_category).toEqual(
|
||||||
@@ -111,7 +122,7 @@ describe("/store/product-categories", () => {
|
|||||||
name: productCategoryParent.name,
|
name: productCategoryParent.name,
|
||||||
description: "test description",
|
description: "test description",
|
||||||
}),
|
}),
|
||||||
category_children: [
|
category_children: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: productCategoryChild4.id,
|
id: productCategoryChild4.id,
|
||||||
handle: productCategoryChild4.handle,
|
handle: productCategoryChild4.handle,
|
||||||
@@ -122,16 +133,15 @@ describe("/store/product-categories", () => {
|
|||||||
handle: productCategoryChild.handle,
|
handle: productCategoryChild.handle,
|
||||||
name: productCategoryChild.name,
|
name: productCategoryChild.name,
|
||||||
}),
|
}),
|
||||||
],
|
]),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// TODO: This one is failing since we don't validate allowed fields currently. We should add that as part of our validators
|
||||||
it("throws error on querying not allowed fields", async () => {
|
it("throws error on querying not allowed fields", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const error = await api
|
const error = await api
|
||||||
.get(`/store/product-categories/${productCategory.id}?fields=mpath`)
|
.get(`/store/product-categories/${productCategory.id}?fields=mpath`)
|
||||||
.catch((e) => e)
|
.catch((e) => e)
|
||||||
@@ -144,8 +154,6 @@ describe("/store/product-categories", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("throws error on querying for internal product category", async () => {
|
it("throws error on querying for internal product category", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const error = await api
|
const error = await api
|
||||||
.get(`/store/product-categories/${productCategoryChild2.id}`)
|
.get(`/store/product-categories/${productCategoryChild2.id}`)
|
||||||
.catch((e) => e)
|
.catch((e) => e)
|
||||||
@@ -153,13 +161,16 @@ describe("/store/product-categories", () => {
|
|||||||
expect(error.response.status).toEqual(404)
|
expect(error.response.status).toEqual(404)
|
||||||
expect(error.response.data.type).toEqual("not_found")
|
expect(error.response.data.type).toEqual("not_found")
|
||||||
expect(error.response.data.message).toEqual(
|
expect(error.response.data.message).toEqual(
|
||||||
`ProductCategory with id: ${productCategoryChild2.id}, is_internal: false, is_active: true was not found`
|
breaking(
|
||||||
|
() =>
|
||||||
|
`ProductCategory with id: ${productCategoryChild2.id}, is_internal: false, is_active: true was not found`,
|
||||||
|
() =>
|
||||||
|
`Product category with id: ${productCategoryChild2.id} was not found`
|
||||||
|
)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("throws error on querying for inactive product category", async () => {
|
it("throws error on querying for inactive product category", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const error = await api
|
const error = await api
|
||||||
.get(`/store/product-categories/${productCategoryChild3.id}`)
|
.get(`/store/product-categories/${productCategoryChild3.id}`)
|
||||||
.catch((e) => e)
|
.catch((e) => e)
|
||||||
@@ -167,21 +178,25 @@ describe("/store/product-categories", () => {
|
|||||||
expect(error.response.status).toEqual(404)
|
expect(error.response.status).toEqual(404)
|
||||||
expect(error.response.data.type).toEqual("not_found")
|
expect(error.response.data.type).toEqual("not_found")
|
||||||
expect(error.response.data.message).toEqual(
|
expect(error.response.data.message).toEqual(
|
||||||
`ProductCategory with id: ${productCategoryChild3.id}, is_internal: false, is_active: true was not found`
|
breaking(
|
||||||
|
() =>
|
||||||
|
`ProductCategory with id: ${productCategoryChild3.id}, is_internal: false, is_active: true was not found`,
|
||||||
|
() =>
|
||||||
|
`Product category with id: ${productCategoryChild3.id} was not found`
|
||||||
|
)
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("GET /store/product-categories", () => {
|
describe("GET /store/product-categories", () => {
|
||||||
afterEach(async () => {
|
//TODO: The listing results in V2 are unexpected and differ from v1, we need to investigate where the issue is
|
||||||
const db = useDb()
|
|
||||||
return await db.teardown()
|
|
||||||
})
|
|
||||||
|
|
||||||
it("gets list of product category with immediate children and parents", async () => {
|
it("gets list of product category with immediate children and parents", async () => {
|
||||||
const api = useApi()
|
const response = await api.get(
|
||||||
|
`/store/product-categories?limit=10${breaking(
|
||||||
const response = await api.get(`/store/product-categories?limit=10`)
|
() => "",
|
||||||
|
() => "&include_ancestors_tree=true&include_descendants_tree=true"
|
||||||
|
)}`
|
||||||
|
)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.count).toEqual(4)
|
expect(response.data.count).toEqual(4)
|
||||||
@@ -195,7 +210,7 @@ describe("/store/product-categories", () => {
|
|||||||
parent_category: expect.objectContaining({
|
parent_category: expect.objectContaining({
|
||||||
id: productCategoryParent.id,
|
id: productCategoryParent.id,
|
||||||
}),
|
}),
|
||||||
category_children: [
|
category_children: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: productCategoryChild4.id,
|
id: productCategoryChild4.id,
|
||||||
rank: 2,
|
rank: 2,
|
||||||
@@ -204,7 +219,7 @@ describe("/store/product-categories", () => {
|
|||||||
id: productCategoryChild.id,
|
id: productCategoryChild.id,
|
||||||
rank: 3,
|
rank: 3,
|
||||||
}),
|
}),
|
||||||
],
|
]),
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: productCategoryParent.id,
|
id: productCategoryParent.id,
|
||||||
@@ -235,9 +250,8 @@ describe("/store/product-categories", () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// TODO: It seems filtering using null doesn't work.
|
||||||
it("gets list of product category with all childrens when include_descendants_tree=true", async () => {
|
it("gets list of product category with all childrens when include_descendants_tree=true", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/store/product-categories?parent_category_id=null&include_descendants_tree=true&limit=10`
|
`/store/product-categories?parent_category_id=null&include_descendants_tree=true&limit=10`
|
||||||
)
|
)
|
||||||
@@ -277,8 +291,6 @@ describe("/store/product-categories", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("throws error when querying not allowed fields", async () => {
|
it("throws error when querying not allowed fields", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const error = await api
|
const error = await api
|
||||||
.get(`/store/product-categories?is_internal=true&limit=10`)
|
.get(`/store/product-categories?is_internal=true&limit=10`)
|
||||||
.catch((e) => e)
|
.catch((e) => e)
|
||||||
@@ -291,8 +303,6 @@ describe("/store/product-categories", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("filters based on free text on name and handle columns", async () => {
|
it("filters based on free text on name and handle columns", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/store/product-categories?q=category-parent&limit=10`
|
`/store/product-categories?q=category-parent&limit=10`
|
||||||
)
|
)
|
||||||
@@ -305,20 +315,18 @@ describe("/store/product-categories", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("filters based on handle attribute of the data model", async () => {
|
it("filters based on handle attribute of the data model", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/store/product-categories?handle=${productCategory.handle}&limit=10`
|
`/store/product-categories?handle=${productCategory.handle}&limit=10`
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.count).toEqual(1)
|
expect(response.data.count).toEqual(1)
|
||||||
expect(response.data.product_categories[0].id).toEqual(productCategory.id)
|
expect(response.data.product_categories[0].id).toEqual(
|
||||||
|
productCategory.id
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("filters based on parent category", async () => {
|
it("filters based on parent category", async () => {
|
||||||
const api = useApi()
|
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/store/product-categories?parent_category_id=${productCategory.id}&limit=10`
|
`/store/product-categories?parent_category_id=${productCategory.id}&limit=10`
|
||||||
)
|
)
|
||||||
@@ -356,3 +364,5 @@ describe("/store/product-categories", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -10,7 +10,7 @@ export const defaults = [
|
|||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"metadata",
|
"metadata",
|
||||||
|
"*parent_category",
|
||||||
"*category_children",
|
"*category_children",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -34,9 +34,11 @@ import { adminWorkflowsExecutionsMiddlewares } from "./admin/workflows-execution
|
|||||||
import { authRoutesMiddlewares } from "./auth/middlewares"
|
import { authRoutesMiddlewares } from "./auth/middlewares"
|
||||||
import { hooksRoutesMiddlewares } from "./hooks/middlewares"
|
import { hooksRoutesMiddlewares } from "./hooks/middlewares"
|
||||||
import { storeCartRoutesMiddlewares } from "./store/carts/middlewares"
|
import { storeCartRoutesMiddlewares } from "./store/carts/middlewares"
|
||||||
|
import { storeCollectionRoutesMiddlewares } from "./store/collections/middlewares"
|
||||||
import { storeCurrencyRoutesMiddlewares } from "./store/currencies/middlewares"
|
import { storeCurrencyRoutesMiddlewares } from "./store/currencies/middlewares"
|
||||||
import { storeCustomerRoutesMiddlewares } from "./store/customers/middlewares"
|
import { storeCustomerRoutesMiddlewares } from "./store/customers/middlewares"
|
||||||
import { storeProductRoutesMiddlewares } from "./store/products/middlewares"
|
import { storeProductRoutesMiddlewares } from "./store/products/middlewares"
|
||||||
|
import { storeProductCategoryRoutesMiddlewares } from "./store/product-categories/middlewares"
|
||||||
import { storeRegionRoutesMiddlewares } from "./store/regions/middlewares"
|
import { storeRegionRoutesMiddlewares } from "./store/regions/middlewares"
|
||||||
|
|
||||||
export const config: MiddlewaresConfig = {
|
export const config: MiddlewaresConfig = {
|
||||||
@@ -48,6 +50,8 @@ export const config: MiddlewaresConfig = {
|
|||||||
...storeCartRoutesMiddlewares,
|
...storeCartRoutesMiddlewares,
|
||||||
...storeCustomerRoutesMiddlewares,
|
...storeCustomerRoutesMiddlewares,
|
||||||
...storeCartRoutesMiddlewares,
|
...storeCartRoutesMiddlewares,
|
||||||
|
...storeCollectionRoutesMiddlewares,
|
||||||
|
...storeProductCategoryRoutesMiddlewares,
|
||||||
...authRoutesMiddlewares,
|
...authRoutesMiddlewares,
|
||||||
...adminWorkflowsExecutionsMiddlewares,
|
...adminWorkflowsExecutionsMiddlewares,
|
||||||
...storeRegionRoutesMiddlewares,
|
...storeRegionRoutesMiddlewares,
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../types/routing"
|
||||||
|
import { refetchCollection } from "../helpers"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const collection = await refetchCollection(
|
||||||
|
req.params.id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields
|
||||||
|
)
|
||||||
|
|
||||||
|
res.status(200).json({ collection })
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { MedusaContainer } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
|
||||||
|
export const refetchCollection = async (
|
||||||
|
collectionId: string,
|
||||||
|
scope: MedusaContainer,
|
||||||
|
fields: string[]
|
||||||
|
) => {
|
||||||
|
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "product_collection",
|
||||||
|
variables: {
|
||||||
|
filters: { id: collectionId },
|
||||||
|
},
|
||||||
|
fields: fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const collections = await remoteQuery(queryObject)
|
||||||
|
return collections[0]
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import * as QueryConfig from "./query-config"
|
||||||
|
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||||
|
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||||
|
import {
|
||||||
|
StoreGetCollectionParams,
|
||||||
|
StoreGetCollectionsParams,
|
||||||
|
} from "./validators"
|
||||||
|
|
||||||
|
export const storeCollectionRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/store/collections",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreGetCollectionsParams,
|
||||||
|
QueryConfig.listTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/store/collections/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreGetCollectionParams,
|
||||||
|
QueryConfig.retrieveTransformQueryConfig
|
||||||
|
),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
export const defaultStoreCollectionFields = [
|
||||||
|
"id",
|
||||||
|
"title",
|
||||||
|
"handle",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const retrieveTransformQueryConfig = {
|
||||||
|
defaults: defaultStoreCollectionFields,
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listTransformQueryConfig = {
|
||||||
|
...retrieveTransformQueryConfig,
|
||||||
|
defaultLimit: 10,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../types/routing"
|
||||||
|
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
|
const query = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "product_collection",
|
||||||
|
variables: {
|
||||||
|
filters: req.filterableFields,
|
||||||
|
...req.remoteQueryConfig.pagination,
|
||||||
|
},
|
||||||
|
fields: req.remoteQueryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { rows: collections, metadata } = await remoteQuery(query)
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
collections,
|
||||||
|
count: metadata.count,
|
||||||
|
offset: metadata.skip,
|
||||||
|
limit: metadata.take,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import {
|
||||||
|
createFindParams,
|
||||||
|
createOperatorMap,
|
||||||
|
createSelectParams,
|
||||||
|
} from "../../utils/validators"
|
||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
export const StoreGetCollectionParams = createSelectParams()
|
||||||
|
|
||||||
|
export type StoreGetCollectionsParamsType = z.infer<
|
||||||
|
typeof StoreGetCollectionsParams
|
||||||
|
>
|
||||||
|
export const StoreGetCollectionsParams = createFindParams({
|
||||||
|
offset: 0,
|
||||||
|
limit: 10,
|
||||||
|
order: "-created_at",
|
||||||
|
}).merge(
|
||||||
|
z.object({
|
||||||
|
q: z.string().optional(),
|
||||||
|
title: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
handle: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
created_at: createOperatorMap().optional(),
|
||||||
|
updated_at: createOperatorMap().optional(),
|
||||||
|
deleted_at: createOperatorMap().optional(),
|
||||||
|
$and: z.lazy(() => StoreGetCollectionsParams.array()).optional(),
|
||||||
|
$or: z.lazy(() => StoreGetCollectionsParams.array()).optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { StoreProductCategoryResponse } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../types/routing"
|
||||||
|
import { refetchCategory } from "../helpers"
|
||||||
|
import { StoreProductCategoryParamsType } from "../validators"
|
||||||
|
import { MedusaError } from "@medusajs/utils"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest<StoreProductCategoryParamsType>,
|
||||||
|
res: MedusaResponse<StoreProductCategoryResponse>
|
||||||
|
) => {
|
||||||
|
const category = await refetchCategory(
|
||||||
|
req.params.id,
|
||||||
|
req.scope,
|
||||||
|
req.remoteQueryConfig.fields,
|
||||||
|
req.filterableFields
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!category) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Product category with id: ${req.params.id} was not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
res.json({ product_category: category })
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { MedusaContainer } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
|
||||||
|
export const refetchCategory = async (
|
||||||
|
categoryId: string,
|
||||||
|
scope: MedusaContainer,
|
||||||
|
fields: string[],
|
||||||
|
filterableFields: Record<string, any> = {}
|
||||||
|
) => {
|
||||||
|
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "product_category",
|
||||||
|
variables: {
|
||||||
|
filters: { ...filterableFields, id: categoryId },
|
||||||
|
},
|
||||||
|
fields: fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const categories = await remoteQuery(queryObject)
|
||||||
|
return categories[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const applyCategoryFilters = (req, res, next) => {
|
||||||
|
if (!req.filterableFields) {
|
||||||
|
req.filterableFields = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.filterableFields = {
|
||||||
|
...req.filterableFields,
|
||||||
|
is_active: true,
|
||||||
|
is_internal: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||||
|
import { validateAndTransformQuery } from "../../utils/validate-query"
|
||||||
|
import { applyCategoryFilters } from "./helpers"
|
||||||
|
import * as QueryConfig from "./query-config"
|
||||||
|
import {
|
||||||
|
StoreProductCategoriesParams,
|
||||||
|
StoreProductCategoryParams,
|
||||||
|
} from "./validators"
|
||||||
|
|
||||||
|
export const storeProductCategoryRoutesMiddlewares: MiddlewareRoute[] = [
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/store/product-categories",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreProductCategoriesParams,
|
||||||
|
QueryConfig.listProductCategoryConfig
|
||||||
|
),
|
||||||
|
applyCategoryFilters,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["GET"],
|
||||||
|
matcher: "/store/product-categories/:id",
|
||||||
|
middlewares: [
|
||||||
|
validateAndTransformQuery(
|
||||||
|
StoreProductCategoryParams,
|
||||||
|
QueryConfig.retrieveProductCategoryConfig
|
||||||
|
),
|
||||||
|
applyCategoryFilters,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
export const defaults = [
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"handle",
|
||||||
|
"rank",
|
||||||
|
"parent_category_id",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"metadata",
|
||||||
|
"*parent_category",
|
||||||
|
"*category_children",
|
||||||
|
]
|
||||||
|
|
||||||
|
export const retrieveProductCategoryConfig = {
|
||||||
|
defaults,
|
||||||
|
isList: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const listProductCategoryConfig = {
|
||||||
|
defaults,
|
||||||
|
defaultLimit: 50,
|
||||||
|
isList: true,
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { StoreProductCategoryListResponse } from "@medusajs/types"
|
||||||
|
import {
|
||||||
|
ContainerRegistrationKeys,
|
||||||
|
remoteQueryObjectFromString,
|
||||||
|
} from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../types/routing"
|
||||||
|
import { StoreProductCategoriesParamsType } from "./validators"
|
||||||
|
|
||||||
|
export const GET = async (
|
||||||
|
req: AuthenticatedMedusaRequest<StoreProductCategoriesParamsType>,
|
||||||
|
res: MedusaResponse<StoreProductCategoryListResponse>
|
||||||
|
) => {
|
||||||
|
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||||
|
|
||||||
|
const queryObject = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "product_category",
|
||||||
|
variables: {
|
||||||
|
filters: req.filterableFields,
|
||||||
|
...req.remoteQueryConfig.pagination,
|
||||||
|
},
|
||||||
|
fields: req.remoteQueryConfig.fields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const { rows: product_categories, metadata } = await remoteQuery(queryObject)
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
product_categories,
|
||||||
|
count: metadata.count,
|
||||||
|
offset: metadata.skip,
|
||||||
|
limit: metadata.take,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
import { optionalBooleanMapper } from "../../../utils/validators/is-boolean"
|
||||||
|
import {
|
||||||
|
createFindParams,
|
||||||
|
createOperatorMap,
|
||||||
|
createSelectParams,
|
||||||
|
} from "../../utils/validators"
|
||||||
|
|
||||||
|
export type StoreProductCategoryParamsType = z.infer<
|
||||||
|
typeof StoreProductCategoryParams
|
||||||
|
>
|
||||||
|
export const StoreProductCategoryParams = createSelectParams().merge(
|
||||||
|
z.object({
|
||||||
|
include_ancestors_tree: z.preprocess(
|
||||||
|
(val: any) => optionalBooleanMapper.get(val?.toLowerCase()),
|
||||||
|
z.boolean().optional()
|
||||||
|
),
|
||||||
|
include_descendants_tree: z.preprocess(
|
||||||
|
(val: any) => optionalBooleanMapper.get(val?.toLowerCase()),
|
||||||
|
z.boolean().optional()
|
||||||
|
),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
export type StoreProductCategoriesParamsType = z.infer<
|
||||||
|
typeof StoreProductCategoriesParams
|
||||||
|
>
|
||||||
|
export const StoreProductCategoriesParams = createFindParams({
|
||||||
|
offset: 0,
|
||||||
|
limit: 50,
|
||||||
|
}).merge(
|
||||||
|
z.object({
|
||||||
|
q: z.string().optional(),
|
||||||
|
id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
description: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
handle: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
parent_category_id: z.union([z.string(), z.array(z.string())]).optional(),
|
||||||
|
include_ancestors_tree: z.preprocess(
|
||||||
|
(val: any) => optionalBooleanMapper.get(val?.toLowerCase()),
|
||||||
|
z.boolean().optional()
|
||||||
|
),
|
||||||
|
include_descendants_tree: z.preprocess(
|
||||||
|
(val: any) => optionalBooleanMapper.get(val?.toLowerCase()),
|
||||||
|
z.boolean().optional()
|
||||||
|
),
|
||||||
|
created_at: createOperatorMap().optional(),
|
||||||
|
updated_at: createOperatorMap().optional(),
|
||||||
|
deleted_at: createOperatorMap().optional(),
|
||||||
|
$and: z.lazy(() => StoreProductCategoriesParams.array()).optional(),
|
||||||
|
$or: z.lazy(() => StoreProductCategoriesParams.array()).optional(),
|
||||||
|
})
|
||||||
|
)
|
||||||
@@ -55,6 +55,7 @@ class ProductCategory {
|
|||||||
@Property({ columnType: "text", default: "", nullable: false })
|
@Property({ columnType: "text", default: "", nullable: false })
|
||||||
description?: string
|
description?: string
|
||||||
|
|
||||||
|
@Searchable()
|
||||||
@Property({ columnType: "text", nullable: false })
|
@Property({ columnType: "text", nullable: false })
|
||||||
handle?: string
|
handle?: string
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { PaginatedResponse } from "../../common"
|
||||||
|
import { ProductCategoryResponse } from "./common"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export interface AdminProductCategoryResponse {
|
||||||
|
product_category: ProductCategoryResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export interface AdminProductCategoryListResponse extends PaginatedResponse {
|
||||||
|
product_categories: ProductCategoryResponse[]
|
||||||
|
}
|
||||||
@@ -1 +0,0 @@
|
|||||||
export * from "./product-category"
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import { PaginatedResponse } from "../../../common"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
interface ProductCategoryResponse {
|
|
||||||
id: string
|
|
||||||
name: string
|
|
||||||
description: string | null
|
|
||||||
handle: string | null
|
|
||||||
is_active: boolean
|
|
||||||
is_internal: boolean
|
|
||||||
rank: number | null
|
|
||||||
parent_category_id: string | null
|
|
||||||
created_at: string | Date
|
|
||||||
updated_at: string | Date
|
|
||||||
|
|
||||||
parent_category: ProductCategoryResponse
|
|
||||||
category_children: ProductCategoryResponse[]
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export interface AdminProductCategoryResponse {
|
|
||||||
product_category: ProductCategoryResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
export interface AdminProductCategoryListResponse extends PaginatedResponse {
|
|
||||||
product_categories: ProductCategoryResponse[]
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export interface ProductCategoryResponse {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
description: string | null
|
||||||
|
handle: string | null
|
||||||
|
is_active: boolean
|
||||||
|
is_internal: boolean
|
||||||
|
rank: number | null
|
||||||
|
parent_category_id: string | null
|
||||||
|
created_at: string | Date
|
||||||
|
updated_at: string | Date
|
||||||
|
|
||||||
|
parent_category: ProductCategoryResponse
|
||||||
|
category_children: ProductCategoryResponse[]
|
||||||
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
export * from "./admin"
|
export * from "./admin"
|
||||||
|
export * from "./store"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { PaginatedResponse } from "../../common"
|
||||||
|
import { ProductCategoryResponse } from "./common"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export interface StoreProductCategoryResponse {
|
||||||
|
product_category: ProductCategoryResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export interface StoreProductCategoryListResponse extends PaginatedResponse {
|
||||||
|
product_categories: ProductCategoryResponse[]
|
||||||
|
}
|
||||||
Reference in new issue
Block a user