Skip to content

Commit 12c1be6

Browse files
committed
remove useSorting from task analysis table and task review table and make new compatible header
1 parent ad5d5bc commit 12c1be6

3 files changed

Lines changed: 129 additions & 51 deletions

File tree

src/components/TableShared/EnhancedTable.jsx

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,115 @@ export const renderTableHeader = (headerGroups) => {
159159
);
160160
};
161161

162+
163+
export const renderTableHeaderWithSorting = (headerGroups, props = {}) => {
164+
const updateCriteria = props.updateCriteria || props.updateReviewTasks;
165+
const currentCriteria = props.criteria || props.reviewCriteria;
166+
const currentSort = currentCriteria?.sortCriteria;
167+
168+
return (
169+
<>
170+
{headerGroups.map((headerGroup, index) => (
171+
<tr {...headerGroup.getHeaderGroupProps()} key={`header-row-${headerGroup.id || index}`}>
172+
{headerGroup.headers.map((column) => {
173+
const headerProps = column.getHeaderProps();
174+
175+
// Make sure to prevent click event conflicts
176+
const onHeaderClick = (e) => {
177+
if (!column.disableSortBy) {
178+
179+
if (!updateCriteria) return;
180+
181+
const currentSort = currentCriteria?.sortCriteria;
182+
let newSortCriteria;
183+
const columnId = column.id;
184+
if (!currentSort || currentSort.sortBy !== columnId) {
185+
newSortCriteria = { sortBy: columnId, direction: "ASC" };
186+
} else if (currentSort.direction === "ASC") {
187+
newSortCriteria = { sortBy: columnId, direction: "DESC" };
188+
} else {
189+
newSortCriteria = { sortBy: "name", direction: "DESC" };
190+
}
191+
192+
updateCriteria({ sortCriteria: newSortCriteria });
193+
}
194+
};
195+
196+
return (
197+
<th
198+
key={`header-cell-${column.id}`}
199+
className={`${headerStyles} ${!column.disableSortBy ? sortableHeaderStyles : ""}`}
200+
{...headerProps}
201+
onClick={onHeaderClick}
202+
style={{
203+
...headerProps.style,
204+
width: column.width,
205+
minWidth: column.minWidth,
206+
position: "relative",
207+
}}
208+
>
209+
<div className="mr-flex mr-items-center mr-flex-shrink-0 mr-ml-2">
210+
<span>{column.render("Header")}</span>
211+
{!column.disableSortBy && (
212+
<span className="mr-opacity-70 mr-text-sm">
213+
{!(!currentSort || currentSort.sortBy !== column.id) ? (
214+
currentSort.direction === "DESC" ? (
215+
"▼"
216+
) : (
217+
"▲"
218+
)
219+
) : (
220+
<span className="mr-text-xs mr-opacity-50"></span>
221+
)}
222+
</span>
223+
)}
224+
{!column.disableResizing && (
225+
<div
226+
className="mr-resizer"
227+
{...column.getResizerProps()}
228+
onClick={(e) => {
229+
e.stopPropagation();
230+
}}
231+
/>
232+
)}
233+
</div>
234+
</th>
235+
);
236+
})}
237+
</tr>
238+
))}
239+
240+
{/* Add a separate row for filters */}
241+
{headerGroups.map((headerGroup, index) => (
242+
<tr key={`filter-row-${headerGroup.id}-${index}`}>
243+
{headerGroup.headers.map((column) => (
244+
<td
245+
key={`filter-cell-${column.id}`}
246+
style={{
247+
width: column.width,
248+
minWidth: column.minWidth,
249+
}}
250+
>
251+
{column.canFilter && (
252+
<div
253+
className="mr-header-filter mr-mr-2"
254+
onClick={(e) => e.stopPropagation()}
255+
style={{
256+
overflow: "hidden",
257+
maxWidth: "100%",
258+
}}
259+
>
260+
{column.render("Filter")}
261+
</div>
262+
)}
263+
</td>
264+
))}
265+
</tr>
266+
))}
267+
</>
268+
);
269+
};
270+
162271
/**
163272
* A table wrapper component that adds horizontal scrolling
164273
*/

src/components/TaskAnalysisTable/TaskAnalysisTable.jsx

Lines changed: 17 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import {
1111
useExpanded,
1212
useFilters,
1313
useResizeColumns,
14-
useSortBy,
1514
useTable,
1615
} from "react-table";
1716
import ConfigureColumnsModal from "../../components/ConfigureColumnsModal/ConfigureColumnsModal";
@@ -36,7 +35,7 @@ import {
3635
SearchFilter,
3736
TableWrapper,
3837
renderTableCell,
39-
renderTableHeader,
38+
renderTableHeaderWithSorting,
4039
} from "../TableShared/EnhancedTable";
4140
import { inputStyles, rowStyles, tableStyles } from "../TableShared/TableStyles";
4241
import ViewTask from "../ViewTask/ViewTask";
@@ -93,15 +92,8 @@ export const TaskAnalysisTableInternal = (props) => {
9392
const [showConfigureColumns, setShowConfigureColumns] = useState(false);
9493

9594
const handleStateChange = useCallback(
96-
({ sortBy, filters }) => {
95+
({ filters }) => {
9796
const newCriteria = {
98-
sortCriteria:
99-
sortBy.length > 0
100-
? {
101-
sortBy: sortBy[0].id,
102-
direction: sortBy[0].desc ? "DESC" : "ASC",
103-
}
104-
: undefined,
10597
filters: filters.reduce((acc, filter) => {
10698
let value = filter.value;
10799

@@ -135,29 +127,16 @@ export const TaskAnalysisTableInternal = (props) => {
135127
[props.updateCriteria, props.criteria],
136128
);
137129

138-
// Sort the data locally within the page (the backend does not do this for us, boo)
139-
const data = useMemo(() => {
140-
if (!props.taskData) return [];
141-
if (!props.criteria?.sortCriteria) return props.taskData;
142-
143-
const { sortBy, direction } = props.criteria.sortCriteria;
144-
const sorted = [...props.taskData].sort((a, b) => {
145-
// Handle null/undefined values consistently in sorting
146-
if (sortBy === "name") {
147-
return (a.name || a.title)?.localeCompare(b.name || b.title) ?? 0;
148-
} else if (sortBy === "reviewDuration") {
149-
const getDuration = (t) => {
150-
if (!t.reviewedAt || !t.reviewStartedAt) return 0;
151-
return differenceInSeconds(parseISO(t.reviewedAt), parseISO(t.reviewStartedAt));
152-
};
153-
return getDuration(a) - getDuration(b);
154-
} else {
155-
return a[sortBy] < b[sortBy] ? -1 : a[sortBy] > b[sortBy] ? 1 : 0;
156-
}
157-
});
158-
159-
return direction === "DESC" ? sorted.reverse() : sorted;
160-
}, [props.taskData, props.criteria?.sortCriteria]);
130+
const data = useMemo(
131+
() =>
132+
(props.taskData || []).sort((a, b) => {
133+
if (props.criteria?.sortCriteria?.direction === "DESC") {
134+
return b[props.criteria?.sortCriteria?.sortBy] - a[props.criteria?.sortCriteria?.sortBy];
135+
}
136+
return a[props.criteria?.sortCriteria?.sortBy] - b[props.criteria?.sortCriteria?.sortBy];
137+
}),
138+
[props.taskData, props.criteria?.sortCriteria],
139+
);
161140

162141
const columnTypes = useMemo(() => {
163142
let taskBaseRoute = null;
@@ -227,15 +206,14 @@ export const TaskAnalysisTableInternal = (props) => {
227206
headerGroups,
228207
rows,
229208
prepareRow,
230-
state: { sortBy, filters },
209+
state: { filters },
231210
} = useTable(
232211
{
233212
columns,
234213
data,
235214
manualSortBy: true,
236215
manualFilters: true,
237216
manualPagination: true,
238-
disableSortRemove: true,
239217
autoResetExpanded: false,
240218
defaultColumn: {
241219
Filter: () => null,
@@ -247,29 +225,21 @@ export const TaskAnalysisTableInternal = (props) => {
247225
id,
248226
value,
249227
})),
250-
sortBy: props.criteria?.sortCriteria
251-
? [
252-
{
253-
id: props.criteria.sortCriteria.sortBy,
254-
desc: props.criteria.sortCriteria.direction === "DESC",
255-
},
256-
]
257-
: [],
258228
},
229+
autoResetSortBy: false,
259230
disableResizing: false,
260231
disableMultiSort: true,
261232
columnResizeMode: "onEnd",
262233
},
263234
useFilters,
264-
useSortBy,
265235
useResizeColumns,
266236
useExpanded,
267237
);
268238

269239
// Update parent when table state changes
270240
useEffect(() => {
271-
handleStateChange({ sortBy, filters });
272-
}, [sortBy, filters]);
241+
handleStateChange({ filters });
242+
}, [filters]);
273243

274244
return (
275245
<Fragment>
@@ -291,7 +261,7 @@ export const TaskAnalysisTableInternal = (props) => {
291261
)}
292262
<TableWrapper>
293263
<table {...getTableProps()} className={tableStyles}>
294-
<thead>{renderTableHeader(headerGroups)}</thead>
264+
<thead>{renderTableHeaderWithSorting(headerGroups, props)}</thead>
295265
<tbody {...getTableBodyProps()}>
296266
{rows.map((row) => {
297267
prepareRow(row);

src/pages/Review/TasksReview/TasksReviewTable.jsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import _pull from "lodash/pull";
1111
import { Fragment, useCallback, useEffect, useMemo, useState } from "react";
1212
import { FormattedDate, FormattedMessage, FormattedTime } from "react-intl";
1313
import { Link } from "react-router-dom";
14-
import { useFilters, useResizeColumns, useSortBy, useTable } from "react-table";
14+
import { useFilters, useResizeColumns, useTable } from "react-table";
1515
import ConfigureColumnsModal from "../../../components/ConfigureColumnsModal/ConfigureColumnsModal";
1616
import Dropdown from "../../../components/Dropdown/Dropdown";
1717
import MapPane from "../../../components/EnhancedMap/MapPane/MapPane";
@@ -27,7 +27,7 @@ import SvgSymbol from "../../../components/SvgSymbol/SvgSymbol";
2727
import {
2828
SearchFilter,
2929
TableWrapper,
30-
renderTableHeader,
30+
renderTableHeaderWithSorting,
3131
} from "../../../components/TableShared/EnhancedTable";
3232
import {
3333
cellStyles,
@@ -252,7 +252,6 @@ export const TaskReviewTable = (props) => {
252252
columnResizeMode: "onEnd",
253253
},
254254
useFilters,
255-
useSortBy,
256255
useResizeColumns,
257256
);
258257

@@ -517,7 +516,7 @@ export const TaskReviewTable = (props) => {
517516
)}
518517
<TableWrapper>
519518
<table {...getTableProps()} className={tableStyles}>
520-
<thead>{renderTableHeader(headerGroups)}</thead>
519+
<thead>{renderTableHeaderWithSorting(headerGroups, props)}</thead>
521520
<tbody {...getTableBodyProps()}>
522521
{rows.map((row) => {
523522
prepareRow(row);

0 commit comments

Comments
 (0)