refactor: users domain (#7070)

**What**
- refactor users domain to use `DataTable`
- add search params to `User` module models
This commit is contained in:
Frane Polić
2024-04-16 16:09:07 +00:00
committed by GitHub
parent a7df6235f9
commit 122b3ea76b
10 changed files with 97 additions and 88 deletions
@@ -1,7 +1,7 @@
import { AdminGetSalesChannelsParams } from "@medusajs/medusa"
import { useQueryParams } from "../../use-query-params"
type UseCustomerTableQueryProps = {
type UseSalesChannelTableQueryProps = {
prefix?: string
pageSize?: number
}
@@ -9,7 +9,7 @@ type UseCustomerTableQueryProps = {
export const useSalesChannelTableQuery = ({
prefix,
pageSize = 20,
}: UseCustomerTableQueryProps) => {
}: UseSalesChannelTableQueryProps) => {
const queryObject = useQueryParams(
["offset", "q", "order", "created_at", "updated_at"],
prefix
@@ -0,0 +1,32 @@
import { useQueryParams } from "../../use-query-params"
type UseUserInviteTableQueryProps = {
prefix?: string
pageSize?: number
}
export const useUserInviteTableQuery = ({
prefix,
pageSize = 20,
}: UseUserInviteTableQueryProps) => {
const queryObject = useQueryParams(
["offset", "q", "order", "created_at", "updated_at"],
prefix
)
const { offset, created_at, updated_at, q, order } = 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,
}
}
@@ -8,7 +8,12 @@ export const UserDetail = () => {
const initialData = useLoaderData() as Awaited<ReturnType<typeof userLoader>>
const { id } = useParams()
const { user, isLoading, isError, error } = useUser(id!, undefined, {
const {
user,
isPending: isLoading,
isError,
error,
} = useUser(id!, undefined, {
initialData,
})
@@ -8,7 +8,7 @@ import { EditUserForm } from "./components/edit-user-form"
export const UserEdit = () => {
const { t } = useTranslation()
const { id } = useParams()
const { user, isLoading, isError, error } = useUser(id!)
const { user, isPending: isLoading, isError, error } = useUser(id!)
if (isError) {
throw error
@@ -7,28 +7,19 @@ import {
Heading,
Input,
StatusBadge,
Table,
Text,
Tooltip,
clx,
usePrompt,
} from "@medusajs/ui"
import {
createColumnHelper,
flexRender,
getCoreRowModel,
getPaginationRowModel,
useReactTable,
} from "@tanstack/react-table"
import { createColumnHelper } from "@tanstack/react-table"
import { format } from "date-fns"
import { useMemo } from "react"
import { useForm } from "react-hook-form"
import { Trans, useTranslation } from "react-i18next"
import * as zod from "zod"
import { ActionMenu } from "../../../../../components/common/action-menu"
import { NoRecords } from "../../../../../components/common/empty-table-content"
import { useDataTable } from "../../../../../hooks/use-data-table"
import { Form } from "../../../../../components/common/form"
import { LocalizedTablePagination } from "../../../../../components/localization/localized-table-pagination"
import { RouteFocusModal } from "../../../../../components/route-modal"
import {
useCreateInvite,
@@ -36,12 +27,15 @@ import {
useInvites,
useResendInvite,
} from "../../../../../hooks/api/invites"
import { DataTable } from "../../../../../components/table/data-table"
import { useUserInviteTableQuery } from "../../../../../hooks/table/query/use-user-invite-table-query"
const InviteUserSchema = zod.object({
email: zod.string().email(),
})
const PAGE_SIZE = 10
const PREFIX = "usr_invite"
export const InviteUserForm = () => {
const { t } = useTranslation()
@@ -53,20 +47,28 @@ export const InviteUserForm = () => {
resolver: zodResolver(InviteUserSchema),
})
const { invites, isLoading, isError, error } = useInvites()
const count = invites?.length ?? 0
const { raw, searchParams } = useUserInviteTableQuery({
prefix: PREFIX,
pageSize: PAGE_SIZE,
})
const noRecords = !isLoading && count === 0
const {
invites,
count,
isPending: isLoading,
isError,
error,
} = useInvites(searchParams)
const columns = useColumns()
const table = useReactTable({
// TODO: Update type when medusa-react is 2.0 compatible
data: (invites ?? []) as unknown as InviteDTO[],
const { table } = useDataTable({
data: (invites ?? []) as InviteDTO[],
columns,
pageCount: Math.ceil(count / PAGE_SIZE),
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
count,
enablePagination: true,
getRowId: (row) => row.id,
pageSize: PAGE_SIZE,
})
const { mutateAsync, isPending } = useCreateInvite()
@@ -136,68 +138,18 @@ export const InviteUserForm = () => {
<div className="flex flex-col gap-y-4">
<Heading level="h2">{t("users.pendingInvites")}</Heading>
<Container className="overflow-hidden p-0">
{!noRecords ? (
<div>
<Table>
<Table.Header className="border-t-0">
{table.getHeaderGroups().map((headerGroup) => {
return (
<Table.Row
key={headerGroup.id}
className="[&_th:last-of-type]:w-[1%] [&_th:last-of-type]:whitespace-nowrap [&_th]:w-1/3"
>
{headerGroup.headers.map((header) => {
return (
<Table.HeaderCell key={header.id}>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</Table.HeaderCell>
)
})}
</Table.Row>
)
})}
</Table.Header>
<Table.Body>
{table.getRowModel().rows.map((row) => (
<Table.Row
key={row.id}
className={clx(
"transition-fg[&_td:last-of-type]:w-[1%] [&_td:last-of-type]:whitespace-nowrap",
{
"bg-ui-bg-highlight hover:bg-ui-bg-highlight-hover":
row.getIsSelected(),
}
)}
>
{row.getVisibleCells().map((cell) => (
<Table.Cell key={cell.id}>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)}
</Table.Cell>
))}
</Table.Row>
))}
</Table.Body>
</Table>
<LocalizedTablePagination
canNextPage={table.getCanNextPage()}
canPreviousPage={table.getCanPreviousPage()}
nextPage={table.nextPage}
previousPage={table.previousPage}
count={count}
pageIndex={table.getState().pagination.pageIndex}
pageCount={table.getPageCount()}
pageSize={PAGE_SIZE}
/>
</div>
) : (
<NoRecords className="h-[200px]" />
)}
<DataTable
table={table}
columns={columns}
count={count}
pageSize={PAGE_SIZE}
prefix={PREFIX}
pagination
search
isLoading={isLoading}
queryObject={raw}
orderBy={["email", "created_at", "updated_at"]}
/>
</Container>
</div>
</div>
@@ -14,7 +14,13 @@ export const UserListTable = () => {
const { raw, searchParams } = useUserTableQuery({
pageSize: PAGE_SIZE,
})
const { users, count, isLoading, isError, error } = useUsers(searchParams, {
const {
users,
count,
isPending: isLoading,
isError,
error,
} = useUsers(searchParams, {
placeholderData: keepPreviousData,
})
@@ -70,6 +70,13 @@ export class AdminGetInvitesParams extends extendedFindParamsMixin({
@IsOptional()
@IsString()
fields?: string
/**
* The term to search invites emails.
*/
@IsString()
@IsOptional()
q?: string
}
export class AdminCreateInviteRequest {
@@ -20,6 +20,7 @@ export const AdminGetUsersParams = createFindParams({
email: z.string().optional(),
first_name: z.string().optional(),
last_name: z.string().optional(),
q: z.string().optional(),
})
)
+2
View File
@@ -14,6 +14,7 @@ import {
DALUtils,
createPsqlIndexStatementHelper,
generateEntityId,
Searchable,
} from "@medusajs/utils"
const inviteEmailIndexName = "IDX_invite_email"
@@ -57,6 +58,7 @@ export default class Invite {
name: inviteEmailIndexName,
expression: inviteEmailIndexStatement,
})
@Searchable()
@Property({ columnType: "text" })
email: string
+5 -1
View File
@@ -14,6 +14,7 @@ import {
DALUtils,
createPsqlIndexStatementHelper,
generateEntityId,
Searchable,
} from "@medusajs/utils"
const userEmailIndexName = "IDX_user_email"
@@ -47,17 +48,20 @@ export default class User {
@PrimaryKey({ columnType: "text" })
id!: string
@Searchable()
@Property({ columnType: "text", nullable: true })
first_name: string | null = null
@Searchable()
@Property({ columnType: "text", nullable: true })
last_name: string | null = null
@Property({ columnType: "text" })
@Index({
name: userEmailIndexName,
expression: userEmailIndexStatement,
})
@Searchable()
@Property({ columnType: "text" })
email: string
@Property({ columnType: "text", nullable: true })