feat(medusa-js, medusa-react, medusa): Prepare API for admin implementations (#3110)

********What********
Add `joinSalesChannels util to stock locations

Add the following endpoints to medusa-react
- inventory items
    - mutations
        - update
        - delete
        - update location level
        - delete location level
        - create location level
    - queries
        - list inventory items
        - get inventory item
        - list location levels
- Stock locations
    - mutations
        - create stock location
        - update stock location
        - delete stock location
    - queries
        - list stock locations
        - get stock locatoin
- Variants
    - queries
        - get inventory
- Reservations
    - mutations
        - create reservation
        - update reservation
        - delete reservation
    - queries
        - list reservations
        - get reservation
- sales channels 
  - mutations
    - associate location with sc
    - remove location association

**Why**
- Update clients to reflect new api endpoints in the core with inventory modules

Co-authored-by: Philip Korsholm <88927411+pKorsholm@users.noreply.github.com>
This commit is contained in:
Rares StefanandPhilip Korsholm authored and GitHub committed 2023-02-16 08:49:48 +00:00
1 parent 121b42acfe
commit 12d304307a
48 files changed
+1756 -57

No files matched your search

@@ -1140,6 +1140,46 @@
"updated_at": "2021-03-17 12:09:59.156058+01",
"metadata": null
},
"inventory_item": {
"id": "iitem_320ZXDBAB4WJVW6115VEM7",
"sku": "sku123",
"origin_country": "dk",
"hs_code": null,
"mid_code": null,
"material": null,
"weight": 10,
"lenght": 4,
"height": 5,
"width": 2,
"requires_shipping": true,
"created_at": "2021-03-17 11:58:56.975971+01",
"updated_at": "2021-03-17 12:09:59.156058+01",
"metadata": null,
"location_levels": [
{
"id": "ilev_320ZXDBAB4WJVW6115VEM7",
"inventory_item_id": "iitem_320ZXDBAB4WJVW6115VEM7",
"location_id": "loc_01F0ZXDBAB9KVZWJVW6115VEM7",
"stocked_quantity": 1,
"reserved_quantity": 0,
"incoming_quantity": 10
}
]
},
"stock_location": {
"id": "loc_01F0ZXDBAB9KVZWJVW6115VEM7",
"name": "Stock location 1",
"address_id": "addr_01F0ZXDBAB9KVZWJVW6115VEM7",
"created_at": "2021-03-17 11:58:56.975971+01",
"updated_at": "2021-03-17 12:09:59.156058+01"
},
"reservation": {
"id": "res_01F0ZXDBAB9KVZWJVW6115VEM7",
"line_item_id": "li_01F0ZXDBAB9KVZWJVW6115VEM7",
"inventory_item_id": "iitem_320ZXDBAB4WJVW6115VEM7",
"location_id": "loc_01F0ZXDBAB9KVZWJVW6115VEM7",
"quantity": 1
},
"invite": {
"id": "invite_320ZXDBAB4WJVW6115VEM7",
"user_email": "lebron@james.com",
@@ -353,6 +353,61 @@ export const adminHandlers = [
}
),
rest.get("/admin/reservations/", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
reservations: fixtures.list("reservation"),
})
)
}),
rest.post("/admin/reservations/", (req, res, ctx) => {
const body = req.body as Record<string, any>
return res(
ctx.status(200),
ctx.json({
reservation: {
...fixtures.get("reservation"),
...body,
},
})
)
}),
rest.get("/admin/reservations/:id", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
reservation: { ...fixtures.get("reservation"), id: req.params.id },
})
)
}),
rest.post("/admin/reservations/:id", (req, res, ctx) => {
const body = req.body as Record<string, any>
return res(
ctx.status(200),
ctx.json({
reservation: {
...fixtures.get("reservation"),
...body,
id: req.params.id,
},
})
)
}),
rest.delete("/admin/reservations/:id", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
id: req.params.id,
object: "reservation",
deleted: true,
})
)
}),
rest.post("/admin/return-reasons/", (req, res, ctx) => {
const body = req.body as Record<string, any>
return res(
@@ -465,6 +520,61 @@ export const adminHandlers = [
)
}),
rest.get("/admin/stock-locations", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
stock_locations: fixtures.list("stock_location"),
})
)
}),
rest.post("/admin/stock-locations", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
stock_location: {
...fixtures.get("stock_location"),
...(req.body as any),
},
})
)
}),
rest.get("/admin/stock-locations/:id", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
stock_location: {
...fixtures.get("stock_location"),
id: req.params.id,
},
})
)
}),
rest.post("/admin/stock-locations/:id", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
stock_location: {
...fixtures.get("stock_location"),
...(req.body as any),
id: req.params.id,
},
})
)
}),
rest.delete("/admin/stock-locations/:id", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
id: req.params.id,
object: "stock_location",
deleted: true,
})
)
}),
rest.get("/admin/notifications/", (req, res, ctx) => {
return res(
ctx.status(200),
@@ -487,6 +597,112 @@ export const adminHandlers = [
)
}),
// inventory
rest.get("/admin/inventory-items", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
inventory_items: fixtures.list("inventory_item"),
})
)
}),
rest.get("/admin/inventory-items/:id", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
inventory_item: fixtures.get("inventory_item"),
})
)
}),
rest.post("/admin/inventory-items/:id", (req, res, ctx) => {
const body = req.body as Record<string, any>
return res(
ctx.status(200),
ctx.json({
inventory_item: {
...fixtures.get("inventory_item"),
...body,
id: req.params.id,
},
})
)
}),
rest.delete("/admin/inventory-items/:id", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
id: req.params.id,
object: "inventory_item",
deleted: true,
})
)
}),
rest.get("/admin/inventory-items/:id/location-levels", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
inventory_item: {
...fixtures.get("inventory_item"),
id: req.params.id,
},
})
)
}),
rest.post("/admin/inventory-items/:id/location-levels", (req, res, ctx) => {
const body = req.body as Record<string, any>
const { location_levels } = fixtures.get("inventory_item")
return res(
ctx.status(200),
ctx.json({
inventory_item: {
...fixtures.get("inventory_item"),
id: req.params.id,
location_levels: [...location_levels, { ...body, id: "2" }],
},
})
)
}),
rest.post(
"/admin/inventory-items/:id/location-levels/:location_id",
(req, res, ctx) => {
const body = req.body as Record<string, any>
const inventoryItem = fixtures.get("inventory_item")
const locationlevel = { ...inventoryItem.location_levels[0], ...body }
return res(
ctx.status(200),
ctx.json({
inventory_item: {
...fixtures.get("inventory_item"),
id: req.params.id,
location_levels: [locationlevel],
},
})
)
}
),
rest.delete(
"/admin/inventory-items/:id/location-levels/:location_id",
(req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
inventory_item: {
...fixtures.get("inventory_item"),
id: req.params.id,
location_levels: [],
},
})
)
}
),
rest.get("/admin/invites", (req, res, ctx) => {
return res(
ctx.status(200),
@@ -1189,6 +1405,24 @@ export const adminHandlers = [
)
}),
rest.get("/admin/variants/:id/inventory", (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
variant: {
...fixtures.get("product_variant"),
sales_channel_availability: [
{
channel_name: "default channel",
channel_id: "1",
available_quantity: 10,
},
],
},
})
)
}),
rest.get("/admin/users/:id", (req, res, ctx) => {
return res(
ctx.status(200),
@@ -1,7 +1,7 @@
import Medusa from "@medusajs/medusa-js"
import {
QueryClientProvider,
QueryClientProviderProps
QueryClientProviderProps,
} from "@tanstack/react-query"
import React from "react"
@@ -8,6 +8,7 @@ export * from "./customers"
export * from "./discounts"
export * from "./draft-orders"
export * from "./gift-cards"
export * from "./inventory-item"
export * from "./invites"
export * from "./notes"
export * from "./notifications"
@@ -21,6 +22,7 @@ export * from "./publishable-api-keys"
export * from "./regions"
export * from "./return-reasons"
export * from "./returns"
export * from "./reservations"
export * from "./sales-channels"
export * from "./shipping-options"
export * from "./shipping-profiles"
@@ -32,3 +34,4 @@ export * from "./users"
export * from "./variants"
export * from "./payment-collections"
export * from "./payments"
export * from "./stock-locations"
@@ -0,0 +1,2 @@
export * from "./queries"
export * from "./mutations"
@@ -0,0 +1,151 @@
import {
AdminInventoryItemsDeleteRes,
AdminInventoryItemsRes,
AdminPostInventoryItemsInventoryItemReq,
AdminPostInventoryItemsItemLocationLevelsLevelReq,
AdminPostInventoryItemsItemLocationLevelsReq,
} from "@medusajs/medusa"
import { Response } from "@medusajs/medusa-js"
import {
useMutation,
UseMutationOptions,
useQueryClient,
} from "@tanstack/react-query"
import { useMedusa } from "../../../contexts"
import { buildOptions } from "../../utils/buildOptions"
import { adminInventoryItemsKeys } from "./queries"
// inventory item
// update inventory item
export const useAdminUpdateInventoryItem = (
inventoryItemId: string,
options?: UseMutationOptions<
Response<AdminInventoryItemsRes>,
Error,
AdminPostInventoryItemsInventoryItemReq
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
(payload: AdminPostInventoryItemsInventoryItemReq) =>
client.admin.inventoryItems.update(inventoryItemId, payload),
buildOptions(
queryClient,
[adminInventoryItemsKeys.detail(inventoryItemId)],
options
)
)
}
// delete inventory item
export const useAdminDeleteInventoryItem = (
inventoryItemId: string,
options?: UseMutationOptions<
Response<AdminInventoryItemsDeleteRes>,
Error,
void
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
() => client.admin.inventoryItems.delete(inventoryItemId),
buildOptions(
queryClient,
[adminInventoryItemsKeys.detail(inventoryItemId)],
options
)
)
}
// location level
export const useAdminUpdateLocationLevel = (
inventoryItemId: string,
options?: UseMutationOptions<
Response<AdminInventoryItemsRes>,
Error,
AdminPostInventoryItemsItemLocationLevelsLevelReq & {
stockLocationId: string
}
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
(
payload: AdminPostInventoryItemsItemLocationLevelsLevelReq & {
stockLocationId: string
}
) =>
client.admin.inventoryItems.updateLocationLevel(
inventoryItemId,
payload.stockLocationId,
{
incoming_quantity: payload.incoming_quantity,
stocked_quantity: payload.stocked_quantity,
}
),
buildOptions(
queryClient,
[
adminInventoryItemsKeys.detail(inventoryItemId),
adminInventoryItemsKeys.lists(),
],
options
)
)
}
export const useAdminDeleteLocationLevel = (
inventoryItemId: string,
options?: UseMutationOptions<Response<AdminInventoryItemsRes>, Error, string>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
(stockLocationId: string) =>
client.admin.inventoryItems.deleteLocationLevel(
inventoryItemId,
stockLocationId
),
buildOptions(
queryClient,
[
adminInventoryItemsKeys.detail(inventoryItemId),
adminInventoryItemsKeys.lists(),
],
options
)
)
}
export const useAdminCreateLocationLevel = (
inventoryItemId: string,
options?: UseMutationOptions<
Response<AdminInventoryItemsRes>,
Error,
AdminPostInventoryItemsItemLocationLevelsReq
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
(payload: AdminPostInventoryItemsItemLocationLevelsReq) =>
client.admin.inventoryItems.createLocationLevel(inventoryItemId, payload),
buildOptions(
queryClient,
[
adminInventoryItemsKeys.detail(inventoryItemId),
adminInventoryItemsKeys.lists(),
],
options
)
)
}
@@ -0,0 +1,79 @@
import {
AdminGetStockLocationsParams,
AdminInventoryItemsListWithVariantsAndLocationLevelsRes,
AdminInventoryItemsLocationLevelsRes,
AdminInventoryItemsRes,
} 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_INVENTORY_ITEMS_QUERY_KEY = `admin_inventory_items` as const
export const adminInventoryItemsKeys = queryKeysFactory(
ADMIN_INVENTORY_ITEMS_QUERY_KEY
)
type InventoryItemsQueryKeys = typeof adminInventoryItemsKeys
export const useAdminInventoryItems = (
query?: AdminGetStockLocationsParams,
options?: UseQueryOptionsWrapper<
Response<AdminInventoryItemsListWithVariantsAndLocationLevelsRes>,
Error,
ReturnType<InventoryItemsQueryKeys["list"]>
>
) => {
const { client } = useMedusa()
const { data, ...rest } = useQuery(
adminInventoryItemsKeys.list(query),
() => client.admin.inventoryItems.list(query),
{ ...options }
)
return { ...data, ...rest } as const
}
export const useAdminInventoryItem = (
inventoryItemId: string,
query?: AdminGetStockLocationsParams,
options?: UseQueryOptionsWrapper<
Response<AdminInventoryItemsRes>,
Error,
ReturnType<InventoryItemsQueryKeys["detail"]>
>
) => {
const { client } = useMedusa()
const { data, ...rest } = useQuery(
adminInventoryItemsKeys.detail(inventoryItemId),
() => client.admin.inventoryItems.retrieve(inventoryItemId, query),
{ ...options }
)
return { ...data, ...rest } as const
}
export const useAdminInventoryItemLocationLevels = (
inventoryItemId: string,
query?: AdminGetStockLocationsParams,
options?: UseQueryOptionsWrapper<
Response<AdminInventoryItemsLocationLevelsRes>,
Error,
ReturnType<InventoryItemsQueryKeys["detail"]>
>
) => {
const { client } = useMedusa()
const { data, ...rest } = useQuery(
adminInventoryItemsKeys.detail(inventoryItemId),
() =>
client.admin.inventoryItems.listLocationLevels(inventoryItemId, query),
{ ...options }
)
return { ...data, ...rest } as const
}
@@ -0,0 +1,2 @@
export * from "./mutations"
export * from "./queries"
@@ -0,0 +1,75 @@
import {
AdminPostReservationsReq,
AdminPostReservationsReservationReq,
AdminReservationsDeleteRes,
AdminReservationsRes,
} from "@medusajs/medusa"
import { Response } from "@medusajs/medusa-js/src"
import {
useMutation,
UseMutationOptions,
useQueryClient,
} from "@tanstack/react-query"
import { useMedusa } from "../../../contexts"
import { buildOptions } from "../../utils/buildOptions"
import { adminReservationsKeys } from "./queries"
export const useAdminCreateReservation = (
options?: UseMutationOptions<
Response<AdminReservationsRes>,
Error,
AdminPostReservationsReq
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
(payload: AdminPostReservationsReq) =>
client.admin.reservations.create(payload),
buildOptions(queryClient, [adminReservationsKeys.list()], options)
)
}
export const useAdminUpdateReservation = (
id: string,
options?: UseMutationOptions<
Response<AdminReservationsRes>,
Error,
AdminPostReservationsReq
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
(payload: AdminPostReservationsReservationReq) =>
client.admin.reservations.update(id, payload),
buildOptions(
queryClient,
[adminReservationsKeys.lists(), adminReservationsKeys.detail(id)],
options
)
)
}
export const useAdminDeleteReservation = (
id: string,
options?: UseMutationOptions<
Response<AdminReservationsDeleteRes>,
Error,
void
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
() => client.admin.reservations.delete(id),
buildOptions(
queryClient,
[adminReservationsKeys.lists(), adminReservationsKeys.detail(id)],
options
)
)
}
@@ -0,0 +1,56 @@
import {
AdminGetReservationsParams,
AdminReservationsListRes,
AdminReservationsRes,
} 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_RESERVATIONS_QUERY_KEY = `admin_stock_locations` as const
export const adminReservationsKeys = queryKeysFactory(
ADMIN_RESERVATIONS_QUERY_KEY
)
type ReservationsQueryKeys = typeof adminReservationsKeys
export const useAdminReservations = (
query?: AdminGetReservationsParams,
options?: UseQueryOptionsWrapper<
Response<AdminReservationsListRes>,
Error,
ReturnType<ReservationsQueryKeys["list"]>
>
) => {
const { client } = useMedusa()
const { data, ...rest } = useQuery(
adminReservationsKeys.list(query),
() => client.admin.reservations.list(query),
{ ...options }
)
return { ...data, ...rest } as const
}
export const useAdminReservation = (
id: string,
options?: UseQueryOptionsWrapper<
Response<AdminReservationsRes>,
Error,
ReturnType<ReservationsQueryKeys["detail"]>
>
) => {
const { client } = useMedusa()
const { data, ...rest } = useQuery(
adminReservationsKeys.detail(id),
() => client.admin.reservations.retrieve(id),
options
)
return { ...data, ...rest } as const
}
@@ -16,6 +16,7 @@ import {
import { useMedusa } from "../../../contexts"
import { buildOptions } from "../../utils/buildOptions"
import { adminProductKeys } from "../products"
import { adminStockLocationsKeys } from "../stock-locations"
import { adminSalesChannelsKeys } from "./queries"
/**
@@ -162,3 +163,73 @@ export const useAdminAddProductsToSalesChannel = (
)
)
}
/**
* Add a location to a sales channel
* @experimental This feature is under development and may change in the future.
* To use this feature please install the stock location in your medusa backend project.
* @description Add a location to a sales channel
* @param options
*/
export const useAdminAddLocationToSalesChannel = (
options?: UseMutationOptions<
Response<AdminSalesChannelsRes>,
Error,
{
sales_channel_id: string
location_id: string
}
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(({ sales_channel_id, location_id }) => {
return client.admin.salesChannels.addLocation(sales_channel_id, {
location_id,
})
}, buildOptions(
queryClient,
[
adminSalesChannelsKeys.lists(),
adminSalesChannelsKeys.details(),
adminStockLocationsKeys.all
],
options
)
)
}
/**
* Remove a location from a sales channel
* @experimental This feature is under development and may change in the future.
* To use this feature please install the stock location in your medusa backend project.
* @description Remove a location from a sales channel
* @param options
*/
export const useAdminRemoveLocationFromSalesChannel = (
options?: UseMutationOptions<
Response<AdminSalesChannelsRes>,
Error,
{
sales_channel_id: string
location_id: string
}
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(({ sales_channel_id, location_id }) => {
return client.admin.salesChannels.removeLocation(sales_channel_id, {
location_id,
})
}, buildOptions(
queryClient,
[
adminSalesChannelsKeys.lists(),
adminSalesChannelsKeys.details(),
adminStockLocationsKeys.all
],
options
)
)
}
@@ -0,0 +1,2 @@
export * from "./queries"
export * from "./mutations"
@@ -0,0 +1,74 @@
import {
AdminPostStockLocationsReq,
AdminStockLocationsDeleteRes,
AdminStockLocationsRes,
} from "@medusajs/medusa"
import { Response } from "@medusajs/medusa-js"
import {
useMutation,
UseMutationOptions,
useQueryClient,
} from "@tanstack/react-query"
import { useMedusa } from "../../../contexts"
import { buildOptions } from "../../utils/buildOptions"
import { adminStockLocationsKeys } from "./queries"
export const useAdminCreateStockLocation = (
options?: UseMutationOptions<
Response<AdminStockLocationsRes>,
Error,
AdminPostStockLocationsReq
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
(payload: AdminPostStockLocationsReq) =>
client.admin.stockLocations.create(payload),
buildOptions(queryClient, [adminStockLocationsKeys.lists()], options)
)
}
export const useAdminUpdateStockLocation = (
id: string,
options?: UseMutationOptions<
Response<AdminStockLocationsRes>,
Error,
AdminPostStockLocationsReq
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
(payload: AdminPostStockLocationsReq) =>
client.admin.stockLocations.update(id, payload),
buildOptions(
queryClient,
[adminStockLocationsKeys.lists(), adminStockLocationsKeys.detail(id)],
options
)
)
}
export const useAdminDeleteStockLocation = (
id: string,
options?: UseMutationOptions<
Response<AdminStockLocationsDeleteRes>,
Error,
void
>
) => {
const { client } = useMedusa()
const queryClient = useQueryClient()
return useMutation(
() => client.admin.stockLocations.delete(id),
buildOptions(
queryClient,
[adminStockLocationsKeys.lists(), adminStockLocationsKeys.detail(id)],
options
)
)
}
@@ -0,0 +1,56 @@
import {
AdminGetStockLocationsParams,
AdminStockLocationsListRes,
AdminStockLocationsRes,
} 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_STOCK_LOCATIONS_QUERY_KEY = `admin_stock_locations` as const
export const adminStockLocationsKeys = queryKeysFactory(
ADMIN_STOCK_LOCATIONS_QUERY_KEY
)
type StockLocationsQueryKeys = typeof adminStockLocationsKeys
export const useAdminStockLocations = (
query?: AdminGetStockLocationsParams,
options?: UseQueryOptionsWrapper<
Response<AdminStockLocationsListRes>,
Error,
ReturnType<StockLocationsQueryKeys["list"]>
>
) => {
const { client } = useMedusa()
const { data, ...rest } = useQuery(
adminStockLocationsKeys.list(query),
() => client.admin.stockLocations.list(query),
options
)
return { ...data, ...rest } as const
}
export const useAdminStockLocation = (
id: string,
options?: UseQueryOptionsWrapper<
Response<AdminStockLocationsRes>,
Error,
ReturnType<StockLocationsQueryKeys["detail"]>
>
) => {
const { client } = useMedusa()
const { data, ...rest } = useQuery(
adminStockLocationsKeys.detail(id),
() => client.admin.stockLocations.retrieve(id),
options
)
return { ...data, ...rest } as const
}
@@ -1,4 +1,8 @@
import { AdminGetVariantsParams, AdminVariantsListRes } from "@medusajs/medusa"
import {
AdminGetVariantsParams,
AdminGetVariantsVariantInventoryRes,
AdminVariantsListRes,
} from "@medusajs/medusa"
import { Response } from "@medusajs/medusa-js"
import { useQuery } from "@tanstack/react-query"
import { useMedusa } from "../../../contexts"
@@ -27,3 +31,20 @@ export const useAdminVariants = (
)
return { ...data, ...rest } as const
}
export const useAdminVariantsInventory = (
id: string,
options?: UseQueryOptionsWrapper<
Response<AdminGetVariantsVariantInventoryRes>,
Error,
ReturnType<VariantQueryKeys["detail"]>
>
) => {
const { client } = useMedusa()
const { data, ...rest } = useQuery(
adminVariantKeys.detail(id),
() => client.admin.variants.getInventory(id),
options
)
return { ...data, ...rest } as const
}
@@ -0,0 +1,144 @@
import {
useAdminUpdateInventoryItem,
useAdminDeleteInventoryItem,
useAdminUpdateLocationLevel,
useAdminDeleteLocationLevel,
useAdminCreateLocationLevel,
} from "../../../../src/"
import { renderHook } from "@testing-library/react-hooks"
import { createWrapper } from "../../../utils"
describe("useAdminUpdateInventoryItem hook", () => {
test("updates an inventory item", async () => {
const payload = {
sku: "test-sku",
}
const { result, waitFor } = renderHook(
() => useAdminUpdateInventoryItem("inventory-item-id"),
{
wrapper: createWrapper(),
}
)
result.current.mutate(payload)
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data.inventory_item).toEqual(
expect.objectContaining({
id: "inventory-item-id",
sku: "test-sku",
})
)
})
})
describe("useAdminDeleteInventoryItem hook", () => {
test("Deletes an inventory item", async () => {
const { result, waitFor } = renderHook(
() => useAdminDeleteInventoryItem("inventory-item-id"),
{
wrapper: createWrapper(),
}
)
result.current.mutate()
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data).toEqual(
expect.objectContaining({
id: "inventory-item-id",
deleted: true,
})
)
})
})
describe("useAdminUpdateLocationLevel hook", () => {
test("Updates a location level", async () => {
const payload = {
incoming_quantity: 10,
}
const { result, waitFor } = renderHook(
() => useAdminUpdateLocationLevel("inventory-item-id"),
{
wrapper: createWrapper(),
}
)
result.current.mutate({ ...payload, stockLocationId: "location_id"})
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data.inventory_item).toEqual(
expect.objectContaining({
id: "inventory-item-id",
location_levels: [
expect.objectContaining({
incoming_quantity: 10,
}),
],
})
)
})
})
describe("useAdminDeleteLocationLevel hook", () => {
test("removes a location level", async () => {
const { result, waitFor } = renderHook(
() => useAdminDeleteLocationLevel("inventory-item-id"),
{
wrapper: createWrapper(),
}
)
result.current.mutate("location_id")
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data.inventory_item).toEqual(
expect.objectContaining({
id: "inventory-item-id",
location_levels: [],
})
)
})
})
describe("useAdminCreateLocationLevel hook", () => {
test("creates a location level", async () => {
const payload = {
location_id: "loc_1",
incoming_quantity: 10,
stocked_quantity: 10,
}
const { result, waitFor } = renderHook(
() => useAdminCreateLocationLevel("inventory-item-id"),
{
wrapper: createWrapper(),
}
)
result.current.mutate(payload)
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data.inventory_item).toEqual(
expect.objectContaining({
id: "inventory-item-id",
location_levels: expect.arrayContaining([
expect.objectContaining({ ...payload }),
]),
})
)
})
})
@@ -0,0 +1,75 @@
import {
useAdminInventoryItem,
useAdminInventoryItemLocationLevels,
useAdminInventoryItems,
useAdminPriceList,
useAdminPriceLists,
} from "../../../../src"
import { renderHook } from "@testing-library/react-hooks"
import { fixtures } from "../../../../mocks/data"
import { createWrapper } from "../../../utils"
describe("useAdminInventoryItems hook", () => {
test("returns a list of inventory items", async () => {
const inventoryItems = fixtures.list("inventory_item")
const { result, waitFor } = renderHook(() => useAdminInventoryItems(), {
wrapper: createWrapper(),
})
await waitFor(() => result.current.isSuccess)
expect(result.current.response.status).toEqual(200)
expect(result.current.inventory_items).toEqual(inventoryItems)
})
})
describe("useAdminInventoryItem hook", () => {
test("returns a single inventory item", async () => {
const inventoryItem = fixtures.get("inventory_item")
const { result, waitFor } = renderHook(
() => useAdminInventoryItem(inventoryItem.id),
{
wrapper: createWrapper(),
}
)
await waitFor(() => result.current.isSuccess)
expect(result.current.response.status).toEqual(200)
expect(result.current.inventory_item).toEqual(inventoryItem)
})
})
describe("useAdminInventoryItem hook", () => {
test("returns a location levels for an inventory item", async () => {
const inventoryItem = fixtures.get("inventory_item")
const { result, waitFor } = renderHook(
() => useAdminInventoryItemLocationLevels(inventoryItem.id),
{
wrapper: createWrapper(),
}
)
await waitFor(() => result.current.isSuccess)
expect(result.current.response.status).toEqual(200)
expect(result.current.inventory_item).toEqual(inventoryItem)
})
})
describe("useAdminPriceList hook", () => {
test("returns a price list", async () => {
const priceList = fixtures.get("price_list")
const { result, waitFor } = renderHook(
() => useAdminPriceList(priceList.id),
{
wrapper: createWrapper(),
}
)
await waitFor(() => result.current.isSuccess)
expect(result.current.response.status).toEqual(200)
expect(result.current.price_list).toEqual(priceList)
})
})
@@ -0,0 +1,88 @@
import {
useAdminCreateShippingProfile,
useAdminUpdateShippingProfile,
useAdminDeleteShippingProfile,
useAdminCreateReservation,
useAdminUpdateReservation,
useAdminDeleteReservation,
} from "../../../../src/"
import { renderHook } from "@testing-library/react-hooks"
import { fixtures } from "../../../../mocks/data"
import { createWrapper } from "../../../utils"
describe("useAdminCreateShippingProfile hook", () => {
test("creates a shipping profile and returns it", async () => {
const reservationPayload = {
location_id: "loc_1",
inventory_item_id: "inv_1",
quantity: 2,
}
const { result, waitFor } = renderHook(() => useAdminCreateReservation(), {
wrapper: createWrapper(),
})
result.current.mutate(reservationPayload)
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data.reservation).toEqual(
expect.objectContaining({
...fixtures.get("reservation"),
...reservationPayload,
})
)
})
})
describe("useAdminUpdateShippingProfile hook", () => {
test("updates a shipping profile and returns it", async () => {
const reservationPayload = {
quantity: 3,
}
const { result, waitFor } = renderHook(
() => useAdminUpdateReservation(fixtures.get("reservation").id),
{
wrapper: createWrapper(),
}
)
result.current.mutate(reservationPayload)
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data.reservation).toEqual(
expect.objectContaining({
...fixtures.get("reservation"),
quantity: 3,
})
)
})
})
describe("useAdminDeleteShippingProfile hook", () => {
test("deletes a shipping profile", async () => {
const { result, waitFor } = renderHook(
() => useAdminDeleteReservation(fixtures.get("reservation").id),
{
wrapper: createWrapper(),
}
)
result.current.mutate()
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data).toEqual(
expect.objectContaining({
id: fixtures.get("reservation").id,
object: "reservation",
deleted: true,
})
)
})
})
@@ -0,0 +1,35 @@
import { useAdminReservation, useAdminReservations } from "../../../../src"
import { renderHook } from "@testing-library/react-hooks"
import { fixtures } from "../../../../mocks/data"
import { createWrapper } from "../../../utils"
describe("useAdminShippingProfiles hook", () => {
test("returns a list of shipping profiles", async () => {
const reservations = fixtures.list("reservation")
const { result, waitFor } = renderHook(() => useAdminReservations(), {
wrapper: createWrapper(),
})
await waitFor(() => result.current.isSuccess)
expect(result.current.response.status).toEqual(200)
expect(result.current.reservations).toEqual(reservations)
})
})
describe("useAdminShippingProfile hook", () => {
test("returns a shipping profile", async () => {
const reservation = fixtures.get("reservation")
const { result, waitFor } = renderHook(
() => useAdminReservation(reservation.id),
{
wrapper: createWrapper(),
}
)
await waitFor(() => result.current.isSuccess)
expect(result.current.response.status).toEqual(200)
expect(result.current.reservation).toEqual(reservation)
})
})
@@ -97,15 +97,15 @@ describe("useAdminDeleteProductsFromSalesChannel hook", () => {
{ wrapper: createWrapper() }
)
result.current.mutate({ product_ids: [
{ id: productId }
]})
result.current.mutate({ product_ids: [{ id: productId }] })
await waitFor(() => result.current.isSuccess)
expect(result.current.data).toEqual(expect.objectContaining({
sales_channel: fixtures.get("sales_channel"),
}))
expect(result.current.data).toEqual(
expect.objectContaining({
sales_channel: fixtures.get("sales_channel"),
})
)
})
})
@@ -119,14 +119,14 @@ describe("useAdminAddProductsToSalesChannel hook", () => {
{ wrapper: createWrapper() }
)
result.current.mutate({ product_ids: [
{ id: productId }
]})
result.current.mutate({ product_ids: [{ id: productId }] })
await waitFor(() => result.current.isSuccess)
expect(result.current.data).toEqual(expect.objectContaining({
sales_channel: fixtures.get("sales_channel"),
}))
expect(result.current.data).toEqual(
expect.objectContaining({
sales_channel: fixtures.get("sales_channel"),
})
)
})
})
@@ -0,0 +1,87 @@
import { renderHook } from "@testing-library/react-hooks"
import { fixtures } from "../../../../mocks/data"
import {
useAdminCreateStockLocation,
useAdminDeleteStockLocation,
useAdminUpdateStockLocation,
} from "../../../../src"
import { createWrapper } from "../../../utils"
describe("useAdminUpdateStockLocation hook", () => {
test("updates a stock location", async () => {
const payload = {
name: "updated name",
}
const { result, waitFor } = renderHook(
() => useAdminUpdateStockLocation("stock-location-id"),
{
wrapper: createWrapper(),
}
)
result.current.mutate(payload)
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data.stock_location).toEqual(
expect.objectContaining({
id: "stock-location-id",
name: "updated name",
})
)
})
})
describe("useAdminCreateStockLocation hook", () => {
test("creates a stock location", async () => {
const locationFixture = fixtures.get("stock_location")
const payload = {
name: "updated name",
}
const { result, waitFor } = renderHook(
() => useAdminCreateStockLocation(),
{
wrapper: createWrapper(),
}
)
result.current.mutate(payload)
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data.stock_location).toEqual(
expect.objectContaining({
...locationFixture,
...payload,
})
)
})
})
describe("useAdminDeleteStockLocation hook", () => {
test("deletes a stock location", async () => {
const { result, waitFor } = renderHook(
() => useAdminDeleteStockLocation("stock-location-id"),
{
wrapper: createWrapper(),
}
)
result.current.mutate()
await waitFor(() => result.current.isSuccess)
expect(result.current.data.response.status).toEqual(200)
expect(result.current.data).toEqual(
expect.objectContaining({
id: "stock-location-id",
object: "stock_location",
deleted: true,
})
)
})
})
@@ -0,0 +1,40 @@
import { renderHook } from "@testing-library/react-hooks"
import { fixtures } from "../../../../mocks/data"
import { useAdminStockLocation, useAdminStockLocations } from "../../../../src"
import { createWrapper } from "../../../utils"
describe("useAdminUpdateStockLocation hook", () => {
test("gets a stock location", async () => {
const stockLocation = fixtures.get("stock_location")
const { result, waitFor } = renderHook(
() => useAdminStockLocation("stock-location-id"),
{
wrapper: createWrapper(),
}
)
await waitFor(() => result.current.isSuccess)
expect(result.current.response.status).toEqual(200)
expect(result.current.stock_location).toEqual(
expect.objectContaining({
...stockLocation,
id: "stock-location-id",
})
)
})
})
describe("useAdminUpdateStockLocations hook", () => {
test("lists stock locations", async () => {
const stockLocation = fixtures.list("stock_location")
const { result, waitFor } = renderHook(() => useAdminStockLocations(), {
wrapper: createWrapper(),
})
await waitFor(() => result.current.isSuccess)
expect(result.current.response.status).toEqual(200)
expect(result.current.stock_locations).toEqual(stockLocation)
})
})
@@ -1,4 +1,4 @@
import { useAdminVariants } from "../../../../src"
import { useAdminVariants, useAdminVariantsInventory } from "../../../../src"
import { renderHook } from "@testing-library/react-hooks"
import { fixtures } from "../../../../mocks/data"
import { createWrapper } from "../../../utils"
@@ -16,3 +16,29 @@ describe("useAdminVariants hook", () => {
expect(result.current.variants).toEqual(variants)
})
})
describe("useAdminVariants hook", () => {
test("returns a variant with saleschannel locations", async () => {
const variant = fixtures.get("product_variant")
const { result, waitFor } = renderHook(
() => useAdminVariantsInventory(variant.id),
{
wrapper: createWrapper(),
}
)
await waitFor(() => result.current.isSuccess)
expect(result.current.response.status).toEqual(200)
expect(result.current.variant).toEqual({
...variant,
sales_channel_availability: [
{
channel_name: "default channel",
channel_id: "1",
available_quantity: 10,
},
],
})
})
})