feat(ui,dashboard): Migrate SC tables to DataTable (#11106)
This commit is contained in:
committed by
GitHub
parent
d588073cea
commit
fcd3e2226e
@@ -0,0 +1,35 @@
|
||||
import { clx } from "@medusajs/ui"
|
||||
import { PropsWithChildren } from "react"
|
||||
|
||||
type DataTableStatusCellProps = PropsWithChildren<{
|
||||
color?: "green" | "red" | "blue" | "orange" | "grey" | "purple"
|
||||
}>
|
||||
|
||||
export const DataTableStatusCell = ({
|
||||
color,
|
||||
children,
|
||||
}: DataTableStatusCellProps) => {
|
||||
return (
|
||||
<div className="txt-compact-small text-ui-fg-subtle flex h-full w-full items-center gap-x-2 overflow-hidden">
|
||||
<div
|
||||
role="presentation"
|
||||
className="flex h-5 w-2 items-center justify-center"
|
||||
>
|
||||
<div
|
||||
className={clx(
|
||||
"h-2 w-2 rounded-sm shadow-[0px_0px_0px_1px_rgba(0,0,0,0.12)_inset]",
|
||||
{
|
||||
"bg-ui-tag-neutral-icon": color === "grey",
|
||||
"bg-ui-tag-green-icon": color === "green",
|
||||
"bg-ui-tag-red-icon": color === "red",
|
||||
"bg-ui-tag-blue-icon": color === "blue",
|
||||
"bg-ui-tag-orange-icon": color === "orange",
|
||||
"bg-ui-tag-purple-icon": color === "purple",
|
||||
}
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<span className="truncate">{children}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,15 +1,18 @@
|
||||
import {
|
||||
Button,
|
||||
clx,
|
||||
DataTableColumnDef,
|
||||
DataTableCommand,
|
||||
DataTableEmptyStateProps,
|
||||
DataTableFilter,
|
||||
DataTableFilteringState,
|
||||
DataTablePaginationState,
|
||||
DataTableRow,
|
||||
DataTableRowSelectionState,
|
||||
DataTableSortingState,
|
||||
Heading,
|
||||
DataTable as Primitive,
|
||||
Text,
|
||||
useDataTable,
|
||||
} from "@medusajs/ui"
|
||||
import React, { ReactNode, useCallback, useState } from "react"
|
||||
@@ -66,14 +69,17 @@ interface DataTableProps<TData> {
|
||||
autoFocusSearch?: boolean
|
||||
rowHref?: (row: TData) => string
|
||||
emptyState?: DataTableEmptyStateProps
|
||||
heading: string
|
||||
heading?: string
|
||||
subHeading?: string
|
||||
prefix?: string
|
||||
pageSize?: number
|
||||
isLoading?: boolean
|
||||
rowSelection?: {
|
||||
state: DataTableRowSelectionState
|
||||
onRowSelectionChange: (value: DataTableRowSelectionState) => void
|
||||
enableRowSelection?: boolean | ((row: DataTableRow<TData>) => boolean)
|
||||
}
|
||||
layout?: "fill" | "auto"
|
||||
}
|
||||
|
||||
export const DataTable = <TData,>({
|
||||
@@ -90,11 +96,13 @@ export const DataTable = <TData,>({
|
||||
autoFocusSearch = false,
|
||||
rowHref,
|
||||
heading,
|
||||
subHeading,
|
||||
prefix,
|
||||
pageSize = 10,
|
||||
emptyState,
|
||||
rowSelection,
|
||||
isLoading = false,
|
||||
layout = "auto",
|
||||
}: DataTableProps<TData>) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@@ -258,14 +266,30 @@ export const DataTable = <TData,>({
|
||||
isLoading,
|
||||
})
|
||||
|
||||
const shouldRenderHeading = heading || subHeading
|
||||
|
||||
return (
|
||||
<Primitive instance={instance}>
|
||||
<Primitive
|
||||
instance={instance}
|
||||
className={clx({
|
||||
"h-full [&_tr]:last-of-type:!border-b": layout === "fill",
|
||||
})}
|
||||
>
|
||||
<Primitive.Toolbar
|
||||
className="flex flex-col items-start justify-between gap-2 md:flex-row md:items-center"
|
||||
translations={toolbarTranslations}
|
||||
>
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<Heading>{heading}</Heading>
|
||||
<div className="flex w-full items-center justify-between gap-2">
|
||||
{shouldRenderHeading && (
|
||||
<div>
|
||||
{heading && <Heading>{heading}</Heading>}
|
||||
{subHeading && (
|
||||
<Text size="small" className="text-ui-fg-subtle">
|
||||
{subHeading}
|
||||
</Text>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center justify-end gap-x-2 md:hidden">
|
||||
{enableFiltering && (
|
||||
<Primitive.FilterMenu tooltip={t("filters.filterLabel")} />
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import {
|
||||
createDataTableColumnHelper,
|
||||
DataTableColumnDef,
|
||||
Tooltip,
|
||||
} from "@medusajs/ui"
|
||||
import { useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { useDate } from "../../../../hooks/use-date"
|
||||
|
||||
type EntityWithDates = {
|
||||
created_at: string
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
const columnHelper = createDataTableColumnHelper<EntityWithDates>()
|
||||
|
||||
export const useDataTableDateColumns = <TData extends EntityWithDates>() => {
|
||||
const { t } = useTranslation()
|
||||
const { getFullDate } = useDate()
|
||||
|
||||
return useMemo(() => {
|
||||
return [
|
||||
columnHelper.accessor("created_at", {
|
||||
header: t("fields.createdAt"),
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<Tooltip
|
||||
content={getFullDate({
|
||||
date: row.original.created_at,
|
||||
includeTime: true,
|
||||
})}
|
||||
>
|
||||
<span>{getFullDate({ date: row.original.created_at })}</span>
|
||||
</Tooltip>
|
||||
)
|
||||
},
|
||||
enableSorting: true,
|
||||
sortAscLabel: t("filters.sorting.dateAsc"),
|
||||
sortDescLabel: t("filters.sorting.dateDesc"),
|
||||
}),
|
||||
columnHelper.accessor("updated_at", {
|
||||
header: t("fields.updatedAt"),
|
||||
cell: ({ row }) => {
|
||||
return (
|
||||
<Tooltip
|
||||
content={getFullDate({
|
||||
date: row.original.updated_at,
|
||||
includeTime: true,
|
||||
})}
|
||||
>
|
||||
<span>{getFullDate({ date: row.original.updated_at })}</span>
|
||||
</Tooltip>
|
||||
)
|
||||
},
|
||||
enableSorting: true,
|
||||
sortAscLabel: t("filters.sorting.dateAsc"),
|
||||
sortDescLabel: t("filters.sorting.dateDesc"),
|
||||
}),
|
||||
] as DataTableColumnDef<TData>[]
|
||||
}, [t, getFullDate])
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./use-sales-channel-table-columns"
|
||||
export * from "./use-sales-channel-table-empty-state"
|
||||
export * from "./use-sales-channel-table-filters"
|
||||
export * from "./use-sales-channel-table-query"
|
||||
@@ -0,0 +1,61 @@
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import { createDataTableColumnHelper, Tooltip } from "@medusajs/ui"
|
||||
import { DataTableStatusCell } from "../../components/data-table-status-cell/data-table-status-cell"
|
||||
import { useDataTableDateColumns } from "../general/use-data-table-date-columns"
|
||||
|
||||
const columnHelper = createDataTableColumnHelper<HttpTypes.AdminSalesChannel>()
|
||||
|
||||
export const useSalesChannelTableColumns = () => {
|
||||
const { t } = useTranslation()
|
||||
const dateColumns = useDataTableDateColumns<HttpTypes.AdminSalesChannel>()
|
||||
|
||||
return useMemo(
|
||||
() => [
|
||||
columnHelper.accessor("name", {
|
||||
header: () => t("fields.name"),
|
||||
enableSorting: true,
|
||||
sortLabel: t("fields.name"),
|
||||
sortAscLabel: t("filters.sorting.alphabeticallyAsc"),
|
||||
sortDescLabel: t("filters.sorting.alphabeticallyDesc"),
|
||||
}),
|
||||
columnHelper.accessor("description", {
|
||||
header: () => t("fields.description"),
|
||||
cell: ({ getValue }) => {
|
||||
return (
|
||||
<Tooltip content={getValue()}>
|
||||
<div className="flex h-full w-full items-center overflow-hidden">
|
||||
<span className="truncate">{getValue()}</span>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)
|
||||
},
|
||||
enableSorting: true,
|
||||
sortLabel: t("fields.description"),
|
||||
sortAscLabel: t("filters.sorting.alphabeticallyAsc"),
|
||||
sortDescLabel: t("filters.sorting.alphabeticallyDesc"),
|
||||
maxSize: 250,
|
||||
minSize: 100,
|
||||
}),
|
||||
columnHelper.accessor("is_disabled", {
|
||||
header: () => t("fields.status"),
|
||||
enableSorting: true,
|
||||
sortLabel: t("fields.status"),
|
||||
sortAscLabel: t("filters.sorting.alphabeticallyAsc"),
|
||||
sortDescLabel: t("filters.sorting.alphabeticallyDesc"),
|
||||
cell: ({ getValue }) => {
|
||||
const value = getValue()
|
||||
return (
|
||||
<DataTableStatusCell color={value ? "grey" : "green"}>
|
||||
{value ? t("general.disabled") : t("general.enabled")}
|
||||
</DataTableStatusCell>
|
||||
)
|
||||
},
|
||||
}),
|
||||
...dateColumns,
|
||||
],
|
||||
[t, dateColumns]
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { DataTableEmptyStateProps } from "@medusajs/ui"
|
||||
import { useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
export const useSalesChannelTableEmptyState = (): DataTableEmptyStateProps => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
return useMemo(() => {
|
||||
const content: DataTableEmptyStateProps = {
|
||||
empty: {
|
||||
heading: t("salesChannels.list.empty.heading"),
|
||||
description: t("salesChannels.list.empty.description"),
|
||||
},
|
||||
filtered: {
|
||||
heading: t("salesChannels.list.filtered.heading"),
|
||||
description: t("salesChannels.list.filtered.description"),
|
||||
},
|
||||
}
|
||||
|
||||
return content
|
||||
}, [t])
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { createDataTableFilterHelper } from "@medusajs/ui"
|
||||
import { useMemo } from "react"
|
||||
import { useTranslation } from "react-i18next"
|
||||
import { useDataTableDateFilters } from "../general/use-data-table-date-filters"
|
||||
|
||||
const filterHelper = createDataTableFilterHelper<HttpTypes.AdminSalesChannel>()
|
||||
|
||||
export const useSalesChannelTableFilters = () => {
|
||||
const { t } = useTranslation()
|
||||
const dateFilters = useDataTableDateFilters()
|
||||
|
||||
return useMemo(
|
||||
() => [
|
||||
filterHelper.accessor("is_disabled", {
|
||||
label: t("fields.status"),
|
||||
type: "radio",
|
||||
options: [
|
||||
{
|
||||
label: t("general.enabled"),
|
||||
value: "false",
|
||||
},
|
||||
{
|
||||
label: t("general.disabled"),
|
||||
value: "true",
|
||||
},
|
||||
],
|
||||
}),
|
||||
...dateFilters,
|
||||
],
|
||||
[dateFilters, t]
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import { HttpTypes } from "@medusajs/types"
|
||||
import { useQueryParams } from "../../../../hooks/use-query-params"
|
||||
|
||||
type UseSalesChannelTableQueryProps = {
|
||||
prefix?: string
|
||||
pageSize?: number
|
||||
}
|
||||
|
||||
export const useSalesChannelTableQuery = ({
|
||||
prefix,
|
||||
pageSize = 20,
|
||||
}: UseSalesChannelTableQueryProps) => {
|
||||
const queryObject = useQueryParams(
|
||||
["offset", "q", "order", "created_at", "updated_at", "is_disabled"],
|
||||
prefix
|
||||
)
|
||||
|
||||
const { offset, created_at, updated_at, is_disabled, ...rest } = queryObject
|
||||
|
||||
const searchParams: HttpTypes.AdminSalesChannelListParams = {
|
||||
limit: pageSize,
|
||||
offset: offset ? Number(offset) : 0,
|
||||
created_at: created_at ? JSON.parse(created_at) : undefined,
|
||||
updated_at: updated_at ? JSON.parse(updated_at) : undefined,
|
||||
is_disabled: is_disabled ? JSON.parse(is_disabled) : undefined,
|
||||
...rest,
|
||||
}
|
||||
|
||||
return searchParams
|
||||
}
|
||||
Reference in New Issue
Block a user