The PR for the Products section is growing quite large, so I would like to merge this PR that contains a lot of the ground work before moving onto finalizing the rest of the domain. **Note** Since the PR contains changes to the core, that the dashboard depends on, the staging env will not work. To preview this PR, you will need to run it locally. ## `@medusajs/medusa` **What** - Adds missing query params to `GET /admin/products/:id/variants` - `options.values` has been added to the default relations of admin product endpoints. ## `medusa-react` **What** - Adds missing hook for `GET /admin/products/:id/variants` ## `@medusajs/dashboard` - Adds base implementation for `DataGrid` component (formerly `BulkEditor`) (WIP) - Adds `/products` overview page - Adds partial `/products/create` page for creating new products (WIP - need to go over design w/ Ludvig before continuing) - Adds `/products/:id` details page - Adds `/products/:id/gallery` page for inspecting a products images in fullscreen. - Adds `/products/:id/edit` page for editing the general information of a product - Adds `/products/:id/attributes` page for editing the attributes information of a product - Adds `/products/:id/sales-channels` page for editing which sales channels a product is available in - Fixes a bug in `DataTable` where a table with two fixed columns would not display correctly For the review its not important to test the DataGrid, as it is still WIP, and I need to go through some minor changes to the behaviour with Ludvig, as virtualizing it adds some constraints. ## `@medusajs/icons` **What** - Pulls latest icons from Figma ## TODO in next PR - [ ] Fix the typing of POST /admin/products/:id as it is currently not possible to delete any of the nullable fields once they have been added. Be aware of this when reviewing this PR. - [ ] Wrap up `/products/create` page - [ ] Add `/products/:id/media` page for managing media associated with the product. - [ ] Add `/products/id/options` for managing product options (need Ludvig to rethink this as the current API is very limited and we can implement the current design as is.) - [ ] Add `/products/:id/variants/:id` page for editing a variant. (Possibly concat all of these into one BulkEditor page?)
124 lines
3.1 KiB
TypeScript
124 lines
3.1 KiB
TypeScript
import {
|
|
ColumnDef,
|
|
OnChangeFn,
|
|
PaginationState,
|
|
Row,
|
|
RowSelectionState,
|
|
getCoreRowModel,
|
|
getPaginationRowModel,
|
|
useReactTable,
|
|
} from "@tanstack/react-table"
|
|
import { useEffect, useMemo, useState } from "react"
|
|
import { useSearchParams } from "react-router-dom"
|
|
|
|
type UseDataTableProps<TData> = {
|
|
data?: TData[]
|
|
columns: ColumnDef<TData, any>[]
|
|
count?: number
|
|
pageSize?: number
|
|
enableRowSelection?: boolean | ((row: Row<TData>) => boolean)
|
|
rowSelection?: {
|
|
state: RowSelectionState
|
|
updater: OnChangeFn<RowSelectionState>
|
|
}
|
|
enablePagination?: boolean
|
|
getRowId?: (original: TData, index: number) => string
|
|
meta?: Record<string, unknown>
|
|
prefix?: string
|
|
}
|
|
|
|
export const useDataTable = <TData,>({
|
|
data = [],
|
|
columns,
|
|
count = 0,
|
|
pageSize: _pageSize = 20,
|
|
enablePagination = true,
|
|
enableRowSelection = false,
|
|
rowSelection: _rowSelection,
|
|
getRowId,
|
|
meta,
|
|
prefix,
|
|
}: UseDataTableProps<TData>) => {
|
|
const [searchParams, setSearchParams] = useSearchParams()
|
|
const offsetKey = `${prefix ? `${prefix}_` : ""}offset`
|
|
const offset = searchParams.get(offsetKey)
|
|
|
|
const [{ pageIndex, pageSize }, setPagination] = useState<PaginationState>({
|
|
pageIndex: offset ? Math.ceil(Number(offset) / _pageSize) : 0,
|
|
pageSize: _pageSize,
|
|
})
|
|
const pagination = useMemo(
|
|
() => ({
|
|
pageIndex,
|
|
pageSize,
|
|
}),
|
|
[pageIndex, pageSize]
|
|
)
|
|
const [localRowSelection, setLocalRowSelection] = useState({})
|
|
const rowSelection = _rowSelection?.state ?? localRowSelection
|
|
const setRowSelection = _rowSelection?.updater ?? setLocalRowSelection
|
|
|
|
useEffect(() => {
|
|
if (!enablePagination) {
|
|
return
|
|
}
|
|
|
|
const index = offset ? Math.ceil(Number(offset) / _pageSize) : 0
|
|
|
|
if (index === pageIndex) {
|
|
return
|
|
}
|
|
|
|
setPagination((prev) => ({
|
|
...prev,
|
|
pageIndex: index,
|
|
}))
|
|
}, [offset, enablePagination, _pageSize, pageIndex])
|
|
|
|
const onPaginationChange = (
|
|
updater: (old: PaginationState) => PaginationState
|
|
) => {
|
|
const state = updater(pagination)
|
|
const { pageIndex, pageSize } = state
|
|
|
|
setSearchParams((prev) => {
|
|
if (!pageIndex) {
|
|
prev.delete(offsetKey)
|
|
return prev
|
|
}
|
|
|
|
const newSearch = new URLSearchParams(prev)
|
|
newSearch.set(offsetKey, String(pageIndex * pageSize))
|
|
|
|
return newSearch
|
|
})
|
|
|
|
setPagination(state)
|
|
return state
|
|
}
|
|
|
|
const table = useReactTable({
|
|
data,
|
|
columns,
|
|
state: {
|
|
rowSelection: rowSelection, // We always pass a selection state to the table even if it's not enabled
|
|
pagination: enablePagination ? pagination : undefined,
|
|
},
|
|
pageCount: Math.ceil((count ?? 0) / pageSize),
|
|
enableRowSelection,
|
|
getRowId,
|
|
onRowSelectionChange: enableRowSelection ? setRowSelection : undefined,
|
|
onPaginationChange: enablePagination
|
|
? (onPaginationChange as OnChangeFn<PaginationState>)
|
|
: undefined,
|
|
getCoreRowModel: getCoreRowModel(),
|
|
getPaginationRowModel: enablePagination
|
|
? getPaginationRowModel()
|
|
: undefined,
|
|
manualPagination: enablePagination ? true : undefined,
|
|
meta,
|
|
})
|
|
|
|
return { table }
|
|
}
|