diff --git a/packages/admin-next/admin-shared/src/extensions/widgets/constants.ts b/packages/admin-next/admin-shared/src/extensions/widgets/constants.ts index 9e15309b29557..af7dea855b48f 100644 --- a/packages/admin-next/admin-shared/src/extensions/widgets/constants.ts +++ b/packages/admin-next/admin-shared/src/extensions/widgets/constants.ts @@ -55,6 +55,13 @@ const PRODUCT_CATEGORY_INJECTION_ZONES = [ "product_category.list.after", ] as const +const PRODUCT_TYPE_INJECTION_ZONES = [ + "product_type.details.before", + "product_type.details.after", + "product_type.list.before", + "product_type.list.after", +] as const + const PRICE_LIST_INJECTION_ZONES = [ "price_list.details.before", "price_list.details.after", @@ -198,4 +205,5 @@ export const INJECTION_ZONES = [ ...WORKFLOW_INJECTION_ZONES, ...CAMPAIGN_INJECTION_ZONES, ...TAX_INJECTION_ZONES, + ...PRODUCT_TYPE_INJECTION_ZONES, ] as const diff --git a/packages/admin-next/dashboard/src/components/layout/settings-layout/settings-layout.tsx b/packages/admin-next/dashboard/src/components/layout/settings-layout/settings-layout.tsx index ed8b5df791afd..b56e9007fff8b 100644 --- a/packages/admin-next/dashboard/src/components/layout/settings-layout/settings-layout.tsx +++ b/packages/admin-next/dashboard/src/components/layout/settings-layout/settings-layout.tsx @@ -49,6 +49,10 @@ const useSettingRoutes = (): NavItemProps[] => { label: t("salesChannels.domain"), to: "/settings/sales-channels", }, + { + label: t("productTypes.domain"), + to: "/settings/product-types", + }, { label: t("shippingProfile.domain"), to: "/settings/shipping-profiles", diff --git a/packages/admin-next/dashboard/src/hooks/api/product-types.tsx b/packages/admin-next/dashboard/src/hooks/api/product-types.tsx index 7e6931350347c..fcc4c5adb0939 100644 --- a/packages/admin-next/dashboard/src/hooks/api/product-types.tsx +++ b/packages/admin-next/dashboard/src/hooks/api/product-types.tsx @@ -1,26 +1,34 @@ -import { QueryKey, UseQueryOptions, useQuery } from "@tanstack/react-query" -import { client } from "../../lib/client" -import { queryKeysFactory } from "../../lib/query-key-factory" +import { FetchError } from "@medusajs/js-sdk" import { HttpTypes } from "@medusajs/types" +import { + QueryKey, + UseMutationOptions, + UseQueryOptions, + useMutation, + useQuery, +} from "@tanstack/react-query" +import { sdk } from "../../lib/client" +import { queryClient } from "../../lib/query-client" +import { queryKeysFactory } from "../../lib/query-key-factory" const PRODUCT_TYPES_QUERY_KEY = "product_types" as const -const productTypesQueryKeys = queryKeysFactory(PRODUCT_TYPES_QUERY_KEY) +export const productTypesQueryKeys = queryKeysFactory(PRODUCT_TYPES_QUERY_KEY) export const useProductType = ( id: string, - query?: Record, + query?: HttpTypes.AdminProductTypeParams, options?: Omit< UseQueryOptions< - { product_type: HttpTypes.AdminProductType }, - Error, - { product_type: HttpTypes.AdminProductType }, + HttpTypes.AdminProductTypeResponse, + FetchError, + HttpTypes.AdminProductTypeResponse, QueryKey >, "queryKey" | "queryFn" > ) => { const { data, ...rest } = useQuery({ - queryFn: () => client.productTypes.retrieve(id, query), + queryFn: () => sdk.admin.productType.retrieve(id, query), queryKey: productTypesQueryKeys.detail(id), ...options, }) @@ -29,22 +37,84 @@ export const useProductType = ( } export const useProductTypes = ( - query?: Record, + query?: HttpTypes.AdminProductTypeListParams, options?: Omit< UseQueryOptions< - { product_types: HttpTypes.AdminProductType[] }, - Error, - { product_types: HttpTypes.AdminProductType[] }, + HttpTypes.AdminProductTypeListResponse, + FetchError, + HttpTypes.AdminProductTypeListResponse, QueryKey >, "queryKey" | "queryFn" > ) => { const { data, ...rest } = useQuery({ - queryFn: () => client.productTypes.list(query), + queryFn: () => sdk.admin.productType.list(query), queryKey: productTypesQueryKeys.list(query), ...options, }) return { ...data, ...rest } } + +export const useCreateProductType = ( + options?: UseMutationOptions< + HttpTypes.AdminProductTypeResponse, + FetchError, + HttpTypes.AdminCreateProductType + > +) => { + return useMutation({ + mutationFn: (payload) => sdk.admin.productType.create(payload), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ queryKey: productTypesQueryKeys.lists() }) + + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} + +export const useUpdateProductType = ( + id: string, + options?: UseMutationOptions< + HttpTypes.AdminProductTypeResponse, + FetchError, + HttpTypes.AdminUpdateProductType + > +) => { + return useMutation({ + mutationFn: (payload) => sdk.admin.productType.update(id, payload), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ + queryKey: productTypesQueryKeys.detail(id), + }) + queryClient.invalidateQueries({ queryKey: productTypesQueryKeys.lists() }) + + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} + +export const useDeleteProductType = ( + id: string, + options?: UseMutationOptions< + HttpTypes.AdminProductTypeDeleteResponse, + FetchError, + void + > +) => { + return useMutation({ + mutationFn: () => sdk.admin.productType.delete(id), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ + queryKey: productTypesQueryKeys.detail(id), + }) + queryClient.invalidateQueries({ queryKey: productTypesQueryKeys.lists() }) + + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} diff --git a/packages/admin-next/dashboard/src/hooks/api/products.tsx b/packages/admin-next/dashboard/src/hooks/api/products.tsx index eb1bdd85c3911..9b4f13a2de8d8 100644 --- a/packages/admin-next/dashboard/src/hooks/api/products.tsx +++ b/packages/admin-next/dashboard/src/hooks/api/products.tsx @@ -1,3 +1,4 @@ +import { FetchError } from "@medusajs/js-sdk" import { HttpTypes } from "@medusajs/types" import { QueryKey, @@ -223,11 +224,11 @@ export const useProduct = ( } export const useProducts = ( - query?: Record, + query?: HttpTypes.AdminProductListParams, options?: Omit< UseQueryOptions< HttpTypes.AdminProductListResponse, - Error, + FetchError, HttpTypes.AdminProductListResponse, QueryKey >, diff --git a/packages/admin-next/dashboard/src/hooks/table/filters/use-date-table-filters.tsx b/packages/admin-next/dashboard/src/hooks/table/filters/use-date-table-filters.tsx new file mode 100644 index 0000000000000..4626d3b3ee991 --- /dev/null +++ b/packages/admin-next/dashboard/src/hooks/table/filters/use-date-table-filters.tsx @@ -0,0 +1,17 @@ +import { useTranslation } from "react-i18next" +import { Filter } from "../../../components/table/data-table" + +export const useDateTableFilters = () => { + const { t } = useTranslation() + + const dateFilters: Filter[] = [ + { label: t("fields.createdAt"), key: "created_at" }, + { label: t("fields.updatedAt"), key: "updated_at" }, + ].map((f) => ({ + key: f.key, + label: f.label, + type: "date", + })) + + return dateFilters +} diff --git a/packages/admin-next/dashboard/src/hooks/table/filters/use-product-table-filters.tsx b/packages/admin-next/dashboard/src/hooks/table/filters/use-product-table-filters.tsx index 251f367cd0d9b..2ec28a3fb98a8 100644 --- a/packages/admin-next/dashboard/src/hooks/table/filters/use-product-table-filters.tsx +++ b/packages/admin-next/dashboard/src/hooks/table/filters/use-product-table-filters.tsx @@ -7,6 +7,7 @@ const excludeableFields = [ "sales_channel_id", "collections", "categories", + "product_types", ] as const export const useProductTableFilters = ( @@ -14,10 +15,17 @@ export const useProductTableFilters = ( ) => { const { t } = useTranslation() - const { product_types } = useProductTypes({ - limit: 1000, - offset: 0, - }) + const isProductTypeExcluded = exclude?.includes("product_types") + + const { product_types } = useProductTypes( + { + limit: 1000, + offset: 0, + }, + { + enabled: !isProductTypeExcluded, + } + ) // const { product_tags } = useAdminProductTags({ // limit: 1000, @@ -61,7 +69,7 @@ export const useProductTableFilters = ( let filters: Filter[] = [] - if (product_types) { + if (product_types && !isProductTypeExcluded) { const typeFilter: Filter = { key: "type_id", label: t("fields.type"), diff --git a/packages/admin-next/dashboard/src/hooks/table/query/use-product-table-query.tsx b/packages/admin-next/dashboard/src/hooks/table/query/use-product-table-query.tsx index 419f43798e470..1cb7fb1790d30 100644 --- a/packages/admin-next/dashboard/src/hooks/table/query/use-product-table-query.tsx +++ b/packages/admin-next/dashboard/src/hooks/table/query/use-product-table-query.tsx @@ -44,7 +44,7 @@ export const useProductTableQuery = ({ q, } = queryObject - const searchParams: HttpTypes.AdminProductParams = { + const searchParams: HttpTypes.AdminProductListParams = { limit: pageSize, offset: offset ? Number(offset) : 0, sales_channel_id: sales_channel_id?.split(","), diff --git a/packages/admin-next/dashboard/src/i18n/translations/en.json b/packages/admin-next/dashboard/src/i18n/translations/en.json index 79f41669c209c..a7839c1501868 100644 --- a/packages/admin-next/dashboard/src/i18n/translations/en.json +++ b/packages/admin-next/dashboard/src/i18n/translations/en.json @@ -1647,6 +1647,25 @@ } } }, + "productTypes": { + "domain": "Product Types", + "create": { + "header": "Create Product Type", + "hint": "Create a new product type to categorize your products.", + "successToast": "Product type {{value}} was successfully created." + }, + "edit": { + "header": "Edit Product Type", + "successToast": "Product type {{value}} was successfully updated." + }, + "delete": { + "confirmation": "You are about to delete the product type {{value}}. This action cannot be undone.", + "successToast": "Product type {{value}} was successfully deleted." + }, + "fields": { + "value": "Value" + } + }, "errors": { "serverError": "Server error - Try again later.", "invalidCredentials": "Wrong email or password" @@ -1758,8 +1777,8 @@ "sent": "Sent", "salesChannels": "Sales Channels", "product": "Product", - "createdAt": "Created at", - "updatedAt": "Updated at", + "createdAt": "Created", + "updatedAt": "Updated", "revokedAt": "Revoked at", "true": "True", "false": "False", diff --git a/packages/admin-next/dashboard/src/providers/router-provider/route-map.tsx b/packages/admin-next/dashboard/src/providers/router-provider/route-map.tsx index a3635fbfc1bc8..fba26e54ff30e 100644 --- a/packages/admin-next/dashboard/src/providers/router-provider/route-map.tsx +++ b/packages/admin-next/dashboard/src/providers/router-provider/route-map.tsx @@ -848,6 +848,43 @@ export const RouteMap: RouteObject[] = [ }, ], }, + { + path: "product-types", + element: , + handle: { + crumb: () => "Product Types", + }, + children: [ + { + path: "", + lazy: () => + import("../../routes/product-types/product-type-list"), + children: [ + { + path: "create", + lazy: () => + import("../../routes/product-types/product-type-create"), + }, + ], + }, + { + path: ":id", + lazy: () => + import("../../routes/product-types/product-type-detail"), + handle: { + crumb: (data: HttpTypes.AdminProductTypeResponse) => + data.product_type.value, + }, + children: [ + { + path: "edit", + lazy: () => + import("../../routes/product-types/product-type-edit"), + }, + ], + }, + ], + }, { path: "shipping-profiles", element: , diff --git a/packages/admin-next/dashboard/src/routes/product-types/common/hooks/use-delete-product-type-action.tsx b/packages/admin-next/dashboard/src/routes/product-types/common/hooks/use-delete-product-type-action.tsx new file mode 100644 index 0000000000000..4eb9cb269029e --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/common/hooks/use-delete-product-type-action.tsx @@ -0,0 +1,42 @@ +import { toast, usePrompt } from "@medusajs/ui" +import { useTranslation } from "react-i18next" +import { useDeleteProductType } from "../../../../hooks/api/product-types" + +export const useDeleteProductTypeAction = (id: string) => { + const { t } = useTranslation() + const prompt = usePrompt() + + const { mutateAsync } = useDeleteProductType(id) + + const handleDelete = async () => { + const result = await prompt({ + title: t("general.areYouSure"), + description: t("productTypes.delete.confirmation"), + confirmText: t("actions.delete"), + cancelText: t("actions.cancel"), + }) + + if (!result) { + return + } + + await mutateAsync(undefined, { + onSuccess: () => { + toast.success(t("general.success"), { + description: t("productTypes.delete.successToast"), + dismissLabel: t("actions.close"), + dismissable: true, + }) + }, + onError: (e) => { + toast.error(t("general.error"), { + description: e.message, + dismissLabel: t("actions.close"), + dismissable: true, + }) + }, + }) + } + + return handleDelete +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-create/components/create-product-type-form/create-product-type-form.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-create/components/create-product-type-form/create-product-type-form.tsx new file mode 100644 index 0000000000000..ad1cd9f5eb743 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-create/components/create-product-type-form/create-product-type-form.tsx @@ -0,0 +1,105 @@ +import { zodResolver } from "@hookform/resolvers/zod" +import { Button, Heading, Input, Text, toast } from "@medusajs/ui" +import { useForm } from "react-hook-form" +import { useTranslation } from "react-i18next" +import { z } from "zod" +import { Form } from "../../../../../components/common/form" +import { + RouteFocusModal, + useRouteModal, +} from "../../../../../components/route-modal" +import { useCreateProductType } from "../../../../../hooks/api/product-types" + +const CreateProductTypeSchema = z.object({ + value: z.string().min(1), +}) + +export const CreateProductTypeForm = () => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + + const form = useForm>({ + defaultValues: { + value: "", + }, + resolver: zodResolver(CreateProductTypeSchema), + }) + + const { mutateAsync, isPending } = useCreateProductType() + + const handleSubmit = form.handleSubmit( + async (values: z.infer) => { + await mutateAsync(values, { + onSuccess: ({ product_type }) => { + toast.success(t("general.success"), { + description: t("productTypes.create.successToast", { + value: product_type.value, + }), + dismissLabel: t("actions.close"), + dismissable: true, + }) + + handleSuccess(`/settings/product-types/${product_type.id}`) + }, + onError: (e) => { + toast.error(t("general.error"), { + description: e.message, + dismissLabel: t("actions.close"), + dismissable: true, + }) + }, + }) + } + ) + + return ( + +
+ +
+ + + + +
+
+ +
+
+ {t("productTypes.create.header")} + + {t("productTypes.create.hint")} + +
+
+ { + return ( + + {t("productTypes.fields.value")} + + + + + + ) + }} + /> +
+
+
+
+
+ ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-create/components/create-product-type-form/index.ts b/packages/admin-next/dashboard/src/routes/product-types/product-type-create/components/create-product-type-form/index.ts new file mode 100644 index 0000000000000..86be7be2e236c --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-create/components/create-product-type-form/index.ts @@ -0,0 +1 @@ +export * from "./create-product-type-form" diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-create/index.ts b/packages/admin-next/dashboard/src/routes/product-types/product-type-create/index.ts new file mode 100644 index 0000000000000..128ac6d700a54 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-create/index.ts @@ -0,0 +1 @@ +export { ProductTypeCreate as Component } from "./product-type-create" diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-create/product-type-create.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-create/product-type-create.tsx new file mode 100644 index 0000000000000..9712dbf769698 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-create/product-type-create.tsx @@ -0,0 +1,10 @@ +import { RouteFocusModal } from "../../../components/route-modal" +import { CreateProductTypeForm } from "./components/create-product-type-form" + +export const ProductTypeCreate = () => { + return ( + + + + ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-general-section/index.ts b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-general-section/index.ts new file mode 100644 index 0000000000000..8b1b4be731133 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-general-section/index.ts @@ -0,0 +1 @@ +export * from "./product-type-general-section" diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-general-section/product-type-general-section.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-general-section/product-type-general-section.tsx new file mode 100644 index 0000000000000..c0c78d70d69ce --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-general-section/product-type-general-section.tsx @@ -0,0 +1,45 @@ +import { PencilSquare, Trash } from "@medusajs/icons" +import { HttpTypes } from "@medusajs/types" +import { Container, Heading } from "@medusajs/ui" +import { useTranslation } from "react-i18next" +import { ActionMenu } from "../../../../../components/common/action-menu" +import { useDeleteProductTypeAction } from "../../../common/hooks/use-delete-product-type-action" + +type ProductTypeGeneralSectionProps = { + productType: HttpTypes.AdminProductType +} + +export const ProductTypeGeneralSection = ({ + productType, +}: ProductTypeGeneralSectionProps) => { + const { t } = useTranslation() + const handleDelete = useDeleteProductTypeAction(productType.id) + + return ( + + {productType.value} + , + to: "edit", + }, + ], + }, + { + actions: [ + { + label: t("actions.delete"), + icon: , + onClick: handleDelete, + }, + ], + }, + ]} + /> + + ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-product-section/index.ts b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-product-section/index.ts new file mode 100644 index 0000000000000..5322e3d14b5c8 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-product-section/index.ts @@ -0,0 +1 @@ +export * from "./product-type-product-section" diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-product-section/product-type-product-section.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-product-section/product-type-product-section.tsx new file mode 100644 index 0000000000000..6a41ef2cd3e72 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/components/product-type-product-section/product-type-product-section.tsx @@ -0,0 +1,66 @@ +import { HttpTypes } from "@medusajs/types" +import { Container, Heading } from "@medusajs/ui" +import { useTranslation } from "react-i18next" + +import { DataTable } from "../../../../../components/table/data-table" +import { useProducts } from "../../../../../hooks/api/products" +import { useProductTableColumns } from "../../../../../hooks/table/columns/use-product-table-columns" +import { useProductTableFilters } from "../../../../../hooks/table/filters/use-product-table-filters" +import { useProductTableQuery } from "../../../../../hooks/table/query/use-product-table-query" +import { useDataTable } from "../../../../../hooks/use-data-table" + +type ProductTypeProductSectionProps = { + productType: HttpTypes.AdminProductType +} + +const PAGE_SIZE = 10 + +export const ProductTypeProductSection = ({ + productType, +}: ProductTypeProductSectionProps) => { + const { t } = useTranslation() + + const { searchParams, raw } = useProductTableQuery({ + pageSize: PAGE_SIZE, + }) + const { products, count, isPending, isError, error } = useProducts({ + ...searchParams, + type_id: [productType.id], + }) + + const filters = useProductTableFilters(["product_types"]) + const columns = useProductTableColumns() + + const { table } = useDataTable({ + columns, + data: products, + count: products?.length || 0, + getRowId: (row) => row.id, + pageSize: PAGE_SIZE, + }) + + if (isError) { + throw error + } + + return ( + +
+ {t("products.domain")} +
+ `/products/${original.id}`} + orderBy={["title", "created_at", "updated_at"]} + queryObject={raw} + search + pagination + /> +
+ ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/index.ts b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/index.ts new file mode 100644 index 0000000000000..098bfbc1edcb1 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/index.ts @@ -0,0 +1,2 @@ +export { productTypeLoader as loader } from "./loader" +export { ProductTypeDetail as Component } from "./product-type-detail" diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/loader.ts b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/loader.ts new file mode 100644 index 0000000000000..15f5142903e07 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/loader.ts @@ -0,0 +1,22 @@ +import { LoaderFunctionArgs } from "react-router-dom" + +import { HttpTypes } from "@medusajs/types" +import { productTypesQueryKeys } from "../../../hooks/api/product-types" +import { sdk } from "../../../lib/client" +import { queryClient } from "../../../lib/query-client" + +const productTypeDetailQuery = (id: string) => ({ + queryKey: productTypesQueryKeys.detail(id), + queryFn: async () => sdk.admin.productType.retrieve(id), +}) + +export const productTypeLoader = async ({ params }: LoaderFunctionArgs) => { + const id = params.id + const query = productTypeDetailQuery(id!) + + return ( + queryClient.getQueryData( + query.queryKey + ) ?? (await queryClient.fetchQuery(query)) + ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/product-type-detail.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/product-type-detail.tsx new file mode 100644 index 0000000000000..4ee09a5cd39be --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-detail/product-type-detail.tsx @@ -0,0 +1,56 @@ +import { Outlet, useLoaderData, useParams } from "react-router-dom" + +import { JsonViewSection } from "../../../components/common/json-view-section" +import { useProductType } from "../../../hooks/api/product-types" +import { ProductTypeGeneralSection } from "./components/product-type-general-section" +import { ProductTypeProductSection } from "./components/product-type-product-section" +import { productTypeLoader } from "./loader" + +import after from "virtual:medusa/widgets/product_type/details/after" +import before from "virtual:medusa/widgets/product_type/details/before" + +export const ProductTypeDetail = () => { + const { id } = useParams() + const initialData = useLoaderData() as Awaited< + ReturnType + > + + const { product_type, isPending, isError, error } = useProductType( + id!, + undefined, + { + initialData, + } + ) + + if (isPending || !product_type) { + return null + } + + if (isError) { + throw error + } + + return ( +
+ {before.widgets.map((w, i) => { + return ( +
+ +
+ ) + })} + + + {after.widgets.map((w, i) => { + return ( +
+ +
+ ) + })} + + +
+ ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/components/edit-product-type-form/edit-product-type-form.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/components/edit-product-type-form/edit-product-type-form.tsx new file mode 100644 index 0000000000000..68989adf31e2d --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/components/edit-product-type-form/edit-product-type-form.tsx @@ -0,0 +1,102 @@ +import { zodResolver } from "@hookform/resolvers/zod" +import { HttpTypes } from "@medusajs/types" +import { Button, Input, toast } from "@medusajs/ui" +import { useForm } from "react-hook-form" +import { useTranslation } from "react-i18next" +import { z } from "zod" +import { Form } from "../../../../../components/common/form" +import { + RouteDrawer, + useRouteModal, +} from "../../../../../components/route-modal" +import { useUpdateProductType } from "../../../../../hooks/api/product-types" + +const EditProductTypeSchema = z.object({ + value: z.string().min(1), +}) + +type EditProductTypeFormProps = { + productType: HttpTypes.AdminProductType +} + +export const EditProductTypeForm = ({ + productType, +}: EditProductTypeFormProps) => { + const { t } = useTranslation() + const { handleSuccess } = useRouteModal() + + const form = useForm>({ + defaultValues: { + value: productType.value, + }, + resolver: zodResolver(EditProductTypeSchema), + }) + + const { mutateAsync, isPending } = useUpdateProductType(productType.id) + + const handleSubmit = form.handleSubmit(async (data) => { + await mutateAsync( + { + value: data.value, + }, + { + onSuccess: ({ product_type }) => { + toast.success(t("general.success"), { + description: t("productTypes.edit.successToast", { + value: product_type.value, + }), + dismissable: true, + dismissLabel: t("general.close"), + }) + handleSuccess() + }, + onError: (error) => { + toast.error(t("general.error"), { + description: error.message, + dismissable: true, + dismissLabel: t("general.close"), + }) + }, + } + ) + }) + + return ( + +
+ + { + return ( + + {t("productTypes.fields.value")} + + + + + + ) + }} + /> + + +
+ + + + +
+
+
+
+ ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/components/edit-product-type-form/index.ts b/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/components/edit-product-type-form/index.ts new file mode 100644 index 0000000000000..47309ea3225b2 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/components/edit-product-type-form/index.ts @@ -0,0 +1 @@ +export * from "./edit-product-type-form" diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/index.ts b/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/index.ts new file mode 100644 index 0000000000000..3baf2b90623c6 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/index.ts @@ -0,0 +1 @@ +export { ProductTypeEdit as Component } from "./product-type-edit" diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/product-type-edit.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/product-type-edit.tsx new file mode 100644 index 0000000000000..b7ac94eb8fd24 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-edit/product-type-edit.tsx @@ -0,0 +1,28 @@ +import { Heading } from "@medusajs/ui" +import { useTranslation } from "react-i18next" +import { useParams } from "react-router-dom" +import { RouteDrawer } from "../../../components/route-modal" +import { useProductType } from "../../../hooks/api/product-types" +import { EditProductTypeForm } from "./components/edit-product-type-form" + +export const ProductTypeEdit = () => { + const { id } = useParams() + const { t } = useTranslation() + + const { product_type, isPending, isError, error } = useProductType(id!) + + const ready = !isPending && !!product_type + + if (isError) { + throw error + } + + return ( + + + {t("productTypes.edit.header")} + + {ready && } + + ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/index.ts b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/index.ts new file mode 100644 index 0000000000000..c788606b51785 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/index.ts @@ -0,0 +1 @@ +export * from "./product-type-list-table" diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/product-table-row-actions.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/product-table-row-actions.tsx new file mode 100644 index 0000000000000..7b0699c92c5de --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/product-table-row-actions.tsx @@ -0,0 +1,41 @@ +import { PencilSquare, Trash } from "@medusajs/icons" +import { HttpTypes } from "@medusajs/types" +import { useTranslation } from "react-i18next" +import { ActionMenu } from "../../../../../components/common/action-menu" +import { useDeleteProductTypeAction } from "../../../common/hooks/use-delete-product-type-action" + +type ProductTypeRowActionsProps = { + productType: HttpTypes.AdminProductType +} + +export const ProductTypeRowActions = ({ + productType, +}: ProductTypeRowActionsProps) => { + const { t } = useTranslation() + const handleDelete = useDeleteProductTypeAction(productType.id) + + return ( + , + to: `/settings/product-types/${productType.id}/edit`, + }, + ], + }, + { + actions: [ + { + label: t("actions.delete"), + icon: , + onClick: handleDelete, + }, + ], + }, + ]} + /> + ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/product-type-list-table.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/product-type-list-table.tsx new file mode 100644 index 0000000000000..1389e7ec782a6 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/product-type-list-table.tsx @@ -0,0 +1,65 @@ +import { Button, Container, Heading } from "@medusajs/ui" +import { keepPreviousData } from "@tanstack/react-query" +import { useTranslation } from "react-i18next" +import { Link } from "react-router-dom" +import { DataTable } from "../../../../../components/table/data-table" +import { useProductTypes } from "../../../../../hooks/api/product-types" +import { useDataTable } from "../../../../../hooks/use-data-table" +import { useProductTypeTableColumns } from "./use-product-type-table-columns" +import { useProductTypeTableFilters } from "./use-product-type-table-filters" +import { useProductTypeTableQuery } from "./use-product-type-table-query" + +const PAGE_SIZE = 20 + +export const ProductTypeListTable = () => { + const { t } = useTranslation() + + const { searchParams, raw } = useProductTypeTableQuery({ + pageSize: PAGE_SIZE, + }) + const { product_types, count, isLoading, isError, error } = useProductTypes( + searchParams, + { + placeholderData: keepPreviousData, + } + ) + + const filters = useProductTypeTableFilters() + const columns = useProductTypeTableColumns() + + const { table } = useDataTable({ + columns, + data: product_types, + count, + getRowId: (row) => row.id, + pageSize: PAGE_SIZE, + }) + + if (isError) { + throw error + } + + return ( + +
+ {t("productTypes.domain")} + +
+ original.id} + queryObject={raw} + pagination + search + /> +
+ ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/use-product-type-table-columns.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/use-product-type-table-columns.tsx new file mode 100644 index 0000000000000..74082fded5e1f --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/use-product-type-table-columns.tsx @@ -0,0 +1,35 @@ +import { HttpTypes } from "@medusajs/types" +import { createColumnHelper } from "@tanstack/react-table" +import { useMemo } from "react" +import { useTranslation } from "react-i18next" +import { ProductTypeRowActions } from "./product-table-row-actions" + +const columnHelper = createColumnHelper() + +export const useProductTypeTableColumns = () => { + const { t } = useTranslation() + + return useMemo( + () => [ + columnHelper.accessor("value", { + header: () => t("productTypes.fields.value"), + cell: ({ getValue }) => getValue(), + }), + columnHelper.accessor("created_at", { + header: () => t("fields.createdAt"), + cell: ({ getValue }) => getValue(), + }), + columnHelper.accessor("updated_at", { + header: () => t("fields.updatedAt"), + cell: ({ getValue }) => getValue(), + }), + columnHelper.display({ + id: "actions", + cell: ({ row }) => { + return + }, + }), + ], + [t] + ) +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/use-product-type-table-filters.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/use-product-type-table-filters.tsx new file mode 100644 index 0000000000000..25b7118cdc6a9 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/use-product-type-table-filters.tsx @@ -0,0 +1,7 @@ +import { useDateTableFilters } from "../../../../../hooks/table/filters/use-date-table-filters" + +export const useProductTypeTableFilters = () => { + const dateFilters = useDateTableFilters() + + return dateFilters +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/use-product-type-table-query.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/use-product-type-table-query.tsx new file mode 100644 index 0000000000000..1957f57a56f7d --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/components/product-type-list-table/use-product-type-table-query.tsx @@ -0,0 +1,31 @@ +import { useQueryParams } from "../../../../../hooks/use-query-params" + +type UseProductTypeTableQueryProps = { + prefix?: string + pageSize?: number +} + +export const useProductTypeTableQuery = ({ + prefix, + pageSize = 20, +}: UseProductTypeTableQueryProps) => { + const queryObject = useQueryParams( + ["offset", "q", "order", "created_at", "updated_at"], + prefix + ) + + const { offset, q, order, created_at, updated_at } = queryObject + const searchParams = { + limit: pageSize, + offset: offset ? Number(offset) : 0, + order, + created_at: created_at ? JSON.parse(created_at) : undefined, + updated_at: updated_at ? JSON.parse(updated_at) : undefined, + q, + } + + return { + searchParams, + raw: queryObject, + } +} diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-list/index.ts b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/index.ts new file mode 100644 index 0000000000000..bf19b7ae9b14e --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/index.ts @@ -0,0 +1 @@ +export { ProductTypeList as Component } from "./product-type-list" diff --git a/packages/admin-next/dashboard/src/routes/product-types/product-type-list/product-type-list.tsx b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/product-type-list.tsx new file mode 100644 index 0000000000000..4399d5d8151e1 --- /dev/null +++ b/packages/admin-next/dashboard/src/routes/product-types/product-type-list/product-type-list.tsx @@ -0,0 +1,28 @@ +import { Outlet } from "react-router-dom" +import { ProductTypeListTable } from "./components/product-type-list-table" + +import after from "virtual:medusa/widgets/product_type/list/after" +import before from "virtual:medusa/widgets/product_type/list/before" + +export const ProductTypeList = () => { + return ( +
+ {before.widgets.map((w, i) => { + return ( +
+ +
+ ) + })} + + {after.widgets.map((w, i) => { + return ( +
+ +
+ ) + })} + +
+ ) +} diff --git a/packages/core/js-sdk/src/admin/index.ts b/packages/core/js-sdk/src/admin/index.ts index f79be661d6cc3..ea00a5d4a99f9 100644 --- a/packages/core/js-sdk/src/admin/index.ts +++ b/packages/core/js-sdk/src/admin/index.ts @@ -10,6 +10,7 @@ import { PriceList } from "./price-list" import { Product } from "./product" import { ProductCategory } from "./product-category" import { ProductCollection } from "./product-collection" +import { ProductType } from "./product-type" import { Region } from "./region" import { SalesChannel } from "./sales-channel" import { ShippingOption } from "./shipping-option" @@ -26,6 +27,7 @@ export class Admin { public productCategory: ProductCategory public priceList: PriceList public product: Product + public productType: ProductType public upload: Upload public region: Region public stockLocation: StockLocation @@ -47,6 +49,7 @@ export class Admin { this.productCategory = new ProductCategory(client) this.priceList = new PriceList(client) this.product = new Product(client) + this.productType = new ProductType(client) this.upload = new Upload(client) this.region = new Region(client) this.stockLocation = new StockLocation(client) diff --git a/packages/core/js-sdk/src/admin/product-type.ts b/packages/core/js-sdk/src/admin/product-type.ts new file mode 100644 index 0000000000000..1f7d4406782cb --- /dev/null +++ b/packages/core/js-sdk/src/admin/product-type.ts @@ -0,0 +1,80 @@ +import { HttpTypes } from "@medusajs/types" +import { Client } from "../client" +import { ClientHeaders } from "../types" + +export class ProductType { + private client: Client + constructor(client: Client) { + this.client = client + } + + async create( + body: HttpTypes.AdminCreateProductType, + query?: HttpTypes.SelectParams, + headers?: ClientHeaders + ) { + return this.client.fetch( + `/admin/product-types`, + { + method: "POST", + headers, + body, + query, + } + ) + } + + async update( + id: string, + body: HttpTypes.AdminUpdateProductType, + query?: HttpTypes.SelectParams, + headers?: ClientHeaders + ) { + return this.client.fetch( + `/admin/product-types/${id}`, + { + method: "POST", + headers, + body, + query, + } + ) + } + + async list( + query?: HttpTypes.AdminProductTypeListParams, + headers?: ClientHeaders + ) { + return this.client.fetch( + `/admin/product-types`, + { + headers, + query: query, + } + ) + } + + async retrieve( + id: string, + query?: HttpTypes.AdminProductTypeParams, + headers?: ClientHeaders + ) { + return this.client.fetch( + `/admin/product-types/${id}`, + { + query, + headers, + } + ) + } + + async delete(id: string, headers?: ClientHeaders) { + return this.client.fetch( + `/admin/product-types/${id}`, + { + method: "DELETE", + headers, + } + ) + } +} diff --git a/packages/core/js-sdk/src/admin/product.ts b/packages/core/js-sdk/src/admin/product.ts index 4ea2b98d27952..ec851254780e9 100644 --- a/packages/core/js-sdk/src/admin/product.ts +++ b/packages/core/js-sdk/src/admin/product.ts @@ -55,7 +55,7 @@ export class Product { ) } async list( - queryParams?: HttpTypes.AdminProductParams, + queryParams?: HttpTypes.AdminProductListParams, headers?: ClientHeaders ) { return await this.client.fetch( diff --git a/packages/core/types/src/http/index.ts b/packages/core/types/src/http/index.ts index 8885dd4736165..ccc184a688c3e 100644 --- a/packages/core/types/src/http/index.ts +++ b/packages/core/types/src/http/index.ts @@ -16,6 +16,7 @@ export * from "./payment" export * from "./pricing" export * from "./product" export * from "./product-category" +export * from "./product-type" export * from "./promotion" export * from "./region" export * from "./reservation" diff --git a/packages/core/types/src/http/product-type/admin/entities.ts b/packages/core/types/src/http/product-type/admin/entities.ts new file mode 100644 index 0000000000000..666f6477deb17 --- /dev/null +++ b/packages/core/types/src/http/product-type/admin/entities.ts @@ -0,0 +1,3 @@ +import { BaseProductType } from "../common" + +export interface AdminProductType extends BaseProductType {} diff --git a/packages/core/types/src/http/product-type/admin/index.ts b/packages/core/types/src/http/product-type/admin/index.ts new file mode 100644 index 0000000000000..1f82a2ead53e3 --- /dev/null +++ b/packages/core/types/src/http/product-type/admin/index.ts @@ -0,0 +1,4 @@ +export * from "./entities" +export * from "./payloads" +export * from "./queries" +export * from "./responses" diff --git a/packages/core/types/src/http/product-type/admin/payloads.ts b/packages/core/types/src/http/product-type/admin/payloads.ts new file mode 100644 index 0000000000000..eb3daab202ffe --- /dev/null +++ b/packages/core/types/src/http/product-type/admin/payloads.ts @@ -0,0 +1,9 @@ +export interface AdminCreateProductType { + value: string + metadata?: Record | null +} + +export interface AdminUpdateProductType { + value?: string + metadata?: Record | null +} diff --git a/packages/core/types/src/http/product-type/admin/queries.ts b/packages/core/types/src/http/product-type/admin/queries.ts new file mode 100644 index 0000000000000..0fba0e659b17b --- /dev/null +++ b/packages/core/types/src/http/product-type/admin/queries.ts @@ -0,0 +1,15 @@ +import { BaseFilterable, OperatorMap } from "../../../dal" +import { FindParams, SelectParams } from "../../common" + +export interface AdminProductTypeListParams + extends FindParams, + BaseFilterable { + q?: string + id?: string | string[] + value?: string | string[] + created_at?: OperatorMap + updated_at?: OperatorMap + deleted_at?: OperatorMap +} + +export interface AdminProductTypeParams extends SelectParams {} diff --git a/packages/core/types/src/http/product-type/admin/responses.ts b/packages/core/types/src/http/product-type/admin/responses.ts new file mode 100644 index 0000000000000..ffd2d2f4d5474 --- /dev/null +++ b/packages/core/types/src/http/product-type/admin/responses.ts @@ -0,0 +1,14 @@ +import { DeleteResponse, PaginatedResponse } from "../../common" +import { AdminProductType } from "./entities" + +export interface AdminProductTypeResponse { + product_type: AdminProductType +} + +export interface AdminProductTypeListResponse + extends PaginatedResponse<{ + product_types: AdminProductType[] + }> {} + +export interface AdminProductTypeDeleteResponse + extends DeleteResponse<"product_type"> {} diff --git a/packages/core/types/src/http/product-type/common.ts b/packages/core/types/src/http/product-type/common.ts new file mode 100644 index 0000000000000..fc7eac0758f13 --- /dev/null +++ b/packages/core/types/src/http/product-type/common.ts @@ -0,0 +1,8 @@ +export interface BaseProductType { + id: string + value: string + created_at?: string + updated_at?: string + deleted_at?: string | null + metadata?: Record | null +} diff --git a/packages/core/types/src/http/product-type/index.ts b/packages/core/types/src/http/product-type/index.ts new file mode 100644 index 0000000000000..3bd2bd2cc018f --- /dev/null +++ b/packages/core/types/src/http/product-type/index.ts @@ -0,0 +1,2 @@ +export * from "./admin" +export * from "./store" diff --git a/packages/core/types/src/http/product-type/store/entities.ts b/packages/core/types/src/http/product-type/store/entities.ts new file mode 100644 index 0000000000000..f8ad9a9487fe6 --- /dev/null +++ b/packages/core/types/src/http/product-type/store/entities.ts @@ -0,0 +1,3 @@ +import { BaseProductType } from "../common" + +export interface StoreProductType extends BaseProductType {} diff --git a/packages/core/types/src/http/product-type/store/index.ts b/packages/core/types/src/http/product-type/store/index.ts new file mode 100644 index 0000000000000..8270e0b265e19 --- /dev/null +++ b/packages/core/types/src/http/product-type/store/index.ts @@ -0,0 +1 @@ +export * from "./entities" diff --git a/packages/core/types/src/http/product/admin/entitites.ts b/packages/core/types/src/http/product/admin/entitites.ts index eff5c6438ef26..3d9eb491c81e3 100644 --- a/packages/core/types/src/http/product/admin/entitites.ts +++ b/packages/core/types/src/http/product/admin/entitites.ts @@ -1,5 +1,7 @@ +import { AdminCollection } from "../../collection" import { AdminPrice } from "../../pricing" import { AdminProductCategory } from "../../product-category" +import { AdminProductType } from "../../product-type" import { AdminSalesChannel } from "../../sales-channel" import { BaseProduct, @@ -7,7 +9,6 @@ import { BaseProductOption, BaseProductOptionValue, BaseProductTag, - BaseProductType, BaseProductVariant, ProductStatus, } from "../common" @@ -16,14 +17,15 @@ 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 { + collection?: AdminCollection | null categories?: AdminProductCategory[] | null sales_channels?: AdminSalesChannel[] | null variants?: AdminProductVariant[] | null + type: AdminProductType | null } export type AdminProductStatus = ProductStatus diff --git a/packages/core/types/src/http/product/admin/queries.ts b/packages/core/types/src/http/product/admin/queries.ts index 0560bb5fee9e4..0f4c277bec487 100644 --- a/packages/core/types/src/http/product/admin/queries.ts +++ b/packages/core/types/src/http/product/admin/queries.ts @@ -1,16 +1,14 @@ import { + BaseProductListParams, 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 { +export interface AdminProductListParams extends BaseProductListParams { price_list_id?: string | string[] variants?: AdminProductVariantParams } diff --git a/packages/core/types/src/http/product/common.ts b/packages/core/types/src/http/product/common.ts index 35657346cbff6..128fcc6263dfc 100644 --- a/packages/core/types/src/http/product/common.ts +++ b/packages/core/types/src/http/product/common.ts @@ -2,6 +2,7 @@ import { BaseFilterable, OperatorMap } from "../../dal" import { BaseCollection } from "../collection/common" import { FindParams } from "../common" import { BaseProductCategory } from "../product-category/common" +import { BaseProductType } from "../product-type/common" export type ProductStatus = "draft" | "proposed" | "published" | "rejected" export interface BaseProduct { @@ -21,10 +22,10 @@ export interface BaseProduct { hs_code: string | null mid_code: string | null material: string | null - collection: BaseCollection | null + collection?: BaseCollection | null collection_id: string | null categories?: BaseProductCategory[] | null - type: BaseProductType | null + type?: BaseProductType | null type_id: string | null tags: BaseProductTag[] | null variants: BaseProductVariant[] | null @@ -72,15 +73,6 @@ export interface BaseProductTag { metadata?: Record | null } -export interface BaseProductType { - id: string - value: string - created_at?: string - updated_at?: string - deleted_at?: string | null - metadata?: Record | null -} - export interface BaseProductOption { id: string title: string @@ -113,9 +105,9 @@ export interface BaseProductOptionValue { deleted_at?: string | null } -export interface BaseProductParams +export interface BaseProductListParams extends FindParams, - BaseFilterable { + BaseFilterable { q?: string status?: ProductStatus | ProductStatus[] sales_channel_id?: string | string[] @@ -143,14 +135,6 @@ export interface BaseProductTagParams value?: string | string[] } -export interface BaseProductTypeParams - extends FindParams, - BaseFilterable { - q?: string - id?: string | string[] - value?: string -} - export interface BaseProductOptionParams extends FindParams, BaseFilterable { diff --git a/packages/core/types/src/http/product/store/entitites.ts b/packages/core/types/src/http/product/store/entitites.ts index 8e8b34660162e..1e27d066b859d 100644 --- a/packages/core/types/src/http/product/store/entitites.ts +++ b/packages/core/types/src/http/product/store/entitites.ts @@ -1,21 +1,21 @@ import { StoreProductCategory } from "../../product-category" +import { StoreProductType } from "../../product-type" import { BaseProduct, BaseProductImage, BaseProductOption, BaseProductOptionValue, BaseProductTag, - BaseProductType, BaseProductVariant, ProductStatus, } from "../common" export interface StoreProduct extends Omit { categories?: StoreProductCategory[] | null + type?: StoreProductType | null } 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 {} diff --git a/packages/core/types/src/http/product/store/queries.ts b/packages/core/types/src/http/product/store/queries.ts index 58f36802c914b..a2a866ac8ce25 100644 --- a/packages/core/types/src/http/product/store/queries.ts +++ b/packages/core/types/src/http/product/store/queries.ts @@ -1,16 +1,14 @@ import { + BaseProductListParams, BaseProductOptionParams, - BaseProductParams, 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 { +export interface StoreProductParams extends BaseProductListParams { // 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 diff --git a/packages/medusa/src/api/admin/products/route.ts b/packages/medusa/src/api/admin/products/route.ts index c9e4b64809d2b..04fb40cbd7cae 100644 --- a/packages/medusa/src/api/admin/products/route.ts +++ b/packages/medusa/src/api/admin/products/route.ts @@ -4,11 +4,11 @@ import { AuthenticatedMedusaRequest, MedusaResponse, } from "../../../types/routing" -import { remapKeysForProduct, remapProductResponse } from "./helpers" import { refetchEntities, refetchEntity } from "../../utils/refetch-entity" +import { remapKeysForProduct, remapProductResponse } from "./helpers" export const GET = async ( - req: AuthenticatedMedusaRequest, + req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { const selectFields = remapKeysForProduct(req.remoteQueryConfig.fields ?? []) diff --git a/packages/medusa/src/api/admin/products/utils/maybe-apply-price-lists-filter.ts b/packages/medusa/src/api/admin/products/utils/maybe-apply-price-lists-filter.ts index 3959e058e6557..0d26a23fceec0 100644 --- a/packages/medusa/src/api/admin/products/utils/maybe-apply-price-lists-filter.ts +++ b/packages/medusa/src/api/admin/products/utils/maybe-apply-price-lists-filter.ts @@ -1,14 +1,15 @@ +import { HttpTypes } from "@medusajs/types" import { ContainerRegistrationKeys, remoteQueryObjectFromString, } from "@medusajs/utils" import { NextFunction } from "express" import { MedusaRequest } from "../../../../types/routing" -import { HttpTypes } from "@medusajs/types" export function maybeApplyPriceListsFilter() { return async (req: MedusaRequest, _, next: NextFunction) => { - const filterableFields: HttpTypes.AdminProductParams = req.filterableFields + const filterableFields: HttpTypes.AdminProductListParams = + req.filterableFields if (!filterableFields.price_list_id) { return next()