diff --git a/integration-tests/modules/__tests__/customer-group/admin/batch-add-customers.ts b/integration-tests/modules/__tests__/customer-group/admin/batch-add-customers.ts index a93431887a..a1cc138e84 100644 --- a/integration-tests/modules/__tests__/customer-group/admin/batch-add-customers.ts +++ b/integration-tests/modules/__tests__/customer-group/admin/batch-add-customers.ts @@ -1,7 +1,7 @@ -import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../../helpers/create-admin-user" +import { ICustomerModuleService } from "@medusajs/types" import { medusaIntegrationTestRunner } from "medusa-test-utils" +import { createAdminUser } from "../../../../helpers/create-admin-user" jest.setTimeout(50000) @@ -13,7 +13,7 @@ const adminHeaders = { medusaIntegrationTestRunner({ env, testSuite: ({ dbConnection, getContainer, api }) => { - describe("POST /admin/customer-groups/:id/customers/batch", () => { + describe("POST /admin/customer-groups/:id/customers/batch/add", () => { let appContainer let customerModuleService: ICustomerModuleService @@ -48,7 +48,7 @@ medusaIntegrationTestRunner({ ]) const response = await api.post( - `/admin/customer-groups/${group.id}/customers/batch`, + `/admin/customer-groups/${group.id}/customers/batch/add`, { customer_ids: customers.map((c) => ({ id: c.id })), }, diff --git a/integration-tests/modules/__tests__/customer-group/admin/batch-remove-customers.ts b/integration-tests/modules/__tests__/customer-group/admin/batch-remove-customers.ts index 7832c3a037..86627978d2 100644 --- a/integration-tests/modules/__tests__/customer-group/admin/batch-remove-customers.ts +++ b/integration-tests/modules/__tests__/customer-group/admin/batch-remove-customers.ts @@ -1,7 +1,7 @@ -import { ICustomerModuleService } from "@medusajs/types" import { ModuleRegistrationName } from "@medusajs/modules-sdk" -import { createAdminUser } from "../../../../helpers/create-admin-user" +import { ICustomerModuleService } from "@medusajs/types" import { medusaIntegrationTestRunner } from "medusa-test-utils" +import { createAdminUser } from "../../../../helpers/create-admin-user" jest.setTimeout(50000) @@ -13,7 +13,7 @@ const adminHeaders = { medusaIntegrationTestRunner({ env, testSuite: ({ dbConnection, getContainer, api }) => { - describe("DELETE /admin/customer-groups/:id/customers/remove", () => { + describe("POST /admin/customer-groups/:id/customers/batch/remove", () => { let appContainer let customerModuleService: ICustomerModuleService @@ -55,7 +55,7 @@ medusaIntegrationTestRunner({ ) const response = await api.post( - `/admin/customer-groups/${group.id}/customers/remove`, + `/admin/customer-groups/${group.id}/customers/batch/remove`, { customer_ids: customers.map((c) => ({ id: c.id })), }, diff --git a/packages/admin-next/dashboard/src/hooks/api/customer-groups.tsx b/packages/admin-next/dashboard/src/hooks/api/customer-groups.tsx index fefae24e74..6517de2bfc 100644 --- a/packages/admin-next/dashboard/src/hooks/api/customer-groups.tsx +++ b/packages/admin-next/dashboard/src/hooks/api/customer-groups.tsx @@ -1,10 +1,21 @@ +import { + QueryKey, + UseMutationOptions, + UseQueryOptions, + useMutation, + useQuery, +} from "@tanstack/react-query" +import { client } from "../../lib/client" +import { queryKeysFactory } from "../../lib/query-key-factory" import { AdminCustomerGroupListResponse, AdminCustomerGroupResponse, } from "@medusajs/types" -import { QueryKey, UseQueryOptions, useQuery } from "@tanstack/react-query" -import { client } from "../../lib/client" -import { queryKeysFactory } from "../../lib/query-key-factory" +import { z } from "zod" +import { CreateCustomerGroupSchema } from "../../v2-routes/customer-groups/customer-group-create/components/create-customer-group-form" +import { queryClient } from "../../lib/medusa" +import { EditCustomerGroupSchema } from "../../v2-routes/customer-groups/customer-group-edit/components/edit-customer-group-form" +import { customersQueryKeys } from "./customers" const CUSTOMER_GROUPS_QUERY_KEY = "customer_groups" as const const customerGroupsQueryKeys = queryKeysFactory(CUSTOMER_GROUPS_QUERY_KEY) @@ -51,3 +62,124 @@ export const useCustomerGroups = ( return { ...data, ...rest } } + +export const useCreateCustomerGroup = ( + options?: UseMutationOptions< + AdminCustomerGroupResponse, + Error, + z.infer + > +) => { + return useMutation({ + mutationFn: (payload) => client.customerGroups.create(payload), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ + queryKey: customerGroupsQueryKeys.lists(), + }) + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} + +export const useUpdateCustomerGroup = ( + id: string, + options?: UseMutationOptions< + AdminCustomerGroupResponse, + Error, + z.infer + > +) => { + return useMutation({ + mutationFn: (payload) => client.customerGroups.update(id, payload), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ + queryKey: customerGroupsQueryKeys.lists(), + }) + queryClient.invalidateQueries({ + queryKey: customerGroupsQueryKeys.detail(id), + }) + + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} + +export const useDeleteCustomerGroup = ( + id: string, + options?: UseMutationOptions< + { id: string; object: "customer-group"; deleted: boolean }, + Error, + void + > +) => { + return useMutation({ + mutationFn: () => client.customerGroups.delete(id), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ + queryKey: customerGroupsQueryKeys.lists(), + }) + queryClient.invalidateQueries({ + queryKey: customerGroupsQueryKeys.detail(id), + }) + + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} + +export const useAddCustomersToGroup = ( + id: string, + options?: UseMutationOptions< + AdminCustomerGroupResponse, + Error, + { customer_ids: { id: string }[] } + > +) => { + return useMutation({ + mutationFn: (payload) => client.customerGroups.addCustomers(id, payload), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ + queryKey: customerGroupsQueryKeys.lists(), + }) + queryClient.invalidateQueries({ + queryKey: customerGroupsQueryKeys.detail(id), + }) + queryClient.invalidateQueries({ + queryKey: customersQueryKeys.lists(), + }) + + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} + +export const useRemoveCustomersFromGroup = ( + id: string, + options?: UseMutationOptions< + AdminCustomerGroupResponse, + Error, + { customer_ids: { id: string }[] } + > +) => { + return useMutation({ + mutationFn: (payload) => client.customerGroups.removeCustomers(id, payload), + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({ + queryKey: customerGroupsQueryKeys.lists(), + }) + queryClient.invalidateQueries({ + queryKey: customerGroupsQueryKeys.detail(id), + }) + queryClient.invalidateQueries({ + queryKey: customersQueryKeys.lists(), + }) + + options?.onSuccess?.(data, variables, context) + }, + ...options, + }) +} diff --git a/packages/admin-next/dashboard/src/hooks/api/customers.tsx b/packages/admin-next/dashboard/src/hooks/api/customers.tsx index 5afc93be5a..de7d66e4d7 100644 --- a/packages/admin-next/dashboard/src/hooks/api/customers.tsx +++ b/packages/admin-next/dashboard/src/hooks/api/customers.tsx @@ -15,7 +15,7 @@ import { } from "@medusajs/types" const CUSTOMERS_QUERY_KEY = "customers" as const -const customersQueryKeys = queryKeysFactory(CUSTOMERS_QUERY_KEY) +export const customersQueryKeys = queryKeysFactory(CUSTOMERS_QUERY_KEY) export const useCustomer = ( id: string, diff --git a/packages/admin-next/dashboard/src/lib/client/customer-groups.ts b/packages/admin-next/dashboard/src/lib/client/customer-groups.ts index a73429121d..0808846d45 100644 --- a/packages/admin-next/dashboard/src/lib/client/customer-groups.ts +++ b/packages/admin-next/dashboard/src/lib/client/customer-groups.ts @@ -2,7 +2,10 @@ import { AdminCustomerGroupListResponse, AdminCustomerGroupResponse, } from "@medusajs/types" -import { getRequest } from "./common" +import { z } from "zod" +import { CreateCustomerGroupSchema } from "../../v2-routes/customer-groups/customer-group-create/components/create-customer-group-form" +import { EditCustomerGroupSchema } from "../../v2-routes/customer-groups/customer-group-edit/components/edit-customer-group-form" +import { deleteRequest, getRequest, postRequest } from "./common" async function retrieveCustomerGroup(id: string, query?: Record) { return getRequest( @@ -18,7 +21,59 @@ async function listCustomerGroups(query?: Record) { ) } +async function createCustomerGroup( + payload: z.infer +) { + return postRequest( + `/admin/customer-groups`, + payload + ) +} + +async function updateCustomerGroup( + id: string, + payload: z.infer +) { + return postRequest( + `/admin/customer-groups/${id}`, + payload + ) +} + +async function deleteCustomerGroup(id: string) { + return deleteRequest<{ + id: string + deleted: boolean + object: "customer-group" + }>(`/admin/customer-groups/${id}`) +} + +async function batchAddCustomers( + id: string, + payload: { customer_ids: { id: string }[] } +) { + return postRequest( + `/admin/customer-groups/${id}/customers/batch/add`, + payload + ) +} + +async function batchRemoveCustomers( + id: string, + payload: { customer_ids: { id: string }[] } +) { + return postRequest( + `/admin/customer-groups/${id}/customers/batch/remove`, + payload + ) +} + export const customerGroups = { retrieve: retrieveCustomerGroup, list: listCustomerGroups, + create: createCustomerGroup, + update: updateCustomerGroup, + delete: deleteCustomerGroup, + addCustomers: batchAddCustomers, + removeCustomers: batchRemoveCustomers, } diff --git a/packages/admin-next/dashboard/src/providers/router-provider/v2.tsx b/packages/admin-next/dashboard/src/providers/router-provider/v2.tsx index 3908ac4ba3..c2ea4fc6c5 100644 --- a/packages/admin-next/dashboard/src/providers/router-provider/v2.tsx +++ b/packages/admin-next/dashboard/src/providers/router-provider/v2.tsx @@ -11,6 +11,7 @@ import { AdminProductCategoryResponse, SalesChannelDTO, UserDTO, + AdminCustomerGroupResponse, } from "@medusajs/types" import { Navigate, Outlet, RouteObject, useLocation } from "react-router-dom" import { ErrorBoundary } from "../../components/error/error-boundary" @@ -343,6 +344,55 @@ export const v2Routes: RouteObject[] = [ }, ], }, + { + path: "/customer-groups", + handle: { + crumb: () => "Customer Groups", + }, + children: [ + { + path: "", + lazy: () => + import("../../v2-routes/customer-groups/customer-group-list"), + children: [ + { + path: "create", + lazy: () => + import( + "../../v2-routes/customer-groups/customer-group-create" + ), + }, + ], + }, + { + path: ":id", + lazy: () => + import( + "../../v2-routes/customer-groups/customer-group-detail" + ), + handle: { + crumb: (data: AdminCustomerGroupResponse) => + data.customer_group.name, + }, + children: [ + { + path: "edit", + lazy: () => + import( + "../../v2-routes/customer-groups/customer-group-edit" + ), + }, + { + path: "add-customers", + lazy: () => + import( + "../../v2-routes/customer-groups/customer-group-add-customers" + ), + }, + ], + }, + ], + }, ], }, ], diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/components/add-customers-form/add-customers-form.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-add-customers/components/add-customers-form/add-customers-form.tsx similarity index 51% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/components/add-customers-form/add-customers-form.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-add-customers/components/add-customers-form/add-customers-form.tsx index 8c85f787e2..cb2234d4e5 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-add-customers/components/add-customers-form/add-customers-form.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-add-customers/components/add-customers-form/add-customers-form.tsx @@ -2,6 +2,7 @@ import { zodResolver } from "@hookform/resolvers/zod" import { Customer } from "@medusajs/medusa" import { Button, Checkbox, Hint, Table, Tooltip, clx } from "@medusajs/ui" import { + OnChangeFn, PaginationState, RowSelectionState, createColumnHelper, @@ -31,12 +32,19 @@ import { } from "../../../../../components/route-modal" import { useQueryParams } from "../../../../../hooks/use-query-params" import { queryClient } from "../../../../../lib/medusa" +import { useCustomers } from "../../../../../hooks/api/customers" +import { useAddCustomersToGroup } from "../../../../../hooks/api/customer-groups" +import { useDataTable } from "../../../../../hooks/use-data-table" +import { useCustomerTableFilters } from "../../../../../hooks/table/filters/use-customer-table-filters" +import { useCustomerTableQuery } from "../../../../../hooks/table/query/use-customer-table-query" +import { DataTable } from "../../../../../components/table/data-table" +import { AdminCustomerResponse } from "@medusajs/types" type AddCustomersFormProps = { customerGroupId: string } -const AddCustomersSchema = zod.object({ +export const AddCustomersSchema = zod.object({ customer_ids: zod.array(zod.string()).min(1), }) @@ -83,36 +91,47 @@ export const AddCustomersForm = ({ ) }, [rowSelection, setValue]) - const params = useQueryParams(["q"]) - const { customers, count, isLoading, isError, error } = useAdminCustomers({ - expand: "groups", - limit: PAGE_SIZE, - offset: pageIndex * PAGE_SIZE, - ...params, + const { searchParams, raw } = useCustomerTableQuery({ pageSize: PAGE_SIZE }) + const filters = useCustomerTableFilters() + + const { customers, count, isLoading, isError, error } = useCustomers({ + fields: "id,email,first_name,last_name,*groups", + ...searchParams, }) + const updater: OnChangeFn = (fn) => { + const state = typeof fn === "function" ? fn(rowSelection) : fn + + const ids = Object.keys(state) + + setValue("customer_ids", ids, { + shouldDirty: true, + shouldTouch: true, + }) + + setRowSelection(state) + } + const columns = useColumns() - const table = useReactTable({ + const { table } = useDataTable({ data: customers ?? [], columns, - pageCount: Math.ceil((count ?? 0) / PAGE_SIZE), - state: { - pagination, - rowSelection, + count, + enablePagination: true, + enableRowSelection: (row) => { + return !row.original.groups?.map((gc) => gc.id).includes(customerGroupId) }, getRowId: (row) => row.id, - onPaginationChange: setPagination, - onRowSelectionChange: setRowSelection, - getCoreRowModel: getCoreRowModel(), - manualPagination: true, - meta: { - customerGroupId, + pageSize: PAGE_SIZE, + rowSelection: { + state: rowSelection, + updater, }, }) const { mutateAsync, isLoading: isMutating } = - useAdminAddCustomersToCustomerGroup(customerGroupId) + useAddCustomersToGroup(customerGroupId) const handleSubmit = form.handleSubmit(async (data) => { await mutateAsync( @@ -121,18 +140,12 @@ export const AddCustomersForm = ({ }, { onSuccess: () => { - queryClient.invalidateQueries(adminCustomerKeys.lists()) handleSuccess(`/customer-groups/${customerGroupId}`) }, } ) }) - const noRecords = - !isLoading && - !customers?.length && - !Object.values(params).filter(Boolean).length - if (isError) { throw error } @@ -165,98 +178,32 @@ export const AddCustomersForm = ({ - - {noRecords ? ( -
- -
- ) : ( -
-
-
-
- -
-
-
- {(customers?.length || 0) > 0 ? ( - - - {table.getHeaderGroups().map((headerGroup) => { - return ( - - {headerGroup.headers.map((header) => { - return ( - - {flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ) - })} - - ) - })} - - - {table.getRowModel().rows.map((row) => ( - cg.id) - .includes(customerGroupId), - } - )} - > - {row.getVisibleCells().map((cell) => ( - - {flexRender( - cell.column.columnDef.cell, - cell.getContext() - )} - - ))} - - ))} - -
- ) : ( -
- -
- )} -
- -
- )} + + ) } -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const useColumns = () => { const { t } = useTranslation() @@ -279,21 +226,14 @@ const useColumns = () => { /> ) }, - cell: ({ row, table }) => { - const { customerGroupId } = table.options.meta as { - customerGroupId: string - } - - const isAdded = row.original.groups - ?.map((gc) => gc.id) - .includes(customerGroupId) - - const isSelected = row.getIsSelected() || isAdded + cell: ({ row }) => { + const isPreSelected = !row.getCanSelect() + const isSelected = row.getIsSelected() || isPreSelected const Component = ( row.toggleSelected(!!value)} onClick={(e) => { e.stopPropagation() @@ -301,7 +241,7 @@ const useColumns = () => { /> ) - if (isAdded) { + if (isPreSelected) { return ( { resolver: zodResolver(CreateCustomerGroupSchema), }) - const { mutateAsync, isLoading } = useAdminCreateCustomerGroup() + const { mutateAsync, isLoading } = useCreateCustomerGroup() const handleSubmit = form.handleSubmit(async (data) => { await mutateAsync( diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/components/create-customer-group-form/index.ts b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-create/components/create-customer-group-form/index.ts similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/components/create-customer-group-form/index.ts rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-create/components/create-customer-group-form/index.ts diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/customer-group-create.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-create/customer-group-create.tsx similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/customer-group-create.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-create/customer-group-create.tsx diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/index.ts b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-create/index.ts similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-create/index.ts rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-create/index.ts diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/components/customer-group-customer-section/customer-group-customer-section.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/components/customer-group-customer-section/customer-group-customer-section.tsx similarity index 79% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/components/customer-group-customer-section/customer-group-customer-section.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/components/customer-group-customer-section/customer-group-customer-section.tsx index e60004231d..4ebf1aa742 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/components/customer-group-customer-section/customer-group-customer-section.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/components/customer-group-customer-section/customer-group-customer-section.tsx @@ -1,23 +1,30 @@ -import { PencilSquare, Trash } from "@medusajs/icons" -import { Customer, CustomerGroup } from "@medusajs/medusa" import { Button, Checkbox, Container, Heading, usePrompt } from "@medusajs/ui" -import { createColumnHelper } from "@tanstack/react-table" +import { Customer } from "@medusajs/medusa" +import { PencilSquare, Trash } from "@medusajs/icons" import { + adminCustomerGroupKeys, + useAdminCustomPost, useAdminCustomerGroupCustomers, - useAdminRemoveCustomersFromCustomerGroup, } from "medusa-react" -import { useMemo } from "react" -import { useTranslation } from "react-i18next" -import { Link } from "react-router-dom" import { ActionMenu } from "../../../../../components/common/action-menu" import { DataTable } from "../../../../../components/table/data-table" +import { Link } from "react-router-dom" +import { RowSelectionState, createColumnHelper } from "@tanstack/react-table" import { useCustomerTableColumns } from "../../../../../hooks/table/columns/use-customer-table-columns" import { useCustomerTableFilters } from "../../../../../hooks/table/filters/use-customer-table-filters" import { useCustomerTableQuery } from "../../../../../hooks/table/query/use-customer-table-query" import { useDataTable } from "../../../../../hooks/use-data-table" +import { useMemo, useState } from "react" +import { useTranslation } from "react-i18next" +import { AdminCustomerGroupResponse, AdminCustomerResponse } from "@medusajs/types" +import { useCustomers } from "../../../../../hooks/api/customers" +import { + useRemoveCustomersFromGroup, + useUpdateCustomerGroup, +} from "../../../../../hooks/api/customer-groups" type CustomerGroupCustomerSectionProps = { - group: CustomerGroup + group: AdminCustomerGroupResponse["customer_group"] } const PAGE_SIZE = 10 @@ -25,22 +32,18 @@ const PAGE_SIZE = 10 export const CustomerGroupCustomerSection = ({ group, }: CustomerGroupCustomerSectionProps) => { + const [rowSelection, setRowSelection] = useState({}) const { t } = useTranslation() + const prompt = usePrompt() const { searchParams, raw } = useCustomerTableQuery({ pageSize: PAGE_SIZE }) - const { customers, count, isLoading, isError, error } = - useAdminCustomerGroupCustomers( - group.id, - { - ...searchParams, - }, - { - keepPreviousData: true, - } - ) + const { customers, count, isLoading, isError, error } = useCustomers({ + ...searchParams, + groups: group.id, + }) - const filters = useCustomerTableFilters(["groups"]) const columns = useColumns() + const filters = useCustomerTableFilters(["groups"]) const { table } = useDataTable({ data: customers ?? [], @@ -50,21 +53,28 @@ export const CustomerGroupCustomerSection = ({ enablePagination: true, enableRowSelection: true, pageSize: PAGE_SIZE, + rowSelection: { + state: rowSelection, + updater: setRowSelection, + }, meta: { customerGroupId: group.id, }, }) - const { mutateAsync } = useAdminRemoveCustomersFromCustomerGroup(group.id) - const prompt = usePrompt() + if (isError) { + throw error + } - const handleRemoveCustomers = async (selection: Record) => { - const selected = Object.keys(selection).filter((k) => selection[k]) + const { mutateAsync } = useRemoveCustomersFromGroup(group.id) + + const handleRemove = async () => { + const keys = Object.keys(rowSelection) const res = await prompt({ title: t("general.areYouSure"), description: t("customerGroups.removeCustomersWarning", { - count: selected.length, + count: keys.length, }), confirmText: t("actions.continue"), cancelText: t("actions.cancel"), @@ -74,13 +84,16 @@ export const CustomerGroupCustomerSection = ({ return } - await mutateAsync({ - customer_ids: selected.map((s) => ({ id: s })), - }) - } - - if (isError) { - throw error + await mutateAsync( + { + customer_ids: keys.map((k) => ({ id: k })), + }, + { + onSuccess: () => { + setRowSelection({}) + }, + } + ) } return ( @@ -111,14 +124,14 @@ export const CustomerGroupCustomerSection = ({ "created_at", "updated_at", ]} + queryObject={raw} commands={[ { - action: handleRemoveCustomers, + action: handleRemove, label: t("actions.remove"), shortcut: "r", }, ]} - queryObject={raw} /> ) @@ -128,12 +141,11 @@ const CustomerActions = ({ customer, customerGroupId, }: { - customer: Customer + customer: AdminCustomerResponse["customer"] customerGroupId: string }) => { const { t } = useTranslation() - const { mutateAsync } = - useAdminRemoveCustomersFromCustomerGroup(customerGroupId) + const { mutateAsync } = useRemoveCustomersFromGroup(customerGroupId) const prompt = usePrompt() @@ -182,7 +194,7 @@ const CustomerActions = ({ ) } -const columnHelper = createColumnHelper() +const columnHelper = createColumnHelper() const useColumns = () => { const columns = useCustomerTableColumns() diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/components/customer-group-customer-section/index.ts b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/components/customer-group-customer-section/index.ts similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/components/customer-group-customer-section/index.ts rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/components/customer-group-customer-section/index.ts diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/components/customer-group-general-section/customer-group-general-section.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/components/customer-group-general-section/customer-group-general-section.tsx similarity index 83% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/components/customer-group-general-section/customer-group-general-section.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/components/customer-group-general-section/customer-group-general-section.tsx index e86b466a67..7b1cbd8fe4 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/components/customer-group-general-section/customer-group-general-section.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/components/customer-group-general-section/customer-group-general-section.tsx @@ -1,13 +1,13 @@ import { PencilSquare, Trash } from "@medusajs/icons" -import type { CustomerGroup } from "@medusajs/medusa" import { Container, Heading } from "@medusajs/ui" -import { useAdminDeleteCustomerGroup } from "medusa-react" import { useTranslation } from "react-i18next" import { useNavigate } from "react-router-dom" import { ActionMenu } from "../../../../../components/common/action-menu" +import { AdminCustomerGroupResponse } from "@medusajs/types" +import { useDeleteCustomerGroup } from "../../../../../hooks/api/customer-groups" type CustomerGroupGeneralSectionProps = { - group: CustomerGroup + group: AdminCustomerGroupResponse["customer_group"] } export const CustomerGroupGeneralSection = ({ @@ -16,7 +16,7 @@ export const CustomerGroupGeneralSection = ({ const { t } = useTranslation() const navigate = useNavigate() - const { mutateAsync } = useAdminDeleteCustomerGroup(group.id) + const { mutateAsync } = useDeleteCustomerGroup(group.id) const handleDelete = async () => { await mutateAsync(undefined, { diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/components/customer-group-general-section/index.ts b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/components/customer-group-general-section/index.ts similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/components/customer-group-general-section/index.ts rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/components/customer-group-general-section/index.ts diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/customer-group-detail.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/customer-group-detail.tsx similarity index 87% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/customer-group-detail.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/customer-group-detail.tsx index 0d93790b5a..eebcbe7c54 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/customer-group-detail.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/customer-group-detail.tsx @@ -1,9 +1,9 @@ -import { useAdminCustomerGroup } from "medusa-react" import { Outlet, json, useLoaderData, useParams } from "react-router-dom" import { JsonViewSection } from "../../../components/common/json-view-section" import { CustomerGroupCustomerSection } from "./components/customer-group-customer-section" import { CustomerGroupGeneralSection } from "./components/customer-group-general-section" import { customerGroupLoader } from "./loader" +import { useCustomerGroup } from "../../../hooks/api/customer-groups" export const CustomerGroupDetail = () => { const initialData = useLoaderData() as Awaited< @@ -11,7 +11,7 @@ export const CustomerGroupDetail = () => { > const { id } = useParams() - const { customer_group, isLoading, isError, error } = useAdminCustomerGroup( + const { customer_group, isLoading, isError, error } = useCustomerGroup( id!, undefined, { initialData } diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/index.ts b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/index.ts similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/index.ts rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/index.ts diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/loader.ts b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/loader.ts similarity index 82% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/loader.ts rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/loader.ts index 1c8c2beb6b..a2beb15d28 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-detail/loader.ts +++ b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-detail/loader.ts @@ -1,8 +1,8 @@ -import { AdminCustomerGroupsRes } from "@medusajs/medusa" import { Response } from "@medusajs/medusa-js" import { adminProductKeys } from "medusa-react" import { LoaderFunctionArgs } from "react-router-dom" +import { AdminCustomerGroupResponse } from "@medusajs/types" import { medusa, queryClient } from "../../../lib/medusa" const customerGroupDetailQuery = (id: string) => ({ @@ -15,7 +15,7 @@ export const customerGroupLoader = async ({ params }: LoaderFunctionArgs) => { const query = customerGroupDetailQuery(id!) return ( - queryClient.getQueryData>( + queryClient.getQueryData>( query.queryKey ) ?? (await queryClient.fetchQuery(query)) ) diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/components/edit-customer-group-form/edit-customer-group-form.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-edit/components/edit-customer-group-form/edit-customer-group-form.tsx similarity index 87% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/components/edit-customer-group-form/edit-customer-group-form.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-edit/components/edit-customer-group-form/edit-customer-group-form.tsx index b1f2bb2a2e..4e75daccbe 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/components/edit-customer-group-form/edit-customer-group-form.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-edit/components/edit-customer-group-form/edit-customer-group-form.tsx @@ -1,5 +1,4 @@ import { zodResolver } from "@hookform/resolvers/zod" -import { CustomerGroup } from "@medusajs/medusa" import { Button, Input } from "@medusajs/ui" import { useAdminUpdateCustomerGroup } from "medusa-react" import { useForm } from "react-hook-form" @@ -10,12 +9,14 @@ import { RouteDrawer, useRouteModal, } from "../../../../../components/route-modal" +import { AdminCustomerGroupResponse } from "@medusajs/types" +import { useUpdateCustomerGroup } from "../../../../../hooks/api/customer-groups" type EditCustomerGroupFormProps = { - group: CustomerGroup + group: AdminCustomerGroupResponse["customer_group"] } -const EditCustomerGroupSchema = z.object({ +export const EditCustomerGroupSchema = z.object({ name: z.string().min(1), }) @@ -32,7 +33,7 @@ export const EditCustomerGroupForm = ({ resolver: zodResolver(EditCustomerGroupSchema), }) - const { mutateAsync, isLoading } = useAdminUpdateCustomerGroup(group.id) + const { mutateAsync, isLoading } = useUpdateCustomerGroup(group.id) const handleSubmit = form.handleSubmit(async (data) => { await mutateAsync(data, { diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/components/edit-customer-group-form/index.ts b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-edit/components/edit-customer-group-form/index.ts similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/components/edit-customer-group-form/index.ts rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-edit/components/edit-customer-group-form/index.ts diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/customer-group-edit.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-edit/customer-group-edit.tsx similarity index 82% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/customer-group-edit.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-edit/customer-group-edit.tsx index e07055a9b0..33d2114e26 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/customer-group-edit.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-edit/customer-group-edit.tsx @@ -1,15 +1,13 @@ import { Heading } from "@medusajs/ui" -import { useAdminCustomerGroup } from "medusa-react" import { useTranslation } from "react-i18next" import { useParams } from "react-router-dom" import { RouteDrawer } from "../../../components/route-modal" import { EditCustomerGroupForm } from "./components/edit-customer-group-form" +import { useCustomerGroup } from "../../../hooks/api/customer-groups" export const CustomerGroupEdit = () => { const { id } = useParams() - const { customer_group, isLoading, isError, error } = useAdminCustomerGroup( - id! - ) + const { customer_group, isLoading, isError, error } = useCustomerGroup(id!) const { t } = useTranslation() diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/index.ts b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-edit/index.ts similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-edit/index.ts rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-edit/index.ts diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx similarity index 87% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx index 3bd0d964df..f508209e87 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/customer-group-list-table.tsx @@ -1,5 +1,4 @@ import { Button, Container, Heading } from "@medusajs/ui" -import { useAdminCustomerGroups } from "medusa-react" import { useTranslation } from "react-i18next" import { Link } from "react-router-dom" import { DataTable } from "../../../../../components/table/data-table" @@ -7,6 +6,7 @@ import { useDataTable } from "../../../../../hooks/use-data-table" import { useCustomerGroupTableColumns } from "./use-customer-group-table-columns" import { useCustomerGroupTableFilters } from "./use-customer-group-table-filters" import { useCustomerGroupTableQuery } from "./use-customer-group-table-query" +import { useCustomerGroups } from "../../../../../hooks/api/customer-groups" const PAGE_SIZE = 20 @@ -17,16 +17,10 @@ export const CustomerGroupListTable = () => { pageSize: PAGE_SIZE, }) const { customer_groups, count, isLoading, isError, error } = - useAdminCustomerGroups( - { - ...searchParams, - expand: "customers", - fields: "id,name,customers,customers.id", - }, - { - keepPreviousData: true, - } - ) + useCustomerGroups({ + ...searchParams, + fields: "id,name,customers.id", + }) const filters = useCustomerGroupTableFilters() const columns = useCustomerGroupTableColumns() diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/index.ts b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/index.ts similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/index.ts rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/index.ts diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-columns.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-columns.tsx similarity index 82% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-columns.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-columns.tsx index 87b070b426..49c747a348 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-columns.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-columns.tsx @@ -1,13 +1,14 @@ import { PencilSquare, Trash } from "@medusajs/icons" -import { CustomerGroup } from "@medusajs/medusa" import { usePrompt } from "@medusajs/ui" import { createColumnHelper } from "@tanstack/react-table" -import { useAdminDeleteCustomerGroup } from "medusa-react" import { useMemo } from "react" import { useTranslation } from "react-i18next" import { ActionMenu } from "../../../../../components/common/action-menu" +import { AdminCustomerGroupResponse } from "@medusajs/types" +import { useDeleteCustomerGroup } from "../../../../../hooks/api/customer-groups" -const columnHelper = createColumnHelper() +const columnHelper = + createColumnHelper() export const useCustomerGroupTableColumns = () => { const { t } = useTranslation() @@ -35,11 +36,15 @@ export const useCustomerGroupTableColumns = () => { ) } -const CustomerGroupActions = ({ group }: { group: CustomerGroup }) => { +const CustomerGroupActions = ({ + group, +}: { + group: AdminCustomerGroupResponse["customer_group"] +}) => { const { t } = useTranslation() const prompt = usePrompt() - const { mutateAsync } = useAdminDeleteCustomerGroup(group.id) + const { mutateAsync } = useDeleteCustomerGroup(group.id) const handleDelete = async () => { const res = await prompt({ diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-filters.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-filters.tsx similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-filters.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-filters.tsx diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-query.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-query.tsx similarity index 85% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-query.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-query.tsx index 05c2275b69..2a714182d6 100644 --- a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-query.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-query.tsx @@ -1,4 +1,3 @@ -import { AdminGetCustomerGroupsParams } from "@medusajs/medusa" import { useQueryParams } from "../../../../../hooks/use-query-params" type UseCustomerGroupTableQueryProps = { @@ -17,7 +16,7 @@ export const useCustomerGroupTableQuery = ({ const { offset, created_at, updated_at, q, order } = queryObject - const searchParams: AdminGetCustomerGroupsParams = { + const searchParams = { limit: pageSize, offset: offset ? Number(offset) : 0, order, diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/customer-group-list.tsx b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/customer-group-list.tsx similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/customer-group-list.tsx rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/customer-group-list.tsx diff --git a/packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/index.ts b/packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/index.ts similarity index 100% rename from packages/admin-next/dashboard/src/routes/customer-groups/customer-group-list/index.ts rename to packages/admin-next/dashboard/src/v2-routes/customer-groups/customer-group-list/index.ts diff --git a/packages/admin-next/dashboard/src/v2-routes/customers/customer-create/components/create-customer-form/create-customer-form.tsx b/packages/admin-next/dashboard/src/v2-routes/customers/customer-create/components/create-customer-form/create-customer-form.tsx index 45f4b1001a..171e44294a 100644 --- a/packages/admin-next/dashboard/src/v2-routes/customers/customer-create/components/create-customer-form/create-customer-form.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customers/customer-create/components/create-customer-form/create-customer-form.tsx @@ -138,16 +138,6 @@ export const CreateCustomerForm = () => { }} /> -
-
- - {t("fields.password")} - - - {t("customers.passwordHint")} - -
-
diff --git a/packages/admin-next/dashboard/src/v2-routes/customers/customer-detail/components/customer-group-section/customer-group-section.tsx b/packages/admin-next/dashboard/src/v2-routes/customers/customer-detail/components/customer-group-section/customer-group-section.tsx index 57d27e77a5..2aa6c3a349 100644 --- a/packages/admin-next/dashboard/src/v2-routes/customers/customer-detail/components/customer-group-section/customer-group-section.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customers/customer-detail/components/customer-group-section/customer-group-section.tsx @@ -1,54 +1,90 @@ -// TODO: Should be added with Customer Groups UI +import { Customer, CustomerGroup } from "@medusajs/medusa" +import { Container, Heading } from "@medusajs/ui" +import { createColumnHelper } from "@tanstack/react-table" +import { useMemo } from "react" +import { useTranslation } from "react-i18next" +import { useCustomerGroups } from "../../../../../hooks/api/customer-groups" +import { + AdminCustomerGroupResponse, + AdminCustomerResponse, +} from "@medusajs/types" +import { DataTable } from "../../../../../components/table/data-table" +import { useDataTable } from "../../../../../hooks/use-data-table" +import { useCustomerGroupTableFilters } from "../../../../customer-groups/customer-group-list/components/customer-group-list-table/use-customer-group-table-filters" +import { t } from "i18next" -// import { Customer, CustomerGroup } from "@medusajs/medusa" -// import { Container, Heading } from "@medusajs/ui" -// import { createColumnHelper } from "@tanstack/react-table" -// import { useAdminCustomerGroups } from "medusa-react" -// import { useMemo } from "react" -// import { useTranslation } from "react-i18next" +type CustomerGroupSectionProps = { + customer: AdminCustomerResponse["customer"] +} -// // TODO: Continue working on this when there is a natural way to get customer groups related to a customer. -// type CustomerGroupSectionProps = { -// customer: Customer -// } +const PAGE_SIZE = 10 -// export const CustomerGroupSection = ({ -// customer, -// }: CustomerGroupSectionProps) => { -// const { customer_groups, isLoading, isError, error } = useAdminCustomerGroups( -// { -// id: customer.groups.map((g) => g.id).join(","), -// } -// ) +export const CustomerGroupSection = ({ + customer, +}: CustomerGroupSectionProps) => { + const { customer_groups, count, isLoading, isError, error } = + useCustomerGroups({ + customers: { id: customer.id }, + }) -// if (isError) { -// throw error -// } + const filters = useCustomerGroupTableFilters() + const columns = useColumns() -// return ( -// -//
-// Groups -//
-//
-// ) -// } + const { table } = useDataTable({ + data: customer_groups ?? [], + columns, + count, + getRowId: (row) => row.id, + enablePagination: true, + enableRowSelection: true, + pageSize: PAGE_SIZE, + }) -// const columnHelper = createColumnHelper() + if (isError) { + throw error + } -// const useColumns = () => { -// const { t } = useTranslation() + if (isError) { + throw error + } -// return useMemo( -// () => [ -// columnHelper.display({ -// id: "select", -// }), -// columnHelper.accessor("name", { -// header: t("fields.name"), -// cell: ({ getValue }) => getValue(), -// }), -// ], -// [t] -// ) -// } + return ( + +
+ {t("customerGroups.domain")} +
+ `/customer-groups/${row.id}`} + filters={filters} + search + pagination + orderBy={["name", "created_at", "updated_at"]} + /> +
+ ) +} + +const columnHelper = + createColumnHelper() + +const useColumns = () => { + const { t } = useTranslation() + + return useMemo( + () => [ + columnHelper.display({ + id: "select", + }), + columnHelper.accessor("name", { + header: t("fields.name"), + cell: ({ getValue }) => getValue(), + }), + ], + [t] + ) +} diff --git a/packages/admin-next/dashboard/src/v2-routes/customers/customer-detail/customer-detail.tsx b/packages/admin-next/dashboard/src/v2-routes/customers/customer-detail/customer-detail.tsx index c8b3f655e4..3e1c6b8d3c 100644 --- a/packages/admin-next/dashboard/src/v2-routes/customers/customer-detail/customer-detail.tsx +++ b/packages/admin-next/dashboard/src/v2-routes/customers/customer-detail/customer-detail.tsx @@ -3,6 +3,7 @@ import { CustomerGeneralSection } from "./components/customer-general-section" import { JsonViewSection } from "../../../components/common/json-view-section" import { customerLoader } from "./loader" import { useCustomer } from "../../../hooks/api/customers" +import { CustomerGroupSection } from "./components/customer-group-section" export const CustomerDetail = () => { const { id } = useParams() @@ -32,7 +33,7 @@ export const CustomerDetail = () => { {/* // TODO: re-add when order endpoints are added to api-v2 */} - {/* */} + diff --git a/packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/batch/route.ts b/packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/batch/add/route.ts similarity index 56% rename from packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/batch/route.ts rename to packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/batch/add/route.ts index 066fd3cabb..8f85a35c41 100644 --- a/packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/batch/route.ts +++ b/packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/batch/add/route.ts @@ -1,15 +1,19 @@ +import { createCustomerGroupCustomersWorkflow } from "@medusajs/core-flows" +import { AdminCustomerGroupResponse } from "@medusajs/types" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" import { AuthenticatedMedusaRequest, MedusaResponse, -} from "../../../../../../types/routing" - -import { AdminPostCustomerGroupsGroupCustomersBatchReq } from "../../../validators" -import { createCustomerGroupCustomersWorkflow } from "@medusajs/core-flows" +} from "../../../../../../../types/routing" +import { AdminPostCustomerGroupsGroupCustomersBatchReq } from "../../../../validators" export const POST = async ( // eslint-disable-next-line max-len req: AuthenticatedMedusaRequest, - res: MedusaResponse + res: MedusaResponse ) => { const { id } = req.params const { customer_ids } = req.validatedBody @@ -30,5 +34,15 @@ export const POST = async ( throw errors[0].error } - res.status(200).json({ customer_group_customers: result }) + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + + const queryObject = remoteQueryObjectFromString({ + entryPoint: "customer_group", + variables: { id }, + fields: req.remoteQueryConfig.fields, + }) + + const [customer_group] = await remoteQuery(queryObject) + + res.status(200).json({ customer_group }) } diff --git a/packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/remove/route.ts b/packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/batch/remove/route.ts similarity index 56% rename from packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/remove/route.ts rename to packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/batch/remove/route.ts index 529ccfbc62..c2e924ca9b 100644 --- a/packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/remove/route.ts +++ b/packages/medusa/src/api-v2/admin/customer-groups/[id]/customers/batch/remove/route.ts @@ -1,15 +1,19 @@ +import { deleteCustomerGroupCustomersWorkflow } from "@medusajs/core-flows" +import { AdminCustomerGroupResponse } from "@medusajs/types" +import { + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" import { AuthenticatedMedusaRequest, MedusaResponse, -} from "../../../../../../types/routing" - -import { AdminPostCustomerGroupsGroupCustomersBatchReq } from "../../../validators" -import { deleteCustomerGroupCustomersWorkflow } from "@medusajs/core-flows" +} from "../../../../../../../types/routing" +import { AdminPostCustomerGroupsGroupCustomersBatchReq } from "../../../../validators" export const POST = async ( // eslint-disable-next-line max-len req: AuthenticatedMedusaRequest, - res: MedusaResponse + res: MedusaResponse ) => { const { id } = req.params const { customer_ids } = req.validatedBody @@ -30,8 +34,15 @@ export const POST = async ( throw errors[0].error } - res.status(200).json({ - object: "customer_group_customers", - deleted: true, + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + + const queryObject = remoteQueryObjectFromString({ + entryPoint: "customer_group", + variables: { id }, + fields: req.remoteQueryConfig.fields, }) + + const [customer_group] = await remoteQuery(queryObject) + + res.status(200).json({ customer_group }) } diff --git a/packages/medusa/src/api-v2/admin/customer-groups/middlewares.ts b/packages/medusa/src/api-v2/admin/customer-groups/middlewares.ts index fbb8923f42..9540ed8ad2 100644 --- a/packages/medusa/src/api-v2/admin/customer-groups/middlewares.ts +++ b/packages/medusa/src/api-v2/admin/customer-groups/middlewares.ts @@ -1,5 +1,6 @@ import * as QueryConfig from "./query-config" +import { transformBody, transformQuery } from "../../../api/middlewares" import { AdminDeleteCustomerGroupsGroupCustomersBatchReq, AdminGetCustomerGroupsGroupCustomersParams, @@ -9,7 +10,6 @@ import { AdminPostCustomerGroupsGroupReq, AdminPostCustomerGroupsReq, } from "./validators" -import { transformBody, transformQuery } from "../../../api/middlewares" import { MiddlewareRoute } from "../../../loaders/helpers/routing/types" import { authenticate } from "../../../utils/authenticate-middleware" @@ -63,14 +63,24 @@ export const adminCustomerGroupRoutesMiddlewares: MiddlewareRoute[] = [ }, { method: ["POST"], - matcher: "/admin/customer-groups/:id/customers/batch", - middlewares: [transformBody(AdminPostCustomerGroupsGroupCustomersBatchReq)], + matcher: "/admin/customer-groups/:id/customers/batch/add", + middlewares: [ + transformBody(AdminPostCustomerGroupsGroupCustomersBatchReq), + transformQuery( + AdminGetCustomerGroupsGroupParams, + QueryConfig.retrieveTransformQueryConfig + ), + ], }, { method: ["POST"], - matcher: "/admin/customer-groups/:id/customers/remove", + matcher: "/admin/customer-groups/:id/customers/batch/remove", middlewares: [ transformBody(AdminDeleteCustomerGroupsGroupCustomersBatchReq), + transformQuery( + AdminGetCustomerGroupsGroupParams, + QueryConfig.retrieveTransformQueryConfig + ), ], }, ] diff --git a/packages/medusa/src/api-v2/admin/customer-groups/validators.ts b/packages/medusa/src/api-v2/admin/customer-groups/validators.ts index e318d6a38a..52eab3587d 100644 --- a/packages/medusa/src/api-v2/admin/customer-groups/validators.ts +++ b/packages/medusa/src/api-v2/admin/customer-groups/validators.ts @@ -1,14 +1,15 @@ -import { OperatorMap } from "@medusajs/types" -import { Transform, Type } from "class-transformer" +import { FindParams, extendedFindParamsMixin } from "../../../types/common" import { IsNotEmpty, IsOptional, IsString, ValidateNested, } from "class-validator" -import { FindParams, extendedFindParamsMixin } from "../../../types/common" -import { OperatorMapValidator } from "../../../types/validators/operator-map" +import { Transform, Type } from "class-transformer" + import { IsType } from "../../../utils" +import { OperatorMap } from "@medusajs/types" +import { OperatorMapValidator } from "../../../types/validators/operator-map" export class AdminGetCustomerGroupsGroupParams extends FindParams {} @@ -61,6 +62,10 @@ export class AdminGetCustomerGroupsParams extends extendedFindParamsMixin({ limit: 100, offset: 0, }) { + @IsOptional() + @IsString() + q?: string + @IsOptional() @IsString({ each: true }) id?: string | string[] @@ -120,6 +125,10 @@ export class AdminGetCustomerGroupsGroupCustomersParams extends extendedFindPara offset: 0, } ) { + @IsOptional() + @IsString() + q?: string + @IsOptional() @IsString({ each: true }) id?: string | string[] diff --git a/packages/medusa/src/api-v2/admin/customers/[id]/route.ts b/packages/medusa/src/api-v2/admin/customers/[id]/route.ts index d23787cd27..2054610cc6 100644 --- a/packages/medusa/src/api-v2/admin/customers/[id]/route.ts +++ b/packages/medusa/src/api-v2/admin/customers/[id]/route.ts @@ -2,12 +2,11 @@ import { deleteCustomersWorkflow, updateCustomersWorkflow, } from "@medusajs/core-flows" -import { ModuleRegistrationName } from "@medusajs/modules-sdk" +import { AdminCustomerResponse, CustomerUpdatableFields } from "@medusajs/types" import { - AdminCustomerResponse, - CustomerUpdatableFields, - ICustomerModuleService, -} from "@medusajs/types" + ContainerRegistrationKeys, + remoteQueryObjectFromString, +} from "@medusajs/utils" import { AuthenticatedMedusaRequest, MedusaResponse, @@ -17,24 +16,26 @@ export const GET = async ( req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const customerModuleService = req.scope.resolve( - ModuleRegistrationName.CUSTOMER - ) + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) - const customer = await customerModuleService.retrieve(req.params.id, { - select: req.retrieveConfig.select, - relations: req.retrieveConfig.relations, + const variables = { id: req.params.id } + + const queryObject = remoteQueryObjectFromString({ + entryPoint: "customer", + variables, + fields: req.remoteQueryConfig.fields, }) - res.status(200).json({ customer: customer as AdminCustomerResponse["customer"] }) + const [customer] = await remoteQuery(queryObject) + + res.status(200).json({ customer }) } export const POST = async ( req: AuthenticatedMedusaRequest, res: MedusaResponse ) => { - const updateCustomers = updateCustomersWorkflow(req.scope) - const { result, errors } = await updateCustomers.run({ + const { errors } = await updateCustomersWorkflow(req.scope).run({ input: { selector: { id: req.params.id }, update: req.validatedBody, @@ -46,7 +47,19 @@ export const POST = async ( throw errors[0].error } - res.status(200).json({ customer: result[0] as AdminCustomerResponse["customer"] }) + const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY) + + const queryObject = remoteQueryObjectFromString({ + entryPoint: "customer", + variables: { + filters: { id: req.params.id }, + }, + fields: req.remoteQueryConfig.fields, + }) + + const [customer] = await remoteQuery(queryObject) + + res.status(200).json({ customer }) } export const DELETE = async ( diff --git a/packages/medusa/src/api-v2/admin/customers/query-config.ts b/packages/medusa/src/api-v2/admin/customers/query-config.ts index 072f73a1e6..48960739a7 100644 --- a/packages/medusa/src/api-v2/admin/customers/query-config.ts +++ b/packages/medusa/src/api-v2/admin/customers/query-config.ts @@ -6,6 +6,7 @@ export const defaultAdminCustomerFields = [ "first_name", "last_name", "email", + "phone", "created_at", "updated_at", "deleted_at", diff --git a/packages/medusa/src/api-v2/admin/customers/validators.ts b/packages/medusa/src/api-v2/admin/customers/validators.ts index bff38273ce..871a3efd7a 100644 --- a/packages/medusa/src/api-v2/admin/customers/validators.ts +++ b/packages/medusa/src/api-v2/admin/customers/validators.ts @@ -24,11 +24,13 @@ export const AdminCustomersParams = createFindParams({ q: z.string().optional(), id: z.union([z.string(), z.array(z.string())]).optional(), email: z.union([z.string(), z.array(z.string())]).optional(), - groups: z.union([ - AdminCustomerGroupInCustomerParams, - z.string(), - z.array(z.string()), - ]).optional(), + groups: z + .union([ + AdminCustomerGroupInCustomerParams, + z.string(), + z.array(z.string()), + ]) + .optional(), company_name: z.union([z.string(), z.array(z.string())]).optional(), first_name: z.union([z.string(), z.array(z.string())]).optional(), last_name: z.union([z.string(), z.array(z.string())]).optional(), diff --git a/packages/types/src/http/customer/admin/customer.ts b/packages/types/src/http/customer/admin/customer.ts index aa7dfb6719..085abffe80 100644 --- a/packages/types/src/http/customer/admin/customer.ts +++ b/packages/types/src/http/customer/admin/customer.ts @@ -6,6 +6,7 @@ import { PaginatedResponse } from "../../../common" export interface CustomerGroupResponse { id: string name: string | null + customers: CustomerResponse[] } /**