feat(medusa-react): add product category queries and mutations (#3218)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@medusajs/medusa-js": patch
|
||||
"medusa-react": patch
|
||||
"@medusajs/medusa": patch
|
||||
---
|
||||
|
||||
feat(medusa-react): add product category queries and mutations
|
||||
@@ -8,8 +8,10 @@ import {
|
||||
AdminProductCategoriesListRes,
|
||||
AdminProductCategoriesCategoryRes,
|
||||
AdminGetProductCategoryParams,
|
||||
AdminPostProductCategoriesCategoryReq,
|
||||
} from "@medusajs/medusa"
|
||||
import qs from "qs"
|
||||
|
||||
import { ResponsePromise } from "../../typings"
|
||||
import BaseResource from "../base"
|
||||
|
||||
@@ -55,7 +57,7 @@ class AdminProductCategoriesResource extends BaseResource {
|
||||
*/
|
||||
update(
|
||||
productCategoryId: string,
|
||||
payload: AdminPostProductCategoriesCategoryParams,
|
||||
payload: AdminPostProductCategoriesCategoryReq,
|
||||
customHeaders: Record<string, any> = {}
|
||||
): ResponsePromise<AdminProductCategoriesCategoryRes> {
|
||||
const path = `/admin/product-categories/${productCategoryId}`
|
||||
@@ -63,10 +65,10 @@ class AdminProductCategoriesResource extends BaseResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a list of product categorys
|
||||
* Retrieve a list of product categories
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable featureflag `product_categories` in your medusa backend project.
|
||||
* @description Retrieve a list of product categorys
|
||||
* @description Retrieve a list of product categories
|
||||
* @returns the list of product category as well as the pagination properties
|
||||
*/
|
||||
list(
|
||||
|
||||
@@ -356,6 +356,14 @@
|
||||
"updated_at": "2021-03-16T21:24:13.657Z",
|
||||
"metadata": null
|
||||
},
|
||||
"product_category": {
|
||||
"id": "pcat_01F0YESBFAZ0DV6V831JXWH0BG",
|
||||
"name": "Skinny Jeans",
|
||||
"handle": "skinny-jeans",
|
||||
"created_at": "2021-03-16T21:24:07.273Z",
|
||||
"updated_at": "2021-03-16T21:24:07.273Z",
|
||||
"deleted_at": null
|
||||
},
|
||||
"product_variant": {
|
||||
"id": "variant_01F0YESHR7P2YAYBDBY5B6X3PK",
|
||||
"title": "Test variant",
|
||||
|
||||
@@ -130,6 +130,82 @@ export const adminHandlers = [
|
||||
)
|
||||
}),
|
||||
|
||||
rest.get("/admin/product-categories/", (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
product_categories: fixtures.list("product_category"),
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.get("/admin/product-categories/:id", (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
product_category: fixtures.get("product_category"),
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.post("/admin/product-categories/", (req, res, ctx) => {
|
||||
const body = req.body as Record<string, any>
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
product_category: {
|
||||
...fixtures.get("product_category"),
|
||||
...body,
|
||||
},
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.post("/admin/product-categories/:id", (req, res, ctx) => {
|
||||
const body = req.body as Record<string, any>
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
product_category: {
|
||||
...fixtures.get("product_category"),
|
||||
...body,
|
||||
},
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.delete("/admin/product-categories/:id", (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
id: req.params.id,
|
||||
object: "product-category",
|
||||
deleted: true,
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.post("/admin/product-categories/:id/products/batch", (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
product_category: fixtures.get("product_category"),
|
||||
})
|
||||
)
|
||||
}),
|
||||
|
||||
rest.delete(
|
||||
"/admin/product-categories/:id/products/batch",
|
||||
(req, res, ctx) => {
|
||||
return res(
|
||||
ctx.status(200),
|
||||
ctx.json({
|
||||
product_category: fixtures.get("product_category"),
|
||||
})
|
||||
)
|
||||
}
|
||||
),
|
||||
|
||||
rest.post("/admin/gift-cards/", (req, res, ctx) => {
|
||||
const body = req.body as Record<string, any>
|
||||
return res(
|
||||
|
||||
@@ -18,6 +18,7 @@ export * from "./price-lists"
|
||||
export * from "./product-tags"
|
||||
export * from "./product-types"
|
||||
export * from "./products"
|
||||
export * from "./product-categories"
|
||||
export * from "./publishable-api-keys"
|
||||
export * from "./regions"
|
||||
export * from "./return-reasons"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./queries"
|
||||
export * from "./mutations"
|
||||
@@ -0,0 +1,167 @@
|
||||
import {
|
||||
useMutation,
|
||||
UseMutationOptions,
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query"
|
||||
import { Response } from "@medusajs/medusa-js"
|
||||
import {
|
||||
AdminDeleteProductCategoriesCategoryProductsBatchReq,
|
||||
AdminPostProductCategoriesCategoryProductsBatchReq,
|
||||
AdminPostProductCategoriesCategoryReq,
|
||||
AdminPostProductCategoriesReq,
|
||||
AdminProductCategoriesCategoryDeleteRes,
|
||||
AdminProductCategoriesCategoryRes,
|
||||
} from "@medusajs/medusa"
|
||||
|
||||
import { useMedusa } from "../../../contexts"
|
||||
import { buildOptions } from "../../utils/buildOptions"
|
||||
import { adminProductCategoryKeys } from "./queries"
|
||||
import { adminProductKeys } from "../products"
|
||||
|
||||
/**
|
||||
* Hook provides a mutation function for creating product categories.
|
||||
*
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable the corresponding feature flag in your medusa backend project.
|
||||
*/
|
||||
export const useAdminCreateProductCategory = (
|
||||
options?: UseMutationOptions<
|
||||
Response<AdminProductCategoriesCategoryRes>,
|
||||
Error,
|
||||
AdminPostProductCategoriesReq
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation(
|
||||
(payload: AdminPostProductCategoriesReq) =>
|
||||
client.admin.productCategories.create(payload),
|
||||
buildOptions(queryClient, [adminProductCategoryKeys.list()], options)
|
||||
)
|
||||
}
|
||||
|
||||
/** Update a product category
|
||||
*
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable feature flag `product_categories` in your medusa backend project.
|
||||
* @description updates a product category
|
||||
* @returns the updated medusa product category
|
||||
*/
|
||||
export const useAdminUpdateProductCategory = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<AdminProductCategoriesCategoryRes>,
|
||||
Error,
|
||||
AdminPostProductCategoriesCategoryReq
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation(
|
||||
(payload: AdminPostProductCategoriesCategoryReq) =>
|
||||
client.admin.productCategories.update(id, payload),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[adminProductCategoryKeys.lists(), adminProductCategoryKeys.detail(id)],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a product category
|
||||
*
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable featureflag `product_categories` in your medusa backend project.
|
||||
* @param id
|
||||
* @param options
|
||||
*/
|
||||
export const useAdminDeleteProductCategory = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<AdminProductCategoriesCategoryDeleteRes>,
|
||||
Error,
|
||||
void
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation(
|
||||
() => client.admin.productCategories.delete(id),
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[adminProductCategoryKeys.lists(), adminProductCategoryKeys.detail(id)],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Add products to a product category
|
||||
*
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable featureflag `product_categories` in your medusa backend project.
|
||||
* @description Add products to a product category
|
||||
* @param id
|
||||
* @param options
|
||||
*/
|
||||
export const useAdminAddProductsToCategory = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<AdminProductCategoriesCategoryRes>,
|
||||
Error,
|
||||
AdminPostProductCategoriesCategoryProductsBatchReq
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation(
|
||||
(payload: AdminPostProductCategoriesCategoryProductsBatchReq) => {
|
||||
return client.admin.productCategories.addProducts(id, payload)
|
||||
},
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[
|
||||
adminProductCategoryKeys.lists(),
|
||||
adminProductCategoryKeys.detail(id),
|
||||
adminProductKeys.list({ product_category_id: [id] }),
|
||||
],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove products from a product category
|
||||
* @experimental This feature is under development and may change in the future.
|
||||
* To use this feature please enable featureflag `product_categories` in your medusa backend project.
|
||||
* @description remove products from a product category
|
||||
* @param id
|
||||
* @param options
|
||||
*/
|
||||
export const useAdminDeleteProductsFromCategory = (
|
||||
id: string,
|
||||
options?: UseMutationOptions<
|
||||
Response<AdminProductCategoriesCategoryRes>,
|
||||
Error,
|
||||
AdminDeleteProductCategoriesCategoryProductsBatchReq
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const queryClient = useQueryClient()
|
||||
return useMutation(
|
||||
(payload: AdminDeleteProductCategoriesCategoryProductsBatchReq) => {
|
||||
return client.admin.productCategories.removeProducts(id, payload)
|
||||
},
|
||||
buildOptions(
|
||||
queryClient,
|
||||
[
|
||||
adminProductCategoryKeys.lists(),
|
||||
adminProductCategoryKeys.detail(id),
|
||||
adminProductKeys.list({ product_category_id: [id] }),
|
||||
],
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import {
|
||||
AdminGetProductCategoriesParams,
|
||||
AdminProductCategoriesListRes,
|
||||
AdminGetProductCategoryParams,
|
||||
AdminProductCategoriesCategoryRes,
|
||||
} from "@medusajs/medusa"
|
||||
import { Response } from "@medusajs/medusa-js"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
import { useMedusa } from "../../../contexts"
|
||||
import { UseQueryOptionsWrapper } from "../../../types"
|
||||
import { queryKeysFactory } from "../../utils"
|
||||
|
||||
const ADMIN_PRODUCT_CATEGORIES_QUERY_KEY = `product_categories` as const
|
||||
export const adminProductCategoryKeys = queryKeysFactory(
|
||||
ADMIN_PRODUCT_CATEGORIES_QUERY_KEY
|
||||
)
|
||||
type ProductCategoryQueryKeys = typeof adminProductCategoryKeys
|
||||
|
||||
export const useAdminProductCategories = (
|
||||
query?: AdminGetProductCategoriesParams,
|
||||
options?: UseQueryOptionsWrapper<
|
||||
Response<AdminProductCategoriesListRes>,
|
||||
Error,
|
||||
ReturnType<ProductCategoryQueryKeys["list"]>
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const { data, ...rest } = useQuery(
|
||||
adminProductCategoryKeys.list(query),
|
||||
() => client.admin.productCategories.list(query),
|
||||
options
|
||||
)
|
||||
return { ...data, ...rest } as const
|
||||
}
|
||||
|
||||
export const useAdminProductCategory = (
|
||||
id: string,
|
||||
query?: AdminGetProductCategoryParams,
|
||||
options?: UseQueryOptionsWrapper<
|
||||
Response<AdminProductCategoriesCategoryRes>,
|
||||
Error,
|
||||
ReturnType<ProductCategoryQueryKeys["detail"]>
|
||||
>
|
||||
) => {
|
||||
const { client } = useMedusa()
|
||||
const { data, ...rest } = useQuery(
|
||||
adminProductCategoryKeys.detail(id),
|
||||
() => client.admin.productCategories.retrieve(id, query),
|
||||
options
|
||||
)
|
||||
|
||||
return { ...data, ...rest } as const
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
import { renderHook } from "@testing-library/react-hooks"
|
||||
|
||||
import {
|
||||
useAdminAddProductsToCategory,
|
||||
useAdminCreateProductCategory,
|
||||
useAdminDeleteProductCategory,
|
||||
useAdminDeleteProductsFromCategory,
|
||||
useAdminUpdateProductCategory,
|
||||
} from "../../../../src"
|
||||
import { fixtures } from "../../../../mocks/data"
|
||||
import { createWrapper } from "../../../utils"
|
||||
|
||||
describe("useAdminCreateProductCategory hook", () => {
|
||||
test("creates a product category", async () => {
|
||||
const category = {
|
||||
name: "Jeans category",
|
||||
}
|
||||
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminCreateProductCategory(),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate(category)
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data.product_category).toEqual(
|
||||
expect.objectContaining({
|
||||
...fixtures.get("product_category"),
|
||||
...category,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAdminUpdateProductCategory hook", () => {
|
||||
test("updates a product category", async () => {
|
||||
const category = {
|
||||
name: "Updated name",
|
||||
}
|
||||
|
||||
const categoryId = fixtures.get("product_category").id
|
||||
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminUpdateProductCategory(categoryId),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
result.current.mutate(category)
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data.response.status).toEqual(200)
|
||||
expect(result.current.data.product_category).toEqual({
|
||||
...fixtures.get("product_category"),
|
||||
...category,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAdminDeleteProductCategory hook", () => {
|
||||
test("deletes a product category", async () => {
|
||||
const id = fixtures.get("product_category").id
|
||||
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminDeleteProductCategory(id),
|
||||
{ wrapper: createWrapper() }
|
||||
)
|
||||
|
||||
result.current.mutate()
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data).toEqual(
|
||||
expect.objectContaining({
|
||||
id,
|
||||
object: "product-category",
|
||||
deleted: true,
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAdminAddProductsToCategory hook", () => {
|
||||
test("add products to a product category", async () => {
|
||||
const id = fixtures.get("product_category").id
|
||||
const productId = fixtures.get("product").id
|
||||
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminAddProductsToCategory(id),
|
||||
{ wrapper: createWrapper() }
|
||||
)
|
||||
|
||||
result.current.mutate({ product_ids: [{ id: productId }] })
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data).toEqual(
|
||||
expect.objectContaining({
|
||||
product_category: fixtures.get("product_category"),
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAdminDeleteProductsFromCategory hook", () => {
|
||||
test("remove products from a product category", async () => {
|
||||
const id = fixtures.get("product_category").id
|
||||
const productId = fixtures.get("product").id
|
||||
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminDeleteProductsFromCategory(id),
|
||||
{ wrapper: createWrapper() }
|
||||
)
|
||||
|
||||
result.current.mutate({ product_ids: [{ id: productId }] })
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.data).toEqual(
|
||||
expect.objectContaining({
|
||||
product_category: fixtures.get("product_category"),
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,37 @@
|
||||
import { useAdminProductCategory, useAdminProductCategories } from "../../../../src"
|
||||
import { renderHook } from "@testing-library/react-hooks"
|
||||
import { fixtures } from "../../../../mocks/data"
|
||||
import { createWrapper } from "../../../utils"
|
||||
|
||||
describe("useAdminProductCategories hook", () => {
|
||||
test("returns a list of categories", async () => {
|
||||
const categories = fixtures.list("product_category")
|
||||
|
||||
const { result, waitFor } = renderHook(() => useAdminProductCategories(), {
|
||||
wrapper: createWrapper(),
|
||||
})
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.response.status).toEqual(200)
|
||||
expect(result.current.product_categories).toEqual(categories)
|
||||
})
|
||||
})
|
||||
|
||||
describe("useAdminProductCategory hook", () => {
|
||||
test("returns a category", async () => {
|
||||
const category = fixtures.get("product_category")
|
||||
|
||||
const { result, waitFor } = renderHook(
|
||||
() => useAdminProductCategory(category.id),
|
||||
{
|
||||
wrapper: createWrapper(),
|
||||
}
|
||||
)
|
||||
|
||||
await waitFor(() => result.current.isSuccess)
|
||||
|
||||
expect(result.current.response.status).toEqual(200)
|
||||
expect(result.current.product_category).toEqual(category)
|
||||
})
|
||||
})
|
||||
@@ -144,6 +144,7 @@ export const defaultProductCategoryFields = [
|
||||
"handle",
|
||||
"is_active",
|
||||
"is_internal",
|
||||
"parent_category_id",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
|
||||
@@ -13,7 +13,7 @@ import { defaultStoreScope } from "."
|
||||
* description: "Retrieve a list of product categories."
|
||||
* x-authenticated: false
|
||||
* parameters:
|
||||
* - (query) q {string} Query used for searching product category names orhandles.
|
||||
* - (query) q {string} Query used for searching product category names or handles.
|
||||
* - (query) parent_category_id {string} Returns categories scoped by parent
|
||||
* - (query) offset=0 {integer} How many product categories to skip in the result.
|
||||
* - (query) limit=100 {integer} Limit the number of product categories returned.
|
||||
|
||||
Reference in New Issue
Block a user