diff --git a/.changeset/tough-peas-cough.md b/.changeset/tough-peas-cough.md new file mode 100644 index 0000000000..4d42ca090a --- /dev/null +++ b/.changeset/tough-peas-cough.md @@ -0,0 +1,5 @@ +--- +"@medusajs/dashboard": patch +--- + +chore(dashboard): migrate inventory location levels table diff --git a/packages/admin/dashboard/src/hooks/api/inventory.tsx b/packages/admin/dashboard/src/hooks/api/inventory.tsx index 02bb3fd128..ae2dc01522 100644 --- a/packages/admin/dashboard/src/hooks/api/inventory.tsx +++ b/packages/admin/dashboard/src/hooks/api/inventory.tsx @@ -176,7 +176,10 @@ export const useInventoryItemLevels = ( ) => { const { data, ...rest } = useQuery({ queryFn: () => sdk.admin.inventoryItem.listLevels(inventoryItemId, query), - queryKey: inventoryItemLevelsQueryKeys.detail(inventoryItemId), + queryKey: inventoryItemLevelsQueryKeys.list({ + ...(query || {}), + inventoryItemId, + }), ...options, }) diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/location-actions.tsx b/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/location-actions.tsx deleted file mode 100644 index 581606b154..0000000000 --- a/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/location-actions.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { PencilSquare, Trash } from "@medusajs/icons" - -import { InventoryTypes } from "@medusajs/types" -import { usePrompt } from "@medusajs/ui" -import { useTranslation } from "react-i18next" -import { ActionMenu } from "../../../../../components/common/action-menu" -import { useDeleteInventoryItemLevel } from "../../../../../hooks/api/inventory" - -export const LocationActions = ({ - level, -}: { - level: InventoryTypes.InventoryLevelDTO -}) => { - const { t } = useTranslation() - const prompt = usePrompt() - const { mutateAsync } = useDeleteInventoryItemLevel( - level.inventory_item_id, - level.location_id - ) - - const handleDelete = async () => { - const res = await prompt({ - title: t("general.areYouSure"), - description: t("inventory.deleteWarning"), - confirmText: t("actions.delete"), - cancelText: t("actions.cancel"), - }) - - if (!res) { - return - } - - await mutateAsync() - } - - return ( - , - label: t("actions.edit"), - to: `locations/${level.location_id}`, - }, - ], - }, - { - actions: [ - { - icon: , - label: t("actions.delete"), - onClick: handleDelete, - disabled: - level.reserved_quantity > 0 || level.stocked_quantity > 0, - }, - ], - }, - ]} - /> - ) -} diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/location-list-table.tsx b/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/location-list-table.tsx index 648698fd36..8503ca2474 100644 --- a/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/location-list-table.tsx +++ b/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/location-list-table.tsx @@ -1,18 +1,19 @@ -import { _DataTable } from "../../../../../components/table/data-table" +import { DataTable } from "../../../../../components/data-table" import { useInventoryItemLevels } from "../../../../../hooks/api/inventory" -import { useDataTable } from "../../../../../hooks/use-data-table" import { useLocationListTableColumns } from "./use-location-list-table-columns" import { useLocationLevelTableQuery } from "./use-location-list-table-query" const PAGE_SIZE = 20 +const PREFIX = "invlvl" export const ItemLocationListTable = ({ inventory_item_id, }: { inventory_item_id: string }) => { - const { searchParams, raw } = useLocationLevelTableQuery({ + const searchParams = useLocationLevelTableQuery({ pageSize: PAGE_SIZE, + prefix: PREFIX, }) const { @@ -23,33 +24,26 @@ export const ItemLocationListTable = ({ error, } = useInventoryItemLevels(inventory_item_id, { ...searchParams, - fields: "*stock_locations", + fields: "+stock_locations.id,+stock_locations.name", }) const columns = useLocationListTableColumns() - const { table } = useDataTable({ - data: inventory_levels ?? [], - columns, - count, - enablePagination: true, - getRowId: (row) => row.id, - pageSize: PAGE_SIZE, - }) - if (isError) { throw error } return ( - <_DataTable - table={table} + row.id} isLoading={isLoading} - pagination - queryObject={raw} + prefix={PREFIX} + layout="fill" + enableSearch={false} /> ) } diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/use-location-list-table-columns.tsx b/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/use-location-list-table-columns.tsx index ec01398b19..82db6d8bcb 100644 --- a/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/use-location-list-table-columns.tsx +++ b/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/use-location-list-table-columns.tsx @@ -1,10 +1,17 @@ import { InventoryTypes, StockLocationDTO } from "@medusajs/types" +import { PencilSquare, Trash } from "@medusajs/icons" -import { createColumnHelper } from "@tanstack/react-table" import { useMemo } from "react" +import { createDataTableColumnHelper, toast, usePrompt } from "@medusajs/ui" import { useTranslation } from "react-i18next" import { PlaceholderCell } from "../../../../../components/table/table-cells/common/placeholder-cell" -import { LocationActions } from "./location-actions" +import { + inventoryItemLevelsQueryKeys, + inventoryItemsQueryKeys, +} from "../../../../../hooks/api" +import { sdk } from "../../../../../lib/client" +import { queryClient } from "../../../../../lib/query-client" +import { useNavigate } from "react-router-dom" /** * Adds missing properties to the InventoryLevelDTO type. @@ -16,10 +23,45 @@ interface ExtendedLocationLevel extends InventoryTypes.InventoryLevelDTO { available_quantity: number } -const columnHelper = createColumnHelper() +const columnHelper = createDataTableColumnHelper() export const useLocationListTableColumns = () => { const { t } = useTranslation() + const navigate = useNavigate() + + const prompt = usePrompt() + + const handleDelete = async (level: ExtendedLocationLevel) => { + const res = await prompt({ + title: t("general.areYouSure"), + description: t("inventory.deleteWarning"), + confirmText: t("actions.delete"), + cancelText: t("actions.cancel"), + }) + + if (!res) { + return + } + + try { + await sdk.admin.inventoryItem.deleteLevel( + level.inventory_item_id, + level.location_id + ) + + queryClient.invalidateQueries({ + queryKey: inventoryItemsQueryKeys.lists(), + }) + queryClient.invalidateQueries({ + queryKey: inventoryItemsQueryKeys.detail(level.inventory_item_id), + }) + queryClient.invalidateQueries({ + queryKey: inventoryItemLevelsQueryKeys.detail(level.inventory_item_id), + }) + } catch (e) { + toast.error(e.message) + } + } return useMemo( () => [ @@ -54,6 +96,7 @@ export const useLocationListTableColumns = () => { ) }, + enableSorting: true, }), columnHelper.accessor("stocked_quantity", { header: t("fields.inStock"), @@ -70,6 +113,7 @@ export const useLocationListTableColumns = () => { ) }, + enableSorting: true, }), columnHelper.accessor("available_quantity", { header: t("inventory.available"), @@ -87,9 +131,31 @@ export const useLocationListTableColumns = () => { ) }, }), - columnHelper.display({ - id: "actions", - cell: ({ row }) => , + columnHelper.action({ + actions: (ctx) => { + const level = ctx.row.original + return [ + [ + { + icon: , + label: t("actions.edit"), + + onClick: (row) => { + navigate(`locations/${level.location_id}`) + }, + }, + ], + [ + { + icon: , + label: t("actions.delete"), + onClick: () => handleDelete(level), + disabled: + level.reserved_quantity > 0 || level.stocked_quantity > 0, + }, + ], + ] + }, }), ], [t] diff --git a/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/use-location-list-table-query.tsx b/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/use-location-list-table-query.tsx index 19f74696ae..ba0115cc8d 100644 --- a/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/use-location-list-table-query.tsx +++ b/packages/admin/dashboard/src/routes/inventory/inventory-detail/components/location-levels-table/use-location-list-table-query.tsx @@ -1,3 +1,4 @@ +import { HttpTypes } from "@medusajs/types" import { useQueryParams } from "../../../../../hooks/use-query-params" export const useLocationLevelTableQuery = ({ @@ -7,38 +8,25 @@ export const useLocationLevelTableQuery = ({ pageSize?: number prefix?: string }) => { - const raw = useQueryParams( + const queryObject = useQueryParams( [ - "id", + "order", + "offset", "location_id", "stocked_quantity", "reserved_quantity", "incoming_quantity", - "available_quantity", - "*stock_locations", ], prefix ) - const { reserved_quantity, stocked_quantity, available_quantity, ...params } = - raw + const { offset, ...rest } = queryObject - const searchParams = { + const searchParams: HttpTypes.AdminInventoryLevelFilters = { limit: pageSize, - reserved_quantity: reserved_quantity - ? JSON.parse(reserved_quantity) - : undefined, - stocked_quantity: stocked_quantity - ? JSON.parse(stocked_quantity) - : undefined, - available_quantity: available_quantity - ? JSON.parse(available_quantity) - : undefined, - ...params, + offset: offset ? Number(offset) : 0, + ...rest, } - return { - searchParams, - raw, - } + return searchParams } diff --git a/packages/admin/dashboard/src/routes/orders/order-create-fulfillment/components/order-create-fulfillment-form/order-create-fulfillment-form.tsx b/packages/admin/dashboard/src/routes/orders/order-create-fulfillment/components/order-create-fulfillment-form/order-create-fulfillment-form.tsx index 0df6dc9d4a..609c4ae546 100644 --- a/packages/admin/dashboard/src/routes/orders/order-create-fulfillment/components/order-create-fulfillment-form/order-create-fulfillment-form.tsx +++ b/packages/admin/dashboard/src/routes/orders/order-create-fulfillment/components/order-create-fulfillment-form/order-create-fulfillment-form.tsx @@ -15,7 +15,6 @@ import { } from "../../../../../components/modals" import { KeyboundForm } from "../../../../../components/utilities/keybound-form" import { useCreateOrderFulfillment } from "../../../../../hooks/api/orders" -import { useStockLocations } from "../../../../../hooks/api/stock-locations" import { getFulfillableQuantity } from "../../../../../lib/order-item" import { CreateFulfillmentSchema } from "./constants" import { OrderCreateFulfillmentItem } from "./order-create-fulfillment-item" @@ -24,6 +23,9 @@ import { useShippingOptions, } from "../../../../../hooks/api" import { getReservationsLimitCount } from "../../../../../lib/orders" +import { sdk } from "../../../../../lib/client" +import { useComboboxData } from "../../../../../hooks/use-combobox-data" +import { Combobox } from "../../../../../components/inputs/combobox" type OrderCreateFulfillmentFormProps = { order: AdminOrder @@ -45,6 +47,16 @@ export function OrderCreateFulfillmentForm({ limit: getReservationsLimitCount(order), }) + const stockLocations = useComboboxData({ + queryFn: (params) => sdk.admin.stockLocation.list(params), + queryKey: ["stock_locations"], + getOptions: (data) => + data.stock_locations.map((location) => ({ + label: location.name, + value: location.id, + })), + }) + const itemReservedQuantitiesMap = useMemo( () => new Map((reservations || []).map((r) => [r.line_item_id, r.quantity])), @@ -78,8 +90,6 @@ export function OrderCreateFulfillmentForm({ control: form.control, }) - const { stock_locations = [] } = useStockLocations() - const { shipping_options = [], isLoading: isShippingOptionsLoading } = useShippingOptions({ stock_location_id: selectedLocationId, @@ -155,7 +165,7 @@ export function OrderCreateFulfillmentForm({ }) useEffect(() => { - if (stock_locations?.length && shipping_options?.length) { + if (shipping_options?.length) { const initialShippingOptionId = order.shipping_methods?.[0]?.shipping_option_id @@ -176,7 +186,7 @@ export function OrderCreateFulfillmentForm({ } // else -> TODO: what if original shipping option is deleted? } } - }, [stock_locations?.length, shipping_options?.length]) + }, [shipping_options]) const fulfilledQuantityArray = (order.items || []).map( (item) => @@ -234,7 +244,7 @@ export function OrderCreateFulfillmentForm({ { + render={({ field: { ...field } }) => { return (
@@ -246,21 +256,15 @@ export function OrderCreateFulfillmentForm({
- +