feat(dashboard): collection product management (#7333)
* feat: implement collection management * fix: toasts * fix: use query keys from the lib --------- Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
@@ -97,11 +97,10 @@ const useCoreRoutes = (): Omit<NavItemProps, "pathname">[] => {
|
|||||||
label: t("products.domain"),
|
label: t("products.domain"),
|
||||||
to: "/products",
|
to: "/products",
|
||||||
items: [
|
items: [
|
||||||
// TODO: Enable when domin is introduced
|
{
|
||||||
// {
|
label: t("collections.domain"),
|
||||||
// label: t("collections.domain"),
|
to: "/collections",
|
||||||
// to: "/collections",
|
},
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
label: t("categories.domain"),
|
label: t("categories.domain"),
|
||||||
to: "/categories",
|
to: "/categories",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { queryClient } from "../../lib/medusa"
|
|||||||
import { queryKeysFactory } from "../../lib/query-key-factory"
|
import { queryKeysFactory } from "../../lib/query-key-factory"
|
||||||
import {
|
import {
|
||||||
CreateProductCollectionReq,
|
CreateProductCollectionReq,
|
||||||
|
UpdateProductCollectionProductsReq,
|
||||||
UpdateProductCollectionReq,
|
UpdateProductCollectionReq,
|
||||||
} from "../../types/api-payloads"
|
} from "../../types/api-payloads"
|
||||||
import {
|
import {
|
||||||
@@ -86,6 +87,29 @@ export const useUpdateCollection = (
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useUpdateCollectionProducts = (
|
||||||
|
id: string,
|
||||||
|
options?: UseMutationOptions<
|
||||||
|
ProductCollectionRes,
|
||||||
|
Error,
|
||||||
|
UpdateProductCollectionProductsReq
|
||||||
|
>
|
||||||
|
) => {
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (payload: UpdateProductCollectionProductsReq) =>
|
||||||
|
client.collections.updateProducts(id, payload),
|
||||||
|
onSuccess: (data, variables, context) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: collectionsQueryKeys.lists() })
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: collectionsQueryKeys.detail(id),
|
||||||
|
})
|
||||||
|
|
||||||
|
options?.onSuccess?.(data, variables, context)
|
||||||
|
},
|
||||||
|
...options,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export const useCreateCollection = (
|
export const useCreateCollection = (
|
||||||
options?: UseMutationOptions<
|
options?: UseMutationOptions<
|
||||||
ProductCollectionRes,
|
ProductCollectionRes,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
CreateProductCollectionReq,
|
CreateProductCollectionReq,
|
||||||
|
UpdateProductCollectionProductsReq,
|
||||||
UpdateProductCollectionReq,
|
UpdateProductCollectionReq,
|
||||||
} from "../../types/api-payloads"
|
} from "../../types/api-payloads"
|
||||||
import {
|
import {
|
||||||
@@ -31,6 +32,16 @@ async function createProductCollection(payload: CreateProductCollectionReq) {
|
|||||||
return postRequest<ProductCollectionRes>(`/admin/collections`, payload)
|
return postRequest<ProductCollectionRes>(`/admin/collections`, payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateProductCollectionProducts(
|
||||||
|
id: string,
|
||||||
|
payload: UpdateProductCollectionProductsReq
|
||||||
|
) {
|
||||||
|
return postRequest<ProductCollectionRes>(
|
||||||
|
`/admin/collections/${id}/products`,
|
||||||
|
payload
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async function deleteProductCollection(id: string) {
|
async function deleteProductCollection(id: string) {
|
||||||
return deleteRequest<ProductCollectionDeleteRes>(`/admin/collections/${id}`)
|
return deleteRequest<ProductCollectionDeleteRes>(`/admin/collections/${id}`)
|
||||||
}
|
}
|
||||||
@@ -39,6 +50,7 @@ export const collections = {
|
|||||||
list: listProductCollections,
|
list: listProductCollections,
|
||||||
retrieve: retrieveProductCollection,
|
retrieve: retrieveProductCollection,
|
||||||
update: updateProductCollection,
|
update: updateProductCollection,
|
||||||
|
updateProducts: updateProductCollectionProducts,
|
||||||
create: createProductCollection,
|
create: createProductCollection,
|
||||||
delete: deleteProductCollection,
|
delete: deleteProductCollection,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ export type CreateInviteReq = CreateInviteDTO
|
|||||||
export type CreateStockLocationReq = CreateStockLocationInput
|
export type CreateStockLocationReq = CreateStockLocationInput
|
||||||
export type UpdateStockLocationReq = UpdateStockLocationInput
|
export type UpdateStockLocationReq = UpdateStockLocationInput
|
||||||
export type UpdateStockLocationSalesChannelsReq = {
|
export type UpdateStockLocationSalesChannelsReq = {
|
||||||
add: string[]
|
add?: string[]
|
||||||
remove: string[]
|
remove?: string[]
|
||||||
}
|
}
|
||||||
export type CreateFulfillmentSetReq = CreateFulfillmentSetDTO
|
export type CreateFulfillmentSetReq = CreateFulfillmentSetDTO
|
||||||
export type CreateServiceZoneReq = CreateServiceZoneDTO
|
export type CreateServiceZoneReq = CreateServiceZoneDTO
|
||||||
@@ -86,6 +86,10 @@ export type CreateShippingProfileReq = CreateShippingProfileDTO
|
|||||||
// Product Collections
|
// Product Collections
|
||||||
export type CreateProductCollectionReq = CreateProductCollectionDTO
|
export type CreateProductCollectionReq = CreateProductCollectionDTO
|
||||||
export type UpdateProductCollectionReq = UpdateProductCollectionDTO
|
export type UpdateProductCollectionReq = UpdateProductCollectionDTO
|
||||||
|
export type UpdateProductCollectionProductsReq = {
|
||||||
|
add?: string[]
|
||||||
|
remove?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
// Price Lists
|
// Price Lists
|
||||||
export type CreatePriceListReq = CreatePriceListDTO
|
export type CreatePriceListReq = CreatePriceListDTO
|
||||||
|
|||||||
+258
-222
@@ -1,11 +1,47 @@
|
|||||||
import type { Product } from "@medusajs/medusa"
|
import { ProductCollectionDTO, ProductDTO } from "@medusajs/types"
|
||||||
import { ProductCollectionDTO } from "@medusajs/types"
|
import {
|
||||||
import { Checkbox, Tooltip } from "@medusajs/ui"
|
Button,
|
||||||
import { createColumnHelper } from "@tanstack/react-table"
|
Checkbox,
|
||||||
import { useMemo } from "react"
|
clx,
|
||||||
|
Hint,
|
||||||
|
Table,
|
||||||
|
toast,
|
||||||
|
Tooltip,
|
||||||
|
} from "@medusajs/ui"
|
||||||
|
import { useForm } from "react-hook-form"
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod"
|
||||||
|
import { keepPreviousData } from "@tanstack/react-query"
|
||||||
|
import {
|
||||||
|
createColumnHelper,
|
||||||
|
flexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
PaginationState,
|
||||||
|
RowSelectionState,
|
||||||
|
useReactTable,
|
||||||
|
} from "@tanstack/react-table"
|
||||||
|
import { Fragment, useEffect, useMemo, useState } from "react"
|
||||||
import { useTranslation } from "react-i18next"
|
import { useTranslation } from "react-i18next"
|
||||||
import * as zod from "zod"
|
import * as zod from "zod"
|
||||||
import { useProductTableColumns } from "../../../../../hooks/table/columns/use-product-table-columns"
|
import { useProductTableColumns } from "../../../../../hooks/table/columns/use-product-table-columns"
|
||||||
|
import {
|
||||||
|
RouteFocusModal,
|
||||||
|
useRouteModal,
|
||||||
|
} from "../../../../../components/route-modal"
|
||||||
|
import { useQueryParams } from "../../../../../hooks/use-query-params"
|
||||||
|
import {
|
||||||
|
productsQueryKeys,
|
||||||
|
useProducts,
|
||||||
|
} from "../../../../../hooks/api/products"
|
||||||
|
import { useHandleTableScroll } from "../../../../../hooks/use-handle-table-scroll.tsx"
|
||||||
|
import { Query } from "../../../../../components/filtering/query"
|
||||||
|
import { OrderBy } from "../../../../../components/filtering/order-by"
|
||||||
|
import {
|
||||||
|
NoRecords,
|
||||||
|
NoResults,
|
||||||
|
} from "../../../../../components/common/empty-table-content"
|
||||||
|
import { LocalizedTablePagination } from "../../../../../components/localization/localized-table-pagination"
|
||||||
|
import { useUpdateCollectionProducts } from "../../../../../hooks/api/collections"
|
||||||
|
import { queryClient } from "../../../../../lib/medusa"
|
||||||
|
|
||||||
// Re-add when supported on the backend
|
// Re-add when supported on the backend
|
||||||
|
|
||||||
@@ -13,7 +49,7 @@ type AddProductsToCollectionFormProps = {
|
|||||||
collection: ProductCollectionDTO
|
collection: ProductCollectionDTO
|
||||||
}
|
}
|
||||||
|
|
||||||
const AddProductsToSalesChannelSchema = zod.object({
|
const AddProductsToCollectionSchema = zod.object({
|
||||||
product_ids: zod.array(zod.string()).min(1),
|
product_ids: zod.array(zod.string()).min(1),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -22,242 +58,242 @@ const PAGE_SIZE = 50
|
|||||||
export const AddProductsToCollectionForm = ({
|
export const AddProductsToCollectionForm = ({
|
||||||
collection,
|
collection,
|
||||||
}: AddProductsToCollectionFormProps) => {
|
}: AddProductsToCollectionFormProps) => {
|
||||||
// const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
// const { handleSuccess } = useRouteModal()
|
const { handleSuccess } = useRouteModal()
|
||||||
|
|
||||||
// const form = useForm<zod.infer<typeof AddProductsToSalesChannelSchema>>({
|
const form = useForm<zod.infer<typeof AddProductsToCollectionSchema>>({
|
||||||
// defaultValues: {
|
defaultValues: {
|
||||||
// product_ids: [],
|
product_ids: [],
|
||||||
// },
|
},
|
||||||
// resolver: zodResolver(AddProductsToSalesChannelSchema),
|
resolver: zodResolver(AddProductsToCollectionSchema),
|
||||||
// })
|
})
|
||||||
|
|
||||||
// const { setValue } = form
|
const { setValue } = form
|
||||||
|
|
||||||
// const { mutateAsync, isLoading: isMutating } =
|
const { mutateAsync, isPending: isMutating } = useUpdateCollectionProducts(
|
||||||
// useAdminAddProductsToCollection(collection.id)
|
collection.id
|
||||||
|
)
|
||||||
|
|
||||||
// const [{ pageIndex, pageSize }, setPagination] = useState<PaginationState>({
|
const [{ pageIndex, pageSize }, setPagination] = useState<PaginationState>({
|
||||||
// pageIndex: 0,
|
pageIndex: 0,
|
||||||
// pageSize: PAGE_SIZE,
|
pageSize: PAGE_SIZE,
|
||||||
// })
|
})
|
||||||
|
|
||||||
// const pagination = useMemo(
|
const pagination = useMemo(
|
||||||
// () => ({
|
() => ({
|
||||||
// pageIndex,
|
pageIndex,
|
||||||
// pageSize,
|
pageSize,
|
||||||
// }),
|
}),
|
||||||
// [pageIndex, pageSize]
|
[pageIndex, pageSize]
|
||||||
// )
|
)
|
||||||
|
|
||||||
// const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
|
const [rowSelection, setRowSelection] = useState<RowSelectionState>({})
|
||||||
|
|
||||||
// useEffect(() => {
|
useEffect(() => {
|
||||||
// setValue(
|
setValue(
|
||||||
// "product_ids",
|
"product_ids",
|
||||||
// Object.keys(rowSelection).filter((k) => rowSelection[k]),
|
Object.keys(rowSelection).filter((k) => rowSelection[k]),
|
||||||
// {
|
{
|
||||||
// shouldDirty: true,
|
shouldDirty: true,
|
||||||
// shouldTouch: true,
|
shouldTouch: true,
|
||||||
// }
|
}
|
||||||
// )
|
)
|
||||||
// }, [rowSelection, setValue])
|
}, [rowSelection, setValue])
|
||||||
|
|
||||||
// const params = useQueryParams(["q", "order"])
|
const params = useQueryParams(["q", "order"])
|
||||||
|
|
||||||
// const { products, count, isLoading, isError, error } = useAdminProducts(
|
const { products, count, isLoading, isError, error } = useProducts(
|
||||||
// {
|
{
|
||||||
// expand: "variants,sales_channels",
|
fields: "*variants,*sales_channels",
|
||||||
// ...params,
|
...params,
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// keepPreviousData: true,
|
placeholderData: keepPreviousData,
|
||||||
// }
|
}
|
||||||
// )
|
)
|
||||||
|
|
||||||
// const columns = useColumns()
|
const columns = useColumns()
|
||||||
|
|
||||||
// const table = useReactTable({
|
const table = useReactTable({
|
||||||
// data: (products ?? []) as Product[],
|
data: (products ?? []) as ProductDTO[],
|
||||||
// columns,
|
columns,
|
||||||
// pageCount: Math.ceil((count ?? 0) / PAGE_SIZE),
|
pageCount: Math.ceil((count ?? 0) / PAGE_SIZE),
|
||||||
// state: {
|
state: {
|
||||||
// pagination,
|
pagination,
|
||||||
// rowSelection,
|
rowSelection,
|
||||||
// },
|
},
|
||||||
// onPaginationChange: setPagination,
|
onPaginationChange: setPagination,
|
||||||
// onRowSelectionChange: setRowSelection,
|
onRowSelectionChange: setRowSelection,
|
||||||
// getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
// manualPagination: true,
|
manualPagination: true,
|
||||||
// getRowId: (row) => row.id,
|
getRowId: (row) => row.id,
|
||||||
// enableRowSelection(row) {
|
enableRowSelection(row) {
|
||||||
// return row.original.collection_id !== collection.id
|
return row.original.collection_id !== collection.id
|
||||||
// },
|
},
|
||||||
// meta: {
|
meta: {
|
||||||
// collectionId: collection.id,
|
collectionId: collection.id,
|
||||||
// },
|
},
|
||||||
// })
|
})
|
||||||
|
|
||||||
// const handleSubmit = form.handleSubmit(async (values) => {
|
const handleSubmit = form.handleSubmit(async (values) => {
|
||||||
// await mutateAsync(
|
try {
|
||||||
// {
|
await mutateAsync({
|
||||||
// product_ids: values.product_ids.map((p) => p),
|
add: values.product_ids,
|
||||||
// },
|
})
|
||||||
// {
|
/**
|
||||||
// onSuccess: () => {
|
* Invalidate the products list query to refetch products and
|
||||||
// /**
|
* determine if they are added to the collection or not.
|
||||||
// * Invalidate the products list query to refetch products and
|
*/
|
||||||
// * determine if they are added to the collection or not.
|
queryClient.invalidateQueries(productsQueryKeys.lists())
|
||||||
// */
|
handleSuccess()
|
||||||
// queryClient.invalidateQueries(adminProductKeys.lists())
|
} catch (e) {
|
||||||
// handleSuccess()
|
toast.error(t("general.error"), {
|
||||||
// },
|
description: e.message,
|
||||||
// }
|
dismissLabel: t("actions.close"),
|
||||||
// )
|
})
|
||||||
// })
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// const { handleScroll, isScrolled, tableContainerRef } = useHandleTableScroll()
|
const { handleScroll, isScrolled, tableContainerRef } = useHandleTableScroll()
|
||||||
|
|
||||||
// const noRecords =
|
const noRecords =
|
||||||
// !isLoading &&
|
!isLoading &&
|
||||||
// products?.length === 0 &&
|
products?.length === 0 &&
|
||||||
// !Object.values(params).filter((v) => v).length
|
!Object.values(params).filter((v) => v).length
|
||||||
|
|
||||||
// if (isError) {
|
if (isError) {
|
||||||
// throw error
|
throw error
|
||||||
// }
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
// <RouteFocusModal.Form form={form}>
|
<RouteFocusModal.Form form={form}>
|
||||||
// <form
|
<form
|
||||||
// onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
// className="flex h-full flex-col overflow-hidden"
|
className="flex h-full flex-col overflow-hidden"
|
||||||
// >
|
>
|
||||||
// <RouteFocusModal.Header>
|
<RouteFocusModal.Header>
|
||||||
// <div className="flex items-center justify-end gap-x-2">
|
<div className="flex items-center justify-end gap-x-2">
|
||||||
// {form.formState.errors.product_ids && (
|
{form.formState.errors.product_ids && (
|
||||||
// <Hint variant="error">
|
<Hint variant="error">
|
||||||
// {form.formState.errors.product_ids.message}
|
{form.formState.errors.product_ids.message}
|
||||||
// </Hint>
|
</Hint>
|
||||||
// )}
|
)}
|
||||||
// <RouteFocusModal.Close asChild>
|
<RouteFocusModal.Close asChild>
|
||||||
// <Button size="small" variant="secondary">
|
<Button size="small" variant="secondary">
|
||||||
// {t("actions.cancel")}
|
{t("actions.cancel")}
|
||||||
// </Button>
|
</Button>
|
||||||
// </RouteFocusModal.Close>
|
</RouteFocusModal.Close>
|
||||||
// <Button size="small" type="submit" isLoading={isMutating}>
|
<Button size="small" type="submit" isLoading={isMutating}>
|
||||||
// {t("actions.save")}
|
{t("actions.save")}
|
||||||
// </Button>
|
</Button>
|
||||||
// </div>
|
</div>
|
||||||
// </RouteFocusModal.Header>
|
</RouteFocusModal.Header>
|
||||||
// <RouteFocusModal.Body className="flex h-full w-full flex-col items-center divide-y overflow-y-auto">
|
<RouteFocusModal.Body className="flex h-full w-full flex-col items-center divide-y overflow-y-auto">
|
||||||
// {!noRecords && (
|
{!noRecords && (
|
||||||
// <div className="flex w-full items-center justify-between px-6 py-4">
|
<div className="flex w-full items-center justify-between px-6 py-4">
|
||||||
// <div></div>
|
<div></div>
|
||||||
// <div className="flex items-center gap-x-2">
|
<div className="flex items-center gap-x-2">
|
||||||
// <Query />
|
<Query />
|
||||||
// <OrderBy keys={["title"]} />
|
<OrderBy keys={["title"]} />
|
||||||
// </div>
|
</div>
|
||||||
// </div>
|
</div>
|
||||||
// )}
|
)}
|
||||||
// {!noRecords ? (
|
{!noRecords ? (
|
||||||
// <Fragment>
|
<Fragment>
|
||||||
// <div
|
<div
|
||||||
// ref={tableContainerRef}
|
ref={tableContainerRef}
|
||||||
// className="w-full flex-1 overflow-y-auto"
|
className="w-full flex-1 overflow-y-auto"
|
||||||
// onScroll={handleScroll}
|
onScroll={handleScroll}
|
||||||
// >
|
>
|
||||||
// {!isLoading && !products?.length ? (
|
{!isLoading && !products?.length ? (
|
||||||
// <div className="flex h-full flex-1 items-center justify-center">
|
<div className="flex h-full flex-1 items-center justify-center">
|
||||||
// <NoResults />
|
<NoResults />
|
||||||
// </div>
|
</div>
|
||||||
// ) : (
|
) : (
|
||||||
// <Table>
|
<Table>
|
||||||
// <Table.Header
|
<Table.Header
|
||||||
// className={clx(
|
className={clx(
|
||||||
// "bg-ui-bg-base transition-fg sticky inset-x-0 top-0 z-10 border-t-0",
|
"bg-ui-bg-base transition-fg sticky inset-x-0 top-0 z-10 border-t-0",
|
||||||
// {
|
{
|
||||||
// "shadow-elevation-card-hover": isScrolled,
|
"shadow-elevation-card-hover": isScrolled,
|
||||||
// }
|
}
|
||||||
// )}
|
)}
|
||||||
// >
|
>
|
||||||
// {table.getHeaderGroups().map((headerGroup) => {
|
{table.getHeaderGroups().map((headerGroup) => {
|
||||||
// return (
|
return (
|
||||||
// <Table.Row
|
<Table.Row
|
||||||
// key={headerGroup.id}
|
key={headerGroup.id}
|
||||||
// className="[&_th:first-of-type]:w-[1%] [&_th:first-of-type]:whitespace-nowrap [&_th]:w-1/5"
|
className="[&_th:first-of-type]:w-[1%] [&_th:first-of-type]:whitespace-nowrap [&_th]:w-1/5"
|
||||||
// >
|
>
|
||||||
// {headerGroup.headers.map((header) => {
|
{headerGroup.headers.map((header) => {
|
||||||
// return (
|
return (
|
||||||
// <Table.HeaderCell key={header.id}>
|
<Table.HeaderCell key={header.id}>
|
||||||
// {flexRender(
|
{flexRender(
|
||||||
// header.column.columnDef.header,
|
header.column.columnDef.header,
|
||||||
// header.getContext()
|
header.getContext()
|
||||||
// )}
|
)}
|
||||||
// </Table.HeaderCell>
|
</Table.HeaderCell>
|
||||||
// )
|
)
|
||||||
// })}
|
})}
|
||||||
// </Table.Row>
|
</Table.Row>
|
||||||
// )
|
)
|
||||||
// })}
|
})}
|
||||||
// </Table.Header>
|
</Table.Header>
|
||||||
// <Table.Body className="border-b-0">
|
<Table.Body className="border-b-0">
|
||||||
// {table.getRowModel().rows.map((row) => (
|
{table.getRowModel().rows.map((row) => (
|
||||||
// <Table.Row
|
<Table.Row
|
||||||
// key={row.id}
|
key={row.id}
|
||||||
// className={clx(
|
className={clx(
|
||||||
// "transition-fg",
|
"transition-fg",
|
||||||
// {
|
{
|
||||||
// "bg-ui-bg-highlight hover:bg-ui-bg-highlight-hover":
|
"bg-ui-bg-highlight hover:bg-ui-bg-highlight-hover":
|
||||||
// row.getIsSelected(),
|
row.getIsSelected(),
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// "bg-ui-bg-disabled hover:bg-ui-bg-disabled":
|
"bg-ui-bg-disabled hover:bg-ui-bg-disabled":
|
||||||
// row.original.collection_id === collection.id,
|
row.original.collection_id === collection.id,
|
||||||
// }
|
}
|
||||||
// )}
|
)}
|
||||||
// >
|
>
|
||||||
// {row.getVisibleCells().map((cell) => (
|
{row.getVisibleCells().map((cell) => (
|
||||||
// <Table.Cell key={cell.id}>
|
<Table.Cell key={cell.id}>
|
||||||
// {flexRender(
|
{flexRender(
|
||||||
// cell.column.columnDef.cell,
|
cell.column.columnDef.cell,
|
||||||
// cell.getContext()
|
cell.getContext()
|
||||||
// )}
|
)}
|
||||||
// </Table.Cell>
|
</Table.Cell>
|
||||||
// ))}
|
))}
|
||||||
// </Table.Row>
|
</Table.Row>
|
||||||
// ))}
|
))}
|
||||||
// </Table.Body>
|
</Table.Body>
|
||||||
// </Table>
|
</Table>
|
||||||
// )}
|
)}
|
||||||
// </div>
|
</div>
|
||||||
// <div className="w-full border-t">
|
<div className="w-full border-t">
|
||||||
// <LocalizedTablePagination
|
<LocalizedTablePagination
|
||||||
// canNextPage={table.getCanNextPage()}
|
canNextPage={table.getCanNextPage()}
|
||||||
// canPreviousPage={table.getCanPreviousPage()}
|
canPreviousPage={table.getCanPreviousPage()}
|
||||||
// nextPage={table.nextPage}
|
nextPage={table.nextPage}
|
||||||
// previousPage={table.previousPage}
|
previousPage={table.previousPage}
|
||||||
// count={count ?? 0}
|
count={count ?? 0}
|
||||||
// pageIndex={pageIndex}
|
pageIndex={pageIndex}
|
||||||
// pageCount={table.getPageCount()}
|
pageCount={table.getPageCount()}
|
||||||
// pageSize={PAGE_SIZE}
|
pageSize={PAGE_SIZE}
|
||||||
// />
|
/>
|
||||||
// </div>
|
</div>
|
||||||
// </Fragment>
|
</Fragment>
|
||||||
// ) : (
|
) : (
|
||||||
// <div className="flex flex-1 items-center justify-center">
|
<div className="flex flex-1 items-center justify-center">
|
||||||
// <NoRecords />
|
<NoRecords />
|
||||||
// {/* TODO: fix this, and add NoRecords as well */}
|
</div>
|
||||||
// </div>
|
)}
|
||||||
// )}
|
</RouteFocusModal.Body>
|
||||||
// </RouteFocusModal.Body>
|
</form>
|
||||||
// </form>
|
</RouteFocusModal.Form>
|
||||||
// </RouteFocusModal.Form>
|
|
||||||
<div>NOT IMPLEMETED</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<Product>()
|
const columnHelper = createColumnHelper<ProductDTO>()
|
||||||
|
|
||||||
const useColumns = () => {
|
const useColumns = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|||||||
+33
-19
@@ -1,19 +1,23 @@
|
|||||||
import { PencilSquare, Plus, Trash } from "@medusajs/icons"
|
import { PencilSquare, Plus, Trash } from "@medusajs/icons"
|
||||||
import { ProductCollectionDTO } from "@medusajs/types"
|
import { ProductCollectionDTO } from "@medusajs/types"
|
||||||
import { Checkbox, Container, Heading, usePrompt } from "@medusajs/ui"
|
import { Checkbox, Container, Heading, toast, usePrompt } from "@medusajs/ui"
|
||||||
import { keepPreviousData } from "@tanstack/react-query"
|
import { keepPreviousData } from "@tanstack/react-query"
|
||||||
import { createColumnHelper } from "@tanstack/react-table"
|
import { createColumnHelper } from "@tanstack/react-table"
|
||||||
import { useAdminRemoveProductsFromCollection } from "medusa-react"
|
|
||||||
import { useMemo } from "react"
|
import { useMemo } from "react"
|
||||||
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 { DataTable } from "../../../../../components/table/data-table"
|
import { DataTable } from "../../../../../components/table/data-table"
|
||||||
import { useProducts } from "../../../../../hooks/api/products"
|
import {
|
||||||
|
productsQueryKeys,
|
||||||
|
useProducts,
|
||||||
|
} from "../../../../../hooks/api/products"
|
||||||
import { useProductTableColumns } from "../../../../../hooks/table/columns/use-product-table-columns"
|
import { useProductTableColumns } from "../../../../../hooks/table/columns/use-product-table-columns"
|
||||||
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 { ExtendedProductDTO } from "../../../../../types/api-responses"
|
||||||
|
import { useUpdateCollectionProducts } from "../../../../../hooks/api/collections"
|
||||||
|
import { queryClient } from "../../../../../lib/medusa"
|
||||||
|
|
||||||
type CollectionProductSectionProps = {
|
type CollectionProductSectionProps = {
|
||||||
collection: ProductCollectionDTO
|
collection: ProductCollectionDTO
|
||||||
@@ -55,8 +59,8 @@ export const CollectionProductSection = ({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const prompt = usePrompt()
|
const prompt = usePrompt()
|
||||||
// Not implemented in 2.0
|
|
||||||
// const { mutateAsync } = useAdminRemoveProductsFromCollection(collection.id)
|
const { mutateAsync } = useUpdateCollectionProducts(collection.id)
|
||||||
|
|
||||||
const handleRemove = async (selection: Record<string, boolean>) => {
|
const handleRemove = async (selection: Record<string, boolean>) => {
|
||||||
const ids = Object.keys(selection)
|
const ids = Object.keys(selection)
|
||||||
@@ -74,16 +78,18 @@ export const CollectionProductSection = ({
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// await mutateAsync(
|
try {
|
||||||
// {
|
await mutateAsync({
|
||||||
// product_ids: ids,
|
remove: ids,
|
||||||
// },
|
})
|
||||||
// {
|
|
||||||
// onSuccess: () => {
|
queryClient.invalidateQueries(productsQueryKeys.lists())
|
||||||
// queryClient.invalidateQueries(adminProductKeys.lists())
|
} catch (e) {
|
||||||
// },
|
toast.error(t("general.error"), {
|
||||||
// }
|
description: e.message,
|
||||||
// )
|
dismissLabel: t("actions.close"),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isError) {
|
if (isError) {
|
||||||
@@ -141,7 +147,7 @@ const ProductActions = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const prompt = usePrompt()
|
const prompt = usePrompt()
|
||||||
const { mutateAsync } = useAdminRemoveProductsFromCollection(collectionId)
|
const { mutateAsync } = useUpdateCollectionProducts(collectionId)
|
||||||
|
|
||||||
const handleRemove = async () => {
|
const handleRemove = async () => {
|
||||||
const res = await prompt({
|
const res = await prompt({
|
||||||
@@ -156,10 +162,18 @@ const ProductActions = ({
|
|||||||
if (!res) {
|
if (!res) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
await mutateAsync({
|
||||||
|
remove: [product.id],
|
||||||
|
})
|
||||||
|
|
||||||
await mutateAsync({
|
queryClient.invalidateQueries(productsQueryKeys.lists())
|
||||||
product_ids: [product.id],
|
} catch (e) {
|
||||||
})
|
toast.error(t("general.error"), {
|
||||||
|
description: e.message,
|
||||||
|
dismissLabel: t("actions.close"),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user