Clean up product typings (#7663)

There are a lot of issues in the admin after applying the correct typings, but fixing those should be done gradually, it's better to keep it out of this PR
This commit is contained in:
Stevche Radevski authored and GitHub committed 2024-06-11 09:28:40 +00:00
1 parent f3bf8c73a3
commit 8e2a42b786
88 files changed
+1205 -990

No files matched your search

@@ -864,7 +864,7 @@ medusaIntegrationTestRunner({
it("successfully creates, updates and deletes an inventory item link from a variant", async () => { it("successfully creates, updates and deletes an inventory item link from a variant", async () => {
const res = await api.post( const res = await api.post(
`/admin/products/${baseProduct.id}/variants/inventory-items/batch`, `/admin/products/${inventoryProduct.id}/variants/inventory-items/batch`,
{ {
create: [ create: [
{ {
@@ -894,7 +894,7 @@ medusaIntegrationTestRunner({
const createdLinkVariant = ( const createdLinkVariant = (
await api.get( await api.get(
`/admin/products/${baseProduct.id}/variants/${inventoryVariant3.id}?fields=inventory_items.inventory.*,inventory_items.*`, `/admin/products/${inventoryProduct.id}/variants/${inventoryVariant3.id}?fields=inventory_items.inventory.*,inventory_items.*`,
adminHeaders adminHeaders
) )
).data.variant ).data.variant
@@ -911,7 +911,7 @@ medusaIntegrationTestRunner({
const updatedLinkVariant = ( const updatedLinkVariant = (
await api.get( await api.get(
`/admin/products/${baseProduct.id}/variants/${inventoryVariant1.id}?fields=inventory_items.inventory.*,inventory_items.*`, `/admin/products/${inventoryProduct.id}/variants/${inventoryVariant1.id}?fields=inventory_items.inventory.*,inventory_items.*`,
adminHeaders adminHeaders
) )
).data.variant ).data.variant
@@ -928,7 +928,7 @@ medusaIntegrationTestRunner({
const deletedLinkVariant = ( const deletedLinkVariant = (
await api.get( await api.get(
`/admin/products/${baseProduct.id}/variants/${inventoryVariant2.id}?fields=inventory_items.inventory.*,inventory_items.*`, `/admin/products/${inventoryProduct.id}/variants/${inventoryVariant2.id}?fields=inventory_items.inventory.*,inventory_items.*`,
adminHeaders adminHeaders
) )
).data.variant ).data.variant
@@ -1,10 +1,10 @@
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { ProductCollectionDTO } from "@medusajs/types"
import { PlaceholderCell } from "../../common/placeholder-cell" import { PlaceholderCell } from "../../common/placeholder-cell"
import { HttpTypes } from "@medusajs/types"
type CollectionCellProps = { type CollectionCellProps = {
collection?: ProductCollectionDTO | null collection?: HttpTypes.AdminCollection | null
} }
export const CollectionCell = ({ collection }: CollectionCellProps) => { export const CollectionCell = ({ collection }: CollectionCellProps) => {
@@ -1,10 +1,10 @@
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { ProductDTO } from "@medusajs/types"
import { Thumbnail } from "../../../../common/thumbnail" import { Thumbnail } from "../../../../common/thumbnail"
import { HttpTypes } from "@medusajs/types"
type ProductCellProps = { type ProductCellProps = {
product: ProductDTO product: HttpTypes.AdminProduct
} }
export const ProductCell = ({ product }: ProductCellProps) => { export const ProductCell = ({ product }: ProductCellProps) => {
@@ -1,10 +1,10 @@
import { ProductStatus } from "@medusajs/types"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { StatusCell } from "../../common/status-cell" import { StatusCell } from "../../common/status-cell"
import { HttpTypes } from "@medusajs/types"
type ProductStatusCellProps = { type ProductStatusCellProps = {
status: ProductStatus status: HttpTypes.AdminProductStatus
} }
export const ProductStatusCell = ({ status }: ProductStatusCellProps) => { export const ProductStatusCell = ({ status }: ProductStatusCellProps) => {
@@ -1,10 +1,10 @@
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { ProductVariantDTO } from "@medusajs/types"
import { PlaceholderCell } from "../../common/placeholder-cell" import { PlaceholderCell } from "../../common/placeholder-cell"
import { HttpTypes } from "@medusajs/types"
type VariantCellProps = { type VariantCellProps = {
variants?: ProductVariantDTO[] | null variants?: HttpTypes.AdminProductVariant[] | null
} }
export const VariantCell = ({ variants }: VariantCellProps) => { export const VariantCell = ({ variants }: VariantCellProps) => {
@@ -1,7 +1,7 @@
import { QueryKey, UseQueryOptions, useQuery } from "@tanstack/react-query" import { QueryKey, UseQueryOptions, useQuery } from "@tanstack/react-query"
import { client } from "../../lib/client" import { client } from "../../lib/client"
import { queryKeysFactory } from "../../lib/query-key-factory" import { queryKeysFactory } from "../../lib/query-key-factory"
import { ProductTypeListRes, ProductTypeRes } from "../../types/api-responses" import { HttpTypes } from "@medusajs/types"
const PRODUCT_TYPES_QUERY_KEY = "product_types" as const const PRODUCT_TYPES_QUERY_KEY = "product_types" as const
const productTypesQueryKeys = queryKeysFactory(PRODUCT_TYPES_QUERY_KEY) const productTypesQueryKeys = queryKeysFactory(PRODUCT_TYPES_QUERY_KEY)
@@ -10,7 +10,12 @@ export const useProductType = (
id: string, id: string,
query?: Record<string, any>, query?: Record<string, any>,
options?: Omit< options?: Omit<
UseQueryOptions<ProductTypeRes, Error, ProductTypeRes, QueryKey>, UseQueryOptions<
{ product_type: HttpTypes.AdminProductType },
Error,
{ product_type: HttpTypes.AdminProductType },
QueryKey
>,
"queryKey" | "queryFn" "queryKey" | "queryFn"
> >
) => { ) => {
@@ -26,7 +31,12 @@ export const useProductType = (
export const useProductTypes = ( export const useProductTypes = (
query?: Record<string, any>, query?: Record<string, any>,
options?: Omit< options?: Omit<
UseQueryOptions<ProductTypeListRes, Error, ProductTypeListRes, QueryKey>, UseQueryOptions<
{ product_types: HttpTypes.AdminProductType[] },
Error,
{ product_types: HttpTypes.AdminProductType[] },
QueryKey
>,
"queryKey" | "queryFn" "queryKey" | "queryFn"
> >
) => { ) => {
@@ -5,14 +5,9 @@ import {
useQuery, useQuery,
UseQueryOptions, UseQueryOptions,
} from "@tanstack/react-query" } from "@tanstack/react-query"
import { client, sdk } from "../../lib/client" import { sdk } from "../../lib/client"
import { queryClient } from "../../lib/query-client" import { queryClient } from "../../lib/query-client"
import { queryKeysFactory } from "../../lib/query-key-factory" import { queryKeysFactory } from "../../lib/query-key-factory"
import {
ProductDeleteRes,
ProductListRes,
ProductRes,
} from "../../types/api-responses"
import { HttpTypes } from "@medusajs/types" import { HttpTypes } from "@medusajs/types"
const PRODUCTS_QUERY_KEY = "products" as const const PRODUCTS_QUERY_KEY = "products" as const
@@ -29,8 +24,8 @@ export const useCreateProductOption = (
options?: UseMutationOptions<any, Error, any> options?: UseMutationOptions<any, Error, any>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload: any) => mutationFn: (payload: HttpTypes.AdminCreateProductOption) =>
client.products.createOption(productId, payload), sdk.admin.product.createOption(productId, payload),
onSuccess: (data: any, variables: any, context: any) => { onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({ queryKey: optionsQueryKeys.lists() }) queryClient.invalidateQueries({ queryKey: optionsQueryKeys.lists() })
queryClient.invalidateQueries({ queryClient.invalidateQueries({
@@ -48,8 +43,8 @@ export const useUpdateProductOption = (
options?: UseMutationOptions<any, Error, any> options?: UseMutationOptions<any, Error, any>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload: any) => mutationFn: (payload: HttpTypes.AdminUpdateProductOption) =>
client.products.updateOption(productId, optionId, payload), sdk.admin.product.updateOption(productId, optionId, payload),
onSuccess: (data: any, variables: any, context: any) => { onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({ queryKey: optionsQueryKeys.lists() }) queryClient.invalidateQueries({ queryKey: optionsQueryKeys.lists() })
queryClient.invalidateQueries({ queryClient.invalidateQueries({
@@ -71,7 +66,7 @@ export const useDeleteProductOption = (
options?: UseMutationOptions<any, Error, void> options?: UseMutationOptions<any, Error, void>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: () => client.products.deleteOption(productId, optionId), mutationFn: () => sdk.admin.product.deleteOption(productId, optionId),
onSuccess: (data: any, variables: any, context: any) => { onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({ queryKey: optionsQueryKeys.lists() }) queryClient.invalidateQueries({ queryKey: optionsQueryKeys.lists() })
queryClient.invalidateQueries({ queryClient.invalidateQueries({
@@ -97,7 +92,8 @@ export const useProductVariant = (
> >
) => { ) => {
const { data, ...rest } = useQuery({ const { data, ...rest } = useQuery({
queryFn: () => client.products.retrieveVariant(productId, variantId, query), queryFn: () =>
sdk.admin.product.retrieveVariant(productId, variantId, query),
queryKey: variantsQueryKeys.detail(variantId), queryKey: variantsQueryKeys.detail(variantId),
...options, ...options,
}) })
@@ -114,7 +110,7 @@ export const useProductVariants = (
> >
) => { ) => {
const { data, ...rest } = useQuery({ const { data, ...rest } = useQuery({
queryFn: () => client.products.listVariants(productId, query), queryFn: () => sdk.admin.product.listVariants(productId, query),
queryKey: variantsQueryKeys.list({ productId, ...query }), queryKey: variantsQueryKeys.list({ productId, ...query }),
...options, ...options,
}) })
@@ -127,8 +123,8 @@ export const useCreateProductVariant = (
options?: UseMutationOptions<any, Error, any> options?: UseMutationOptions<any, Error, any>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload: any) => mutationFn: (payload: HttpTypes.AdminCreateProductVariant) =>
client.products.createVariant(productId, payload), sdk.admin.product.createVariant(productId, payload),
onSuccess: (data: any, variables: any, context: any) => { onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({ queryKey: variantsQueryKeys.lists() }) queryClient.invalidateQueries({ queryKey: variantsQueryKeys.lists() })
queryClient.invalidateQueries({ queryClient.invalidateQueries({
@@ -146,8 +142,8 @@ export const useUpdateProductVariant = (
options?: UseMutationOptions<any, Error, any> options?: UseMutationOptions<any, Error, any>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload: any) => mutationFn: (payload: HttpTypes.AdminUpdateProductVariant) =>
client.products.updateVariant(productId, variantId, payload), sdk.admin.product.updateVariant(productId, variantId, payload),
onSuccess: (data: any, variables: any, context: any) => { onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({ queryKey: variantsQueryKeys.lists() }) queryClient.invalidateQueries({ queryKey: variantsQueryKeys.lists() })
queryClient.invalidateQueries({ queryClient.invalidateQueries({
@@ -168,8 +164,9 @@ export const useUpdateProductVariantsBatch = (
options?: UseMutationOptions<any, Error, any> options?: UseMutationOptions<any, Error, any>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload: any) => mutationFn: (
client.products.updateVariantsBatch(productId, payload), payload: HttpTypes.AdminBatchProductVariantRequest["update"]
) => sdk.admin.product.batchVariants(productId, { update: payload }),
onSuccess: (data: any, variables: any, context: any) => { onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({ queryKey: variantsQueryKeys.lists() }) queryClient.invalidateQueries({ queryKey: variantsQueryKeys.lists() })
queryClient.invalidateQueries({ queryClient.invalidateQueries({
@@ -188,7 +185,7 @@ export const useDeleteVariant = (
options?: UseMutationOptions<any, Error, void> options?: UseMutationOptions<any, Error, void>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: () => client.products.deleteVariant(productId, variantId), mutationFn: () => sdk.admin.product.deleteVariant(productId, variantId),
onSuccess: (data: any, variables: any, context: any) => { onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({ queryKey: variantsQueryKeys.lists() }) queryClient.invalidateQueries({ queryKey: variantsQueryKeys.lists() })
queryClient.invalidateQueries({ queryClient.invalidateQueries({
@@ -213,7 +210,7 @@ export const useProduct = (
> >
) => { ) => {
const { data, ...rest } = useQuery({ const { data, ...rest } = useQuery({
queryFn: () => client.products.retrieve(id, query), queryFn: () => sdk.admin.product.retrieve(id, query),
queryKey: productsQueryKeys.detail(id), queryKey: productsQueryKeys.detail(id),
...options, ...options,
}) })
@@ -224,12 +221,17 @@ export const useProduct = (
export const useProducts = ( export const useProducts = (
query?: Record<string, any>, query?: Record<string, any>,
options?: Omit< options?: Omit<
UseQueryOptions<ProductListRes, Error, ProductListRes, QueryKey>, UseQueryOptions<
HttpTypes.AdminProductListResponse,
Error,
HttpTypes.AdminProductListResponse,
QueryKey
>,
"queryFn" | "queryKey" "queryFn" | "queryKey"
> >
) => { ) => {
const { data, ...rest } = useQuery({ const { data, ...rest } = useQuery({
queryFn: () => client.products.list(query), queryFn: () => sdk.admin.product.list(query),
queryKey: productsQueryKeys.list(query), queryKey: productsQueryKeys.list(query),
...options, ...options,
}) })
@@ -245,7 +247,8 @@ export const useCreateProduct = (
> >
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload: any) => sdk.admin.product.create(payload), mutationFn: (payload: HttpTypes.AdminCreateProduct) =>
sdk.admin.product.create(payload),
onSuccess: (data: any, variables: any, context: any) => { onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({ queryKey: productsQueryKeys.lists() }) queryClient.invalidateQueries({ queryKey: productsQueryKeys.lists() })
options?.onSuccess?.(data, variables, context) options?.onSuccess?.(data, variables, context)
@@ -256,10 +259,11 @@ export const useCreateProduct = (
export const useUpdateProduct = ( export const useUpdateProduct = (
id: string, id: string,
options?: UseMutationOptions<ProductRes, Error, any> options?: UseMutationOptions<HttpTypes.AdminProductResponse, Error, any>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: (payload: any) => client.products.update(id, payload), mutationFn: (payload: HttpTypes.AdminUpdateProduct) =>
sdk.admin.product.update(id, payload),
onSuccess: (data: any, variables: any, context: any) => { onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({ queryKey: productsQueryKeys.lists() }) queryClient.invalidateQueries({ queryKey: productsQueryKeys.lists() })
queryClient.invalidateQueries({ queryKey: productsQueryKeys.detail(id) }) queryClient.invalidateQueries({ queryKey: productsQueryKeys.detail(id) })
@@ -272,10 +276,14 @@ export const useUpdateProduct = (
export const useDeleteProduct = ( export const useDeleteProduct = (
id: string, id: string,
options?: UseMutationOptions<ProductDeleteRes, Error, void> options?: UseMutationOptions<
HttpTypes.AdminProductDeleteResponse,
Error,
void
>
) => { ) => {
return useMutation({ return useMutation({
mutationFn: () => client.products.delete(id), mutationFn: () => sdk.admin.product.delete(id),
onSuccess: (data: any, variables: any, context: any) => { onSuccess: (data: any, variables: any, context: any) => {
queryClient.invalidateQueries({ queryKey: productsQueryKeys.lists() }) queryClient.invalidateQueries({ queryKey: productsQueryKeys.lists() })
queryClient.invalidateQueries({ queryKey: productsQueryKeys.detail(id) }) queryClient.invalidateQueries({ queryKey: productsQueryKeys.detail(id) })
@@ -21,9 +21,9 @@ import {
VariantCell, VariantCell,
VariantHeader, VariantHeader,
} from "../../../components/table/table-cells/product/variant-cell" } from "../../../components/table/table-cells/product/variant-cell"
import { ExtendedProductDTO } from "../../../types/api-responses" import { HttpTypes } from "@medusajs/types"
const columnHelper = createColumnHelper<ExtendedProductDTO>() const columnHelper = createColumnHelper<HttpTypes.AdminProduct>()
export const useProductTableColumns = () => { export const useProductTableColumns = () => {
return useMemo( return useMemo(
@@ -1,6 +1,4 @@
import { AdminGetProductsParams } from "@medusajs/medusa" import { HttpTypes } from "@medusajs/types"
import { ProductStatus } from "@medusajs/types"
import { useQueryParams } from "../../use-query-params" import { useQueryParams } from "../../use-query-params"
type UseProductTableQueryProps = { type UseProductTableQueryProps = {
@@ -46,7 +44,7 @@ export const useProductTableQuery = ({
q, q,
} = queryObject } = queryObject
const searchParams: AdminGetProductsParams = { const searchParams: HttpTypes.AdminProductParams = {
limit: pageSize, limit: pageSize,
offset: offset ? Number(offset) : 0, offset: offset ? Number(offset) : 0,
sales_channel_id: sales_channel_id?.split(","), sales_channel_id: sales_channel_id?.split(","),
@@ -56,9 +54,9 @@ export const useProductTableQuery = ({
collection_id: collection_id?.split(","), collection_id: collection_id?.split(","),
is_giftcard: is_giftcard ? is_giftcard === "true" : undefined, is_giftcard: is_giftcard ? is_giftcard === "true" : undefined,
order: order, order: order,
tags: tags?.split(","), tags: tags ? { value: tags.split(",") } : undefined,
type_id: type_id?.split(","), type_id: type_id?.split(","),
status: status?.split(",") as ProductStatus[], status: status?.split(",") as HttpTypes.AdminProductStatus[],
q, q,
} }
@@ -10,7 +10,6 @@ import { invites } from "./invites"
import { payments } from "./payments" import { payments } from "./payments"
import { priceLists } from "./price-lists" import { priceLists } from "./price-lists"
import { productTypes } from "./product-types" import { productTypes } from "./product-types"
import { products } from "./products"
import { promotions } from "./promotions" import { promotions } from "./promotions"
import { reservations } from "./reservations" import { reservations } from "./reservations"
import { salesChannels } from "./sales-channels" import { salesChannels } from "./sales-channels"
@@ -42,7 +41,6 @@ export const client = {
reservations: reservations, reservations: reservations,
fulfillments: fulfillments, fulfillments: fulfillments,
fulfillmentProviders: fulfillmentProviders, fulfillmentProviders: fulfillmentProviders,
products: products,
productTypes: productTypes, productTypes: productTypes,
priceLists: priceLists, priceLists: priceLists,
stockLocations: stockLocations, stockLocations: stockLocations,
@@ -1,12 +1,18 @@
import { ProductTypeListRes, ProductTypeRes } from "../../types/api-responses" import { HttpTypes } from "@medusajs/types"
import { getRequest } from "./common" import { getRequest } from "./common"
async function listProductTypes(query?: Record<string, any>) { async function listProductTypes(query?: Record<string, any>) {
return getRequest<ProductTypeListRes>(`/admin/product-types`, query) return getRequest<{ product_types: HttpTypes.AdminProductType[] }>(
`/admin/product-types`,
query
)
} }
async function retrieveProductType(id: string, query?: Record<string, any>) { async function retrieveProductType(id: string, query?: Record<string, any>) {
return getRequest<ProductTypeRes>(`/admin/product-types/${id}`, query) return getRequest<{ product_type: HttpTypes.AdminProductType }>(
`/admin/product-types/${id}`,
query
)
} }
export const productTypes = { export const productTypes = {
@@ -1,100 +0,0 @@
import { ProductDeleteRes, ProductListRes } from "../../types/api-responses"
import { deleteRequest, getRequest, postRequest } from "./common"
async function retrieveProduct(id: string, query?: Record<string, any>) {
return getRequest<any>(`/admin/products/${id}`, query)
}
async function createProduct(payload: any) {
return postRequest<any>(`/admin/products`, payload)
}
async function listProducts(query?: Record<string, any>) {
return getRequest<ProductListRes>(`/admin/products`, query)
}
async function updateProduct(id: string, payload: any) {
return postRequest<any>(`/admin/products/${id}`, payload)
}
async function deleteProduct(id: string) {
return deleteRequest<ProductDeleteRes>(`/admin/products/${id}`)
}
async function retrieveVariant(
productId: string,
variantId: string,
query?: Record<string, any>
) {
return getRequest<any>(
`/admin/products/${productId}/variants/${variantId}`,
query
)
}
async function listVariants(productId: string, query?: Record<string, any>) {
return getRequest<any>(`/admin/products/${productId}/variants`, query)
}
async function createVariant(productId: string, payload: any) {
return postRequest<any>(`/admin/products/${productId}/variants`, payload)
}
async function updateVariant(
productId: string,
variantId: string,
payload: any
) {
return postRequest<any>(
`/admin/products/${productId}/variants/${variantId}`,
payload
)
}
async function updateVariantsBatch(
productId: string,
payload: { add: any[]; update: any[]; remove: any[] }
) {
return postRequest<any>(
`/admin/products/${productId}/variants/batch`,
payload
)
}
async function deleteVariant(productId: string, variantId: string) {
return deleteRequest<any>(
`/admin/products/${productId}/variants/${variantId}`
)
}
async function createOption(productId: string, payload: any) {
return postRequest<any>(`/admin/products/${productId}/options`, payload)
}
async function updateOption(productId: string, optionId: string, payload: any) {
return postRequest<any>(
`/admin/products/${productId}/options/${optionId}`,
payload
)
}
async function deleteOption(productId: string, optionId: string) {
return deleteRequest<any>(`/admin/products/${productId}/options/${optionId}`)
}
export const products = {
retrieve: retrieveProduct,
list: listProducts,
create: createProduct,
update: updateProduct,
delete: deleteProduct,
retrieveVariant,
listVariants,
createVariant,
updateVariant,
updateVariantsBatch,
deleteVariant,
createOption,
updateOption,
deleteOption,
}
@@ -63,7 +63,7 @@ export const RouteMap: RouteObject[] = [
path: ":id", path: ":id",
lazy: () => import("../../routes/products/product-detail"), lazy: () => import("../../routes/products/product-detail"),
handle: { handle: {
crumb: (data: { product: HttpTypes.AdminProduct }) => crumb: (data: HttpTypes.AdminProductResponse) =>
data.product.title, data.product.title,
}, },
children: [ children: [
@@ -22,7 +22,6 @@ import { useProductTableColumns } from "../../../../../hooks/table/columns/use-p
import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters.tsx" import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters.tsx"
import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query.tsx" import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query.tsx"
import { useDataTable } from "../../../../../hooks/use-data-table.tsx" import { useDataTable } from "../../../../../hooks/use-data-table.tsx"
import { ExtendedProductDTO } from "../../../../../types/api-responses.ts"
type AddProductsToCollectionFormProps = { type AddProductsToCollectionFormProps = {
collection: HttpTypes.AdminCollection collection: HttpTypes.AdminCollection
@@ -186,7 +185,7 @@ export const AddProductsToCollectionForm = ({
) )
} }
const columnHelper = createColumnHelper<ExtendedProductDTO>() const columnHelper = createColumnHelper<HttpTypes.AdminProduct>()
const useColumns = () => { const useColumns = () => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -13,7 +13,6 @@ import { useProductTableColumns } from "../../../../../hooks/table/columns/use-p
import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters" import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters"
import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query" import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table" import { useDataTable } from "../../../../../hooks/use-data-table"
import { ExtendedProductDTO } from "../../../../../types/api-responses"
type CollectionProductSectionProps = { type CollectionProductSectionProps = {
collection: HttpTypes.AdminCollection collection: HttpTypes.AdminCollection
@@ -139,7 +138,7 @@ const ProductActions = ({
product, product,
collectionId, collectionId,
}: { }: {
product: ExtendedProductDTO product: HttpTypes.AdminProduct
collectionId: string collectionId: string
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -201,7 +200,7 @@ const ProductActions = ({
) )
} }
const columnHelper = createColumnHelper<ExtendedProductDTO>() const columnHelper = createColumnHelper<HttpTypes.AdminProduct>()
const useColumns = () => { const useColumns = () => {
const columns = useProductTableColumns() const columns = useProductTableColumns()
@@ -4,16 +4,16 @@ import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import * as zod from "zod" import * as zod from "zod"
import { ProductCollectionDTO } from "@medusajs/types"
import { Form } from "../../../../../components/common/form" import { Form } from "../../../../../components/common/form"
import { import {
RouteDrawer, RouteDrawer,
useRouteModal, useRouteModal,
} from "../../../../../components/route-modal" } from "../../../../../components/route-modal"
import { useUpdateCollection } from "../../../../../hooks/api/collections" import { useUpdateCollection } from "../../../../../hooks/api/collections"
import { HttpTypes } from "@medusajs/types"
type EditCollectionFormProps = { type EditCollectionFormProps = {
collection: ProductCollectionDTO collection: HttpTypes.AdminCollection
} }
const EditCollectionSchema = zod.object({ const EditCollectionSchema = zod.object({
@@ -1,15 +1,15 @@
import { Container, Heading } from "@medusajs/ui" import { Container, Heading } from "@medusajs/ui"
import { ProductVariantDTO } from "@medusajs/types"
import { ActionMenu } from "../../../../components/common/action-menu" import { ActionMenu } from "../../../../components/common/action-menu"
import { InventoryItemRes } from "../../../../types/api-responses" import { InventoryItemRes } from "../../../../types/api-responses"
import { PencilSquare } from "@medusajs/icons" import { PencilSquare } from "@medusajs/icons"
import { SectionRow } from "../../../../components/common/section" import { SectionRow } from "../../../../components/common/section"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { HttpTypes } from "@medusajs/types"
type InventoryItemGeneralSectionProps = { type InventoryItemGeneralSectionProps = {
inventoryItem: InventoryItemRes["inventory_item"] & { inventoryItem: InventoryItemRes["inventory_item"] & {
variant: ProductVariantDTO | ProductVariantDTO[] variant: HttpTypes.AdminProductVariant | HttpTypes.AdminProductVariant[]
} }
} }
export const InventoryItemGeneralSection = ({ export const InventoryItemGeneralSection = ({
@@ -74,7 +74,7 @@ export const InventoryItemGeneralSection = ({
) )
} }
const getQuantityFormat = (quantity: number, locations: number) => { const getQuantityFormat = (quantity: number, locations?: number) => {
return `${quantity ?? "-"} return `${quantity ?? "-"}
${quantity ? `across ${locations} locations` : ""}` ${quantity ? `across ${locations ?? "-"} locations` : ""}`
} }
@@ -1,4 +1,4 @@
import { CurrencyDTO, HttpTypes, ProductVariantDTO } from "@medusajs/types" import { CurrencyDTO, HttpTypes } from "@medusajs/types"
import { ColumnDef, createColumnHelper } from "@tanstack/react-table" import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
import { useEffect, useMemo, useState } from "react" import { useEffect, useMemo, useState } from "react"
import { UseFormReturn } from "react-hook-form" import { UseFormReturn } from "react-hook-form"
@@ -9,7 +9,6 @@ import { CurrencyCell } from "../../../../../components/grid/grid-cells/common/c
import { DataGrid } from "../../../../../components/grid/data-grid" import { DataGrid } from "../../../../../components/grid/data-grid"
import { DataGridMeta } from "../../../../../components/grid/types" import { DataGridMeta } from "../../../../../components/grid/types"
import { useCurrencies } from "../../../../../hooks/api/currencies" import { useCurrencies } from "../../../../../hooks/api/currencies"
import { ExtendedProductDTO } from "../../../../../types/api-responses"
import { useRegions } from "../../../../../hooks/api/regions" import { useRegions } from "../../../../../hooks/api/regions"
import { useStore } from "../../../../../hooks/api/store" import { useStore } from "../../../../../hooks/api/store"
@@ -95,7 +94,7 @@ export const CreateShippingOptionsPricesForm = ({
} }
const columnHelper = createColumnHelper< const columnHelper = createColumnHelper<
ExtendedProductDTO | ProductVariantDTO HttpTypes.AdminProduct | HttpTypes.AdminProductVariant
>() >()
const useColumns = ({ const useColumns = ({
@@ -107,45 +106,46 @@ const useColumns = ({
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const colDefs: ColumnDef<ExtendedProductDTO | ProductVariantDTO>[] = const colDefs: ColumnDef<
useMemo(() => { HttpTypes.AdminProduct | HttpTypes.AdminProductVariant
return [ >[] = useMemo(() => {
...currencies.map((currency) => { return [
return columnHelper.display({ ...currencies.map((currency) => {
header: t("fields.priceTemplate", { return columnHelper.display({
regionOrCountry: currency.code.toUpperCase(), header: t("fields.priceTemplate", {
}), regionOrCountry: currency.code.toUpperCase(),
cell: ({ row, table }) => { }),
return ( cell: ({ row, table }) => {
<CurrencyCell return (
currency={currency} <CurrencyCell
meta={table.options.meta as DataGridMeta<any>} currency={currency}
field={`currency_prices.${currency.code}`} meta={table.options.meta as DataGridMeta<any>}
/> field={`currency_prices.${currency.code}`}
) />
}, )
}) },
}), })
...regions.map((region) => { }),
return columnHelper.display({ ...regions.map((region) => {
header: t("fields.priceTemplate", { return columnHelper.display({
regionOrCountry: region.name, header: t("fields.priceTemplate", {
}), regionOrCountry: region.name,
cell: ({ row, table }) => { }),
return ( cell: ({ row, table }) => {
<CurrencyCell return (
currency={currencies.find( <CurrencyCell
(c) => c.code === region.currency_code currency={currencies.find(
)} (c) => c.code === region.currency_code
meta={table.options.meta as DataGridMeta<any>} )}
field={`region_prices.${region.id}`} meta={table.options.meta as DataGridMeta<any>}
/> field={`region_prices.${region.id}`}
) />
}, )
}) },
}), })
] }),
}, [t, currencies, regions]) ]
}, [t, currencies, regions])
return colDefs return colDefs
} }
@@ -6,13 +6,12 @@ import * as zod from "zod"
import { import {
CurrencyDTO, CurrencyDTO,
PriceDTO, PriceDTO,
ProductVariantDTO,
ShippingOptionDTO, ShippingOptionDTO,
HttpTypes,
} from "@medusajs/types" } from "@medusajs/types"
import { Button, toast } from "@medusajs/ui" import { Button, toast } from "@medusajs/ui"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { HttpTypes } from "@medusajs/types"
import { ColumnDef, createColumnHelper } from "@tanstack/react-table" import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
import { DataGrid } from "../../../../../components/grid/data-grid/index" import { DataGrid } from "../../../../../components/grid/data-grid/index"
import { CurrencyCell } from "../../../../../components/grid/grid-cells/common/currency-cell/index" import { CurrencyCell } from "../../../../../components/grid/grid-cells/common/currency-cell/index"
@@ -25,7 +24,6 @@ import { useCurrencies } from "../../../../../hooks/api/currencies"
import { useRegions } from "../../../../../hooks/api/regions" import { useRegions } from "../../../../../hooks/api/regions"
import { useUpdateShippingOptions } from "../../../../../hooks/api/shipping-options" import { useUpdateShippingOptions } from "../../../../../hooks/api/shipping-options"
import { useStore } from "../../../../../hooks/api/store" import { useStore } from "../../../../../hooks/api/store"
import { ExtendedProductDTO } from "../../../../../types/api-responses"
import { castNumber } from "../../../../../lib/cast-number.ts" import { castNumber } from "../../../../../lib/cast-number.ts"
const getInitialCurrencyPrices = (prices: PriceDTO[]) => { const getInitialCurrencyPrices = (prices: PriceDTO[]) => {
@@ -254,7 +252,7 @@ export function EditShippingOptionsPricingForm({
} }
const columnHelper = createColumnHelper< const columnHelper = createColumnHelper<
ExtendedProductDTO | ProductVariantDTO HttpTypes.AdminProduct | HttpTypes.AdminProductVariant
>() >()
const useColumns = ({ const useColumns = ({
@@ -266,45 +264,46 @@ const useColumns = ({
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const colDefs: ColumnDef<ExtendedProductDTO | ProductVariantDTO>[] = const colDefs: ColumnDef<
useMemo(() => { HttpTypes.AdminProduct | HttpTypes.AdminProductVariant
return [ >[] = useMemo(() => {
...currencies.map((currency) => { return [
return columnHelper.display({ ...currencies.map((currency) => {
header: t("fields.priceTemplate", { return columnHelper.display({
regionOrCountry: currency.code.toUpperCase(), header: t("fields.priceTemplate", {
}), regionOrCountry: currency.code.toUpperCase(),
cell: ({ row, table }) => { }),
return ( cell: ({ row, table }) => {
<CurrencyCell return (
currency={currency} <CurrencyCell
meta={table.options.meta as DataGridMeta<any>} currency={currency}
field={`currency_prices.${currency.code}`} meta={table.options.meta as DataGridMeta<any>}
/> field={`currency_prices.${currency.code}`}
) />
}, )
}) },
}), })
...regions.map((region) => { }),
return columnHelper.display({ ...regions.map((region) => {
header: t("fields.priceTemplate", { return columnHelper.display({
regionOrCountry: region.name, header: t("fields.priceTemplate", {
}), regionOrCountry: region.name,
cell: ({ row, table }) => { }),
return ( cell: ({ row, table }) => {
<CurrencyCell return (
currency={currencies.find( <CurrencyCell
(c) => c.code === region.currency_code currency={currencies.find(
)} (c) => c.code === region.currency_code
meta={table.options.meta as DataGridMeta<any>} )}
field={`region_prices.${region.id}`} meta={table.options.meta as DataGridMeta<any>}
/> field={`region_prices.${region.id}`}
) />
}, )
}) },
}), })
] }),
}, [t, currencies, regions]) ]
}, [t, currencies, regions])
return colDefs return colDefs
} }
@@ -1,10 +1,5 @@
import { Buildings, XCircle } from "@medusajs/icons" import { Buildings, XCircle } from "@medusajs/icons"
import { import { AdminOrder, FulfillmentDTO, OrderLineItemDTO } from "@medusajs/types"
AdminOrder,
FulfillmentDTO,
OrderLineItemDTO,
ProductVariantDTO,
} from "@medusajs/types"
import { import {
Container, Container,
Copy, Copy,
@@ -49,7 +44,7 @@ const UnfulfilledItem = ({
item, item,
currencyCode, currencyCode,
}: { }: {
item: OrderLineItemDTO & { variant: ProductVariantDTO } item: OrderLineItemDTO & { variant: HttpTypes.AdminProductVariant }
currencyCode: string currencyCode: string
}) => { }) => {
return ( return (
@@ -1,4 +1,4 @@
import { CurrencyDTO, ProductVariantDTO } from "@medusajs/types" import { CurrencyDTO, HttpTypes } from "@medusajs/types"
import { ColumnDef, createColumnHelper } from "@tanstack/react-table" import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -7,11 +7,10 @@ import { CurrencyCell } from "../../../../components/grid/grid-cells/common/curr
import { ReadonlyCell } from "../../../../components/grid/grid-cells/common/readonly-cell" import { ReadonlyCell } from "../../../../components/grid/grid-cells/common/readonly-cell"
import { VoidCell } from "../../../../components/grid/grid-cells/common/void-cell" import { VoidCell } from "../../../../components/grid/grid-cells/common/void-cell"
import { DataGridMeta } from "../../../../components/grid/types" import { DataGridMeta } from "../../../../components/grid/types"
import { ExtendedProductDTO } from "../../../../types/api-responses"
import { isProductRow } from "../utils" import { isProductRow } from "../utils"
const columnHelper = createColumnHelper< const columnHelper = createColumnHelper<
ExtendedProductDTO | ProductVariantDTO HttpTypes.AdminProduct | HttpTypes.AdminProductVariant
>() >()
export const usePriceListGridColumns = ({ export const usePriceListGridColumns = ({
@@ -21,57 +20,58 @@ export const usePriceListGridColumns = ({
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const colDefs: ColumnDef<ExtendedProductDTO | ProductVariantDTO>[] = const colDefs: ColumnDef<
useMemo(() => { HttpTypes.AdminProduct | HttpTypes.AdminProductVariant
return [ >[] = useMemo(() => {
columnHelper.display({ return [
id: t("fields.title"), columnHelper.display({
header: t("fields.title"), id: t("fields.title"),
cell: ({ row }) => { header: t("fields.title"),
cell: ({ row }) => {
const entity = row.original
if (isProductRow(entity)) {
return (
<VoidCell>
<div className="flex h-full w-full items-center gap-x-2 overflow-hidden">
<Thumbnail src={entity.thumbnail} />
<span className="truncate">{entity.title}</span>
</div>
</VoidCell>
)
}
return (
<ReadonlyCell>
<div className="flex h-full w-full items-center gap-x-2 overflow-hidden">
<span className="truncate">{entity.title}</span>
</div>
</ReadonlyCell>
)
},
}),
...currencies.map((currency) => {
return columnHelper.display({
header: `Price ${currency.code.toUpperCase()}`,
cell: ({ row, table }) => {
const entity = row.original const entity = row.original
if (isProductRow(entity)) { if (isProductRow(entity)) {
return ( return <VoidCell />
<VoidCell>
<div className="flex h-full w-full items-center gap-x-2 overflow-hidden">
<Thumbnail src={entity.thumbnail} />
<span className="truncate">{entity.title}</span>
</div>
</VoidCell>
)
} }
return ( return (
<ReadonlyCell> <CurrencyCell
<div className="flex h-full w-full items-center gap-x-2 overflow-hidden"> currency={currency}
<span className="truncate">{entity.title}</span> meta={table.options.meta as DataGridMeta}
</div> field={`products.${entity.product_id}.variants.${entity.id}.currency_prices.${currency.code}.amount`}
</ReadonlyCell> />
) )
}, },
}), })
...currencies.map((currency) => { }),
return columnHelper.display({ ]
header: `Price ${currency.code.toUpperCase()}`, }, [t, currencies])
cell: ({ row, table }) => {
const entity = row.original
if (isProductRow(entity)) {
return <VoidCell />
}
return (
<CurrencyCell
currency={currency}
meta={table.options.meta as DataGridMeta}
field={`products.${entity.product_id}.variants.${entity.id}.currency_prices.${currency.code}.amount`}
/>
)
},
})
}),
]
}, [t, currencies])
return colDefs return colDefs
} }
@@ -1,6 +1,5 @@
import { PriceListDTO, ProductVariantDTO } from "@medusajs/types" import { PriceListDTO, HttpTypes } from "@medusajs/types"
import { TFunction } from "i18next" import { TFunction } from "i18next"
import { ExtendedProductDTO } from "../../../types/api-responses"
import { PriceListStatus } from "./constants" import { PriceListStatus } from "./constants"
const getValues = (priceList: PriceListDTO) => { const getValues = (priceList: PriceListDTO) => {
@@ -49,7 +48,7 @@ export const getPriceListStatus = (
} }
export const isProductRow = ( export const isProductRow = (
row: ExtendedProductDTO | ProductVariantDTO row: HttpTypes.AdminProduct | HttpTypes.AdminProductVariant
): row is ExtendedProductDTO => { ): row is HttpTypes.AdminProduct => {
return "variants" in row return "variants" in row
} }
@@ -13,9 +13,9 @@ import { useProductTableColumns } from "../../../../../hooks/table/columns/use-p
import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters" import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters"
import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query" import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table" import { useDataTable } from "../../../../../hooks/use-data-table"
import { ExtendedProductDTO } from "../../../../../types/api-responses"
import { PricingProductsRecordType } from "../../../common/schemas" import { PricingProductsRecordType } from "../../../common/schemas"
import { PricingCreateSchemaType } from "./schema" import { PricingCreateSchemaType } from "./schema"
import { HttpTypes } from "@medusajs/types"
type PricingProductsFormProps = { type PricingProductsFormProps = {
form: UseFormReturn<PricingCreateSchemaType> form: UseFormReturn<PricingCreateSchemaType>
@@ -132,7 +132,7 @@ export const PricingProductsForm = ({ form }: PricingProductsFormProps) => {
) )
} }
const columnHelper = createColumnHelper<ExtendedProductDTO>() const columnHelper = createColumnHelper<HttpTypes.AdminProduct>()
const useColumns = () => { const useColumns = () => {
const base = useProductTableColumns() const base = useProductTableColumns()
@@ -1,5 +1,5 @@
import { PencilSquare, Plus, Trash } from "@medusajs/icons" import { PencilSquare, Plus, Trash } from "@medusajs/icons"
import { PriceListDTO } from "@medusajs/types" import { PriceListDTO, HttpTypes } from "@medusajs/types"
import { Checkbox, Container, Heading, usePrompt } from "@medusajs/ui" import { Checkbox, Container, Heading, usePrompt } from "@medusajs/ui"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
import { RowSelectionState, createColumnHelper } from "@tanstack/react-table" import { RowSelectionState, createColumnHelper } from "@tanstack/react-table"
@@ -13,7 +13,6 @@ import { useProductTableColumns } from "../../../../../hooks/table/columns/use-p
import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters" import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters"
import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query" import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table" import { useDataTable } from "../../../../../hooks/use-data-table"
import { ExtendedProductDTO } from "../../../../../types/api-responses"
type PricingProductSectionProps = { type PricingProductSectionProps = {
priceList: PriceListDTO priceList: PriceListDTO
@@ -145,7 +144,7 @@ export const PricingProductSection = ({
) )
} }
const ProductRowAction = ({ product }: { product: ExtendedProductDTO }) => { const ProductRowAction = ({ product }: { product: HttpTypes.AdminProduct }) => {
const { t } = useTranslation() const { t } = useTranslation()
// TODO: The endpoint to remove prices by product id is not implemented in v2. // TODO: The endpoint to remove prices by product id is not implemented in v2.
@@ -171,7 +170,7 @@ const ProductRowAction = ({ product }: { product: ExtendedProductDTO }) => {
) )
} }
const columnHelper = createColumnHelper<ExtendedProductDTO>() const columnHelper = createColumnHelper<HttpTypes.AdminProduct>()
const useColumns = () => { const useColumns = () => {
const base = useProductTableColumns() const base = useProductTableColumns()
@@ -2,6 +2,7 @@ import {
CreatePriceListPriceDTO, CreatePriceListPriceDTO,
PriceListDTO, PriceListDTO,
UpdatePriceListPriceDTO, UpdatePriceListPriceDTO,
HttpTypes,
} from "@medusajs/types" } from "@medusajs/types"
import { Button } from "@medusajs/ui" import { Button } from "@medusajs/ui"
import { UseFormReturn, useForm, useWatch } from "react-hook-form" import { UseFormReturn, useForm, useWatch } from "react-hook-form"
@@ -23,7 +24,6 @@ import {
} from "../../../../../hooks/api/price-lists" } from "../../../../../hooks/api/price-lists"
import { useStore } from "../../../../../hooks/api/store" import { useStore } from "../../../../../hooks/api/store"
import { castNumber } from "../../../../../lib/cast-number" import { castNumber } from "../../../../../lib/cast-number"
import { ExtendedProductDTO } from "../../../../../types/api-responses"
import { usePriceListGridColumns } from "../../../common/hooks/use-price-list-grid-columns" import { usePriceListGridColumns } from "../../../common/hooks/use-price-list-grid-columns"
import { import {
PricingProductsRecordSchema, PricingProductsRecordSchema,
@@ -33,7 +33,7 @@ import { isProductRow } from "../../../common/utils"
type PricingProductPricesFormProps = { type PricingProductPricesFormProps = {
priceList: PriceListDTO priceList: PriceListDTO
products: ExtendedProductDTO[] products: HttpTypes.AdminProduct[]
} }
const PricingProductPricesSchema = z.object({ const PricingProductPricesSchema = z.object({
@@ -245,7 +245,7 @@ export const PricingProductPricesForm = ({
} }
function initDefaultValues( function initDefaultValues(
products: ExtendedProductDTO[], products: HttpTypes.AdminProduct[],
existingProducts: any, existingProducts: any,
form: UseFormReturn<z.infer<typeof PricingProductPricesSchema>>, form: UseFormReturn<z.infer<typeof PricingProductPricesSchema>>,
record: VariantsPriceRecord record: VariantsPriceRecord
@@ -1,4 +1,4 @@
import { CurrencyDTO, ProductVariantDTO } from "@medusajs/types" import { CurrencyDTO, HttpTypes } from "@medusajs/types"
import { ColumnDef, createColumnHelper } from "@tanstack/react-table" import { ColumnDef, createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
import { UseFormReturn, useWatch } from "react-hook-form" import { UseFormReturn, useWatch } from "react-hook-form"
@@ -48,7 +48,7 @@ export const VariantPricingForm = ({ form }: VariantPricingFormProps) => {
) )
} }
const columnHelper = createColumnHelper<ProductVariantDTO>() const columnHelper = createColumnHelper<HttpTypes.AdminProductVariant>()
export const useVariantPriceGridColumns = ({ export const useVariantPriceGridColumns = ({
currencies = [], currencies = [],
@@ -57,7 +57,7 @@ export const useVariantPriceGridColumns = ({
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const colDefs: ColumnDef<ProductVariantDTO>[] = useMemo(() => { const colDefs: ColumnDef<HttpTypes.AdminProductVariant>[] = useMemo(() => {
return [ return [
columnHelper.display({ columnHelper.display({
id: t("fields.title"), id: t("fields.title"),
@@ -1,5 +1,4 @@
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from "@hookform/resolvers/zod"
import { Product } from "@medusajs/medusa"
import { Button, Input } from "@medusajs/ui" import { Button, Input } from "@medusajs/ui"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -11,9 +10,10 @@ import {
useRouteModal, useRouteModal,
} from "../../../../../components/route-modal" } from "../../../../../components/route-modal"
import { useUpdateProduct } from "../../../../../hooks/api/products" import { useUpdateProduct } from "../../../../../hooks/api/products"
import { HttpTypes } from "@medusajs/types"
type ProductAttributesFormProps = { type ProductAttributesFormProps = {
product: Product product: HttpTypes.AdminProduct
} }
const dimension = zod const dimension = zod
@@ -1,5 +1,4 @@
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from "@hookform/resolvers/zod"
import { Product } from "@medusajs/medusa"
import { Button, Input, toast } from "@medusajs/ui" import { Button, Input, toast } from "@medusajs/ui"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -12,9 +11,10 @@ import {
useRouteModal, useRouteModal,
} from "../../../../../components/route-modal" } from "../../../../../components/route-modal"
import { useCreateProductOption } from "../../../../../hooks/api/products" import { useCreateProductOption } from "../../../../../hooks/api/products"
import { HttpTypes } from "@medusajs/types"
type EditProductOptionsFormProps = { type EditProductOptionsFormProps = {
product: Product product: HttpTypes.AdminProduct
} }
const CreateProductOptionSchema = z.object({ const CreateProductOptionSchema = z.object({
@@ -1,5 +1,4 @@
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from "@hookform/resolvers/zod"
import { Product } from "@medusajs/medusa"
import { Button, Heading, Input, Switch } from "@medusajs/ui" import { Button, Heading, Input, Switch } from "@medusajs/ui"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -17,9 +16,10 @@ import {
import { useCreateProductVariant } from "../../../../../hooks/api/products" import { useCreateProductVariant } from "../../../../../hooks/api/products"
import { castNumber } from "../../../../../lib/cast-number" import { castNumber } from "../../../../../lib/cast-number"
import { optionalInt } from "../../../../../lib/validation" import { optionalInt } from "../../../../../lib/validation"
import { HttpTypes } from "@medusajs/types"
type CreateProductVariantFormProps = { type CreateProductVariantFormProps = {
product: Product product: HttpTypes.AdminProduct
isStockAndInventoryEnabled?: boolean isStockAndInventoryEnabled?: boolean
} }
@@ -3,7 +3,7 @@ import { Button, ProgressStatus, ProgressTabs, toast } from "@medusajs/ui"
import { useEffect, useMemo, useState } from "react" import { useEffect, useMemo, useState } from "react"
import { useForm, useWatch } from "react-hook-form" import { useForm, useWatch } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { SalesChannelDTO } from "@medusajs/types" import { SalesChannelDTO, HttpTypes } from "@medusajs/types"
import { import {
RouteFocusModal, RouteFocusModal,
useRouteModal, useRouteModal,
@@ -21,7 +21,6 @@ import { ProductCreateInventoryKitForm } from "../product-create-inventory-kit-f
import { ProductCreateVariantsForm } from "../product-create-variants-form" import { ProductCreateVariantsForm } from "../product-create-variants-form"
import { isFetchError } from "../../../../../lib/is-fetch-error" import { isFetchError } from "../../../../../lib/is-fetch-error"
import { sdk } from "../../../../../lib/client" import { sdk } from "../../../../../lib/client"
import { HttpTypes } from "@medusajs/types"
enum Tab { enum Tab {
DETAILS = "details", DETAILS = "details",
@@ -1,4 +1,4 @@
import { ProductVariantDTO, RegionDTO } from "@medusajs/types" import { HttpTypes, RegionDTO } from "@medusajs/types"
import { useMemo } from "react" import { useMemo } from "react"
import { UseFormReturn, useWatch } from "react-hook-form" import { UseFormReturn, useWatch } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -10,7 +10,6 @@ import { DataGridTextCell } from "../../../../../components/data-grid/data-grid-
import { createDataGridHelper } from "../../../../../components/data-grid/utils" import { createDataGridHelper } from "../../../../../components/data-grid/utils"
import { DataGridCurrencyCell } from "../../../../../components/data-grid/data-grid-cells/data-grid-currency-cell" import { DataGridCurrencyCell } from "../../../../../components/data-grid/data-grid-cells/data-grid-currency-cell"
import { DataGridBooleanCell } from "../../../../../components/data-grid/data-grid-cells/data-grid-boolean-cell" import { DataGridBooleanCell } from "../../../../../components/data-grid/data-grid-cells/data-grid-boolean-cell"
import { DataGridCountrySelectCell } from "../../../../../components/data-grid/data-grid-cells/data-grid-country-select-cell"
import { useRegions } from "../../../../../hooks/api/regions" import { useRegions } from "../../../../../hooks/api/regions"
type ProductCreateVariantsFormProps = { type ProductCreateVariantsFormProps = {
@@ -64,7 +63,7 @@ export const ProductCreateVariantsForm = ({
) )
} }
const columnHelper = createDataGridHelper<ProductVariantDTO>() const columnHelper = createDataGridHelper<HttpTypes.AdminProductVariant>()
const useColumns = ({ const useColumns = ({
options, options,
@@ -1,9 +1,9 @@
import { CreateProductDTO } from "@medusajs/types" import { HttpTypes } from "@medusajs/types"
import { ProductCreateSchemaType } from "./types" import { ProductCreateSchemaType } from "./types"
import { castNumber } from "../../../lib/cast-number" import { castNumber } from "../../../lib/cast-number"
export const normalizeProductFormValues = ( export const normalizeProductFormValues = (
values: ProductCreateSchemaType & { status: CreateProductDTO["status"] } values: ProductCreateSchemaType & { status: HttpTypes.AdminProductStatus }
) => { ) => {
const thumbnail = values.media?.find((media) => media.isThumbnail)?.url const thumbnail = values.media?.find((media) => media.isThumbnail)?.url
const images = values.media const images = values.media
@@ -1,13 +1,13 @@
import { PencilSquare } from "@medusajs/icons" import { PencilSquare } from "@medusajs/icons"
import { Product } from "@medusajs/medusa"
import { Container, Heading, Text } from "@medusajs/ui" import { Container, Heading, Text } from "@medusajs/ui"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { ActionMenu } from "../../../../../components/common/action-menu" import { ActionMenu } from "../../../../../components/common/action-menu"
import { SectionRow } from "../../../../../components/common/section" import { SectionRow } from "../../../../../components/common/section"
import { getFormattedCountry } from "../../../../../lib/addresses" import { getFormattedCountry } from "../../../../../lib/addresses"
import { HttpTypes } from "@medusajs/types"
type ProductAttributeSectionProps = { type ProductAttributeSectionProps = {
product: Product product: HttpTypes.AdminProduct
} }
export const ProductAttributeSection = ({ export const ProductAttributeSection = ({
@@ -1,11 +1,11 @@
import { PencilSquare, Trash } from "@medusajs/icons" import { PencilSquare, Trash } from "@medusajs/icons"
import { Product } from "@medusajs/medusa"
import { Container, Heading, StatusBadge, usePrompt } from "@medusajs/ui" import { Container, Heading, StatusBadge, usePrompt } from "@medusajs/ui"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { useNavigate } from "react-router-dom" import { useNavigate } from "react-router-dom"
import { ActionMenu } from "../../../../../components/common/action-menu" import { ActionMenu } from "../../../../../components/common/action-menu"
import { SectionRow } from "../../../../../components/common/section" import { SectionRow } from "../../../../../components/common/section"
import { useDeleteProduct } from "../../../../../hooks/api/products" import { useDeleteProduct } from "../../../../../hooks/api/products"
import { HttpTypes } from "@medusajs/types"
const productStatusColor = (status: string) => { const productStatusColor = (status: string) => {
switch (status) { switch (status) {
@@ -23,7 +23,7 @@ const productStatusColor = (status: string) => {
} }
type ProductGeneralSectionProps = { type ProductGeneralSectionProps = {
product: Product product: HttpTypes.AdminProduct
} }
export const ProductGeneralSection = ({ export const ProductGeneralSection = ({
@@ -1,5 +1,4 @@
import { PencilSquare, ThumbnailBadge } from "@medusajs/icons" import { PencilSquare, ThumbnailBadge } from "@medusajs/icons"
import { Product } from "@medusajs/medusa"
import { import {
Button, Button,
Checkbox, Checkbox,
@@ -16,9 +15,10 @@ import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
import { ActionMenu } from "../../../../../components/common/action-menu" import { ActionMenu } from "../../../../../components/common/action-menu"
import { useUpdateProduct } from "../../../../../hooks/api/products" import { useUpdateProduct } from "../../../../../hooks/api/products"
import { HttpTypes } from "@medusajs/types"
type ProductMedisaSectionProps = { type ProductMedisaSectionProps = {
product: Product product: HttpTypes.AdminProduct
} }
export const ProductMediaSection = ({ product }: ProductMedisaSectionProps) => { export const ProductMediaSection = ({ product }: ProductMedisaSectionProps) => {
@@ -1,17 +1,17 @@
import { PencilSquare, Plus, Trash } from "@medusajs/icons" import { PencilSquare, Plus, Trash } from "@medusajs/icons"
import { Product } from "@medusajs/medusa"
import { Badge, Container, Heading, usePrompt } from "@medusajs/ui" import { Badge, Container, Heading, usePrompt } from "@medusajs/ui"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { ActionMenu } from "../../../../../components/common/action-menu" import { ActionMenu } from "../../../../../components/common/action-menu"
import { SectionRow } from "../../../../../components/common/section" import { SectionRow } from "../../../../../components/common/section"
import { useDeleteProductOption } from "../../../../../hooks/api/products" import { useDeleteProductOption } from "../../../../../hooks/api/products"
import { HttpTypes } from "@medusajs/types"
const OptionActions = ({ const OptionActions = ({
product, product,
option, option,
}: { }: {
product: Product product: HttpTypes.AdminProduct
option: any option: HttpTypes.AdminProductOption
}) => { }) => {
const { t } = useTranslation() const { t } = useTranslation()
const { mutateAsync } = useDeleteProductOption(product.id, option.id) const { mutateAsync } = useDeleteProductOption(product.id, option.id)
@@ -61,7 +61,7 @@ const OptionActions = ({
} }
type ProductOptionSectionProps = { type ProductOptionSectionProps = {
product: Product product: HttpTypes.AdminProduct
} }
export const ProductOptionSection = ({ export const ProductOptionSection = ({
@@ -88,12 +88,12 @@ export const ProductOptionSection = ({
/> />
</div> </div>
{product.options.map((option) => { {product.options?.map((option) => {
return ( return (
<SectionRow <SectionRow
title={option.title} title={option.title}
key={option.id} key={option.id}
value={option.values.map((val) => { value={option.values?.map((val) => {
return ( return (
<Badge <Badge
key={val.value} key={val.value}
@@ -1,13 +1,13 @@
import { PencilSquare } from "@medusajs/icons" import { PencilSquare } from "@medusajs/icons"
import { Product } from "@medusajs/medusa"
import { Badge, Container, Heading } from "@medusajs/ui" import { Badge, Container, Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { Link } from "react-router-dom" import { Link } from "react-router-dom"
import { ActionMenu } from "../../../../../components/common/action-menu" import { ActionMenu } from "../../../../../components/common/action-menu"
import { SectionRow } from "../../../../../components/common/section" import { SectionRow } from "../../../../../components/common/section"
import { HttpTypes } from "@medusajs/types"
type ProductOrganizationSectionProps = { type ProductOrganizationSectionProps = {
product: Product product: HttpTypes.AdminProduct
} }
export const ProductOrganizationSection = ({ export const ProductOrganizationSection = ({
@@ -37,7 +37,7 @@ export const ProductOrganizationSection = ({
<SectionRow <SectionRow
title={t("fields.tags")} title={t("fields.tags")}
value={ value={
product.tags.length > 0 product.tags?.length
? product.tags.map((tag) => ( ? product.tags.map((tag) => (
<Badge key={tag.id} className="w-fit" size="2xsmall" asChild> <Badge key={tag.id} className="w-fit" size="2xsmall" asChild>
<Link to={`/products?tags=${tag.id}`}>{tag.value}</Link> <Link to={`/products?tags=${tag.id}`}>{tag.value}</Link>
@@ -75,7 +75,7 @@ export const ProductOrganizationSection = ({
<SectionRow <SectionRow
title={t("fields.categories")} title={t("fields.categories")}
value={ value={
product.categories?.length > 0 product.categories?.length
? product.categories.map((pcat) => ( ? product.categories.map((pcat) => (
<Badge <Badge
key={pcat.id} key={pcat.id}
@@ -1,12 +1,12 @@
import { Channels, PencilSquare } from "@medusajs/icons" import { Channels, PencilSquare } from "@medusajs/icons"
import { Product } from "@medusajs/medusa"
import { Container, Heading, Text, Tooltip } from "@medusajs/ui" import { Container, Heading, Text, Tooltip } from "@medusajs/ui"
import { Trans, useTranslation } from "react-i18next" import { Trans, useTranslation } from "react-i18next"
import { ActionMenu } from "../../../../../components/common/action-menu" import { ActionMenu } from "../../../../../components/common/action-menu"
import { useSalesChannels } from "../../../../../hooks/api/sales-channels" import { useSalesChannels } from "../../../../../hooks/api/sales-channels"
import { HttpTypes } from "@medusajs/types"
type ProductSalesChannelSectionProps = { type ProductSalesChannelSectionProps = {
product: Product product: HttpTypes.AdminProduct
} }
// TODO: The fetched sales channel doesn't contain all necessary info // TODO: The fetched sales channel doesn't contain all necessary info
@@ -1,7 +1,6 @@
import { PencilSquare, Plus } from "@medusajs/icons" import { PencilSquare, Plus } from "@medusajs/icons"
import { Container, Heading } from "@medusajs/ui" import { Container, Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { ProductDTO } from "@medusajs/types"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
import { ActionMenu } from "../../../../../components/common/action-menu" import { ActionMenu } from "../../../../../components/common/action-menu"
@@ -11,9 +10,10 @@ import { useProductVariantTableColumns } from "./use-variant-table-columns"
import { useProductVariantTableFilters } from "./use-variant-table-filters" import { useProductVariantTableFilters } from "./use-variant-table-filters"
import { useProductVariantTableQuery } from "./use-variant-table-query" import { useProductVariantTableQuery } from "./use-variant-table-query"
import { useProductVariants } from "../../../../../hooks/api/products" import { useProductVariants } from "../../../../../hooks/api/products"
import { HttpTypes } from "@medusajs/types"
type ProductVariantSectionProps = { type ProductVariantSectionProps = {
product: ProductDTO product: HttpTypes.AdminProduct
} }
const PAGE_SIZE = 10 const PAGE_SIZE = 10
@@ -1,5 +1,4 @@
import { PencilSquare, Trash } from "@medusajs/icons" import { PencilSquare, Trash } from "@medusajs/icons"
import { Product, ProductVariant } from "@medusajs/medusa"
import { Badge, usePrompt } from "@medusajs/ui" import { Badge, usePrompt } from "@medusajs/ui"
import { createColumnHelper } from "@tanstack/react-table" import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
@@ -8,13 +7,14 @@ import { useTranslation } from "react-i18next"
import { ActionMenu } from "../../../../../components/common/action-menu" import { ActionMenu } from "../../../../../components/common/action-menu"
import { PlaceholderCell } from "../../../../../components/table/table-cells/common/placeholder-cell" import { PlaceholderCell } from "../../../../../components/table/table-cells/common/placeholder-cell"
import { useDeleteVariant } from "../../../../../hooks/api/products" import { useDeleteVariant } from "../../../../../hooks/api/products"
import { HttpTypes } from "@medusajs/types"
const VariantActions = ({ const VariantActions = ({
variant, variant,
product, product,
}: { }: {
variant: ProductVariant variant: HttpTypes.AdminProductVariant
product: Product product: HttpTypes.AdminProduct
}) => { }) => {
const { mutateAsync } = useDeleteVariant(product.id, variant.id) const { mutateAsync } = useDeleteVariant(product.id, variant.id)
const { t } = useTranslation() const { t } = useTranslation()
@@ -63,9 +63,11 @@ const VariantActions = ({
) )
} }
const columnHelper = createColumnHelper<ProductVariant>() const columnHelper = createColumnHelper<HttpTypes.AdminProductVariant>()
export const useProductVariantTableColumns = (product?: Product) => { export const useProductVariantTableColumns = (
product?: HttpTypes.AdminProduct
) => {
const { t } = useTranslation() const { t } = useTranslation()
const optionColumns = useMemo(() => { const optionColumns = useMemo(() => {
@@ -141,7 +143,9 @@ export const useProductVariantTableColumns = (product?: Product) => {
columnHelper.display({ columnHelper.display({
id: "actions", id: "actions",
cell: ({ row, table }) => { cell: ({ row, table }) => {
const { product } = table.options.meta as { product: Product } const { product } = table.options.meta as {
product: HttpTypes.AdminProduct
}
return <VariantActions variant={row.original} product={product} /> return <VariantActions variant={row.original} product={product} />
}, },
@@ -1,4 +1,4 @@
import { AdminGetProductsVariantsParams } from "@medusajs/medusa" import { HttpTypes } from "@medusajs/types"
import { useQueryParams } from "../../../../../hooks/use-query-params" import { useQueryParams } from "../../../../../hooks/use-query-params"
export const useProductVariantTableQuery = ({ export const useProductVariantTableQuery = ({
@@ -31,7 +31,7 @@ export const useProductVariantTableQuery = ({
order, order,
} = queryObject } = queryObject
const searchParams: AdminGetProductsVariantsParams = { const searchParams: HttpTypes.AdminProductVariantParams = {
limit: pageSize, limit: pageSize,
offset: offset ? Number(offset) : 0, offset: offset ? Number(offset) : 0,
manage_inventory: manage_inventory manage_inventory: manage_inventory
@@ -1,14 +1,14 @@
import { LoaderFunctionArgs } from "react-router-dom" import { LoaderFunctionArgs } from "react-router-dom"
import { productsQueryKeys } from "../../../hooks/api/products" import { productsQueryKeys } from "../../../hooks/api/products"
import { client } from "../../../lib/client" import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client" import { queryClient } from "../../../lib/query-client"
import { PRODUCT_DETAIL_FIELDS } from "./constants" import { PRODUCT_DETAIL_FIELDS } from "./constants"
const productDetailQuery = (id: string) => ({ const productDetailQuery = (id: string) => ({
queryKey: productsQueryKeys.detail(id), queryKey: productsQueryKeys.detail(id),
queryFn: async () => queryFn: async () =>
client.products.retrieve(id, { fields: PRODUCT_DETAIL_FIELDS }), sdk.admin.product.retrieve(id, { fields: PRODUCT_DETAIL_FIELDS }),
}) })
export const productLoader = async ({ params }: LoaderFunctionArgs) => { export const productLoader = async ({ params }: LoaderFunctionArgs) => {
@@ -1,5 +1,4 @@
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from "@hookform/resolvers/zod"
import { ProductOption } from "@medusajs/medusa"
import { Button, Input } from "@medusajs/ui" import { Button, Input } from "@medusajs/ui"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -12,9 +11,10 @@ import {
useRouteModal, useRouteModal,
} from "../../../../../components/route-modal" } from "../../../../../components/route-modal"
import { useUpdateProductOption } from "../../../../../hooks/api/products" import { useUpdateProductOption } from "../../../../../hooks/api/products"
import { HttpTypes } from "@medusajs/types"
type EditProductOptionFormProps = { type EditProductOptionFormProps = {
option: ProductOption option: HttpTypes.AdminProductOption
} }
const CreateProductOptionSchema = z.object({ const CreateProductOptionSchema = z.object({
@@ -1,5 +1,4 @@
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from "@hookform/resolvers/zod"
import { Product, ProductVariant } from "@medusajs/medusa"
import { Button, Heading, Input, Switch } from "@medusajs/ui" import { Button, Heading, Input, Switch } from "@medusajs/ui"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -19,10 +18,11 @@ import {
parseOptionalFormNumber, parseOptionalFormNumber,
} from "../../../../../lib/form-helpers" } from "../../../../../lib/form-helpers"
import { optionalInt } from "../../../../../lib/validation" import { optionalInt } from "../../../../../lib/validation"
import { HttpTypes } from "@medusajs/types"
type ProductEditVariantFormProps = { type ProductEditVariantFormProps = {
product: Product product: HttpTypes.AdminProduct
variant: ProductVariant variant: HttpTypes.AdminProductVariant
} }
const ProductEditVariantSchema = z.object({ const ProductEditVariantSchema = z.object({
@@ -1,7 +1,7 @@
import { LoaderFunctionArgs } from "react-router-dom" import { LoaderFunctionArgs } from "react-router-dom"
import { productsQueryKeys } from "../../../hooks/api/products" import { productsQueryKeys } from "../../../hooks/api/products"
import { client } from "../../../lib/client" import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client" import { queryClient } from "../../../lib/query-client"
const queryKey = (id: string) => { const queryKey = (id: string) => {
@@ -9,7 +9,7 @@ const queryKey = (id: string) => {
} }
const queryFn = async (id: string) => { const queryFn = async (id: string) => {
return await client.products.retrieve(id) return await sdk.admin.product.retrieve(id)
} }
const editProductVariantQuery = (id: string) => ({ const editProductVariantQuery = (id: string) => ({
@@ -1,4 +1,3 @@
import { ProductVariant } from "@medusajs/medusa"
import { Heading } from "@medusajs/ui" import { Heading } from "@medusajs/ui"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { json, useLoaderData, useParams } from "react-router-dom" import { json, useLoaderData, useParams } from "react-router-dom"
@@ -6,6 +5,7 @@ import { RouteDrawer } from "../../../components/route-modal"
import { useProduct } from "../../../hooks/api/products" import { useProduct } from "../../../hooks/api/products"
import { ProductEditVariantForm } from "./components/product-edit-variant-form" import { ProductEditVariantForm } from "./components/product-edit-variant-form"
import { editProductVariantLoader } from "./loader" import { editProductVariantLoader } from "./loader"
import { HttpTypes } from "@medusajs/types"
export const ProductEditVariant = () => { export const ProductEditVariant = () => {
const initialData = useLoaderData() as Awaited< const initialData = useLoaderData() as Awaited<
@@ -20,7 +20,7 @@ export const ProductEditVariant = () => {
}) })
const variant = product?.variants.find( const variant = product?.variants.find(
(v: ProductVariant) => v.id === variant_id (v: HttpTypes.AdminProductVariant) => v.id === variant_id
) )
if (!isLoading && !variant) { if (!isLoading && !variant) {
@@ -44,7 +44,7 @@ export const ProductEditVariant = () => {
{ready && ( {ready && (
<ProductEditVariantForm <ProductEditVariantForm
product={product} product={product}
variant={variant as unknown as ProductVariant} variant={variant as unknown as HttpTypes.AdminProductVariant}
/> />
)} )}
</RouteDrawer> </RouteDrawer>
@@ -1,6 +1,4 @@
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from "@hookform/resolvers/zod"
import { Product } from "@medusajs/medusa"
import { ProductStatus } from "@medusajs/types"
import { Button, Input, Select, Text, Textarea } from "@medusajs/ui" import { Button, Input, Select, Text, Textarea } from "@medusajs/ui"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -14,9 +12,10 @@ import {
} from "../../../../../components/route-modal" } from "../../../../../components/route-modal"
import { useUpdateProduct } from "../../../../../hooks/api/products" import { useUpdateProduct } from "../../../../../hooks/api/products"
import { parseOptionalFormData } from "../../../../../lib/form-helpers" import { parseOptionalFormData } from "../../../../../lib/form-helpers"
import { HttpTypes } from "@medusajs/types"
type EditProductFormProps = { type EditProductFormProps = {
product: Product product: HttpTypes.AdminProduct
} }
const EditProductSchema = zod.object({ const EditProductSchema = zod.object({
@@ -58,7 +57,7 @@ export const EditProductForm = ({ product }: EditProductFormProps) => {
title, title,
discountable, discountable,
handle, handle,
status: status as ProductStatus, status: status as HttpTypes.AdminProductStatus,
...nullableData, ...nullableData,
}, },
{ {
@@ -16,8 +16,8 @@ import { useProductTableColumns } from "../../../../../hooks/table/columns/use-p
import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters" import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters"
import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query" import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table" import { useDataTable } from "../../../../../hooks/use-data-table"
import { ExtendedProductDTO } from "../../../../../types/api-responses"
import { productsLoader } from "../../loader" import { productsLoader } from "../../loader"
import { HttpTypes } from "@medusajs/types"
const PAGE_SIZE = 20 const PAGE_SIZE = 20
@@ -43,7 +43,7 @@ export const ProductListTable = () => {
const columns = useColumns() const columns = useColumns()
const { table } = useDataTable({ const { table } = useDataTable({
data: (products ?? []) as ExtendedProductDTO[], data: (products ?? []) as HttpTypes.AdminProduct[],
columns, columns,
count, count,
enablePagination: true, enablePagination: true,
@@ -81,7 +81,7 @@ export const ProductListTable = () => {
) )
} }
const ProductActions = ({ product }: { product: ExtendedProductDTO }) => { const ProductActions = ({ product }: { product: HttpTypes.AdminProduct }) => {
const { t } = useTranslation() const { t } = useTranslation()
const prompt = usePrompt() const prompt = usePrompt()
const { mutateAsync } = useDeleteProduct(product.id) const { mutateAsync } = useDeleteProduct(product.id)
@@ -144,7 +144,7 @@ const ProductActions = ({ product }: { product: ExtendedProductDTO }) => {
) )
} }
const columnHelper = createColumnHelper<ExtendedProductDTO>() const columnHelper = createColumnHelper<HttpTypes.AdminProduct>()
const useColumns = () => { const useColumns = () => {
const base = useProductTableColumns() const base = useProductTableColumns()
@@ -1,13 +1,13 @@
import { QueryClient } from "@tanstack/react-query" import { QueryClient } from "@tanstack/react-query"
import { productsQueryKeys } from "../../../hooks/api/products" import { productsQueryKeys } from "../../../hooks/api/products"
import { client } from "../../../lib/client" import { sdk } from "../../../lib/client"
import { queryClient } from "../../../lib/query-client" import { queryClient } from "../../../lib/query-client"
import { ProductListRes } from "../../../types/api-responses" import { ProductListRes } from "../../../types/api-responses"
const productsListQuery = () => ({ const productsListQuery = () => ({
queryKey: productsQueryKeys.list({ limit: 20, offset: 0 }), queryKey: productsQueryKeys.list({ limit: 20, offset: 0 }),
queryFn: async () => client.products.list({ limit: 20, offset: 0 }), queryFn: async () => sdk.admin.product.list({ limit: 20, offset: 0 }),
}) })
export const productsLoader = (client: QueryClient) => { export const productsLoader = (client: QueryClient) => {
@@ -5,7 +5,6 @@ import {
TriangleLeftMini, TriangleLeftMini,
TriangleRightMini, TriangleRightMini,
} from "@medusajs/icons" } from "@medusajs/icons"
import { Image, Product } from "@medusajs/medusa"
import { Button, IconButton, Text, Tooltip, clx, usePrompt } from "@medusajs/ui" import { Button, IconButton, Text, Tooltip, clx, usePrompt } from "@medusajs/ui"
import { useCallback, useEffect, useState } from "react" import { useCallback, useEffect, useState } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -13,9 +12,10 @@ import { Link, useLocation } from "react-router-dom"
import { RouteFocusModal } from "../../../../../components/route-modal" import { RouteFocusModal } from "../../../../../components/route-modal"
import { useUpdateProduct } from "../../../../../hooks/api/products" import { useUpdateProduct } from "../../../../../hooks/api/products"
import { HttpTypes } from "@medusajs/types"
type ProductMediaGalleryProps = { type ProductMediaGalleryProps = {
product: Product product: HttpTypes.AdminProduct
} }
export const ProductMediaGallery = ({ product }: ProductMediaGalleryProps) => { export const ProductMediaGallery = ({ product }: ProductMediaGalleryProps) => {
@@ -303,7 +303,10 @@ type Media = {
isThumbnail: boolean isThumbnail: boolean
} }
const getMedia = (images: Image[] | null, thumbnail: string | null) => { const getMedia = (
images: HttpTypes.AdminProductImage[] | null,
thumbnail: string | null
) => {
const media: Media[] = const media: Media[] =
images?.map((image) => ({ images?.map((image) => ({
id: image.id, id: image.id,
@@ -1,5 +1,4 @@
import { zodResolver } from "@hookform/resolvers/zod" import { zodResolver } from "@hookform/resolvers/zod"
import { Product } from "@medusajs/medusa"
import { Button, toast } from "@medusajs/ui" import { Button, toast } from "@medusajs/ui"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
@@ -14,9 +13,10 @@ import { useUpdateProduct } from "../../../../../hooks/api/products"
import { useComboboxData } from "../../../../../hooks/use-combobox-data" import { useComboboxData } from "../../../../../hooks/use-combobox-data"
import { client, sdk } from "../../../../../lib/client" import { client, sdk } from "../../../../../lib/client"
import { CategoryCombobox } from "../../../common/components/category-combobox" import { CategoryCombobox } from "../../../common/components/category-combobox"
import { HttpTypes } from "@medusajs/types"
type ProductOrganizationFormProps = { type ProductOrganizationFormProps = {
product: Product product: HttpTypes.AdminProduct
} }
const ProductOrganizationSchema = zod.object({ const ProductOrganizationSchema = zod.object({
@@ -5,9 +5,9 @@ import { useTranslation } from "react-i18next"
import * as zod from "zod" import * as zod from "zod"
import { RouteFocusModal, useRouteModal } from "../../../components/route-modal" import { RouteFocusModal, useRouteModal } from "../../../components/route-modal"
import { useUpdateProductVariantsBatch } from "../../../hooks/api/products" import { useUpdateProductVariantsBatch } from "../../../hooks/api/products"
import { ExtendedProductDTO } from "../../../types/api-responses"
import { VariantPricingForm } from "../common/variant-pricing-form" import { VariantPricingForm } from "../common/variant-pricing-form"
import { castNumber } from "../../../lib/cast-number" import { castNumber } from "../../../lib/cast-number"
import { HttpTypes } from "@medusajs/types"
export const UpdateVariantPricesSchema = zod.object({ export const UpdateVariantPricesSchema = zod.object({
variants: zod.array( variants: zod.array(
@@ -23,7 +23,11 @@ export type UpdateVariantPricesSchemaType = zod.infer<
typeof UpdateVariantPricesSchema typeof UpdateVariantPricesSchema
> >
export const PricingEdit = ({ product }: { product: ExtendedProductDTO }) => { export const PricingEdit = ({
product,
}: {
product: HttpTypes.AdminProduct
}) => {
const { t } = useTranslation() const { t } = useTranslation()
const { handleSuccess } = useRouteModal() const { handleSuccess } = useRouteModal()
const form = useForm<UpdateVariantPricesSchemaType>({ const form = useForm<UpdateVariantPricesSchemaType>({
@@ -1,4 +1,4 @@
import { Product, SalesChannel } from "@medusajs/medusa" import { SalesChannel } from "@medusajs/medusa"
import { Button, Checkbox } from "@medusajs/ui" import { Button, Checkbox } from "@medusajs/ui"
import { RowSelectionState, createColumnHelper } from "@tanstack/react-table" import { RowSelectionState, createColumnHelper } from "@tanstack/react-table"
import { useEffect, useMemo, useState } from "react" import { useEffect, useMemo, useState } from "react"
@@ -18,9 +18,10 @@ import { useSalesChannelTableQuery } from "../../../../../hooks/table/query/use-
import { useDataTable } from "../../../../../hooks/use-data-table" import { useDataTable } from "../../../../../hooks/use-data-table"
import { useSalesChannels } from "../../../../../hooks/api/sales-channels" import { useSalesChannels } from "../../../../../hooks/api/sales-channels"
import { useUpdateProduct } from "../../../../../hooks/api/products" import { useUpdateProduct } from "../../../../../hooks/api/products"
import { HttpTypes } from "@medusajs/types"
type EditSalesChannelsFormProps = { type EditSalesChannelsFormProps = {
product: Product product: HttpTypes.AdminProduct
} }
const EditSalesChannelsSchema = zod.object({ const EditSalesChannelsSchema = zod.object({
@@ -22,7 +22,7 @@ import { useProductTableColumns } from "../../../../hooks/table/columns/use-prod
import { useProductTableFilters } from "../../../../hooks/table/filters/use-product-table-filters" import { useProductTableFilters } from "../../../../hooks/table/filters/use-product-table-filters"
import { useProductTableQuery } from "../../../../hooks/table/query/use-product-table-query" import { useProductTableQuery } from "../../../../hooks/table/query/use-product-table-query"
import { useDataTable } from "../../../../hooks/use-data-table" import { useDataTable } from "../../../../hooks/use-data-table"
import { ExtendedProductDTO } from "../../../../types/api-responses" import { HttpTypes } from "@medusajs/types"
type AddProductsToSalesChannelFormProps = { type AddProductsToSalesChannelFormProps = {
salesChannel: SalesChannelDTO salesChannel: SalesChannelDTO
@@ -176,7 +176,7 @@ export const AddProductsToSalesChannelForm = ({
) )
} }
const columnHelper = createColumnHelper<ExtendedProductDTO>() const columnHelper = createColumnHelper<HttpTypes.AdminProduct>()
const useColumns = () => { const useColumns = () => {
const base = useProductTableColumns() const base = useProductTableColumns()
@@ -22,7 +22,7 @@ import { useProductTableColumns } from "../../../../../hooks/table/columns/use-p
import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters" import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters"
import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query" import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query"
import { useDataTable } from "../../../../../hooks/use-data-table" import { useDataTable } from "../../../../../hooks/use-data-table"
import { ExtendedProductDTO } from "../../../../../types/api-responses" import { HttpTypes } from "@medusajs/types"
const PAGE_SIZE = 10 const PAGE_SIZE = 10
@@ -154,7 +154,7 @@ export const SalesChannelProductSection = ({
) )
} }
const columnHelper = createColumnHelper<ExtendedProductDTO>() const columnHelper = createColumnHelper<HttpTypes.AdminProduct>()
const useColumns = () => { const useColumns = () => {
const base = useProductTableColumns() const base = useProductTableColumns()
@@ -1,4 +1,4 @@
import { CustomerGroup, Product, ProductType } from "@medusajs/medusa" import { CustomerGroup } from "@medusajs/medusa"
import { Button } from "@medusajs/ui" import { Button } from "@medusajs/ui"
import { OnChangeFn, RowSelectionState } from "@tanstack/react-table" import { OnChangeFn, RowSelectionState } from "@tanstack/react-table"
import { useState } from "react" import { useState } from "react"
@@ -25,7 +25,6 @@ import { useProductCollectionConditionsTableColumns } from "../../hooks/columns/
import { useProductCollectionConditionsTableFilters } from "../../hooks/filters/use-product-collection-conditions-table-filters" import { useProductCollectionConditionsTableFilters } from "../../hooks/filters/use-product-collection-conditions-table-filters"
import { useProductCollectionConditionsTableQuery } from "../../hooks/query/use-product-collection-conditions-table-query" import { useProductCollectionConditionsTableQuery } from "../../hooks/query/use-product-collection-conditions-table-query"
import { ProductCollectionDTO } from "@medusajs/types"
import { keepPreviousData } from "@tanstack/react-query" import { keepPreviousData } from "@tanstack/react-query"
import { useCollections } from "../../../../../hooks/api/collections" import { useCollections } from "../../../../../hooks/api/collections"
import { useCustomerGroups } from "../../../../../hooks/api/customer-groups" import { useCustomerGroups } from "../../../../../hooks/api/customer-groups"
@@ -33,6 +32,7 @@ import { useProductTypes } from "../../../../../hooks/api/product-types"
import { useProducts } from "../../../../../hooks/api/products" import { useProducts } from "../../../../../hooks/api/products"
import { ConditionEntities } from "../../constants" import { ConditionEntities } from "../../constants"
import { ConditionsOption } from "../../types" import { ConditionsOption } from "../../types"
import { HttpTypes } from "@medusajs/types"
const PAGE_SIZE = 50 const PAGE_SIZE = 50
@@ -102,7 +102,7 @@ const ProductConditionsTable = ({ selected = [], onSave }: ConditionsProps) => {
if (added.length) { if (added.length) {
const addedProducts = (products?.filter((p) => added.includes(p.id!)) ?? const addedProducts = (products?.filter((p) => added.includes(p.id!)) ??
[]) as Product[] []) as HttpTypes.AdminProduct[]
if (addedProducts.length > 0) { if (addedProducts.length > 0) {
const newConditions = addedProducts.map((p) => ({ const newConditions = addedProducts.map((p) => ({
@@ -322,7 +322,7 @@ const ProductTypeConditionsTable = ({
if (added.length) { if (added.length) {
const addedTypes = (product_types?.filter((p) => added.includes(p.id!)) ?? const addedTypes = (product_types?.filter((p) => added.includes(p.id!)) ??
[]) as ProductType[] []) as HttpTypes.AdminProductType[]
if (addedTypes.length > 0) { if (addedTypes.length > 0) {
const newConditions = addedTypes.map((p) => ({ const newConditions = addedTypes.map((p) => ({
@@ -431,7 +431,7 @@ const ProductCollectionConditionsTable = ({
if (added.length) { if (added.length) {
const addedCollections = (collections?.filter((p) => const addedCollections = (collections?.filter((p) =>
added.includes(p.id!) added.includes(p.id!)
) ?? []) as ProductCollectionDTO[] ) ?? []) as HttpTypes.AdminCollection[]
if (addedCollections.length > 0) { if (addedCollections.length > 0) {
const newConditions = addedCollections.map((p) => ({ const newConditions = addedCollections.map((p) => ({
@@ -1,10 +1,10 @@
import { ProductCollectionDTO } from "@medusajs/types" import { HttpTypes } from "@medusajs/types"
import { Checkbox } from "@medusajs/ui" import { Checkbox } from "@medusajs/ui"
import { createColumnHelper } from "@tanstack/react-table" import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
const columnHelper = createColumnHelper<ProductCollectionDTO>() const columnHelper = createColumnHelper<HttpTypes.AdminCollection>()
export const useProductCollectionConditionsTableColumns = () => { export const useProductCollectionConditionsTableColumns = () => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -1,10 +1,10 @@
import { Product } from "@medusajs/medusa"
import { Checkbox } from "@medusajs/ui" import { Checkbox } from "@medusajs/ui"
import { createColumnHelper } from "@tanstack/react-table" import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
import { useProductTableColumns } from "../../../../../hooks/table/columns/use-product-table-columns" import { useProductTableColumns } from "../../../../../hooks/table/columns/use-product-table-columns"
import { HttpTypes } from "@medusajs/types"
const columnHelper = createColumnHelper<Product>() const columnHelper = createColumnHelper<HttpTypes.AdminProduct>()
export const useProductConditionsTableColumns = () => { export const useProductConditionsTableColumns = () => {
const base = useProductTableColumns() const base = useProductTableColumns()
@@ -1,10 +1,10 @@
import { ProductType } from "@medusajs/medusa" import { HttpTypes } from "@medusajs/types"
import { Checkbox } from "@medusajs/ui" import { Checkbox } from "@medusajs/ui"
import { createColumnHelper } from "@tanstack/react-table" import { createColumnHelper } from "@tanstack/react-table"
import { useMemo } from "react" import { useMemo } from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
const columnHelper = createColumnHelper<ProductType>() const columnHelper = createColumnHelper<HttpTypes.AdminProductType>()
export const useProductTypeConditionsTableColumns = () => { export const useProductTypeConditionsTableColumns = () => {
const { t } = useTranslation() const { t } = useTranslation()
@@ -13,11 +13,6 @@ import {
OrderDTO, OrderDTO,
PaymentProviderDTO, PaymentProviderDTO,
PriceListDTO, PriceListDTO,
ProductCategoryDTO,
ProductCollectionDTO,
ProductDTO,
ProductTypeDTO,
ProductVariantDTO,
PromotionDTO, PromotionDTO,
PromotionRuleDTO, PromotionRuleDTO,
SalesChannelDTO, SalesChannelDTO,
@@ -27,9 +22,9 @@ import {
StockLocationDTO, StockLocationDTO,
StoreDTO, StoreDTO,
UserDTO, UserDTO,
HttpTypes,
} from "@medusajs/types" } from "@medusajs/types"
import { ProductTagDTO } from "@medusajs/types/dist/product"
import { WorkflowExecutionDTO } from "../routes/workflow-executions/types" import { WorkflowExecutionDTO } from "../routes/workflow-executions/types"
type ListRes = { type ListRes = {
@@ -105,29 +100,6 @@ export type InviteDeleteRes = DeleteRes
export type OrderRes = { order: OrderDTO } export type OrderRes = { order: OrderDTO }
export type OrderListRes = { orders: OrderDTO[] } & ListRes export type OrderListRes = { orders: OrderDTO[] } & ListRes
// Products
export type ExtendedProductDTO = ProductDTO & {
variants: ProductVariantDTO[] | null
sales_channels: SalesChannelDTO[] | null
collections: ProductCollectionDTO[] | null
categories: ProductCategoryDTO[] | null
}
export type ProductRes = { product: ExtendedProductDTO }
export type ProductListRes = { products: ExtendedProductDTO[] } & ListRes
export type ProductDeleteRes = DeleteRes
// Categories
export type CategoryRes = { category: ProductCategoryDTO }
export type CategoriesListRes = { categories: ProductCategoryDTO[] } & ListRes
// Tags
export type TagRes = { tag: ProductTagDTO }
export type TagsListRes = { tags: ProductTagDTO[] } & ListRes
// Product Types
export type ProductTypeRes = { product_type: ProductTypeDTO }
export type ProductTypeListRes = { product_types: ProductTypeDTO[] } & ListRes
// Payments // Payments
export type PaymentProvidersListRes = { export type PaymentProvidersListRes = {
+217 -1
View File
@@ -8,12 +8,27 @@ export class Product {
this.client = client this.client = client
} }
async batch(
body: HttpTypes.AdminBatchProductRequest,
query?: SelectParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminBatchProductResponse>(
`/admin/products/batch`,
{
method: "POST",
headers,
body,
query,
}
)
}
async create( async create(
body: HttpTypes.AdminCreateProduct, body: HttpTypes.AdminCreateProduct,
query?: SelectParams, query?: SelectParams,
headers?: ClientHeaders headers?: ClientHeaders
) { ) {
return await this.client.fetch<{ product: HttpTypes.AdminProduct }>( return await this.client.fetch<HttpTypes.AdminProductResponse>(
`/admin/products`, `/admin/products`,
{ {
method: "POST", method: "POST",
@@ -23,4 +38,205 @@ export class Product {
} }
) )
} }
async update(
id: string,
body: HttpTypes.AdminUpdateProduct,
query?: SelectParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminProductResponse>(
`/admin/products/${id}`,
{
method: "POST",
headers,
body,
query,
}
)
}
async list(
queryParams?: HttpTypes.AdminProductParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminProductListResponse>(
`/admin/products`,
{
headers,
query: queryParams,
}
)
}
async retrieve(id: string, query?: SelectParams, headers?: ClientHeaders) {
return await this.client.fetch<HttpTypes.AdminProductResponse>(
`/admin/products/${id}`,
{
query,
headers,
}
)
}
async delete(id: string, headers?: ClientHeaders) {
return await this.client.fetch<HttpTypes.AdminProductDeleteResponse>(
`/admin/products/${id}`,
{
method: "DELETE",
headers,
}
)
}
async batchVariants(
productId: string,
body: HttpTypes.AdminBatchProductVariantRequest,
query?: SelectParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminBatchProductVariantResponse>(
`/admin/products/${productId}/variants/batch`,
{
method: "POST",
headers,
body,
query,
}
)
}
async createVariant(
productId: string,
body: HttpTypes.AdminCreateProductVariant,
query?: SelectParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminProductResponse>(
`/admin/products/${productId}/variants`,
{
method: "POST",
headers,
body,
query,
}
)
}
async updateVariant(
productId: string,
id: string,
body: HttpTypes.AdminUpdateProductVariant,
query?: SelectParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminProductResponse>(
`/admin/products/${productId}/variants/${id}`,
{
method: "POST",
headers,
body,
query,
}
)
}
async listVariants(
productId: string,
queryParams?: HttpTypes.AdminProductVariantParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminProductVariantListResponse>(
`/admin/products/${productId}/variants`,
{
headers,
query: queryParams,
}
)
}
async retrieveVariant(
productId: string,
id: string,
query?: SelectParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminProductVariantResponse>(
`/admin/products/${productId}/variants/${id}`,
{
query,
headers,
}
)
}
async deleteVariant(productId: string, id: string, headers?: ClientHeaders) {
return await this.client.fetch<HttpTypes.AdminProductVariantDeleteResponse>(
`/admin/products/${productId}/variants/${id}`,
{
method: "DELETE",
headers,
}
)
}
async createOption(
productId: string,
body: HttpTypes.AdminCreateProductOption,
query?: SelectParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminProductResponse>(
`/admin/products/${productId}/options`,
{
method: "POST",
headers,
body,
query,
}
)
}
async updateOption(
productId: string,
id: string,
body: HttpTypes.AdminUpdateProductOption,
query?: SelectParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminProductResponse>(
`/admin/products/${productId}/variants/${id}`,
{
method: "POST",
headers,
body,
query,
}
)
}
async listOptions(
productId: string,
queryParams?: HttpTypes.AdminProductOptionParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminProductOptionListResponse>(
`/admin/products/${productId}/options`,
{
headers,
query: queryParams,
}
)
}
async retrieveOption(
productId: string,
id: string,
query?: SelectParams,
headers?: ClientHeaders
) {
return await this.client.fetch<HttpTypes.AdminProductOptionResponse>(
`/admin/products/${productId}/options/${id}`,
{
query,
headers,
}
)
}
async deleteOption(productId: string, id: string, headers?: ClientHeaders) {
return await this.client.fetch<HttpTypes.AdminProductOptionDeleteResponse>(
`/admin/products/${productId}/options/${id}`,
{
method: "DELETE",
headers,
}
)
}
} }
+10 -9
View File
@@ -71,7 +71,7 @@ export class Store {
public category = { public category = {
list: async ( list: async (
query?: FindParams & HttpTypes.StoreProductCategoryFilters, query?: HttpTypes.StoreProductCategoryParams,
headers?: ClientHeaders headers?: ClientHeaders
) => { ) => {
return this.client.fetch< return this.client.fetch<
@@ -99,22 +99,23 @@ export class Store {
public product = { public product = {
list: async ( list: async (
query?: FindParams & HttpTypes.StoreProductFilters, query?: HttpTypes.StoreProductParams,
headers?: ClientHeaders headers?: ClientHeaders
) => { ) => {
return this.client.fetch< return this.client.fetch<HttpTypes.StoreProductListResponse>(
PaginatedResponse<{ products: HttpTypes.StoreProduct[] }> `/store/products`,
>(`/store/products`, { {
query, query,
headers, headers,
}) }
)
}, },
retrieve: async ( retrieve: async (
id: string, id: string,
query?: SelectParams, query?: SelectParams,
headers?: ClientHeaders headers?: ClientHeaders
) => { ) => {
return this.client.fetch<{ product: HttpTypes.StoreProduct }>( return this.client.fetch<HttpTypes.StoreProductResponse>(
`/store/products/${id}`, `/store/products/${id}`,
{ {
query, query,
@@ -1,96 +0,0 @@
import {
BaseProduct,
BaseProductCategory,
BaseProductCategoryFilters,
BaseProductFilters,
BaseProductImage,
BaseProductOption,
BaseProductOptionFilters,
BaseProductOptionValue,
BaseProductTag,
BaseProductTagFilters,
BaseProductType,
BaseProductTypeFilters,
BaseProductVariant,
BaseProductVariantFilters,
} from "./common"
export interface AdminProduct extends Omit<BaseProduct, "categories"> {
categories?: AdminProductCategory[]
}
export interface AdminProductCategory extends BaseProductCategory {
is_active?: boolean
is_internal?: boolean
}
export interface AdminProductVariant extends BaseProductVariant {}
export interface AdminProductTag extends BaseProductTag {}
export interface AdminProductType extends BaseProductType {}
export interface AdminProductOption extends BaseProductOption {}
export interface AdminProductImage extends BaseProductImage {}
export interface AdminProductOptionValue extends BaseProductOptionValue {}
export interface AdminProductFilters extends BaseProductFilters {}
export interface AdminProductTagFilters extends BaseProductTagFilters {}
export interface AdminProductTypeFilters extends BaseProductTypeFilters {}
export interface AdminProductOptionFilters extends BaseProductOptionFilters {}
export interface AdminProductVariantFilters extends BaseProductVariantFilters {}
export interface AdminProductCategoryFilters
extends BaseProductCategoryFilters {}
export interface AdminCreateProductVariantPrice {
currency_code: string
amount: number
min_quantity?: number
max_quantity?: number
}
export interface AdminCreateProductVariant {
title: string
sku?: string
ean?: string
upc?: string
barcode?: string
hs_code?: string
mid_code?: string
allow_backorder?: boolean
manage_inventory?: boolean
variant_rank?: number
weight?: number
length?: number
height?: number
width?: number
origin_country?: string
material?: string
metadata?: Record<string, any>
prices: AdminCreateProductVariantPrice[]
options?: Record<string, any>
}
export interface AdminCreateProduct {
title: string
subtitle?: string
description?: string
is_giftcard?: boolean
discountable?: boolean
images?: { url: string }[]
thumbnail?: string
handle?: string
status?: string
type_id?: string | null
collection_id?: string | null
categories?: { id: string }[]
tags?: { id?: string; value?: string }[]
options?: { title?: string; values?: string[] }[]
variants?: AdminCreateProductVariant[]
sales_channels?: { id: string }[]
weight?: number
length?: number
height?: number
width?: number
hs_code?: string
mid_code?: string
origin_country?: string
material?: string
metadata?: Record<string, any>
}
@@ -0,0 +1,33 @@
import { AdminPrice } from "../../pricing"
import { AdminSalesChannel } from "../../sales-channel"
import {
BaseProduct,
BaseProductCategory,
BaseProductImage,
BaseProductOption,
BaseProductOptionValue,
BaseProductTag,
BaseProductType,
BaseProductVariant,
ProductStatus,
} from "../common"
export interface AdminProductCategory extends BaseProductCategory {
is_active?: boolean
is_internal?: boolean
}
export interface AdminProductVariant extends BaseProductVariant {
prices: AdminPrice[] | null
}
export interface AdminProductTag extends BaseProductTag {}
export interface AdminProductType extends BaseProductType {}
export interface AdminProductOption extends BaseProductOption {}
export interface AdminProductImage extends BaseProductImage {}
export interface AdminProductOptionValue extends BaseProductOptionValue {}
export interface AdminProduct
extends Omit<BaseProduct, "categories" | "variants"> {
categories?: AdminProductCategory[] | null
sales_channels?: AdminSalesChannel[] | null
variants?: AdminProductVariant[] | null
}
export type AdminProductStatus = ProductStatus
@@ -0,0 +1,4 @@
export * from "./entitites"
export * from "./payloads"
export * from "./responses"
export * from "./queries"
@@ -0,0 +1,127 @@
import { BatchMethodRequest } from "../../../common"
import { ProductStatus } from "../common"
export interface AdminBatchProductRequest
extends BatchMethodRequest<AdminCreateProduct, AdminUpdateProduct> {}
export interface AdminBatchProductVariantRequest
extends BatchMethodRequest<
AdminCreateProductVariant,
AdminUpdateProductVariant
> {}
export interface AdminCreateProductVariantPrice {
currency_code: string
amount: number
min_quantity?: number | null
max_quantity?: number | null
}
export interface AdminCreateProductVariant {
title: string
sku?: string
ean?: string
upc?: string
barcode?: string
hs_code?: string
mid_code?: string
allow_backorder?: boolean
manage_inventory?: boolean
variant_rank?: number
weight?: number
length?: number
height?: number
width?: number
origin_country?: string
material?: string
metadata?: Record<string, unknown>
prices: AdminCreateProductVariantPrice[]
options?: Record<string, string>
}
export interface AdminCreateProduct {
title: string
subtitle?: string
description?: string
is_giftcard?: boolean
discountable?: boolean
images?: { url: string }[]
thumbnail?: string
handle?: string
status?: ProductStatus
type_id?: string
collection_id?: string
categories?: { id: string }[]
tags?: { id?: string; value?: string }[]
options?: AdminCreateProductOption[]
variants?: AdminCreateProductVariant[]
sales_channels?: { id: string }[]
weight?: number
length?: number
height?: number
width?: number
hs_code?: string
mid_code?: string
origin_country?: string
material?: string
metadata?: Record<string, unknown>
}
export interface AdminUpdateProductVariant {
title?: string
sku?: string | null
ean?: string | null
upc?: string | null
barcode?: string | null
hs_code?: string | null
mid_code?: string | null
allow_backorder?: boolean
manage_inventory?: boolean
variant_rank?: number
weight?: number | null
length?: number | null
height?: number | null
width?: number | null
origin_country?: string | null
material?: string | null
metadata?: Record<string, unknown> | null
prices?: AdminCreateProductVariantPrice[]
options?: Record<string, string>
}
export interface AdminUpdateProduct {
title?: string
subtitle?: string | null
description?: string | null
is_giftcard?: boolean
discountable?: boolean
images?: { url: string }[]
thumbnail?: string | null
handle?: string
status?: ProductStatus
type_id?: string | null
collection_id?: string | null
categories?: { id: string }[]
tags?: { id?: string; value?: string }[]
options?: AdminUpdateProductOption[]
variants?: AdminCreateProductVariant[]
sales_channels?: { id: string }[]
weight?: number | null
length?: number | null
height?: number | null
width?: number | null
hs_code?: string | null
mid_code?: string | null
origin_country?: string | null
material?: string | null
metadata?: Record<string, unknown> | null
}
export interface AdminCreateProductOption {
title: string
values: string[]
}
export interface AdminUpdateProductOption {
title?: string
values?: string[]
}
@@ -0,0 +1,18 @@
import {
BaseProductCategoryParams,
BaseProductOptionParams,
BaseProductParams,
BaseProductTagParams,
BaseProductTypeParams,
BaseProductVariantParams,
} from "../common"
export interface AdminProductTagParams extends BaseProductTagParams {}
export interface AdminProductTypeParams extends BaseProductTypeParams {}
export interface AdminProductOptionParams extends BaseProductOptionParams {}
export interface AdminProductVariantParams extends BaseProductVariantParams {}
export interface AdminProductParams extends BaseProductParams {
price_list_id?: string | string[]
variants?: AdminProductVariantParams
}
export interface AdminProductCategoryParams extends BaseProductCategoryParams {}
@@ -0,0 +1,45 @@
import { BatchMethodResponse } from "../../../common"
import { DeleteResponse, PaginatedResponse } from "../../common"
import {
AdminProduct,
AdminProductOption,
AdminProductVariant,
} from "./entitites"
export interface AdminProductResponse {
product: AdminProduct
}
export type AdminProductListResponse = PaginatedResponse<{
products: AdminProduct[]
}>
export interface AdminProductDeleteResponse extends DeleteResponse<"product"> {}
export interface AdminBatchProductResponse
extends BatchMethodResponse<AdminProduct> {}
export interface AdminProductVariantResponse {
variant: AdminProductVariant
}
export type AdminProductVariantListResponse = PaginatedResponse<{
variants: AdminProductVariant[]
}>
export interface AdminProductVariantDeleteResponse
extends DeleteResponse<"variant", AdminProduct> {}
export interface AdminBatchProductVariantResponse
extends BatchMethodResponse<AdminProductVariant> {}
export interface AdminProductOptionResponse {
product_option: AdminProductOption
}
export type AdminProductOptionListResponse = PaginatedResponse<{
product_options: AdminProductOption[]
}>
export interface AdminProductOptionDeleteResponse
extends DeleteResponse<"product_option", AdminProduct> {}
+94 -86
View File
@@ -1,94 +1,94 @@
import { BaseFilterable, OperatorMap } from "../../dal" import { BaseFilterable, OperatorMap } from "../../dal"
import { BaseCollection } from "../collection/common" import { BaseCollection } from "../collection/common"
import { FindParams } from "../common"
export type ProductStatus = "draft" | "proposed" | "published" | "rejected" export type ProductStatus = "draft" | "proposed" | "published" | "rejected"
export interface BaseProduct { export interface BaseProduct {
id?: string id: string
title?: string title: string
handle?: string handle: string
subtitle?: string | null subtitle: string | null
description?: string | null description: string | null
is_giftcard?: boolean is_giftcard: boolean
status?: ProductStatus status: ProductStatus
thumbnail?: string thumbnail: string | null
width?: number width: number | null
weight?: number weight: number | null
length?: number length: number | null
height?: number height: number | null
origin_country?: string origin_country: string | null
hs_code?: string hs_code: string | null
mid_code?: string mid_code: string | null
material?: string material: string | null
collection?: BaseCollection collection: BaseCollection | null
collection_id?: string | null collection_id: string | null
categories?: BaseProductCategory[] categories?: BaseProductCategory[] | null
type?: BaseProductType | null type: BaseProductType | null
type_id?: string | null type_id: string | null
tags?: BaseProductTag[] tags: BaseProductTag[] | null
variants?: BaseProductVariant[] variants: BaseProductVariant[] | null
options?: BaseProductOption[] options: BaseProductOption[] | null
images?: BaseProductImage[] images: BaseProductImage[] | null
discountable?: boolean discountable: boolean
external_id?: string | null external_id: string | null
created_at?: string created_at: string | null
updated_at?: string updated_at: string | null
deleted_at?: string | null deleted_at: string | null
metadata?: Record<string, unknown> | null metadata?: Record<string, unknown> | null
} }
export interface BaseProductVariant { export interface BaseProductVariant {
id?: string id: string
title?: string title: string | null
sku?: string sku: string | null
barcode?: string barcode: string | null
ean?: string ean: string | null
upc?: string upc: string | null
allow_backorder?: boolean allow_backorder: boolean | null
manage_inventory?: boolean manage_inventory: boolean | null
hs_code?: string hs_code: string | null
origin_country?: string origin_country: string | null
mid_code?: string mid_code: string | null
material?: string material: string | null
weight?: number weight: number | null
length?: number length: number | null
height?: number height: number | null
width?: number width: number | null
options?: BaseProductOptionValue[] options: BaseProductOptionValue[] | null
product?: BaseProduct product?: BaseProduct | null
product_id?: string | null product_id?: string
variant_rank?: number variant_rank?: number | null
created_at?: string created_at: string
updated_at?: string updated_at: string
deleted_at?: string | null deleted_at: string | null
metadata?: Record<string, unknown> | null metadata?: Record<string, unknown> | null
} }
export interface BaseProductCategory { export interface BaseProductCategory {
id?: string id: string
name?: string name: string
description?: string | null description: string | null
handle?: string handle: string
rank?: number rank?: number
parent_category?: BaseProductCategory parent_category?: BaseProductCategory | null
parent_category_id?: string parent_category_id?: string | null
category_children?: BaseProductCategory[] category_children?: BaseProductCategory[]
products?: BaseProduct[] products?: BaseProduct[]
created_at?: string created_at?: string
updated_at?: string updated_at?: string
metadata?: Record<string, unknown> metadata?: Record<string, unknown> | null
} }
export interface BaseProductTag { export interface BaseProductTag {
id?: string id: string
value?: string value: string
products?: BaseProduct[] products?: BaseProduct[]
metadata?: Record<string, unknown> | null metadata?: Record<string, unknown> | null
} }
export interface BaseProductType { export interface BaseProductType {
id?: string id: string
value?: string value: string
created_at?: string created_at?: string
updated_at?: string updated_at?: string
deleted_at?: string | null deleted_at?: string | null
@@ -96,10 +96,10 @@ export interface BaseProductType {
} }
export interface BaseProductOption { export interface BaseProductOption {
id?: string id: string
title?: string title: string
product?: BaseProduct product?: BaseProduct | null
product_id?: string product_id?: string | null
values?: BaseProductOptionValue[] values?: BaseProductOptionValue[]
metadata?: Record<string, unknown> | null metadata?: Record<string, unknown> | null
created_at?: string created_at?: string
@@ -108,8 +108,8 @@ export interface BaseProductOption {
} }
export interface BaseProductImage { export interface BaseProductImage {
id?: string id: string
url?: string url: string
created_at?: string created_at?: string
updated_at?: string updated_at?: string
deleted_at?: string | null deleted_at?: string | null
@@ -117,19 +117,22 @@ export interface BaseProductImage {
} }
export interface BaseProductOptionValue { export interface BaseProductOptionValue {
id?: string id: string
value?: string value: string
option?: BaseProductOption option?: BaseProductOption | null
option_id?: string option_id?: string | null
metadata?: Record<string, unknown> | null metadata?: Record<string, unknown> | null
created_at?: string created_at?: string
updated_at?: string updated_at?: string
deleted_at?: string | null deleted_at?: string | null
} }
export interface BaseProductFilters extends BaseFilterable<BaseProductFilters> { export interface BaseProductParams
extends FindParams,
BaseFilterable<BaseProductParams> {
q?: string q?: string
status?: ProductStatus | ProductStatus[] status?: ProductStatus | ProductStatus[]
sales_channel_id?: string | string[]
title?: string | string[] title?: string | string[]
handle?: string | string[] handle?: string | string[]
id?: string | string[] id?: string | string[]
@@ -146,30 +149,34 @@ export interface BaseProductFilters extends BaseFilterable<BaseProductFilters> {
deleted_at?: OperatorMap<string> deleted_at?: OperatorMap<string>
} }
export interface BaseProductTagFilters export interface BaseProductTagParams
extends BaseFilterable<BaseProductTagFilters> { extends FindParams,
BaseFilterable<BaseProductTagParams> {
q?: string q?: string
id?: string | string[] id?: string | string[]
value?: string | string[] value?: string | string[]
} }
export interface BaseProductTypeFilters export interface BaseProductTypeParams
extends BaseFilterable<BaseProductTypeFilters> { extends FindParams,
BaseFilterable<BaseProductTypeParams> {
q?: string q?: string
id?: string | string[] id?: string | string[]
value?: string value?: string
} }
export interface BaseProductOptionFilters export interface BaseProductOptionParams
extends BaseFilterable<BaseProductOptionFilters> { extends FindParams,
BaseFilterable<BaseProductOptionParams> {
q?: string q?: string
id?: string | string[] id?: string | string[]
title?: string | string[] title?: string | string[]
product_id?: string | string[] product_id?: string | string[]
} }
export interface BaseProductVariantFilters export interface BaseProductVariantParams
extends BaseFilterable<BaseProductVariantFilters> { extends FindParams,
BaseFilterable<BaseProductVariantParams> {
q?: string q?: string
id?: string | string[] id?: string | string[]
sku?: string | string[] sku?: string | string[]
@@ -177,8 +184,9 @@ export interface BaseProductVariantFilters
options?: Record<string, string> options?: Record<string, string>
} }
export interface BaseProductCategoryFilters export interface BaseProductCategoryParams
extends BaseFilterable<BaseProductCategoryFilters> { extends FindParams,
BaseFilterable<BaseProductCategoryParams> {
q?: string q?: string
id?: string | string[] id?: string | string[]
name?: string | string[] name?: string | string[]
@@ -1,38 +0,0 @@
import {
BaseProduct,
BaseProductCategory,
BaseProductCategoryFilters,
BaseProductFilters,
BaseProductImage,
BaseProductOption,
BaseProductOptionFilters,
BaseProductOptionValue,
BaseProductTag,
BaseProductTagFilters,
BaseProductType,
BaseProductTypeFilters,
BaseProductVariant,
BaseProductVariantFilters,
} from "./common"
export interface StoreProduct extends BaseProduct {}
export interface StoreProductCategory extends BaseProductCategory {}
export interface StoreProductVariant extends BaseProductVariant {}
export interface StoreProductTag extends BaseProductTag {}
export interface StoreProductType extends BaseProductType {}
export interface StoreProductOption extends BaseProductOption {}
export interface StoreProductImage extends BaseProductImage {}
export interface StoreProductOptionValue extends BaseProductOptionValue {}
export interface StoreProductTagFilters extends BaseProductTagFilters {}
export interface StoreProductTypeFilters extends BaseProductTypeFilters {}
export interface StoreProductOptionFilters extends BaseProductOptionFilters {}
export interface StoreProductVariantFilters extends BaseProductVariantFilters {}
export interface StoreProductFilters extends BaseProductFilters {
// The region ID and currency_code are not filters, but are used for the pricing context. Maybe move to separate type definition.
region_id?: string
currency_code?: string
variants?: StoreProductVariantFilters
}
export interface StoreProductCategoryFilters
extends BaseProductCategoryFilters {}
@@ -0,0 +1,21 @@
import {
BaseProduct,
BaseProductCategory,
BaseProductImage,
BaseProductOption,
BaseProductOptionValue,
BaseProductTag,
BaseProductType,
BaseProductVariant,
ProductStatus,
} from "../common"
export interface StoreProduct extends BaseProduct {}
export interface StoreProductCategory extends BaseProductCategory {}
export interface StoreProductVariant extends BaseProductVariant {}
export interface StoreProductTag extends BaseProductTag {}
export interface StoreProductType extends BaseProductType {}
export interface StoreProductOption extends BaseProductOption {}
export interface StoreProductImage extends BaseProductImage {}
export interface StoreProductOptionValue extends BaseProductOptionValue {}
export type StoreProductStatus = ProductStatus
@@ -0,0 +1,3 @@
export * from "./entitites"
export * from "./responses"
export * from "./queries"
@@ -0,0 +1,20 @@
import {
BaseProductCategoryParams,
BaseProductParams,
BaseProductOptionParams,
BaseProductTagParams,
BaseProductTypeParams,
BaseProductVariantParams,
} from "../common"
export interface StoreProductTagParams extends BaseProductTagParams {}
export interface StoreProductTypeParams extends BaseProductTypeParams {}
export interface StoreProductOptionParams extends BaseProductOptionParams {}
export interface StoreProductVariantParams extends BaseProductVariantParams {}
export interface StoreProductParams extends BaseProductParams {
// The region ID and currency_code are not params, but are used for the pricing context. Maybe move to separate type definition.
region_id?: string
currency_code?: string
variants?: StoreProductVariantParams
}
export interface StoreProductCategoryParams extends BaseProductCategoryParams {}
@@ -0,0 +1,10 @@
import { PaginatedResponse } from "../../common"
import { StoreProduct } from "../store"
export interface StoreProductResponse {
product: StoreProduct
}
export type StoreProductListResponse = PaginatedResponse<{
products: StoreProduct[]
}>
@@ -1,7 +1,9 @@
import { OperatorMap } from "../../../dal" import { BaseFilterable, OperatorMap } from "../../../dal"
import { FindParams } from "../../common" import { FindParams } from "../../common"
export interface AdminSalesChannelListParams extends FindParams { export interface AdminSalesChannelListParams
extends FindParams,
BaseFilterable<AdminSalesChannelListParams> {
id?: string | string[] id?: string | string[]
q?: string q?: string
name?: string | string[] name?: string | string[]
@@ -12,6 +14,4 @@ export interface AdminSalesChannelListParams extends FindParams {
created_at?: OperatorMap<string> created_at?: OperatorMap<string>
updated_at?: OperatorMap<string> updated_at?: OperatorMap<string>
deleted_at?: OperatorMap<string> deleted_at?: OperatorMap<string>
$and?: AdminSalesChannelListParams[]
$or?: AdminSalesChannelListParams[]
} }
+61 -61
View File
@@ -23,15 +23,15 @@ export interface ProductDTO {
/** /**
* The handle of the product. The handle can be used to create slug URL paths. * The handle of the product. The handle can be used to create slug URL paths.
*/ */
handle?: string | null handle: string
/** /**
* The subttle of the product. * The subttle of the product.
*/ */
subtitle?: string | null subtitle: string | null
/** /**
* The description of the product. * The description of the product.
*/ */
description?: string | null description: string | null
/** /**
* Whether the product is a gift card. * Whether the product is a gift card.
*/ */
@@ -43,49 +43,49 @@ export interface ProductDTO {
/** /**
* The URL of the product's thumbnail. * The URL of the product's thumbnail.
*/ */
thumbnail?: string | null thumbnail: string | null
/** /**
* The width of the product. * The width of the product.
*/ */
width?: number | null width: number | null
/** /**
* The weight of the product. * The weight of the product.
*/ */
weight?: number | null weight: number | null
/** /**
* The length of the product. * The length of the product.
*/ */
length?: number | null length: number | null
/** /**
* The height of the product. * The height of the product.
*/ */
height?: number | null height: number | null
/** /**
* The origin country of the product. * The origin country of the product.
*/ */
origin_country?: string | null origin_country: string | null
/** /**
* The HS Code of the product. * The HS Code of the product.
*/ */
hs_code?: string | null hs_code: string | null
/** /**
* The MID Code of the product. * The MID Code of the product.
*/ */
mid_code?: string | null mid_code: string | null
/** /**
* The material of the product. * The material of the product.
*/ */
material?: string | null material: string | null
/** /**
* The associated product collection. * The associated product collection.
* *
* @expandable * @expandable
*/ */
collection?: ProductCollectionDTO | null collection: ProductCollectionDTO | null
/** /**
* The associated product collection id. * The associated product collection id.
*/ */
collection_id?: string | null collection_id: string | null
/** /**
* The associated product categories. * The associated product categories.
* *
@@ -97,11 +97,11 @@ export interface ProductDTO {
* *
* @expandable * @expandable
*/ */
type?: ProductTypeDTO | null type: ProductTypeDTO | null
/** /**
* The associated product type id. * The associated product type id.
*/ */
type_id?: string | null type_id: string | null
/** /**
* The associated product tags. * The associated product tags.
* *
@@ -134,19 +134,19 @@ export interface ProductDTO {
* The ID of the product in an external system. This is useful if you're integrating the product with a third-party service and want to maintain * The ID of the product in an external system. This is useful if you're integrating the product with a third-party service and want to maintain
* a reference to the ID in the integrated service. * a reference to the ID in the integrated service.
*/ */
external_id?: string | null external_id: string | null
/** /**
* When the product was created. * When the product was created.
*/ */
created_at?: string | Date created_at: string | Date
/** /**
* When the product was updated. * When the product was updated.
*/ */
updated_at?: string | Date updated_at: string | Date
/** /**
* When the product was deleted. * When the product was deleted.
*/ */
deleted_at?: string | Date deleted_at: string | Date
/** /**
* Holds custom data in key-value pairs. * Holds custom data in key-value pairs.
*/ */
@@ -170,59 +170,59 @@ export interface ProductVariantDTO {
/** /**
* The SKU of the product variant. * The SKU of the product variant.
*/ */
sku?: string | null sku: string | null
/** /**
* The barcode of the product variant. * The barcode of the product variant.
*/ */
barcode?: string | null barcode: string | null
/** /**
* The EAN of the product variant. * The EAN of the product variant.
*/ */
ean?: string | null ean: string | null
/** /**
* The UPC of the product variant. * The UPC of the product variant.
*/ */
upc?: string | null upc: string | null
/** /**
* Whether the product variant can be ordered when it's out of stock. * Whether the product variant can be ordered when it's out of stock.
*/ */
allow_backorder?: boolean allow_backorder: boolean
/** /**
* Whether the product variant's inventory should be managed by the core system. * Whether the product variant's inventory should be managed by the core system.
*/ */
manage_inventory?: boolean manage_inventory: boolean
/** /**
* The HS Code of the product variant. * The HS Code of the product variant.
*/ */
hs_code?: string | null hs_code: string | null
/** /**
* The origin country of the product variant. * The origin country of the product variant.
*/ */
origin_country?: string | null origin_country: string | null
/** /**
* The MID Code of the product variant. * The MID Code of the product variant.
*/ */
mid_code?: string | null mid_code: string | null
/** /**
* The material of the product variant. * The material of the product variant.
*/ */
material?: string | null material: string | null
/** /**
* The weight of the product variant. * The weight of the product variant.
*/ */
weight?: number | null weight: number | null
/** /**
* The length of the product variant. * The length of the product variant.
*/ */
length?: number | null length: number | null
/** /**
* The height of the product variant. * The height of the product variant.
*/ */
height?: number | null height: number | null
/** /**
* The width of the product variant. * The width of the product variant.
*/ */
width?: number | null width: number | null
/** /**
* The associated product options. * The associated product options.
* *
@@ -232,7 +232,7 @@ export interface ProductVariantDTO {
/** /**
* Holds custom data in key-value pairs. * Holds custom data in key-value pairs.
*/ */
metadata?: Record<string, unknown> | null metadata: Record<string, unknown> | null
/** /**
* The associated product. * The associated product.
* *
@@ -242,7 +242,7 @@ export interface ProductVariantDTO {
/** /**
* The associated product id. * The associated product id.
*/ */
product_id?: string | null product_id: string | null
/** /**
* he ranking of the variant among other variants associated with the product. * he ranking of the variant among other variants associated with the product.
*/ */
@@ -1183,19 +1183,19 @@ export interface CreateProductVariantDTO {
/** /**
* The SKU of the product variant. * The SKU of the product variant.
*/ */
sku?: string | null sku?: string
/** /**
* The barcode of the product variant. * The barcode of the product variant.
*/ */
barcode?: string | null barcode?: string
/** /**
* The EAN of the product variant. * The EAN of the product variant.
*/ */
ean?: string | null ean?: string
/** /**
* The UPC of the product variant. * The UPC of the product variant.
*/ */
upc?: string | null upc?: string
/** /**
* Whether the product variant can be ordered when it's out of stock. * Whether the product variant can be ordered when it's out of stock.
*/ */
@@ -1207,35 +1207,35 @@ export interface CreateProductVariantDTO {
/** /**
* The HS Code of the product variant. * The HS Code of the product variant.
*/ */
hs_code?: string | null hs_code?: string
/** /**
* The origin country of the product variant. * The origin country of the product variant.
*/ */
origin_country?: string | null origin_country?: string
/** /**
* The MID Code of the product variant. * The MID Code of the product variant.
*/ */
mid_code?: string | null mid_code?: string
/** /**
* The material of the product variant. * The material of the product variant.
*/ */
material?: string | null material?: string
/** /**
* The weight of the product variant. * The weight of the product variant.
*/ */
weight?: number | null weight?: number
/** /**
* The length of the product variant. * The length of the product variant.
*/ */
length?: number | null length?: number
/** /**
* The height of the product variant. * The height of the product variant.
*/ */
height?: number | null height?: number
/** /**
* The width of the product variant. * The width of the product variant.
*/ */
width?: number | null width?: number
/** /**
* The options of the variant. Each key is an option's title, and value * The options of the variant. Each key is an option's title, and value
* is an option's value. If an option with the specified title doesn't exist, * is an option's value. If an option with the specified title doesn't exist,
@@ -1340,7 +1340,7 @@ export interface UpdateProductVariantDTO {
/** /**
* Holds custom data in key-value pairs. * Holds custom data in key-value pairs.
*/ */
metadata?: Record<string, unknown> metadata?: Record<string, unknown> | null
} }
/** /**
@@ -1472,11 +1472,11 @@ export interface UpdateProductDTO {
/** /**
* The subttle of the product. * The subttle of the product.
*/ */
subtitle?: string subtitle?: string | null
/** /**
* The description of the product. * The description of the product.
*/ */
description?: string description?: string | null
/** /**
* Whether the product is a gift card. * Whether the product is a gift card.
*/ */
@@ -1488,7 +1488,7 @@ export interface UpdateProductDTO {
/** /**
* The URL of the product's thumbnail. * The URL of the product's thumbnail.
*/ */
thumbnail?: string thumbnail?: string | null
/** /**
* The handle of the product. The handle can be used to create slug URL paths. * The handle of the product. The handle can be used to create slug URL paths.
* If not supplied, the value of the `handle` attribute of the product is set to the slug version of the `title` attribute. * If not supplied, the value of the `handle` attribute of the product is set to the slug version of the `title` attribute.
@@ -1530,37 +1530,37 @@ export interface UpdateProductDTO {
/** /**
* The width of the product. * The width of the product.
*/ */
width?: number width?: number | null
/** /**
* The height of the product. * The height of the product.
*/ */
height?: number height?: number | null
/** /**
* The length of the product. * The length of the product.
*/ */
length?: number length?: number | null
/** /**
* The weight of the product. * The weight of the product.
*/ */
weight?: number weight?: number | null
/** /**
* The origin country of the product. * The origin country of the product.
*/ */
origin_country?: string origin_country?: string | null
/** /**
* The HS Code of the product. * The HS Code of the product.
*/ */
hs_code?: string hs_code?: string | null
/** /**
* The material of the product. * The material of the product.
*/ */
material?: string material?: string | null
/** /**
* The MID Code of the product. * The MID Code of the product.
*/ */
mid_code?: string mid_code?: string | null
/** /**
* Holds custom data in key-value pairs. * Holds custom data in key-value pairs.
*/ */
metadata?: Record<string, unknown> metadata?: Record<string, unknown> | null
} }
@@ -6,9 +6,9 @@ export type CreateProductVariantWorkflowInputDTO =
} }
export type UpdateProductVariantWorkflowInputDTO = export type UpdateProductVariantWorkflowInputDTO =
(ProductTypes.UpsertProductVariantDTO & { ProductTypes.UpsertProductVariantDTO & {
prices?: PricingTypes.CreateMoneyAmountDTO[] prices?: PricingTypes.CreateMoneyAmountDTO[]
})[] }
export type CreateProductWorkflowInputDTO = Omit< export type CreateProductWorkflowInputDTO = Omit<
ProductTypes.CreateProductDTO, ProductTypes.CreateProductDTO,
@@ -7,37 +7,29 @@ import {
updateProductOptionsWorkflow, updateProductOptionsWorkflow,
} from "@medusajs/core-flows" } from "@medusajs/core-flows"
import { import { remapKeysForProduct, remapProductResponse } from "../../../helpers"
ContainerRegistrationKeys, import { HttpTypes } from "@medusajs/types"
remoteQueryObjectFromString, import { refetchEntity } from "../../../../../utils/refetch-entity"
} from "@medusajs/utils"
import { refetchProduct, remapProductResponse } from "../../../helpers"
import { AdminUpdateProductOptionType } from "../../../validators"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductOptionResponse>
) => { ) => {
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const productId = req.params.id const productId = req.params.id
const optionId = req.params.option_id const optionId = req.params.option_id
const productOption = await refetchEntity(
"product_option",
{ id: optionId, product_id: productId },
req.scope,
req.remoteQueryConfig.fields
)
const variables = { id: optionId, product_id: productId } res.status(200).json({ product_option: productOption })
const queryObject = remoteQueryObjectFromString({
entryPoint: "product_option",
variables,
fields: req.remoteQueryConfig.fields,
})
const [product_option] = await remoteQuery(queryObject)
res.status(200).json({ product_option })
} }
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest<AdminUpdateProductOptionType>, req: AuthenticatedMedusaRequest<HttpTypes.AdminUpdateProductOption>,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductResponse>
) => { ) => {
const productId = req.params.id const productId = req.params.id
const optionId = req.params.option_id const optionId = req.params.option_id
@@ -49,17 +41,19 @@ export const POST = async (
}, },
}) })
const product = await refetchProduct( const product = await refetchEntity(
"product",
productId, productId,
req.scope, req.scope,
req.remoteQueryConfig.fields remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
) )
res.status(200).json({ product: remapProductResponse(product) }) res.status(200).json({ product: remapProductResponse(product) })
} }
export const DELETE = async ( export const DELETE = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductOptionDeleteResponse>
) => { ) => {
const productId = req.params.id const productId = req.params.id
const optionId = req.params.option_id const optionId = req.params.option_id
@@ -69,10 +63,11 @@ export const DELETE = async (
input: { ids: [optionId] /* product_id: productId */ }, input: { ids: [optionId] /* product_id: productId */ },
}) })
const product = await refetchProduct( const product = await refetchEntity(
"product",
productId, productId,
req.scope, req.scope,
req.remoteQueryConfig.fields remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
) )
res.status(200).json({ res.status(200).json({
@@ -4,30 +4,25 @@ import {
} from "../../../../../types/routing" } from "../../../../../types/routing"
import { createProductOptionsWorkflow } from "@medusajs/core-flows" import { createProductOptionsWorkflow } from "@medusajs/core-flows"
import { remapKeysForProduct, remapProductResponse } from "../../helpers"
import { HttpTypes } from "@medusajs/types"
import { import {
ContainerRegistrationKeys, refetchEntities,
remoteQueryObjectFromString, refetchEntity,
} from "@medusajs/utils" } from "../../../../utils/refetch-entity"
import { refetchProduct, remapProductResponse } from "../../helpers"
import { AdminCreateProductOptionType } from "../../validators"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest<HttpTypes.AdminProductOptionParams>,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductOptionListResponse>
) => { ) => {
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const productId = req.params.id const productId = req.params.id
const { rows: product_options, metadata } = await refetchEntities(
const queryObject = remoteQueryObjectFromString({ "product_option",
entryPoint: "product_option", { ...req.filterableFields, product_id: productId },
variables: { req.scope,
filters: { ...req.filterableFields, product_id: productId }, req.remoteQueryConfig.fields,
...req.remoteQueryConfig.pagination, req.remoteQueryConfig.pagination
}, )
fields: req.remoteQueryConfig.fields,
})
const { rows: product_options, metadata } = await remoteQuery(queryObject)
res.json({ res.json({
product_options, product_options,
@@ -38,25 +33,26 @@ export const GET = async (
} }
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest<AdminCreateProductOptionType>, req: AuthenticatedMedusaRequest<HttpTypes.AdminCreateProductOption>,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductResponse>
) => { ) => {
const productId = req.params.id const productId = req.params.id
const input = [
{
...req.validatedBody,
product_id: productId,
},
]
await createProductOptionsWorkflow(req.scope).run({ await createProductOptionsWorkflow(req.scope).run({
input: { product_options: input }, input: {
product_options: [
{
...req.validatedBody,
product_id: productId,
},
],
},
}) })
const product = await refetchProduct( const product = await refetchEntity(
"product",
productId, productId,
req.scope, req.scope,
req.remoteQueryConfig.fields remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
) )
res.status(200).json({ product: remapProductResponse(product) }) res.status(200).json({ product: remapProductResponse(product) })
} }
@@ -6,36 +6,23 @@ import {
AuthenticatedMedusaRequest, AuthenticatedMedusaRequest,
MedusaResponse, MedusaResponse,
} from "../../../../types/routing" } from "../../../../types/routing"
import { remapKeysForProduct, remapProductResponse } from "../helpers"
import { UpdateProductDTO } from "@medusajs/types"
import {
ContainerRegistrationKeys,
remoteQueryObjectFromString,
} from "@medusajs/utils"
import {
refetchProduct,
remapKeysForProduct,
remapProductResponse,
} from "../helpers"
import { AdminUpdateProductType } from "../validators"
import { MedusaError } from "@medusajs/utils" import { MedusaError } from "@medusajs/utils"
import { HttpTypes } from "@medusajs/types"
import { refetchEntity } from "../../../utils/refetch-entity"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductResponse>
) => { ) => {
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const variables = { id: req.params.id }
const selectFields = remapKeysForProduct(req.remoteQueryConfig.fields ?? []) const selectFields = remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
const queryObject = remoteQueryObjectFromString({ const product = await refetchEntity(
entryPoint: "product", "product",
variables, req.params.id,
fields: selectFields, req.scope,
}) selectFields
)
const [product] = await remoteQuery(queryObject)
if (!product) { if (!product) {
throw new MedusaError(MedusaError.Types.NOT_FOUND, "Product not found") throw new MedusaError(MedusaError.Types.NOT_FOUND, "Product not found")
} }
@@ -44,27 +31,29 @@ export const GET = async (
} }
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest<AdminUpdateProductType>, req: AuthenticatedMedusaRequest<HttpTypes.AdminUpdateProduct>,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductResponse>
) => { ) => {
const { result } = await updateProductsWorkflow(req.scope).run({ const { result } = await updateProductsWorkflow(req.scope).run({
input: { input: {
selector: { id: req.params.id }, selector: { id: req.params.id },
update: req.validatedBody as UpdateProductDTO, update: req.validatedBody,
}, },
}) })
const product = await refetchProduct( const product = await refetchEntity(
"product",
result[0].id, result[0].id,
req.scope, req.scope,
req.remoteQueryConfig.fields remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
) )
res.status(200).json({ product: remapProductResponse(product) }) res.status(200).json({ product: remapProductResponse(product) })
} }
export const DELETE = async ( export const DELETE = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductDeleteResponse>
) => { ) => {
const id = req.params.id const id = req.params.id
@@ -8,44 +8,36 @@ import {
} from "@medusajs/core-flows" } from "@medusajs/core-flows"
import { import {
ContainerRegistrationKeys, remapKeysForProduct,
remoteQueryObjectFromString,
} from "@medusajs/utils"
import {
refetchProduct,
remapKeysForVariant, remapKeysForVariant,
remapProductResponse, remapProductResponse,
remapVariantResponse, remapVariantResponse,
} from "../../../helpers" } from "../../../helpers"
import { AdminUpdateProductVariantType } from "../../../validators" import { HttpTypes } from "@medusajs/types"
import { refetchEntity } from "../../../../../utils/refetch-entity"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductVariantResponse>
) => { ) => {
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
// TODO: Should we allow fetching a variant without knowing the product ID? In such case we'll need to change the route to /admin/products/variants/:id
const productId = req.params.id const productId = req.params.id
const variantId = req.params.variant_id const variantId = req.params.variant_id
const variables = { id: variantId, product_id: productId } const variables = { id: variantId, product_id: productId }
const queryObject = remoteQueryObjectFromString({ const variant = await refetchEntity(
entryPoint: "variant", "variant",
variables, variables,
fields: remapKeysForVariant(req.remoteQueryConfig.fields ?? []), req.scope,
}) remapKeysForVariant(req.remoteQueryConfig.fields ?? [])
)
const [variant] = await remoteQuery(queryObject)
res.status(200).json({ variant: remapVariantResponse(variant) }) res.status(200).json({ variant: remapVariantResponse(variant) })
} }
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest<AdminUpdateProductVariantType>, req: AuthenticatedMedusaRequest<HttpTypes.AdminUpdateProductVariant>,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductResponse>
) => { ) => {
// TODO: Should we allow fetching a variant without knowing the product ID? In such case we'll need to change the route to /admin/products/variants/:id
const productId = req.params.id const productId = req.params.id
const variantId = req.params.variant_id const variantId = req.params.variant_id
@@ -56,19 +48,19 @@ export const POST = async (
}, },
}) })
const product = await refetchProduct( const product = await refetchEntity(
"product",
productId, productId,
req.scope, req.scope,
req.remoteQueryConfig.fields remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
) )
res.status(200).json({ product: remapProductResponse(product) }) res.status(200).json({ product: remapProductResponse(product) })
} }
export const DELETE = async ( export const DELETE = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductVariantDeleteResponse>
) => { ) => {
// TODO: Should we allow fetching a variant without knowing the product ID? In such case we'll need to change the route to /admin/products/variants/:id
const productId = req.params.id const productId = req.params.id
const variantId = req.params.variant_id const variantId = req.params.variant_id
@@ -77,16 +69,17 @@ export const DELETE = async (
input: { ids: [variantId] /* product_id: productId */ }, input: { ids: [variantId] /* product_id: productId */ },
}) })
const product = await refetchProduct( const product = await refetchEntity(
"product",
productId, productId,
req.scope, req.scope,
req.remoteQueryConfig.fields remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
) )
res.status(200).json({ res.status(200).json({
id: variantId, id: variantId,
object: "variant", object: "variant",
deleted: true, deleted: true,
parent: product, parent: remapProductResponse(product),
}) })
} }
@@ -3,21 +3,12 @@ import {
AuthenticatedMedusaRequest, AuthenticatedMedusaRequest,
MedusaResponse, MedusaResponse,
} from "../../../../../../types/routing" } from "../../../../../../types/routing"
import {
AdminBatchUpdateProductVariantType,
AdminCreateProductType,
} from "../../../validators"
import { BatchMethodRequest } from "@medusajs/types"
import { refetchBatchVariants, remapVariantResponse } from "../../../helpers" import { refetchBatchVariants, remapVariantResponse } from "../../../helpers"
import { HttpTypes } from "@medusajs/types"
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest< req: AuthenticatedMedusaRequest<HttpTypes.AdminBatchProductVariantRequest>,
BatchMethodRequest< res: MedusaResponse<HttpTypes.AdminBatchProductVariantResponse>
AdminCreateProductType,
AdminBatchUpdateProductVariantType
>
>,
res: MedusaResponse
) => { ) => {
const productId = req.params.id const productId = req.params.id
@@ -31,8 +22,7 @@ export const POST = async (
product_id: productId, product_id: productId,
})), })),
delete: req.validatedBody.delete, delete: req.validatedBody.delete,
// TODO: Fix types }
} as any
const { result } = await batchProductVariantsWorkflow(req.scope).run({ const { result } = await batchProductVariantsWorkflow(req.scope).run({
input: normalizedInput, input: normalizedInput,
@@ -5,36 +5,29 @@ import {
import { createProductVariantsWorkflow } from "@medusajs/core-flows" import { createProductVariantsWorkflow } from "@medusajs/core-flows"
import { import {
remoteQueryObjectFromString, remapKeysForProduct,
ContainerRegistrationKeys,
} from "@medusajs/utils"
import {
refetchProduct,
remapKeysForVariant, remapKeysForVariant,
remapProductResponse, remapProductResponse,
remapVariantResponse, remapVariantResponse,
} from "../../helpers" } from "../../helpers"
import { AdminCreateProductVariantType } from "../../validators" import { HttpTypes } from "@medusajs/types"
import {
refetchEntities,
refetchEntity,
} from "../../../../utils/refetch-entity"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest, req: AuthenticatedMedusaRequest,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductVariantListResponse>
) => { ) => {
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const productId = req.params.id const productId = req.params.id
const { rows: variants, metadata } = await refetchEntities(
const queryObject = remoteQueryObjectFromString({ "variant",
entryPoint: "variant", { ...req.filterableFields, product_id: productId },
variables: { req.scope,
filters: { ...req.filterableFields, product_id: productId }, remapKeysForVariant(req.remoteQueryConfig.fields ?? []),
order: req.listConfig.order, req.remoteQueryConfig.pagination
skip: req.listConfig.skip, )
take: req.listConfig.take,
},
fields: remapKeysForVariant(req.remoteQueryConfig.fields ?? []),
})
const { rows: variants, metadata } = await remoteQuery(queryObject)
res.json({ res.json({
variants: variants.map(remapVariantResponse), variants: variants.map(remapVariantResponse),
@@ -45,8 +38,8 @@ export const GET = async (
} }
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest<AdminCreateProductVariantType>, req: AuthenticatedMedusaRequest<HttpTypes.AdminCreateProductVariant>,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductResponse>
) => { ) => {
const productId = req.params.id const productId = req.params.id
const input = [ const input = [
@@ -60,10 +53,12 @@ export const POST = async (
input: { product_variants: input }, input: { product_variants: input },
}) })
const product = await refetchProduct( const product = await refetchEntity(
"product",
productId, productId,
req.scope, req.scope,
req.remoteQueryConfig.fields remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
) )
res.status(200).json({ product: remapProductResponse(product) }) res.status(200).json({ product: remapProductResponse(product) })
} }
@@ -3,24 +3,15 @@ import {
AuthenticatedMedusaRequest, AuthenticatedMedusaRequest,
MedusaResponse, MedusaResponse,
} from "../../../../types/routing" } from "../../../../types/routing"
import {
AdminBatchUpdateProductType,
AdminCreateProductType,
} from "../validators"
import { BatchMethodRequest } from "@medusajs/types"
import { refetchBatchProducts, remapProductResponse } from "../helpers" import { refetchBatchProducts, remapProductResponse } from "../helpers"
import { HttpTypes } from "@medusajs/types"
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest< req: AuthenticatedMedusaRequest<HttpTypes.AdminBatchProductRequest>,
BatchMethodRequest<AdminCreateProductType, AdminBatchUpdateProductType> res: MedusaResponse<HttpTypes.AdminBatchProductResponse>
>,
res: MedusaResponse
) => { ) => {
// TODO: Fix types
const input = req.validatedBody as any
const { result } = await batchProductsWorkflow(req.scope).run({ const { result } = await batchProductsWorkflow(req.scope).run({
input, input: req.validatedBody,
}) })
const batchResults = await refetchBatchProducts( const batchResults = await refetchBatchProducts(
@@ -4,6 +4,7 @@ import {
MedusaContainer, MedusaContainer,
ProductDTO, ProductDTO,
ProductVariantDTO, ProductVariantDTO,
HttpTypes,
} from "@medusajs/types" } from "@medusajs/types"
import { import {
ContainerRegistrationKeys, ContainerRegistrationKeys,
@@ -46,19 +47,24 @@ export const remapKeysForVariant = (selectFields: string[]) => {
return [...variantFields, ...pricingFields] return [...variantFields, ...pricingFields]
} }
export const remapProductResponse = (product: ProductDTO) => { export const remapProductResponse = (
product: ProductDTO
): HttpTypes.AdminProduct => {
return { return {
...product, ...product,
variants: product.variants?.map(remapVariantResponse), variants: product.variants?.map(remapVariantResponse),
} // TODO: Remove any once all typings are cleaned up
} as any
} }
export const remapVariantResponse = (variant: ProductVariantDTO) => { export const remapVariantResponse = (
variant: ProductVariantDTO
): HttpTypes.AdminProductVariant => {
if (!variant) { if (!variant) {
return variant return variant
} }
return { const resp = {
...variant, ...variant,
prices: (variant as any).price_set?.prices?.map((price) => ({ prices: (variant as any).price_set?.prices?.map((price) => ({
id: price.id, id: price.id,
@@ -70,26 +76,11 @@ export const remapVariantResponse = (variant: ProductVariantDTO) => {
created_at: price.created_at, created_at: price.created_at,
updated_at: price.updated_at, updated_at: price.updated_at,
})), })),
price_set: undefined,
} }
}
export const refetchProduct = async ( delete (resp as any).price_set
productId: string, // TODO: Remove any once all typings are cleaned up
scope: MedusaContainer, return resp as any
fields: string[]
) => {
const remoteQuery = scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const queryObject = remoteQueryObjectFromString({
entryPoint: "product",
variables: {
filters: { id: productId },
},
fields: remapKeysForProduct(fields ?? []),
})
const products = await remoteQuery(queryObject)
return products[0]
} }
export const refetchVariant = async ( export const refetchVariant = async (
+18 -34
View File
@@ -1,40 +1,25 @@
import { createProductsWorkflow } from "@medusajs/core-flows" import { createProductsWorkflow } from "@medusajs/core-flows"
import { CreateProductDTO } from "@medusajs/types" import { HttpTypes } from "@medusajs/types"
import {
ContainerRegistrationKeys,
remoteQueryObjectFromString,
} from "@medusajs/utils"
import { import {
AuthenticatedMedusaRequest, AuthenticatedMedusaRequest,
MedusaResponse, MedusaResponse,
} from "../../../types/routing" } from "../../../types/routing"
import { import { remapKeysForProduct, remapProductResponse } from "./helpers"
refetchProduct, import { refetchEntities, refetchEntity } from "../../utils/refetch-entity"
remapKeysForProduct,
remapProductResponse,
} from "./helpers"
import {
AdminCreateProductType,
AdminGetProductsParamsType,
} from "./validators"
export const GET = async ( export const GET = async (
req: AuthenticatedMedusaRequest<AdminGetProductsParamsType>, req: AuthenticatedMedusaRequest<HttpTypes.AdminProductParams>,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductListResponse>
) => { ) => {
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
const selectFields = remapKeysForProduct(req.remoteQueryConfig.fields ?? []) const selectFields = remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
const queryObject = remoteQueryObjectFromString({ const { rows: products, metadata } = await refetchEntities(
entryPoint: "product", "product",
variables: { req.filterableFields,
filters: req.filterableFields, req.scope,
...req.remoteQueryConfig.pagination, selectFields,
}, req.remoteQueryConfig.pagination
fields: selectFields, )
})
const { rows: products, metadata } = await remoteQuery(queryObject)
res.json({ res.json({
products: products.map(remapProductResponse), products: products.map(remapProductResponse),
@@ -45,19 +30,18 @@ export const GET = async (
} }
export const POST = async ( export const POST = async (
req: AuthenticatedMedusaRequest<AdminCreateProductType>, req: AuthenticatedMedusaRequest<HttpTypes.AdminCreateProduct>,
res: MedusaResponse res: MedusaResponse<HttpTypes.AdminProductResponse>
) => { ) => {
const input = [req.validatedBody as CreateProductDTO]
const { result } = await createProductsWorkflow(req.scope).run({ const { result } = await createProductsWorkflow(req.scope).run({
input: { products: input }, input: { products: [req.validatedBody] },
}) })
const product = await refetchProduct( const product = await refetchEntity(
"product",
result[0].id, result[0].id,
req.scope, req.scope,
req.remoteQueryConfig.fields remapKeysForProduct(req.remoteQueryConfig.fields ?? [])
) )
res.status(200).json({ product: remapProductResponse(product) }) res.status(200).json({ product: remapProductResponse(product) })
@@ -4,11 +4,11 @@ import {
} from "@medusajs/utils" } from "@medusajs/utils"
import { NextFunction } from "express" import { NextFunction } from "express"
import { MedusaRequest } from "../../../../types/routing" import { MedusaRequest } from "../../../../types/routing"
import { AdminGetProductsParamsType } from "../validators" import { HttpTypes } from "@medusajs/types"
export function maybeApplyPriceListsFilter() { export function maybeApplyPriceListsFilter() {
return async (req: MedusaRequest, _, next: NextFunction) => { return async (req: MedusaRequest, _, next: NextFunction) => {
const filterableFields: AdminGetProductsParamsType = req.filterableFields const filterableFields: HttpTypes.AdminProductParams = req.filterableFields
if (!filterableFields.price_list_id) { if (!filterableFields.price_list_id) {
return next() return next()
@@ -163,13 +163,30 @@ export const AdminCreateProductVariant = z
export type AdminUpdateProductVariantType = z.infer< export type AdminUpdateProductVariantType = z.infer<
typeof AdminUpdateProductVariant typeof AdminUpdateProductVariant
> >
export const AdminUpdateProductVariant = AdminCreateProductVariant.extend({ export const AdminUpdateProductVariant = z
id: z.string().optional(), .object({
title: z.string().optional(), id: z.string().optional(),
prices: z.array(AdminUpdateVariantPrice).optional(), title: z.string().optional(),
allow_backorder: z.boolean().optional(), prices: z.array(AdminUpdateVariantPrice).optional(),
manage_inventory: z.boolean().optional(), sku: z.string().nullable().optional().nullable(),
}).strict() ean: z.string().nullable().optional().nullable(),
upc: z.string().nullable().optional().nullable(),
barcode: z.string().nullable().optional().nullable(),
hs_code: z.string().nullable().optional().nullable(),
mid_code: z.string().nullable().optional().nullable(),
allow_backorder: z.boolean().optional(),
manage_inventory: z.boolean().optional(),
variant_rank: z.number().optional(),
weight: z.number().nullable().optional().nullable(),
length: z.number().nullable().optional().nullable(),
height: z.number().nullable().optional().nullable(),
width: z.number().nullable().optional().nullable(),
origin_country: z.string().nullable().optional().nullable(),
material: z.string().nullable().optional().nullable(),
metadata: z.record(z.unknown()).optional().nullable(),
options: z.record(z.string()).optional(),
})
.strict()
export type AdminBatchUpdateProductVariantType = z.infer< export type AdminBatchUpdateProductVariantType = z.infer<
typeof AdminBatchUpdateProductVariant typeof AdminBatchUpdateProductVariant
@@ -190,46 +207,57 @@ export const AdminCreateProduct = z
description: z.string().nullable().optional(), description: z.string().nullable().optional(),
is_giftcard: z.boolean().optional().default(false), is_giftcard: z.boolean().optional().default(false),
discountable: z.boolean().optional().default(true), discountable: z.boolean().optional().default(true),
images: z images: z.array(z.object({ url: z.string() })).optional(),
.array(z.object({ url: z.string() })) thumbnail: z.string().optional(),
.nullable()
.optional(),
thumbnail: z.string().nullable().optional(),
handle: z.string().optional(), handle: z.string().optional(),
status: statusEnum.optional().default(ProductStatus.DRAFT), status: statusEnum.optional().default(ProductStatus.DRAFT),
type_id: z.string().nullable().optional(), type_id: z.string().optional(),
collection_id: z.string().nullable().optional(), collection_id: z.string().optional(),
categories: z categories: z.array(AdminCreateProductProductCategory).optional(),
.array(AdminCreateProductProductCategory) tags: z.array(AdminUpdateProductTag).optional(),
.nullable()
.optional(),
tags: z.array(AdminUpdateProductTag).nullable().optional(),
options: z.array(AdminCreateProductOption).optional(), options: z.array(AdminCreateProductOption).optional(),
variants: z.array(AdminCreateProductVariant).optional(), variants: z.array(AdminCreateProductVariant).optional(),
sales_channels: z sales_channels: z.array(z.object({ id: z.string() })).optional(),
.array(z.object({ id: z.string() })) weight: z.number().optional(),
.nullable() length: z.number().optional(),
.optional(), height: z.number().optional(),
weight: z.number().nullable().optional(), width: z.number().optional(),
length: z.number().nullable().optional(), hs_code: z.string().optional(),
height: z.number().nullable().optional(), mid_code: z.string().optional(),
width: z.number().nullable().optional(), origin_country: z.string().optional(),
hs_code: z.string().nullable().optional(), material: z.string().optional(),
mid_code: z.string().nullable().optional(),
origin_country: z.string().nullable().optional(),
material: z.string().nullable().optional(),
metadata: z.record(z.unknown()).optional(), metadata: z.record(z.unknown()).optional(),
}) })
.strict() .strict()
export type AdminUpdateProductType = z.infer<typeof AdminUpdateProduct> export type AdminUpdateProductType = z.infer<typeof AdminUpdateProduct>
export const AdminUpdateProduct = AdminCreateProduct.omit({ is_giftcard: true }) export const AdminUpdateProduct = z
.extend({ .object({
title: z.string().optional(), title: z.string().optional(),
discountable: z.boolean().optional(), discountable: z.boolean().optional(),
is_giftcard: z.boolean().optional(),
options: z.array(AdminUpdateProductOption).optional(), options: z.array(AdminUpdateProductOption).optional(),
variants: z.array(AdminUpdateProductVariant).optional(), variants: z.array(AdminUpdateProductVariant).optional(),
status: statusEnum.optional(), status: statusEnum.optional(),
subtitle: z.string().optional().nullable(),
description: z.string().optional().nullable(),
images: z.array(z.object({ url: z.string() })).optional(),
thumbnail: z.string().optional().nullable(),
handle: z.string().optional(),
type_id: z.string().optional().nullable(),
collection_id: z.string().optional().nullable(),
categories: z.array(AdminCreateProductProductCategory).optional(),
tags: z.array(AdminUpdateProductTag).nullable().optional(),
sales_channels: z.array(z.object({ id: z.string() })).optional(),
weight: z.number().optional().nullable(),
length: z.number().optional().nullable(),
height: z.number().optional().nullable(),
width: z.number().optional().nullable(),
hs_code: z.string().optional().nullable(),
mid_code: z.string().optional().nullable(),
origin_country: z.string().optional().nullable(),
material: z.string().optional().nullable(),
metadata: z.record(z.unknown()).optional().nullable(),
}) })
.strict() .strict()