UNPKG

@premieroctet/next-admin

Version:

Next-Admin provides a customizable and turnkey admin dashboard for applications built with Next.js and powered by the Prisma ORM. It aims to simplify the development process by providing a turnkey admin system that can be easily integrated into your proje

297 lines (296 loc) 15.2 kB
"use client"; import { jsx, jsxs } from "react/jsx-runtime"; import { EllipsisVerticalIcon, TrashIcon } from "@heroicons/react/24/outline"; import external_clsx_default from "clsx"; import external_lodash_debounce_default from "lodash.debounce"; import { useEffect, useMemo, useOptimistic, useState, useTransition } from "react"; import { twMerge } from "tailwind-merge"; import { ITEMS_PER_PAGE } from "../config.mjs"; import ClientActionDialogContext_mjs_default from "../context/ClientActionDialogContext.mjs"; import { useConfig } from "../context/ConfigContext.mjs"; import { useI18n } from "../context/I18nContext.mjs"; import useDataColumns_mjs_default from "../hooks/useDataColumns.mjs"; import { useDeleteAction } from "../hooks/useDeleteAction.mjs"; import { useRouterInternal } from "../hooks/useRouterInternal.mjs"; import { reorderData, slugify } from "../utils/tools.mjs"; import external_ActionDropdownItem_mjs_default from "./ActionDropdownItem.mjs"; import { DataTable } from "./DataTable.mjs"; import external_Filters_mjs_default from "./Filters.mjs"; import external_ListHeader_mjs_default from "./ListHeader.mjs"; import { Message } from "./Message.mjs"; import { Pagination } from "./Pagination.mjs"; import external_TableRowsIndicator_mjs_default from "./TableRowsIndicator.mjs"; import Button_mjs_default from "./radix/Button.mjs"; import Checkbox_mjs_default from "./radix/Checkbox.mjs"; import { Dropdown, DropdownBody, DropdownContent, DropdownItem, DropdownTrigger } from "./radix/Dropdown.mjs"; import { Select, SelectContent, SelectItem, SelectTrigger } from "./radix/Select.mjs"; const itemsPerPageSizes = [ 10, 25, 50, 100 ]; function List({ resource, data, total, actions, resourcesIdProperty, title, icon, schema, clientActionsComponents, rawData, listFilterOptions }) { const { router, query } = useRouterInternal(); const [isPending, startTransition] = useTransition(); const [_orderPending, startOrderTransition] = useTransition(); const { options, apiBasePath } = useConfig(); const [rowSelection, setRowSelection] = useState({}); const pageIndex = "string" == typeof query.page ? Number(query.page) - 1 : 0; const modelDefaultListSize = options?.model?.[resource]?.list?.defaultListSize; const pageSize = Number(query.itemsPerPage) || modelDefaultListSize || ITEMS_PER_PAGE; const modelOptions = options?.["model"]?.[resource]; const sortColumn = modelOptions?.list?.orderField ? void 0 : query.sortColumn; const sortDirection = modelOptions?.list?.orderField ? void 0 : query.sortDirection; const { deleteItems } = useDeleteAction(resource); const { t } = useI18n(); const columns = useDataColumns_mjs_default({ data, resource, sortable: !modelOptions?.list?.orderField, resourcesIdProperty, sortColumn, sortDirection, rawData }); const allListSizes = useMemo(()=>{ if (modelDefaultListSize) return [ ...itemsPerPageSizes, modelDefaultListSize ].sort((a, b)=>a - b); return itemsPerPageSizes; }, [ modelDefaultListSize ]); let onSearchChange; const [optimisticData, optimisticOrderData] = useOptimistic(data, (prevData, newData)=>{ if (!modelOptions?.list?.orderField) return prevData; return newData; }); const hasDeletePermission = !modelOptions?.permissions || modelOptions?.permissions?.includes("delete"); if (!(modelOptions?.list?.search && modelOptions?.list?.search?.length === 0)) onSearchChange = external_lodash_debounce_default((e)=>{ startTransition(()=>{ router?.push({ pathname: location.pathname, query: { ...query, search: e.target.value } }); }); }, 300); const checkboxColumn = { id: "__nextadmin-select-row", header: ({ table })=>{ if (0 === table.getRowModel().rows.length) return null; return /*#__PURE__*/ jsx("div", { className: "px-1", children: /*#__PURE__*/ jsx(Checkbox_mjs_default, { checked: table.getIsAllRowsSelected(), indeterminate: table.getIsSomeRowsSelected(), onChange: table.getToggleAllRowsSelectedHandler() }) }); }, cell: ({ row })=>/*#__PURE__*/ jsx("div", { className: "px-1", children: /*#__PURE__*/ jsx(Checkbox_mjs_default, { checked: row.getIsSelected(), indeterminate: row.getIsSomeSelected(), onChange: row.getToggleSelectedHandler(), disabled: !row.getCanSelect(), onClick: (e)=>e.stopPropagation() }) }) }; const actionsColumn = { id: "__nextadmin-actions", header: ()=>null, cell: ({ row })=>{ const idProperty = resourcesIdProperty[resource]; if (!hasDeletePermission) return; return /*#__PURE__*/ jsxs(Dropdown, { children: [ /*#__PURE__*/ jsx(DropdownTrigger, { asChild: true, children: /*#__PURE__*/ jsx(Button_mjs_default, { variant: "ghost", size: "sm", className: "hover:bg-nextadmin-background-emphasis !px-2 py-2", children: /*#__PURE__*/ jsx(EllipsisVerticalIcon, { className: "text-nextadmin-content-default dark:text-dark-nextadmin-content-default h-6 w-6" }) }) }), /*#__PURE__*/ jsx(DropdownBody, { children: /*#__PURE__*/ jsxs(DropdownContent, { side: "left", align: "start", sideOffset: 5, className: "z-50 space-y-1.5 px-2 py-2", children: [ actions?.map((action)=>/*#__PURE__*/ jsx(external_ActionDropdownItem_mjs_default, { action: action, resourceIds: [ row.original[idProperty].value ], resource: resource }, action.id)), /*#__PURE__*/ jsxs(DropdownItem, { className: twMerge(external_clsx_default("flex cursor-pointer items-center gap-2 rounded-md px-2 py-1 text-red-700 hover:bg-red-50 dark:text-red-400")), onClick: (evt)=>{ evt.stopPropagation(); deleteItems([ row.original[idProperty].value ]); }, children: [ /*#__PURE__*/ jsx(TrashIcon, { className: "h-5 w-5" }), t("list.row.actions.delete.label") ] }) ] }) }) ] }); } }; useEffect(()=>{ setRowSelection({}); }, [ data ]); const getSelectedRowsIds = ()=>{ const indices = Object.keys(rowSelection); const selectedRows = data.filter((_, index)=>indices.includes(index.toString())); const idField = resourcesIdProperty[resource]; return selectedRows.map((row)=>row[idField].value); }; const handleOrderChange = modelOptions?.list?.orderField ? (value)=>{ startOrderTransition(async ()=>{ const idField = resourcesIdProperty[resource]; const newData = reorderData(optimisticData, value.currentId, value.moveOverId, modelOptions?.list?.orderField, idField); optimisticOrderData(newData); await fetch(`${apiBasePath}/${slugify(resource)}/order`, { method: "POST", body: JSON.stringify(optimisticData) }); router.refresh(); }); } : void 0; return /*#__PURE__*/ jsx(ClientActionDialogContext_mjs_default, { componentsMap: clientActionsComponents, children: /*#__PURE__*/ jsxs("div", { className: "flow-root h-full", children: [ /*#__PURE__*/ jsx(external_ListHeader_mjs_default, { title: title, icon: icon, resource: resource, search: query.search || "", onSearchChange: onSearchChange, isPending: isPending, selectedRows: rowSelection, actions: actions, getSelectedRowsIds: getSelectedRowsIds, onDelete: ()=>deleteItems(getSelectedRowsIds()), totalCount: total, schema: schema }), /*#__PURE__*/ jsxs("div", { className: "bg-nextadmin-background-default dark:bg-dark-nextadmin-background-default max-w-full p-4 align-middle sm:p-8", children: [ /*#__PURE__*/ jsxs("div", { className: "-mt-2 mb-2 space-y-4 sm:-mt-4 sm:mb-4", children: [ /*#__PURE__*/ jsx(Message, {}), /*#__PURE__*/ jsx(external_Filters_mjs_default, { filters: listFilterOptions }) ] }), /*#__PURE__*/ jsx(DataTable, { resource: resource, data: optimisticData, columns: [ checkboxColumn, ...columns, actionsColumn ], resourcesIdProperty: resourcesIdProperty, rowSelection: rowSelection, setRowSelection: setRowSelection, icon: icon, onOrderChange: handleOrderChange, orderField: modelOptions?.list?.orderField }), optimisticData.length ? /*#__PURE__*/ jsxs("div", { className: "flex flex-1 flex-wrap items-center justify-between gap-2 py-4", children: [ /*#__PURE__*/ jsx("div", { children: /*#__PURE__*/ jsx(external_TableRowsIndicator_mjs_default, { pageIndex: pageIndex, totalRows: total, currentPageIndex: pageIndex, pageSize: pageSize }) }), /*#__PURE__*/ jsxs("div", { className: "flex flex-1 items-center justify-end gap-y-2 space-x-4", children: [ /*#__PURE__*/ jsxs(Select, { onValueChange: (value)=>{ if (isNaN(Number(value))) return; router?.push({ pathname: location.pathname, query: { ...query, page: 1, itemsPerPage: value } }); }, children: [ /*#__PURE__*/ jsx(SelectTrigger, { className: "bg-nextadmin-background-default dark:bg-dark-nextadmin-background-subtle max-h-[36px] max-w-[100px]", children: /*#__PURE__*/ jsx("span", { className: "text-nextadmin-content-inverted dark:text-dark-nextadmin-content-inverted pointer-events-none", children: pageSize }) }), /*#__PURE__*/ jsx(SelectContent, { children: allListSizes.map((size)=>/*#__PURE__*/ jsx(SelectItem, { value: size.toString(), children: size }, size)) }) ] }), /*#__PURE__*/ jsx(Pagination, { currentPageIndex: pageIndex, totalPageCount: Math.ceil(total / pageSize), onPageChange: (pageIndex)=>{ router?.push({ pathname: location.pathname, query: { ...query, page: pageIndex + 1 } }); } }) ] }) ] }) : null ] }) ] }) }); } const components_List = List; export { components_List as default };