UNPKG

seti-ramesesv1

Version:

Reusable components and context for Next.js apps

107 lines (104 loc) 9.21 kB
import { jsxs, jsx } from 'react/jsx-runtime'; import { Filter, ArrowUp, RefreshCcw, ChevronsLeft, ChevronLeft, ChevronRight, Search, Pencil, File, Trash, ChevronDown } from 'lucide-react'; import React__default, { useState, useEffect, useMemo } from 'react'; import styles from '../../styles/Datalist.module.css.js'; import { Select } from '../ui/Select.js'; import { Text } from '../ui/Text.js'; import { Tooltip } from '../ui/Tooltip.js'; import MoreMenu from './DatalistMoreMenu.js'; import { IconButton } from './IconButton.js'; const getNestedValue = (obj, path) => { return path.split(".").reduce((acc, part) => acc?.[part], obj); }; const DataList = ({ cols, hiddencols, sortcol, orderby, handler, limit = 20, openItem, hideToolbar = false, allowSearch = false, searchMode = "manual", onEdit, onView, onDelete, onMore, emptyState, renderExpandedRow, actionColumnWidth = 120, searchFields, }) => { const [items, setItems] = useState([]); const [searchText, setSearchText] = useState(""); const [expandedRowIndex, setExpandedRowIndex] = useState(null); const [start, setStart] = useState(0); const [filterColumn, setFilterColumn] = useState(""); const [filters, setFilters] = useState({}); const [appliedFilters, setAppliedFilters] = useState({}); const showActions = onView || onDelete || onEdit || (onMore?.length ?? 0) > 0; const doSearch = async (params) => { const query = { start: params._start ?? start, limit, searchtext: searchText, cols: cols ?? null, hiddencols: hiddencols ?? null, sortcol: sortcol ?? params.sortcol ?? null, orderby: orderby ?? null, filters: params.filters ?? appliedFilters, searchfields: searchFields ?? undefined, }; const results = await handler(query); setItems(results ?? []); }; useEffect(() => { doSearch({ _start: 0 }); }, []); useEffect(() => { if (searchMode === "auto") { const timeout = setTimeout(() => { doSearch({ _start: start }); }, 300); return () => clearTimeout(timeout); } }, [searchText, appliedFilters, start, searchMode]); const uniqueFilterValues = useMemo(() => { const values = []; if (filterColumn) { for (const item of items) { // const val = item[filterColumn]; const val = getNestedValue(item, filterColumn); if (val && !values.includes(val)) values.push(val); } } return values; }, [filterColumn, items]); const displayedItems = items.slice(0, limit); const hasNext = items.length > limit; return (jsxs("div", { className: styles.datalistContainer, children: [jsxs("div", { style: { visibility: hideToolbar ? "hidden" : "visible", marginTop: hideToolbar ? "-50px" : "" }, className: styles.toolbar, children: [jsxs("div", { className: styles.leftControls, children: [jsx(Select, { label: "Filter", value: filterColumn, onChange: setFilterColumn, options: cols.map((c) => ({ id: c.name, value: c.name, title: c.title })) }), filterColumn && (jsx(Select, { label: "Value", value: filters[filterColumn] || "", onChange: (val) => setFilters((prev) => ({ ...prev, [filterColumn]: val })), options: uniqueFilterValues.map((v) => ({ id: v, value: v, title: v })) })), jsx(Tooltip, { content: "Apply Filters", children: jsx(IconButton, { icon: jsx(Filter, { size: 16 }), onClick: () => { const updated = { ...filters }; setAppliedFilters(updated); doSearch({ _start: 0, filters: updated }); } }) }), Object.keys(appliedFilters).length > 0 && (jsx(Tooltip, { content: "Clear Filters", children: jsx(IconButton, { icon: jsx(ArrowUp, { size: 16 }), onClick: () => { setFilters({}); setAppliedFilters({}); setFilterColumn(""); doSearch({ _start: 0, filters: {} }); } }) })), jsx(Tooltip, { content: "Refresh", children: jsx(IconButton, { icon: jsx(RefreshCcw, { size: 16 }), onClick: () => doSearch({ _start: start }) }) })] }), jsxs("div", { className: styles.rightControls, children: [jsx(IconButton, { icon: jsx(ChevronsLeft, { size: 16 }), onClick: () => { setStart(0); doSearch({ _start: 0 }); // ✅ reset start }, disabled: start === 0 }), jsx(IconButton, { icon: jsx(ChevronLeft, { size: 16 }), onClick: () => { const prevStart = Math.max(0, start - limit); setStart(prevStart); doSearch({ _start: prevStart }); // ✅ pass updated start }, disabled: start === 0 }), jsx(IconButton, { icon: jsx(ChevronRight, { size: 16 }), onClick: () => { const nextStart = start + limit; console.log(nextStart); setStart(nextStart); doSearch({ _start: nextStart }); }, disabled: !hasNext }), allowSearch && (jsx("div", { className: styles.inlineControl, children: jsx(Text, { label: "Search", value: searchText, onChange: (e) => setSearchText(e.target.value), onKeyDown: (e) => { if (searchMode === "manual" && e.key === "Enter") { e.preventDefault(); doSearch({ _start: 0 }); } }, endIcon: searchMode === "manual" ? jsx(Search, { size: 16 }) : undefined, onEndIconClick: searchMode === "manual" ? () => doSearch({ _start: 0 }) : undefined }) }))] })] }), jsx("div", { className: styles.datalistScroll, children: jsxs("table", { className: styles.datalistTable, children: [jsx("thead", { children: jsxs("tr", { children: [cols.map((col) => (jsx("th", { style: { width: col.width, textAlign: (["left", "right", "center", "justify", "start", "end"].includes(col.alignment || "") ? col.alignment : "left"), }, children: col.title }, col.name))), showActions && jsx("th", { style: { width: actionColumnWidth, textAlign: "center" }, children: "Actions" }), renderExpandedRow && jsx("th", {})] }) }), jsx("tbody", { children: displayedItems.length === 0 ? (jsx("tr", { children: jsxs("td", { colSpan: cols.length + 2, style: { textAlign: "center", padding: "2rem" }, children: [jsx("p", { children: jsx("strong", { children: emptyState?.title ?? "No Data" }) }), jsx("p", { children: emptyState?.message ?? "Try adjusting filters or search." })] }) })) : (displayedItems.map((item, idx) => { const isExpanded = expandedRowIndex === idx; return (jsxs(React__default.Fragment, { children: [jsxs("tr", { className: styles.hoverableRow, onClick: () => openItem?.(item), style: { cursor: openItem ? "pointer" : undefined }, children: [cols.map((col) => ( // <td key={col.name}>{item[col.name] ?? ""}</td> jsx("td", { children: getNestedValue(item, col.name) ?? "" }, col.name))), showActions && (jsx("td", { children: jsxs("div", { className: styles.actionButtons, children: [onEdit && (jsx(IconButton, { icon: jsx(Pencil, { size: 12, color: "#3bd930" }), onClick: () => onEdit(item) })), onView && (jsx(IconButton, { icon: jsx(File, { size: 12, color: "#5452ff" }), onClick: () => onView(item) })), onDelete && (jsx(IconButton, { icon: jsx(Trash, { size: 12, color: "#ff4242" }), onClick: () => onDelete(item) })), onMore && jsx(MoreMenu, { actions: onMore, item: item })] }) })), renderExpandedRow && (jsx("td", { children: jsx(IconButton, { icon: isExpanded ? jsx(ChevronDown, { size: 16 }) : jsx(ChevronLeft, { size: 16 }), onClick: (e) => { e.stopPropagation(); setExpandedRowIndex(isExpanded ? null : idx); } }) }))] }), renderExpandedRow && isExpanded && (jsx("tr", { className: styles.expandedRow, children: jsx("td", { colSpan: cols.length + (showActions ? 1 : 0), children: jsx("div", { className: styles.expandedContent, children: renderExpandedRow(item) }) }) }))] }, idx)); })) })] }) })] })); }; export { DataList as default }; //# sourceMappingURL=Datalist.js.map