Skip to content

Commit bf6e4b3

Browse files
authored
Merge pull request #19 from Jing27540/pr-76
The pr looks good for me. We only update two files, another changes is made by the pr-76.
2 parents 810423c + a1670dc commit bf6e4b3

File tree

10 files changed

+463
-134
lines changed

10 files changed

+463
-134
lines changed

public/assets/icons/copy-temp.png

2.99 KB
Loading
5.23 KB
Loading

public/assets/icons/edit-temp.png

4.29 KB
Loading
6.2 KB
Loading

src/components/Table/Table.tsx

Lines changed: 134 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,18 @@ import {
88
getSortedRowModel,
99
SortingState,
1010
useReactTable,
11+
ExpandedState,
12+
getExpandedRowModel,
1113
} from "@tanstack/react-table";
1214
import React, { useEffect, useMemo, useRef, useState } from "react";
1315
import { Col, Container, Row, Table as BTable } from "react-bootstrap";
16+
import { BsChevronRight, BsChevronDown } from "react-icons/bs";
1417
import ColumnFilter from "./ColumnFilter";
1518
import GlobalFilter from "./GlobalFilter";
1619
import Pagination from "./Pagination";
1720
import RowSelectCheckBox from "./RowSelectCheckBox";
1821
import { FaSearch } from "react-icons/fa";
1922

20-
/**
21-
* @author Ankur Mundra on May, 2023
22-
*/
23-
2423
interface TableProps {
2524
data: Record<string, any>[];
2625
columns: ColumnDef<any, any>[];
@@ -30,6 +29,9 @@ interface TableProps {
3029
tableSize?: { span: number; offset: number };
3130
columnVisibility?: Record<string, boolean>;
3231
onSelectionChange?: (selectedData: Record<any, any>[]) => void;
32+
renderSubComponent?: (props: { row: any }) => React.ReactNode;
33+
getRowCanExpand?: (row: any) => boolean;
34+
disableGlobalFilter?: boolean; // Disable the Global Search
3335
}
3436

3537
const Table: React.FC<TableProps> = ({
@@ -41,89 +43,104 @@ const Table: React.FC<TableProps> = ({
4143
onSelectionChange,
4244
columnVisibility = {},
4345
tableSize = { span: 12, offset: 0 },
46+
renderSubComponent,
47+
getRowCanExpand,
48+
disableGlobalFilter = false, // // Disable the Global Search
4449
}) => {
45-
const colsPlusSelectable = useMemo(() => {
46-
const selectableColumn: any = {
47-
id: "select",
48-
header: ({ table }: any) => {
49-
return (
50-
<RowSelectCheckBox
51-
{...{
52-
checked: table.getIsAllRowsSelected(),
53-
indeterminate: table.getIsSomeRowsSelected(),
54-
onChange: table.getToggleAllRowsSelectedHandler(),
55-
}}
56-
/>
57-
);
58-
},
59-
cell: ({ row }: any) => {
60-
return (
61-
<RowSelectCheckBox
62-
{...{
63-
checked: row.getIsSelected(),
64-
disabled: !row.getCanSelect(),
65-
indeterminate: row.getIsSomeSelected(),
66-
onChange: row.getToggleSelectedHandler(),
67-
}}
68-
/>
69-
);
70-
},
71-
enableSorting: false,
72-
enableFilter: false,
73-
};
74-
return [selectableColumn, ...columns];
75-
}, [columns]);
76-
7750
const [rowSelection, setRowSelection] = useState({});
7851
const [sorting, setSorting] = useState<SortingState>([]);
7952
const [globalFilter, setGlobalFilter] = useState<string | number>("");
8053
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
8154
const [columnVisibilityState, setColumnVisibilityState] = useState(columnVisibility);
82-
const [isGlobalFilterVisible, setIsGlobalFilterVisible] = useState(showGlobalFilter); // State for global filter visibility
55+
const [isGlobalFilterVisible, setIsGlobalFilterVisible] = useState(showGlobalFilter);
56+
const [expanded, setExpanded] = useState<ExpandedState>({});
8357

8458
const selectable = typeof onSelectionChange === "function";
8559
const onSelectionChangeRef = useRef<any>(onSelectionChange);
8660

61+
const colsPlusExpander = useMemo(() => {
62+
if (!renderSubComponent) return columns;
63+
64+
const expanderColumn: ColumnDef<any, any> = {
65+
id: "expander",
66+
header: () => null,
67+
cell: ({ row }) => {
68+
if (getRowCanExpand ? !getRowCanExpand(row) : false) {
69+
return null;
70+
}
71+
return (
72+
<button
73+
className="btn btn-link p-0"
74+
onClick={(e) => {
75+
e.stopPropagation();
76+
row.toggleExpanded();
77+
}}
78+
>
79+
{row.getIsExpanded() ? <BsChevronDown /> : <BsChevronRight />}
80+
</button>
81+
);
82+
},
83+
enableSorting: false,
84+
enableColumnFilter: false,
85+
};
86+
87+
const selectableColumn = selectable
88+
? [
89+
{
90+
id: "select",
91+
header: ({ table }: any) => (
92+
<RowSelectCheckBox
93+
{...{
94+
checked: table.getIsAllRowsSelected(),
95+
indeterminate: table.getIsSomeRowsSelected(),
96+
onChange: table.getToggleAllRowsSelectedHandler(),
97+
}}
98+
/>
99+
),
100+
cell: ({ row }: any) => (
101+
<RowSelectCheckBox
102+
{...{
103+
checked: row.getIsSelected(),
104+
disabled: !row.getCanSelect(),
105+
indeterminate: row.getIsSomeSelected(),
106+
onChange: row.getToggleSelectedHandler(),
107+
}}
108+
/>
109+
),
110+
enableSorting: false,
111+
enableFilter: false,
112+
},
113+
]
114+
: [];
115+
116+
return [...selectableColumn, expanderColumn, ...columns];
117+
}, [columns, selectable, renderSubComponent, getRowCanExpand]);
118+
87119
const table = useReactTable({
88120
data: initialData,
89-
columns: selectable ? colsPlusSelectable : columns,
121+
columns: colsPlusExpander,
90122
state: {
91123
sorting,
92124
globalFilter,
93125
columnFilters,
94126
rowSelection,
95127
columnVisibility: columnVisibilityState,
128+
expanded,
96129
},
97130
onSortingChange: setSorting,
98131
onRowSelectionChange: setRowSelection,
99132
onGlobalFilterChange: setGlobalFilter,
100133
onColumnFiltersChange: setColumnFilters,
101134
onColumnVisibilityChange: setColumnVisibilityState,
135+
onExpandedChange: setExpanded,
136+
getRowCanExpand,
102137
getCoreRowModel: getCoreRowModel(),
103138
getSortedRowModel: getSortedRowModel(),
104139
getFilteredRowModel: getFilteredRowModel(),
105140
getPaginationRowModel: getPaginationRowModel(),
141+
getExpandedRowModel: getExpandedRowModel(),
106142
});
107143

108-
const {
109-
getState,
110-
getHeaderGroups,
111-
getRowModel,
112-
getCanNextPage,
113-
getCanPreviousPage,
114-
previousPage,
115-
nextPage,
116-
setPageIndex,
117-
setPageSize,
118-
getPageCount,
119-
} = table;
120-
121-
// Used to return early from useEffect() on mount.
122-
const firstRenderRef = useRef(true);
123-
// This useEffect() watches flatRows such that on change it
124-
// calls the onSelectionChange() prop. Technically, it calls
125-
// the onSelectionChangeRef.current function if it exists.
126-
127144
const flatRows = table.getSelectedRowModel().flatRows;
128145

129146
useEffect(() => {
@@ -144,6 +161,8 @@ const Table: React.FC<TableProps> = ({
144161
setIsGlobalFilterVisible(!isGlobalFilterVisible);
145162
};
146163

164+
const firstRenderRef = useRef(true);
165+
147166
return (
148167
<>
149168
<Container>
@@ -153,75 +172,80 @@ const Table: React.FC<TableProps> = ({
153172
<GlobalFilter filterValue={globalFilter} setFilterValue={setGlobalFilter} />
154173
)}
155174
</Col>
156-
<span style={{ marginLeft: "5px" }} onClick={toggleGlobalFilter}>
157-
<FaSearch style={{ cursor: "pointer" }} />
158-
{isGlobalFilterVisible ? " Hide" : " Show"}
159-
</span>{" "}
175+
{!disableGlobalFilter && (
176+
<span style={{ marginLeft: "5px" }} onClick={toggleGlobalFilter}>
177+
<FaSearch style={{ cursor: "pointer" }} />
178+
{isGlobalFilterVisible ? " Hide" : " Show"}
179+
</span>
180+
)}
160181
</Row>
161182
</Container>
162183
<Container>
163184
<Row>
164185
<Col md={tableSize}>
165186
<BTable striped hover responsive size="sm">
166187
<thead className="table-secondary">
167-
{getHeaderGroups().map((headerGroup) => (
188+
{table.getHeaderGroups().map((headerGroup) => (
168189
<tr key={headerGroup.id}>
169-
{headerGroup.headers.map((header) => {
170-
return (
171-
<th key={header.id} colSpan={header.colSpan}>
172-
{header.isPlaceholder ? null : (
173-
<>
174-
<div
175-
{...{
176-
className: header.column.getCanSort()
177-
? "cursor-pointer select-none"
178-
: "",
179-
onClick: header.column.getToggleSortingHandler(),
180-
}}
181-
>
182-
{flexRender(header.column.columnDef.header, header.getContext())}
183-
{{
184-
asc: " 🔼",
185-
desc: " 🔽",
186-
}[header.column.getIsSorted() as string] ?? null}
187-
</div>
188-
{showColumnFilter && header.column.getCanFilter() ? (
189-
<ColumnFilter column={header.column} />
190-
) : null}
191-
</>
192-
)}
193-
</th>
194-
);
195-
})}
190+
{headerGroup.headers.map((header) => (
191+
<th key={header.id} colSpan={header.colSpan}>
192+
{header.isPlaceholder ? null : (
193+
<>
194+
<div
195+
{...{
196+
className: header.column.getCanSort()
197+
? "cursor-pointer select-none"
198+
: "",
199+
onClick: header.column.getToggleSortingHandler(),
200+
}}
201+
>
202+
{flexRender(header.column.columnDef.header, header.getContext())}
203+
{{
204+
asc: " 🔼",
205+
desc: " 🔽",
206+
}[header.column.getIsSorted() as string] ?? null}
207+
</div>
208+
{showColumnFilter && header.column.getCanFilter() ? (
209+
<ColumnFilter column={header.column} />
210+
) : null}
211+
</>
212+
)}
213+
</th>
214+
))}
196215
</tr>
197216
))}
198217
</thead>
199218
<tbody>
200-
{getRowModel().rows.map((row) => {
201-
return (
202-
<tr key={row.id}>
203-
{row.getVisibleCells().map((cell) => {
204-
return (
205-
<td key={cell.id}>
206-
{flexRender(cell.column.columnDef.cell, cell.getContext())}
207-
</td>
208-
);
209-
})}
219+
{table.getRowModel().rows.map((row) => (
220+
<React.Fragment key={row.id}>
221+
<tr>
222+
{row.getVisibleCells().map((cell) => (
223+
<td key={cell.id}>
224+
{flexRender(cell.column.columnDef.cell, cell.getContext())}
225+
</td>
226+
))}
210227
</tr>
211-
);
212-
})}
228+
{row.getIsExpanded() && renderSubComponent && (
229+
<tr>
230+
<td colSpan={row.getVisibleCells().length}>
231+
{renderSubComponent({ row })}
232+
</td>
233+
</tr>
234+
)}
235+
</React.Fragment>
236+
))}
213237
</tbody>
214238
</BTable>
215239
{showPagination && (
216240
<Pagination
217-
nextPage={nextPage}
218-
previousPage={previousPage}
219-
canNextPage={getCanNextPage}
220-
canPreviousPage={getCanPreviousPage}
221-
setPageIndex={setPageIndex}
222-
setPageSize={setPageSize}
223-
getPageCount={getPageCount}
224-
getState={getState}
241+
nextPage={table.nextPage}
242+
previousPage={table.previousPage}
243+
canNextPage={table.getCanNextPage}
244+
canPreviousPage={table.getCanPreviousPage}
245+
setPageIndex={table.setPageIndex}
246+
setPageSize={table.setPageSize}
247+
getPageCount={table.getPageCount}
248+
getState={table.getState}
225249
/>
226250
)}
227251
</Col>
@@ -231,4 +255,4 @@ const Table: React.FC<TableProps> = ({
231255
);
232256
};
233257

234-
export default Table;
258+
export default Table;

0 commit comments

Comments
 (0)